From f58f3d0f869d7ed98bc54e048af4122cac04fba1 Mon Sep 17 00:00:00 2001 From: Rokas Puzonas Date: Sun, 18 Feb 2024 23:12:38 +0200 Subject: [PATCH] add border --- src/main-scene.zig | 193 +++++++++++++++++++++++++++------------------ 1 file changed, 115 insertions(+), 78 deletions(-) diff --git a/src/main-scene.zig b/src/main-scene.zig index 9502f52..5c09425 100644 --- a/src/main-scene.zig +++ b/src/main-scene.zig @@ -11,10 +11,14 @@ const friction = 0.99; const walkForce = 4000; const maxSpeed = 200; const handDistance = 50; -const deathBallSize: f32 = 10; +const deathBallSize: f32 = 13; const playerSize = 20; -const virtualWidth = 300; -const virtualHeight = 300; +const virtualWidth = 350; +const virtualHeight = 350; +const safeRadius = 500; +const spawnAreaWidth = 400; + +const arenaRadius = safeRadius + spawnAreaWidth; const enemyFriction = friction; @@ -244,7 +248,7 @@ pub fn deinit(self: *Self) void { self.pixel_effect.deinit(); } -fn tickPlayer(self: *Self) void { +fn updatePlayer(self: *Self) void { const dt = rl.GetFrameTime(); var player = &self.player; var rope = &self.rope; @@ -260,6 +264,12 @@ fn tickPlayer(self: *Self) void { player.acceleration = rl.Vector2Scale(player.acceleration, walkForce); } + if (player.position.length() > arenaRadius) { + const push_strength = std.math.pow(f32, player.position.length() - arenaRadius + 10, 2); + const push_direction = player.position.normalize().neg(); + player.acceleration = player.acceleration.add(push_direction.scale(push_strength)); + } + player.velocity = rl.Vector2Add(player.velocity, rl.Vector2Scale(player.acceleration, dt)); player.velocity = rl.Vector2ClampValue(player.velocity, 0, maxSpeed); player.velocity = rl.Vector2Scale(player.velocity, std.math.pow(f32, (1 - friction), dt)); @@ -274,7 +284,7 @@ fn tickPlayer(self: *Self) void { rope.update(dt); } -fn tickEnemies(self: *Self) !void { +fn updateEnemies(self: *Self) !void { var rng = self.prng.random(); const dt = rl.GetFrameTime(); var enemies = &self.enemies; @@ -282,7 +292,7 @@ fn tickEnemies(self: *Self) !void { var rope = &self.rope; self.enemyTimer -= dt; - if (self.enemyTimer <= 0) { + if (self.enemyTimer <= 0 and player.alive()) { self.enemyTimer = 0.5 + rng.float(f32) * 2; self.spawnedEnemiesCount += 1; const enemyPosition = rl.Vector2.randomOnUnitCircle(rng).scale(400); @@ -297,7 +307,7 @@ fn tickEnemies(self: *Self) !void { self.damagePlayer(); } - if (enemy.vulnerable() and rl.Vector2Distance(enemy.position, deathBallPosition) < enemy.size + deathBallSize) { + if (enemy.vulnerable() and player.alive() and rl.Vector2Distance(enemy.position, deathBallPosition) < enemy.size + deathBallSize) { self.damageEnemy(enemy); } @@ -402,8 +412,8 @@ fn tickUI(self: *Self) !void { const screen_box = UIBox.init(0 ,0, virtualWidth, virtualHeight); const font = rl.GetFontDefault(); - try allocDrawText(allocator, "{d}", .{self.spawnedEnemiesCount}, 10, 10, 12, rl.RED); - try allocDrawText(allocator, "{d}", .{self.killCount}, 10, 30, 12, rl.GREEN); + // try allocDrawText(allocator, "{d}", .{self.spawnedEnemiesCount}, 10, 10, 12, rl.RED); + // try allocDrawText(allocator, "{d}", .{self.killCount}, 10, 30, 12, rl.GREEN); const minutes_text = try std.fmt.allocPrint(allocator, "{d:.0}", .{self.timePassed/60}); defer allocator.free(minutes_text); @@ -417,9 +427,9 @@ fn tickUI(self: *Self) !void { const minutes_text_z = try std.mem.concatWithSentinel(allocator, u8, &.{ minutes_text }, 0); defer allocator.free(minutes_text_z); - const font_size = 12; + const font_size = 20; const time_passed_width: f32 = @floatFromInt(rl.MeasureText(minutes_text_z, font_size) + rl.MeasureText(":000", font_size)); - const time_passed_pos = screen_box.center_top().add(.{ .x = -time_passed_width/2, .y = 30 }); + const time_passed_pos = screen_box.center_top().add(.{ .x = -time_passed_width/2, .y = 10 }); rl.DrawTextEx( font, time_passed_text, @@ -430,7 +440,7 @@ fn tickUI(self: *Self) !void { ); if (!self.player.alive()) { - const modal_size = rl.Vector2{ .x = 200, .y = 400 }; + const modal_size = rl.Vector2{ .x = 200, .y = 200 }; const modal = screen_box.box( screen_box.center() - modal_size.x/2, screen_box.middle() - modal_size.y/2, @@ -448,11 +458,20 @@ fn tickUI(self: *Self) !void { rl.BLACK ); - if (self.ui.button("Restart?", content.left(), content.top() + 70, content.width, 30)) { + try allocDrawText( + allocator, + "Kills: {d}", .{self.killCount}, + @intFromFloat(content.left() + 10), + @intFromFloat(content.top() + 60), + 30, + rl.BLACK + ); + + if (self.ui.button("Restart?", content.left(), content.bottom() - 70, content.width, 30)) { self.reset(); } - if (self.ui.button("Exit?", content.left(), content.top() + 120, content.width, 30)) { + if (self.ui.button("Exit?", content.left(), content.bottom() - 30, content.width, 30)) { self.should_close = true; } } else if (self.paused) { @@ -497,7 +516,7 @@ fn drawPlayer(self: *Self) void { var player = &self.player; const handPosition = player.getHandPosition(); - const healthWidth = 5; + const healthWidth = 7; const healthPercent = @as(f32, @floatFromInt(player.health)) / @as(f32, @floatFromInt(player.maxHealth)); var healthColor = rl.GREEN; if (player.invincibility > 0 and @rem(player.invincibility, 0.2) < 0.1) { @@ -513,9 +532,10 @@ fn drawPlayer(self: *Self) void { ); for (0..(player.health+1)) |i| { const percent = @as(f32, @floatFromInt(i)) / @as(f32, @floatFromInt(player.maxHealth)); - rl.DrawLineV( + rl.DrawLineEx( player.position, player.position.add((rl.Vector2{ .x = playerSize + healthWidth, .y = 0 }).rotate(percent * 2 * rl.PI)), + 5, rl.BLACK ); } @@ -533,83 +553,100 @@ fn drawPlayer(self: *Self) void { ); } +fn rgba(r: u8, g: u8, b: u8, a: u8) rl.Color { + return rl.Color{ .r = r, .g = g, .b = b, .a = a }; +} + +fn rgb(r: u8, g: u8, b: u8) rl.Color { + return rgba(r, g, b, 255); +} + +fn drawWorld(self: *Self) void { + rl.rlSetLineWidth(1); + var enemies = &self.enemies; + var rope = &self.rope; + const deathBallPosition = rope.nodePositions.get(rope.nodePositions.len-1); + + rl.ClearBackground(rl.BLACK); + rl.DrawCircle(0, 0, arenaRadius, rl.BROWN); + rl.DrawCircle(0, 0, 5, rl.GOLD); + + rl.DrawCircleLines(0, 0, safeRadius, rl.WHITE); + rl.DrawCircleLines(0, 0, safeRadius + spawnAreaWidth, rl.WHITE); + + self.drawPlayer(); + + for (enemies.items) |*enemy| { + var color = enemy.color; + if (enemy.invincibility > 0 and @rem(enemy.invincibility, 0.2) < 0.1) { + color = rl.LIGHTGRAY; + } + + rl.DrawCircle( + @intFromFloat(enemy.position.x), + @intFromFloat(enemy.position.y), + enemy.size, + color + ); + } + + rl.rlDrawRenderBatchActive(); + rl.rlSetLineWidth(3); + for (0..(rope.nodePositions.len-1)) |i| { + var node1: rl.Vector2 = rope.nodePositions.get(i); + var node2: rl.Vector2 = rope.nodePositions.get(i+1); + rl.DrawLine( + @intFromFloat(node1.x), + @intFromFloat(node1.y), + @intFromFloat(node2.x), + @intFromFloat(node2.y), + rgb(106, 7, 17) + ); + } + rl.rlDrawRenderBatchActive(); + rl.rlSetLineWidth(1); + + for (rope.nodePositions.slice()) |node| { + rl.DrawCircle( + @intFromFloat(node.x), + @intFromFloat(node.y), + 5, + rgb(194, 12, 30) + ); + } + + rl.DrawCircle( + @intFromFloat(deathBallPosition.x), + @intFromFloat(deathBallPosition.y), + deathBallSize, + rgb(239, 48, 67) + ); +} + pub fn tick(self: *Self) !void { const dt = rl.GetFrameTime(); - self.camera.offset.x = virtualWidth/2; - self.camera.offset.y = virtualHeight/2; - self.camera.zoom = 0.4; - self.camera.target = rl.Vector2Lerp(self.camera.target, self.player.position, 10 * dt); - - var enemies = &self.enemies; - var rope = &self.rope; - - if (self.player.input.isPausePressed()) { + if (self.player.input.isPausePressed() and self.player.alive()) { self.togglePaused(); } if (!self.paused) { - self.tickPlayer(); - try self.tickEnemies(); + self.camera.offset.x = virtualWidth/2; + self.camera.offset.y = virtualHeight/2; + self.camera.zoom = 0.4; + self.camera.target = rl.Vector2Lerp(self.camera.target, self.player.position, 10 * dt); + + self.updatePlayer(); + try self.updateEnemies(); if (self.player.alive()) { self.timePassed += rl.GetFrameTime(); } } - const deathBallPosition = rope.nodePositions.get(rope.nodePositions.len-1); - self.pixel_effect.begin(); - rl.ClearBackground(rl.BROWN); rl.BeginMode2D(self.camera); - { - rl.DrawCircle(0, 0, 5, rl.GOLD); - - self.drawPlayer(); - - for (enemies.items) |*enemy| { - var color = enemy.color; - if (enemy.invincibility > 0 and @rem(enemy.invincibility, 0.2) < 0.1) { - color = rl.LIGHTGRAY; - } - - rl.DrawCircle( - @intFromFloat(enemy.position.x), - @intFromFloat(enemy.position.y), - enemy.size, - color - ); - } - - const rope_color = rl.PURPLE; - for (0..(rope.nodePositions.len-1)) |i| { - var node1: rl.Vector2 = rope.nodePositions.get(i); - var node2: rl.Vector2 = rope.nodePositions.get(i+1); - rl.DrawLine( - @intFromFloat(node1.x), - @intFromFloat(node1.y), - @intFromFloat(node2.x), - @intFromFloat(node2.y), - rope_color - ); - } - - for (rope.nodePositions.slice()) |node| { - rl.DrawCircle( - @intFromFloat(node.x), - @intFromFloat(node.y), - 5, - rope_color - ); - } - - rl.DrawCircle( - @intFromFloat(deathBallPosition.x), - @intFromFloat(deathBallPosition.y), - deathBallSize, - rl.RED - ); - } + self.drawWorld(); rl.EndMode2D(); self.pixel_effect.end();