Skip to content

Commit

Permalink
particles + knocback when shooting
Browse files Browse the repository at this point in the history
  • Loading branch information
F-3r committed Mar 11, 2023
1 parent 251a33d commit 0a08200
Show file tree
Hide file tree
Showing 12 changed files with 234 additions and 193 deletions.
1 change: 0 additions & 1 deletion app/camera.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ def follow(camera, target:, bounds:)
camera[:y] = (target.y - (camera.h / 2) + (target.h / 2)).clamp(0, bounds.top - camera.h)
end

# Returns a copy of the object with its x and y coordinates translated
def translate(camera, object)
return object.map do |o|
if sprite = o[:sprite]
Expand Down
34 changes: 34 additions & 0 deletions app/effects/fireworks_effect.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@

module FireworksEffect
DISSOLVE_SPEED = 2
class << self
def emit_particle(sys)
{
x: sys.x + rand(20),
y: sys.y + rand(20),
w: 1,
h: 1,
angle: 0,
dir: rand(360),
r: rand(255), g: rand(255), b: rand(255), a: 150,
path: :pixel,
blendmode_enum: 2
}
end

def tick(particle, sys)
sys.particles.delete particle if dead_particle? particle

particle.x += 1.5 * (Math.cos(particle.dir * DEG2RAD) - 1) / DISSOLVE_SPEED
particle.y += 1.5 * (Math.sin(particle.dir * DEG2RAD) - 1) / DISSOLVE_SPEED
particle.angle += (particle.dir < 180) ? -0.5 : 0.5
particle.h += 2 / DISSOLVE_SPEED
particle.w += 2 / DISSOLVE_SPEED
particle.a -= DISSOLVE_SPEED
end

def dead_particle?(particle)
particle.a <= 0
end
end
end
35 changes: 35 additions & 0 deletions app/effects/smoke_effect.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
module SmokeEffect
DISSOLVE_SPEED = 2
class << self
def emit_particle(sys)
color = random(150,255)
puts "dir: #{sys.dir + rand(180) - 90}"
{
x: sys.x,
y: sys.y,
w: 8,
h: 8,
angle: 0,
dir: sys.dir + rand(180) - 90,
r: color, g: color, b: color, a: 150,
path: Sprite::SPRITES[:bullet],
blendmode_enum: 2
}
end

def tick(particle, sys)
sys.particles.delete particle if dead_particle? particle

particle.x += (Math.cos(particle.dir * DEG2RAD)) *1.2
particle.y += (Math.sin(particle.dir * DEG2RAD)) *1.2
particle.angle += [-5, 5].sample
particle.h -= 0.1
particle.w -= 0.1
particle.a -= 5
end

def dead_particle?(particle)
particle.a <= 0
end
end
end
93 changes: 15 additions & 78 deletions app/fireworks.rb
Original file line number Diff line number Diff line change
@@ -1,89 +1,26 @@
module Fireworks
DEG2RAD = Math::PI / 180

class << self
def create
[]
end

def ignite(x, y, rate, counter, reducer)
{
x: x,
y: y,
rate: rate,
particles: [],
ticks_since_last_emission: 0,
counter: counter,
reducer: reducer,
}
end

def update fw
fw.counter -= 1
update_particles fw
if emit? fw
# rate: 5 => 12 pps; 0.2 => 300 pps. If ticks_per_emision < 1, multiple particles will be emitted in a single tick
ticks_per_emission = 60.fdiv(fw.rate)

# count ticks until we reach a tick where we should emit a particle.
fw.ticks_since_last_emission += 1
particles_to_emit = (fw.ticks_since_last_emission / ticks_per_emission).floor

if particles_to_emit > 0
particles_to_emit.times { |i| fw.particles << emit(fw) }
fw.ticks_since_last_emission = 0
end
end
end

def emit? fw
true if fw.counter.nil?
fw.counter > 0
end

def dead? fw
fw.counter <= 0 && fw.particles.empty?
end

def update_particles fw
fw.particles.reject! {|p| p[:a]<=0}

