add fire animation
This commit is contained in:
parent
19e37f507d
commit
3c61d2164d
BIN
assets/fire/1.png
Normal file
BIN
assets/fire/1.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 2.6 KiB |
BIN
assets/fire/2.png
Normal file
BIN
assets/fire/2.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 4.8 KiB |
BIN
assets/fire/3.png
Normal file
BIN
assets/fire/3.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 4.4 KiB |
BIN
assets/fire/4.png
Normal file
BIN
assets/fire/4.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 2.8 KiB |
BIN
assets/fire/5.png
Normal file
BIN
assets/fire/5.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 5.3 KiB |
@ -12,7 +12,10 @@ pub fn build(b: *std.Build) !void {
|
|||||||
"Prototype_Character/Default/walk.png",
|
"Prototype_Character/Default/walk.png",
|
||||||
"Prototype_Character/Default/death.png",
|
"Prototype_Character/Default/death.png",
|
||||||
"font/pixeloid/PixeloidSans.ttf",
|
"font/pixeloid/PixeloidSans.ttf",
|
||||||
"tranquil_tunnels_transparent.png"
|
"tranquil_tunnels_transparent.png",
|
||||||
|
"fire/1.png",
|
||||||
|
"fire/2.png",
|
||||||
|
"fire/5.png",
|
||||||
};
|
};
|
||||||
|
|
||||||
const asset_dir_realpath = try b.build_root.join(b.graph.arena, &.{ assets_dir });
|
const asset_dir_realpath = try b.build_root.join(b.graph.arena, &.{ assets_dir });
|
||||||
|
|||||||
413
src/app.zig
413
src/app.zig
@ -43,11 +43,16 @@ font: Gfx.Font.Id,
|
|||||||
idle_animations: AnimationDirections,
|
idle_animations: AnimationDirections,
|
||||||
walk_animations: AnimationDirections,
|
walk_animations: AnimationDirections,
|
||||||
death_animations: AnimationDirections,
|
death_animations: AnimationDirections,
|
||||||
|
fire1_animation: Animation,
|
||||||
|
fire2_animation: Animation,
|
||||||
|
fire5_animation: Animation,
|
||||||
gradient_sprite: Gfx.Sprite.Id,
|
gradient_sprite: Gfx.Sprite.Id,
|
||||||
|
|
||||||
terrain_sheet: Tilesheet,
|
terrain_sheet: Tilesheet,
|
||||||
terrain_tiles: []Tile,
|
terrain_tiles: []Tile,
|
||||||
|
|
||||||
|
show_minion_state: bool = false,
|
||||||
|
|
||||||
const terrain_origin_x: i32 = -80;
|
const terrain_origin_x: i32 = -80;
|
||||||
const terrain_origin_y: i32 = -60;
|
const terrain_origin_y: i32 = -60;
|
||||||
const terrain_width = 160;
|
const terrain_width = 160;
|
||||||
@ -64,7 +69,9 @@ const Tilesheet = struct {
|
|||||||
width: u32,
|
width: u32,
|
||||||
height: u32,
|
height: u32,
|
||||||
|
|
||||||
pub fn init(gpa: Allocator, image: Gfx.ImageData, width: u32, height: u32, tile_size: Vec2) !Tilesheet {
|
pub fn init(gpa: Allocator, image: Gfx.ImageData, tile_size: Vec2) !Tilesheet {
|
||||||
|
const width = @divFloor(image.width, @as(u32, @intFromFloat(tile_size.x)));
|
||||||
|
const height = @divFloor(image.height, @as(u32, @intFromFloat(tile_size.y)));
|
||||||
const sprites = try gpa.alloc(Gfx.Sprite.Id, width * height);
|
const sprites = try gpa.alloc(Gfx.Sprite.Id, width * height);
|
||||||
errdefer gpa.free(sprites);
|
errdefer gpa.free(sprites);
|
||||||
@memset(sprites, Gfx.getNilSprite());
|
@memset(sprites, Gfx.getNilSprite());
|
||||||
@ -179,6 +186,8 @@ const Entity = struct {
|
|||||||
minion_carried_wood_len: u32 = 0,
|
minion_carried_wood_len: u32 = 0,
|
||||||
minion_wander_target: ?Vec2 = null,
|
minion_wander_target: ?Vec2 = null,
|
||||||
minion_wander_cooldown: Nanoseconds = 0,
|
minion_wander_cooldown: Nanoseconds = 0,
|
||||||
|
minion_animation: AnimationName = .idle,
|
||||||
|
minion_animation_dir: AnimationDirection = .down,
|
||||||
|
|
||||||
tree_health: u32 = 0,
|
tree_health: u32 = 0,
|
||||||
tree_visual_health: f32 = 0,
|
tree_visual_health: f32 = 0,
|
||||||
@ -195,12 +204,15 @@ const Entity = struct {
|
|||||||
wood_next_carried: ?EntityId = null,
|
wood_next_carried: ?EntityId = null,
|
||||||
wood_visual_pos: Vec2 = .init(0, 0),
|
wood_visual_pos: Vec2 = .init(0, 0),
|
||||||
|
|
||||||
|
eternal_flame_size: FlameSize = .small,
|
||||||
|
|
||||||
pos: Vec2 = .init(0, 0),
|
pos: Vec2 = .init(0, 0),
|
||||||
vel: Vec2 = .init(0, 0),
|
vel: Vec2 = .init(0, 0),
|
||||||
acc: Vec2 = .init(0, 0),
|
acc: Vec2 = .init(0, 0),
|
||||||
|
|
||||||
animation: AnimationName = .idle,
|
animation: ?Animation = null,
|
||||||
animation_dir: AnimationDirection = .down,
|
animation_rect: Rect = .init(0, 0, 0, 0),
|
||||||
|
animation_flip: bool = false,
|
||||||
animation_index: u32 = 0,
|
animation_index: u32 = 0,
|
||||||
animation_timer: Nanoseconds = 0,
|
animation_timer: Nanoseconds = 0,
|
||||||
|
|
||||||
@ -226,9 +238,14 @@ const Entity = struct {
|
|||||||
eternal_flame,
|
eternal_flame,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const FlameSize = enum {
|
||||||
|
small,
|
||||||
|
medium,
|
||||||
|
large,
|
||||||
|
};
|
||||||
|
|
||||||
const Flags = packed struct {
|
const Flags = packed struct {
|
||||||
has_kinematics: bool = false,
|
has_kinematics: bool = false,
|
||||||
has_animation: bool = false
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -436,35 +453,45 @@ pub fn init(self: *App, plt: Platform.Init) !?u8 {
|
|||||||
const idle_sheet = try Tilesheet.init(
|
const idle_sheet = try Tilesheet.init(
|
||||||
plt.arena,
|
plt.arena,
|
||||||
initImageDataFromSTB(try STBImage.load(plt.assets.readFile("Prototype_Character/Default/idle.png"))),
|
initImageDataFromSTB(try STBImage.load(plt.assets.readFile("Prototype_Character/Default/idle.png"))),
|
||||||
2,
|
|
||||||
3,
|
|
||||||
.init(32, 32)
|
.init(32, 32)
|
||||||
);
|
);
|
||||||
|
|
||||||
const walk_sheet = try Tilesheet.init(
|
const walk_sheet = try Tilesheet.init(
|
||||||
plt.arena,
|
plt.arena,
|
||||||
initImageDataFromSTB(try STBImage.load(plt.assets.readFile("Prototype_Character/Default/walk.png"))),
|
initImageDataFromSTB(try STBImage.load(plt.assets.readFile("Prototype_Character/Default/walk.png"))),
|
||||||
4,
|
|
||||||
3,
|
|
||||||
.init(32, 32)
|
.init(32, 32)
|
||||||
);
|
);
|
||||||
|
|
||||||
const death_sheet = try Tilesheet.init(
|
const death_sheet = try Tilesheet.init(
|
||||||
plt.arena,
|
plt.arena,
|
||||||
initImageDataFromSTB(try STBImage.load(plt.assets.readFile("Prototype_Character/Default/death.png"))),
|
initImageDataFromSTB(try STBImage.load(plt.assets.readFile("Prototype_Character/Default/death.png"))),
|
||||||
3,
|
|
||||||
3,
|
|
||||||
.init(32, 32)
|
.init(32, 32)
|
||||||
);
|
);
|
||||||
|
|
||||||
const terrain_sheet = try Tilesheet.init(
|
const terrain_sheet = try Tilesheet.init(
|
||||||
plt.arena,
|
plt.arena,
|
||||||
initImageDataFromSTB(try STBImage.load(plt.assets.readFile("tranquil_tunnels_transparent.png"))),
|
initImageDataFromSTB(try STBImage.load(plt.assets.readFile("tranquil_tunnels_transparent.png"))),
|
||||||
128,
|
|
||||||
128,
|
|
||||||
.init(8, 8)
|
.init(8, 8)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const fire1_sheet = try Tilesheet.init(
|
||||||
|
plt.arena,
|
||||||
|
initImageDataFromSTB(try STBImage.load(plt.assets.readFile("fire/1.png"))),
|
||||||
|
.init(16, 32)
|
||||||
|
);
|
||||||
|
|
||||||
|
const fire2_sheet = try Tilesheet.init(
|
||||||
|
plt.arena,
|
||||||
|
initImageDataFromSTB(try STBImage.load(plt.assets.readFile("fire/2.png"))),
|
||||||
|
.init(32, 48)
|
||||||
|
);
|
||||||
|
|
||||||
|
const fire5_sheet = try Tilesheet.init(
|
||||||
|
plt.arena,
|
||||||
|
initImageDataFromSTB(try STBImage.load(plt.assets.readFile("fire/5.png"))),
|
||||||
|
.init(32, 48)
|
||||||
|
);
|
||||||
|
|
||||||
const terrain_tiles = try plt.arena.alloc(Tile, terrain_width*terrain_height);
|
const terrain_tiles = try plt.arena.alloc(Tile, terrain_width*terrain_height);
|
||||||
|
|
||||||
const ns_per_s = std.time.ns_per_s;
|
const ns_per_s = std.time.ns_per_s;
|
||||||
@ -496,6 +523,36 @@ pub fn init(self: *App, plt: Platform.Init) !?u8 {
|
|||||||
.idle_animations = try AnimationDirections.init(plt.arena, idle_sheet, ns_per_s / idle_fps, 2),
|
.idle_animations = try AnimationDirections.init(plt.arena, idle_sheet, ns_per_s / idle_fps, 2),
|
||||||
.walk_animations = try AnimationDirections.init(plt.arena, walk_sheet, ns_per_s / walk_fps, 4),
|
.walk_animations = try AnimationDirections.init(plt.arena, walk_sheet, ns_per_s / walk_fps, 4),
|
||||||
.death_animations = try AnimationDirections.init(plt.arena, death_sheet, ns_per_s / death_fps, 3),
|
.death_animations = try AnimationDirections.init(plt.arena, death_sheet, ns_per_s / death_fps, 3),
|
||||||
|
.fire1_animation = try Animation.init(plt.arena, fire1_sheet, std.time.ns_per_ms * 100, &.{
|
||||||
|
.init(0, 0),
|
||||||
|
.init(1, 0),
|
||||||
|
.init(2, 0),
|
||||||
|
.init(3, 0),
|
||||||
|
.init(4, 0),
|
||||||
|
.init(5, 0),
|
||||||
|
.init(6, 0),
|
||||||
|
.init(7, 0),
|
||||||
|
}),
|
||||||
|
.fire2_animation = try Animation.init(plt.arena, fire2_sheet, std.time.ns_per_ms * 100, &.{
|
||||||
|
.init(0, 0),
|
||||||
|
.init(1, 0),
|
||||||
|
.init(2, 0),
|
||||||
|
.init(3, 0),
|
||||||
|
.init(4, 0),
|
||||||
|
.init(5, 0),
|
||||||
|
.init(6, 0),
|
||||||
|
.init(7, 0),
|
||||||
|
}),
|
||||||
|
.fire5_animation = try Animation.init(plt.arena, fire5_sheet, std.time.ns_per_ms * 100, &.{
|
||||||
|
.init(0, 0),
|
||||||
|
.init(1, 0),
|
||||||
|
.init(2, 0),
|
||||||
|
.init(3, 0),
|
||||||
|
.init(4, 0),
|
||||||
|
.init(5, 0),
|
||||||
|
.init(6, 0),
|
||||||
|
.init(7, 0),
|
||||||
|
}),
|
||||||
.entities_buffer = undefined,
|
.entities_buffer = undefined,
|
||||||
.entities = .init(&self.entities_buffer),
|
.entities = .init(&self.entities_buffer),
|
||||||
.prng = Prng.init(@truncate(@as(u96, @intCast(now.nanoseconds)))),
|
.prng = Prng.init(@truncate(@as(u96, @intCast(now.nanoseconds)))),
|
||||||
@ -518,7 +575,8 @@ pub fn init(self: *App, plt: Platform.Init) !?u8 {
|
|||||||
|
|
||||||
self.eternal_flame_id = self.spawnEntity(Entity{
|
self.eternal_flame_id = self.spawnEntity(Entity{
|
||||||
.type = .eternal_flame,
|
.type = .eternal_flame,
|
||||||
.pos = .init(200, 0)
|
.pos = .init(250, 0),
|
||||||
|
.eternal_flame_size = .large,
|
||||||
}).?;
|
}).?;
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
@ -695,16 +753,21 @@ fn spawnEntity(self: *App, e: Entity) ?EntityId {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn spawnMinion(self: *App, pos: Vec2) void {
|
pub fn spawnMinion(self: *App, pos: Vec2) void {
|
||||||
|
const character_size = Vec2.init(96, 96);
|
||||||
|
|
||||||
_ = self.spawnEntity(Entity{
|
_ = self.spawnEntity(Entity{
|
||||||
.type = .minion,
|
.type = .minion,
|
||||||
.flags = .{
|
.flags = .{
|
||||||
.has_animation = true,
|
|
||||||
.has_kinematics = true
|
.has_kinematics = true
|
||||||
},
|
},
|
||||||
|
|
||||||
.pos = pos,
|
.pos = pos,
|
||||||
|
|
||||||
.animation = .idle,
|
.minion_animation = .idle,
|
||||||
|
.animation_rect = .{
|
||||||
|
.pos = .init(-character_size.x/2, -character_size.y*0.7),
|
||||||
|
.size = character_size,
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -741,7 +804,7 @@ fn spawnTree(self: *App, station_id: EntityId) void {
|
|||||||
.tree_max_health = health,
|
.tree_max_health = health,
|
||||||
.seed = rng.int(u64),
|
.seed = rng.int(u64),
|
||||||
|
|
||||||
.pos = station.pos
|
.pos = station.pos.add(.init((rng.float(f32)-0.5) * terrain_tile_size.x, 0))
|
||||||
})) |id| {
|
})) |id| {
|
||||||
station.station_owned_tree = id;
|
station.station_owned_tree = id;
|
||||||
}
|
}
|
||||||
@ -1085,7 +1148,11 @@ fn minionLogic(self: *App, plt: Platform.Frame, minion_id: EntityId) !void {
|
|||||||
const wood = self.entities.getAssumeExists(wood_id);
|
const wood = self.entities.getAssumeExists(wood_id);
|
||||||
const eternal_flame = self.entities.getAssumeExists(self.eternal_flame_id);
|
const eternal_flame = self.entities.getAssumeExists(self.eternal_flame_id);
|
||||||
|
|
||||||
|
var rng = self.prng.random();
|
||||||
|
|
||||||
wood.pos = eternal_flame.pos;
|
wood.pos = eternal_flame.pos;
|
||||||
|
wood.pos.x += (rng.float(f32)-0.5) * 2 * 30;
|
||||||
|
wood.pos.y -= rng.float(f32) * 30;
|
||||||
wood.wood_burning = true;
|
wood.wood_burning = true;
|
||||||
threw_anything = true;
|
threw_anything = true;
|
||||||
}
|
}
|
||||||
@ -1391,6 +1458,8 @@ fn showDebug(self: *App, plt: Platform.Frame) !void {
|
|||||||
self.heat = @intCast(heat);
|
self.heat = @intCast(heat);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_ = ImGUI.checkbox("Minion state", &self.show_minion_state);
|
||||||
|
|
||||||
ImGUI.separator();
|
ImGUI.separator();
|
||||||
_ = ImGUI.text("Minion upgrades", .{});
|
_ = ImGUI.text("Minion upgrades", .{});
|
||||||
_ = ImGUI.inputU32("count", &self.upgrades.minion_count);
|
_ = ImGUI.inputU32("count", &self.upgrades.minion_count);
|
||||||
@ -1469,7 +1538,7 @@ fn showDebug(self: *App, plt: Platform.Frame) !void {
|
|||||||
var minion_iter = self.initEntityIteratorByType(.minion);
|
var minion_iter = self.initEntityIteratorByType(.minion);
|
||||||
while (minion_iter.next()) |minion_id| {
|
while (minion_iter.next()) |minion_id| {
|
||||||
const minion = self.entities.getAssumeExists(minion_id);
|
const minion = self.entities.getAssumeExists(minion_id);
|
||||||
ImGUI.text("{f}, wood_head: {?f}", .{minion_id, minion.minion_carried_wood_head});
|
ImGUI.text("{f}, len: {}, wood_head: {?f}", .{minion_id, minion.minion_carried_wood_len, minion.minion_carried_wood_head});
|
||||||
}
|
}
|
||||||
|
|
||||||
ImGUI.separator();
|
ImGUI.separator();
|
||||||
@ -1479,6 +1548,16 @@ fn showDebug(self: *App, plt: Platform.Frame) !void {
|
|||||||
ImGUI.text("{f}, carried_by: {?f}, next: {?f}", .{wood_id, wood.wood_carried_by, wood.wood_next_carried});
|
ImGUI.text("{f}, carried_by: {?f}, next: {?f}", .{wood_id, wood.wood_carried_by, wood.wood_next_carried});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (ImGUI.beginTabItem("Minions")) {
|
||||||
|
defer ImGUI.endTabItem();
|
||||||
|
|
||||||
|
var minion_iter = self.initEntityIteratorByType(.minion);
|
||||||
|
while (minion_iter.next()) |minion_id| {
|
||||||
|
const minion = self.entities.getAssumeExists(minion_id);
|
||||||
|
ImGUI.text("{f}, animation: {}, acc: {}, vel: {}", .{minion_id, minion.minion_animation, minion.acc.length(), minion.vel.length()});
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1490,7 +1569,6 @@ fn drawTree(self: *App, seed: u64, pos: Vec2, health_percent: f32) void {
|
|||||||
defer Gfx.transformPop();
|
defer Gfx.transformPop();
|
||||||
|
|
||||||
Gfx.transformTranslate(pos);
|
Gfx.transformTranslate(pos);
|
||||||
Gfx.transformTranslate(.init((rng.float(f32)-0.5) * terrain_tile_size.x, 0));
|
|
||||||
|
|
||||||
{
|
{
|
||||||
Gfx.transformPush();
|
Gfx.transformPush();
|
||||||
@ -1553,6 +1631,28 @@ fn drawTree(self: *App, seed: u64, pos: Vec2, health_percent: f32) void {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn drawEntityAnimation(self: *App, e: *Entity, dt: Nanoseconds) void {
|
||||||
|
_ = self; // autofix
|
||||||
|
if (e.animation) |animation| {
|
||||||
|
e.animation_timer += dt;
|
||||||
|
while (e.animation_timer >= animation.frame_duration) {
|
||||||
|
e.animation_timer -= animation.frame_duration;
|
||||||
|
e.animation_index += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
e.animation_index = e.animation_index % @as(u32, @intCast(animation.frames.len));
|
||||||
|
const sprite = animation.frames[e.animation_index];
|
||||||
|
|
||||||
|
var rect = e.animation_rect;
|
||||||
|
if (e.animation_flip) {
|
||||||
|
rect.pos.x += rect.size.x;
|
||||||
|
rect.size.x *= -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
Gfx.drawSprite(sprite, e.pos.add(rect.pos), rect.size, .white);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn frame(self: *App, plt: Platform.Frame) !void {
|
pub fn frame(self: *App, plt: Platform.Frame) !void {
|
||||||
const input = plt.input;
|
const input = plt.input;
|
||||||
_ = input; // autofix
|
_ = input; // autofix
|
||||||
@ -1655,6 +1755,17 @@ pub fn frame(self: *App, plt: Platform.Frame) !void {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
var minion_iter = self.initEntityIteratorByType(.minion);
|
||||||
|
while (minion_iter.next()) |minion_id| {
|
||||||
|
const minion = self.entities.getAssumeExists(minion_id);
|
||||||
|
|
||||||
|
if (minion.minion_state == .wander and minion.target_entity != null) {
|
||||||
|
self.unsetEntityTarget(minion_id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
{ // Ensure that `target_entity` and `targeted_by_entity` don't point to dead entities
|
{ // Ensure that `target_entity` and `targeted_by_entity` don't point to dead entities
|
||||||
var entity_iter = self.entities.iterator();
|
var entity_iter = self.entities.iterator();
|
||||||
while (entity_iter.next()) |entity_id| {
|
while (entity_iter.next()) |entity_id| {
|
||||||
@ -1722,6 +1833,27 @@ pub fn frame(self: *App, plt: Platform.Frame) !void {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
{ // Each burn station will assign itself to the nearest minion that has wood
|
||||||
|
var burn_station_iter = self.initEntityIteratorByType(.burn_station);
|
||||||
|
while (burn_station_iter.next()) |burn_station_id| {
|
||||||
|
const burn_station = self.entities.getAssumeExists(burn_station_id);
|
||||||
|
if (burn_station.targeted_by_entity != null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
var minion_iter = self.initNearestEntityIter(.minion, burn_station.pos, plt.arena);
|
||||||
|
while (try minion_iter.next()) |minion_id| {
|
||||||
|
const minion = self.entities.getAssumeExists(minion_id);
|
||||||
|
const state = minion.minion_state;
|
||||||
|
if (state == .wander and minion.minion_carried_wood_len == self.upgrades.minion_carry_capacity) {
|
||||||
|
self.setEntityTarget(minion_id, burn_station_id);
|
||||||
|
minion.minion_state = .goto_burn_station;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
{ // Each tree entity will assign itself to the nearest minion that isn't busy
|
{ // Each tree entity will assign itself to the nearest minion that isn't busy
|
||||||
var tree_iter = self.initEntityIteratorByType(.tree);
|
var tree_iter = self.initEntityIteratorByType(.tree);
|
||||||
while (tree_iter.next()) |tree_id| {
|
while (tree_iter.next()) |tree_id| {
|
||||||
@ -1786,51 +1918,79 @@ pub fn frame(self: *App, plt: Platform.Frame) !void {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
{ // Each burn station will assign itself to the nearest minion that has wood
|
{ // Clear acceleration
|
||||||
var burn_station_iter = self.initEntityIteratorByType(.burn_station);
|
var entity_iter = self.entities.iterator();
|
||||||
while (burn_station_iter.next()) |burn_station_id| {
|
while (entity_iter.next()) |id| {
|
||||||
const burn_station = self.entities.getAssumeExists(burn_station_id);
|
const e = self.entities.getAssumeExists(id);
|
||||||
if (burn_station.targeted_by_entity != null) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
var minion_iter = self.initNearestEntityIter(.minion, burn_station.pos, plt.arena);
|
if (e.flags.has_kinematics) {
|
||||||
while (try minion_iter.next()) |minion_id| {
|
e.acc = .init(0, 0);
|
||||||
const minion = self.entities.getAssumeExists(minion_id);
|
|
||||||
const state = minion.minion_state;
|
|
||||||
if (state == .wander and minion.minion_carried_wood_len == self.upgrades.minion_carry_capacity) {
|
|
||||||
self.setEntityTarget(minion_id, burn_station_id);
|
|
||||||
minion.minion_state = .goto_burn_station;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{ // Minion logic & animations
|
||||||
var minion_iter = self.entities.iterator();
|
var minion_iter = self.initEntityIteratorByType(.minion);
|
||||||
while (minion_iter.next()) |minion_id| {
|
while (minion_iter.next()) |minion_id| {
|
||||||
const minion = self.entities.getAssumeExists(minion_id);
|
const minion = self.entities.getAssumeExists(minion_id);
|
||||||
if (minion.type != .minion) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
try self.minionLogic(plt, minion_id);
|
try self.minionLogic(plt, minion_id);
|
||||||
|
|
||||||
if (minion.acc.x > 0) {
|
if (minion.acc.x > 0) {
|
||||||
minion.animation = .walk;
|
minion.minion_animation = .walk;
|
||||||
minion.animation_dir = .right;
|
minion.minion_animation_dir = .right;
|
||||||
} else if (minion.acc.x < 0) {
|
} else if (minion.acc.x < 0) {
|
||||||
minion.animation = .walk;
|
minion.minion_animation = .walk;
|
||||||
minion.animation_dir = .left;
|
minion.minion_animation_dir = .left;
|
||||||
} else {
|
} else {
|
||||||
minion.animation = .idle;
|
minion.minion_animation = .idle;
|
||||||
minion.animation_dir = .down;
|
minion.minion_animation_dir = .down;
|
||||||
|
}
|
||||||
|
|
||||||
|
const animations = switch (minion.minion_animation) {
|
||||||
|
.idle => self.idle_animations,
|
||||||
|
.walk => self.walk_animations,
|
||||||
|
.death => self.death_animations
|
||||||
|
};
|
||||||
|
|
||||||
|
minion.animation_flip = false;
|
||||||
|
minion.animation = switch (minion.minion_animation_dir) {
|
||||||
|
.right => animations.right,
|
||||||
|
.up => animations.up,
|
||||||
|
.down => animations.down,
|
||||||
|
.left => blk: {
|
||||||
|
minion.animation_flip = true;
|
||||||
|
break :blk animations.right;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
{ // Apply kinamatics
|
||||||
|
var entity_iter = self.entities.iterator();
|
||||||
|
while (entity_iter.next()) |id| {
|
||||||
|
const e = self.entities.getAssumeExists(id);
|
||||||
|
|
||||||
|
if (e.flags.has_kinematics) {
|
||||||
|
e.vel = e.vel.add(e.acc.multiplyScalar(dt));
|
||||||
|
e.pos = e.pos.add(e.vel.multiplyScalar(dt));
|
||||||
|
|
||||||
|
e.pos.y = @min(e.pos.y, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (e.type == .minion) {
|
||||||
|
const stats = self.upgrades.minion_walk;
|
||||||
|
e.vel = e.vel.limitLength(stats.max_velocity);
|
||||||
|
|
||||||
|
if (0 <= stats.friction and stats.friction <= 1) {
|
||||||
|
const friction_force = std.math.pow(f32, 1 - stats.friction, dt);
|
||||||
|
e.vel = e.vel.multiplyScalar(friction_force);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{ // Wood position follow
|
||||||
var wood_iter = self.initEntityIteratorByType(.wood);
|
var wood_iter = self.initEntityIteratorByType(.wood);
|
||||||
while (wood_iter.next()) |wood_id| {
|
while (wood_iter.next()) |wood_id| {
|
||||||
const wood = self.entities.getAssumeExists(wood_id);
|
const wood = self.entities.getAssumeExists(wood_id);
|
||||||
@ -1895,86 +2055,97 @@ pub fn frame(self: *App, plt: Platform.Frame) !void {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const character_size = Vec2.init(96, 96);
|
|
||||||
{
|
|
||||||
var entity_iter = self.entities.iterator();
|
|
||||||
while (entity_iter.next()) |id| {
|
|
||||||
const e = self.entities.getAssumeExists(id);
|
|
||||||
|
|
||||||
if (e.flags.has_kinematics) {
|
|
||||||
e.vel = e.vel.add(e.acc.multiplyScalar(dt));
|
|
||||||
e.pos = e.pos.add(e.vel.multiplyScalar(dt));
|
|
||||||
|
|
||||||
e.pos.y = @min(e.pos.y, 0);
|
|
||||||
|
|
||||||
e.acc = .init(0, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (e.type == .minion) {
|
|
||||||
const stats = self.upgrades.minion_walk;
|
|
||||||
e.vel = e.vel.limitLength(stats.max_velocity);
|
|
||||||
|
|
||||||
if (0 <= stats.friction and stats.friction <= 1) {
|
|
||||||
const friction_force = std.math.pow(f32, 1 - stats.friction, dt);
|
|
||||||
e.vel = e.vel.multiplyScalar(friction_force);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (e.flags.has_animation) {
|
|
||||||
const animations = switch (e.animation) {
|
|
||||||
.idle => self.idle_animations,
|
|
||||||
.walk => self.walk_animations,
|
|
||||||
.death => self.death_animations
|
|
||||||
};
|
|
||||||
var flip_animation = false;
|
|
||||||
const animation = switch (e.animation_dir) {
|
|
||||||
.right => animations.right,
|
|
||||||
.up => animations.up,
|
|
||||||
.down => animations.down,
|
|
||||||
.left => blk: {
|
|
||||||
flip_animation = true;
|
|
||||||
break :blk animations.right;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
e.animation_timer += plt.dt;
|
|
||||||
while (e.animation_timer >= animation.frame_duration) {
|
|
||||||
e.animation_timer -= animation.frame_duration;
|
|
||||||
e.animation_index += 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
e.animation_index = e.animation_index % @as(u32, @intCast(animation.frames.len));
|
|
||||||
const sprite = animation.frames[e.animation_index];
|
|
||||||
|
|
||||||
var size = character_size;
|
|
||||||
var pos = e.pos;
|
|
||||||
pos.y -= character_size.y*0.7;
|
|
||||||
if (flip_animation) {
|
|
||||||
size.x *= -1;
|
|
||||||
pos.x += character_size.x/2;
|
|
||||||
} else {
|
|
||||||
pos.x -= character_size.x/2;
|
|
||||||
}
|
|
||||||
|
|
||||||
Gfx.drawSprite(sprite, pos, size, .white);
|
|
||||||
|
|
||||||
if (e.type == .minion and e.minion_state == .burn_wood and e.minion_throw_cooldown > 0) {
|
|
||||||
Gfx.drawRectangle(e.pos.sub(.init(5, 65)), .init(10, 10), .rgb(200, 20, 20));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (e.type == .burn_station) {
|
|
||||||
Gfx.drawRectangle(e.pos.sub(.init(5, 5)), .init(10, 10), .rgb(200, 20, 20));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
{ // Draw eternal flame
|
{ // Draw eternal flame
|
||||||
var eternal_flame_iter = self.initEntityIteratorByType(.eternal_flame);
|
var eternal_flame_iter = self.initEntityIteratorByType(.eternal_flame);
|
||||||
while (eternal_flame_iter.next()) |id| {
|
while (eternal_flame_iter.next()) |id| {
|
||||||
const eternal_flame = self.entities.getAssumeExists(id);
|
const eternal_flame = self.entities.getAssumeExists(id);
|
||||||
|
|
||||||
Gfx.drawRectangle(eternal_flame.pos.sub(.init(10, 50)), .init(30, 50), .rgb(150, 30, 20));
|
{ // Draw holder
|
||||||
|
Gfx.transformPush();
|
||||||
|
defer Gfx.transformPop();
|
||||||
|
Gfx.transformTranslate(eternal_flame.pos);
|
||||||
|
Gfx.transformScale(terrain_tile_size);
|
||||||
|
Gfx.transformTranslate(.init(-1.5, -1));
|
||||||
|
|
||||||
|
Gfx.drawSprite(
|
||||||
|
self.terrain_sheet.get(118, 90),
|
||||||
|
.init(0, 0),
|
||||||
|
.init(1, 1),
|
||||||
|
.white
|
||||||
|
);
|
||||||
|
Gfx.drawSprite(
|
||||||
|
self.terrain_sheet.get(119, 90),
|
||||||
|
.init(1, 0),
|
||||||
|
.init(1, 1),
|
||||||
|
.white
|
||||||
|
);
|
||||||
|
Gfx.drawSprite(
|
||||||
|
self.terrain_sheet.get(120, 90),
|
||||||
|
.init(2, 0),
|
||||||
|
.init(1, 1),
|
||||||
|
.white
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (eternal_flame.eternal_flame_size) {
|
||||||
|
.small => {
|
||||||
|
const flame_size = Vec2.init(16, 32).multiplyScalar(4);
|
||||||
|
eternal_flame.animation = self.fire1_animation;
|
||||||
|
eternal_flame.animation_rect = .init(-flame_size.x/2, -flame_size.y, flame_size.x, flame_size.y);
|
||||||
|
},
|
||||||
|
.medium => {
|
||||||
|
const flame_size = Vec2.init(32, 48).multiplyScalar(4);
|
||||||
|
eternal_flame.animation = self.fire2_animation;
|
||||||
|
eternal_flame.animation_rect = .init(-flame_size.x/2, -flame_size.y, flame_size.x, flame_size.y);
|
||||||
|
},
|
||||||
|
.large => {
|
||||||
|
const flame_size = Vec2.init(32, 48).multiplyScalar(4);
|
||||||
|
eternal_flame.animation = self.fire5_animation;
|
||||||
|
eternal_flame.animation_rect = .init(-flame_size.x/2, -flame_size.y, flame_size.x, flame_size.y);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
self.drawEntityAnimation(eternal_flame, plt.dt);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
var entity_iter = self.entities.iterator();
|
||||||
|
while (entity_iter.next()) |id| {
|
||||||
|
const e = self.entities.getAssumeExists(id);
|
||||||
|
|
||||||
|
if (e.type != .eternal_flame) {
|
||||||
|
self.drawEntityAnimation(e, plt.dt);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (e.type == .minion and e.minion_state == .burn_wood and e.minion_throw_cooldown > 0) {
|
||||||
|
Gfx.drawRectangle(e.pos.sub(.init(5, 65)), .init(10, 10), .rgb(200, 20, 20));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (e.type == .burn_station) {
|
||||||
|
Gfx.drawSprite(
|
||||||
|
self.terrain_sheet.get(123, 81),
|
||||||
|
e.pos.sub(.init(terrain_tile_size.x/2, terrain_tile_size.y)),
|
||||||
|
terrain_tile_size,
|
||||||
|
.white
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (e.type == .minion and self.show_minion_state) {
|
||||||
|
Gfx.drawText(self.font, .{
|
||||||
|
.height = 16,
|
||||||
|
.text = try std.fmt.allocPrint(plt.arena, "{}", .{e.minion_state}),
|
||||||
|
.pos = e.pos.add(.init(0, 20)),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
{ // Draw eternal flame stats
|
||||||
|
var eternal_flame_iter = self.initEntityIteratorByType(.eternal_flame);
|
||||||
|
while (eternal_flame_iter.next()) |id| {
|
||||||
|
const eternal_flame = self.entities.getAssumeExists(id);
|
||||||
|
|
||||||
Gfx.drawText(self.font, .{
|
Gfx.drawText(self.font, .{
|
||||||
.text = try std.fmt.allocPrint(plt.arena, "Stack: {}", .{self.countEternalFlameStackSize()}),
|
.text = try std.fmt.allocPrint(plt.arena, "Stack: {}", .{self.countEternalFlameStackSize()}),
|
||||||
.pos = eternal_flame.pos.sub(.init(10, 80)),
|
.pos = eternal_flame.pos.sub(.init(10, 80)),
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user