diff --git a/.vscode/settings.json b/.vscode/settings.json index adb8654..66eb04c 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -3,4 +3,5 @@ "editor.insertSpaces": true, "editor.fontFamily": "'Operator Mono Lig', monospace", "editor.fontSize": 14, + "editor.fontLigatures": true, } \ No newline at end of file diff --git a/game/enemy/ai.rb b/game/enemy/ai.rb index 59cf532..e2e9955 100644 --- a/game/enemy/ai.rb +++ b/game/enemy/ai.rb @@ -2,6 +2,7 @@ class EnemyAI AGGRO_RADIUS = 2000 BASE_SPEED = 130.0 CORNER_OFFSET = 35 # how far from tile center to place corner waypoint + ATTACK_COOLDOWN = 0.2 # seconds def initialize(enemy, type) @enemy = enemy @@ -11,22 +12,14 @@ class EnemyAI @last_player_tile = nil @avoiding_obstacle = false @speed = BASE_SPEED - @lorentz_effect_active = false - - $bus.on(:lorentz_field) do - @lorentz_effect_active = true - end - - $bus.on(:lorentz_field_end) do - @lorentz_effect_active = false - end + @time_since_attack = ATTACK_COOLDOWN end def update(player_x, player_y, dt) distance = Math.sqrt((player_x - @enemy.x)**2 + (player_y - @enemy.y)**2) return unless distance < AGGRO_RADIUS - if @lorentz_effect_active && distance < 230 + if @enemy.lorentz && distance < 230 @speed = BASE_SPEED * 0.3 else @speed = BASE_SPEED @@ -42,7 +35,14 @@ class EnemyAI enemy_tile[0] > start_room_tile[0] - 1 && enemy_tile[0] < start_room_tile[0] + 3 && enemy_tile[1] > start_room_tile[1] - 1 && enemy_tile[1] < start_room_tile[1] + 3 - return if $bus.get_all(:collides?, @enemy.rect)&.include?(:character) + if $bus.get_all(:collides?, @enemy.rect)&.include?(:character) + if @time_since_attack >= ATTACK_COOLDOWN + $bus.emit(:enemy_attack, 10) # deal 10 damage + @time_since_attack = 0 + end + @time_since_attack += dt + return + end prop_in_tile = $bus.get(:prop_at, enemy_tile[0], enemy_tile[1]) @@ -150,15 +150,14 @@ class EnemyAI end def move_towards(target_x, target_y, dt) - angle = Gosu.angle(@enemy.x, @enemy.y, target_x, target_y) - dx = Gosu.offset_x(angle, @speed * dt) - dy = Gosu.offset_y(angle, @speed * dt) + dx_raw = target_x - @enemy.x + dy_raw = target_y - @enemy.y + angle = Math.atan2(dy_raw, dx_raw) + + dx = Math.cos(angle) * @speed * dt + dy = Math.sin(angle) * @speed * dt @enemy.x += dx @enemy.y += dy - - if $bus.get_all(:collides?, @enemy.rect)&.include?(:character) - # Attack player - end end end \ No newline at end of file diff --git a/game/enemy/base.rb b/game/enemy/base.rb index 4ef1883..ede5997 100644 --- a/game/enemy/base.rb +++ b/game/enemy/base.rb @@ -1,14 +1,14 @@ require_relative 'ai' class Enemy - attr_accessor :x, :y, :w, :h + 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 - @i_h = h + @i_w = w * s + @i_h = h * s @s = s end @@ -20,11 +20,17 @@ class Enemy [@i_w, @i_h, @s] end - def initialize(x, y) + def initialize(x, y, health = 100) @x = x @y = y @w = 25 @h = 30 + @health = health + @lorentz = false + + $bus.on(:lorentz_field?) do |lorentz| + @lorentz = lorentz + end @ai = EnemyAI.new(self, :chase) @@ -33,6 +39,15 @@ class Enemy end end + def take_damage(amount) + @health -= amount + pp "Enemy takes #{amount} damage, health now #{@health}" + if @health <= 0 + pp "Enemy dies" + $bus.emit(:enemy_died, self) + end + end + def rect [@x - @w / 2, @y - @h / 2, @w, @h] end @@ -53,16 +68,17 @@ class Enemy screen_x = @x - cam_x screen_y = @y - cam_y - self.class.sprite.draw( - screen_x - self.class.frame_size[0], - screen_y - self.class.frame_size[1], - screen_y - self.class.frame_size[1], + 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] ) - Gosu.draw_rect(screen_x - @w / 2, screen_y - @h / 2, @w, @h, Gosu::Color.new(0x40FF0000), Float::INFINITY) if $bus.get(:settings, :debug) + 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 diff --git a/game/enemy/force.rb b/game/enemy/force.rb index 546245d..060fe8e 100644 --- a/game/enemy/force.rb +++ b/game/enemy/force.rb @@ -4,8 +4,13 @@ class Force < Enemy load 'assets/images/force.png', 21, 32, 1.7 def initialize(x, y) - super - @w = 20 - @h = 20 + super(x, y, 100) + + $bus.on(:occams_razor_attack) do |attack_x, attack_y, range, damage| + # Whoa, did'nt know ruby had hypot functions built in! + if Math.hypot(@x - attack_x, @y - attack_y) <= range + take_damage(damage) + end + end end end \ No newline at end of file diff --git a/game/enemy/handler.rb b/game/enemy/handler.rb index 0e97375..a7e5cf4 100644 --- a/game/enemy/handler.rb +++ b/game/enemy/handler.rb @@ -3,6 +3,11 @@ require_relative 'force' class EnemyHandler def initialize @enemies = [] + + $bus.on(:enemy_died) do |enemy| + $bus.remove_owner(enemy) + @enemies.delete(enemy) + end end def update(dt) diff --git a/game/hud/layer.rb b/game/hud/layer.rb index 16e1342..762103a 100644 --- a/game/hud/layer.rb +++ b/game/hud/layer.rb @@ -5,6 +5,10 @@ class HUDLayer @hud_bg = Gosu::Image.new("assets/images/hud.png", retro: true) @hud_fg = Gosu::Image.new("assets/images/hud_fg.png", retro: true) @inventory = Inventory.new + + $bus.on(:enemy_attack) do |damage| + pp "Player takes #{damage} damage!" + end end def draw diff --git a/game/weapons/handler.rb b/game/weapons/handler.rb index 86eb963..4c5ec39 100644 --- a/game/weapons/handler.rb +++ b/game/weapons/handler.rb @@ -1,5 +1,5 @@ require_relative 'lorentz_field' -#require_relative 'occams_razor' +require_relative 'occams_razor' #require_relative 'quantum_bow' #require_relative 'blade_of_recursion' @@ -7,7 +7,7 @@ class WeaponHandler def initialize @weapons = { lorentz_field: LorentzField.new, - #occams_razor: OccamsRazor.new, + occams_razor: OccamsRazor.new, #quantum_bow: QuantumBow.new, #blade_of_recursion: BladeOfRecursion.new } diff --git a/game/weapons/lorentz_field.rb b/game/weapons/lorentz_field.rb index 3b757f0..621efba 100644 --- a/game/weapons/lorentz_field.rb +++ b/game/weapons/lorentz_field.rb @@ -32,7 +32,7 @@ class LorentzField $bus.emit(:consume, :lorentz_field, 1) @active = true @time = 0 - $bus.emit(:lorentz_field) + $bus.emit(:lorentz_field?, true) end def update(dt) @@ -42,7 +42,7 @@ class LorentzField if @time >= BASE_TIME @time = 0 @active = false - $bus.emit(:lorentz_field_end) + $bus.emit(:lorentz_field?, false) end end diff --git a/game/weapons/occams_razor.rb b/game/weapons/occams_razor.rb index 052ed57..8fb2939 100644 --- a/game/weapons/occams_razor.rb +++ b/game/weapons/occams_razor.rb @@ -1,9 +1,35 @@ class OccamsRazor + BASE_TIME = 0.2 # seconds per attack + def initialize - # + @time = 0 + @active = false + @damage = 20 + @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(dt) - # + def attack + return if @active + + @active = true + @time = BASE_TIME + + # Check for enemies in range and deal damage + player_x, player_y = $bus.get(:player_position) + $bus.emit(:occams_razor_attack, player_x, player_y, @range, @damage) + end + + def update(dt) + return unless @active + + @time -= dt + if @time <= 0 + @active = false + @time = 0 + end + end + + def draw + # Nothing for now, but player attack animation would go here end end \ No newline at end of file