diff --git a/game/enemy/ai.rb b/game/enemy/ai.rb index c75b58a..030a81c 100644 --- a/game/enemy/ai.rb +++ b/game/enemy/ai.rb @@ -18,6 +18,7 @@ class EnemyAI end 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 @speed = @base_speed * 0.3 else @@ -65,7 +66,7 @@ class EnemyAI [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) @avoiding_obstacle = true end @@ -131,12 +132,12 @@ class EnemyAI ] # 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 opposite = [center_x - (first[0] - center_x), center_y - (first[1] - center_y)] 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 << second diff --git a/game/enemy/base.rb b/game/enemy/base.rb index 6bc22ca..866c973 100644 --- a/game/enemy/base.rb +++ b/game/enemy/base.rb @@ -58,6 +58,12 @@ class Enemy end 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 if @health <= 0 $bus.emit(:enemy_died, self) diff --git a/game/weapons/occams_razor.rb b/game/weapons/occams_razor.rb index 3d91cdd..6ff65c4 100644 --- a/game/weapons/occams_razor.rb +++ b/game/weapons/occams_razor.rb @@ -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 end - def attack(_direction) + def attack(direction) return if @active @active = true @time = BASE_TIME + @direction = direction # radians + @spread = Math::PI # 90° total arc + # Check for enemies in range and deal damage player_x, player_y = $bus.get(:player_position) $bus.emit(:attack, player_x, player_y, @range, @damage) @@ -23,6 +26,10 @@ class OccamsRazor return unless @active @time -= dt + + progress = @time / BASE_TIME + @spread = (Math::PI) * progress + if @time <= 0 @active = false @time = 0 @@ -30,6 +37,27 @@ class OccamsRazor end 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 \ No newline at end of file