mirror of
https://github.com/simtactics/mysimulation.git
synced 2025-03-15 06:41:21 +00:00
235 lines
8.1 KiB
Zig
235 lines
8.1 KiB
Zig
|
const std = @import("std");
|
||
|
const rl = @import("raylib");
|
||
|
const world = @import("world.zig");
|
||
|
const nso = @import("niotso.zig");
|
||
|
const clap = @import("clap");
|
||
|
|
||
|
const dbg = std.debug;
|
||
|
|
||
|
const GameScreen = enum {
|
||
|
login,
|
||
|
cas, // Create-A-Sim
|
||
|
map, // city screen
|
||
|
lot, // world view
|
||
|
};
|
||
|
|
||
|
//We start that NorthWest so it is easy to determine the flip
|
||
|
const CardinalDirection = enum {
|
||
|
NorthWest, // 0, sprite 1
|
||
|
NorthEast, // 1, sprite 1 flip
|
||
|
SouthEast, // 2, sprite 2
|
||
|
SouthWest, // 3, sprite 2 flip
|
||
|
};
|
||
|
|
||
|
const Rotations = enum {
|
||
|
left, // 0
|
||
|
right, // 1
|
||
|
};
|
||
|
|
||
|
const RotationManager = struct {
|
||
|
Direction: CardinalDirection,
|
||
|
|
||
|
pub fn init(self: RotationManager) RotationManager {
|
||
|
return self;
|
||
|
}
|
||
|
|
||
|
pub fn rotate(self: *RotationManager, rotation: Rotations) void {
|
||
|
//rotate the direction by 90 degrees
|
||
|
var direction_index = @as(i8, @intFromEnum(self.Direction));
|
||
|
switch (rotation) {
|
||
|
.left => {
|
||
|
direction_index = direction_index - 1;
|
||
|
},
|
||
|
.right => {
|
||
|
direction_index = direction_index + 1;
|
||
|
},
|
||
|
}
|
||
|
// Circle around if out of bounds
|
||
|
if (direction_index < 0) {
|
||
|
self.Direction = CardinalDirection.SouthWest;
|
||
|
} else if (direction_index > 3) {
|
||
|
self.Direction = CardinalDirection.NorthWest;
|
||
|
} else {
|
||
|
self.Direction = @as(CardinalDirection, @enumFromInt(direction_index));
|
||
|
}
|
||
|
//Result
|
||
|
dbg.print("Orientation: {any}\n", .{self.Direction});
|
||
|
}
|
||
|
};
|
||
|
|
||
|
/// Still in the proof of concept phase, don't mind the mess
|
||
|
pub fn main() anyerror!void {
|
||
|
const screen_width = 800;
|
||
|
const screen_height = 600;
|
||
|
|
||
|
rl.initWindow(screen_width, screen_height, "My Simulation");
|
||
|
defer rl.closeWindow();
|
||
|
|
||
|
var current_screen: GameScreen = .login;
|
||
|
var frame_counter: i32 = 0;
|
||
|
|
||
|
// NOTE: jip
|
||
|
// I don't think we can get away with using the built-in camera
|
||
|
// We need pixel perfect isometric camera
|
||
|
var lot_camera = rl.Camera3D{
|
||
|
.position = rl.Vector3.init(-90.0, 20.0, 90.0),
|
||
|
.target = rl.Vector3.init(0, 0.0, 0),
|
||
|
.up = rl.Vector3.init(0, 1.0, 0),
|
||
|
.fovy = 10,
|
||
|
.projection = rl.CameraProjection.camera_orthographic,
|
||
|
};
|
||
|
|
||
|
var city_camera = rl.Camera3D{
|
||
|
.position = rl.Vector3.init(18.0, 21.0, 18),
|
||
|
.target = rl.Vector3.init(0, 0, 0),
|
||
|
.up = rl.Vector3.init(0, 1.0, 0),
|
||
|
.fovy = 45,
|
||
|
.projection = rl.CameraProjection.camera_perspective,
|
||
|
};
|
||
|
|
||
|
const floorLevel = rl.Vector3.init(0.0, 0.0, 0.0);
|
||
|
const itemStatic = rl.Vector3.init(0.0, 1.0, 0.0);
|
||
|
const itemStaticSize = rl.Vector2.init(2.0, 2.0);
|
||
|
|
||
|
var rotation_manager = RotationManager.init(.{
|
||
|
.Direction = CardinalDirection.SouthEast,
|
||
|
});
|
||
|
|
||
|
rl.setTargetFPS(60);
|
||
|
|
||
|
const logo = rl.Texture.init("resources/logo.png");
|
||
|
const splash = rl.Texture.init("resources/tsosplash.png");
|
||
|
const chair1 = rl.Texture.init("resources/items/dorm/chair/chair_1.png");
|
||
|
const chair1_rect = rl.Rectangle.init(0, 0, @as(f32, @floatFromInt(-chair1.width)), @as(f32, @floatFromInt(chair1.height)));
|
||
|
const chair2 = rl.Texture.init("resources/items/dorm/chair/chair_2.png");
|
||
|
const chair2_rect = rl.Rectangle.init(0, 0, @as(f32, @floatFromInt(-chair2.width)), @as(f32, @floatFromInt(chair2.height)));
|
||
|
const city = rl.loadImage("resources/cities/city_0100/elevation.png");
|
||
|
// const city_texture = rl.Texture.init("resources/cities/city_0100/vertexcolor.png");
|
||
|
// TODO: figure out a better way to unload all images and textures.
|
||
|
defer {
|
||
|
rl.unloadTexture(splash);
|
||
|
rl.unloadTexture(logo);
|
||
|
rl.unloadTexture(chair1);
|
||
|
rl.unloadTexture(chair2);
|
||
|
rl.unloadImage(city);
|
||
|
}
|
||
|
|
||
|
const mesh = rl.genMeshHeightmap(city, rl.Vector3.init(16, 8, 16));
|
||
|
const model = rl.loadModelFromMesh(mesh);
|
||
|
|
||
|
// model.materials[0].maps[rl.MATERIAL_MAP_DIFFUSE].texture = city_texture;
|
||
|
|
||
|
while (!rl.windowShouldClose()) {
|
||
|
|
||
|
// Update
|
||
|
// ------------------
|
||
|
switch (current_screen) {
|
||
|
// Skip straight to lot view until city server is complete
|
||
|
.login => {
|
||
|
frame_counter += 1;
|
||
|
|
||
|
if (frame_counter > 120) current_screen = .lot;
|
||
|
},
|
||
|
// TODO: Write CAS (Create-A-Sim) screen
|
||
|
.cas => {},
|
||
|
.map => {},
|
||
|
.lot => {
|
||
|
const zoom_increment = 5;
|
||
|
// rotate with keyboard
|
||
|
if (rl.isKeyPressed(rl.KeyboardKey.key_s)) {
|
||
|
if (lot_camera.fovy == 10) {
|
||
|
lot_camera.fovy += zoom_increment;
|
||
|
}
|
||
|
|
||
|
dbg.print("Zoom level: {d}\n", .{
|
||
|
lot_camera.fovy,
|
||
|
});
|
||
|
} else if (rl.isKeyPressed(rl.KeyboardKey.key_w)) {
|
||
|
if (lot_camera.fovy == 15) {
|
||
|
lot_camera.fovy -= zoom_increment;
|
||
|
}
|
||
|
|
||
|
dbg.print("Zoom level: {d}\n", .{
|
||
|
lot_camera.fovy,
|
||
|
});
|
||
|
}
|
||
|
// roate with scrollwheel
|
||
|
const mouse_wheel_y = std.math.clamp(-rl.getMouseWheelMove(), -1, 1) * zoom_increment;
|
||
|
if (mouse_wheel_y != 0) {
|
||
|
const zoom_min = 10;
|
||
|
const zoom_max = 25;
|
||
|
lot_camera.fovy = std.math.clamp(lot_camera.fovy + mouse_wheel_y, zoom_min, zoom_max);
|
||
|
dbg.print("Zoom level: {d}\n", .{
|
||
|
lot_camera.fovy,
|
||
|
});
|
||
|
}
|
||
|
if (rl.isKeyPressed(rl.KeyboardKey.key_a)) {
|
||
|
lot_camera.position = rl.Vector3.init(-90.0, 20.0, 90.0);
|
||
|
rotation_manager.rotate(Rotations.left);
|
||
|
dbg.print("rotate left\n", .{});
|
||
|
} else if (rl.isKeyPressed(rl.KeyboardKey.key_d)) {
|
||
|
lot_camera.position = rl.Vector3.init(90.0, 20.0, 90.0);
|
||
|
rotation_manager.rotate(Rotations.right);
|
||
|
dbg.print("rotate right\n", .{});
|
||
|
}
|
||
|
|
||
|
// camera.update(rl.CameraMode.camera_custom);
|
||
|
},
|
||
|
}
|
||
|
// ------------------
|
||
|
|
||
|
// Draw
|
||
|
rl.beginDrawing();
|
||
|
defer rl.endDrawing();
|
||
|
|
||
|
switch (current_screen) {
|
||
|
// Mockup loading screen, skips straight to world
|
||
|
.login => {
|
||
|
// Splash screen
|
||
|
rl.drawTexture(splash, 0, 0, rl.Color.white);
|
||
|
rl.drawTexture(logo, screen_width / 2.0 - 240, 30, rl.Color.white);
|
||
|
|
||
|
// Loading text
|
||
|
rl.drawText("Reticulating splines...", 20, screen_height - 30, 20, rl.Color.white);
|
||
|
},
|
||
|
// Skip this for now
|
||
|
.cas => {},
|
||
|
.map => {
|
||
|
rl.clearBackground(rl.Color.sky_blue);
|
||
|
|
||
|
city_camera.begin();
|
||
|
defer city_camera.end();
|
||
|
|
||
|
rl.drawModel(model, floorLevel, 1.0, rl.Color.green);
|
||
|
},
|
||
|
// Low view (i.e. world)
|
||
|
.lot => {
|
||
|
rl.clearBackground(rl.Color.sky_blue);
|
||
|
|
||
|
lot_camera.begin();
|
||
|
defer lot_camera.end();
|
||
|
|
||
|
rl.drawPlane(floorLevel, rl.Vector2.init(64, 64), rl.Color.dark_green);
|
||
|
switch (rotation_manager.Direction) {
|
||
|
.NorthWest => {
|
||
|
rl.drawBillboardRec(lot_camera, chair1, chair1_rect, itemStatic, itemStaticSize, rl.Color.white);
|
||
|
},
|
||
|
.NorthEast => {
|
||
|
rl.drawBillboard(lot_camera, chair1, itemStatic, 2.0, rl.Color.white);
|
||
|
},
|
||
|
.SouthEast => {
|
||
|
rl.drawBillboard(lot_camera, chair2, itemStatic, 2.0, rl.Color.white);
|
||
|
},
|
||
|
.SouthWest => {
|
||
|
rl.drawBillboardRec(lot_camera, chair2, chair2_rect, itemStatic, itemStaticSize, rl.Color.white);
|
||
|
},
|
||
|
}
|
||
|
|
||
|
// rl.drawGrid(64, 1.0);
|
||
|
},
|
||
|
}
|
||
|
|
||
|
rl.drawFPS(10, 10);
|
||
|
}
|
||
|
}
|