diff options
author | Gene Pasquet <dev@etenil.net> | 2025-05-28 01:19:25 +0100 |
---|---|---|
committer | Gene Pasquet <dev@etenil.net> | 2025-05-28 01:19:25 +0100 |
commit | 71ca9de9cadfcbd41327cbc37a94f54794d2316d (patch) | |
tree | b690ded62c0cb36bb510c7c55c63366e5496e959 | |
parent | 4fd3c145865cde9f6afaddf6f1eed376ba0384bb (diff) |
Start using pymunk for physics
-rw-r--r-- | requirements.txt | 1 | ||||
-rw-r--r-- | src/macroknight/entities.hy | 45 | ||||
-rw-r--r-- | src/macroknight/game.hy | 101 | ||||
-rw-r--r-- | src/macroknight/systems.hy | 2 |
4 files changed, 114 insertions, 35 deletions
diff --git a/requirements.txt b/requirements.txt index 9a9d87e..ac5689a 100644 --- a/requirements.txt +++ b/requirements.txt @@ -3,3 +3,4 @@ hy==1.1.0 hyrule==1.0.0 pygame==2.6.1 PyTMX==3.32 +pymunk==6.11.1 diff --git a/src/macroknight/entities.hy b/src/macroknight/entities.hy index af684c2..1979e56 100644 --- a/src/macroknight/entities.hy +++ b/src/macroknight/entities.hy @@ -22,16 +22,23 @@ (defclass PlayerKilled [Exception]) +(defclass Physics [] + (defn __init__ [self body shape] + (setv self.body body) + (setv self.shape shape))) + (defclass Entity [Sprite] ;;; Game entity (setv _fixed False) + (setv _managed False) (setv _type "none") - (defn __init__ [self id tile tile-size x y] + (defn __init__ [self id tile physics tile-size x y] (.__init__ (super)) (setv self.id id) (setv self.tile-size tile-size) (setv self._surf (Surface #(tile-size tile-size))) + (setv self._physics physics) (.blit self._surf tile #(0 0)) (setv self._rect (.get_rect self._surf :left (* x tile-size) @@ -40,6 +47,9 @@ (defn [property] fixed [self] self._fixed) + (defn [property] managed [self] + self._managed) + (defn [property] rect [self] self._rect) @@ -57,24 +67,23 @@ (setv _fixed True) (setv _type "level") - (defn __init__ [self id tile tile-size x y scaling] + (defn __init__ [self id tile physics tile-size x y scaling] (let [tile-width (* (.get_width tile) scaling) tile-height (* (.get_height tile) scaling) tile_ (if (!= scaling 1) (pygame.transform.scale tile #(tile-width tile-height)) tile)] - (.__init__ (super) id tile_ tile-size x y)))) + (.__init__ (super) id tile_ physics tile-size x y)))) (defclass Goal [Entity] (setv _type "goal") (setv _fixed True)) - (defclass Character [Entity] (setv _type "enemy") - (defn __init__ [self id tiles tile-size x y] - (.__init__ (super) id (get tiles 0) tile-size x y) + (defn __init__ [self id tiles physics tile-size x y] + (.__init__ (super) id (get tiles 0) physics tile-size x y) (setv self.tiles tiles) (setv self.facing Direction.RIGHT) (setv self.attacking False) @@ -125,23 +134,39 @@ (defclass Player [Character] (setv _type "player") - (setv SPEED 3) + (setv _managed True) + (setv SPEED 100) (setv JUMP_IMPULSE 10) (setv MAX_JUMPING 100) - (defn __init__ [self id tiles tile-size x y] - (.__init__ (super) id tiles tile-size x y) + (defn __init__ [self id tiles physics tile-size x y] + (.__init__ (super) id tiles physics tile-size x y) (setv self.jumping False) (setv self.jump-move 0)) (defn [property] total-move [self] (merge-moves self.moves)) + (defn move [self move] + ;; (.append self.moves move) + ;; (.move_ip self._rect (get move 0) (get move 1)) + ;; ;; (setv self._physics.body.velocity move) + ;; (when (!= (get move 0) 0) + ;; (setv self.facing + ;; (.x-from-move Direction move))) + ) + (defn jump [self] (setv self.jumping True) (when (< self.jump-move self.MAX_JUMPING) (setv self.jump-move (+ self.jump-move self.JUMP_IMPULSE)) - (.move self #(0 (neg self.JUMP_IMPULSE)))))) + (.move self #(0 (neg self.JUMP_IMPULSE))))) + + + (defn [property] rect [self] + (setv self._rect.x self._physics.body.position.x) + (setv self._rect.y self._physics.body.position.y) + self._rect)) (defclass Enemy [Character] (setv _type "Enemy")) diff --git a/src/macroknight/game.hy b/src/macroknight/game.hy index 125768a..c6c329e 100644 --- a/src/macroknight/game.hy +++ b/src/macroknight/game.hy @@ -16,13 +16,16 @@ (require hy) (require hyrule *) (import pygame + pymunk + pymunk.pygame_util pytmx.util_pygame [load_pygame] - entities [Player LevelTile Goal Enemy PlayerKilled] + entities [Player LevelTile Goal Enemy PlayerKilled Physics] tiles [TileSet draw-tile] utils [neg] text [render-text] systems [apply-gravity apply-collisions run-enemies GoalHit] - math [floor]) + math [floor] + pprint [pprint]) (pygame.init) @@ -30,8 +33,10 @@ (setv TILE_SIZE (* TILE_SCALING 16)) (setv MACRO_STEP_WAIT 300) (setv MACRO_COOLDOWN 2000) +(setv FPS 60.0) (setv screen (pygame.display.set_mode #((* TILE_SCALING 640) (* TILE_SCALING 480)))) +(setv screen-options (pymunk.pygame_util.DrawOptions screen)) (setv clock (pygame.time.Clock)) (setv tileset (TileSet "assets/monochrome-transparent.png" TILE_SCALING TILE_SIZE TILE_SIZE 1)) (setv levels [(load_pygame "assets/level-0.tmx") @@ -55,7 +60,8 @@ (render-text screen tileset "ENTER FOR MACRO" 13 27) (pygame.display.flip) - (pygame.time.wait 3000)) + ;; (pygame.time.wait 3000) ;;; TODO: reactivate + ) (setv game-running True) @@ -65,6 +71,8 @@ (setv running True) (setv level (get levels level-id)) (setv entities []) + (setv space (pymunk.Space)) + (setv space.gravity #(0.0 200.0)) (setv player-pos #(5 5)) (for [item (get level.layers 1)] (let [tile-x (abs-to-tile-index item.x) @@ -72,18 +80,30 @@ (case item.type "Player" (setv player-pos #(tile-x tile-y)) "Goal" (.append entities - (Goal (len entities) - (get tileset.tiles 0) - TILE_SIZE - tile-x - tile-y)) + (let [entity + (Goal (len entities) + (get tileset.tiles 0) + (let [body (pymunk.Body :body_type pymunk.Body.STATIC)] + (setv body.position #(item.x item.y)) + (Physics body (pymunk.Poly.create_box body #(TILE_SIZE TILE_SIZE)))) + TILE_SIZE + tile-x + tile-y)] + (.add space entity._physics.body entity._physics.shape) + entity)) "Enemy1" (.append entities - (Enemy (len entities) - [(get tileset.tiles 128) - (get tileset.tiles 129)] - TILE_SIZE - tile-x - tile-y))))) + (let [entity + (Enemy (len entities) + [(get tileset.tiles 128) + (get tileset.tiles 129)] + (let [body (pymunk.Body 10 0.2)] + (setv body.position #(item.x item.y)) + (Physics body (pymunk.Poly.create_box body #(TILE_SIZE TILE_SIZE)))) + TILE_SIZE + tile-x + tile-y)] + (.add space entity._physics.body entity._physics.shape) + entity))))) (setv player-pos (let [player-objects (lfor ent (get level.layers 1) :if (= ent.type "Player") ent)] @@ -92,8 +112,17 @@ #((abs-to-tile-index player-object.x) (abs-to-tile-index player-object.y))) #(5 5)))) - (setv player (Player (len entities) [(get tileset.tiles 28) - (get tileset.tiles 29)] TILE_SIZE #* player-pos)) + (setv player (Player (len entities) + [(get tileset.tiles 28) (get tileset.tiles 29)] + (let [body (pymunk.Body 10 (float "inf"))] + (setv body.position #((* TILE_SIZE (get player-pos 0)) + (* TILE_SIZE (get player-pos 1)))) + (setv body.elasticity 0.2) + (setv body.friction 0.5) + (Physics body (pymunk.Poly.create_box body #(TILE_SIZE TILE_SIZE)))) + TILE_SIZE + #* player-pos)) + (.add space player._physics.body player._physics.shape) (.append entities player) (setv macro-input-mode False) @@ -103,8 +132,21 @@ (for [#(id tiledef) (enumerate (.tiles (get level.layers 0)))] (let [x (get tiledef 0) y (get tiledef 1) - tile (get tiledef 2)] - (.append entities (LevelTile (+ id id-offset) tile TILE_SIZE x y TILE_SCALING))))) + tile (get tiledef 2) + tile-ent (LevelTile + (+ id id-offset) + tile + (let [body (pymunk.Body :body_type pymunk.Body.STATIC)] + (setv body.position #((* x TILE_SIZE) (* y TILE_SIZE))) + (setv body.elasticity 0.0) + (setv body.friction 0.6) + (Physics body (pymunk.Poly.create_box body #(TILE_SIZE TILE_SIZE)))) + TILE_SIZE + x + y + TILE_SCALING)] + (.add space tile-ent._physics.body tile-ent._physics.shape) + (.append entities tile-ent)))) (setv ongoing_inputs []) @@ -178,10 +220,14 @@ (draw-tile screen tileset 725 (+ 4 indicator) 5)))) (for [inp ongoing_inputs] (case inp - 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_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_a (setv player._physics.body.velocity #((neg player.SPEED) 0)) + pygame.K_s (setv player._physics.body.velocity #(0 1)) + pygame.K_w (setv player._physics.body.velocity #(0 -100)) ;; (.jump player) + pygame.K_d (setv player._physics.body.velocity #(player.SPEED 0)) pygame.K_SPACE (.attack player))) (try @@ -217,17 +263,24 @@ (.flush player))) - + (pprint player._physics.body.position) + (for [entity entities] (.blit screen entity.surf entity.rect)) + + ;; (space.debug_draw screen-options) + + (pygame.display.flip) (when (and (!= 0 macro-wait-time) (> (pygame.time.get_ticks) macro-wait-time)) (setv macro-wait-time 0)) - (.tick clock 60))) + (.step space (/ 1.0 FPS)) + + (.tick clock FPS))) diff --git a/src/macroknight/systems.hy b/src/macroknight/systems.hy index 91d4e8c..b967504 100644 --- a/src/macroknight/systems.hy +++ b/src/macroknight/systems.hy @@ -31,7 +31,7 @@ ~@body))) (defsystem apply-gravity - (not entity.fixed) + (not (or entity.fixed entity.managed)) (.move entity #(0 GRAVITY))) (defsystem apply-collisions |