How to solve player ship from getting stuck

I recently rebooted my attempt at the 2D Space Shooter course from Game Dev HQ and while playtesting my prototype my ship would get stuck occasionally when wrapping the screen horizontally. I originally found that during my last iteration of the course and it was reported to me by some playtesters and I wanted to take an opportunity to address the issue during this iteration from the beginning.

Recreating the issue

On the player script, I have 2 floats that represent my min and max horizontal screen bounds and I set their value to be -11.28 and 11.28.

[SerializeField] float minHorizontalBounds = -11.28f;
[SerializeField] float maxHorizontalBounds = 11.28f;

Then, inside my CalculateMovement function, I perform the translation on the transform and then clamp my horizontal position between the min and max bounds.

// Perform the translation operation
transform.Translate(direction * (speed * Time.deltaTime));

// Get the player's new y position and clamp it between the min and max vertical bounds
var yClamped = Mathf.Clamp(transform.position.y, minVerticalBounds, maxVerticalBounds);

// Get the player's new x position and clamp it between the min and max horizontal bounds
var xClamped = Mathf.Clamp(transform.position.x, minHorizontalBounds, maxHorizontalBounds);

I then check to see if the current x position is at either min or max and if so, I invert the position and update the transform.

// if player's x position while clamped is at either min or max bounds, invert the clamped position.
if (xClamped == minHorizontalBounds || xClamped == maxHorizontalBounds)
{
    xClamped = -xClamped;
}
// update the position to the clamped values.
transform.postion = new Vector2(xClamped, yClamped);

This works pretty well until you happen to stop your ship at exactly 11.28 or -11.28 as your ship will not be visible or barely visible and if you look at the x position value, you’ll notice that it bounces back and forth between positive and negative 11.28.

Problem Identification

Now what do you do because this is not an ideal scenario for your players as you can’t see what happened to the player. One of the best things that I love about software and game design is that we can work on getting things done step by step. We got something working event though it has flaws. Let’s give this a thought and think about the problem for a moment.

Pause here and think about it...

Okay, so after contemplating for a moment did you spot the area where we introduced this logic bomb? Great if you did but if you didn’t that’s okay too. Basically, it happens in our if statement where we check to see if the xClamped position is or going out of bounds and then flip it positive or negative depending. That isn’t necessarily a problem as long as your player has momentum when hitting either boundary. If you happen to lose your momentum by releasing your movement key at the point your player reaches the boundary, then you are likely to run into this scenario.

Finding a solution

Okay, we have a prototype and some working code but found a flaw in our design and implementation. Now what? Well, we start out by brainstorming possible solutions? Questions that I asked myself:

  • What are we really trying to achieve with that feature?
  • Does the Framework or API’s have something to help us?
  • Is the logic an issue?

When I think about what I truly want the player to experience, I would say, “As the player approaches the boundary by a small amount, go ahead and invert their position so that it appears to come out on the other side.” This sounds reasonable to me and a good answer or item 1 above. As we dig further into item 2 above, let’s think about what we’re dealing with. If you said, floats then you would be correct. Floats inside of computers can be tricky as precision can cause weird issues. If we re-read our statement, we have a float representing the player’s x and y positions. We want to trigger our flip logic as it approaches our boundary within a small margin. What can we mathematically say for approaches? Did you say to yourself, “Approximately?”

At this point, I went and consulted the documentation for our framework and API which in this case is Unity.

So, I start by searching the web for, “Unity MathF” to see if I can find something that will work.

Oh, would you look at that. Approximately so, I open the docs, and see what I need to do to use it.

This looks promising and seems to be what we want to do.

Let’s code up our solution

Okay, so we have an if statement where we are checking if 2 different logical conditions are true. If the x position is equal to the max boundary OR the x position is equal to the min boundary. This actually fits in nicely with what we want to do because we pass it 2 values as floats and it returns us a true/false on whether or not the values are close enough to each other to consider them equal.

How would you code that?

if (Mathf.Approximately(xClamped, maxHorizontalBounds) ||
   Mathf.Approximately(xClamped, minHorizontalBounds))
{
    xClamped = -xClamped;
}

Let’s take a look at it in action.

Attempt 1

After looking at the video we see that it still has an issue. Why? We are checking to see if we are close to the number and then invert with in a fraction. Right? Is it enough? No, can you solve this?

My next solution involves adjusting my float values representing my min and max horizontal boundaries to -11.281 and 11.279 respectively. How does that solve our issue? We are adjusting the values to be a close approximation on one another and so even if we land directly on the 11.28 value, we either stay where we are or flip once to the other side, and the bouncing stops. Let’s see that in action now.

Success!

If you followed along and participated in the journey through discovery with me, congratulations on implementing a feature, testing it, brainstorming the possibly reason why it doesn’t work exactly as intended, made a couple of iterations and ultimately are happy with the outcome.

My tips on troubleshooting

  1. Breath
  2. Don’t overthink it
  3. Focus on one small thing at a time.
  4. Make your assumptions then test them.

Leave a Reply

Recent Comments
    Archives
    Categories
    Categories
    Login
    Loading...
    Sign Up

    New membership are not allowed.

    Loading...
    %d bloggers like this: