Enhance enemy AI and weapon mechanics: add knockback effect based on player position in Enemy class; improve attack direction handling and animation in OccamsRazor class.
Basically the finishing touches.
This commit is contained in:
+4
-3
@@ -18,6 +18,7 @@ class EnemyAI
|
|||||||
end
|
end
|
||||||
|
|
||||||
def update(player_x, player_y, dt, force = false)
|
def update(player_x, player_y, dt, force = false)
|
||||||
|
distance = Math.hypot(@enemy.x - player_x, @enemy.y - player_y)
|
||||||
if @enemy.lorentz && distance < 230
|
if @enemy.lorentz && distance < 230
|
||||||
@speed = @base_speed * 0.3
|
@speed = @base_speed * 0.3
|
||||||
else
|
else
|
||||||
@@ -65,7 +66,7 @@ class EnemyAI
|
|||||||
[center_x - CORNER_OFFSET, center_y + CORNER_OFFSET]
|
[center_x - CORNER_OFFSET, center_y + CORNER_OFFSET]
|
||||||
]
|
]
|
||||||
|
|
||||||
closest_idx = corners.each_with_index.min_by { |c, _| Gosu.distance(c[0], c[1], @enemy.x, @enemy.y) }[1]
|
closest_idx = corners.each_with_index.min_by { |c, _| Math.hypot(c[0] - @enemy.x, c[1] - @enemy.y) }[1]
|
||||||
@waypoints = corners.rotate(closest_idx)
|
@waypoints = corners.rotate(closest_idx)
|
||||||
@avoiding_obstacle = true
|
@avoiding_obstacle = true
|
||||||
end
|
end
|
||||||
@@ -131,12 +132,12 @@ class EnemyAI
|
|||||||
]
|
]
|
||||||
|
|
||||||
# first waypoint: corner closest to where we're coming from
|
# first waypoint: corner closest to where we're coming from
|
||||||
first = corners.min_by { |cx, cy| Gosu.distance(cx, cy, prev_cx, prev_cy) }
|
first = corners.min_by { |cx, cy| Math.hypot(cx - prev_cx, cy - prev_cy) }
|
||||||
|
|
||||||
# second waypoint: closest to next tile but not opposite to first
|
# second waypoint: closest to next tile but not opposite to first
|
||||||
opposite = [center_x - (first[0] - center_x), center_y - (first[1] - center_y)]
|
opposite = [center_x - (first[0] - center_x), center_y - (first[1] - center_y)]
|
||||||
candidates = corners.reject { |c| c == first || c == opposite }
|
candidates = corners.reject { |c| c == first || c == opposite }
|
||||||
second = candidates.min_by { |cx, cy| Gosu.distance(cx, cy, next_cx, next_cy) }
|
second = candidates.min_by { |cx, cy| Math.hypot(cx - next_cx, cy - next_cy) }
|
||||||
|
|
||||||
waypoints << first
|
waypoints << first
|
||||||
waypoints << second
|
waypoints << second
|
||||||
|
|||||||
@@ -58,6 +58,12 @@ class Enemy
|
|||||||
end
|
end
|
||||||
|
|
||||||
def take_damage(amount)
|
def take_damage(amount)
|
||||||
|
# knockback a bit based on player position
|
||||||
|
player_x, player_y = $bus.get(:player_position) || [0, 0]
|
||||||
|
angle = Math.atan2(@y - player_y, @x - player_x)
|
||||||
|
knockback_distance = 10
|
||||||
|
@x += Math.cos(angle) * knockback_distance
|
||||||
|
@y += Math.sin(angle) * knockback_distance
|
||||||
@health -= amount
|
@health -= amount
|
||||||
if @health <= 0
|
if @health <= 0
|
||||||
$bus.emit(:enemy_died, self)
|
$bus.emit(:enemy_died, self)
|
||||||
|
|||||||
@@ -8,12 +8,15 @@ class OccamsRazor
|
|||||||
@range = 45 # how many pixels from player center to enemy center the attack hits, this is a melee weapon so it should be small
|
@range = 45 # how many pixels from player center to enemy center the attack hits, this is a melee weapon so it should be small
|
||||||
end
|
end
|
||||||
|
|
||||||
def attack(_direction)
|
def attack(direction)
|
||||||
return if @active
|
return if @active
|
||||||
|
|
||||||
@active = true
|
@active = true
|
||||||
@time = BASE_TIME
|
@time = BASE_TIME
|
||||||
|
|
||||||
|
@direction = direction # radians
|
||||||
|
@spread = Math::PI # 90° total arc
|
||||||
|
|
||||||
# Check for enemies in range and deal damage
|
# Check for enemies in range and deal damage
|
||||||
player_x, player_y = $bus.get(:player_position)
|
player_x, player_y = $bus.get(:player_position)
|
||||||
$bus.emit(:attack, player_x, player_y, @range, @damage)
|
$bus.emit(:attack, player_x, player_y, @range, @damage)
|
||||||
@@ -23,6 +26,10 @@ class OccamsRazor
|
|||||||
return unless @active
|
return unless @active
|
||||||
|
|
||||||
@time -= dt
|
@time -= dt
|
||||||
|
|
||||||
|
progress = @time / BASE_TIME
|
||||||
|
@spread = (Math::PI) * progress
|
||||||
|
|
||||||
if @time <= 0
|
if @time <= 0
|
||||||
@active = false
|
@active = false
|
||||||
@time = 0
|
@time = 0
|
||||||
@@ -30,6 +37,27 @@ class OccamsRazor
|
|||||||
end
|
end
|
||||||
|
|
||||||
def draw
|
def draw
|
||||||
# Nothing for now, but player attack animation would go here
|
return unless @active
|
||||||
|
|
||||||
|
px, py = $bus.get(:player_position)
|
||||||
|
cam_x, cam_y = $bus.get(:camera_pos) || [0, 0]
|
||||||
|
|
||||||
|
cx = px - cam_x
|
||||||
|
cy = py - cam_y
|
||||||
|
|
||||||
|
step = 0.1 # radians (~6°)
|
||||||
|
|
||||||
|
angle_start = @direction - @spread
|
||||||
|
angle_end = @direction + @spread
|
||||||
|
|
||||||
|
alpha = ((@time / BASE_TIME) * 255).to_i
|
||||||
|
color = Gosu::Color.new(alpha, 255, 255, 255)
|
||||||
|
|
||||||
|
(angle_start..angle_end).step(step) do |rad|
|
||||||
|
x = cx + Math.cos(rad) * @range
|
||||||
|
y = cy + Math.sin(rad) * @range
|
||||||
|
|
||||||
|
Gosu.draw_rect(x, y, 4, 4, color, Float::INFINITY)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
Reference in New Issue
Block a user