diff options
| author | Gene Pasquet <dev@etenil.net> | 2025-05-18 08:38:25 +0100 | 
|---|---|---|
| committer | Gene Pasquet <dev@etenil.net> | 2025-05-18 08:38:25 +0100 | 
| commit | 1cf28e193729ee64a17e6464ce7310c67f5eae34 (patch) | |
| tree | 906ff27f5e533397f4f760a245d0606232a87b1f | |
| parent | be71ead1e21d55049a18747f2d0d2159b11868f3 (diff) | |
Progress on animations and enemies
| -rw-r--r-- | assets/monochrome-transparent.png | bin | 19451 -> 26816 bytes | |||
| -rw-r--r-- | macroknight.tiled-session | 36 | ||||
| -rw-r--r-- | src/macroknight/entities.hy | 69 | ||||
| -rw-r--r-- | src/macroknight/game.hy | 32 | ||||
| -rw-r--r-- | src/macroknight/systems.hy | 66 | ||||
| -rw-r--r-- | src/macroknight/utils.hy | 32 | 
6 files changed, 172 insertions, 63 deletions
| diff --git a/assets/monochrome-transparent.png b/assets/monochrome-transparent.pngBinary files differ index 9f8187d..3102227 100644 --- a/assets/monochrome-transparent.png +++ b/assets/monochrome-transparent.png diff --git a/macroknight.tiled-session b/macroknight.tiled-session index 20c0f18..8aa14c8 100644 --- a/macroknight.tiled-session +++ b/macroknight.tiled-session @@ -3,38 +3,45 @@          "height": 4300,          "width": 2      }, -    "activeFile": "assets/level-0.tmx", +    "activeFile": "assets/level-3.tmx",      "expandedProjectPaths": [          ".",          "assets"      ],      "fileStates": {          "assets/level-0.tmx": { +            "expandedObjectLayers": [ +                7 +            ],              "scale": 3,              "selectedLayer": 1,              "viewCenter": { -                "x": 245.16666666666669, -                "y": 330.16666666666663 +                "x": 441.5, +                "y": 363.5              }          },          "assets/level-1.tmx": {              "scale": 4,              "selectedLayer": 0,              "viewCenter": { -                "x": 553.625, -                "y": 290.375 +                "x": 319.875, +                "y": 240              }          },          "assets/level-3.tmx": { -            "scale": 2.1404687499999997, -            "selectedLayer": 0, +            "expandedObjectLayers": [ +                2 +            ], +            "scale": 2, +            "selectedLayer": 1,              "viewCenter": { -                "x": 320.25695306226737, -                "y": 240.3679100664282 +                "x": 320.25, +                "y": 240.25              }          },          "assets/monochrome_transparent.tsx": { -            "scaleInDock": 1 +            "scaleInDock": 2, +            "scaleInEditor": 2          },          "assets/tileset_colored.tsx": {              "scaleInDock": 1 @@ -46,11 +53,16 @@      "map.tileWidth": 16,      "map.width": 40,      "openFiles": [ -        "assets/level-0.tmx" +        "assets/level-0.tmx", +        "assets/monochrome_transparent.tsx", +        "assets/level-1.tmx", +        "assets/level-3.tmx"      ],      "project": "macroknight.tiled-project",      "recentFiles": [ +        "assets/level-0.tmx", +        "assets/monochrome_transparent.tsx",          "assets/level-1.tmx", -        "assets/level-0.tmx" +        "assets/level-3.tmx"      ]  } diff --git a/src/macroknight/entities.hy b/src/macroknight/entities.hy index c490b25..760aeca 100644 --- a/src/macroknight/entities.hy +++ b/src/macroknight/entities.hy @@ -1,16 +1,19 @@ +(require hyrule [case])  (import pygame.sprite [Sprite]          pygame [Surface]          pygame -        utils [neg merge-moves]) +        utils [neg merge-moves Direction] +        enum [Enum])  (defclass Entity [Sprite] -   ;;; Game entity +;;; Game entity    (setv _fixed False)    (setv _type "none")    (defn __init__ [self id tile tile-size x y]      (.__init__ (super))      (setv self.id id) +    (setv self.tile-size tile-size)      (setv self._surf (Surface #(tile-size tile-size)))      (.blit self._surf tile #(0 0))      (setv self._rect (.get_rect self._surf @@ -27,7 +30,11 @@      self._surf)    (defn [property] type [self] -    self._type)) +    self._type) + +  (defn [property] pos [self] +    #((/ self.rect.x self.tile-size) +       (/ self.rect.y self.tile-size))))  (defclass LevelTile [Entity]    (setv _fixed True) @@ -51,20 +58,29 @@    (setv JUMP_IMPULSE 10)    (setv MAX_JUMPING 100) -  (defn __init__ [self id tile tile-size x y] -    (.__init__ (super) id tile tile-size x y) +  (defn __init__ [self id tiles tile-size x y] +    (.__init__ (super) id (get tiles 0) tile-size x y) +    (setv self.tiles tiles)      (setv self.jumping False)      (setv self.jump-move 0)      (setv self.moves []) -    (setv self._disp_surf (.copy self._surf))) +    (setv self._disp_surf (.copy self._surf)) +    (setv self.facing Direction.RIGHT) +    (setv self.attacking False) +    (setv self.animate-end 0))    (defn move [self move]      (.append self.moves move) -    (.move_ip self._rect (get move 0) (get move 1))) +    (.move_ip self._rect (get move 0) (get move 1)) +    (setv self.facing +          (.x-from-move Direction move)))    (defn [property] total-move [self]      (merge-moves self.moves)) +  (defn attack [self] +    (setv self.attacking True)) +    (defn jump [self]      (setv self.jumping True)      (when (< self.jump-move self.MAX_JUMPING) @@ -74,13 +90,21 @@    (defn ground [self]      (setv self.jump-move 0)) -  (defn animate [self] -    (let [x-move (get self.total-move 0)] -      (setv self._disp_surf -            (cond -              (< x-move 0) (pygame.transform.flip self._surf True False) -              (> x-move 0) (.copy self._surf) -              True self._disp_surf)))) +  (defn animate [self ticks] +    ;; Attack animation +    (when (and self.attacking (= self.animate-end 0)) +      (setv self.animate-end (+ ticks 200)) +      (.blit self._surf (get self.tiles 1) #(0 0))) +    (when (and self.attacking (> ticks self.animate-end)) +      (setv self.animate-end 0) +      (setv self.attacking False) +      (.blit self._surf (get self.tiles 0) #(0 0))) + +    ;; Facing direction +    (setv self._disp_surf +          (case self.facing +                Direction.LEFT (pygame.transform.flip self._surf True False) +                Direction.RIGHT (.copy self._surf))))    (defn flush [self]      (setv self.moves [])) @@ -89,21 +113,30 @@      self._disp_surf))  (defclass Enemy [Entity] -  (setv _type "enemy")) +  (setv _type "enemy") -(defclass Enemy2Swords [Enemy]    (defn __init__ [self id tile tile-size x y]      (.__init__ (super) id tile tile-size x y) +    (setv self.facing Direction.RIGHT) +    (setv self.attacking False)      (.flush self)) -   +    (defn move [self move]      (.append self.moves move) -    (.move_ip self._rect (get move 0) (get move 1))) +    (.move_ip self._rect (get move 0) (get move 1)) +    (setv self.facing +          (.x-from-move Direction move)))    (defn flush [self]      (setv self.moves []))    (defn ground [self]) + +  (defn animate [self ticks] +    (setv self._disp_surf +          (case self.facing +                Direction.LEFT (pygame.transform.flip self._surf True False) +                Direction.RIGHT (.copy self._surf))))    (defn [property] total-move [self]      (merge-moves self.moves))) diff --git a/src/macroknight/game.hy b/src/macroknight/game.hy index 4e1ce7e..95cb8b1 100644 --- a/src/macroknight/game.hy +++ b/src/macroknight/game.hy @@ -2,11 +2,11 @@  (require hyrule *)  (import pygame          pytmx.util_pygame [load_pygame] -        entities [Player LevelTile Goal Enemy2Swords] +        entities [Player LevelTile Goal Enemy]          tiles [TileSet draw-tile]          utils [neg]          text [render-text] -        systems [apply-gravity apply-collisions GoalHit] +        systems [apply-gravity apply-collisions run-enemies GoalHit]          math [floor])  (pygame.init) @@ -48,11 +48,11 @@                                    tile-x                                    tile-y))              "Enemy1" (.append entities -                              (Enemy2Swords (len entities) -                                            (get tileset.tiles 128) -                                            TILE_SIZE -                                            tile-x -                                            tile-y))))) +                              (Enemy (len entities) +                                     (get tileset.tiles 128) +                                     TILE_SIZE +                                     tile-x +                                     tile-y)))))    (setv player-pos          (let [player-objects (lfor ent (get level.layers 1) :if (= ent.type "Player") ent)] @@ -61,7 +61,8 @@                  #((abs-to-tile-index player-object.x)                     (abs-to-tile-index player-object.y)))                #(5 5)))) -  (setv player (Player 1 (get tileset.tiles 28) TILE_SIZE #* player-pos)) +  (setv player (Player 1 [(get tileset.tiles 28) +                          (get tileset.tiles 29)] TILE_SIZE #* player-pos))    (.append entities player)    (setv macro-input-mode False)    (setv macro-wait-time 0) @@ -86,7 +87,7 @@                                   (setv running False)                                   (setv game-running False))                                 (if macro-input-mode -                                   (when (in event.key [pygame.K_a pygame.K_w pygame.K_a pygame.K_s pygame.K_d]) +                                   (when (in event.key [pygame.K_a pygame.K_w pygame.K_a pygame.K_s pygame.K_d pygame.K_RETURN])                                       (setv (get macro-commands (.index macro-commands None)) event.key))                                     (if (and (= event.key pygame.K_SPACE) (= macro-wait-time 0))                                         (setv macro-input-mode True) @@ -115,7 +116,9 @@                        pygame.K_a (.move player #((neg (* 2 TILE_SIZE)) 0))                        pygame.K_s (.move player #(0 TILE_SIZE))                        pygame.K_w (.move player #(0 (neg (/ player.MAX_JUMPING 2)))) -                      pygame.K_d (.move player #((* 2 TILE_SIZE) 0))) +                      pygame.K_d (.move player #((* 2 TILE_SIZE) 0)) +                      pygame.K_RETURN (.attack player)) +                                  (if (= command-id (- (len macro-commands) 1))                      (do                        (setv macro-commands [None None None]) @@ -132,6 +135,7 @@                        pygame.K_d (draw-tile screen tileset 1058 x-pos 5)                        pygame.K_s (draw-tile screen tileset 1059 x-pos 5)                        pygame.K_a (draw-tile screen tileset 1060 x-pos 5) +                      pygame.K_RETURN (draw-tile screen tileset 329 x-pos 5)                        None (draw-tile screen tileset 725 x-pos 5)))))          ;; Not in macro mode @@ -145,21 +149,21 @@                    pygame.K_a (.move player #((neg player.SPEED) 0))                    pygame.K_s (.move player #(0 1))                    pygame.K_w (.jump player) -                  pygame.K_d (.move player #(player.SPEED 0)))) +                  pygame.K_d (.move player #(player.SPEED 0)) +                  pygame.K_RETURN (.attack player))) -           -                      (try              (when (any ongoing_inputs)                (for [entity entities]                  (apply-collisions entity entities))) -            (.animate player) +            (.animate player (pygame.time.get_ticks))              (.flush player)              ;; Apply systems              (for [entity entities]                (apply-gravity entity entities) +              (run-enemies entity entities)                (apply-collisions entity entities))              (except [GoalHit] diff --git a/src/macroknight/systems.hy b/src/macroknight/systems.hy index fccccd0..8c1bb9c 100644 --- a/src/macroknight/systems.hy +++ b/src/macroknight/systems.hy @@ -1,25 +1,53 @@ +(import utils [sub-points Direction]) +  ;; Define systems here  (setv GRAVITY 5)  (defclass GoalHit [Exception]) -(defn apply-gravity [entity entities] -  (when (not entity.fixed) -    (.move entity #(0 GRAVITY)))) +(defn entities-by-type [entities types] +  (gfor ent entities +        :if (in ent.type types) +        ent)) + +(defmacro defsystem [name pred #* body] +  `(defn ~name [entity entities] +     (when ~pred +       ~@body))) + +(defsystem apply-gravity +  (not entity.fixed) +  (.move entity #(0 GRAVITY))) + +(defsystem apply-collisions +  (not entity.fixed) +  (for [ent (gfor enti entities +                  :if (!= enti.id entity.id) +                  enti)] +    (when (.colliderect entity.rect ent.rect) +      (if (= ent.type "goal") +          (raise (GoalHit)) +          (let [collision-rect (.clip entity.rect ent.rect) +                move-x (get entity.total-move 0) +                move-y (get entity.total-move 1)] +            (when (!= move-x 0) +              (.move entity #((* (if (> move-x 0) -1 1) collision-rect.width) 0))) +            (when (!= move-y 0) +              (.move entity #(0 (* (if (> move-y 0) -1 1) collision-rect.height)))))) +      (.ground entity)))) -(defn apply-collisions [entity entities] -  (when (not entity.fixed) -    (for [ent (gfor enti entities -                    :if (!= enti.id entity.id) -                    enti)] -      (when (.colliderect entity.rect ent.rect) -        (if (= ent.type "goal") -            (raise (GoalHit)) -            (let [collision-rect (.clip entity.rect ent.rect) -                  move-x (get entity.total-move 0) -                  move-y (get entity.total-move 1)] -              (when (!= move-x 0) -                (.move entity #((* (if (> move-x 0) -1 1) collision-rect.width) 0))) -              (when (!= move-y 0) -                (.move entity #(0 (* (if (> move-y 0) -1 1) collision-rect.height)))))) -        (.ground entity))))) +(defsystem run-enemies +  (= entity.type "enemy") +  ;; If the player is on the tile next to the enemy, attack. +  (let [player (next (entities-by-type entities ["player"])) +        dist (sub-points entity.pos player.pos) +        direction (.x-from-move Direction dist)] +    ;; If facing the player and within reach, attack) +    (when (and (= direction entity.facing) +               (< (get dist 1) 1) ;; Same level +               (< (abs (get dist 0)) 2) +               (not entity.attacking)) +      (setv entity.attacking True) +      (print "attack") +      ) +    )) diff --git a/src/macroknight/utils.hy b/src/macroknight/utils.hy index a857d02..dde8d2e 100644 --- a/src/macroknight/utils.hy +++ b/src/macroknight/utils.hy @@ -1,3 +1,31 @@ +(import enum [Enum]) + +(defclass Direction [Enum] +  (setv UP "UP") +  (setv DOWN "DOWN") +  (setv LEFT "LEFT") +  (setv RIGHT "RIGHT") + +  (defn [staticmethod] from-move [move] +    #((.x-from-move Direction move) +       (.y-from-move Direction move))) + +  (defn [staticmethod] x-from-move [move] +    (if (>= (get move 0) 0) +        Direction.RIGHT +        Direction.LEFT)) + +  (defn [staticmethod] y-from-move [move] +    (if (>= (get move 0) 0) +        Direction.DOWN +        Direction.UP)) + +  (defn [staticmethod] x-between-points [point1 point2] +    (let [delta-x (abs (- (get point1 0) (get point2 0)))] +      (if (>= delta-x 0) +          Direction.RIGHT +          Direction.LEFT)))) +  (defn neg [value]    (* -1 value)) @@ -12,3 +40,7 @@              #((+ (get end-move 0) (get move 0))                 (+ (get end-move 1) (get move 1)))))      end-move)) + +(defn sub-points [point1 point2] +  #((- (get point2 0) (get point1 0)) +     (- (get point2 1) (get point2 1)))) | 
