Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
The CollideAgainstBounce is a collision method which performs the following:
Returns true if a collision has occurred.
Repositions the calling Circle and/or the argument object depending on the argument masses.
Changes the calling Shape's Velocity and/or the argument object's Velocity depending on the argument masses.
Note: All collision methods, including CollideAgainstBounce, are methods common to all Shapes. If you came here through a link on a page beside the Circle (such as Polygon), don't worry, the code for all shapes is identical.
The signature for CollideAgainstBounce is as follows:
Arguments:
Circle circle (or other shape) - the shape to collide against. This method supports other shapes as well, and if you find a shape that you'd like to collide against which is not supported, please request this feature in the forums.
float thisMass - the mass of this shape. This does not have to be an absolute mass since it will only be used relative to the otherMass argument.
float otherMass - the mass of the argument shape. Just like thisMass, otherMass does not have to be absolute. It will be compared against thisMass.
float elasticity - The amount of bounce that will result. A value of 1 results in all momentum being preserved through the collision. A value of 0 results in no momentum being preserved. Negative values should not be used. Values greater than 1 introduce extra momentum. Values greater than 1 can be used to simulate "bouncing" against a wound-up spring, or to create false physics. For more information on the elasticity variable, see the Elasticity Examples section below.
The following code creates a Plinko board.
Add the following using statements:
Add the following at class scope:
Add the following in Initialize after initializing FlatRedBall:
Add the following in Update:
Since CollideAgainstBounce returns a bool, your code can use the return value to modify your game when a collision occurs:
The Collision tutorial mentions:
Let's consider why this is the case. Imagine a situation where a shape (or parent of a shape) is moving toward the right. This is being done with the following code:
If this code is called every frame, that means that the XVelocity will be set to 1 every frame, regardless of what it was before. Imagine that "someShape" performs bounce collision against a wall. When collision occurs, the shape's XVelocity will get inverted (that is, set to -1) so that it moves to the left. However, if Velocity is set to 1 every frame, than the -1 would get changed back to 1. In other words, the setting of velocity every frame would cancel out the velocity change from CollideAgainstBounce. Let's look at another example: one where an object is moved with the mouse. In this example, the mouse is simply setting the position of an object:
In this case, someShape will have a velocity of 0 (assuming there is no other code that sets its velocity. Therefore, even though someShape appears to be moving smoothly with the mouse, if another object bounces against it, it may not bounce at all.
The following example shows a problem with using CollideAgainstBounce and Mouse control and how it can be corrected.
Add the following using statements:
Add the following at class scope:
Add the following in Initialize after initializing FlatRedball:
Add the following in Update:
The CollideAgainstBounce method is effective for performing bouncing physics, but it can also be used in situations where you'd like collision to reset velocity, such as in platformers. It's very common to have acceleration in platformers, and the easiest way to do this is to set the player Entity to have a negative YAcceleration. However, if the player collides with the ground using CollideAgainstMove, the YAcceleration will continue to accumulate the YVelocity value. Eventually this value will build up to be so large that the player will fall through the level. Even if this doesn't occur, the player will show weird behavior if it walks off of a ledge. To solve this, you can simply use CollideAgainstBounce instead of CollideAgainstMove. An elasticity of 0 will result in the same behavior as CollideAgainstMove, but the velocity will be modified according to the velocity to solve accumulation errors. You can try this in the demo above by setting the elasticity argument to 0.
Due to the popularity of the , it is very common to have shapes attached to other . Because of this common setup, all shapes have special behavior in their collision methods to reposition or change the velocity of their .
The attachment hierarchy is a collection of and their attachments - or child/parent relationships - which define which objects control the position and rotation of other objects. The following shows a typical attachment hierarchy for an .
Methods like CollideAgainstMove and CollideAgainstBounce are commonly used to prevent overlapping and modify velocity in response to collisions. CollideAgainstMove modifies the absolute Position of the calling shape and the shape it is colliding with to prevent overlapping. CollideAgainstBounce prevents overlapping just like CollideAgainstMove, but also modifies the velocity of the two shapes involved.
This may seem to present a problem; shapes have their absolute properties modified through the CollideAgainstMove and CollideAgainstBounce methods; however, as shown in the entity pattern above, shapes are often not at the root of the attachment hierarchy. Therefore it would seem as if these methods will only work when the shapes involved are the roots of their respective attachment hierarchies.
As mentioned above, the CollideAgainstMove and CollideAgainstBounce methods will update the root's absolute properties. However, if two shapes share the same root, the collision methods will not be able to reposition the objects properly. The following image shows the conflict:
Notice that in this situation both children will be modifying the parents' property. However, the parent's absolute values control the absolute values of the attached shapes.
In these situations the regular CollideAgainst methods will work correctly, but the Move and Bounce versions of the method will not be able to properly modify values. Keep this in mind if you are using a shared root for multiple shapes.
The AbsolutePointPosition method returns the absolute position of the point on the polygon matching the argument index. Passing an index outside of the list of points will result in an exception.
The following code shows how to create a bullet at the 2nd point on a polygon (index 1):
CollideAgainstMove can be used to test whether two shapes are touching. If the shapes are overlapping this method also moves one or both so that they no longer overlap. CollideAgainstMove also works between all types of .
CollideAgainstMove is a common method used in games which include solid collision. Sometimes the collision is between two movable objects (such as a player and a box which can be pushed), and sometimes the collision is between a movable and static object (such as a player and a wall).
CollideAgainstMove lets you specify how objects should behave when colliding. The first argument is the object to collide against, the second is the mass of the caller, and the third is the mass of the object colliding against.
For example, to collide a Player entity against a wall (assuming the entity ):
Inversely to have a player push a block, and have the player not slow down at all when pushing the block:
To have both objects impacted equally by the collision, the same mass can be used. For example, if two cars collide (again assuming that the cars implement )
Any value can be used for the mass of the two objects - you're not limited to using 0 and 1. We use 0 and 1 above to express intent - that one object should be mass-less, or that the two objects should have the same mass. For example, a heavier object could collide against a lighter object:
Add the following using statements:
Add the following at class scope:
Add the following in Initialize after initializing FlatRedBall:
Add the following in Update:
In brief mathematical terms, the CollideAgainstMove repositions the calling shape and the argument shape along the vector that is normal to the surface vector at the point of collision. The amount that each object moves when colliding depends on the two masses passed in to the method.
For example, consider the following situation. There are two Polygons - ball and surface. The ball has a positive XVelocity and negative YVelocity, causing it to fall down and to the right toward the surface Polygon:
Eventually the ball will overlap the surface. Let's assume that the following method is being called every frame:
In this case the ball is given a 0 mass and the surface is given a 1 mass. In other words, surface will never be moved by this method while ball will.
When a collision occurs, the vector of the edge where the collision happened is determined. Then the normal (perpendicular) vector is calculated and the shape(s) is (are) moved along the normal vector the required distance to separate them. For example, the first time ball penetrates surface, the following edge vector and reposition vector are calculated:
Since the ball has 0 mass, it will be moved by the full reposition vector. If the value were different, say .5 and .5, then ball and surface would each move half of the reposition vector. Of course, surface would move in the opposite direction as ball so that the two separate after the call.
Since this CollideAgainstMove resolves this penetration, it is never seen when the engine draws the shapes. But if the velocity of ball is not changed, then it will continue to penetrate surface every frame, then get pushed back out every frame. The result is what appears to be a smooth sliding movement across as follows:
The Polygon class overrides the . The Polygon's ForceUpdateDependencies method does the same thing as the (updates the instance's absolute Position and Rotation values according to attachments); however, it *also* updates the Polygon's internal vertices.
In most situations you will not need to call ForceUpdateDependencies. Polygons will automatically update the internal vertices when performing any collision methods (such as CollideAgainst), or right before rendering a Polygon.
Since these two situations are common whenever a Polygon is used, you will usually not need to worry about calling ForceUpdateDependencies. However, if you are creating a Polygon and immediately wanting to use it with any method that may need to use its absolute vertices (such as , then you will need to manually call ForceUpdateDependencies after instantiation.
The IsPointInside method returns whether an absolute X/Y position is inside the calling Polygon. This function takes 3D position objects (such as Vector3) but ignores the Z value. Only X and Y are considered.
The following code creates a Polygon that is in the shape of a rectangle. When the user moves the cursor in the polygon it turns red; otherwise it is yellow.
Add the following using statements:
Define the Polygon at class scope:
Add the following in Initializing after initializing FlatRedBall (or CustomInitialize if using Screens):
Add the following in Update (or CustomActivity if using Screens):
The IsPointInside method requires that the Polygon has constructed its internal vertices. This means that you must either:
If neither of the above has happened, then the internal vertices will not be set and this function will always return false.
The CreateRectangle method creates a Polygon that is in the shape of a rectangle. Polygons created through the CreateRectangle method are no different than any other Polygon - the CreateRectangle method is simply a method that simplifies a common task.
Since Polygons and have the same methods for performing collision and both inherit from the class, the decision of whether to use the Polygon or depends on whether you need rotation support.
If you need to have rotation support, you should use the Polygon class. do not consider rotation when drawn or when performing collision. However, because of this, collision is faster than Polygon collision. If rotation is not needed, you should consider using the class for performance reasons.
The following code creates a Polygon using the CreateRectangle method. The Polygon is then added to the ShapeManager to be visible.
Add the following using statements:
Add the following to Initialize after initializing FlatRedBall:
Notice that the values used in the above line of code are "scale" values. Scale values in FlatRedBall represent the distnace from the center to the edge of an object. For example, an object which has a ScaleX of 2 will have a width of 4. Therefore, the rectangle created in the code above will have a width of 4 units and a height of 6 units.
The CreateEquilateral static method is a method in the Polygon class which can be used to quickly create equilateral (same-length sides) Polygons.
The following code creates two Polygons. One is a 4-sided polygon. The other one is a very high-vertex count Polygon which can be used to draw smooth Circles. Keep in mind that high-vertex polygons like the one created in this example can be expensive when performing collisions.
Add the following using statement:
Add the following to Initialize after initializing FlatRedBall:
The OptimizeRadius method can be called to adjust the relative points of a Polygon to reduce its radius. The radius of a polygon is used internally to improve the performance of collision methods.
The OptimizeRadius method should be called if a Polygon's points are set or changed. This method will adjust the values of each relative point to optimize the radius of the Polygon. This method will also modify the position of the Polygon to keep the absolute position of each vertex constant. In other words, this method can be called after Polygons are positioned and it should have no impact on the final appearance or behavior of the Polygon - aside from improved performance.
The following code creates two Polygons. The Points are assigned such that the Polygon is not symmetric about its center. The Polygon called optimizedPolygon has its OptimizeRadius method called to make it symmetric. Finally, two circles are created to show the position and radius of both Polygons.
Add the following using statement:
Add the following to Initialize after initializing FlatRedBall:
The ProjectParentVelocityOnLastMoveCollisionTangent method is a very powerful and useful method for creating realistic collision. This method can be used in many types of games to help reduce "tunneling" - that is, objects hopping through other objects because of high speeds.
The ProjectParentVelocityOnLastMoveCollisionTangent property is a very long property name which takes a little bit of understanding. Let's break it down.
To explain what this property means, we'll start from the back and go to the front. First, we'll start with:
This phrase indicates that the property that we are investigating will give us information about the last time a "Move" collision was called. In other words, the last time was called. That's all!
Next, we'll add the Tangent property. In math, a tangent is a line which moves parallel (in the same direction) as a surface. The following image shows a blue line which is a tangent on the yellow circle
The phrase "on last move collision tangent" means that we are going to do something with the line (or Vector in more precise terms) that is tangential to the point where the collision happened the last time was called.
Next we'll look at the phrase Project Velocity. The "..." appears in the title because we're going to explain why the word "Parent" appears after this section. A projection in Linear Algebra is the operation done between two Vectors where one Vector is modified so that it is parallel to the second vector, and its length is set to be its length along the second vector. This is a difficult concept to explain in words, so observe the following picture:
In this picture Vector A is projected onto Vector B, resulting in Vector 3. Notice that the result will always be parallel to the projected-on Vector.
Assuming there is no bouncing, friction, or energy loss from the collision, this projection realistically represents the behavior of a moving object as it collides with another object. In other words, projecting the velocity on the tangent of the last collision will make the object appear to collide with the object and keep moving in a realistic manner after the collision.
ProjectParentVelocityOnLastMoveCollisionTangent provides the following overloads:
The minimumVectorLengthSquared argument is an argument that can control whether velocity modifications should be performed. Shapes which have the ProjectParentVelocityOnLastMoveCollisionTangent method store the vector that they were moved along in the last CollideAgainstMove call. This property is the called LastMoveCollisionReposition. The minimumVectorLengthSquared is a value which is compared against the square of the length of LastMoveCollisionReposition. This can be used to prevent the projection of velocity.
Most of the time this is not needed, and calling the no-argument version of ProjectParentVelocityOnLastMoveCollisionTangent uses a default value of 0 for minimumVectorLengthSquared. This argument can be used in very rare cases where large numbers can result in precision loss.
The following code creates two Polygons. The smaller polygon will move down and to the right, then slide along the larger polygon. Once the smaller polygon reaches the end of the larger polygon, it will continue to move to the right. In other words, it will lose its "downward" component of its velocity vector.
Add the following using statement:
Add the following at class scope:
Add the following to Initialize after initializing FlatRedBall:
Add the following to Update
Things to try: If you remove the call to
you will notice that the moving Polygon will continue to move downward after reaching the end of the larger Polygon. Give it a shot to see the difference.
ProjectParentVelocityOnLastMoveCollisionTangent is useful both for realistic physics, as well as semi-realistic physics as found in many platformers (such as Super Mario Bros.)
The following is a block of code which can serve as an example for how to handle collision in a platformer:
The Points property is an array of values which contain the position of each point on the polygon. These values are in "object space". In other words, they are relative to the containing Polygon's position and rotation values.
The Points property can be assigned - this essentially changes the shape of the Polygon. This is a more-efficient and often more-convenient way to change a Polygon rather than to construct a new one if your game requires dynamic shapes. For more information, see .
The values in the Points array are all relative to the containing Polygon. This means that if the Polygon moves or rotates, the values stored in the Points property will remain the same.
Add the following using statements:
Add the following at class scope:
Add the following in Initialize after initializing FlatRedBall:
Add the following in Update:
The Polygon class is used to define collidable shapes. Polygons can contain any number of points and can be either convex or concave. Polygons can be drawn to the screen by adding them to the ShapeManager or by setting their Visible property to true.
Polygons are typically used for objects which need complex collision. Polygons can collide with other Polygons as well as other FlatRedBall shapes such as Circle and AxisAlignedRectangle.
Polygon collision is significantly slower than Circle and Rectangle collision, so if your game can use simpler shapes those are recommended for performance reasons.
The Polygon class sits is in the FlatRedBall.Math.Geometry namespace, so adding
can simplify your code. Also, Polygons use the FlatRedBall.Math.Geometry.Point struct, so the following code can help solve ambiguities:
The Polygon class provides the CreateRectangle shortcut methods for creating rectangular Polygons:
You can also assign the Points object. For more information, see the .
Polygons can be constructed by assigning the points. Note that points are relative to the center of a polygon, not in absolute coordinates.
Polygons support points in any order, but adding points clockwise is recommended for performance reasons. Internally, FlatRedBall is able to perform faster collision checks between polygons if both have points added clockwise.
The example above adds points clockwise. We can see this by overlaying the polygon's origin and drawing the order in which points have been added as shown in the following image:
Polygons provide an IsClockwise method which checks if the points are in clockwise order, as shown in the following code:
Each Polygon has a BoundingRadius method which is set when the point list reference is updated. This BoundingRadius is used internally in collision methods. When two Polygons collide, their distances are compared to their BoundingRadius. If the two are too far away to possibly have a collision, then no deeper checks are performed.
This helps reduce the cost of performing polygon collision, especially when polygons are often separated by larger distances.
This method repositions a Polygon or its TopParent if it has one, changes the LastMoveCollisionReposition property, and finally updates all attachments. This code performs all of the updates which would happen on a successful CollideAgainstMove call. This method is rarely used. It can be used if collision is handled outside of the polygon class but the LastMoveCollisionReposition property is still used in other parts of code. If collision that repositions a polygon calls this method rather than simply changing its Position values, then code that uses the LastMoveCollisionReposition property (such as ProjectParentVelocityOnLastMoveCollisionTangent) will still work correctly.
All FlatRedBall shapes inherit from the class, so they inherit the X, Y, Z, and Position properties. The Z value of shapes impacts their rendering, but not collision. In other words, shapes will render differently according to their Z value when rendering on a 3D camera, but they will collide as if their Z values are all the same.
The Position of the Polygon is a bit of an abstract concept because it may or may not represent the center of a Polygon. In fact, it may not even lie inside of a Polygon depending on how the Points values are set. If you use the or functions, then the Position will represent the center of the Polygon. If you have constructed the Polygon yourself by setting the Polygon's , then the Position value relative to points depends on the values you've assigned to .
Shapes and non-Shapes which are on the same Layer (or which are all un-Layered) will not sort with each other. For more information see .
The ScaleBy method can be used to adjust a Polygon's points to make it larger or smaller. The ScaleBy method is relative to the current state of the polygon. This means that calling ScaleBy with any number other than 1 multiple times will continually change the polygon.
Calling ScaleBy multiple times will continually change the polygon. For example:
will double the relative value of each point. Calling the method again will double it once more.
Ignoring floating point inaccuracy, the following line of code will result in no changes to a Polygon:
Since ScaleBy modifies the points on a Polygon, the Polygon has no built-in way to preserve the original shape of the polygon. To do so, you will have to keep track of that information yourself:
The "thin Polygon problem", also known as collision tunneling, is a collision bug that is very commonly collision problem. As the name suggests, this bug occurs when dealing with thin shapes. Although we use Polygons in this discussion, it applies to AxisAlignedRectangles as well. This bug manifests itself in one of three ways:
Moving objects completely pass through Polygons. This is known as "tunneling".
Moving objects becoming stuck inside polygons.
Moving objects touching and being moved to an unexpected location on the surface of the Polygon.
Tunneling also exists with other shapes: Although this article talks specifically about Polygons, tunneling is a problem that exists with all other shape types and is not limited to Polygons. In fact, the incremental movement that is used in FlatRedBall which leads to tunneling is a general problem in game development, and the term "tunneling" is not a term which is simply used in FlatRedBall. If you are experiencing objects falling-through or passing-through other objects, this article may help you solve your problems - even if you're not using Polygons.
Of course you may be wondering "what defines thin?" Whether a Polygon is thin or not depends on the distance between lines of a Polygon relative to the velocity of objects that will collide against the Polygon. For example, if you have have a rectangle-shaped Polygon that is 1 unit thick, you probably will not experience any collision problems when an object moving at .1 units per second collides against your Polygon. If, on the other hand, the moving object is moving at 60 units per second, you will almost certainly see this bug.
The FlatRedBall collision system is a "historyless" collision system. This means that the collision performed at any given time does not consider the previous positions of objects. This approach has its benefits - it uses less memory, is slightly faster, and is very flexible. Of course, this can result in the bug discussed in this article. Let's look at an example of why a historyless collision system can result in tunneling Frame A shows a yellow ball (could be any shape really) falling towards a light-blue surface. In this example we'll assume that the ball is traveling at a very high speed. There is no collision for frame A, so the ball continues to fall normally. Because the ball traveled so quickly, it has nearly moved completely through the surface in one frame. Since FlatRedBall does look at the ball's position in frame A (it's historyless), the collision that it performs results in what we see in frame C: If you were to look only at frame B without looking at frame A, you may also prefer the end-position resulting in C.
Fortunately there are a number of solutions to the thin polygon problem. Which you employ depends on the type of problem you're seeing and what kind of options you have from the genre of game you're developing.
The first solution to the thin polygon problem is to simply make your objects not move as fast. This will resolve tunneling in almost every situation. However, this may not be an option for you because of the type of game you are developing. If you are making a racing game, then you may not want to slow the cars down just to resolve this issue (and you shouldn't either!). Of course, as we mentioned above, these problems occur when the speed of the colliding object is high relative to the *width* of the polygon. In other words, you can usually solve these problems by simply making your collision areas wider. This is especially effective if the borders of your game mark the absolute boundaries that the player can occupy. In other words, if your game takes place inside a room and the player can't walk outside of the room, then you can widen the walls to virtually any size you'd like to prevent tunneling.
Increasing the frame rate of your game by reducing the is an effective but very expensive approach to solving this problem. More information on this can be found .
One solution which simulates increasing the frame rate, but isolates the performance impact to the code you are working with is to have your colliding objects (Entities) keep track of their last-frame position, then subdivide the distance they've traveled in one frame into smaller segments, and performing collision tests at each point. At a high level here are steps on how to do the collision tests:
In your Entity object which must perform multiple collisions, mark its position at the end of the Update method.
At the beginning of the frame, compare subtract the last position from the current position to identify the distance traveled.
Determine how much you want to subdivide your frame.
Write a loop as follows:
Depending on the shape of your object you may be able to create a swept shape. The Capsule2D class is a useful shape for testing collisions of circles. You can also create your own Polygons or Lines to check if a collision occurred between two frames. If a collision did occur you may need to "rewind time" and subdivide the last frame to get more accurate results.
The section above describes a situation where polygon collision error occurs even if the speed of the moving Polygon is very low. In general the simpler shapes have more accurate collision than Polygons. Therefore, replacing the moving Polygon with a Circle will improve the accuracy of collision - while improving performance at the same time.
All FlatRedBall shapes inherit from the class, so they inherit the X, Y, Z, and Position properties.
The Z value of shapes impacts their rendering, but not collision. In other words, shapes will render differently according to their Z value when rendering on a 3D camera, but they will collide as if their Z values are all the same.
The Position of the Polygon is a bit of an abstract concept because it may or may not represent the center of a Polygon. In fact, it may not even lie inside of a Polygon depending on how the Points values are set.
If you use the or functions, then the Position will represent the center of the Polygon. If you have constructed the Polygon yourself by setting the Polygon's , then the Position value relative to points depends on the values you've assigned to .
Shapes and non-Shapes which are on the same Layer (or which are all un-Layered) will not sort with each other. For more information see .
In this hierarchy the entity itself is considered the "root" or . This means that by default absolute changes to position and rotation will affect ONLY the root object. In other words, if the VisibleRepresentation's X is changed in code, the change will not be drawn or persist next frame. To change the VisibleRepresentation's absolute position or rotation, code must either change the root's absolute values, or the relative values of the VisibleRepresentation.
This characteristic is not unique to - it applies to all including all shapes.
Fortunately, this is not the case. Since shapes are often children of other , any modification to position or velocity gets "pushed up" to the root of the attachment hierarchy.
The following code loads a .plylstx to create a containing Polygons. Another Polygon is created which is controlled by the . Move collision is used to keep the moving Polygon and the Polygons loaded from the .plylstx from overlapping. Notice that the mass variables can be modified to allow for different collision behavior.
Files Used:
If one of the colliding shapes is an AxisAlignedRectangle then the direction of the "move" (the reposition) is subject to this value. For more information, see the .
Wait for one frame so that the Polygon has a chance to render and have its internal vertices set properly. If your polygon is not rendered or part of the then waiting one frame will not result in the internal vertices being updated.
Call
Although the Polygon object itself is not an IScalable, the CreateRectangle uses scale values. For more information on how scale values are used elsewhere in the FlatRedBall engine, see the .
Finally we introduce the word "Parent". The reason Parent appears in this method name is because most shapes are never used alone, but rather are used as children of another object (usually ). Therefore, the shape shouldn't modify its own Velocity, but rather the Velocity of its parent.
This method is only used in more complex situations. You can usually accomplish the exact same behavior by simply calling with an elasticity of 0.
To retrieve the absolute position of each , the relative points must be converted into world (or absolute) coordinates.
The following code creates a Polygon which spins automatically and is repositioned based off of activity. Three are positioned in the world coordinates of each of the Polygon's points in the Update method. Since the are being positioned in world space, the position of the points must be converted to world space so that the appear in the proper position.
The Polygon class provides collision methods and properties to simplify common game programming tasks. The following code creates two Polygons which turn red when they collide. Note that this uses input code. For information on using FlatRedBall input, see .
ScaleBy will modify the of the calling Polygon is used internally for collisions. There is no need to call after calling ScaleBy.
One of the most common situations where tunneling exists is in platformers that use YAcceleration for gravity. The reason this can cause so many problems is because the speed that the distance that the game character falls impacts how fast the character hits the ground. If your game includes large drops, you may notice that the character sometimes falls through the world when falling long distances. Most professionally-made platformers include a maximum falling speed for game play reasons. Implementing this maximum falling speed (also known as "terminal velocity") can both improve the feel of your game as well as possibly solve tunneling. For a discussion on how to limit falling speed, .
So far we've talked about tunneling issues, but there are also situations where two polygons may report a collision, but not separate correctly. This occurs in the if you move the moving Polygon to the edges of the mouth polygon. To solve this, you can add additional points to the smiley polygon in the PolygonEditor as described .
The Clone method can be used to create a copy of a given Polygon. A cloned polygon will be identical to the original polygon. Cloned polygons can be used if you are loading Polygons from a file and want to create multiple instances of a given Polygon. For example, you may create a Polygon (which we'll call attack Polygon) in the PolygonEditor. Whenever your character attacks, you may want to clone the attack Polygon and add the newly-created Polygon to a list of polygons in your Screen, which can be used to test collision against enemies.
The Visible property controls whether a particular shape is drawn. Setting Visible to false will make a shape no longer be drawn. Setting Visible to true will make the shape drawn - even if it is not part of the ShapeManager.
All visible shapes are stored in lists in the ShapeManager for drawing. If a visible shape is made invisible (its Visible is set to false) then it is removed from the shape that stores all to-be-drawn shapes of that particular type. This characteristic of the Visible property improves the speed of drawing shapes, but can have a small performance impact on the Visible property.
The VectorFrom returns a vector from the argument position to the calling instance. This method returns the shortest vector which can be traveled along to reach the surface of the calling instance. This method does not return the distance from the calling point to the center of the shape.
The following code creates a concave Polygon and a Line. The Line draws the shortest line from the tip of the cursor to the Polygon. Add the following using statements:
Add the following at class scope:
Add the following in Initialize after initializing FlatRedball:
Add the following to Update: