Welcome back to the .NET Platform Tour.
We are going to look at some things which cause gameplay to err.
I will be using this file as my map.
Based on experience, one thing that usually causes problems is two platforms or walls that lie next to each other.
With two platforms, this can usually cause problems because ineffective platform programming usually causes the character to 'fall' off the
platforms by walking across the crack between them. The falling is usually because the platform check does not allow the player to "climb"
back onto the platform.
With two walls forming one flat-top surface, this could cause the player to stop at the crack, as if there is actually a wall in front of the
player. This is usually due to a one-off or an incorrect inequality (>=, <=) error, which causes the program to think that the wall is
actually slightly elevated from the other wall, when they are both at the same elevation.
Also, with a wall laid on another wall to form a larger, flat surface on the side, some checks make it possible for the player to actually
land on the bottom wall. This is usually due to a one-off or incorrect inequality on the check to see if the player landed on the wall.
I bring these up because these are common problems in platform games like this. Fortunately, we don't have any of those errors. Check
the example file and see that none of those occur. But, there is one problem.
The player can fall through platforms.
Play this level and make your way up to the uppermost platform (the one that is to the left) and try to walk off the right end onto the small
platform below (with the three coins above it). The player will fall through the platform and all the way to the pair of platforms at
the bottom of the level. This bug comes from our check to see if the platform top lies in the shoulder range of the player.
Now, how do we fix this problem?
The easy way to weasel out of this problem is to use terminal velocity to keep the player from falling too fast. This will, unfortunately,
make all falls pathetically slow, especially since our initial velocity for the jump is already -32. Our character will reach terminal
velocity too soon. Terminal velocity is handy for higher falls, but it is unnecessary, unless we decide to have scrolling levels (hint hint).
The hard way is, of course, to do some test to see if the falling player has passed through a platform.
It's actually not as hard as it seems.
I made a mistake in the gravity coding. The >> operation does come after the addition operation, so right now, the player offset
performs like (PlayerVeloc + Gravity) / 2 instead of PlayerVeloc + (Gravity / 2). No biggie, we'll just think of it as unique jumping.
So, the distance that the player moves (subtracting Gravity because we added it to Playerveloc):
Gravity + (Playerveloc + Gravity) / 2
Playerveloc + 3 * Gravity / 2
And, convenience would inspire us to turn 3 * Gravity / 2 into a constant as well.
PlayerLoc.Offset(0, PlayerVeloc + GRAVITY >> 1) 'This is how far the player has moved.
PlayerVeloc += GRAVITY 'This is how much velocity has changed.
And now, to put this into action.
Const GRAVITYTH As Integer = GRAVITY * 3 >> 1
'This represents how much the player moved due to gravity.
Notice that our SHOULDER check is gone (replaced by our new check). This only has a small effect on jumping to platforms (we cannot climb
up to high platforms like we could with SHOULDER, but we can still climb up to platforms due to the value of GRAVITYTH.
So, we can remove the declare for the SHOULDER constant.
That's one less bug in the game.
If PlayerVeloc > 0 AndAlso PlayerLoc.Bottom >= Platform.Top AndAlso PlayerLoc.Bottom - PlayerVeloc - GRAVITYTH <= Platform.Top Then
If PlayerLoc.Left < Platform.Right AndAlso PlayerLoc.Right > Platform.Left Then
Check out this file. Can you find the problem?
Yes, the problem is the floating wall on the left side. The wall floats above the platform, so when the player jumps up under the block,
the player will land on the platform, and then be thrown up onto the wall.
How would we fix this?
A. Check for wall collision when the player lands on the platform so that we can move the player to the bottom of the wall immediately.
B. Use a boolean to determine when the player lands on a platform and if it is set, do a wall check for moving the player back down.
C. Perform the wall check before the platform check so that the player will never be high enough to land on the platform.
The problem arises when the player lands on the platform and then the wall check moves him to the top of the wall. So, either of those
would be good places.
C is clearly wrong since the player already lands on the platform.
Doing the wall check first will simply cause the player to stand on the platform instead of the wall, where we want the player to stand on neither. A would be a fine alternative, but requires two loops through the walls. The best choice would be B.
So, we will set a boolean variable to true when the player lands on a platform. Then if this variable is set, we change the wall collision
code to move the player to the bottom. Well, since we are in the IsJumping routine, and if the player lands on a platform, the IsJumping variable will be False, otherwise it will be True.
This is definitely an *ugly* fix to this problem, but having a wall floating over a platform in this way is ugly itself.
For Each Wall In Walls
If PlayerLoc.IntersectsWith(Wall) Then
If IsJumping = False Then 'If the player has landed on a platform.
IsJumping = True
'Knock the player off the platform and make the player
PlayerLoc.Offset(0, Wall.Bottom - PlayerLoc.Top + GRAVITYTH)
'Move the player to under the wall. We need GRAVITYTH so that the player climb up to the platform.
PlayerVeloc = 0
'Make the player start falling.
ElseIf PlayerVeloc > 0 Then
'If player is falling, then the player will land on the wall.
IsJumping = False
'Stop the jump.
LeftEnd = Wall.Left : RightEnd = Wall.Right
'Set the endpoints.
AnimCycler = 0
'Reset the cycler.
PlayerLoc.Offset(0, Wall.Top - PlayerLoc.Bottom)
'Position the player to stand on this wall.
'The player has jumped up into the wall.
PlayerLoc.Offset(0, Wall.Bottom - PlayerLoc.Top)
'Move the player to under the wall.
PlayerVeloc = 0
'Make the player start falling down.
In LoadLevel, if you are using LTRB Rectangle, change the Floater section to this (We should be using New
Rectangle instead of LTRB).
Feel free to download the 3rd update here.
Floaters = New ArrayList(BR.ReadInt32())
For LV = 1 To Floaters.Capacity
Floaters.Add(New LevFloater(New Rectangle(BR.ReadInt32(), BR.ReadInt32(), FLOATERSIZE, FLOATERSIZE), _
BR.ReadInt32(), BR.ReadInt32(), BR.ReadInt32(), BR.ReadInt32(), _
CType(BR.ReadInt32(), PeriodicDesignation), CType(BR.ReadInt32(), PeriodicDesignation)))
Floaters.Capacity = 20