Class: Engine::GameObject

Inherits:
Object
  • Object
show all
Defined in:
lib/engine/game_object.rb

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(name = "Game Object", pos: Vector[0, 0, 0], rotation: 0, scale: Vector[1, 1, 1], components: [], parent: nil) ⇒ GameObject

Returns a new instance of GameObject.



13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
# File 'lib/engine/game_object.rb', line 13

def initialize(name = "Game Object", pos: Vector[0, 0, 0], rotation: 0, scale: Vector[1, 1, 1], components: [], parent: nil)
  GameObject.object_spawned(self)
  @pos = Vector[pos[0], pos[1], pos[2] || 0]
  if rotation.is_a?(Numeric)
    self.rotation = Quaternion.from_euler(Vector[0, 0, rotation])
  elsif rotation.is_a?(Quaternion)
    self.rotation = rotation
  else
    self.rotation = Quaternion.from_euler(rotation)
  end
  @scale = scale
  @name = name
  @components = components.select { |component| !component.renderer? && !component.ui_renderer? }
  @renderers = components.select { |component| component.renderer? }
  @ui_renderers = components.select { |component| component.ui_renderer? }
  @created_at = Time.now
  @parent = parent
  parent.add_child(self) if parent

  components.each { |component| component.set_game_object(self) }
  components.each(&:start)
end

Instance Attribute Details

#componentsObject

Returns the value of attribute components.



11
12
13
# File 'lib/engine/game_object.rb', line 11

def components
  @components
end

#created_atObject

Returns the value of attribute created_at.



11
12
13
# File 'lib/engine/game_object.rb', line 11

def created_at
  @created_at
end

#nameObject

Returns the value of attribute name.



11
12
13
# File 'lib/engine/game_object.rb', line 11

def name
  @name
end

#parentObject

Returns the value of attribute parent.



11
12
13
# File 'lib/engine/game_object.rb', line 11

def parent
  @parent
end

#posObject

Returns the value of attribute pos.



11
12
13
# File 'lib/engine/game_object.rb', line 11

def pos
  @pos
end

#renderersObject

Returns the value of attribute renderers.



11
12
13
# File 'lib/engine/game_object.rb', line 11

def renderers
  @renderers
end

#scaleObject

Returns the value of attribute scale.



11
12
13
# File 'lib/engine/game_object.rb', line 11

def scale
  @scale
end

#ui_renderersObject

Returns the value of attribute ui_renderers.



11
12
13
# File 'lib/engine/game_object.rb', line 11

def ui_renderers
  @ui_renderers
end

Class Method Details

.destroy_allObject



195
196
197
198
199
# File 'lib/engine/game_object.rb', line 195

def self.destroy_all
  GameObject.objects.dup.each do |object|
    object.destroy! unless object.destroyed?
  end
end

.destroyed_objectsObject



230
231
232
# File 'lib/engine/game_object.rb', line 230

def self.destroyed_objects
  @destroyed_objects ||= []
end

.erase_destroyed_objectsObject



170
171
172
173
174
175
# File 'lib/engine/game_object.rb', line 170

def self.erase_destroyed_objects
  destroyed_objects.each do |object|
    object._erase!
  end
  @destroyed_objects = []
end

.mesh_renderersObject



210
211
212
213
214
# File 'lib/engine/game_object.rb', line 210

def self.mesh_renderers
  GameObject.objects.flat_map do |object|
    object.renderers
  end
end

.method_added(name) ⇒ Object



5
6
7
8
9
# File 'lib/engine/game_object.rb', line 5

def self.method_added(name)
  @methods ||= Set.new
  return if name == :initialize || name == :destroyed?
  @methods.add(name)
end

.object_spawned(object) ⇒ Object



222
223
224
# File 'lib/engine/game_object.rb', line 222

def self.object_spawned(object)
  objects << object
end

.objectsObject



226
227
228
# File 'lib/engine/game_object.rb', line 226

def self.objects
  @objects ||= []
end

.render_ui(delta_time) ⇒ Object



216
217
218
219
220
# File 'lib/engine/game_object.rb', line 216

def self.render_ui(delta_time)
  GameObject.objects.each do |object|
    object.ui_renderers.each { |renderer| renderer.update(delta_time) }
  end
end

.update_all(delta_time) ⇒ Object



201
202
203
204
205
206
207
208
# File 'lib/engine/game_object.rb', line 201

def self.update_all(delta_time)
  GameObject.objects.each do |object|
    object.components.each { |component| component.update(delta_time) }
  end

  Component.erase_destroyed_components
  GameObject.erase_destroyed_objects
end

Instance Method Details

#_erase!Object



160
161
162
163
164
165
166
167
168
# File 'lib/engine/game_object.rb', line 160

def _erase!
  GameObject.objects.delete(self)
  parent.children.delete(self) if parent
  name = @name
  self.class.instance_variable_get(:@methods).each do |method|
    singleton_class.send(:undef_method, method)
    singleton_class.send(:define_method, method) { raise "This object has been destroyed: #{name}" }
  end
end

#add_child(child) ⇒ Object



44
45
46
47
# File 'lib/engine/game_object.rb', line 44

def add_child(child)
  child.parent = self
  children << child
end

#childrenObject



40
41
42
# File 'lib/engine/game_object.rb', line 40

def children
  @children ||= Set.new
end

#destroy!Object



149
150
151
152
153
154
155
156
157
158
# File 'lib/engine/game_object.rb', line 149

