This commit is contained in:
Bedir Tuğra Karaabalı 2025-09-07 01:51:47 +03:00
parent eb1d7fd0b9
commit e75be484cd
5 changed files with 280 additions and 37 deletions

View File

@ -1,7 +1,7 @@
# 🟢 Yelbegen - Zig Oyun Motoru # 🟢 Yelbegen - Zig Oyun Motoru
**Yelbegen**, öğrenme ve deney amaçlı olarak geliştirilen **modüler bir oyun motoru**dur. **Yelbegen**, öğrenme ve deney amaçlı olarak geliştirilen **modüler bir simülatör motoru**dur.
Motor, **Zig** programlama dili kullanılarak yazılmakta ve Raylib ile RayGUI kütüphanelerini kullanmaktadır. Motor, **Zig** programlama dili kullanılarak yazılmakta ve Raylib ile RayGUI kütüphanelerini kullanmaktadır.
--- ---

View File

@ -91,6 +91,23 @@ pub fn build(b: *std.Build) void {
}, },
}); });
const mod4 = b.addModule("InputOps", .{
// The root source file is the "entry point" of this module. Users of
// this module will only be able to access public declarations contained
// in this file, which means that if you have declarations that you
// intend to expose to consumers that were defined in other files part
// of this module, you will have to make sure to re-export them from
// the root file.
.root_source_file = b.path("src/input/base_input.zig"),
// Later on we'll use this module as the root module of a test executable
// which requires us to specify a target.
.target = target,
.imports = &.{
.{.name = "raylib", .module = raylib},
.{.name = "Cam", .module = mod2},
},
});
// Here we define an executable. An executable needs to have a root module // Here we define an executable. An executable needs to have a root module
// which needs to expose a `main` function. While we could add a main function // which needs to expose a `main` function. While we could add a main function
// to the module defined above, it's sometimes preferable to split business // to the module defined above, it's sometimes preferable to split business
@ -129,8 +146,9 @@ pub fn build(b: *std.Build) void {
// can be extremely useful in case of collisions (which can happen // can be extremely useful in case of collisions (which can happen
// importing modules from different packages). // importing modules from different packages).
.{ .name = "Drawers", .module = mod }, .{ .name = "Drawers", .module = mod },
.{ .name = "Cam", .module = mod2}, .{ .name = "Cam", .module = mod2 },
.{ .name="Gui", .module = mod3}, .{ .name= "Gui", .module = mod3 },
.{ .name= "InputOps", .module = mod4 },
}, },
}), }),
}); });

View File

@ -2,29 +2,34 @@ const gui = @import("raygui");
const rl = @import("raylib"); const rl = @import("raylib");
const std = @import("std"); const std = @import("std");
pub var is_cursor_hidden: bool = undefined;
pub const GUI = struct { pub const GUI = struct {
pos : rl.Rectangle, height: f32,
gui_pos : rl.Rectangle, width: f32,
guiPos: rl.Rectangle,
pub fn init(pos : rl.Rectangle) GUI { pub fn init(width_: f32, height_: f32) GUI {
var Gui__ = GUI { var Gui__ = GUI{
.pos = pos, .height = height_,
.gui_pos = rl.Rectangle.init(0, 0, 0, 0), .width = width_,
.guiPos = rl.Rectangle.init(0, 0, 0, 0),
}; };
Gui__.addRightSide(); Gui__.addRightSide();
return Gui__; return Gui__;
} }
fn addRightSide(self : *GUI) void { fn addRightSide(self: *GUI) void {
self.gui_pos.height = self.pos.height; // menü ekranın sağında olmalıdır ve absolute bir
self.gui_pos.width = self.pos.width / 4; // pozisyondan kaçınır
self.gui_pos.x = self.pos.x/4 * 3; self.guiPos.height = self.height;
self.gui_pos.y = 0; self.guiPos.width = self.width / 4.0;
self.guiPos.x = self.width / 4.0 * 3.0;
self.guiPos.y = 0.0;
} }
pub fn draw(self : *GUI) void { pub fn draw(self: *GUI) void {
//panel //panel
rl.drawRectangleRec(self.gui_pos, .dark_gray); rl.drawRectangleRec(self.guiPos, .red);
} }
}; };

View File

@ -0,0 +1,195 @@
const std = @import("std");
const rl = @import("raylib");
const cm = @import("Cam");
pub var is_object_dragging : bool = undefined; // drag işlemi için gerekli
pub var freeMode = false;
// ışın ve ışına bağlı çarpışma ray ve raycollison değişkenleri ile yapılır.
var selected_shape_index:?usize = 0;
pub const ShapeType = enum {
cube,
rectangle,
sphere,
cylinder,
}; //tipler
pub const Shape = struct {
position: rl.Vector3,
color: rl.Color,
data: union(enum) {
// 'box' terimi hem küpü hem de dikdörtgen prizmayı kapsar
cube: struct {
width: f32,
height: f32,
length: f32,
},
sphere: struct {
radius: f32,
},
cylinder: struct {
radius: f32,
height: f32,
},
},
pub fn initCube(position: rl.Vector3, color: rl.Color, width: f32, height: f32, length: f32) Shape {
return Shape{
.position = position,
.color = color,
.data = .{ .cube = .{ .width = width, .height = height, .length = length } },
};
}
// Küre için özel init metodu
pub fn initSphere(position: rl.Vector3, color: rl.Color, radius: f32) Shape {
return Shape{
.position = position,
.color = color,
.data = .{ .sphere = .{ .radius = radius } },
};
}
// Silindir için özel init metodu
pub fn initCylinder(position: rl.Vector3, color: rl.Color, radius: f32, height: f32) Shape {
return Shape{
.position = position,
.color = color,
.data = .{ .cylinder = .{ .radius = radius, .height = height } },
};
}
};
// Raylib döngüsünde kullanmak için çizim fonksiyonu
pub fn drawShapes(shapes : *std.ArrayList(Shape)) void {
for (shapes.items, 0..) |shape, index| {
// Seçili nesneyi işaretle
if (selected_shape_index) |sel_index| {
if (index == sel_index) {
// Seçili nesnenin sınırlarını çiz
switch (shape.data) {
.cube => |d| {
//const box = getBoundingBoxForCube(shape.position, d.width, d.height, d.length);
//rl.drawCubeWiresV(box.min, box.max, .yellow);
rl.drawCubeWires(shape.position, d.width + 0.5, d.height + 0.5, d.length + 0.5, .green);
},
.sphere => |d| rl.drawSphereWires(shape.position, d.radius + 0.5, 16, 16, .green),
.cylinder => |d| rl.drawCylinderWires(shape.position, d.radius + 0.5, d.radius + 0.5, d.height, 10, .green),
}
}
}
// Asıl nesneyi çiz
switch (shape.data) {
.cube => |d| rl.drawCubeV(shape.position, rl.Vector3.init(d.width, d.height, d.length), shape.color),
.sphere => |d| rl.drawSphere(shape.position, d.radius, shape.color),
.cylinder => |d| rl.drawCylinder(shape.position, d.radius, d.radius, d.height, 10, shape.color),
}
}
}
pub fn findClosestHitObject(
mouse_position: rl.Vector2,
camera: rl.Camera3D,
shapes: *std.ArrayList(Shape),
) void {
// Fare tuşuna basılıyorsa kontrol et
if (!rl.isMouseButtonPressed(.left)) {
return;
}
const ray = rl.getScreenToWorldRay(mouse_position, camera);
var closest_hit_index: ?usize = null;
var closest_distance = std.math.floatMax(f32);
for (shapes.items, 0..) |shape, index| {
var hit_info = rl.RayCollision{.hit = false, .distance = 0.0,
.normal = rl.Vector3.init(0, 0, 0),
.point = rl.Vector3.init(0, 0, 0)};
switch (shape.data) {
.cube => |cube_data| {
const box = getBoundingBoxForCube(shape.position,
cube_data.width, cube_data.height, cube_data.length);
hit_info = rl.getRayCollisionBox(ray, box);
},
.sphere => |sphere_data| {
hit_info = rl.getRayCollisionSphere(ray, shape.position, sphere_data.radius);
},
.cylinder => |cylinder_data| {
// Performans için BoundingBox çarpışma testini kullan
const box = getBoundingBoxForCylinder(shape.position, cylinder_data.radius, cylinder_data.height);
hit_info = rl.getRayCollisionBox(ray, box);
},
}
if (hit_info.hit and hit_info.distance < closest_distance) {
closest_hit_index = index;
closest_distance = hit_info.distance;
}
}
selected_shape_index = closest_hit_index;
}
pub fn getBoundingBoxForCube(position: rl.Vector3, width: f32, height: f32, length: f32) rl.BoundingBox {
// Nesnenin boyutlarının yarısını hesapla
const half_width = width / 2.0;
const half_height = height / 2.0;
const half_length = length / 2.0;
// Minimum köşeyi (sol alt arka) hesapla
const min_x = position.x - half_width;
const min_y = position.y - half_height;
const min_z = position.z - half_length;
// Maksimum köşeyi (sağ üst ön) hesapla
const max_x = position.x + half_width;
const max_y = position.y + half_height;
const max_z = position.z + half_length;
return rl.BoundingBox{
.min = rl.Vector3.init(min_x, min_y, min_z),
.max = rl.Vector3.init(max_x, max_y, max_z),
};
}
pub fn getBoundingBoxForCylinder(position: rl.Vector3, radius: f32, height: f32) rl.BoundingBox {
// Yüksekliğin yarısını hesapla
const half_height = height / 2.0;
// Minimum köşe noktasını (min x, min y, min z) hesapla
const min_x = position.x - radius;
const min_y = position.y - half_height;
const min_z = position.z - radius;
// Maksimum köşe noktasını (max x, max y, max z) hesapla
const max_x = position.x + radius;
const max_y = position.y + half_height;
const max_z = position.z + radius;
// BoundingBox yapısını döndür
return rl.BoundingBox{
.min = rl.Vector3.init(min_x, min_y, min_z),
.max = rl.Vector3.init(max_x, max_y, max_z),
};
}
pub fn inputControls() void {
if (rl.isMouseButtonPressed(.right)) {
freeMode = !freeMode;
if (freeMode) {
rl.disableCursor();
} else {
rl.enableCursor();
}
}
}

View File

@ -4,38 +4,56 @@ const gi = @import("raygui");
const gr = @import("Drawers"); const gr = @import("Drawers");
const cm = @import("Cam"); const cm = @import("Cam");
const panel = @import("Gui"); const panel = @import("Gui");
const io = @import("InputOps");
var text: [:0]u8 = undefined; var text: [:0]u8 = undefined;
const screen_width = 1920;
const screen_height = 1080;
const allocator = std.heap.c_allocator; // C deki malloc a ulaşır
pub fn main() anyerror!void { pub fn main() anyerror!void {
var shapes = try std.ArrayList(io.Shape).initCapacity(allocator, 1024);
defer shapes.deinit(allocator);
const base_cube = rl.Vector3.init(-20, 20, 0); var my_gui = panel.GUI.init(@floatFromInt(screen_width), @floatFromInt(screen_height));
const my_cube = io.Shape.initCube(rl.Vector3.init(0, 0, 0),
.red, 2.0, 2.0, 2.0);
const my_sphere = io.Shape.initSphere(rl.Vector3.init(2.0, 0, 0), .gold, 1.0);
const my_cylinder = io.Shape.initCylinder(rl.Vector3.init(-2.0, 0, 0), .pink, 1, 1);
const screen_height = 1200; try shapes.append(allocator, my_cube);
const screen_width = 800; try shapes.append(allocator, my_sphere);
try shapes.append(allocator, my_cylinder);
var my_gui = panel.GUI.init(rl.Rectangle.init(0, 0, screen_width, screen_height)); panel.is_cursor_hidden = false;
io.is_object_dragging = false;
rl.initWindow(screen_height, screen_width, "YELBEGEN");
rl.initWindow(screen_width, screen_height, "YELBEGEN");
defer rl.closeWindow(); defer rl.closeWindow();
var cam = rl.Camera3D{ var cam = rl.Camera3D{
.position = rl.Vector3.init(290, 120, 250), .position = rl.Vector3.init(10, 10, 10),
.target = rl.Vector3.init(20,20,20), .target = rl.Vector3.init(0,0,0),
.up = rl.Vector3.init(0, 2.0, 0), .up = rl.Vector3.init(0, 1.0, 0),
.fovy = 45.0, .fovy = 45.0,
.projection = rl.CameraProjection.perspective, .projection = rl.CameraProjection.perspective,
}; };
rl.setTargetFPS(60);
while (!rl.windowShouldClose()) { while (!rl.windowShouldClose()) {
//update io.inputControls();
if (rl.isKeyDown(.a)) { io.findClosestHitObject(rl.getMousePosition(), cam, &shapes);
cam.position.x += 0.01;
} else if (rl.isKeyDown(.b)) { if (io.freeMode) {
cam.position.y += 0.01; rl.updateCamera(&cam, .free);
} else if (rl.isKeyDown(.c)) { }
cam.position.z += 0.01;
}
rl.beginDrawing(); rl.beginDrawing();
defer rl.endDrawing(); defer rl.endDrawing();
@ -43,12 +61,19 @@ pub fn main() anyerror!void {
rl.clearBackground(.ray_white); rl.clearBackground(.ray_white);
rl.beginMode3D(cam); rl.beginMode3D(cam);
rl.drawCube(base_cube, 40, 40, 40, .red); io.drawShapes(&shapes);
rl.drawCube(rl.Vector3.zero(), 300, 1, 300, .gray); rl.drawGrid(10, 1.0);
rl.endMode3D(); rl.endMode3D();
rl.drawText(rl.textFormat("x:%.2f y:%.2f z:%.2f", .{cam.position.x, cam.position.y, cam.position.z}), rl.drawText(rl.textFormat("x:%.2f y:%.2f z:%.2f", .{cam.position.x, cam.position.y, cam.position.z}),
180, 200, 20, .light_gray); 180, 200, 20, .light_gray);
rl.drawText(rl.textFormat("x : %d y : %d", .{rl.getScreenWidth(), rl.getScreenHeight()}), 50, 50, 20, .red);
my_gui.draw(); my_gui.draw();
rl.drawFPS(200, 200);
if (io.is_object_dragging) {
rl.drawText("Nesne drag...", 10, 10, 20, .dark_gray);
} else {
rl.drawText("Nesne hazır...", 10, 10, 20, .dark_gray);
}
} }