aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGene Pasquet <dev@etenil.net>2025-05-28 01:19:25 +0100
committerGene Pasquet <dev@etenil.net>2025-05-28 01:19:25 +0100
commit71ca9de9cadfcbd41327cbc37a94f54794d2316d (patch)
treeb690ded62c0cb36bb510c7c55c63366e5496e959
parent4fd3c145865cde9f6afaddf6f1eed376ba0384bb (diff)
Start using pymunk for physics
-rw-r--r--requirements.txt1
-rw-r--r--src/macroknight/entities.hy45
-rw-r--r--src/macroknight/game.hy101
-rw-r--r--src/macroknight/systems.hy2
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