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
.
199 200 201 |
# File 'lib/minigl/movement.rb', line 199 def bottom @bottom end |
#h ⇒ Object (readonly)
Height of the bounding box.
191 192 193 |
# File 'lib/minigl/movement.rb', line 191 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
.
203 204 205 |
# File 'lib/minigl/movement.rb', line 203 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.
177 178 179 |
# File 'lib/minigl/movement.rb', line 177 def mass @mass end |
#max_speed ⇒ Object (readonly)
A Vector with the speed limits for the object (x: horizontal component, y: vertical component).
185 186 187 |
# File 'lib/minigl/movement.rb', line 185 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.
217 218 219 |
# File 'lib/minigl/movement.rb', line 217 def passable @passable end |
#prev_speed ⇒ Object (readonly)
A Vector containing the speed of the object in the previous frame.
224 225 226 |
# File 'lib/minigl/movement.rb', line 224 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
.
207 208 209 |
# File 'lib/minigl/movement.rb', line 207 def right @right end |
#speed ⇒ Object (readonly)
A Vector with the current speed of the object (x: horizontal component, y: vertical component).
181 182 183 |
# File 'lib/minigl/movement.rb', line 181 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.
221 222 223 |
# File 'lib/minigl/movement.rb', line 221 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
.
195 196 197 |
# File 'lib/minigl/movement.rb', line 195 def top @top end |
#w ⇒ Object (readonly)
Width of the bounding box.
188 189 190 |
# File 'lib/minigl/movement.rb', line 188 def w @w end |
#x ⇒ Object
The x-coordinate of the top left corner of the bounding box.
210 211 212 |
# File 'lib/minigl/movement.rb', line 210 def x @x end |
#y ⇒ Object
The y-coordinate of the top left corner of the bounding box.
213 214 215 |
# File 'lib/minigl/movement.rb', line 213 def y @y end |
Instance Method Details
#bounds ⇒ Object
Returns the bounding box as a Rectangle.
227 228 229 |
# File 'lib/minigl/movement.rb', line 227 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.
500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 |
# File 'lib/minigl/movement.rb', line 500 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.
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 |
# File 'lib/minigl/movement.rb', line 246 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, nil] y_aim = @y + @speed.y + (dn ? @h : 0); y_lim_def = [y_aim, nil] coll_list.each do |c| find_limits(c, x_aim, y_aim, x_lim_def, y_lim_def, up, rt, dn, lf) end if x_lim_def[0] != x_aim && y_lim_def[0] != y_aim x_time = (x_lim_def[0] - @x - (lf ? 0 : @w)).to_f / @speed.x y_time = (y_lim_def[0] - @y - (up ? 0 : @h)).to_f / @speed.y if x_time < y_time stop_at_x(x_lim_def[0], lf) move_bounds = Rectangle.new(@x, up ? @y + @speed.y : @y, @w, @h + @speed.y.abs) stop_at_y(y_lim_def[0], up) if move_bounds.intersect?(y_lim_def[1].bounds) else stop_at_y(y_lim_def[0], up) move_bounds = Rectangle.new(lf ? @x + @speed.x : @x, @y, @w + @speed.x.abs, @h) stop_at_x(x_lim_def[0], lf) if move_bounds.intersect?(x_lim_def[1].bounds) end elsif x_lim_def[0] != x_aim stop_at_x(x_lim_def[0], lf) elsif y_lim_def[0] != y_aim stop_at_y(y_lim_def[0], up) 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.
363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 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 |
# File 'lib/minigl/movement.rb', line 363 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.
442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 |
# File 'lib/minigl/movement.rb', line 442 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 |