feat: add experimental game engine & demo game, fix ACPI events
This commit is contained in:
@@ -0,0 +1,134 @@
|
||||
/*
|
||||
* tilemap.h
|
||||
* MontaukOS 2D Game Engine - Tile Map
|
||||
* Grid-based terrain with per-tile rendering and collision
|
||||
* Copyright (c) 2026 Daniel Hammer
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include <cstdint>
|
||||
#include <montauk/heap.h>
|
||||
#include <montauk/string.h>
|
||||
#include "engine/sprite.h"
|
||||
|
||||
namespace engine {
|
||||
|
||||
static constexpr int MAX_TILE_TYPES = 16;
|
||||
|
||||
struct TileType {
|
||||
Spritesheet* sheet; // tile image (may be a single-tile spritesheet)
|
||||
int src_x, src_y; // source position within the sheet
|
||||
int src_w, src_h; // source size (typically tile_size x tile_size)
|
||||
bool solid; // blocks movement
|
||||
};
|
||||
|
||||
struct Tilemap {
|
||||
int* data = nullptr;
|
||||
int map_w = 0;
|
||||
int map_h = 0;
|
||||
int tile_size = 16; // native tile size in pixels
|
||||
|
||||
TileType types[MAX_TILE_TYPES];
|
||||
int type_count = 0;
|
||||
|
||||
bool alloc(int w, int h, int ts = 16) {
|
||||
map_w = w;
|
||||
map_h = h;
|
||||
tile_size = ts;
|
||||
data = (int*)montauk::malloc(w * h * sizeof(int));
|
||||
if (!data) return false;
|
||||
montauk::memset(data, 0, w * h * sizeof(int));
|
||||
return true;
|
||||
}
|
||||
|
||||
void free_map() {
|
||||
if (data) { montauk::mfree(data); data = nullptr; }
|
||||
}
|
||||
|
||||
// Register a tile type. Returns the tile ID.
|
||||
int add_type(Spritesheet* sheet, int sx, int sy, int sw, int sh, bool solid) {
|
||||
if (type_count >= MAX_TILE_TYPES) return -1;
|
||||
int id = type_count++;
|
||||
types[id].sheet = sheet;
|
||||
types[id].src_x = sx;
|
||||
types[id].src_y = sy;
|
||||
types[id].src_w = sw;
|
||||
types[id].src_h = sh;
|
||||
types[id].solid = solid;
|
||||
return id;
|
||||
}
|
||||
|
||||
void set(int x, int y, int tile_id) {
|
||||
if (x >= 0 && x < map_w && y >= 0 && y < map_h)
|
||||
data[y * map_w + x] = tile_id;
|
||||
}
|
||||
|
||||
int get(int x, int y) const {
|
||||
if (x < 0 || x >= map_w || y < 0 || y >= map_h) return -1;
|
||||
return data[y * map_w + x];
|
||||
}
|
||||
|
||||
bool is_solid(int x, int y) const {
|
||||
int id = get(x, y);
|
||||
if (id < 0 || id >= type_count) return true; // out of bounds = solid
|
||||
return types[id].solid;
|
||||
}
|
||||
|
||||
// Check if a world-pixel rectangle collides with any solid tile.
|
||||
// World coordinates are in native (unscaled) pixels.
|
||||
bool collides(int wx, int wy, int ww, int wh) const {
|
||||
// Negative coordinates are always solid (out of bounds)
|
||||
if (wx < 0 || wy < 0) return true;
|
||||
int tx0 = wx / tile_size;
|
||||
int ty0 = wy / tile_size;
|
||||
int tx1 = (wx + ww - 1) / tile_size;
|
||||
int ty1 = (wy + wh - 1) / tile_size;
|
||||
|
||||
for (int ty = ty0; ty <= ty1; ty++)
|
||||
for (int tx = tx0; tx <= tx1; tx++)
|
||||
if (is_solid(tx, ty))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Draw visible tiles to the pixel buffer.
|
||||
// cam_x/cam_y: camera position in world pixels (native scale).
|
||||
// scale: rendering scale factor.
|
||||
void draw(uint32_t* dst, int dst_w, int dst_h,
|
||||
int cam_x, int cam_y, int scale) const {
|
||||
if (!data) return;
|
||||
|
||||
int ts = tile_size * scale;
|
||||
|
||||
// Determine visible tile range
|
||||
int tx0 = cam_x / tile_size;
|
||||
int ty0 = cam_y / tile_size;
|
||||
int tx1 = tx0 + dst_w / ts + 2;
|
||||
int ty1 = ty0 + dst_h / ts + 2;
|
||||
|
||||
if (tx0 < 0) tx0 = 0;
|
||||
if (ty0 < 0) ty0 = 0;
|
||||
if (tx1 > map_w) tx1 = map_w;
|
||||
if (ty1 > map_h) ty1 = map_h;
|
||||
|
||||
for (int ty = ty0; ty < ty1; ty++) {
|
||||
for (int tx = tx0; tx < tx1; tx++) {
|
||||
int id = data[ty * map_w + tx];
|
||||
if (id < 0 || id >= type_count) continue;
|
||||
|
||||
const TileType& tt = types[id];
|
||||
if (!tt.sheet) continue;
|
||||
|
||||
int sx = tx * ts - cam_x * scale;
|
||||
int sy = ty * ts - cam_y * scale;
|
||||
|
||||
tt.sheet->draw_region(dst, dst_w, dst_h,
|
||||
tt.src_x, tt.src_y,
|
||||
tt.src_w, tt.src_h,
|
||||
sx, sy, scale);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace engine
|
||||
Reference in New Issue
Block a user