diff --git a/.gitmodules b/.gitmodules index 7216298..f501634 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +1,6 @@ [submodule "raylib-zig"] path = raylib-zig url = https://github.com/Not-Nik/raylib-zig.git +[submodule "zig-ecs"] + path = zig-ecs + url = https://github.com/prime31/zig-ecs.git diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..8bd69ef --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,15 @@ +{ + "version": "0.2.0", + "configurations": [ + { + "type": "cppvsdbg", + "request": "launch", + "name": "(gdb) launch", + "program": "${workspaceFolder}/zig-out/bin/zig-raylib-game-test.exe", + "args": [], + "cwd": "${workspaceFolder}", + "console": "integratedTerminal", + "preLaunchTask": "zig debug build" + } + ] +} \ No newline at end of file diff --git a/.vscode/tasks.json b/.vscode/tasks.json new file mode 100644 index 0000000..0485dd7 --- /dev/null +++ b/.vscode/tasks.json @@ -0,0 +1,10 @@ +{ + "version": "2.0.0", + "tasks": [ + { + "label": "zig debug build", + "type": "shell", + "command": "zig build" + } + ] +} \ No newline at end of file diff --git a/build.zig b/build.zig index a82b735..979d1be 100644 --- a/build.zig +++ b/build.zig @@ -1,33 +1,21 @@ const std = @import("std"); const rl = @import("raylib-zig/build.zig"); +const ecs = @import("zig-ecs/build.zig"); pub fn build(b: *std.Build) !void { const target = b.standardTargetOptions(.{}); const optimize = b.standardOptimizeOption(.{}); var raylib = rl.getModule(b, "raylib-zig"); var raylib_math = rl.math.getModule(b, "raylib-zig"); + var zigecs = ecs.getModule(b, "zig-ecs"); //web exports are completely separate - if (target.getOsTag() == .emscripten) { - const exe_lib = rl.compileForEmscripten(b, "zig-raylib-game-test", "src/main.zig", target, optimize); - exe_lib.addModule("raylib", raylib); - exe_lib.addModule("raylib-math", raylib_math); - const raylib_artifact = rl.getRaylib(b, target, optimize); - // Note that raylib itself is not actually added to the exe_lib output file, so it also needs to be linked with emscripten. - exe_lib.linkLibrary(raylib_artifact); - const link_step = try rl.linkWithEmscripten(b, &[_]*std.Build.Step.Compile{ exe_lib, raylib_artifact }); - b.getInstallStep().dependOn(&link_step.step); - const run_step = try rl.emscriptenRunStep(b); - run_step.step.dependOn(&link_step.step); - const run_option = b.step("run", "Run zig-raylib-game-test"); - run_option.dependOn(&run_step.step); - return; - } const exe = b.addExecutable(.{ .name = "zig-raylib-game-test", .root_source_file = .{ .path = "src/main.zig" }, .optimize = optimize, .target = target }); rl.link(b, exe, target, optimize); exe.addModule("raylib", raylib); exe.addModule("raylib-math", raylib_math); + exe.addModule("zig-ecs", zigecs); const run_cmd = b.addRunArtifact(exe); const run_step = b.step("run", "Run zig-raylib-game-test"); @@ -35,4 +23,3 @@ pub fn build(b: *std.Build) !void { b.installArtifact(exe); } - diff --git a/src/EntitySystem.zig b/src/EntitySystem.zig deleted file mode 100644 index 390df08..0000000 --- a/src/EntitySystem.zig +++ /dev/null @@ -1,129 +0,0 @@ -const std = @import("std"); -const Etyp = @import("EntitySystemTypes.zig"); - -//Variables Entity - -var EntityIDs: std.ArrayList(usize) = undefined; -var EntityAmount: u32 = 0; - -var Signatures: std.ArrayList(Etyp.Signature) = undefined; - -//Entity System - -fn CreateEntitysub() !Etyp.Entity { - if (EntityAmount >= Etyp.MAXEntitys) { - return error.GenericError; - } - EntityAmount += 1; - return EntityIDs.pop(); -} - -fn DestroyEntitysub(entity: Etyp.Entity) void { - Signatures.items[entity] = null; - EntityIDs.append(entity); - EntityAmount -= 1; -} - -fn SetSignature(entity: Etyp.Entity, signature: Etyp.Signature) void { - Signatures.items[entity] = signature; -} - -fn GetSignature(entity: Etyp.Entity) Etyp.Signature { - return Signatures.items[entity]; -} - -//Component Manager variables - -var ComponentTypeList: std.StringArrayHashMap(Etyp.Component) = std.StringArrayHashMap(Etyp.Component).init(std.heap.page_allocator); - -var ComponentArrays: std.StringArrayHashMap(usize) = std.StringArrayHashMap(usize).init(std.heap.page_allocator); -var String2CompArr: std.StringArrayHashMap(usize) = std.StringArrayHashMap(usize).init(std.heap.page_allocator); - -var NextComponent: Etyp.Component = 0; - -//component manager - -fn RegisterComponentsub(comptime in: anytype) !void { - var name = @typeName(in); - try ComponentTypeList.put(name, NextComponent); - ComponentArrays = Etyp.ComponentArray(in).init(); - try String2CompArr.put(name, ComponentArrays.len); -} - -fn GetComponentArray(comptime in: type) type { - return ComponentArrays[@typeName(in)](); -} -fn GetComponentTypesub(comptime in: type) Etyp.Component{ - return ComponentTypeList[@typeName(in)]; -} -fn AddComponentsub(Entity: Etyp.Entity, comptime Component: type) void{ - GetComponentArray(Component).AddComponent(Entity, Component); -} -fn RemoveComponentsub(Entity: Etyp.Entity, comptime in: anytype) void{ - GetComponentArray(in).Removedata(Entity); -} -fn GetComponentsub(Entity: Etyp.Entity, comptime in: type) type{ - return GetComponentArray(in).GetData(Entity); -} -fn EntityDestroyed(Entity: Etyp.Entity) void{ - for(ComponentArrays.values())|val|{ - val.EntityDestroyed(Entity); - } -} - -//THE MASTER -pub fn Init() !void{ - EntityIDs = init: { - var temp = try std.ArrayList(usize).initCapacity(std.heap.page_allocator, Etyp.MAXEntitys); - var i = Etyp.MAXEntitys; - while (i > 0) { - temp.appendAssumeCapacity(i); - i -= 1; - } - break :init temp; - }; - Signatures = try std.ArrayList(Etyp.Signature).initCapacity(std.heap.page_allocator, Etyp.MAXEntitys); -} -pub fn CreateEntity() !Etyp.Entity{ - return try CreateEntitysub(); -} - -pub fn DestroyEntity(Entity: Etyp.entity) void{ - DestroyEntitysub(Entity); - EntityDestroyed(Entity); -} - -pub fn RegisterComponent(comptime in: anytype) !void{ - try RegisterComponentsub(in); -} - -pub fn AddComponent(Entity: Etyp.Entity, comptime in: anytype) void{ - AddComponentsub(Entity, in); - var sig = GetSignature(Entity); - sig.setValue(GetComponentTypesub(in), true); - SetSignature(Entity, sig); -} - -pub fn RemoveComponent(Entity: Etyp.Entity, comptime in: anytype) void{ - RemoveComponentsub(Entity, in); - var sig = GetSignature(Entity); - sig.setValue(GetComponentTypesub(in), false); - SetSignature(Entity, sig); -} - -pub fn GetComponent(Entity: Etyp.Entity, comptime in: anytype) @TypeOf(in){ - return GetComponentsub(Entity, in); -} - -pub fn GetComponentType(comptime in: anytype) Etyp.Component{ - return GetComponentTypesub(in); -} -pub fn GetEntitys(Signature: Etyp.Signature) []Etyp.Entity{ - var sel = std.ArrayList(Etyp.Entity).init(std.heap.page_allocator); - for(Signatures.items, 0..)|val, i|{ - if(val.intersectWith(Signature) == Signature){ - try sel.append(i); - } - } - return sel.items; -} \ No newline at end of file diff --git a/src/EntitySystemTypes.zig b/src/EntitySystemTypes.zig index 9cd253a..4ee168b 100644 --- a/src/EntitySystemTypes.zig +++ b/src/EntitySystemTypes.zig @@ -1,85 +1,16 @@ const std = @import("std"); const rl = @import("raylib"); -//Max Vars - -pub const MAXEntitys: u32 = 1000; - -pub const MAXComponents: u32 = 32; - -//Id Types -pub const Entity = usize; - -pub const Component = usize; - -pub const Signature = std.bit_set.IntegerBitSet(MAXComponents); - -//Component array type - -pub fn ComponentArray (comptime T: type) type { - return struct { - Components: [MAXEntitys]T, - Entity2Array: std.AutoArrayHashMap(Entity, usize), - Array2Entity: std.AutoArrayHashMap(usize, Entity), - sizeM: usize, - const Self = @This(); - - pub fn AddComponent(entity: Entity, comp: T) void { - var newidx: usize = Self.sizeM; - Self.Entity2Array[entity] = newidx; - Self.Entity2Array[newidx] = entity; - Self.Components[newidx] = comp; - Self.sizeM += 1; - } - pub fn Removedata(entity: Entity) void { - var remidx: usize = Self.Entity2Array[entity]; - var lastidx: usize = Self.sizeM - 1; - Self.Components[remidx] = Self.Components[lastidx]; - - var lastentity: entity = Self.Array2Entity[lastidx]; - Self.Entity2Array[lastentity] = remidx; - Self.Array2Entity[remidx] = lastentity; - - Self.Entity2Array[entity] = null; - Self.Array2Entity[lastentity] = null; - - Self.sizeM -= 1; - } - pub fn GetData(entity: Entity) type { - return Self.Components[Self.Entity2Array[entity]]; - } - pub fn EntityDestroyed(self: ComponentArray, entity: Entity) void { - for(self.Array2Entity) |val|{ - if(val == entity){ - self.Removedata(entity); - return; - } - } - } - pub fn init() Self{ - return .{ - .Components = undefined, - .Entity2Array = std.AutoArrayHashMap(Entity, usize).init(std.heap.page_allocator), - .Array2Entity = std.AutoArrayHashMap(usize, Entity).init(std.heap.page_allocator), - .sizeM = 0 - }; - } - }; -} - - -//Components - pub const Transform = struct { pos: rl.Vector2, rot: f16, }; - -//Systems - -pub const Systems = struct { - const Self = @This(); - pub fn Gravity() void{ - - } +pub const Rigidbody = struct { + vel: rl.Vector2, +}; +pub const Gravity = struct { + vel: rl.Vector2, +}; +pub const Sprite = struct { + image: rl.Texture2D, }; \ No newline at end of file diff --git a/src/Images/9k.png b/src/Images/9k.png new file mode 100644 index 0000000..0f3b474 Binary files /dev/null and b/src/Images/9k.png differ diff --git a/src/main.zig b/src/main.zig index fa7ebc1..499a576 100644 --- a/src/main.zig +++ b/src/main.zig @@ -1,36 +1,66 @@ const rl = @import("raylib"); const std = @import("std"); -const EnS = @import("EntitySystem.zig"); -const Etyp = @import("EntitySystemTypes.zig"); +const ecs = @import("zig-ecs"); +const EnSysTypes = @import("EntitySystemTypes.zig"); +const time = @cImport(@cInclude("time.h")); pub fn main() anyerror!void { - const screenWidth = 1280; + const screenWidth = 1280; // set screen size const screenHeight = 720; - rl.initWindow(screenWidth, screenHeight, "AHHHH"); + rl.initWindow(screenWidth, screenHeight, "AHHHH"); // make window defer rl.closeWindow(); - var alloc = std.heap.ArenaAllocator.init(std.heap.page_allocator); - var ptr = try alloc.allocator().create(Etyp.Transform); - ptr.* = Etyp.Transform{ .pos = rl.Vector2.init(0, 0), .rot = 0 }; - //rl.setTargetFPS(60); - try EnS.Init(); - try EnS.RegisterComponent(Etyp.Transform); + var Aloc = std.heap.ArenaAllocator.init(std.heap.page_allocator); // specify memory allocator + defer Aloc.deinit(); - var player = try EnS.CreateEntity(); - - EnS.AddComponent(player, Etyp.Transform{ .pos = rl.Vector2.init(0, 0), .rot = 0 }); + var reg = ecs.Registry.init(Aloc.allocator()); // specify Entity Registry + try SetupECS(®); // run Entity Registry setup + rl.setTargetFPS(60); // set max fps + var delta: f32 = 0; while (!rl.windowShouldClose()) { - Etyp.Systems.Gravity(); - rl.beginDrawing(); defer rl.endDrawing(); - var pos = EnS.GetComponent(player, Etyp.Transform).pos; + rl.clearBackground(rl.Color.black); - rl.drawRectangle(pos.x, pos.y, 5, 5, rl.Color.gold); + try PhysicsSystem(®, delta); + try DrawSystem(®); - rl.clearBackground(rl.Color.black); rl.drawFPS(10, 10); + const text = try std.fmt.allocPrintZ(Aloc.allocator(), "{d}", .{delta}); + rl.drawText(text, 500, 10, 11, rl.Color.white); + delta = 1.0 / @as(f32, @floatFromInt(rl.getFPS())); } } +pub fn SetupECS(reg: *ecs.Registry) !void { + var player = reg.create(); + reg.add(player, EnSysTypes.Transform{.pos = rl.Vector2.init(50, 50), .rot = 0}); + reg.add(player, EnSysTypes.Rigidbody{.vel = rl.Vector2.init(0, 0)}); + reg.add(player, EnSysTypes.Gravity{.vel = rl.Vector2.init(0, 0)}); + reg.add(player, EnSysTypes.Sprite{.image = rl.loadTexture("src/Images/9k.png")}); +} +pub fn DrawSystem(reg: *ecs.Registry) !void { + var view = reg.*.view(.{EnSysTypes.Transform, EnSysTypes.Sprite}, .{}); + var iter = view.entityIterator(); + while(iter.next())|entity|{ + const Transform = view.getConst(EnSysTypes.Transform, entity); + const Sprite = view.getConst(EnSysTypes.Sprite, entity); + rl.drawTextureEx(Sprite.image, Transform.pos, Transform.rot, 1, rl.Color.white); + } +} +pub fn PhysicsSystem(reg: *ecs.Registry, deltaTime: f32) !void { + var view = reg.*.view(.{EnSysTypes.Transform, EnSysTypes.Rigidbody, EnSysTypes.Gravity}, .{}); + var iter = view.entityIterator(); + while(iter.next())|entity|{ + var Rigidbody = view.get(EnSysTypes.Rigidbody, entity); + var Transform = view.get(EnSysTypes.Transform, entity); + const Gravity = view.getConst(EnSysTypes.Gravity, entity); + + Rigidbody.*.vel.x += Gravity.vel.x; + Rigidbody.*.vel.y += Gravity.vel.y; + Transform.*.pos.x += Rigidbody.*.vel.x / deltaTime; + Transform.*.pos.y += Rigidbody.*.vel.y / deltaTime; + } +} + diff --git a/zig-ecs b/zig-ecs new file mode 160000 index 0000000..d7f7b8d --- /dev/null +++ b/zig-ecs @@ -0,0 +1 @@ +Subproject commit d7f7b8d3ea137b9e53cc421f628ccdb0776285fc