add border

This commit is contained in:
Rokas Puzonas 2024-02-18 23:12:38 +02:00
parent 2941d9a39c
commit f58f3d0f86

View File

@ -11,10 +11,14 @@ const friction = 0.99;
const walkForce = 4000; const walkForce = 4000;
const maxSpeed = 200; const maxSpeed = 200;
const handDistance = 50; const handDistance = 50;
const deathBallSize: f32 = 10; const deathBallSize: f32 = 13;
const playerSize = 20; const playerSize = 20;
const virtualWidth = 300; const virtualWidth = 350;
const virtualHeight = 300; const virtualHeight = 350;
const safeRadius = 500;
const spawnAreaWidth = 400;
const arenaRadius = safeRadius + spawnAreaWidth;
const enemyFriction = friction; const enemyFriction = friction;
@ -244,7 +248,7 @@ pub fn deinit(self: *Self) void {
self.pixel_effect.deinit(); self.pixel_effect.deinit();
} }
fn tickPlayer(self: *Self) void { fn updatePlayer(self: *Self) void {
const dt = rl.GetFrameTime(); const dt = rl.GetFrameTime();
var player = &self.player; var player = &self.player;
var rope = &self.rope; var rope = &self.rope;
@ -260,6 +264,12 @@ fn tickPlayer(self: *Self) void {
player.acceleration = rl.Vector2Scale(player.acceleration, walkForce); 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.Vector2Add(player.velocity, rl.Vector2Scale(player.acceleration, dt));
player.velocity = rl.Vector2ClampValue(player.velocity, 0, maxSpeed); player.velocity = rl.Vector2ClampValue(player.velocity, 0, maxSpeed);
player.velocity = rl.Vector2Scale(player.velocity, std.math.pow(f32, (1 - friction), dt)); 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); rope.update(dt);
} }
fn tickEnemies(self: *Self) !void { fn updateEnemies(self: *Self) !void {
var rng = self.prng.random(); var rng = self.prng.random();
const dt = rl.GetFrameTime(); const dt = rl.GetFrameTime();
var enemies = &self.enemies; var enemies = &self.enemies;
@ -282,7 +292,7 @@ fn tickEnemies(self: *Self) !void {
var rope = &self.rope; var rope = &self.rope;
self.enemyTimer -= dt; self.enemyTimer -= dt;
if (self.enemyTimer <= 0) { if (self.enemyTimer <= 0 and player.alive()) {
self.enemyTimer = 0.5 + rng.float(f32) * 2; self.enemyTimer = 0.5 + rng.float(f32) * 2;
self.spawnedEnemiesCount += 1; self.spawnedEnemiesCount += 1;
const enemyPosition = rl.Vector2.randomOnUnitCircle(rng).scale(400); const enemyPosition = rl.Vector2.randomOnUnitCircle(rng).scale(400);
@ -297,7 +307,7 @@ fn tickEnemies(self: *Self) !void {
self.damagePlayer(); 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); self.damageEnemy(enemy);
} }
@ -402,8 +412,8 @@ fn tickUI(self: *Self) !void {
const screen_box = UIBox.init(0 ,0, virtualWidth, virtualHeight); const screen_box = UIBox.init(0 ,0, virtualWidth, virtualHeight);
const font = rl.GetFontDefault(); const font = rl.GetFontDefault();
try allocDrawText(allocator, "{d}", .{self.spawnedEnemiesCount}, 10, 10, 12, rl.RED); // 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.killCount}, 10, 30, 12, rl.GREEN);
const minutes_text = try std.fmt.allocPrint(allocator, "{d:.0}", .{self.timePassed/60}); const minutes_text = try std.fmt.allocPrint(allocator, "{d:.0}", .{self.timePassed/60});
defer allocator.free(minutes_text); 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); const minutes_text_z = try std.mem.concatWithSentinel(allocator, u8, &.{ minutes_text }, 0);
defer allocator.free(minutes_text_z); 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_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( rl.DrawTextEx(
font, font,
time_passed_text, time_passed_text,
@ -430,7 +440,7 @@ fn tickUI(self: *Self) !void {
); );
if (!self.player.alive()) { 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( const modal = screen_box.box(
screen_box.center() - modal_size.x/2, screen_box.center() - modal_size.x/2,
screen_box.middle() - modal_size.y/2, screen_box.middle() - modal_size.y/2,
@ -448,11 +458,20 @@ fn tickUI(self: *Self) !void {
rl.BLACK 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(); 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; self.should_close = true;
} }
} else if (self.paused) { } else if (self.paused) {
@ -497,7 +516,7 @@ fn drawPlayer(self: *Self) void {
var player = &self.player; var player = &self.player;
const handPosition = player.getHandPosition(); const handPosition = player.getHandPosition();
const healthWidth = 5; const healthWidth = 7;
const healthPercent = @as(f32, @floatFromInt(player.health)) / @as(f32, @floatFromInt(player.maxHealth)); const healthPercent = @as(f32, @floatFromInt(player.health)) / @as(f32, @floatFromInt(player.maxHealth));
var healthColor = rl.GREEN; var healthColor = rl.GREEN;
if (player.invincibility > 0 and @rem(player.invincibility, 0.2) < 0.1) { 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| { for (0..(player.health+1)) |i| {
const percent = @as(f32, @floatFromInt(i)) / @as(f32, @floatFromInt(player.maxHealth)); const percent = @as(f32, @floatFromInt(i)) / @as(f32, @floatFromInt(player.maxHealth));
rl.DrawLineV( rl.DrawLineEx(
player.position, player.position,
player.position.add((rl.Vector2{ .x = playerSize + healthWidth, .y = 0 }).rotate(percent * 2 * rl.PI)), player.position.add((rl.Vector2{ .x = playerSize + healthWidth, .y = 0 }).rotate(percent * 2 * rl.PI)),
5,
rl.BLACK 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 { pub fn tick(self: *Self) !void {
const dt = rl.GetFrameTime(); const dt = rl.GetFrameTime();
self.camera.offset.x = virtualWidth/2; if (self.player.input.isPausePressed() and self.player.alive()) {
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()) {
self.togglePaused(); self.togglePaused();
} }
if (!self.paused) { if (!self.paused) {
self.tickPlayer(); self.camera.offset.x = virtualWidth/2;
try self.tickEnemies(); 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()) { if (self.player.alive()) {
self.timePassed += rl.GetFrameTime(); self.timePassed += rl.GetFrameTime();
} }
} }
const deathBallPosition = rope.nodePositions.get(rope.nodePositions.len-1);
self.pixel_effect.begin(); self.pixel_effect.begin();
rl.ClearBackground(rl.BROWN);
rl.BeginMode2D(self.camera); rl.BeginMode2D(self.camera);
{ self.drawWorld();
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
);
}
rl.EndMode2D(); rl.EndMode2D();
self.pixel_effect.end(); self.pixel_effect.end();