Module: MiniGL::Movement
- Included in:
- GameObject
- Defined in:
- lib/minigl/movement.rb
Overview
This module provides objects with physical properties and methods for moving. It allows moving with or without collision checking (based on rectangular bounding boxes), including a method to behave as an elevator, affecting other objects’ positions as it moves.
Instance Attribute Summary collapse
-
#bottom ⇒ Object
readonly
The object that is making contact with this from below.
-
#h ⇒ Object
readonly
Height of the bounding box.
-
#left ⇒ Object
readonly
The object that is making contact with this from the left.
-
#mass ⇒ Object
readonly
The mass of the object, in arbitrary units.
-
#max_speed ⇒ Object
readonly
A Vector with the speed limits for the object (x: horizontal component, y: vertical component).
-
#passable ⇒ Object
Whether a moving object can pass through this block when coming from below.
-
#prev_speed ⇒ Object
readonly
A Vector containing the speed of the object in the previous frame.
-
#right ⇒ Object
readonly
The object that is making contact with this from the right.
-
#speed ⇒ Object
readonly
A Vector with the current speed of the object (x: horizontal component, y: vertical component).
-
#stored_forces ⇒ Object
A Vector with the horizontal and vertical components of a force that be applied in the next time
move
is called. -
#top ⇒ Object
readonly
The object that is making contact with this from above.
-
#w ⇒ Object
readonly
Width of the bounding box.
-
#x ⇒ Object
The x-coordinate of the top left corner of the bounding box.
-
#y ⇒ Object
The y-coordinate of the top left corner of the bounding box.
Instance Method Summary collapse
-
#bounds ⇒ Object
Returns the bounding box as a Rectangle.
-
#cycle(points, speed, obstacles = nil, obst_obstacles = nil, obst_ramps = nil, stop_time = 0) ⇒ Object
Causes the object to move in cycles across multiple given points (the first point in the array is the first point the object will move towards, so it doesn’t need to be equal to the current/initial position).
-
#move(forces, obst, ramps, set_speed = false) ⇒ Object
Moves this object, based on the forces being applied to it, and performing collision checking.
-
#move_carrying(arg, speed, carried_objs, obstacles, ramps, ignore_collision = false) ⇒ Object
Moves this object as an elevator (i.e., potentially carrying other objects) with the specified forces or towards a given point.
-
#move_free(aim, speed) ⇒ Object
Moves this object, without performing any collision checking, towards a specified point or in a specified direction.
Instance Attribute Details
#bottom ⇒ Object (readonly)
The object that is making contact with this from below. If there’s no contact, returns nil
.
195 196 197 |
# File 'lib/minigl/movement.rb', line 195 def bottom @bottom end |
#h ⇒ Object (readonly)
Height of the bounding box.
187 188 189 |
# File 'lib/minigl/movement.rb', line 187 def h @h end |
#left ⇒ Object (readonly)
The object that is making contact with this from the left. If there’s no contact, returns nil
.
199 200 201 |
# File 'lib/minigl/movement.rb', line 199 def left @left end |
#mass ⇒ Object (readonly)
The mass of the object, in arbitrary units. The default value for GameObject instances, for example, is 1. The larger the mass (i.e., the heavier the object), the more intense the forces applied to the object have to be in order to move it.
173 174 175 |
# File 'lib/minigl/movement.rb', line 173 def mass @mass end |
#max_speed ⇒ Object (readonly)
A Vector with the speed limits for the object (x: horizontal component, y: vertical component).
181 182 183 |
# File 'lib/minigl/movement.rb', line 181 def max_speed @max_speed end |
#passable ⇒ Object
Whether a moving object can pass through this block when coming from below. This is a common feature of platforms in platform games.
213 214 215 |
# File 'lib/minigl/movement.rb', line 213 def passable @passable end |
#prev_speed ⇒ Object (readonly)
A Vector containing the speed of the object in the previous frame.
220 221 222 |
# File 'lib/minigl/movement.rb', line 220 def prev_speed @prev_speed end |
#right ⇒ Object (readonly)
The object that is making contact with this from the right. If there’s no contact, returns nil
.
203 204 205 |
# File 'lib/minigl/movement.rb', line 203 def right @right end |
#speed ⇒ Object (readonly)
A Vector with the current speed of the object (x: horizontal component, y: vertical component).
177 178 179 |
# File 'lib/minigl/movement.rb', line 177 def speed @speed end |
#stored_forces ⇒ Object
A Vector with the horizontal and vertical components of a force that be applied in the next time move
is called.
217 218 219 |
# File 'lib/minigl/movement.rb', line 217 def stored_forces @stored_forces end |
#top ⇒ Object (readonly)
The object that is making contact with this from above. If there’s no contact, returns nil
.
191 192 193 |
# File 'lib/minigl/movement.rb', line 191 def top @top end |
#w ⇒ Object (readonly)
Width of the bounding box.
184 185 186 |
# File 'lib/minigl/movement.rb', line 184 def w @w end |
#x ⇒ Object
The x-coordinate of the top left corner of the bounding box.
206 207 208 |
# File 'lib/minigl/movement.rb', line 206 def x @x end |
#y ⇒ Object
The y-coordinate of the top left corner of the bounding box.
209 210 211 |
# File 'lib/minigl/movement.rb', line 209 def y @y end |
Instance Method Details
#bounds ⇒ Object
Returns the bounding box as a Rectangle.
223 224 225 |
# File 'lib/minigl/movement.rb', line 223 def bounds Rectangle.new @x, @y, @w, @h end |
#cycle(points, speed, obstacles = nil, obst_obstacles = nil, obst_ramps = nil, stop_time = 0) ⇒ Object
Causes the object to move in cycles across multiple given points (the first point in the array is the first point the object will move towards, so it doesn’t need to be equal to the current/initial position). If obstacles are provided, it will behave as an elevator (as in move_carrying
).
Parameters:
- points
-
An array of Vectors representing the path that the object will perform.
- speed
-
The constant speed at which the object will move. This must be provided as a scalar, not a vector.
- obstacles
-
An array of obstacles to be considered in the collision checking, and carried along when colliding from above. Obstacles must be instances of Block (or derived classes), or objects that
include Movement
. - obst_obstacles
-
Obstacles that should be considered when moving objects from the
obstacles
array, i.e., these obstacles won’t interfere in the elevator’s movement, but in the movement of the objects being carried. - obst_ramps
-
Ramps to consider when moving objects from the
obstacles
array, as described forobst_obstacles
. - stop_time
-
Optional stop time (in frames) when the object reaches each of the points.
516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 |
# File 'lib/minigl/movement.rb', line 516 def cycle(points, speed, obstacles = nil, obst_obstacles = nil, obst_ramps = nil, stop_time = 0) unless @cycle_setup @cur_point = 0 if @cur_point.nil? if obstacles obst_obstacles = [] if obst_obstacles.nil? obst_ramps = [] if obst_ramps.nil? points[@cur_point], speed, obstacles, obst_obstacles, obst_ramps else move_free points[@cur_point], speed end end if @speed.x == 0 and @speed.y == 0 unless @cycle_setup @cycle_timer = 0 @cycle_setup = true end if @cycle_timer >= stop_time if @cur_point == points.length - 1 @cur_point = 0 else @cur_point += 1 end @cycle_setup = false else @cycle_timer += 1 end end end |
#move(forces, obst, ramps, set_speed = false) ⇒ Object
Moves this object, based on the forces being applied to it, and performing collision checking.
Parameters:
- forces
-
A Vector where x is the horizontal component of the resulting force and y is the vertical component.
- obst
-
An array of obstacles to be considered in the collision checking. Obstacles must be instances of Block (or derived classes), or objects that
include Movement
. - ramps
-
An array of ramps to be considered in the collision checking. Ramps must be instances of Ramp (or derived classes).
- set_speed
-
Set this flag to
true
to cause theforces
vector to be treated as a speed vector, i.e., the object’s speed will be directly set to the given values. The force of gravity will also be ignored in this case.
242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 |
# File 'lib/minigl/movement.rb', line 242 def move(forces, obst, ramps, set_speed = false) if set_speed @speed.x = forces.x @speed.y = forces.y else forces.x += G.gravity.x; forces.y += G.gravity.y forces.x += @stored_forces.x; forces.y += @stored_forces.y @stored_forces.x = @stored_forces.y = 0 forces.x = 0 if (forces.x < 0 and @left) or (forces.x > 0 and @right) forces.y = 0 if (forces.y < 0 and @top) or (forces.y > 0 and @bottom) if @bottom.is_a? Ramp if @bottom.ratio > G.ramp_slip_threshold forces.x += (@bottom.left ? -1 : 1) * (@bottom.ratio - G.ramp_slip_threshold) * G.ramp_slip_force / G.ramp_slip_threshold elsif forces.x > 0 && @bottom.left || forces.x < 0 && !@bottom.left forces.x *= @bottom.factor end end @speed.x += forces.x / @mass; @speed.y += forces.y / @mass end @speed.x = 0 if @speed.x.abs < G.min_speed.x @speed.y = 0 if @speed.y.abs < G.min_speed.y @speed.x = (@speed.x <=> 0) * @max_speed.x if @speed.x.abs > @max_speed.x @speed.y = (@speed.y <=> 0) * @max_speed.y if @speed.y.abs > @max_speed.y @prev_speed = @speed.clone x = @speed.x < 0 ? @x + @speed.x : @x y = @speed.y < 0 ? @y + @speed.y : @y w = @w + (@speed.x < 0 ? -@speed.x : @speed.x) h = @h + (@speed.y < 0 ? -@speed.y : @speed.y) move_bounds = Rectangle.new x, y, w, h coll_list = [] obst.each do |o| coll_list << o if o != self && move_bounds.intersect?(o.bounds) end ramps.each do |r| r.check_can_collide move_bounds end if coll_list.length > 0 up = @speed.y < 0; rt = @speed.x > 0; dn = @speed.y > 0; lf = @speed.x < 0 if @speed.x == 0 || @speed.y == 0 # Ortogonal if rt; x_lim = find_right_limit coll_list elsif lf; x_lim = find_left_limit coll_list elsif dn; y_lim = find_down_limit coll_list elsif up; y_lim = find_up_limit coll_list end if rt && @x + @w + @speed.x > x_lim @x = x_lim - @w @speed.x = 0 elsif lf && @x + @speed.x < x_lim @x = x_lim @speed.x = 0 elsif dn && @y + @h + @speed.y > y_lim; @y = y_lim - @h; @speed.y = 0 elsif up && @y + @speed.y < y_lim; @y = y_lim; @speed.y = 0 end else # Diagonal x_aim = @x + @speed.x + (rt ? @w : 0); x_lim_def = x_aim y_aim = @y + @speed.y + (dn ? @h : 0); y_lim_def = y_aim coll_list.each do |c| if c.passable; x_lim = x_aim elsif rt; x_lim = c.x else; x_lim = c.x + c.w end if dn; y_lim = c.y elsif c.passable; y_lim = y_aim else; y_lim = c.y + c.h end if c.passable y_lim_def = y_lim if dn && @y + @h <= y_lim && y_lim < y_lim_def elsif (rt && @x + @w > x_lim) || (lf && @x < x_lim) # Can't limit by x, will limit by y y_lim_def = y_lim if (dn && y_lim < y_lim_def) || (up && y_lim > y_lim_def) elsif (dn && @y + @h > y_lim) || (up && @y < y_lim) # Can't limit by y, will limit by x x_lim_def = x_lim if (rt && x_lim < x_lim_def) || (lf && x_lim > x_lim_def) else x_time = 1.0 * (x_lim - @x - (@speed.x < 0 ? 0 : @w)) / @speed.x y_time = 1.0 * (y_lim - @y - (@speed.y < 0 ? 0 : @h)) / @speed.y if x_time > y_time # Will limit by x x_lim_def = x_lim if (rt && x_lim < x_lim_def) || (lf && x_lim > x_lim_def) elsif (dn && y_lim < y_lim_def) || (up && y_lim > y_lim_def) y_lim_def = y_lim end end end if x_lim_def != x_aim @speed.x = 0 if lf; @x = x_lim_def else; @x = x_lim_def - @w end end if y_lim_def != y_aim @speed.y = 0 if up; @y = y_lim_def else; @y = y_lim_def - @h end end end end @x += @speed.x @y += @speed.y ramps.each do |r| r.check_intersection self end check_contact obst, ramps end |
#move_carrying(arg, speed, carried_objs, obstacles, ramps, ignore_collision = false) ⇒ Object
Moves this object as an elevator (i.e., potentially carrying other objects) with the specified forces or towards a given point.
Parameters:
- arg
-
A Vector specifying either the forces acting on this object or a point towards the object should move.
- speed
-
If the first argument is a forces vector, then this should be
nil
. If it is a point, then this is the constant speed at which the object will move (provided as a scalar, not a vector). - carried_objs
-
An array of objects that can potentially be carried by this object while it moves. The objects must respond to
x
,y
,w
andh
. - obstacles
-
Obstacles that should be considered for collision checking with the carried objects, if they include the
Movement
module, and with this object too, if moving with forces and theignore_collision
flag is false. - ramps
-
Ramps that should be considered for the carried objects, if they include the
Movement
module, and for this object too, if moving with forces andignore_collision
is false. - ignore_collision
-
Set to true to make this object ignore collision even when moving with forces.
379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 |
# File 'lib/minigl/movement.rb', line 379 def (arg, speed, carried_objs, obstacles, ramps, ignore_collision = false) if speed x_d = arg.x - @x; y_d = arg.y - @y distance = Math.sqrt(x_d**2 + y_d**2) if distance == 0 @speed.x = @speed.y = 0 return end @speed.x = 1.0 * x_d * speed / distance @speed.y = 1.0 * y_d * speed / distance x_aim = @x + @speed.x; y_aim = @y + @speed.y else x_aim = @x + @speed.x + G.gravity.x + arg.x y_aim = @y + @speed.y + G.gravity.y + arg.y end passengers = [] carried_objs.each do |o| if @x + @w > o.x && o.x + o.w > @x foot = o.y + o.h if foot.round(6) == @y.round(6) || @speed.y < 0 && foot < @y && foot > y_aim passengers << o end end end prev_x = @x; prev_y = @y if speed if @speed.x > 0 && x_aim >= arg.x || @speed.x < 0 && x_aim <= arg.x @x = arg.x; @speed.x = 0 else @x = x_aim end if @speed.y > 0 && y_aim >= arg.y || @speed.y < 0 && y_aim <= arg.y @y = arg.y; @speed.y = 0 else @y = y_aim end else move(arg, ignore_collision ? [] : obstacles, ignore_collision ? [] : ramps) end forces = Vector.new @x - prev_x, @y - prev_y prev_g = G.gravity.clone G.gravity.x = G.gravity.y = 0 passengers.each do |p| if p.class.included_modules.include?(Movement) prev_speed = p.speed.clone prev_forces = p.stored_forces.clone prev_bottom = p.bottom p.speed.x = p.speed.y = 0 p.stored_forces.x = p.stored_forces.y = 0 p.instance_exec { @bottom = nil } p.move(forces * p.mass, obstacles, ramps) p.speed.x = prev_speed.x p.speed.y = prev_speed.y p.stored_forces.x = prev_forces.x p.stored_forces.y = prev_forces.y p.instance_exec(prev_bottom) { |b| @bottom = b } else p.x += forces.x p.y += forces.y end end G.gravity = prev_g end |
#move_free(aim, speed) ⇒ Object
Moves this object, without performing any collision checking, towards a specified point or in a specified direction.
Parameters:
- aim
-
A
Vector
specifying where the object will move to or an angle (in degrees) indicating the direction of the movement. Angles are measured starting from the right (i.e., to move to the right, the angle must be 0) and raising clockwise. - speed
-
The constant speed at which the object will move. This must be provided as a scalar, not a vector.
458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 |
# File 'lib/minigl/movement.rb', line 458 def move_free(aim, speed) if aim.is_a? Vector x_d = aim.x - @x; y_d = aim.y - @y distance = Math.sqrt(x_d**2 + y_d**2) if distance == 0 @speed.x = @speed.y = 0 return end @speed.x = 1.0 * x_d * speed / distance @speed.y = 1.0 * y_d * speed / distance if (@speed.x < 0 and @x + @speed.x <= aim.x) or (@speed.x >= 0 and @x + @speed.x >= aim.x) @x = aim.x @speed.x = 0 else @x += @speed.x end if (@speed.y < 0 and @y + @speed.y <= aim.y) or (@speed.y >= 0 and @y + @speed.y >= aim.y) @y = aim.y @speed.y = 0 else @y += @speed.y end else rads = aim * Math::PI / 180 @speed.x = speed * Math.cos(rads) @speed.y = speed * Math.sin(rads) @x += @speed.x @y += @speed.y end end |