Files
i-mic-fps/lib/managers/collision_manager.rb

87 lines
2.5 KiB
Ruby

class IMICFPS
class CollisionManager
attr_reader :game_state, :collisions
def initialize(game_state:)
@game_state = game_state
@collisions = {}
@aabb_tree = AABBTree.new
@physics_manager = PhysicsManager.new(collision_manager: self)
end
def add(entity)
@aabb_tree.insert(entity, entity.bounding_box)
end
def update
@game_state.entities.each do |entity|
next unless entity.is_a?(Entity)
next unless node = @aabb_tree.objects[entity]
unless entity.bounding_box == node.bounding_box
puts "Updating #{entity.class}"
@aabb_tree.update(entity, entity.bounding_box.clone)
end
end
check_broadphase
@physics_manager.update
end
def search(collider)
@aabb_tree.search(collider)
end
def remove(entity)
@aabb_tree.remove(entity)
end
def check_broadphase
# FIXME: Cache collisions to speed things up
@collisions.clear
broadphase = {}
@game_state.entities.each do |entity|
next unless entity.collidable?
next if entity.collision == :static # Only dynamic entities can be resolved
search = @aabb_tree.search(entity.bounding_box)
if search.size > 0
search.reject! {|ent| ent == entity || !ent.collidable?}
broadphase[entity] = search
end
end
broadphase.each do |entity, _collisions|
_collisions.each do |ent|
# aabb vs aabb
next unless entity.bounding_box.intersect?(ent.bounding_box)
# entity model aabb tree vs ent model aabb tree
ent_tree_search = ent.model.aabb_tree.search(localize_entity_bounding_box(entity, ent), true)
next if ent_tree_search.size == 0
# puts "#{ent.class} -> #{ent_tree_search.size} (#{Gosu.milliseconds})"
entity.position.y = ent_tree_search.first.object.vertices.first.y if entity.is_a?(Player) && ent.is_a?(Terrain)
@collisions[entity] = _collisions
end
end
end
# AABBTree on entities is relative to model origin of 0,0,0
def localize_entity_bounding_box(entity, target)
return entity.bounding_box if target.position == 0 && target.orientation == 0
# "tranform" entity bounding box into target's space
local = (target.position) # needs tweaking, works well enough for now
box = entity.bounding_box.clone
box.min -= local
box.max -= local
return box
end
end
end