mirror of
https://github.com/SleepingInsomniac/asteroids
synced 2024-12-26 21:59:30 +01:00
Add collision
This commit is contained in:
parent
86f413a2af
commit
fb844057b0
4 changed files with 119 additions and 5 deletions
|
@ -3,10 +3,13 @@ class Asteroid < VectorSprite
|
||||||
|
|
||||||
def initialize
|
def initialize
|
||||||
super
|
super
|
||||||
@frame = VectorSprite.generate_circle(15, size: 10.0, jitter: 3.0)
|
@frame = [] of Vector2
|
||||||
end
|
end
|
||||||
|
|
||||||
def draw(renderer)
|
def draw(renderer)
|
||||||
|
# renderer.draw_color = SDL::Color[0, 100, 100, 255]
|
||||||
|
# draw_radius(renderer)
|
||||||
|
|
||||||
frame = project_points(points: @frame, scale: Vector2.new(@size, @size))
|
frame = project_points(points: @frame, scale: Vector2.new(@size, @size))
|
||||||
renderer.draw_color = SDL::Color[128, 128, 128, 255]
|
renderer.draw_color = SDL::Color[128, 128, 128, 255]
|
||||||
draw_frame(renderer, frame)
|
draw_frame(renderer, frame)
|
||||||
|
|
|
@ -35,12 +35,16 @@ class Asteroids < Game
|
||||||
ship.position = Vector2.new(x: width / 2.0, y: height / 2.0)
|
ship.position = Vector2.new(x: width / 2.0, y: height / 2.0)
|
||||||
end
|
end
|
||||||
|
|
||||||
4.times do
|
8.times do
|
||||||
@asteroids << Asteroid.build do |a|
|
@asteroids << Asteroid.build do |a|
|
||||||
a.position = Vector2.new(x: rand(0.0..width.to_f), y: rand(0.0..height.to_f))
|
a.position = Vector2.new(x: rand(0.0..width.to_f), y: rand(0.0..height.to_f))
|
||||||
a.velocity = Vector2.new(x: rand(-20.0..20.0), y: rand(-20.0..20.0))
|
v_max = 30.0
|
||||||
|
a.velocity = Vector2.new(x: rand(-v_max..v_max), y: rand(-v_max..v_max))
|
||||||
a.rotation_speed = rand(-5.0..5.0)
|
a.rotation_speed = rand(-5.0..5.0)
|
||||||
a.size = rand(0.5..4.0)
|
|
||||||
|
size = rand(5.0..30.0)
|
||||||
|
a.mass = size
|
||||||
|
a.frame = VectorSprite.generate_circle(size.to_i, size: size, jitter: 3.0)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -85,6 +89,44 @@ class Asteroids < Game
|
||||||
a.update(dt)
|
a.update(dt)
|
||||||
a.position = wrap(a.position)
|
a.position = wrap(a.position)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
collission_pairs = [] of Tuple(Asteroid, Asteroid)
|
||||||
|
@asteroids.each do |a|
|
||||||
|
@asteroids.each do |b|
|
||||||
|
next if a == b
|
||||||
|
next if collission_pairs.includes?({a, b})
|
||||||
|
|
||||||
|
if a.collides_with?(b)
|
||||||
|
collission_pairs << {a, b}
|
||||||
|
a.resolve_collision(b)
|
||||||
|
puts "#{a} collided with #{b}"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
@bullets.each do |bullet|
|
||||||
|
@asteroids.each do |asteroid|
|
||||||
|
if bullet.collides_with?(asteroid)
|
||||||
|
if asteroid.mass > 3.0
|
||||||
|
2.times do
|
||||||
|
@asteroids << Asteroid.build do |a|
|
||||||
|
a.position = asteroid.position + Vector2.new(rand(-1.0..1.0), rand(-1.0..1.0))
|
||||||
|
v_max = 30.0
|
||||||
|
a.velocity = Vector2.new(x: rand(-v_max..v_max), y: rand(-v_max..v_max))
|
||||||
|
a.rotation_speed = rand(-5.0..5.0)
|
||||||
|
size = asteroid.average_radius / 2
|
||||||
|
a.mass = size
|
||||||
|
points = size < 6 ? 6 : size.to_i
|
||||||
|
a.frame = VectorSprite.generate_circle(points, size: size, jitter: 3.0)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
@asteroids.delete(asteroid)
|
||||||
|
@bullets.delete(bullet)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def draw
|
def draw
|
||||||
|
|
|
@ -11,4 +11,8 @@ class Bullet < Sprite
|
||||||
renderer.draw_color = SDL::Color[brightness, brightness, 0]
|
renderer.draw_color = SDL::Color[brightness, brightness, 0]
|
||||||
renderer.draw_point(@position.x.to_i, @position.y.to_i)
|
renderer.draw_point(@position.x.to_i, @position.y.to_i)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def collides_with?(other : VectorSprite)
|
||||||
|
@position.distance(other.position) < other.average_radius
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
module LxGame
|
module LxGame
|
||||||
abstract class VectorSprite < Sprite
|
abstract class VectorSprite < Sprite
|
||||||
getter frame = [] of Vector2
|
property mass : Float64 = 10.0
|
||||||
|
property frame = [] of Vector2
|
||||||
|
@average_radius : Float64? = nil
|
||||||
|
|
||||||
def self.generate_circle(num_points : Int, size = 1.0, jitter = 0.0) : Array(Vector2)
|
def self.generate_circle(num_points : Int, size = 1.0, jitter = 0.0) : Array(Vector2)
|
||||||
0.upto(num_points).map do |n|
|
0.upto(num_points).map do |n|
|
||||||
|
@ -36,6 +38,18 @@ module LxGame
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def average_radius
|
||||||
|
@average_radius ||= begin
|
||||||
|
# calculate length from center for all points
|
||||||
|
lengths = frame.map do |vec|
|
||||||
|
Math.sqrt(vec.x ** 2 + vec.y ** 2)
|
||||||
|
end
|
||||||
|
|
||||||
|
# get the average of the lengths
|
||||||
|
lengths.reduce { |t, p| t + p } / frame.size.to_f
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
def update(dt : Float64)
|
def update(dt : Float64)
|
||||||
update_position(dt)
|
update_position(dt)
|
||||||
end
|
end
|
||||||
|
@ -45,5 +59,56 @@ module LxGame
|
||||||
draw_line(renderer, frame[n], frame[(n + 1) % frame.size])
|
draw_line(renderer, frame[n], frame[(n + 1) % frame.size])
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def draw_radius(renderer : SDL::Renderer, points = 30)
|
||||||
|
circle = self.class.generate_circle(points, average_radius).map do |point|
|
||||||
|
point + @position
|
||||||
|
end
|
||||||
|
draw_frame(renderer, frame: circle)
|
||||||
|
end
|
||||||
|
|
||||||
|
def distance_between(other)
|
||||||
|
@position.distance(other.position)
|
||||||
|
end
|
||||||
|
|
||||||
|
def collides_with?(other : VectorSprite)
|
||||||
|
distance_between(other) < average_radius + other.average_radius
|
||||||
|
end
|
||||||
|
|
||||||
|
# Move objects so that they don't overlap
|
||||||
|
def offset_position(other : VectorSprite)
|
||||||
|
distance = distance_between(other)
|
||||||
|
overlap = distance - average_radius - other.average_radius
|
||||||
|
offset = ((@position - other.position) * (overlap / 2)) / distance
|
||||||
|
|
||||||
|
@position -= offset
|
||||||
|
other.position += offset
|
||||||
|
end
|
||||||
|
|
||||||
|
def resolve_collision(other : VectorSprite)
|
||||||
|
offset_position(other)
|
||||||
|
distance = distance_between(other)
|
||||||
|
|
||||||
|
# Calculate the new velocities
|
||||||
|
normal_vec = (@position - other.position) / distance
|
||||||
|
tangental_vec = Vector2.new(-normal_vec.y, normal_vec.x)
|
||||||
|
|
||||||
|
# Dot product of velocity with the tangent
|
||||||
|
# (the direction in which to bounce towards)
|
||||||
|
dp_tangent_a = velocity.dot(tangental_vec)
|
||||||
|
dp_tangent_b = other.velocity.dot(tangental_vec)
|
||||||
|
|
||||||
|
# Dot product of the normal
|
||||||
|
dp_normal_a = velocity.dot(normal_vec)
|
||||||
|
dp_normal_b = other.velocity.dot(normal_vec)
|
||||||
|
|
||||||
|
# conservation of momentum
|
||||||
|
ma = (dp_normal_a * (mass - other.mass) + 2.0 * other.mass * dp_normal_b) / (mass + other.mass)
|
||||||
|
mb = (dp_normal_b * (other.mass - mass) + 2.0 * mass * dp_normal_a) / (mass + other.mass)
|
||||||
|
|
||||||
|
# Set the new velocities
|
||||||
|
@velocity = (tangental_vec * dp_tangent_a) + (normal_vec * ma)
|
||||||
|
other.velocity = (tangental_vec * dp_tangent_b) + (normal_vec * mb)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
Loading…
Reference in a new issue