mirror of
https://github.com/cyberarm/i-mic-fps.git
synced 2025-12-13 06:42:35 +00:00
114 lines
3.1 KiB
Ruby
114 lines
3.1 KiB
Ruby
# frozen_string_literal: true
|
|
|
|
class IMICFPS
|
|
class CollisionManager
|
|
attr_reader :map, :collisions
|
|
|
|
def initialize(map:)
|
|
@map = map
|
|
@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
|
|
@map.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 = {}
|
|
|
|
@map.entities.each do |entity|
|
|
next unless entity.collidable?
|
|
next if entity.manifest.collision_resolution == :static # Only dynamic entities can be resolved
|
|
|
|
search = @aabb_tree.search(entity.bounding_box)
|
|
if search.size.positive?
|
|
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.zero? && target.orientation.zero?
|
|
|
|
# "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
|
|
|
|
box
|
|
end
|
|
|
|
def on_ground?(entity) # TODO: Use some form of caching to speed this up
|
|
on_ground = false
|
|
@collisions.detect do |a, b|
|
|
next unless entity == a || entity == b
|
|
|
|
vs = a
|
|
vs = b if a == entity
|
|
|
|
broadphase = search(Ray.new(entity.position, Vector.down, entity.velocity.y.abs))
|
|
|
|
broadphase.detect do |ent|
|
|
ray = Ray.new(entity.position - ent.position, Vector.down)
|
|
if ent.model.aabb_tree.search(ray).size.positive?
|
|
on_ground = true
|
|
return true
|
|
end
|
|
end
|
|
|
|
break if on_ground
|
|
end
|
|
|
|
on_ground
|
|
end
|
|
end
|
|
end
|