Compare commits

..

2 Commits

Author SHA1 Message Date
61d024b56d Added falling (& jumping) animation for lion.
Added some grass tiles.
2023-06-05 01:31:14 +02:00
ced8a1994f Added collision detection (with tiles). 2023-06-05 01:00:02 +02:00
7 changed files with 93 additions and 22 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.9 KiB

After

Width:  |  Height:  |  Size: 4.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.8 KiB

After

Width:  |  Height:  |  Size: 6.2 KiB

View File

@ -14,8 +14,8 @@ x
x x x x
x x x x
xxxxxxxxxx x xxxxxxxxxx x
x SSSS x x x
x SSSSS x x S S S x
x P S S S S x x P S S S S x
xxxxxxxxxxxxxxxxxxxxxxxxx xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx xxxxxxxxxxxxxxxxxxxxxxxxx xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

View File

@ -9,6 +9,8 @@ const Renderer = @import("renderer.zig").Renderer;
pub const Context = struct { pub const Context = struct {
const DefaultDisplayWidth = 960; const DefaultDisplayWidth = 960;
const DefaultDisplayHeight = 540; const DefaultDisplayHeight = 540;
// const DefaultDisplayWidth = 480;
// const DefaultDisplayHeight = 270;
allocator: std.mem.Allocator, allocator: std.mem.Allocator,
palette: Palette = undefined, palette: Palette = undefined,

View File

@ -6,7 +6,7 @@ pub const PointF = struct {
x: f32, x: f32,
y: f32, y: f32,
pub const Zero = Point{ .x = 0, .y = 0 }; pub const Zero = PointF{ .x = 0, .y = 0 };
pub fn init(x: f32, y: f32) PointF { pub fn init(x: f32, y: f32) PointF {
return PointF{ .x = x, .y = y }; return PointF{ .x = x, .y = y };

View File

@ -20,10 +20,11 @@ pub const Game = struct {
health: i64 = 4, health: i64 = 4,
playerPosition: engine.PointF, playerPosition: engine.PointF,
playerFallingAnimation: Animation,
playerIdleAnimation: Animation, playerIdleAnimation: Animation,
playerWalkingAnimation: Animation, playerWalkingAnimation: Animation,
playerDirection: Direction, playerDirection: Direction,
isPlayerWalking: bool, playerVelocity: engine.PointF,
starAnimation: Animation, starAnimation: Animation,
@ -37,10 +38,11 @@ pub const Game = struct {
return Game{ return Game{
.level = level, .level = level,
.playerPosition = playerPosition, .playerPosition = playerPosition,
.playerFallingAnimation = Animation.initPartialLoop(renderer.sprites.get("character_lion_48").?, 0.2, 8, 12),
.playerIdleAnimation = Animation.initPartialLoop(renderer.sprites.get("character_lion_48").?, 0.25, 0, 4), .playerIdleAnimation = Animation.initPartialLoop(renderer.sprites.get("character_lion_48").?, 0.25, 0, 4),
.playerWalkingAnimation = Animation.initPartialLoop(renderer.sprites.get("character_lion_48").?, 0.125, 4, 8), .playerWalkingAnimation = Animation.initPartialLoop(renderer.sprites.get("character_lion_48").?, 0.125, 4, 8),
.playerDirection = Direction.Right, .playerDirection = Direction.Right,
.isPlayerWalking = false, .playerVelocity = engine.PointF.Zero,
.starAnimation = Animation.init(renderer.sprites.get("item_star_32").?, 0.15), .starAnimation = Animation.init(renderer.sprites.get("item_star_32").?, 0.15),
.renderer = renderer, .renderer = renderer,
.randomTile = TileMap(usize).init(allocator), .randomTile = TileMap(usize).init(allocator),
@ -79,14 +81,49 @@ pub const Game = struct {
renderer.textures.get("opaque").?.drawTintedScaled(allegro.mapRgba(127, 127, 127, 127), topLeftScreen.x, topLeftScreen.y, tileSizeScreen, tileSizeScreen); renderer.textures.get("opaque").?.drawTintedScaled(allegro.mapRgba(127, 127, 127, 127), topLeftScreen.x, topLeftScreen.y, tileSizeScreen, tileSizeScreen);
} }
pub fn moveCharacter(self: *Game, distance: f32) void { pub fn movePlayer(self: *Game, dt: f32) void {
self.playerPosition.x += distance; const to = self.playerPosition.add(self.playerVelocity.multiply(dt));
self.isPlayerWalking = true; self.playerPosition = to;
self.playerDirection = if (distance > 0) Direction.Right else Direction.Left; if (self.playerVelocity.y > 0 and self.playerIsOnTile()) {
self.playerPosition.y = std.math.floor(self.playerPosition.y);
self.playerVelocity.y = 0;
} else if (self.playerVelocity.y < 0 and self.playerIsUnderTile()) {
self.playerPosition.y = std.math.ceil(self.playerPosition.y);
self.playerVelocity.y = -self.playerVelocity.y;
}
if (self.playerVelocity.x != 0) {
const playerTileTop = @floatToInt(i64, std.math.floor(self.playerPosition.y));
const playerTileBottom = @floatToInt(i64, std.math.floor(self.playerPosition.y + 0.99));
if (self.playerVelocity.x < 0) {
const playerTileLeft = @floatToInt(i64, std.math.ceil(self.playerPosition.x)) - 1;
if (self.level.tiles.get(playerTileLeft, playerTileTop) != null or self.level.tiles.get(playerTileLeft, playerTileBottom) != null) {
self.playerPosition.x = std.math.ceil(self.playerPosition.x);
self.playerVelocity.x = 0;
}
}
// const playerTileRight = @floatToInt(i64, std.math.floor(self.playerPosition.x)) + 1;
}
self.playerDirection = if (self.playerVelocity.x == 0) self.playerDirection else if (self.playerVelocity.x > 0) Direction.Right else Direction.Left;
self.boundsInTiles = Game.calculateBoundsInTiles(self.playerPosition); self.boundsInTiles = Game.calculateBoundsInTiles(self.playerPosition);
} }
pub fn playerIsOnTile(self: Game) bool {
const playerTileHeight = @floatToInt(i64, std.math.floor(self.playerPosition.y)) + 1;
const playerTileLeft = @floatToInt(i64, std.math.floor(self.playerPosition.x + 0.5));
const playerTileRight = @floatToInt(i64, std.math.ceil(self.playerPosition.x - 0.5));
return self.level.tiles.get(playerTileLeft, playerTileHeight) != null or self.level.tiles.get(playerTileRight, playerTileHeight) != null;
}
pub fn playerIsUnderTile(self: Game) bool {
const playerTileHeight = @floatToInt(i64, std.math.ceil(self.playerPosition.y)) - 1;
const playerTileLeft = @floatToInt(i64, std.math.floor(self.playerPosition.x + 0.5));
const playerTileRight = @floatToInt(i64, std.math.ceil(self.playerPosition.x - 0.5));
return self.level.tiles.get(playerTileLeft, playerTileHeight) != null or self.level.tiles.get(playerTileRight, playerTileHeight) != null;
}
pub fn randomTileOffset(self: *Game, x: i64, y: i64, maxOffset: usize) usize { pub fn randomTileOffset(self: *Game, x: i64, y: i64, maxOffset: usize) usize {
if (self.randomTile.get(x, y)) |offset| { if (self.randomTile.get(x, y)) |offset| {
return offset; return offset;
@ -134,7 +171,8 @@ pub const Game = struct {
} }
pub fn tick(self: *Game, t: f32, dt: f32) void { pub fn tick(self: *Game, t: f32, dt: f32) void {
_ = t;
_ = self;
_ = dt; _ = dt;
self.playerAnimation.tick(t);
} }
}; };

View File

@ -26,21 +26,46 @@ pub const GameScene = struct {
} }
pub fn tick(self: *GameScene, ctx: *Context, t: f32, dt: f32) void { pub fn tick(self: *GameScene, ctx: *Context, t: f32, dt: f32) void {
const speed: f32 = 6; // tiles/s const horizontalWalkAcceleration: f32 = 13;
const gravity: f32 = 71;
const jumpVelocity: f32 = -26;
const maxFallVelocity: f32 = 23;
const maxHorizontalWalkVelocity: f32 = 7; // tiles/s
if (ctx.keys.isKeyPressed(allegro.c.ALLEGRO_KEY_LEFT)) { if (ctx.keys.isKeyPressed(allegro.c.ALLEGRO_KEY_LEFT)) {
self.game.moveCharacter(-speed * dt); self.game.playerVelocity.x = std.math.max(-maxHorizontalWalkVelocity, self.game.playerVelocity.x - horizontalWalkAcceleration);
self.game.playerWalkingAnimation.tick(t);
} else if (ctx.keys.isKeyPressed(allegro.c.ALLEGRO_KEY_RIGHT)) { } else if (ctx.keys.isKeyPressed(allegro.c.ALLEGRO_KEY_RIGHT)) {
self.game.moveCharacter(speed * dt); self.game.playerVelocity.x = std.math.min(maxHorizontalWalkVelocity, self.game.playerVelocity.x + horizontalWalkAcceleration);
self.game.playerWalkingAnimation.tick(t);
} else { } else {
if (self.game.isPlayerWalking) { if (std.math.fabs(self.game.playerVelocity.x) > 0.2) {
self.game.playerVelocity.x = self.game.playerVelocity.x - std.math.sign(self.game.playerVelocity.x) * horizontalWalkAcceleration * dt;
} else {
self.game.playerVelocity.x = 0;
}
}
if (self.game.playerVelocity.y == 0 and ctx.keys.isKeyPressed(allegro.c.ALLEGRO_KEY_SPACE)) {
self.game.playerVelocity.y = jumpVelocity;
} else if (!self.game.playerIsOnTile()) {
self.game.playerVelocity.y = std.math.min(maxFallVelocity, self.game.playerVelocity.y + gravity * dt);
}
// self.game.playerVelocity.y = std.math.min(maxFallVelocity, self.game.playerVelocity.y + self.game.playerAcceleration.y * dt);
if (self.game.playerVelocity.y != 0) {
self.game.playerFallingAnimation.tick(t);
self.game.playerIdleAnimation.reset();
self.game.playerWalkingAnimation.reset();
} else if (self.game.playerVelocity.x != 0 and self.game.playerVelocity.y == 0) {
self.game.playerWalkingAnimation.tick(t);
self.game.playerFallingAnimation.tick(t);
self.game.playerIdleAnimation.reset();
} else if (self.game.playerVelocity.x == 0) {
self.game.playerIdleAnimation.tick(t);
self.game.playerFallingAnimation.tick(t);
self.game.playerWalkingAnimation.reset(); self.game.playerWalkingAnimation.reset();
} }
self.game.isPlayerWalking = false; self.game.movePlayer(dt);
self.game.playerIdleAnimation.tick(t);
}
self.game.starAnimation.tick(t); self.game.starAnimation.tick(t);
} }
@ -82,10 +107,14 @@ pub const GameScene = struct {
1 => { 1 => {
if (ordinals.right) offset = 0; if (ordinals.right) offset = 0;
if (ordinals.left) offset = 3; if (ordinals.left) offset = 3;
if (ordinals.top) offset = 15;
if (ordinals.bottom) offset = 14;
}, },
2 => { 2 => {
if (ordinals.right and ordinals.left) offset = 1 + self.game.randomTileOffset(x, y, 2); if (ordinals.right and ordinals.left) offset = 1 + self.game.randomTileOffset(x, y, 2);
if (ordinals.top and ordinals.bottom) offset = 12; if (ordinals.top and ordinals.bottom) offset = 12;
if (ordinals.top and ordinals.left) offset = 9;
if (ordinals.top and ordinals.right) offset = 8;
if (ordinals.right and ordinals.bottom) offset = 4; if (ordinals.right and ordinals.bottom) offset = 4;
if (ordinals.left and ordinals.bottom) offset = 5; if (ordinals.left and ordinals.bottom) offset = 5;
}, },
@ -112,15 +141,17 @@ pub const GameScene = struct {
} }
} }
const playerDirectionFrameOffset: usize = if (self.game.playerDirection == game.Game.Direction.Left) 0 else 8; const playerDirectionFrameOffset: usize = if (self.game.playerDirection == game.Game.Direction.Left) 0 else 12;
if (self.game.isPlayerWalking) { if (self.game.playerVelocity.y != 0) {
self.game.drawSpriteFrameP("character_lion_48", self.game.playerFallingAnimation.current + playerDirectionFrameOffset, self.game.playerPosition.add(engine.PointF.init(-0.25, -0.25)));
} else if (self.game.playerVelocity.x != 0 and self.game.playerVelocity.y == 0) {
self.game.drawSpriteFrameP("character_lion_48", self.game.playerWalkingAnimation.current + playerDirectionFrameOffset, self.game.playerPosition.add(engine.PointF.init(-0.25, -0.25))); self.game.drawSpriteFrameP("character_lion_48", self.game.playerWalkingAnimation.current + playerDirectionFrameOffset, self.game.playerPosition.add(engine.PointF.init(-0.25, -0.25)));
} else { } else {
self.game.drawSpriteFrameP("character_lion_48", self.game.playerIdleAnimation.current + playerDirectionFrameOffset, self.game.playerPosition.add(engine.PointF.init(-0.25, -0.25))); self.game.drawSpriteFrameP("character_lion_48", self.game.playerIdleAnimation.current + playerDirectionFrameOffset, self.game.playerPosition.add(engine.PointF.init(-0.25, -0.25)));
} }
if (ctx.showDebug) { if (ctx.showDebug) {
ctx.renderer.printTextV("debug", ctx.palette.background.text, 0.01, 0.1, Renderer.TextAlignment.Left, "Character: ({d}, {d})", .{ self.game.playerPosition.x, self.game.playerPosition.y }); ctx.renderer.printTextV("debug", ctx.palette.background.text, 0.01, 0.1, Renderer.TextAlignment.Left, "Character: ({d:.2}, {d:.2})", .{ self.game.playerPosition.x, self.game.playerPosition.y });
ctx.renderer.printTextV("debug", ctx.palette.background.text, 0.01, 0.15, Renderer.TextAlignment.Left, "Tiles: ({d}, {d}) -> ({d}, {d})", .{ tileBounds.min.x, tileBounds.min.y, tileBounds.max.x, tileBounds.max.y }); ctx.renderer.printTextV("debug", ctx.palette.background.text, 0.01, 0.15, Renderer.TextAlignment.Left, "Tiles: ({d}, {d}) -> ({d}, {d})", .{ tileBounds.min.x, tileBounds.min.y, tileBounds.max.x, tileBounds.max.y });
// self.game.debugHighlightTile(self.game.playerPosition); // self.game.debugHighlightTile(self.game.playerPosition);
} }