Added exit/completion of the game/level.
This commit is contained in:
parent
bbd8a56209
commit
f97496a343
BIN
src/assets/images/exit_portal.png
Normal file
BIN
src/assets/images/exit_portal.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.1 KiB |
@ -7,6 +7,8 @@ pub const Object = @import("engine/object.zig").Object;
|
||||
pub const OpaquePtr = @import("engine/opaque_ptr.zig").OpaquePtr;
|
||||
pub const Point = @import("engine/point.zig").Point;
|
||||
pub const PointF = @import("engine/point_f.zig").PointF;
|
||||
pub const pt = Point.init;
|
||||
pub const ptF = PointF.init;
|
||||
pub const Rectangle = @import("engine/rectangle.zig").Rectangle;
|
||||
pub const RectangleF = @import("engine/rectangle_f.zig").RectangleF;
|
||||
pub const Scene = @import("engine/scene.zig").Scene;
|
||||
|
@ -5,6 +5,7 @@ pub const Point = struct {
|
||||
x: i64,
|
||||
y: i64,
|
||||
|
||||
pub const One = Point{ .x = 1, .y = 1 };
|
||||
pub const Zero = Point{ .x = 0, .y = 0 };
|
||||
|
||||
pub fn init(x: i64, y: i64) Point {
|
||||
|
@ -6,6 +6,8 @@ pub const PointF = struct {
|
||||
x: f32,
|
||||
y: f32,
|
||||
|
||||
pub const Half = PointF{ .x = 0.5, .y = 0.5 };
|
||||
pub const One = PointF{ .x = 1, .y = 1 };
|
||||
pub const Zero = PointF{ .x = 0, .y = 0 };
|
||||
|
||||
pub fn init(x: f32, y: f32) PointF {
|
||||
|
@ -12,12 +12,18 @@ pub const Game = struct {
|
||||
Right,
|
||||
};
|
||||
|
||||
pub const State = enum {
|
||||
InProgress,
|
||||
Over,
|
||||
Completed,
|
||||
};
|
||||
|
||||
pub const TileSize = 32;
|
||||
|
||||
prng: std.rand.DefaultPrng = std.rand.DefaultPrng.init(0),
|
||||
|
||||
level: Level,
|
||||
isOver: bool = false,
|
||||
state: State = .InProgress,
|
||||
starsCollected: usize = 0,
|
||||
starsTotal: usize,
|
||||
|
||||
@ -70,7 +76,7 @@ pub const Game = struct {
|
||||
}
|
||||
|
||||
pub fn drawSpriteFrame(self: *Game, spriteName: []const u8, frame: usize, x: i64, y: i64) void {
|
||||
self.drawSpriteFrameP(spriteName, frame, engine.Point.init(x, y).float());
|
||||
self.drawSpriteFrameP(spriteName, frame, engine.pt(x, y).float());
|
||||
}
|
||||
|
||||
pub fn drawSpriteFrameP(self: *Game, spriteName: []const u8, frame: usize, position: engine.PointF) void {
|
||||
@ -87,13 +93,13 @@ pub const Game = struct {
|
||||
}
|
||||
|
||||
pub fn movePlayer(self: *Game, dt: f32) void {
|
||||
if (self.isOver) return;
|
||||
if (self.state != .InProgress) return;
|
||||
|
||||
const to = self.playerPosition.add(self.playerVelocity.multiply(dt));
|
||||
self.playerPosition = to;
|
||||
|
||||
if (self.playerPosition.y > 21.5) {
|
||||
self.isOver = true;
|
||||
self.state = .Over;
|
||||
return;
|
||||
}
|
||||
|
||||
@ -124,21 +130,22 @@ pub const Game = struct {
|
||||
}
|
||||
self.playerDirection = if (self.playerVelocity.x == 0) self.playerDirection else if (self.playerVelocity.x > 0) Direction.Right else Direction.Left;
|
||||
|
||||
const playerCenter = self.playerPosition.add(engine.PointF.init(0.5, 0.5)).floor().integer();
|
||||
const playerCenter = self.playerPosition.add(engine.PointF.Half).floor().integer();
|
||||
var dx: i64 = -1;
|
||||
while (dx <= 1) : (dx += 1) {
|
||||
var dy: i64 = -1;
|
||||
while (dy <= 1) : (dy += 1) {
|
||||
const x = playerCenter.x + dx;
|
||||
const y = playerCenter.y + dy;
|
||||
const collectablePosition = engine.Point.init(x, y);
|
||||
const collectablePosition = engine.pt(x, y);
|
||||
|
||||
if (self.level.collectables.get(x, y)) |collectable| {
|
||||
if (self.collected.hasValue(x, y, true)) continue;
|
||||
if (self.playerPosition.distance2(collectablePosition.float()) > 1.5) continue;
|
||||
|
||||
switch (collectable) {
|
||||
Level.Collectable.Star => {
|
||||
.Exit => self.state = .Completed,
|
||||
.Star => {
|
||||
self.starsCollected += 1;
|
||||
self.collected.set(x, y, true) catch {};
|
||||
},
|
||||
@ -177,25 +184,25 @@ pub const Game = struct {
|
||||
|
||||
// return values are in view coordinates
|
||||
pub fn tile(self: Game, x: f32, y: f32) engine.PointF {
|
||||
return self.tileP(engine.PointF.init(x, y));
|
||||
return self.tileP(engine.ptF(x, y));
|
||||
}
|
||||
|
||||
pub fn tileCenter(self: Game, x: i64, y: i64) engine.PointF {
|
||||
return self.tileCenterP(engine.Point.init(x, y));
|
||||
return self.tileCenterP(engine.pt(x, y));
|
||||
}
|
||||
|
||||
pub fn tileCenterP(self: Game, position: engine.Point) engine.PointF {
|
||||
const center = engine.PointF.init(0.5, 0.5);
|
||||
const center = engine.PointF.Half;
|
||||
return self.tileP(position.float().add(center));
|
||||
}
|
||||
|
||||
pub fn tileP(self: Game, position: engine.PointF) engine.PointF {
|
||||
const relative = position.subtract(self.boundsInTiles.min);
|
||||
return engine.PointF.init(relative.x / self.boundsInTiles.width(), relative.y / self.boundsInTiles.height());
|
||||
return engine.ptF(relative.x / self.boundsInTiles.width(), relative.y / self.boundsInTiles.height());
|
||||
}
|
||||
|
||||
pub fn tileTopLeft(self: Game, x: i64, y: i64) engine.PointF {
|
||||
return self.tileTopLeftP(engine.Point.init(x, y));
|
||||
return self.tileTopLeftP(engine.pt(x, y));
|
||||
}
|
||||
|
||||
pub fn tileTopLeftP(self: Game, p: engine.Point) engine.PointF {
|
||||
|
@ -8,6 +8,7 @@ pub const Level = struct {
|
||||
};
|
||||
|
||||
pub const Collectable = enum {
|
||||
Exit,
|
||||
Star,
|
||||
};
|
||||
|
||||
@ -44,9 +45,10 @@ pub const Level = struct {
|
||||
for (line, 0..) |tile, column| {
|
||||
var x = @intCast(i64, column);
|
||||
switch (tile) {
|
||||
'P' => character = engine.Point.init(x, y),
|
||||
'S' => try collectables.set(x, y, Collectable.Star),
|
||||
'x' => try tiles.set(x, y, Tile.Grass),
|
||||
'P' => character = engine.pt(x, y),
|
||||
'S' => try collectables.set(x, y, .Star),
|
||||
'E' => try collectables.set(x, y, .Exit),
|
||||
'x' => try tiles.set(x, y, .Grass),
|
||||
else => {},
|
||||
}
|
||||
}
|
||||
|
@ -24,7 +24,7 @@ pub const GameScene = struct {
|
||||
}
|
||||
|
||||
pub fn handle(self: *GameScene, ctx: *Context, event: *allegro.Event) !void {
|
||||
if (self.game.isOver) {
|
||||
if (self.game.state != .InProgress) {
|
||||
switch (event.type) {
|
||||
allegro.c.ALLEGRO_EVENT_KEY_DOWN => {
|
||||
switch (event.keyboard.keycode) {
|
||||
@ -50,7 +50,7 @@ pub const GameScene = struct {
|
||||
const maxFallVelocity: f32 = 23;
|
||||
const maxHorizontalWalkVelocity: f32 = 7; // tiles/s
|
||||
|
||||
if (self.game.isOver) {
|
||||
if (self.game.state != .InProgress) {
|
||||
self.game.playerIdleAnimation.tick(t);
|
||||
return;
|
||||
}
|
||||
@ -116,13 +116,16 @@ pub const GameScene = struct {
|
||||
const randomDirtOffset = self.game.randomTileOffset(x, 99, 3);
|
||||
self.game.drawSpriteFrame("tiles_dirt_32", 0 + randomDirtOffset, x, 19);
|
||||
self.game.drawSpriteFrame("tiles_dirt_32", 3 + randomDirtOffset, x, 20);
|
||||
}
|
||||
|
||||
var y = tileBounds.min.y;
|
||||
while (y <= tileBounds.max.y) : (y += 1) {
|
||||
var y = tileBounds.min.y;
|
||||
while (y <= tileBounds.max.y) : (y += 1) {
|
||||
x = tileBounds.min.x;
|
||||
while (x < tileBounds.max.x) : (x += 1) {
|
||||
if (tiles.get(x, y)) |tile| {
|
||||
switch (tile) {
|
||||
game.Level.Tile.Grass => {
|
||||
const ordinals = tiles.getOrdinals(x, y, game.Level.Tile.Grass);
|
||||
.Grass => {
|
||||
const ordinals = tiles.getOrdinals(x, y, .Grass);
|
||||
var offset: usize = 17;
|
||||
switch (ordinals.count()) {
|
||||
1 => {
|
||||
@ -156,10 +159,14 @@ pub const GameScene = struct {
|
||||
if (self.game.collected.hasValue(x, y, true)) continue;
|
||||
|
||||
switch (collectable) {
|
||||
game.Level.Collectable.Star => {
|
||||
const distanceToPlayer = engine.Point.init(x, y).float().distance(self.game.playerPosition);
|
||||
.Star => {
|
||||
const distanceToPlayer = engine.pt(x, y).float().distance(self.game.playerPosition);
|
||||
self.game.drawSpriteFrame("item_star_32", self.game.starAnimation.currentOffset(@floatToInt(usize, @mod(distanceToPlayer * 0.54, 1) * 16)), x, y);
|
||||
},
|
||||
.Exit => {
|
||||
const position = self.game.tileP(engine.pt(x, y).float().subtract(engine.ptF(0.5, 1)));
|
||||
renderer.drawTextureV("exit_portal", position.x, position.y);
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -167,11 +174,11 @@ pub const GameScene = struct {
|
||||
|
||||
const playerDirectionFrameOffset: usize = if (self.game.playerDirection == game.Game.Direction.Left) 0 else 12;
|
||||
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)));
|
||||
self.game.drawSpriteFrameP("character_lion_48", self.game.playerFallingAnimation.current + playerDirectionFrameOffset, self.game.playerPosition.add(engine.ptF(-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.ptF(-0.25, -0.25)));
|
||||
} 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.ptF(-0.25, -0.25)));
|
||||
}
|
||||
|
||||
ctx.renderer.printTextV("default", ctx.palette.background.text, 0.01, 0.01, .Left, "Stars collected: {d}", .{self.game.starsCollected});
|
||||
@ -181,15 +188,25 @@ pub const GameScene = struct {
|
||||
ctx.renderer.drawTintedSpriteFrameV("pie_charts_24", percentage - 1, ctx.palette.background.text, 0.97, 0.01);
|
||||
}
|
||||
|
||||
if (self.game.isOver) {
|
||||
const textColor = allegro.mapRgb(0x48, 0x91, 0x00);
|
||||
const textColor = allegro.mapRgb(0x48, 0x91, 0x00);
|
||||
|
||||
if (self.game.state != .InProgress) {
|
||||
ctx.renderer.textures.get("opaque").?.drawTintedScaled(allegro.mapRgba(0, 0, 0, 191), 0, 0, @intToFloat(f32, ctx.renderer.display.width()), @intToFloat(f32, ctx.renderer.display.height()));
|
||||
ctx.renderer.drawTextV("default", textColor, 0.5, 0.2, .Center, "Game over");
|
||||
ctx.renderer.drawSpriteFrameV("text_balloons", 0, 0.48, 0.40);
|
||||
ctx.renderer.drawTextV("small", ctx.palette.background.text, 0.547, 0.436, .Center, "Do you want to");
|
||||
ctx.renderer.drawTextV("small", ctx.palette.background.text, 0.547, 0.465, .Center, "try again?");
|
||||
ctx.renderer.drawSpriteFrameV("character_lion_48", self.game.playerIdleAnimation.current + 12, 0.44, 0.57);
|
||||
ctx.renderer.drawTextV("small", textColor, 0.5, 0.7, .Center, "[enter] try again | [escape] quit");
|
||||
|
||||
if (self.game.state == .Over) {
|
||||
ctx.renderer.drawTextV("default", textColor, 0.5, 0.2, .Center, "Game over");
|
||||
}
|
||||
if (self.game.state == .Completed) {
|
||||
ctx.renderer.drawTextV("default", textColor, 0.5, 0.2, .Center, "Level completed");
|
||||
}
|
||||
|
||||
if (self.game.starsCollected < self.game.starsTotal) {
|
||||
ctx.renderer.drawSpriteFrameV("text_balloons", 0, 0.45, 0.40);
|
||||
ctx.renderer.drawTextV("small", ctx.palette.background.text, 0.517, 0.436, .Center, "Do you want to");
|
||||
ctx.renderer.drawTextV("small", ctx.palette.background.text, 0.517, 0.465, .Center, "try again?");
|
||||
ctx.renderer.drawSpriteFrameV("character_lion_48", self.game.playerIdleAnimation.current + 12, 0.41, 0.57);
|
||||
ctx.renderer.drawTextV("small", textColor, 0.5, 0.7, .Center, "[enter] try again | [escape] quit");
|
||||
}
|
||||
}
|
||||
|
||||
if (ctx.showDebug) {
|
||||
|
@ -44,6 +44,7 @@ pub fn main() !void {
|
||||
|
||||
allegro.setNewBitmapFlags(allegro.NewBitmapFlags{ .MIN_LINEAR = false, .MAG_LINEAR = false });
|
||||
try renderer.textures.addFromFile("character_lion_48", paths.AssetsDir ++ "/images/character_lion_48.png");
|
||||
try renderer.textures.addFromFile("exit_portal", paths.AssetsDir ++ "/images/exit_portal.png");
|
||||
try renderer.textures.addFromFile("item_star_32", paths.AssetsDir ++ "/images/item_star_32.png");
|
||||
try renderer.textures.addFromFile("pie_charts_24", paths.AssetsDir ++ "/images/pie_charts_24.png");
|
||||
try renderer.textures.addFromFile("text_balloons", paths.AssetsDir ++ "/images/text_balloons.png");
|
||||
|
@ -62,6 +62,17 @@ pub const Renderer = struct {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn drawTexture(self: Renderer, textureName: []const u8, x: f32, y: f32) void {
|
||||
if (self.textures.get(textureName)) |texture| {
|
||||
texture.drawScaledUniform(x, y, self.viewport.scale);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn drawTextureV(self: Renderer, textureName: []const u8, x: f32, y: f32) void {
|
||||
const screen = self.viewport.viewToScreen(x, y);
|
||||
self.drawTexture(textureName, screen.x, screen.y);
|
||||
}
|
||||
|
||||
pub fn drawTextV(self: Renderer, fontName: []const u8, color: allegro.Color, x: f32, y: f32, alignment: TextAlignment, text: [*:0]const u8) void {
|
||||
const screen = self.viewport.viewToScreen(x, y);
|
||||
self.drawText(fontName, color, screen.x, screen.y, alignment, text);
|
||||
|
Loading…
Reference in New Issue
Block a user