lib/minigl/movement.rb in minigl-1.2.5 vs lib/minigl/movement.rb in minigl-1.2.6
- old
+ new
@@ -1,30 +1,95 @@
require_relative 'global'
module AGL
+ # Represents an object with a rectangular bounding box and the +passable+
+ # property. It is the simplest structure that can be passed as an element of
+ # the +obst+ array parameter of the +move+ method.
class Block
- attr_reader :x, :y, :w, :h, :passable
+ # The x-coordinate of the top left corner of the bounding box.
+ attr_reader :x
+ # The y-coordinate of the top left corner of the bounding box.
+ attr_reader :y
+
+ # The width of the bounding box.
+ attr_reader :w
+
+ # The height of the bounding box.
+ attr_reader :h
+
+ # Whether a moving object can pass through this block when coming from
+ # below. This is a common feature of platforms in platform games.
+ attr_reader :passable
+
+ # Creates a new block.
+ # Parameters:
+ # [x] The x-coordinate of the top left corner of the bounding box.
+ # [y] The y-coordinate of the top left corner of the bounding box.
+ # [w] The width of the bounding box.
+ # [h] The height of the bounding box.
+ # [passable] Whether a moving object can pass through this block when
+ # coming from below. This is a common feature of platforms in platform
+ # games.
def initialize x, y, w, h, passable
@x = x; @y = y; @w = w; @h = h
@passable = passable
end
+ # Returns the bounding box of this block as a Rectangle.
def bounds
Rectangle.new @x, @y, @w, @h
end
end
+ # Represents a ramp, i.e., an inclined structure which allows walking over
+ # it while automatically going up or down. It can be imagined as a right
+ # triangle, with a side parallel to the x axis and another one parallel to
+ # the y axis. You must provide instances of this class (or derived classes)
+ # to the +ramps+ array parameter of the +move+ method.
class Ramp
+ # Creates a new ramp.
+ # Parameters:
+ # [x] The x-coordinate of the top left corner of a rectangle that
+ # completely (and precisely) encloses the ramp (thought of as a right
+ # triangle).
+ # [y] The y-coordinate of the top left corner of the rectangle described
+ # above.
+ # [w] The width of the ramp (which corresponds to the width of the
+ # rectangle described above).
+ # [h] The height of the ramp (which corresponds to the height of the
+ # rectangle described above, and to the difference between the lowest
+ # point of the ramp, where it usually meets the floor, and the
+ # highest).
+ # [left] Whether the height of the ramp increases from left to right. Use
+ # +false+ for a ramp that goes down from left to right.
def initialize x, y, w, h, left
@x = x
@y = y
@w = w
@h = h
@left = left
end
+ # Checks if an object is in contact with this ramp (standing over it).
+ # Parameters:
+ # [obj] The object to check contact with. It must have the +x+, +y+, +w+
+ # and +h+ accessible attributes determining its bounding box.
+ def contact? obj
+ obj.x.round(6) == get_x(obj).round(6) && obj.y.round(6) == get_y(obj).round(6)
+ end
+
+ # Checks if an object is intersecting this ramp (inside the corresponding
+ # right triangle and at the floor level or above).
+ # Parameters:
+ # [obj] The object to check intersection with. It must have the +x+, +y+,
+ # +w+ and +h+ accessible attributes determining its bounding box.
+ def intersects obj
+ obj.x + obj.w > @x && obj.x < @x + @w && obj.y > get_y(obj) && obj.y <= @y + @h - obj.h
+ end
+
+ # :nodoc:
def can_collide? obj
@can_collide = (obj.speed.y >= 0 and not intersects(obj))
end
def check_intersection obj
@@ -44,18 +109,10 @@
# obj.speed.x *= (@w / (@w + @h))
# obj.speed.y = 0
end
end
- def contact? obj
- obj.x.round(6) == get_x(obj).round(6) && obj.y.round(6) == get_y(obj).round(6)
- end
-
- def intersects obj
- obj.x + obj.w > @x && obj.x < @x + @w && obj.y > get_y(obj) && obj.y <= @y + @h - obj.h
- end
-
def get_x obj
return @x + (1.0 * (@y + @h - obj.y - obj.h) * @w / @h) - obj.w if @left
@x + (1.0 * (obj.y + obj.h - @y) * @w / @h)
end
@@ -65,18 +122,70 @@
return @y - obj.h if obj.x < @x
@y + (1.0 * (obj.x - @x) * @h / @w) - obj.h
end
end
+ # 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.
module Movement
- attr_reader :speed, :w, :h, :passable, :top, :bottom, :left, :right
- attr_accessor :x, :y, :stored_forces
-
+ # A Vector with the current speed of the object (x: horizontal component,
+ # y: vertical component).
+ attr_reader :speed
+
+ # Width of the bounding box.
+ attr_reader :w
+
+ # Height of the bounding box.
+ attr_reader :h
+
+ # Whether a moving object can pass through this block when coming from
+ # below. This is a common feature of platforms in platform games.
+ attr_reader :passable
+
+ # The object that is making contact with this from above. If there's no
+ # contact, returns +nil+.
+ attr_reader :top
+
+ # The object that is making contact with this from below. If there's no
+ # contact, returns +nil+.
+ attr_reader :bottom
+
+ # The object that is making contact with this from the left. If there's no
+ # contact, returns +nil+.
+ attr_reader :left
+
+ # The object that is making contact with this from the right. If there's
+ # no contact, returns +nil+.
+ attr_reader :right
+
+ # The x-coordinate of the top left corner of the bounding box.
+ attr_accessor :x
+
+ # The y-coordinate of the top left corner of the bounding box.
+ attr_accessor :y
+
+ # A Vector with the horizontal and vertical components of a force that
+ # be applied in the next time +move+ is called.
+ attr_accessor :stored_forces
+
+ # Returns the bounding box as a Rectangle.
def bounds
Rectangle.new @x, @y, @w, @h
end
-
+
+ # 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 <code>include Movement</code>.
+ # [ramps] An array of ramps to be considered in the collision checking.
+ # Ramps must be instances of Ramp (or derived classes).
def move forces, obst, ramps
forces.x += Game.gravity.x; forces.y += Game.gravity.y
forces.x += @stored_forces.x; forces.y += @stored_forces.y
@stored_forces.x = @stored_forces.y = 0
@@ -171,11 +280,21 @@
ramps.each do |r|
r.check_intersection self
end
check_contact obst, ramps
end
-
+
+ # Moves this object as an elevator (i.e., potentially carrying other
+ # objects) towards a given point.
+ # Parameters:
+ # [aim] A Vector specifying where the object will move to.
+ # [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 <code>include Movement</code>.
def move_carrying aim, speed, obstacles
x_d = aim.x - @x; y_d = aim.y - @y
distance = Math.sqrt(x_d**2 + y_d**2)
@speed.x = 1.0 * x_d * speed / distance
@speed.y = 1.0 * y_d * speed / distance
@@ -204,11 +323,17 @@
@y = y_aim
end
passengers.each do |p| p.y = @y - p.h end
end
-
+
+ # Moves this object, without performing any collision checking, towards
+ # the specified point.
+ # Parameters:
+ # [aim] A Vector specifying where the object will move to.
+ # [speed] The constant speed at which the object will move. This must be
+ # provided as a scalar, not a vector.
def move_free aim, speed
x_d = aim.x - @x; y_d = aim.y - @y
distance = Math.sqrt(x_d**2 + y_d**2)
@speed.x = 1.0 * x_d * speed / distance
@speed.y = 1.0 * y_d * speed / distance
@@ -225,10 +350,27 @@
@speed.y = 0
else
@y += @speed.y
end
end
-
+
+ # Causes the object to move in cycles across multiple given points (the
+ # method must be called repeatedly, and it returns the value that must be
+ # provided to +cur_point+ after the first call). 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.
+ # [cur_point] The index of the point in the path that the object is
+ # currently moving to. In the first call, it is a good idea to
+ # provide 0, while in the subsequent calls, you must provide
+ # the return value of this method.
+ # [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 <code>include Movement</code>.
def cycle points, cur_point, speed, obstacles = nil
if obstacles
move_carrying points[cur_point], speed, obstacles
else
move_free points[cur_point], speed