fw.particles.each do |p|
p.x += (Math.cos(p.dir * DEG2RAD) - 1) / fw.reducer
p.y += (Math.sin(p.dir * DEG2RAD) - 1) / fw.reducer
p.angle += p.dir < 180 ? -0.5 : 0.5
p.h += (2)/fw.reducer
p.w += (2)/fw.reducer
p.a -= 1
end
end

def render(sprites, fw)
sprites << fw.particles
end

def emit fw
{
x: (fw.x) + rand(20), y: (fw.y) + rand(20), w: 1, h: 1, angle: 0, dir: rand(360),
r: rand(255), g: rand(255), b: rand(255), a: 150,
path: :pixel, blendmode_enum: 2,
}
end

def extinguish(fireworks)
fireworks.length.times { |i| fireworks.pop }
end

def launch(fireworks, num)
num.times {|fw| fireworks << ignite(rand(1200)+40, rand(700)+10, 20, 50, [5,10,10,15][rand(4)])}
def tick(fireworks, args)
fireworks.reject! { ParticleSystem.dead? _1 }
fireworks.each { ParticleSystem.tick(args, _1) }
args.outputs.sprites << fireworks.flat_map { _1.particles }
end

def tick(args, fireworks)
sprites = args.outputs.sprites
fireworks.each do |fw|
update(fw)
fireworks.delete(fw) if dead? fw
render(sprites, fw)
def launch(fireworks, args)
if args.tick_count.mod_zero?(4)
fireworks << ParticleSystem.create(
FireworksEffect,
x: rand(1200)+40,
y: rand(700)+10,
w: 20,
h:20,
rate: random(30,50),
duration: random(20,50)
)
end
end
end
Expand Down
4 changes: 3 additions & 1 deletion app/main.rb
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,9 @@
require "app/hud.rb"
require "app/fireworks.rb"
require "app/boss.rb"

require "app/particle_system.rb"
require "app/effects/smoke_effect.rb"
require "app/effects/fireworks_effect.rb"
require "app/scenes/game_over.rb"
require "app/scenes/gameplay.rb"
require "app/scenes/level_generation.rb"
Expand Down
5 changes: 3 additions & 2 deletions app/mana_chip.rb
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,13 @@ def create(enemy)

def animate(args, mana_chip)
mana_chip.angle += 1
mana_chip.w = 12 + 1 * Math.sin(args.state.tick_count / 15)
mana_chip.h = 12 + 1 * Math.sin(args.state.tick_count / 15)
mana_chip.w = 12 + 2 * Math.sin(args.state.tick_count / 20)
mana_chip.h = 12 + 2 * Math.sin(args.state.tick_count / 20)
end

def tick(args, mana_chip)
animate(args, mana_chip)

player = args.state.player
if args.geometry.distance(mana_chip, player) <= player.mana_chip_magnetic_dist
mana_chip.angle = args.geometry.angle_to(mana_chip, player)
Expand Down
51 changes: 51 additions & 0 deletions app/particle_system.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
module ParticleSystem
class << self
def create(effect, x:, y:, w: 1, h: 1, rate: 20, dir: 0, duration: nil)
{
effect: effect, # effect is a module that implements the Effect interface Eg: app/smoke_effect.rb
rate: rate,
x: x,
y: y,
w: w,
h: h,
dir: dir,
duration: duration,
ticks_since_last_emission: 0,
particles: []
}
end

def tick(args, sys)
sys.duration -= 1 if sys.duration

sys.particles.each { sys.effect.tick _1, sys }

if emit? sys
# rate: 5 => 12 pps; 0.2 => 300 pps. If ticks_per_emision < 1, multiple particles will be emitted in a single tick
ticks_per_emission = 60.fdiv(sys.rate)

# count ticks until we reach a tick where we should emit a particle.
sys.ticks_since_last_emission += 1
particles_to_emit = (sys.ticks_since_last_emission / ticks_per_emission).floor

if particles_to_emit > 0
particles_to_emit.times { |i| sys.particles << sys.effect.emit_particle(sys) }
sys.ticks_since_last_emission = 0
end
end
end

def emit? sys
true if sys.duration.nil?
sys.duration > 0
end

def dead? sys
sys.duration <= 0 && sys.particles.empty?
end

def destroy(sys)
sys.particles = []
end
end
end
Loading

0 comments on commit 0a08200

Please sign in to comment.