Handles obstacle-related jobs
- License
- GPL-3.0-only
- Source
Methods
(static) addAllBackground()
- Source
Add all the groups of background obstacles
- Background obstacles appear underneath everything else and don't interact with the player
- Calls
addGroup()
for each group
(static) addAllCollectAndAvoid()
- Source
Add all the groups of collectable and avoidable obstacles
- Both of these obstacle types are drawn in the same 'layer' between background and floating obstacles
- Calls
addGroup()
for each group
(static) addAllFloating()
- Source
Add all the groups of floating obstacles
- Floating obstacles appear above everything else and don't interact with the player
- Calls
addGroup()
for each group
(static) addGroup(_data)
- Source
Add a group of obstacles to the game
Loops through the group, calling spawn()
repeatedly until _data.total
obstacles of this group type have been added.
Parameters
Name | Type | Description |
---|---|---|
_data |
object | An object describing a group of obstacles, originating from a |
(static) addGroupToRadiusRanges(_data)
- Source
Check the range of radii for a group of obstacles
Over the entire game we want to know what the smallest and highest radii of obstacles is. This info is then used to decide which sound effects to add to an obstacle:
- Smallest obstacles will have the highest-pitch version of SFX
- Largest obstacles will have the lowest-pitch version of SFX
Parameters
Name | Type | Description |
---|---|---|
_data |
object | An object describing a group of obstacles, originating from a |
(static) bounceInRectangle(_obstacle, _rect)
- Source
Bounce an obstacle off the walls of a rectangle
Parameters
Name | Type | Description |
---|---|---|
_obstacle |
object | |
_rect |
object | A rectangle with top, right, bottom, left properties |
(static) bounceOffPlayer(_obstacle) → {object}
- Source
Calculate effects of a collision between the player and an obstacle
This is an elastic collision, no energy is lost in the collision ie its a 'perfect'/unrealistic collision.
Conservation of momentum
Momentum is the product of mass and velocity:
p = m * v
(Player.radius * Player.speed) + (_obstacle.radius * Obstacle.speed)
=
(Player.radius * Player.speedAfter) + (_obstacle.radius * Obstacle.speedAfter)
Conservation of kinetic energy
Kinetic energy of an object is half its mass times the square of its velocity:
ke = (0.5 * m) * (v * v)
((0.5 * Player.radius) * (Player.speed * Player.speed)) + ((0.5 * _obstacle.radius) * (Obstacle.speed * Obstacle.speed))
=
((0.5 * Player.radius) * (Player.speedAfter * Player.speedAfter)) + ((0.5 * _obstacle.radius) * (Obstacle.speedAfter * Obstacle.speedAfter))
So after collision:
Player.speedAfter = (Player.speed * (Player.radius - _obstacle.radius)) + (2 * _obstacle.radius * Obstacle.speed) / (Player.radius + _obstacle.radius)
Obstacle.speedAfter = (Obstacle.speed * (_obstacle.radius - Player.radius)) + (2 * Player.radius * Player.speed) / (Player.radius + _obstacle.radius)
Project the velocity vectors of the 2 objects (player and obstacle) onto the vectors which are normal (perpendicular) and tangent to the surface of the collision.
So for each velocity (player and obstacle) we have 2 components:
- Normal component: These undergo a 1-dimensional collison, computed using the formulas above
- Tangential component: Unchanged by the collision, as there is no force along the line tangent to the collision surface
Then the unit normal vector is multiplied by the scalar normal velocity after the collision, to get a vector which has a direction normal to the collision surface, and a magnitude which is the normal component of the velocity after the collision.
The same is done with the unit tangent vector and the scalar tangential velocity
Finally the new velocity vectors are found by adding the normal velocity and tangential velocity for each object.
- Find unit normal and unit tangent vectors Unit normal:
- Has magnitude of 1
- Direction is normal (perpendicular) to the surfaces of the objects at the point of collision Unit tangent:
- Has magnitude of 1
- Direction is tangent to the surfaces of the objects at the point of collision
First find a normal vector:
- A vector whose components are the difference between the coordinates of the centres of the circles
normalVector = { x: _obstacle.pos.x - Player.pos.x, y: _obstacle.pos.y - Player.pos.y };
Next get the unit vector of normalVector
:
normalVectorMagnitude = Math.sqrt(
(normalVector.x * normalVector.x) +
(normalVector.y * normalVector.y)
);
unitNormalVector = {
x: normalVector.x / normalVectorMagnitude,
y: normalVector.y / normalVectorMagnitude
}
// OR
normalVectorMagnitude = vectorGetMagnitude(normalVector);
unitNormalVector = vectorScalarMultiply(normalVector, normalVectorMagnitude);
Next get the unit vector of tangentVector
:
- x component is equal to the negative of the y component of the unit normal vector
- y component is equal to the xcomponent of the unit normal vector
unitTangentVector = {
x: -1 * unitNormalVector.y,
y: unitNormalVector.x
}
-
Create the initial (before the collision) velocity vectors ALREADY DONE (Player/obstacle vectors)
-
After the collision:
- The tangential component of the velocities is unchanged
- The normal component of the velocities can be found using the 1D collision formulas above
So for the player and obstacle velocity vectors we need to resolve them into normal and tangential components. To do this, project the velocity vectors onto the unit normal and unit tangent vectors by computing the dot product.
normalVectorPlayerMagnitude = vectorGetDotProduct(unitNormalVector, Player.velocityVector);
tangentVectorPlayerMagnitude = vectorGetDotProduct(unitTangentVector, Player.velocityVector);
normalVectorObstacleMagnitude = vectorGetDotProduct(unitNormalVector, _obstacle.velocityVector);
tangentVectorObstacleMagnitude = vectorGetDotProduct(unitTangentVector, _obstacle.velocityVector);
- Find new (after collision) tangential velocities, which are simply equal to the old ones:
tangentVectorPlayerMagnitudeAfter = tangentVectorPlayerMagnitude;
tangentVectorObstacleMagnitudeAfter = tangentVectorObstacleMagnitude;
- Find the new normal velocities using the 1D collision formulas from earlier
normalVectorPlayerMagnitudeAfter =
((normalVectorPlayerMagnitude * (Player.radius - _obstacle.radius)) +
(2 * _obstacle.radius * normalVectorObstacleMagnitude)) /
(Player.radius + _obstacle.radius)
normalVectorObstacleMagnitudeAfter =
((normalVectorObstacleMagnitude * (_obstacle.radius - Player.radius)) +
(2 * Player.radius * normalVectorPlayerMagnitude)) /
(Player.radius + _obstacle.radius)
- Convert the scalar normal and tangential velocities into vectors:
- Multiply the unit normal vector by the scalar normal velocity (magnitude) to get a vector which is normal to the surfaces at the point of collision with a magnitude equal to the normal component of the velocity.
- Multiply the unit tangential vector by the scalar tangential velocity (magnitude) to get a vector which is tangential to the surfaces at the point of collision with a magnitude equal to the tangential component of the velocity.
normalVectorPlayerAfter = vectorScalarMultiply(unitNormalVector, normalVectorPlayerMagnitudeAfter);
tangentVectorPlayerAfter = vectorScalarMultiply(unitTangentVector, tangentVectorPlayerMagnitudeAfter);
normalVectorObstacleAfter = vectorScalarMultiply(unitNormalVector, normalVectorObstacleMagnitudeAfter);
tangentVectorObstacleAfter = vectorScalarMultiply(unitTangentVector, tangentVectorObstacleMagnitudeAfter);
- Find the final velocity vectors by adding the normal and tangential components for each object
playerVelocityVectorAfter = vectorAdd(normalVectorPlayerAfter, tangentVectorPlayerAfter);
playerVectorMagnitudeAfter = vectorGetMagnitude(playerVelocityVectorAfter);
playerUnitVectorAfter = {
x: playerVelocityVectorAfter.x / playerVectorMagnitudeAfter,
y: playerVelocityVectorAfter.y / playerVectorMagnitudeAfter,
};
obstacleVelocityVectorAfter = vectorAdd(normalVectorObstacleAfter, tangentVectorObstacleAfter);
obstacleVectorMagnitudeAfter = vectorGetMagnitude(obstacleVelocityVectorAfter);
obstacleUnitVectorAfter = {
x: obstacleVelocityVectorAfter.x / obstacleVectorMagnitudeAfter,
y: obstacleVelocityVectorAfter.y / obstacleVectorMagnitudeAfter,
};
These are velocity vectors (including magnitude) so need to be broken down into unit vectors and magnitude for use on the player and obstacle
Parameters
Name | Type | Description |
---|---|---|
_obstacle |
object | The collided-with obstacle |
Returns
object |
A vector which is used to move the control stick and give the effect of the player being knocked |
(static) deleteObstacles()
- Source
Empty the obstacles array so that old obstacles can be garbage collected
(static) explodeAllAvoids()
- Source
Starts explosion animations for all avoidable objects
Used at the end of a completed level to wipe out the objects.
(static) getRandomVector(_degreesMin, _degreesMax) → {object}
- Source
Get a random vector for an obstacle, based on its allowable range of movement as described in its group data
Parameters
Name | Type | Description |
---|---|---|
_degreesMin |
number | Smallest possible angle of direction in degrees |
_degreesMax |
number | Largest possible angle of direction in degrees |
Returns
object |
A normalised vector |
(static) getSoundIDFromRadius(_r, _orderedSfx_ar) → {string}
- Source
Choose sound based on size of obstacle
Parameters
Name | Type | Description |
---|---|---|
_r |
number | Obstacle radius |
_orderedSfx_ar |
array | An array of IDs for sounds which may represent this obstacle. The sounds will all be the same SFX, each processed to a different pitch. They should be ordered in descending pitch order. |
Returns
string |
A sound ID |
(static) increaseVectorAngle(_obstacle, _inc)
- Source
Adjust an obstacle's vector to incrementally spin the obstacle
Directly adjusts the vector property of the object.
Parameters
Name | Type | Description |
---|---|---|
_obstacle |
object | |
_inc |
number | A negative or positive number, in degrees, by which to adjust the vector |
(static) incrementExplosionAnimation(_obstacle)
- Source
Process the next frame of the obstacle explosion animation
At the end of the animation, mark the obstacle as deleted.
Parameters
Name | Type | Description |
---|---|---|
_obstacle |
object |
(static) reset()
- Source
Wipes all obstacles and related data, to be used before starting a new level
(static) spawn(_data)
- Source
Creates an individual obstacle object and adds it to ObstacleManager.obstacles
array
Sets various properties depending on the type of obstacle.
Parameters
Name | Type | Description |
---|---|---|
_data |
object | An object describing a group of obstacles, originating from a |
(static) update(_frames)
- Source
Loop through all obstacles, updating their positions and other properties
Parameters
Name | Type | Description |
---|---|---|
_frames |
number | Number of frames passed since last update, in case the engine isn't keeping up with our desired frame rate and we need perform multiple operations to keep things as smooth/consistent as possible |
(static) wrapAroundRectangle(_obstacle, _rect)
- Source
Wrap an obstacle at the boundaries of a rectangle
Behaviour varies based on obstacle type.
Parameters
Name | Type | Description |
---|---|---|
_obstacle |
object | |
_rect |
object | A rectangle with top, right, bottom, left properties |