120 lines
2.6 KiB
Ruby
120 lines
2.6 KiB
Ruby
require_relative 'ai'
|
|
|
|
class Enemy
|
|
attr_accessor :x, :y, :w, :h, :lorentz
|
|
|
|
def self.load(path, w, h, s)
|
|
# Once artwork is done need to load each animation here.
|
|
# But as artwork takes time, for now just load a single image.
|
|
@sprite = Gosu::Image.new(path, retro: true)
|
|
@i_w = w * s
|
|
@i_h = h * s
|
|
@s = s
|
|
end
|
|
|
|
def self.sprite
|
|
@sprite
|
|
end
|
|
|
|
def self.frame_size
|
|
[@i_w, @i_h, @s]
|
|
end
|
|
|
|
def initialize(x, y, health = 100)
|
|
@x = x
|
|
@y = y
|
|
@w = 25
|
|
@h = 30
|
|
@health = health
|
|
@stun = 0
|
|
@last_lock = :none
|
|
@lorentz = $bus.get(:lorentz_field?) || false
|
|
|
|
$bus.on(:lorentz_field!) do |lorentz|
|
|
@lorentz = lorentz
|
|
end
|
|
|
|
@ai = EnemyAI.new(self, :chase)
|
|
|
|
$bus.on(:collides?) do |rect|
|
|
next collides?(rect) ? :enemy : nil
|
|
end
|
|
|
|
$bus.on(:blast) do |x, y, radius, damage, _|
|
|
dist = Math.hypot(@x - x, @y - y)
|
|
if dist <= radius + 20
|
|
take_damage(damage * 2)
|
|
end
|
|
end
|
|
|
|
$bus.on(:stun) do |x, y|
|
|
dist = Math.hypot(@x - x, @y - y)
|
|
if dist <= 100
|
|
@stun = 60 * 1 # stun for 1 second
|
|
end
|
|
end
|
|
end
|
|
|
|
def take_damage(amount)
|
|
@health -= amount
|
|
if @health <= 0
|
|
$bus.emit(:enemy_died, self)
|
|
end
|
|
end
|
|
|
|
def rect
|
|
[@x - @w / 2, @y - @h / 2, @w, @h]
|
|
end
|
|
|
|
def collides?(rect)
|
|
return true if intersects?(self.rect, rect)
|
|
false
|
|
end
|
|
|
|
def update(dt)
|
|
if @stun > 0
|
|
@stun -= 1
|
|
return
|
|
end
|
|
|
|
player_pos = $bus.get(:player_position)
|
|
closest_event_horizon = $bus.get(:closest_event_horizon, @x, @y, 200)
|
|
if closest_event_horizon
|
|
@ai.update(*closest_event_horizon, dt, @last_lock != :event_horizon)
|
|
@last_lock = :event_horizon
|
|
else
|
|
@ai.update(*player_pos, dt, @last_lock != :player) if player_pos
|
|
@last_lock = :player
|
|
end
|
|
|
|
if $bus.get_all(:collides?, rect).include?(:trap)
|
|
$bus.emit(:trap_stepped_on, rect, :enemy)
|
|
end
|
|
end
|
|
|
|
def draw
|
|
cam_x, cam_y = $bus.get(:camera_pos) || [0, 0]
|
|
|
|
screen_x = @x - cam_x
|
|
screen_y = @y - cam_y
|
|
|
|
self.class.sprite.draw(
|
|
screen_x - self.class.frame_size[0] / 2,
|
|
screen_y - self.class.frame_size[1] / 2,
|
|
screen_y - self.class.frame_size[1] / 2 + 10,
|
|
self.class.frame_size[2],
|
|
self.class.frame_size[2]
|
|
)
|
|
|
|
# Health bar
|
|
|
|
health_width = (@w * @health / 100.0)
|
|
Gosu.draw_rect(screen_x - @w / 2, screen_y - @h / 2 - 10, health_width, 5, Gosu::Color.new(0xFF00FF00), Float::INFINITY)
|
|
|
|
if $bus.get(:settings, :debug)
|
|
Gosu.draw_rect(screen_x - @w / 2, screen_y - @h / 2, @w, @h, Gosu::Color.new(0x40FF0000), Float::INFINITY)
|
|
end
|
|
|
|
@ai.draw
|
|
end
|
|
end |