From f219e74a40c06851fd713f86e892ace3073a9b33 Mon Sep 17 00:00:00 2001 From: Alex Clink Date: Sat, 13 Nov 2021 12:45:51 -0500 Subject: [PATCH] Add emitter --- package.rb | 2 +- src/asteroids.cr | 3 +- src/bullet.cr | 5 +- src/lx_game/emitter.cr | 45 ++++++++++++++++++ src/lx_game/particle.cr | 26 ++++++++++ src/lx_game/sprite.cr | 6 +++ src/ship.cr | 102 +++++++++++++++++++++++----------------- 7 files changed, 140 insertions(+), 49 deletions(-) create mode 100644 src/lx_game/emitter.cr create mode 100644 src/lx_game/particle.cr diff --git a/package.rb b/package.rb index a478ae0..66ad649 100755 --- a/package.rb +++ b/package.rb @@ -72,7 +72,7 @@ end puts "Copying Info.plist" FileUtils.cp 'Info.plist', "#{BUILD_DIR}/" -build_cmd = %{shards build --release --link-flags="-rpath @executable_path/../Frameworks -L #{`brew --prefix sfml`.chomp}/lib/ -mmacosx-version-min=10.14 -headerpad_max_install_names"} +build_cmd = %{shards build --release --link-flags="-rpath @executable_path/../Frameworks -L #{`brew --prefix sdl2`.chomp}/lib/ -mmacosx-version-min=10.14 -headerpad_max_install_names"} puts "Building: `#{build_cmd}`" puts `#{build_cmd}` diff --git a/src/asteroids.cr b/src/asteroids.cr index 7194a09..45695da 100644 --- a/src/asteroids.cr +++ b/src/asteroids.cr @@ -50,8 +50,7 @@ class Asteroids < Game end @bullets.each do |bullet| - bullet.update - bullet.age += dt + bullet.update(dt) end @bullets = @bullets.reject { |b| b.age >= 4.0 } diff --git a/src/bullet.cr b/src/bullet.cr index 0c7e488..a6d4c91 100644 --- a/src/bullet.cr +++ b/src/bullet.cr @@ -1,8 +1,9 @@ class Bullet < Sprite property age : Float64 = 0.0 - def update - @position += @velocity + def update(dt : Float64) + update_position(dt) + @age += dt end def draw(renderer) diff --git a/src/lx_game/emitter.cr b/src/lx_game/emitter.cr new file mode 100644 index 0000000..801e1bf --- /dev/null +++ b/src/lx_game/emitter.cr @@ -0,0 +1,45 @@ +require "./sprite" +require "./particle" + +module LxGame + class Emitter < Sprite + property emitting : Bool = true + property particles = [] of Particle + property max_age : Float64 = 1.0 + property emit_freq : Float64 = 0.05 + property strength : Float64 = 50.0 + @last_emitted : Float64 = 0.0 + property emit_angle : Float64 = 1.0 + + def generate_particle + Particle.build do |particle| + particle.position = @position + direction = rand((@rotation - @emit_angle)..(@rotation + @emit_angle)) + particle.velocity = @velocity + Vector2.new(Math.cos(direction), Math.sin(direction)) * @strength + particle.lifespan = @max_age + end + end + + def update(dt : Float64) + update_position(dt) + + @last_emitted += dt + + if @emitting && @last_emitted >= @emit_freq + @last_emitted = 0.0 + @particles << generate_particle + end + + @particles.each { |particle| particle.update(dt) } + @particles.reject! { |particle| particle.dead? } + end + + def draw(renderer : SDL::Renderer) + renderer.draw_color = SDL::Color[255, 255, 0, 255] + + @particles.each do |particle| + particle.draw(renderer) + end + end + end +end diff --git a/src/lx_game/particle.cr b/src/lx_game/particle.cr new file mode 100644 index 0000000..476b2f8 --- /dev/null +++ b/src/lx_game/particle.cr @@ -0,0 +1,26 @@ +require "./sprite" + +module LxGame + class Particle < Sprite + property age : Float64 = 0.0 + property lifespan : Float64 = 4.0 + @dead : Bool = false + + def dead? + @age >= @lifespan + end + + def update(dt : Float64) + return if dead? + update_position(dt) + @age += dt + end + + def draw(renderer : SDL::Renderer) + return if dead? + brightness = ((@lifespan - @age) / @lifespan) * 255 + renderer.draw_color = SDL::Color[brightness / 2, brightness / 2, brightness / 2] + renderer.draw_point(@position.x.to_i, @position.y.to_i) + end + end +end diff --git a/src/lx_game/sprite.cr b/src/lx_game/sprite.cr index d721962..49dd1df 100644 --- a/src/lx_game/sprite.cr +++ b/src/lx_game/sprite.cr @@ -18,6 +18,12 @@ module LxGame @rotation_speed = 0.0 end + def update_position(dt : Float64) + @rotation += @rotation_speed * dt + @position += @velocity * dt + end + + abstract def update(dt : Float64) abstract def draw(renderer : SDL::Renderer) end end diff --git a/src/ship.cr b/src/ship.cr index 74932b7..f960b8f 100644 --- a/src/ship.cr +++ b/src/ship.cr @@ -1,12 +1,16 @@ class Ship < VectorSprite getter frame : Array(Vector2) - @last_fired : Float64 + @fire_cooldown : Float64 = 0.0 + @fire_rate : Float64 = 0.2 + @emitter : Emitter + @l_emitter : Emitter + @r_emitter : Emitter def initialize super - @r_engine = 0.03 - @t_engine = 0.1 + @r_engine = 10.0 + @t_engine = 20.0 @frame = [ Vector2.new(5.0, 0.0), @@ -14,85 +18,95 @@ class Ship < VectorSprite Vector2.new(-3.0, -3.0), ] - @jet_left = [Vector2.new(2.0, -5.0), Vector2.new(2.0, -3.5)] - @jet_right = [Vector2.new(2.0, 3.5), Vector2.new(2.0, 5.0)] - @jet_rear = [Vector2.new(-7.0, 0.0), Vector2.new(-3.0, 0.0)] + @emitter = Emitter.build do |e| + e.position = @position + e.emit_freq = 0.01 + e.emit_angle = 0.5 + e.strength = 50.0 + e.max_age = 0.25 + end - @thrusting_left = false - @thrusting_right = false - @thrusting_forward = false + @l_emitter = Emitter.build do |e| + e.position = @position + e.emit_freq = 0.01 + e.emit_angle = 0.3 + e.strength = 25.0 + e.max_age = 0.25 + end - @last_fired = Time.monotonic.total_milliseconds + @r_emitter = Emitter.build do |e| + e.position = @position + e.emit_freq = 0.01 + e.emit_angle = 0.3 + e.strength = 25.0 + e.max_age = 0.25 + end end def can_fire? - now = Time.monotonic.total_milliseconds - now - @last_fired > 100.0 + @fire_cooldown <= 0.0 end def fire - @last_fired = Time.monotonic.total_milliseconds + @fire_cooldown = @fire_rate + @velocity.x -= Math.cos(@rotation) * 3.0 + @velocity.y -= Math.sin(@rotation) * 3.0 Bullet.build do |bullet| bullet.position = project_points([@frame[0]]).first - bullet.velocity = @velocity + Vector2.new(Math.cos(@rotation), Math.sin(@rotation)) * 0.1 + bullet.velocity = @velocity + Vector2.new(Math.cos(@rotation), Math.sin(@rotation)) * 100.0 end end def rotate_right(dt : Float64, amount = @r_engine) - @thrusting_left = true + @l_emitter.emitting = true @rotation_speed += amount * dt end def rotate_left(dt : Float64, amount = @r_engine) - @thrusting_right = true + @r_emitter.emitting = true @rotation_speed -= amount * dt end def thrust(dt : Float64) - @thrusting_forward = true + @emitter.emitting = true @velocity.x += Math.cos(@rotation) * dt * @t_engine @velocity.y += Math.sin(@rotation) * dt * @t_engine end def update(dt : Float64) - @rotation += @rotation_speed - @position += @velocity + @fire_cooldown -= dt unless can_fire? + update_position(dt) - # @rotation_speed = 0.0 if @rotation_speed < 0.001 && @rotation_speed > -0.001 - # rotate_left(dt, 0.01) if @rotation_speed >= 0.01 - # rotate_right(dt, 0.01) if @rotation_speed <= -0.01 + @emitter.update(dt) + @emitter.position = project_points([Vector2.new(-3.0, 0.0)]).first + @emitter.velocity = @velocity + @emitter.rotation = @rotation - Math::PI + + @l_emitter.update(dt) + @l_emitter.position = project_points([Vector2.new(3.0, -1.0)]).first + @l_emitter.velocity = @velocity + @l_emitter.rotation = @rotation - 1.5 + + @r_emitter.update(dt) + @r_emitter.position = project_points([Vector2.new(3.0, 1.0)]).first + @r_emitter.velocity = @velocity + @r_emitter.rotation = @rotation + 1.5 end def draw(renderer) + @emitter.draw(renderer) + @emitter.emitting = false + @l_emitter.draw(renderer) + @l_emitter.emitting = false + @r_emitter.draw(renderer) + @r_emitter.emitting = false frame = project_points(@frame) renderer.draw_color = SDL::Color[128, 128, 128, 255] - - if @thrusting_left - @thrusting_left = false - jet_left = project_points(@jet_left, @rotation + rand(-0.5..0.5)) - draw_line(renderer, jet_left[0], jet_left[1]) - end - - if @thrusting_right - @thrusting_right = false - jet_right = project_points(@jet_right, @rotation + rand(-0.5..0.5)) - draw_line(renderer, jet_right[0], jet_right[1]) - end - - if @thrusting_forward - @thrusting_forward = false - jet_rear = project_points(@jet_rear, @rotation + rand(-0.5..0.5)) - draw_line(renderer, jet_rear[0], jet_rear[1]) - end - renderer.draw_color = SDL::Color[255, 255, 255, 255] draw_line(renderer, frame[0], frame[1]) draw_line(renderer, frame[1], frame[2]) draw_line(renderer, frame[2], frame[0]) - - # renderer.draw_color = SDL::Color[255, 255, 0, 255] - # renderer.draw_point(@position.x.to_i, @position.y.to_i) end end