mirror of
https://github.com/cyberarm/i-mic-fps.git
synced 2025-12-15 23:52:35 +00:00
Implemented a first class BoundingBox, refactored to use bounding box.
This commit is contained in:
@@ -37,8 +37,6 @@ else
|
|||||||
raise RuntimeError, "Unsupported platform."
|
raise RuntimeError, "Unsupported platform."
|
||||||
end
|
end
|
||||||
|
|
||||||
BoundingBox = Struct.new(:min_x, :min_y, :min_z, :max_x, :max_y, :max_z)
|
|
||||||
|
|
||||||
if RUBY_VERSION < "2.5.0"
|
if RUBY_VERSION < "2.5.0"
|
||||||
puts "-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-"
|
puts "-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-"
|
||||||
puts "|NOTICE| Ruby is #{RUBY_VERSION} not 2.5.0+..............................|Notice|"
|
puts "|NOTICE| Ruby is #{RUBY_VERSION} not 2.5.0+..............................|Notice|"
|
||||||
@@ -63,6 +61,7 @@ $debug = ARGV.join.include?("--debug") ? true : false
|
|||||||
require_relative "lib/common_methods"
|
require_relative "lib/common_methods"
|
||||||
|
|
||||||
require_relative "lib/math/vector"
|
require_relative "lib/math/vector"
|
||||||
|
require_relative "lib/math/bounding_box"
|
||||||
require_relative "lib/trees/aabb_tree"
|
require_relative "lib/trees/aabb_tree"
|
||||||
|
|
||||||
require_relative "lib/managers/input_mapper"
|
require_relative "lib/managers/input_mapper"
|
||||||
|
|||||||
@@ -9,6 +9,11 @@ class IMICFPS
|
|||||||
@aabb_tree.add(entity.normalized_bounding_box, entity)
|
@aabb_tree.add(entity.normalized_bounding_box, entity)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def update
|
||||||
|
lazy_check_collisions
|
||||||
|
@aabb_tree.update
|
||||||
|
end
|
||||||
|
|
||||||
def remove(entity)
|
def remove(entity)
|
||||||
@aabb_tree.remove(entity)
|
@aabb_tree.remove(entity)
|
||||||
end
|
end
|
||||||
@@ -19,8 +24,10 @@ class IMICFPS
|
|||||||
@game_state.entities.each do |other|
|
@game_state.entities.each do |other|
|
||||||
next if entity == other
|
next if entity == other
|
||||||
next if entity.is_a?(Terrain) || other.is_a?(Terrain)
|
next if entity.is_a?(Terrain) || other.is_a?(Terrain)
|
||||||
|
next unless entity.collidable?
|
||||||
|
next unless other.collidable?
|
||||||
|
|
||||||
if entity.intersect(other)
|
if entity.normalized_bounding_box.intersect(other.normalized_bounding_box)
|
||||||
entity.debug_color = Color.new(1.0,0.0,0.0)
|
entity.debug_color = Color.new(1.0,0.0,0.0)
|
||||||
other.debug_color = Color.new(1.0,0.0,0.0)
|
other.debug_color = Color.new(1.0,0.0,0.0)
|
||||||
|
|
||||||
@@ -33,10 +40,5 @@ class IMICFPS
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def update
|
|
||||||
lazy_check_collisions
|
|
||||||
# @aabb_tree.rebuild
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
100
lib/math/bounding_box.rb
Normal file
100
lib/math/bounding_box.rb
Normal file
@@ -0,0 +1,100 @@
|
|||||||
|
class IMICFPS
|
||||||
|
class BoundingBox
|
||||||
|
attr_accessor :min_x, :min_y, :min_z, :max_x, :max_y, :max_z
|
||||||
|
|
||||||
|
def initialize(min_x = 0.0, min_y = 0.0, min_z = 0.0, max_x = 0.0, max_y = 0.0, max_z = 0.0)
|
||||||
|
@min_x = min_x
|
||||||
|
@min_y = min_y
|
||||||
|
@min_z = min_z
|
||||||
|
|
||||||
|
@max_x = max_x
|
||||||
|
@max_y = max_y
|
||||||
|
@max_z = max_z
|
||||||
|
end
|
||||||
|
|
||||||
|
def ==(other)
|
||||||
|
min_x == other.min_x &&
|
||||||
|
min_y == other.min_y &&
|
||||||
|
min_z == other.min_z &&
|
||||||
|
max_x == other.max_x &&
|
||||||
|
max_y == other.max_y &&
|
||||||
|
max_z == other.max_z
|
||||||
|
end
|
||||||
|
|
||||||
|
# returns a new bounding box that includes both bounding boxes
|
||||||
|
def union(other)
|
||||||
|
temp = BoundingBox.new
|
||||||
|
temp.min_x = [min_x, other.min_x].min
|
||||||
|
temp.min_y = [min_y, other.min_y].min
|
||||||
|
temp.min_z = [min_z, other.min_z].min
|
||||||
|
|
||||||
|
temp.max_x = [max_x, other.max_x].max
|
||||||
|
temp.max_y = [max_y, other.max_y].max
|
||||||
|
temp.max_z = [max_z, other.max_z].max
|
||||||
|
|
||||||
|
return temp
|
||||||
|
end
|
||||||
|
|
||||||
|
# returns boolean
|
||||||
|
def intersect(other)
|
||||||
|
(min_x <= other.max_x && max_x >= other.min_x) &&
|
||||||
|
(min_y <= other.max_y && max_y >= other.min_y) &&
|
||||||
|
(min_z <= other.max_z && max_z >= other.min_z)
|
||||||
|
end
|
||||||
|
|
||||||
|
def difference(other)
|
||||||
|
temp = BoundingBox.new
|
||||||
|
temp.min_x = min_x - other.min_x
|
||||||
|
temp.min_y = min_y - other.min_y
|
||||||
|
temp.min_z = min_z - other.min_z
|
||||||
|
|
||||||
|
temp.max_x = max_x - other.max_x
|
||||||
|
temp.max_y = max_y - other.max_y
|
||||||
|
temp.max_z = max_z - other.max_z
|
||||||
|
|
||||||
|
return temp
|
||||||
|
end
|
||||||
|
|
||||||
|
def volume
|
||||||
|
width * height * depth
|
||||||
|
end
|
||||||
|
|
||||||
|
def width
|
||||||
|
@max_x - @min_x
|
||||||
|
end
|
||||||
|
|
||||||
|
def height
|
||||||
|
@max_y - @min_y
|
||||||
|
end
|
||||||
|
|
||||||
|
def depth
|
||||||
|
@max_z - @min_z
|
||||||
|
end
|
||||||
|
|
||||||
|
def normalize(entity)
|
||||||
|
temp = BoundingBox.new
|
||||||
|
temp.min_x = min_x.to_f * entity.scale
|
||||||
|
temp.min_y = min_y.to_f * entity.scale
|
||||||
|
temp.min_z = min_z.to_f * entity.scale
|
||||||
|
|
||||||
|
temp.max_x = max_x.to_f * entity.scale
|
||||||
|
temp.max_y = max_y.to_f * entity.scale
|
||||||
|
temp.max_z = max_z.to_f * entity.scale
|
||||||
|
|
||||||
|
return temp
|
||||||
|
end
|
||||||
|
|
||||||
|
def normalize_with_offset(entity)
|
||||||
|
temp = BoundingBox.new
|
||||||
|
temp.min_x = min_x.to_f * entity.scale + entity.position.x
|
||||||
|
temp.min_y = min_y.to_f * entity.scale + entity.position.y
|
||||||
|
temp.min_z = min_z.to_f * entity.scale + entity.position.z
|
||||||
|
|
||||||
|
temp.max_x = max_x.to_f * entity.scale + entity.position.x
|
||||||
|
temp.max_y = max_y.to_f * entity.scale + entity.position.y
|
||||||
|
temp.max_z = max_z.to_f * entity.scale + entity.position.z
|
||||||
|
|
||||||
|
return temp
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
class IMICFPS
|
class IMICFPS
|
||||||
class Terrain < Entity
|
class Terrain < Entity
|
||||||
def setup
|
def setup
|
||||||
bind_model("base", "randomish_terrain")
|
bind_model("base", "randomish_terrain")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -6,10 +6,9 @@ class IMICFPS
|
|||||||
include OpenGL
|
include OpenGL
|
||||||
include GLU
|
include GLU
|
||||||
include CommonMethods
|
include CommonMethods
|
||||||
attr_accessor :scale
|
attr_accessor :scale, :visible, :renderable, :backface_culling
|
||||||
attr_accessor :visible, :renderable, :backface_culling
|
|
||||||
attr_reader :position, :rotation, :velocity
|
attr_reader :position, :rotation, :velocity
|
||||||
attr_reader :model, :name, :debug_color, :width, :height, :depth, :last_x, :last_y, :last_z, :normalized_bounding_box
|
attr_reader :model, :name, :debug_color, :normalized_bounding_box
|
||||||
def initialize(x: 0, y: 0, z: 0, bound_model: nil, scale: MODEL_METER_SCALE, backface_culling: true, auto_manage: true, manifest_file: nil)
|
def initialize(x: 0, y: 0, z: 0, bound_model: nil, scale: MODEL_METER_SCALE, backface_culling: true, auto_manage: true, manifest_file: nil)
|
||||||
@position = Vector.new(x, y, z)
|
@position = Vector.new(x, y, z)
|
||||||
@scale = scale
|
@scale = scale
|
||||||
@@ -27,7 +26,6 @@ class IMICFPS
|
|||||||
@physics = false
|
@physics = false
|
||||||
@mass = 100 # kg
|
@mass = 100 # kg
|
||||||
|
|
||||||
@width, @height, @depth = 0,0,0
|
|
||||||
@delta_time = Gosu.milliseconds
|
@delta_time = Gosu.milliseconds
|
||||||
@last_position = Vector.new(@position.x, @position.y, @position.z)
|
@last_position = Vector.new(@position.x, @position.y, @position.z)
|
||||||
|
|
||||||
@@ -39,9 +37,6 @@ class IMICFPS
|
|||||||
@normalized_bounding_box = normalize_bounding_box_with_offset
|
@normalized_bounding_box = normalize_bounding_box_with_offset
|
||||||
|
|
||||||
box = normalize_bounding_box
|
box = normalize_bounding_box
|
||||||
@width = box.max_x-box.min_x
|
|
||||||
@height = box.max_y-box.min_y
|
|
||||||
@depth = box.max_z-box.min_z
|
|
||||||
end
|
end
|
||||||
|
|
||||||
return self
|
return self
|
||||||
@@ -61,9 +56,6 @@ class IMICFPS
|
|||||||
@normalized_bounding_box = normalize_bounding_box_with_offset
|
@normalized_bounding_box = normalize_bounding_box_with_offset
|
||||||
|
|
||||||
box = normalize_bounding_box
|
box = normalize_bounding_box
|
||||||
@width = box.max_x-box.min_x
|
|
||||||
@height = box.max_y-box.min_y
|
|
||||||
@depth = box.max_z-box.min_z
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def model
|
def model
|
||||||
@@ -89,8 +81,6 @@ class IMICFPS
|
|||||||
unless at_same_position?
|
unless at_same_position?
|
||||||
@normalized_bounding_box = normalize_bounding_box_with_offset if model
|
@normalized_bounding_box = normalize_bounding_box_with_offset if model
|
||||||
end
|
end
|
||||||
|
|
||||||
@last_x, @last_y, @last_z = @x, @y, @z
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def debug_color=(color)
|
def debug_color=(color)
|
||||||
@@ -101,53 +91,16 @@ class IMICFPS
|
|||||||
@position == @last_position
|
@position == @last_position
|
||||||
end
|
end
|
||||||
|
|
||||||
# Do two Axis Aligned Bounding Boxes intersect?
|
|
||||||
def intersect(other)
|
|
||||||
me = normalized_bounding_box
|
|
||||||
other = other.normalized_bounding_box
|
|
||||||
|
|
||||||
# puts "bounding boxes match!" if a == b
|
|
||||||
if (me.min_x <= other.max_x && me.max_x >= other.min_x) &&
|
|
||||||
(me.min_y <= other.max_y && me.max_y >= other.min_y) &&
|
|
||||||
(me.min_z <= other.max_z && me.max_z >= other.min_z)
|
|
||||||
return true
|
|
||||||
else
|
|
||||||
return false
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def distance(vertex, other)
|
def distance(vertex, other)
|
||||||
return Math.sqrt((vertex.x-other.x)**2 + (vertex.y-other.y)**2 + (vertex.z-other.z)**2)
|
return Math.sqrt((vertex.x-other.x)**2 + (vertex.y-other.y)**2 + (vertex.z-other.z)**2)
|
||||||
end
|
end
|
||||||
|
|
||||||
def normalize_bounding_box
|
def normalize_bounding_box_with_offset
|
||||||
box = @bound_model.model.bounding_box
|
@bound_model.model.bounding_box.normalize_with_offset(self)
|
||||||
|
|
||||||
temp = BoundingBox.new
|
|
||||||
temp.min_x = box.min_x.to_f*scale
|
|
||||||
temp.min_y = box.min_y.to_f*scale
|
|
||||||
temp.min_z = box.min_z.to_f*scale
|
|
||||||
|
|
||||||
temp.max_x = box.max_x.to_f*scale
|
|
||||||
temp.max_y = box.max_y.to_f*scale
|
|
||||||
temp.max_z = box.max_z.to_f*scale
|
|
||||||
|
|
||||||
return temp
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def normalize_bounding_box_with_offset
|
def normalize_bounding_box
|
||||||
box = @bound_model.model.bounding_box
|
@bound_model.model.bounding_box.normalize(self)
|
||||||
|
|
||||||
temp = BoundingBox.new
|
|
||||||
temp.min_x = box.min_x.to_f*scale+@position.x
|
|
||||||
temp.min_y = box.min_y.to_f*scale+@position.y
|
|
||||||
temp.min_z = box.min_z.to_f*scale+@position.z
|
|
||||||
|
|
||||||
temp.max_x = box.max_x.to_f*scale+@position.x
|
|
||||||
temp.max_y = box.max_y.to_f*scale+@position.y
|
|
||||||
temp.max_z = box.max_z.to_f*scale+@position.z
|
|
||||||
|
|
||||||
return temp
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def handleGlError
|
def handleGlError
|
||||||
|
|||||||
@@ -10,13 +10,20 @@ class IMICFPS
|
|||||||
raise "Object can't be nil!" unless object
|
raise "Object can't be nil!" unless object
|
||||||
|
|
||||||
if @root
|
if @root
|
||||||
@root.insert_subtree(bounding_box, object)
|
@root.insert_subtree(bounding_box.dup, object)
|
||||||
else
|
else
|
||||||
@root = AABBNode.new(parent: nil, object: object, bounding_box: BoundingBox.new(0,0,0, 0,0,0))
|
@root = AABBNode.new(parent: nil, object: object, bounding_box: BoundingBox.new(0,0,0, 0,0,0))
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def update(object)
|
def update
|
||||||
|
@objects.each do |object, node|
|
||||||
|
unless object.bounding_box == node.bounding_box
|
||||||
|
puts "#{object.class} mutated!"
|
||||||
|
remove(node)
|
||||||
|
add(object)
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
# Returns a list of all collided objects inside Bounding Box
|
# Returns a list of all collided objects inside Bounding Box
|
||||||
@@ -26,17 +33,23 @@ class IMICFPS
|
|||||||
end
|
end
|
||||||
|
|
||||||
def remove(object)
|
def remove(object)
|
||||||
|
@root.remove_subtree(@objects[object])
|
||||||
|
@objects[object] = nil
|
||||||
end
|
end
|
||||||
|
|
||||||
class AABBNode
|
class AABBNode
|
||||||
|
attr_accessor :bounding_box, :parent, :object, :a, :b
|
||||||
def initialize(parent:, object:, bounding_box:)
|
def initialize(parent:, object:, bounding_box:)
|
||||||
@parent = parent
|
@parent = parent
|
||||||
@object = object
|
@object = object
|
||||||
@bounding_box = bounding_box
|
@bounding_box = bounding_box
|
||||||
|
|
||||||
|
@a = nil
|
||||||
|
@b = nil
|
||||||
end
|
end
|
||||||
|
|
||||||
def insert_subtree(bounding_box, object)
|
def insert_subtree(bounding_box, object)
|
||||||
p "#{bounding_box} -> #{object.class}"
|
# p "#{bounding_box} -> #{object.class}"
|
||||||
end
|
end
|
||||||
|
|
||||||
def remove_subtree(node)
|
def remove_subtree(node)
|
||||||
|
|||||||
Reference in New Issue
Block a user