def destroy!
  return unless GameObject.objects.include?(self)
  children.each(&:destroy!)
  components.each(&:destroy!)
  ui_renderers.each(&:destroy!)
  renderers.each(&:destroy!)

  GameObject.destroyed_objects << self unless @destroyed
  @destroyed = true
end

#destroyed?Boolean

Returns:

  • (Boolean)


145
146
147
# File 'lib/engine/game_object.rb', line 145

def destroyed?
  @destroyed
end

#euler_anglesObject



65
66
67
# File 'lib/engine/game_object.rb', line 65

def euler_angles
  rotation.to_euler
end

#forwardObject



189
190
191
192
193
# File 'lib/engine/game_object.rb', line 189

def forward
  return @forward if @cached_forward_rotation == rotation
  @cached_forward_rotation = rotation.dup
  @forward = local_to_world_direction(Vector[0, 0, 1])
end

#local_to_world_coordinate(local) ⇒ Object



93
94
95
96
97
# File 'lib/engine/game_object.rb', line 93

def local_to_world_coordinate(local)
  local_x4 = Matrix[[local[0], local[1], local[2], 1.0]]
  world = local_x4 * model_matrix
  Vector[world[0, 0], world[0, 1], world[0, 2]]
end

#local_to_world_direction(local) ⇒ Object



105
106
107
# File 'lib/engine/game_object.rb', line 105

def local_to_world_direction(local)
  local_to_world_coordinate(local) - pos
end

#model_matrixObject



115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
# File 'lib/engine/game_object.rb', line 115

def model_matrix
  cache_key = [@pos.dup, rotation.dup, @scale.dup, @parent&.model_matrix&.to_a]
  @model_matrix = nil if @model_matrix_cache_key != cache_key
  @model_matrix_cache_key = cache_key
  @model_matrix ||=
    begin
      rot = euler_angles * Math::PI / 180

      cos_x = Math.cos(rot[0])
      cos_y = Math.cos(rot[1])
      cos_z = Math.cos(rot[2])

      sin_x = Math.sin(rot[0])
      sin_y = Math.sin(rot[1])
      sin_z = Math.sin(rot[2])

      Matrix[
        [scale[0] * (cos_y * cos_z), scale[0] * (-cos_y * sin_z), scale[0] * sin_y, 0],
        [scale[1] * (cos_x * sin_z + sin_x * sin_y * cos_z), scale[1] * (cos_x * cos_z - sin_x * sin_y * sin_z), scale[1] * -sin_x * cos_y, 0],
        [scale[2] * (sin_x * sin_z - cos_x * sin_y * cos_z), scale[2] * (sin_x * cos_z + cos_x * sin_y * sin_z), scale[2] * cos_x * cos_y, 0],
        [x, y, z, 1]
      ]
    end
  if parent
    @model_matrix * parent.model_matrix
  else
    @model_matrix
  end
end

#rightObject



183
184
185
186
187
# File 'lib/engine/game_object.rb', line 183

def right
  return @right if @cached_right_rotation == rotation
  @cached_right_rotation = rotation.dup
  @right = local_to_world_direction(Vector[1, 0, 0])
end

#rotate_around(axis, angle) ⇒ Object



109
110
111
112
113
# File 'lib/engine/game_object.rb', line 109

def rotate_around(axis, angle)
  rotation_quaternion = Quaternion.from_angle_axis(angle, axis)

  self.rotation = rotation_quaternion * rotation
end

#rotationObject



55
56
57
# File 'lib/engine/game_object.rb', line 55

def rotation
  @rotation_quaternion
end

#rotation=(value) ⇒ Object



59
60
61
62
63
# File 'lib/engine/game_object.rb', line 59

def rotation=(value)
  raise "Rotation must be a Quaternion" unless value.is_a?(Quaternion)

  @rotation_quaternion = value
end

#to_sObject



36
37
38
# File 'lib/engine/game_object.rb', line 36

def to_s
  @name
end

#upObject



177
178
179
180
181
# File 'lib/engine/game_object.rb', line 177

def up
  return @up if @cached_up_rotation == rotation
  @cached_up_rotation = rotation.dup
  @up = local_to_world_direction(Vector[0, 1, 0])
end

#world_to_local_coordinate(world) ⇒ Object



99
100
101
102
103
# File 'lib/engine/game_object.rb', line 99

def world_to_local_coordinate(world)
  world_x4 = Matrix[[world[0], world[1], world[2], 1.0]]
  local = world_x4 * model_matrix.inverse
  Vector[local[0, 0], local[0, 1], local[0, 2]]
end

#xObject



69
70
71
# File 'lib/engine/game_object.rb', line 69

def x
  @pos[0]
end

#x=(value) ⇒ Object



73
74
75
# File 'lib/engine/game_object.rb', line 73

def x=(value)
  @pos = Vector[value, y, z]
end

#yObject



77
78
79
# File 'lib/engine/game_object.rb', line 77

def y
  @pos[1]
end

#y=(value) ⇒ Object



81
82
83
# File 'lib/engine/game_object.rb', line 81

def y=(value)
  @pos = Vector[x, value, z]
end

#zObject



85
86
87
# File 'lib/engine/game_object.rb', line 85

def z
  @pos[2]
end

#z=(value) ⇒ Object



89
90
91
# File 'lib/engine/game_object.rb', line 89

def z=(value)
  @pos = Vector[x, y, value]
end