Some games include enemies which turn around when reaching a platform edge. For example, in Super Mario World, the red Koopa enemies (turtles) walk until they reach an edge, then turn around.
We will add this logic to our Enemies in this tutorial.
Currently Enemies have a single collision shape called AxisAlignedRectangleInstance.
This shape acts as the Enemy's body. It can be used to keep the enemy from moving through the ground, walls, and ceiling (the SolidCollision TileShapeCollection). Currently this shape does not provide enough information to detect ledges. From the point of view of the AxisAlignedRectangleInstance, this first situation...
... provides the same information as this second situation...
Both situations are identical in the collision event - they both result in collision and both have the same RepositionDirection. To detect if the Enemy is near the edge of a platform, we can use a new collision rectangle (displayed in green). If this green rectangle is not colliding with SolidCollision, then the player is near a ledge. For example, in the following diagram the Enemy is near the edge of a platform on the right side:
If the player is not near a ledge, then the green rectangle will collide with solid collision.
Since we want to detect ledges on both the left and right side, we need to have one new rectangle on each side.
When we define these rectangles, we need to remember a few things:
These rectangles should not be used for solid collision - they should be excluded from the ICollidable interface
These rectangles should be smaller than the size of our tiles (16x16) so they do not reach across gaps or down pits
These rectangles will be used to apply logic when not colliding with the SolidCollision. Normally we perform logic when a collision occurs, so we will need to write custom code to handle this situation.
As mentioned above, we'll need to create two AxisAlignedRectangle instances in our Enemy entity - one for left edge collision and one for right edge collision. To create the left edge collision rectangle:
Select the Enemy entity
Select the Quick Actions tab and click the Add Object to Enemy button
Select the type AxisAlignedRectangle
Enter the name LeftEdgeCollision
Click OK
With the LeftEdgeCollision object selected, click on the Variables tab
Change X to -12
Change Y to -12
Change Width to 8
Change Height to 8
To help visualize, change the Color to Green
Repeat the steps above to create RightEdgeCollision, but change the X value to a positive 12 so it sits on the right side of the Enemy.
Now our enemy has two extra rectangles which it can use for detecting edges, but these rectangles are being used for solid collision. To fix this:
Select the LeftEdgeCollision
Click on the Properties tab
Change IncludeInICollidable to False so that the rectangle is not used in default collision relationships (like EnemyListVsSolidCollision in GameScreen)
Repeat the steps above for the RightEdgeCollision and the Enemy will no longer use these two rectangles for solid collision.
Normally when performing logic related to collision, we do so inside a collision relationship event. Detecting an edge is different because we need to respond to a situation when there is no collision. Therefore, we will be writing code which happens every frame inside of our GameScreen CustomActivity. To detect if the enemy should turn around, modify the GameScreen.cs file so that its CustomActivity matches the following code snippet:
This code shows that we can check collisions directly in code at any time, rather than relying purely on CollisionRelationships. Notice that we only perform this logic if the Enemy is on the ground. Otherwise, enemies would alternate directions very quickly when falling. If using the default level, this logic won't do anything since there are no raised platforms. We can modify Level1Map to add a few platforms. Feel free to adjust it however you like, as long as you have platforms with edges which we can use to test this logic.
We should also adjust the Enemy1 starting position so it starts on a ledge instead of falling from the top of the level. Change the X and Y values on Enemy1 in Level1 so that it starts in the right spot. This may take a little trial-and-error. Once you have the Enemy on a platform, you may notice that it still runs off the edge. The reason for this is because the Enemy moves very quickly and it takes time to slow down when changing directions.
To do this:
Select the Enemy entity
Click the Entity Input Movement tab
Change the Max Speed to 100
Change the Slow Down Time to 0.03
These changes enable the enemy to turn around without falling off of the platform. It's important to note that with enough Max Speed or a large enough Slow Down Time will result in an enemy sliding off of an edge.
Now our enemy has functionality for turning around based on wall collision and edge detection. The two approaches shown here could also be used to turn around when Enemies collide with other Enemies (also using reposition values), but we'll leave this and other situations to individuals who are interested.