ballistic projectiles for cannons
This commit is contained in:
@@ -21,6 +21,7 @@ TOWER_COST :: 50
|
||||
MAX_PROJECTILES :: 64
|
||||
PROJECTILE_SPEED :: 280 // pixels per second
|
||||
PROJECTILE_HIT_RADIUS :: 10
|
||||
CANNON_PROJECTILES_SPEED :: 320.0
|
||||
|
||||
OVERLAY_BAR_H :: 28
|
||||
OVERLAY_PADDING :: 6
|
||||
|
||||
+79
-13
@@ -8,6 +8,13 @@ Projectile :: struct {
|
||||
target_slot: int,
|
||||
damage: int,
|
||||
speed: f32,
|
||||
mode: Projectile_Mode,
|
||||
direction: Vec2,
|
||||
}
|
||||
|
||||
Projectile_Mode :: enum {
|
||||
Homing, // chases target
|
||||
Ballistic, // flies in a fixed direction
|
||||
}
|
||||
|
||||
acquire_projectile :: proc(world: ^World) -> ^Projectile {
|
||||
@@ -33,6 +40,7 @@ spawn_projectile :: proc(world: ^World, from: Vec2, target_slot: int, damage: in
|
||||
p := acquire_projectile(world)
|
||||
if p == nil do return
|
||||
|
||||
p.mode = .Homing
|
||||
p^ = Projectile {
|
||||
active = true,
|
||||
position = from,
|
||||
@@ -42,36 +50,94 @@ spawn_projectile :: proc(world: ^World, from: Vec2, target_slot: int, damage: in
|
||||
}
|
||||
}
|
||||
|
||||
spawn_ballistic :: proc(world: ^World, from, dir: Vec2, damage: int) {
|
||||
p := acquire_projectile(world)
|
||||
if p == nil do return
|
||||
p^ = Projectile {
|
||||
active = true,
|
||||
position = from,
|
||||
direction = dir,
|
||||
mode = .Ballistic,
|
||||
damage = damage,
|
||||
speed = CANNON_PROJECTILES_SPEED,
|
||||
}
|
||||
}
|
||||
|
||||
hit_enemy_at :: proc(world: ^World, pos: Vec2, damage: int) -> bool {
|
||||
for i in 0 ..< MAX_ENEMIES {
|
||||
e := &world.enemies[i]
|
||||
if !e.active do continue
|
||||
if distance(pos, e.position) <= PROJECTILE_HIT_RADIUS {
|
||||
apply_tower_hit(world, e, damage)
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
update_projectiles :: proc(world: ^World, dt: f32) {
|
||||
for i in 0 ..< MAX_PROJECTILES {
|
||||
p := &world.projectiles[i]
|
||||
if !p.active do continue
|
||||
|
||||
target, ok := enemy_still_on_map(world, p.target_slot)
|
||||
if !ok {
|
||||
p.active = false
|
||||
continue
|
||||
switch p.mode {
|
||||
case .Homing:
|
||||
update_homing_projectile(world, p, dt)
|
||||
case .Ballistic:
|
||||
update_ballistic_projectile(world, p, dt)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
move_toward(&p.position, target.position, p.speed, dt)
|
||||
update_homing_projectile :: proc(world: ^World, p: ^Projectile, dt: f32) {
|
||||
target, ok := enemy_still_on_map(world, p.target_slot)
|
||||
if !ok {
|
||||
p.active = false
|
||||
return
|
||||
}
|
||||
|
||||
if distance(p.position, target.position) <= PROJECTILE_HIT_RADIUS {
|
||||
target.health -= p.damage
|
||||
p.active = false
|
||||
move_toward(&p.position, target.position, p.speed, dt)
|
||||
|
||||
if target.health <= 0 {
|
||||
target.active = false
|
||||
push_event(world, .Enemy_Killed, gold_reward = 5)
|
||||
}
|
||||
if distance(p.position, target.position) <= PROJECTILE_HIT_RADIUS {
|
||||
target.health -= p.damage
|
||||
p.active = false
|
||||
|
||||
if target.health <= 0 {
|
||||
target.active = false
|
||||
push_event(world, .Enemy_Killed, gold_reward = 5)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
update_ballistic_projectile :: proc(world: ^World, p: ^Projectile, dt: f32) {
|
||||
step := p.speed * dt
|
||||
p.position.x += p.direction.x * step
|
||||
p.position.y += p.direction.y * step
|
||||
|
||||
if hit_enemy_at(world, p.position, p.damage) {
|
||||
p.active = false
|
||||
return
|
||||
}
|
||||
|
||||
if p.position.x < 0 ||
|
||||
p.position.y < 0 ||
|
||||
p.position.x > MAP_W * TILE_SIZE ||
|
||||
p.position.y > MAP_H * TILE_SIZE {
|
||||
p.active = false
|
||||
}
|
||||
}
|
||||
|
||||
render_projectiles :: proc(world: ^World) {
|
||||
for i in 0 ..< MAX_PROJECTILES {
|
||||
p := world.projectiles[i]
|
||||
if !p.active do continue
|
||||
rl.DrawCircle(i32(p.position.x), i32(p.position.y), 4, rl.GOLD)
|
||||
color := rl.GOLD
|
||||
radius: f32 = 4
|
||||
if p.mode == .Ballistic {
|
||||
color = rl.GRAY
|
||||
radius = 6
|
||||
}
|
||||
rl.DrawCircle(i32(p.position.x), i32(p.position.y), radius, color)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+8
-1
@@ -232,7 +232,14 @@ update_towers :: proc(world: ^World, dt: f32) {
|
||||
spawn_projectile(world, t.position, slot, damage)
|
||||
case .Cannon:
|
||||
if target := enemy_at_slot(world, slot); target != nil {
|
||||
apply_tower_hit(world, target, damage)
|
||||
len := distance(t.position, target.position)
|
||||
if (len > 0.001) {
|
||||
dir := Vec2 {
|
||||
(target.position.x - t.position.x) / len,
|
||||
(target.position.y - t.position.y) / len,
|
||||
}
|
||||
spawn_ballistic(world, t.position, dir, damage)
|
||||
}
|
||||
}
|
||||
case .Ice:
|
||||
if target := enemy_at_slot(world, slot); target != nil {
|
||||
|
||||
Reference in New Issue
Block a user