Enabled tile randomization.

This commit is contained in:
Sander Schobers 2023-06-04 19:23:37 +02:00
parent e66908ca71
commit 7a51415e5e
6 changed files with 85 additions and 31 deletions

View File

@ -3,6 +3,7 @@ const assets = @import("engine/assets.zig");
pub const Fonts = assets.Fonts;
pub const FPS = @import("engine/fps.zig").FPS;
pub const Keys = @import("engine/keys.zig").Keys;
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;

19
src/engine/object.zig Normal file
View File

@ -0,0 +1,19 @@
const std = @import("std");
pub fn Object(comptime T: type) type {
return struct {
const Self = @This();
allocator: std.mem.Allocator,
ptr: *T,
pub fn create(allocator: std.mem.Allocator) !Self {
const ptr = try allocator.create(T);
return Self{ .allocator = allocator, .ptr = ptr };
}
pub fn destroy(self: Self) void {
self.allocator.destroy(self.ptr);
}
};
}

View File

@ -2,8 +2,9 @@ const std = @import("std");
const allegro = @import("allegro");
const engine = @import("../engine.zig");
const Animation = @import("animation.zig").Animation;
const Renderer = @import("../renderer.zig").Renderer;
const Level = @import("level.zig").Level;
const Renderer = @import("../renderer.zig").Renderer;
const TileMap = @import("tile_map.zig").TileMap;
pub const Game = struct {
pub const Direction = enum {
@ -13,6 +14,8 @@ pub const Game = struct {
pub const TileSize = 32;
prng: std.rand.DefaultPrng = std.rand.DefaultPrng.init(0),
level: Level,
health: i64 = 4,
@ -25,10 +28,11 @@ pub const Game = struct {
starAnimation: Animation,
renderer: *Renderer,
randomTile: TileMap(usize),
// current viewport translated to tiles.
boundsInTiles: engine.RectangleF,
pub fn init(level: Level, renderer: *Renderer) Game {
pub fn init(allocator: std.mem.Allocator, level: Level, renderer: *Renderer) Game {
const playerPosition = level.character.float();
return Game{
.level = level,
@ -39,10 +43,16 @@ pub const Game = struct {
.isPlayerWalking = false,
.starAnimation = Animation.init(renderer.sprites.get("item_star_32").?, 0.15),
.renderer = renderer,
.randomTile = TileMap(usize).init(allocator),
.boundsInTiles = Game.calculateBoundsInTiles(playerPosition),
};
}
pub fn deinit(self: *Game) void {
self.level.deinit();
self.randomTile.deinit();
}
fn calculateBoundsInTiles(position: engine.PointF) engine.RectangleF {
return engine.RectangleF.initRelative(
position.x - 15,
@ -77,6 +87,15 @@ pub const Game = struct {
self.boundsInTiles = Game.calculateBoundsInTiles(self.playerPosition);
}
pub fn randomTileOffset(self: *Game, x: i64, y: i64, maxOffset: usize) usize {
if (self.randomTile.get(x, y)) |offset| {
return offset;
}
const offset = self.prng.random().intRangeLessThan(usize, 0, maxOffset);
self.randomTile.set(x, y, offset) catch {};
return offset;
}
// 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));

View File

@ -15,7 +15,7 @@ pub const Level = struct {
tiles: TileMap(Tile),
collectables: TileMap(Collectable),
pub fn load(allocator: std.mem.Allocator, path: []const u8) !Level {
pub fn init(allocator: std.mem.Allocator, path: []const u8) !Level {
const path_ = try std.fs.realpathAlloc(allocator, path);
defer allocator.free(path_);
@ -25,10 +25,10 @@ pub const Level = struct {
const data = try file.readToEndAlloc(allocator, 1024 * 1024);
defer allocator.free(data);
return try Level.loadFromMemory(allocator, data);
return try Level.initFromMemory(allocator, data);
}
pub fn loadFromMemory(allocator: std.mem.Allocator, data: []const u8) !Level {
pub fn initFromMemory(allocator: std.mem.Allocator, data: []const u8) !Level {
const n = std.mem.count(u8, data, "\n");
_ = n;
@ -41,9 +41,6 @@ pub const Level = struct {
while (lines.next()) |line| {
defer y += 1;
try tiles.ensureColumns(line.len);
try collectables.ensureColumns(line.len);
for (line, 0..) |tile, column| {
var x = @intCast(i64, column);
switch (tile) {
@ -61,4 +58,9 @@ pub const Level = struct {
.collectables = collectables,
};
}
pub fn deinit(self: *Level) void {
self.tiles.deinit();
self.collectables.deinit();
}
};

View File

@ -1,4 +1,5 @@
const std = @import("std");
const Object = @import("../engine/object.zig").Object;
pub fn TileMap(comptime Value: type) type {
return struct {
@ -13,7 +14,7 @@ pub fn TileMap(comptime Value: type) type {
};
}
pub fn deinit(self: Column) void {
pub fn deinit(self: *Column) void {
self.values.deinit();
}
@ -27,35 +28,45 @@ pub fn TileMap(comptime Value: type) type {
};
allocator: std.mem.Allocator,
columns: std.ArrayList(Column),
columns: std.AutoHashMap(i64, Column),
pub fn init(allocator: std.mem.Allocator) Self {
return Self{
.allocator = allocator,
.columns = std.ArrayList(Column).init(allocator),
.columns = std.AutoHashMap(i64, Column).init(allocator),
};
}
pub fn deinit(self: Self) void {
for (self.columns.items) |item| {
item.deinit();
pub fn deinit(self: *Self) void {
var columns = self.columns.valueIterator();
while (columns.next()) |c| {
c.deinit();
}
self.columns.deinit();
}
pub fn column(self: Self, i: i64) *Column {
return &self.columns.items[@intCast(usize, i)];
pub fn column(self: Self, x: i64) *Column {
return self.columns.getPtr(x).?;
}
pub fn ensureColumns(self: *Self, n: usize) !void {
while (self.columns.items.len < n) {
try self.columns.append(Column.init(self.allocator));
pub fn ensureColumn(self: *Self, x: i64) !*Column {
if (self.columns.getPtr(x)) |c| {
return c;
}
try self.columns.put(x, Column.init(self.allocator));
return self.columns.getPtr(x).?;
}
pub fn set(self: *Self, c: i64, r: i64, value: Value) !void {
try self.ensureColumns(@intCast(usize, c) + 1);
try self.column(c).set(r, value);
pub fn get(self: Self, x: i64, y: i64) ?Value {
if (self.columns.get(x)) |c| {
return c.get(y);
}
return null;
}
pub fn set(self: *Self, x: i64, y: i64, value: Value) !void {
const c = try self.ensureColumn(x);
try c.set(y, value);
}
};
}

View File

@ -10,13 +10,13 @@ pub const GameScene = struct {
game: game.Game = undefined,
pub fn enter(self: *GameScene, ctx: *Context) void {
const level = game.Level.load(ctx.allocator, paths.AssetsDir ++ "/levels/level1.txt") catch unreachable;
self.game = game.Game.init(level, &ctx.renderer);
const level = game.Level.init(ctx.allocator, paths.AssetsDir ++ "/levels/level1.txt") catch unreachable;
self.game = game.Game.init(ctx.allocator, level, &ctx.renderer);
}
pub fn exit(self: *GameScene, ctx: *Context) void {
self.game.deinit();
_ = ctx;
_ = self;
}
pub fn handle(self: *GameScene, ctx: *Context, event: *allegro.Event) !void {
@ -68,20 +68,22 @@ pub const GameScene = struct {
var x = tileBounds.min.x;
while (x < tileBounds.max.x) : (x += 1) {
self.game.drawSpriteFrame("tiles_dirt_32", 0, x, 19);
self.game.drawSpriteFrame("tiles_dirt_32", 3, x, 20);
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);
if (x < 0) continue;
const tiles = self.game.level.tiles.column(x);
const collectables = self.game.level.collectables.column(x);
const tiles = self.game.level.tiles.ensureColumn(x) catch continue;
const collectables = self.game.level.collectables.ensureColumn(x) catch continue;
var y = tileBounds.min.y;
while (y < tileBounds.max.y) : (y += 1) {
if (tiles.get(y)) |tile| {
switch (tile) {
game.Level.Tile.Grass => {
self.game.drawSpriteFrame("tiles_grass_32", 1, x, y - 1);
self.game.drawSpriteFrame("tiles_grass_32", 5, x, y);
const randomOffset = self.game.randomTileOffset(x, y, 2);
self.game.drawSpriteFrame("tiles_grass_32", 1 + randomOffset, x, y - 1);
self.game.drawSpriteFrame("tiles_grass_32", 5 + randomOffset, x, y);
},
// else => {},
}