182 lines
6.9 KiB
Zig
182 lines
6.9 KiB
Zig
const std = @import("std");
|
|
const sdl = @import("sdl.zig").c;
|
|
const gs = @import("./game_state.zig");
|
|
const assert = std.debug.assert;
|
|
const SCREEN_WIDTH = 640;
|
|
const SCREEN_HEIGHT = 480;
|
|
const SCREEN_FPS: f64 = 30.0;
|
|
const SCREEN_TICKS_PER_FRAME: f64 = 1000 / SCREEN_FPS;
|
|
const PHYS_UPS: f64 = 310.0;
|
|
const PHYS_TICKS_PER_UPDATE: f64 = 1000 / PHYS_UPS;
|
|
const PHYS_UPDATES_PER_RENDER: f64 = PHYS_UPS / SCREEN_FPS;
|
|
const phys_updates_per_render: u32 = @intFromFloat(PHYS_UPDATES_PER_RENDER);
|
|
|
|
const log = sdl.SDL_Log;
|
|
const GameText = @import("./text.zig").GameText;
|
|
const RGBAColor = @import("./utils/rgb_color.zig").RGBAColor;
|
|
const Timer = @import("./utils/timer.zig").Timer;
|
|
|
|
var window: *sdl.struct_SDL_Window = undefined;
|
|
// var screen_surface: *sdl.struct_SDL_Surface = undefined;
|
|
var renderer: *sdl.struct_SDL_Renderer = undefined;
|
|
|
|
const Offset = struct {
|
|
x: i32,
|
|
y: i32,
|
|
};
|
|
var img_pos: Offset = .{ .x = 0, .y = 0 };
|
|
|
|
pub fn main() !void {
|
|
errdefer |err| if (err == error.SdlError) std.log.err("SDL error: {s}", .{sdl.SDL_GetError()});
|
|
try init();
|
|
defer close();
|
|
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
|
|
const allocator = gpa.allocator();
|
|
|
|
var game_state_controller = try gs.GameStateController.init(allocator, renderer);
|
|
defer game_state_controller.deinit();
|
|
|
|
var quit = false;
|
|
|
|
var game_timer = Timer{};
|
|
game_timer.start();
|
|
|
|
var frame_time = Timer{};
|
|
frame_time.start();
|
|
|
|
var prev_frame_ms: f64 = 16.0;
|
|
var accumulator: f64 = 0.0;
|
|
var prev_game_state: ?*const gs.GameState = null;
|
|
var current_game_state: ?*const gs.GameState = undefined;
|
|
|
|
while (!quit) {
|
|
|
|
// double newTime = time();
|
|
// double frameTime = newTime - currentTime;
|
|
// if ( frameTime > 0.25 )
|
|
// frameTime = 0.25;
|
|
// currentTime = newTime;
|
|
|
|
// accumulator += frameTime;
|
|
|
|
// while ( accumulator >= dt )
|
|
// {
|
|
// previousState = currentState;
|
|
// integrate( currentState, t, dt );
|
|
// t += dt;
|
|
// accumulator -= dt;
|
|
// }
|
|
|
|
// const double alpha = accumulator / dt;
|
|
|
|
// State state = currentState * alpha +
|
|
// previousState * ( 1.0 - alpha );
|
|
|
|
// Wait for time to render screen, keep running physics
|
|
accumulator = accumulator + SCREEN_TICKS_PER_FRAME;
|
|
const total_phys_ticks: u32 = @intFromFloat(PHYS_TICKS_PER_UPDATE * PHYS_UPDATES_PER_RENDER);
|
|
const game_time_ms: u32 = @intFromFloat(game_timer.getTicks());
|
|
const phys_done_at_ticks: u32 = game_time_ms + total_phys_ticks;
|
|
var phys_ticks_used: f64 = 0;
|
|
std.debug.print("Phys ticks/upd: {d}\nAcc: {d}\nTotal phys ticks {d}ms\nPhys done at {d}ms\n", .{ PHYS_TICKS_PER_UPDATE, accumulator, total_phys_ticks, phys_done_at_ticks });
|
|
// Run a physics update
|
|
while (accumulator >= PHYS_TICKS_PER_UPDATE) {
|
|
// Control loop here
|
|
var event: sdl.SDL_Event = undefined;
|
|
while (sdl.SDL_PollEvent(&event) != 0) {
|
|
switch (event.type) {
|
|
sdl.SDL_QUIT => {
|
|
quit = true;
|
|
},
|
|
sdl.SDL_KEYDOWN => {
|
|
switch (event.key.keysym.sym) {
|
|
sdl.SDLK_RETURN => {},
|
|
else => {},
|
|
}
|
|
log("Got key event: %i\n", event.key.keysym.sym);
|
|
},
|
|
else => {},
|
|
}
|
|
}
|
|
prev_game_state = current_game_state;
|
|
current_game_state = try game_state_controller.update_tick();
|
|
const phys_ticks_this_update: f64 = current_game_state.?.phys_ticks - phys_ticks_used;
|
|
accumulator -= phys_ticks_this_update;
|
|
|
|
// std.debug.print(" PU in {d}ms ", .{phys_ticks_this_update});
|
|
// std.debug.print(" Acc:{d} - ", .{accumulator});
|
|
|
|
// TODO dont turn it into an int, take the extra phys_frames and do a partial render
|
|
// if (phys_ticks_this_update < PHYS_TICKS_PER_UPDATE) {
|
|
// const ticks: u32 = @intFromFloat(PHYS_TICKS_PER_UPDATE - phys_ticks_this_update);
|
|
// sdl.SDL_Delay(ticks);
|
|
// const ticksf: f64 = @floatFromInt(ticks);
|
|
// accumulator -= (phys_ticks_this_update + ticksf);
|
|
// } else {
|
|
// // std.debug.print("PHYSICS JANK: Physics Update took {d}ms, target: {d}ms\n", .{ phys_ticks_this_update, PHYS_TICKS_PER_UPDATE });
|
|
// accumulator -= phys_ticks_this_update;
|
|
// }
|
|
phys_ticks_used = current_game_state.?.phys_ticks;
|
|
// std.debug.print(" PhyTicks this render: {d} ", .{current_game_state.?.phys_ticks});
|
|
}
|
|
// TODO lerp together prev and current states
|
|
// Otherwise will have physics jank
|
|
|
|
// Update screen frame
|
|
std.debug.print("Took {d} phys frames\n", .{current_game_state.?.phys_updates_since_render});
|
|
try game_state_controller.render(current_game_state.?);
|
|
|
|
prev_frame_ms = frame_time.getTicks();
|
|
std.debug.print("Rendered to screen in {d}ms\n***\n***\n", .{prev_frame_ms});
|
|
frame_time.reset();
|
|
// const frame_time_ticks = frame_time.getTicks();
|
|
// if (frame_time_ticks < SCREEN_TICKS_PER_FRAME) {
|
|
// sdl.SDL_Delay(SCREEN_TICKS_PER_FRAME - frame_time_ticks);
|
|
// }
|
|
}
|
|
return;
|
|
}
|
|
|
|
fn init() !void {
|
|
// Init SDL with video subsystem flag
|
|
if (sdl.SDL_Init(sdl.SDL_INIT_VIDEO) < 0) {
|
|
log("Unable to initialize SDL: %s\n", sdl.SDL_GetError());
|
|
return error.SDLInitializationFailed;
|
|
}
|
|
|
|
const opt_window = sdl.SDL_CreateWindow("Game Window", sdl.SDL_WINDOWPOS_UNDEFINED, sdl.SDL_WINDOWPOS_UNDEFINED, SCREEN_WIDTH, SCREEN_HEIGHT, sdl.SDL_WINDOW_SHOWN);
|
|
if (opt_window == null) {
|
|
log("Unable to initialize SDL window: %s\n", sdl.SDL_GetError());
|
|
return error.SDLInitializationFailed;
|
|
}
|
|
window = opt_window.?;
|
|
|
|
renderer = sdl.SDL_CreateRenderer(window, -1, sdl.SDL_RENDERER_ACCELERATED) orelse {
|
|
log("Unable to initialize SDL window: %s\n", sdl.SDL_GetError());
|
|
return error.SDLInitializationFailed;
|
|
};
|
|
_ = sdl.SDL_SetRenderDrawColor(renderer, 0xff, 0xff, 0xff, 0xff);
|
|
|
|
// screen_surface = sdl.SDL_GetWindowSurface(window);
|
|
|
|
const img_flags = sdl.IMG_INIT_PNG;
|
|
if (sdl.IMG_Init(img_flags) != img_flags) {
|
|
// NOTE remember that errors with SDL_Image will be in IMG_GetError() not SDL_GetError()
|
|
log("Unable to initialize SDL Image: %s\n", sdl.IMG_GetError());
|
|
return error.SDLInitializationFailed;
|
|
}
|
|
|
|
if (sdl.TTF_Init() < 0) {
|
|
log("Unable to initialize SDL TTF: %s\n", sdl.TTF_GetError());
|
|
return error.SDLInitializationFailed;
|
|
}
|
|
}
|
|
|
|
fn close() void {
|
|
sdl.SDL_DestroyRenderer(renderer);
|
|
sdl.SDL_DestroyWindow(window);
|
|
sdl.IMG_Quit();
|
|
sdl.TTF_Quit();
|
|
sdl.SDL_Quit();
|
|
}
|