add gun with mouse control
This commit is contained in:
parent
2a55252942
commit
1220b36531
@ -7,6 +7,8 @@ const Engine = @import("./engine/root.zig");
|
|||||||
const STBImage = @import("stb_image");
|
const STBImage = @import("stb_image");
|
||||||
const Gfx = Engine.Graphics;
|
const Gfx = Engine.Graphics;
|
||||||
const Audio = Engine.Audio;
|
const Audio = Engine.Audio;
|
||||||
|
const Vec2 = Engine.Vec2;
|
||||||
|
const Rect = Engine.Math.Rect;
|
||||||
|
|
||||||
const Assets = @This();
|
const Assets = @This();
|
||||||
|
|
||||||
@ -18,18 +20,34 @@ const FontName = enum {
|
|||||||
const EnumArray = std.EnumArray(FontName, Gfx.Font.Id);
|
const EnumArray = std.EnumArray(FontName, Gfx.Font.Id);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
pub const Tilemap = struct {
|
||||||
|
texture: Gfx.TextureId,
|
||||||
|
tile_size: Engine.Vec2,
|
||||||
|
|
||||||
|
|
||||||
|
pub fn getTileUV(self: Tilemap, tile_x: f32, tile_y: f32) Rect {
|
||||||
|
const texture_info = Engine.Graphics.getTextureInfo(self.texture);
|
||||||
|
const tilemap_size = Vec2.initFromInt(u32, texture_info.width, texture_info.height);
|
||||||
|
|
||||||
|
return .{
|
||||||
|
.pos = Vec2.init(tile_x, tile_y).multiply(self.tile_size).divide(tilemap_size),
|
||||||
|
.size = self.tile_size.divide(tilemap_size),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
arena: std.heap.ArenaAllocator,
|
arena: std.heap.ArenaAllocator,
|
||||||
|
|
||||||
font_id: FontName.EnumArray,
|
font_id: FontName.EnumArray,
|
||||||
wood01: Audio.Data.Id,
|
wood01: Audio.Data.Id,
|
||||||
map: tiled.Tilemap,
|
map: tiled.Tilemap,
|
||||||
tilesets: tiled.Tileset.List,
|
tilesets: tiled.Tileset.List,
|
||||||
tileset_texture: Gfx.TextureId,
|
|
||||||
players_texture: Gfx.TextureId,
|
|
||||||
tile_size: Engine.Vec2,
|
|
||||||
player_size: Engine.Vec2,
|
|
||||||
move_sound: []Audio.Data.Id,
|
move_sound: []Audio.Data.Id,
|
||||||
|
|
||||||
|
terrain_tilemap: Tilemap,
|
||||||
|
players_tilemap: Tilemap,
|
||||||
|
weapons_tilemap: Tilemap,
|
||||||
|
|
||||||
pub fn init(gpa: std.mem.Allocator) !Assets {
|
pub fn init(gpa: std.mem.Allocator) !Assets {
|
||||||
var arena = std.heap.ArenaAllocator.init(gpa);
|
var arena = std.heap.ArenaAllocator.init(gpa);
|
||||||
errdefer arena.deinit();
|
errdefer arena.deinit();
|
||||||
@ -88,6 +106,16 @@ pub fn init(gpa: std.mem.Allocator) !Assets {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const weapons_tileset = try STBImage.load(@embedFile("assets/kenney_desert-shooter-pack_1.0/PNG/Weapons/tilemap_packed.png"));
|
||||||
|
defer weapons_tileset.deinit();
|
||||||
|
const weapons_texture = try Gfx.addTexture(&.{
|
||||||
|
.{
|
||||||
|
.width = weapons_tileset.width,
|
||||||
|
.height = weapons_tileset.height,
|
||||||
|
.rgba = weapons_tileset.rgba8_pixels
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
const move_c = try Audio.load(.{
|
const move_c = try Audio.load(.{
|
||||||
.data = @embedFile("assets/kenney_desert-shooter-pack_1.0/Sounds/move-c.ogg"),
|
.data = @embedFile("assets/kenney_desert-shooter-pack_1.0/Sounds/move-c.ogg"),
|
||||||
.format = .vorbis,
|
.format = .vorbis,
|
||||||
@ -104,11 +132,19 @@ pub fn init(gpa: std.mem.Allocator) !Assets {
|
|||||||
.wood01 = wood01,
|
.wood01 = wood01,
|
||||||
.map = map,
|
.map = map,
|
||||||
.tilesets = tilesets,
|
.tilesets = tilesets,
|
||||||
.tileset_texture = tileset_texture,
|
.move_sound = move_sound,
|
||||||
.tile_size = .init(16, 16),
|
.terrain_tilemap = .{
|
||||||
.players_texture = players_texture,
|
.texture = tileset_texture,
|
||||||
.player_size = .init(24, 24),
|
.tile_size = .initFromInt(u32, tileset.tile_width, tileset.tile_height)
|
||||||
.move_sound = move_sound
|
},
|
||||||
|
.players_tilemap = .{
|
||||||
|
.texture = players_texture,
|
||||||
|
.tile_size = .init(24, 24)
|
||||||
|
},
|
||||||
|
.weapons_tilemap = .{
|
||||||
|
.texture = weapons_texture,
|
||||||
|
.tile_size = .init(24, 24)
|
||||||
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -14,6 +14,7 @@ const GraphicsSystem = @import("./graphics.zig");
|
|||||||
const TextureId = GraphicsSystem.TextureId;
|
const TextureId = GraphicsSystem.TextureId;
|
||||||
const GraphicsCommand = GraphicsSystem.Command;
|
const GraphicsCommand = GraphicsSystem.Command;
|
||||||
const Font = GraphicsSystem.Font;
|
const Font = GraphicsSystem.Font;
|
||||||
|
const Sprite = GraphicsSystem.Sprite;
|
||||||
|
|
||||||
const Math = @import("./math.zig");
|
const Math = @import("./math.zig");
|
||||||
const Rect = Math.Rect;
|
const Rect = Math.Rect;
|
||||||
@ -110,6 +111,7 @@ audio: Audio,
|
|||||||
graphics: Graphics,
|
graphics: Graphics,
|
||||||
|
|
||||||
show_debug: bool,
|
show_debug: bool,
|
||||||
|
hide_cursor: bool,
|
||||||
|
|
||||||
pub fn init(self: *Frame, gpa: std.mem.Allocator) void {
|
pub fn init(self: *Frame, gpa: std.mem.Allocator) void {
|
||||||
self.* = Frame{
|
self.* = Frame{
|
||||||
@ -119,7 +121,8 @@ pub fn init(self: *Frame, gpa: std.mem.Allocator) void {
|
|||||||
.input = .empty,
|
.input = .empty,
|
||||||
.audio = .empty,
|
.audio = .empty,
|
||||||
.graphics = .empty,
|
.graphics = .empty,
|
||||||
.show_debug = false
|
.show_debug = false,
|
||||||
|
.hide_cursor = false
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -131,6 +134,10 @@ pub fn deltaTime(self: Frame) f32 {
|
|||||||
return @as(f32, @floatFromInt(self.dt_ns)) / std.time.ns_per_s;
|
return @as(f32, @floatFromInt(self.dt_ns)) / std.time.ns_per_s;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn time(self: Frame) f64 {
|
||||||
|
return @as(f64, @floatFromInt(self.time_ns)) / std.time.ns_per_s;
|
||||||
|
}
|
||||||
|
|
||||||
pub fn isKeyDown(self: Frame, key_code: KeyCode) bool {
|
pub fn isKeyDown(self: Frame, key_code: KeyCode) bool {
|
||||||
return self.input.down_keys.contains(key_code);
|
return self.input.down_keys.contains(key_code);
|
||||||
}
|
}
|
||||||
@ -214,15 +221,6 @@ pub fn popScissor(self: *Frame) void {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const DrawRectangleOptions = struct {
|
|
||||||
rect: Rect,
|
|
||||||
color: Vec4,
|
|
||||||
texture: ?struct {
|
|
||||||
id: TextureId,
|
|
||||||
uv: Rect,
|
|
||||||
} = null
|
|
||||||
};
|
|
||||||
|
|
||||||
pub fn drawRectangle(self: *Frame, opts: GraphicsCommand.DrawRectangle) void {
|
pub fn drawRectangle(self: *Frame, opts: GraphicsCommand.DrawRectangle) void {
|
||||||
self.pushGraphicsCommand(.{ .draw_rectangle = opts });
|
self.pushGraphicsCommand(.{ .draw_rectangle = opts });
|
||||||
}
|
}
|
||||||
|
|||||||
@ -45,10 +45,9 @@ pub const Command = union(enum) {
|
|||||||
pub const DrawRectangle = struct {
|
pub const DrawRectangle = struct {
|
||||||
rect: Rect,
|
rect: Rect,
|
||||||
color: Vec4,
|
color: Vec4,
|
||||||
texture: ?struct {
|
sprite: ?Sprite = null,
|
||||||
id: TextureId,
|
rotation: f32 = 0,
|
||||||
uv: Rect,
|
origin: Vec2 = .init(0, 0),
|
||||||
} = null
|
|
||||||
};
|
};
|
||||||
|
|
||||||
set_scissor: Rect,
|
set_scissor: Rect,
|
||||||
@ -93,6 +92,11 @@ const Texture = struct {
|
|||||||
pub const TextureId = Texture.Id;
|
pub const TextureId = Texture.Id;
|
||||||
pub const TextureInfo = Texture.Info;
|
pub const TextureInfo = Texture.Info;
|
||||||
|
|
||||||
|
pub const Sprite = struct {
|
||||||
|
texture: TextureId,
|
||||||
|
uv: Rect,
|
||||||
|
};
|
||||||
|
|
||||||
var gpa: std.mem.Allocator = undefined;
|
var gpa: std.mem.Allocator = undefined;
|
||||||
|
|
||||||
var main_pipeline: sgl.Pipeline = .{};
|
var main_pipeline: sgl.Pipeline = .{};
|
||||||
@ -352,38 +356,38 @@ fn drawRectangle(opts: Command.DrawRectangle) void {
|
|||||||
const pos = opts.rect.pos;
|
const pos = opts.rect.pos;
|
||||||
const size = opts.rect.size;
|
const size = opts.rect.size;
|
||||||
|
|
||||||
const top_left = pos;
|
const top_left = Vec2.init(0, 0).rotateAround(opts.rotation, opts.origin);
|
||||||
const top_right = pos.add(.{ .x = size.x, .y = 0 });
|
const top_right = Vec2.init(size.x, 0).rotateAround(opts.rotation, opts.origin);
|
||||||
const bottom_right = pos.add(size);
|
const bottom_right = size.rotateAround(opts.rotation, opts.origin);
|
||||||
const bottom_left = pos.add(.{ .x = 0, .y = size.y });
|
const bottom_left = Vec2.init(0, size.y).rotateAround(opts.rotation, opts.origin);
|
||||||
|
|
||||||
if (opts.texture) |texture| {
|
if (opts.sprite) |sprite| {
|
||||||
const uv = texture.uv;
|
const uv = sprite.uv;
|
||||||
const quad = [4]Vertex{
|
const quad = [4]Vertex{
|
||||||
.{
|
.{
|
||||||
.pos = top_left,
|
.pos = pos.add(top_left),
|
||||||
.uv = .init(uv.left(), uv.top())
|
.uv = .init(uv.left(), uv.top())
|
||||||
},
|
},
|
||||||
.{
|
.{
|
||||||
.pos = top_right,
|
.pos = pos.add(top_right),
|
||||||
.uv = .init(uv.right(), uv.top())
|
.uv = .init(uv.right(), uv.top())
|
||||||
},
|
},
|
||||||
.{
|
.{
|
||||||
.pos = bottom_right,
|
.pos = pos.add(bottom_right),
|
||||||
.uv = .init(uv.right(), uv.bottom())
|
.uv = .init(uv.right(), uv.bottom())
|
||||||
},
|
},
|
||||||
.{
|
.{
|
||||||
.pos = bottom_left,
|
.pos = pos.add(bottom_left),
|
||||||
.uv = .init(uv.left(), uv.bottom())
|
.uv = .init(uv.left(), uv.bottom())
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
drawQuad(quad, opts.color, texture.id);
|
drawQuad(quad, opts.color, sprite.texture);
|
||||||
} else {
|
} else {
|
||||||
const quad = .{
|
const quad = .{
|
||||||
top_left,
|
pos.add(top_left),
|
||||||
top_right,
|
pos.add(top_right),
|
||||||
bottom_right,
|
pos.add(bottom_right),
|
||||||
bottom_left
|
pos.add(bottom_left)
|
||||||
};
|
};
|
||||||
drawQuadNoUVs(quad, opts.color);
|
drawQuadNoUVs(quad, opts.color);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -63,6 +63,21 @@ pub const Vec2 = extern struct {
|
|||||||
return Vec2.init(-self.y, self.x);
|
return Vec2.init(-self.y, self.x);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn rotate(self: Vec2, angle: f32) Vec2 {
|
||||||
|
return init(
|
||||||
|
@cos(angle) * self.x - @sin(angle) * self.y,
|
||||||
|
@sin(angle) * self.x + @cos(angle) * self.y,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn rotateAround(self: Vec2, angle: f32, origin: Vec2) Vec2 {
|
||||||
|
return self.sub(origin).rotate(angle).add(origin);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn getAngle(self: Vec2) f32 {
|
||||||
|
return std.math.atan2(self.y, self.x);
|
||||||
|
}
|
||||||
|
|
||||||
pub fn flip(self: Vec2) Vec2 {
|
pub fn flip(self: Vec2) Vec2 {
|
||||||
return Vec2.init(-self.x, -self.y);
|
return Vec2.init(-self.x, -self.y);
|
||||||
}
|
}
|
||||||
@ -120,7 +135,10 @@ pub const Vec2 = extern struct {
|
|||||||
pub fn limitLength(self: Vec2, max_length: f32) Vec2 {
|
pub fn limitLength(self: Vec2, max_length: f32) Vec2 {
|
||||||
const self_length = self.length();
|
const self_length = self.length();
|
||||||
if (self_length > max_length) {
|
if (self_length > max_length) {
|
||||||
return Vec2.init(self.x / self_length * max_length, self.y / self_length * max_length);
|
if (self_length == 0) {
|
||||||
|
return Vec2.init(0, 0);
|
||||||
|
}
|
||||||
|
return self.divideScalar(self_length / max_length);
|
||||||
} else {
|
} else {
|
||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
@ -131,7 +149,7 @@ pub const Vec2 = extern struct {
|
|||||||
if (self_length == 0) {
|
if (self_length == 0) {
|
||||||
return Vec2.init(0, 0);
|
return Vec2.init(0, 0);
|
||||||
}
|
}
|
||||||
return Vec2.init(self.x / self_length, self.y / self_length);
|
return self.divideScalar(self_length);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn initScalar(value: f32) Vec2 {
|
pub fn initScalar(value: f32) Vec2 {
|
||||||
|
|||||||
@ -39,6 +39,8 @@ game: Game,
|
|||||||
assets: Assets,
|
assets: Assets,
|
||||||
frame: Frame,
|
frame: Frame,
|
||||||
|
|
||||||
|
canvas_size: ?Vec2 = null,
|
||||||
|
|
||||||
const RunOptions = struct {
|
const RunOptions = struct {
|
||||||
window_title: [*:0]const u8 = "Game",
|
window_title: [*:0]const u8 = "Game",
|
||||||
window_width: u31 = 640,
|
window_width: u31 = 640,
|
||||||
@ -161,6 +163,16 @@ fn sokolFrame(self: *Engine) !void {
|
|||||||
|
|
||||||
const screen_size = Vec2.init(sapp.widthf(), sapp.heightf());
|
const screen_size = Vec2.init(sapp.widthf(), sapp.heightf());
|
||||||
|
|
||||||
|
var revert_mouse_position: ?Vec2 = null;
|
||||||
|
if (self.canvas_size) |canvas_size| {
|
||||||
|
if (self.frame.input.mouse.position) |mouse| {
|
||||||
|
const transform = ScreenScalar.init(screen_size, canvas_size);
|
||||||
|
|
||||||
|
revert_mouse_position = mouse;
|
||||||
|
self.frame.input.mouse.position = mouse.sub(transform.translation).divideScalar(transform.scale);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
_ = frame.arena.reset(.retain_capacity);
|
_ = frame.arena.reset(.retain_capacity);
|
||||||
const arena = frame.arena.allocator();
|
const arena = frame.arena.allocator();
|
||||||
@ -179,6 +191,7 @@ fn sokolFrame(self: *Engine) !void {
|
|||||||
|
|
||||||
frame.time_ns = time_passed;
|
frame.time_ns = time_passed;
|
||||||
frame.dt_ns = time_passed - self.last_frame_at;
|
frame.dt_ns = time_passed - self.last_frame_at;
|
||||||
|
frame.hide_cursor = false;
|
||||||
|
|
||||||
try self.game.tick(&self.frame);
|
try self.game.tick(&self.frame);
|
||||||
|
|
||||||
@ -186,15 +199,24 @@ fn sokolFrame(self: *Engine) !void {
|
|||||||
frame.input.released_keys = .initEmpty();
|
frame.input.released_keys = .initEmpty();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (self.frame.graphics.canvas_size) |canvas_size| {
|
if (self.canvas_size) |canvas_size| {
|
||||||
_ = ScreenScalar.apply(
|
const transform = ScreenScalar.init(
|
||||||
&self.frame,
|
|
||||||
screen_size,
|
screen_size,
|
||||||
canvas_size,
|
canvas_size
|
||||||
rgb(0, 0, 0),
|
);
|
||||||
|
transform.apply(
|
||||||
|
screen_size,
|
||||||
|
&self.frame,
|
||||||
|
rgb(0, 0, 0)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sapp.showMouse(!self.frame.hide_cursor);
|
||||||
|
|
||||||
|
// Canvas size modification must always be applied a frame later.
|
||||||
|
// So that mouse coordinate transformations are consistent.
|
||||||
|
self.canvas_size = self.frame.graphics.canvas_size;
|
||||||
|
|
||||||
{
|
{
|
||||||
Gfx.beginFrame();
|
Gfx.beginFrame();
|
||||||
defer Gfx.endFrame(frame.graphics.clear_color);
|
defer Gfx.endFrame(frame.graphics.clear_color);
|
||||||
@ -210,6 +232,10 @@ fn sokolFrame(self: *Engine) !void {
|
|||||||
for (frame.audio.commands.items) |command| {
|
for (frame.audio.commands.items) |command| {
|
||||||
try Audio.mixer.commands.push(command);
|
try Audio.mixer.commands.push(command);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (revert_mouse_position) |pos| {
|
||||||
|
self.frame.input.mouse.position = pos;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn showDebugWindow(frame: *Frame) !void {
|
fn showDebugWindow(frame: *Frame) !void {
|
||||||
|
|||||||
@ -16,12 +16,7 @@ const ScreenScalar = @This();
|
|||||||
translation: Vec2,
|
translation: Vec2,
|
||||||
scale: f32,
|
scale: f32,
|
||||||
|
|
||||||
pub fn apply(
|
pub fn init(window_size: Vec2, canvas_size: Vec2) ScreenScalar {
|
||||||
frame: *Frame,
|
|
||||||
window_size: Vec2,
|
|
||||||
canvas_size: Vec2,
|
|
||||||
color: Vec4
|
|
||||||
) ScreenScalar {
|
|
||||||
// TODO: Render to a lower resolution instead of scaling.
|
// TODO: Render to a lower resolution instead of scaling.
|
||||||
// To avoid pixel bleeding in spritesheet artifacts
|
// To avoid pixel bleeding in spritesheet artifacts
|
||||||
const scale = @floor(@min(
|
const scale = @floor(@min(
|
||||||
@ -33,6 +28,16 @@ pub fn apply(
|
|||||||
translation.x = @round(translation.x);
|
translation.x = @round(translation.x);
|
||||||
translation.y = @round(translation.y);
|
translation.y = @round(translation.y);
|
||||||
|
|
||||||
|
return ScreenScalar{
|
||||||
|
.translation = translation,
|
||||||
|
.scale = scale
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn apply(self: ScreenScalar, window_size: Vec2, frame: *Frame, color: Vec4) void {
|
||||||
|
const scale = self.scale;
|
||||||
|
const translation = self.translation;
|
||||||
|
|
||||||
frame.prependGraphicsCommand(.{
|
frame.prependGraphicsCommand(.{
|
||||||
.push_transformation = .{
|
.push_transformation = .{
|
||||||
.translation = translation,
|
.translation = translation,
|
||||||
@ -72,9 +77,4 @@ pub fn apply(
|
|||||||
},
|
},
|
||||||
.color = color
|
.color = color
|
||||||
});
|
});
|
||||||
|
|
||||||
return ScreenScalar{
|
|
||||||
.translation = translation,
|
|
||||||
.scale = scale
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|||||||
131
src/game.zig
131
src/game.zig
@ -1,15 +1,19 @@
|
|||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
const Allocator = std.mem.Allocator;
|
const Allocator = std.mem.Allocator;
|
||||||
const assert = std.debug.assert;
|
const assert = std.debug.assert;
|
||||||
|
const clamp = std.math.clamp;
|
||||||
|
|
||||||
const Assets = @import("./assets.zig");
|
const Assets = @import("./assets.zig");
|
||||||
|
const Tilemap = Assets.Tilemap;
|
||||||
|
|
||||||
const Engine = @import("./engine/root.zig");
|
const Engine = @import("./engine/root.zig");
|
||||||
const Nanoseconds = Engine.Nanoseconds;
|
const Nanoseconds = Engine.Nanoseconds;
|
||||||
const imgui = Engine.imgui;
|
const imgui = Engine.imgui;
|
||||||
const Vec2 = Engine.Vec2;
|
const Vec2 = Engine.Vec2;
|
||||||
|
const Vec4 = Engine.Math.Vec4;
|
||||||
const Rect = Engine.Math.Rect;
|
const Rect = Engine.Math.Rect;
|
||||||
const rgb = Engine.Math.rgb;
|
const rgb = Engine.Math.rgb;
|
||||||
|
const rgba = Engine.Math.rgba;
|
||||||
const Range = Engine.Math.Range;
|
const Range = Engine.Math.Range;
|
||||||
const TextureId = Engine.Graphics.TextureId;
|
const TextureId = Engine.Graphics.TextureId;
|
||||||
const AudioId = Engine.Audio.Data.Id;
|
const AudioId = Engine.Audio.Data.Id;
|
||||||
@ -99,6 +103,7 @@ player: Vec2,
|
|||||||
player_anim_state: Animation.State = .default,
|
player_anim_state: Animation.State = .default,
|
||||||
last_faced_left: bool = false,
|
last_faced_left: bool = false,
|
||||||
player_walk_sound: AudioBundle = .empty,
|
player_walk_sound: AudioBundle = .empty,
|
||||||
|
hand_offset: Vec2 = .zero,
|
||||||
|
|
||||||
player_anim: Animation,
|
player_anim: Animation,
|
||||||
|
|
||||||
@ -106,18 +111,15 @@ pub fn init(gpa: Allocator, seed: u64, assets: *Assets) !Game {
|
|||||||
var arena = std.heap.ArenaAllocator.init(gpa);
|
var arena = std.heap.ArenaAllocator.init(gpa);
|
||||||
errdefer arena.deinit();
|
errdefer arena.deinit();
|
||||||
|
|
||||||
const texture_info = Engine.Graphics.getTextureInfo(assets.players_texture);
|
|
||||||
const tilemap_size = Vec2.initFromInt(u32, texture_info.width, texture_info.height);
|
|
||||||
const tile_size = assets.player_size;
|
|
||||||
const player_anim = Animation{
|
const player_anim = Animation{
|
||||||
.texture = assets.players_texture,
|
.texture = assets.players_tilemap.texture,
|
||||||
.frames = try arena.allocator().dupe(Animation.Frame, &.{
|
.frames = try arena.allocator().dupe(Animation.Frame, &.{
|
||||||
.{
|
.{
|
||||||
.uv = getUVFromTilemap(tilemap_size, tile_size, 0, 0),
|
.uv = assets.players_tilemap.getTileUV(0, 0),
|
||||||
.duration = 0.1,
|
.duration = 0.1,
|
||||||
},
|
},
|
||||||
.{
|
.{
|
||||||
.uv = getUVFromTilemap(tilemap_size, tile_size, 1, 0),
|
.uv = assets.players_tilemap.getTileUV(1, 0),
|
||||||
.duration = 0.2,
|
.duration = 0.2,
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
@ -157,24 +159,37 @@ fn findSpawnpoint(assets: *Assets) ?Vec2 {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn getUVFromTilemap(tilemap_size: Vec2, tile_size: Vec2, tile_x: f32, tile_y: f32) Rect {
|
const DrawTileOptions = struct {
|
||||||
return .{
|
pos: Vec2,
|
||||||
.pos = Vec2.init(tile_x, tile_y).multiply(tile_size).divide(tilemap_size),
|
scale: Vec2 = .init(1, 1),
|
||||||
.size = tile_size.divide(tilemap_size),
|
color: Vec4 = rgb(255, 255, 255),
|
||||||
};
|
rotation: f32 = 0,
|
||||||
}
|
origin: Vec2 = .init(0, 0),
|
||||||
|
|
||||||
fn getUVFromTilemapByID(tilemap_size: Vec2, tile_size: Vec2, tile_id: u32) Rect {
|
tilemap: Tilemap,
|
||||||
const tile_id_f32: f32 = @floatFromInt(tile_id);
|
tile: Vec2
|
||||||
const width_in_tiles = tilemap_size.x / tile_size.x;
|
};
|
||||||
const tile_x = @rem(tile_id_f32, width_in_tiles);
|
|
||||||
const tile_y = @divFloor(tile_id_f32, width_in_tiles);
|
fn drawTile(frame: *Engine.Frame, opts: DrawTileOptions) void {
|
||||||
return getUVFromTilemap(tilemap_size, tile_size, tile_x, tile_y);
|
frame.drawRectangle(.{
|
||||||
|
.rect = .{
|
||||||
|
.pos = opts.pos,
|
||||||
|
.size = opts.tilemap.tile_size.multiply(opts.scale)
|
||||||
|
},
|
||||||
|
.color = opts.color,
|
||||||
|
.rotation = opts.rotation,
|
||||||
|
.origin = opts.origin,
|
||||||
|
.sprite = .{
|
||||||
|
.texture = opts.tilemap.texture,
|
||||||
|
.uv = opts.tilemap.getTileUV(opts.tile.x, opts.tile.y)
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
fn drawTilemap(self: *Game, frame: *Engine.Frame) void {
|
fn drawTilemap(self: *Game, frame: *Engine.Frame) void {
|
||||||
const texture = self.assets.tileset_texture;
|
const tilemap = self.assets.terrain_tilemap;
|
||||||
const texture_info = Engine.Graphics.getTextureInfo(texture);
|
const texture_info = Engine.Graphics.getTextureInfo(tilemap.texture);
|
||||||
|
const tilemap_size = Vec2.initFromInt(u32,texture_info.width, texture_info.height);
|
||||||
|
|
||||||
const map = self.assets.map;
|
const map = self.assets.map;
|
||||||
|
|
||||||
@ -193,19 +208,15 @@ fn drawTilemap(self: *Game, frame: *Engine.Frame) void {
|
|||||||
const tile_gid = tile_layer.get(x, y) orelse continue;
|
const tile_gid = tile_layer.get(x, y) orelse continue;
|
||||||
const tile = map.getTile(self.assets.tilesets, tile_gid) orelse continue;
|
const tile = map.getTile(self.assets.tilesets, tile_gid) orelse continue;
|
||||||
|
|
||||||
const tilemap_size = Vec2.initFromInt(u32,texture_info.width, texture_info.height);
|
const tile_id_f32: f32 = @floatFromInt(tile.id);
|
||||||
const tile_size = Vec2.initFromInt(u32, tile.tileset.tile_width, tile.tileset.tile_height);
|
const width_in_tiles = tilemap_size.x / tilemap.tile_size.x;
|
||||||
|
const tile_x = @rem(tile_id_f32, width_in_tiles);
|
||||||
|
const tile_y = @divFloor(tile_id_f32, width_in_tiles);
|
||||||
|
|
||||||
frame.drawRectangle(.{
|
drawTile(frame, .{
|
||||||
.rect = Rect{
|
.pos = Vec2.initFromInt(i32, x, y).multiply(tilemap.tile_size),
|
||||||
.pos = Vec2.initFromInt(i32, x, y).multiply(tile_size),
|
.tilemap = tilemap,
|
||||||
.size = tile_size
|
.tile = .init(tile_x, tile_y)
|
||||||
},
|
|
||||||
.color = rgb(255, 255, 255),
|
|
||||||
.texture = .{
|
|
||||||
.id = self.assets.tileset_texture,
|
|
||||||
.uv = getUVFromTilemapByID(tilemap_size, tile_size, tile.id)
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -222,10 +233,13 @@ pub fn tick(self: *Game, frame: *Engine.Frame) !void {
|
|||||||
frame.show_debug = !frame.show_debug;
|
frame.show_debug = !frame.show_debug;
|
||||||
}
|
}
|
||||||
|
|
||||||
frame.pushTransform(
|
frame.drawRectangle(.{
|
||||||
canvas_size.divideScalar(2).sub(self.player),
|
.rect = .init(0, 0, canvas_size.x, canvas_size.y),
|
||||||
.init(1, 1)
|
.color = rgb(20, 20, 20)
|
||||||
);
|
});
|
||||||
|
|
||||||
|
const camera_offset = canvas_size.divideScalar(2).sub(self.player);
|
||||||
|
frame.pushTransform(camera_offset, .init(1, 1));
|
||||||
defer frame.popTransform();
|
defer frame.popTransform();
|
||||||
|
|
||||||
var dir = Vec2.init(0, 0);
|
var dir = Vec2.init(0, 0);
|
||||||
@ -261,18 +275,13 @@ pub fn tick(self: *Game, frame: *Engine.Frame) !void {
|
|||||||
|
|
||||||
self.drawTilemap(frame);
|
self.drawTilemap(frame);
|
||||||
|
|
||||||
frame.drawRectangle(.{
|
|
||||||
.rect = .init(0, 0, canvas_size.x, canvas_size.y),
|
|
||||||
.color = rgb(20, 20, 20)
|
|
||||||
});
|
|
||||||
|
|
||||||
if (dir.x < 0) {
|
if (dir.x < 0) {
|
||||||
self.last_faced_left = true;
|
self.last_faced_left = true;
|
||||||
} else if (dir.x > 0) {
|
} else if (dir.x > 0) {
|
||||||
self.last_faced_left = false;
|
self.last_faced_left = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
var size = self.assets.player_size;
|
var size = self.assets.players_tilemap.tile_size;
|
||||||
if (self.last_faced_left) {
|
if (self.last_faced_left) {
|
||||||
size.x *= -1;
|
size.x *= -1;
|
||||||
}
|
}
|
||||||
@ -282,15 +291,47 @@ pub fn tick(self: *Game, frame: *Engine.Frame) !void {
|
|||||||
.size = size,
|
.size = size,
|
||||||
},
|
},
|
||||||
.color = rgb(255, 255, 255),
|
.color = rgb(255, 255, 255),
|
||||||
.texture = .{
|
.sprite = .{
|
||||||
.id = self.player_anim.texture,
|
.texture = self.player_anim.texture,
|
||||||
.uv = self.player_anim.frames[self.player_anim_state.frame_index].uv
|
.uv = self.player_anim.frames[self.player_anim_state.frame_index].uv
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const max_hand_length = 32;
|
||||||
|
if (frame.input.mouse.position) |mouse_screen| {
|
||||||
|
const mouse = mouse_screen.sub(camera_offset);
|
||||||
|
const player_to_mouse = mouse.sub(self.player);
|
||||||
|
self.hand_offset = mouse.sub(self.player).limitLength(max_hand_length);
|
||||||
|
|
||||||
|
const opacity = clamp((player_to_mouse.length() - max_hand_length) / 16, 0, 1);
|
||||||
|
drawTile(frame, .{
|
||||||
|
.pos = mouse.sub(self.assets.weapons_tilemap.tile_size.multiplyScalar(0.5)),
|
||||||
|
.tilemap = self.assets.weapons_tilemap,
|
||||||
|
.color = rgba(255, 255, 255, opacity),
|
||||||
|
.tile = .init(4, 2)
|
||||||
|
});
|
||||||
|
frame.hide_cursor = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
const hand = self.player.add(self.hand_offset);
|
||||||
|
var hand_flip_x: f32 = 1;
|
||||||
|
if (self.hand_offset.x < 0) {
|
||||||
|
hand_flip_x *= -1;
|
||||||
|
}
|
||||||
|
const hand_scale = Vec2.init(1, hand_flip_x);
|
||||||
|
const weapon_size = self.assets.weapons_tilemap.tile_size;
|
||||||
|
drawTile(frame, .{
|
||||||
|
.pos = hand.add(weapon_size.multiplyScalar(-0.5).multiply(hand_scale)),
|
||||||
|
.scale = hand_scale,
|
||||||
|
.tilemap = self.assets.weapons_tilemap,
|
||||||
|
.tile = .init(0, 0),
|
||||||
|
.origin = weapon_size.multiplyScalar(0.5).multiply(hand_scale),
|
||||||
|
.rotation = self.hand_offset.getAngle()
|
||||||
|
});
|
||||||
|
|
||||||
frame.drawText(self.player, "Player", .{
|
frame.drawText(self.player, "Player", .{
|
||||||
.font = regular_font,
|
.font = regular_font,
|
||||||
.size = 1
|
.size = 16
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user