0
\$\begingroup\$

I'm making an endless runner game where platforms move towards the player so it makes it seem like the player is running across them. I'm trying to make it so that when the player dies, the platforms stop moving. What I have isn't working, when the player dies, the platforms just keep moving as if nothing has happened. Here is the script I have that is attached to the player:

 using System.Collections;
 using System.Collections.Generic;
 using UnityEngine;
 using UnityEngine.SceneManagement;

 public class CoinColliderScript : MonoBehaviour
 {
     void OnTriggerEnter(Collider target)
     {
         if (target.tag == "Enemy")
         {
         StartCoroutine(Died());
         }
     }

     IEnumerator Died()
     {
         PlatformMover.dead = true;
         gameObject.GetComponentInParent<Animator>().Play("Male Died");
         yield return new WaitForSeconds(0.5f);
         SceneManager.LoadScene("MainMenu");
     }
 }

Here is the script I have that is attached to the platforms:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class PlatformMover : MonoBehaviour
{
    private Vector3 newPlatPos;

    public float platMoveSpeed;

    public static bool dead;

    public void Start()
    {
        dead = false;
    }

    void Update()
    {
        if (dead)
        {
            newPlatPos = new Vector3(transform.position.x, transform.position.y, transform.position.z);
        } else if (!dead)
        {
            newPlatPos = new Vector3(transform.position.x, transform.position.y, transform.position.z - platMoveSpeed);
        }
        transform.position = newPlatPos;
    }
}

New Code:

Attached to platforms:

public class PlatformMover : MonoBehaviour
{
    private Vector3 newPlatPos;

    public float platMoveSpeed;

    void Update()
    {
        if (!CoinColliderScript.Dead)
        {
            newPlatPos = new Vector3(transform.position.x, transform.position.y, transform.position.z - platMoveSpeed * Time.deltaTime);
        }
        transform.position = newPlatPos;
    }
}

Attach to player:

public class CoinColliderScript : MonoBehaviour
{
    private static bool dead = false;
    public static bool Dead
    {
        get => dead;
        set
        {
            dead = value;
            print("'Dead' changed to " + value);
        }
    }

    void OnTriggerEnter(Collider target)
    {
        if (target.tag == "Enemy")
        {
            StartCoroutine(Died());
        
        }
    }

    IEnumerator Died()
    {
        dead = true;
        gameObject.GetComponentInParent<Animator>().Play("Male Died");
        yield return new WaitForSeconds(0.5f);
        SceneManager.LoadScene("MainMenu");
    }
}
\$\endgroup\$
4
  • 1
    \$\begingroup\$ Looks like you're setting dead to false anytime a platform is spawned. Are you spawning platforms after the player has died? \$\endgroup\$
    – DMGregory
    Commented Jul 21, 2020 at 3:05
  • \$\begingroup\$ I'm spawning platforms after the player has died but I would assume that doesn't much of a difference as it takes a long time for a newly spawned platform to reach where the player is and the Scene switches after only half a second. What would make it so that dead is set to false every time a platform is spawned? The script that spawns the platforms is in a different class than what is shown in my post \$\endgroup\$
    – Matheson
    Commented Jul 21, 2020 at 3:14
  • \$\begingroup\$ "What would make it so that dead is set to false every time a platform is spawned?" public void Start() { dead = false; } \$\endgroup\$
    – Kevin
    Commented Jul 21, 2020 at 3:21
  • \$\begingroup\$ @Kevin Doesn't that mean it's set to false only once at the very start? Meaning it doesn't continuously get set to false whenever a platform is spawned? But either way, if I remove that section of the code, it still doesn't fix the problem. \$\endgroup\$
    – Matheson
    Commented Jul 21, 2020 at 3:35

1 Answer 1

1
\$\begingroup\$

As DMGregory observed, it seems like your root issue is that you are setting dead to false each time you spawn a platform:

public void Start()
{
    dead = false;
}

You asked

doesn't that mean it's set to false only once at the very start?

As noted in the Unity documentation, "Start is called on the frame when a script is enabled just before any of the Update methods are called the first time." If it's not clear, that means that the Start() function will be called once on each instance of PlatformMover when you first instantiate or activate it.

Using public static variables like this is generally considered bad coding practice, partially because it can easily cause issues exactly such as this. There are lots of other ways to structure your code, but I don't want to get off on too much of a tangent, so I'll focus on how to improve your existing approach.

A key issue is that the dead variable is in the wrong place conceptually. Right now, you run this when the player dies: PlatformMover.dead = true; Look at that code by itself, and think about it out of context. It looks a lot like you're saying that the PlatformMover is dead. It's not at all obvious that the player is dead. Likewise, because the dead variable is in the wrong place, you're trying to initialize it in the wrong place - in the Start() function for PlatformMover.

It would make much more sense to put your dead variable in a Player script, so you could write Player.dead = true; and your platforms could check if (!Player.dead)

However, using a variable is still a bad idea. If you want to do something that isn't much more complicated but is still more maintainable, try this:

public class Player {
    private static bool dead = false;
    public static bool Dead {
        get => dead;
        set {
            dead = value;
            print("'Dead' changed to " + value);
        }
    }
} 

Here we've created a property that we can use like a variable (Player.Dead = true;, if (Player.Dead)) but actually behaves like a function. This is better than using a public variable, because we can run other code when we change the value of "dead". In this case, I've added a print() command that will log to the console, so you can more easily keep track of when something is changing the value of Dead. That's probably enough to help you find and remove any other problematic code.

Some additional tips regarding your movement code:

 if (dead)
 {
     newPlatPos = new Vector3(transform.position.x, transform.position.y, transform.position.z);
 } else if (!dead)
 {
     newPlatPos = new Vector3(transform.position.x, transform.position.y, transform.position.z - platMoveSpeed);
 }
 transform.position = newPlatPos;

The first condition is completely pointless and can be removed (it effectively says transform.position = transform.position). The second condition can be simplified using transform.Translate(). You've also forgotten to factor in Time.deltaTime to make the movement framerate-independent. Combined with my above suggestions, it should probably look more like this:

if (!Player.Dead) transform.Translate(new Vector3(0, 0, -platMoveSpeed * Time.deltaTime));

Note that you will need to increase the value of platMoveSpeed (probably by multiplying it by 60) so that it looks the same when you include Time.deltaTime.

\$\endgroup\$
9
  • \$\begingroup\$ I tried making the changes you suggested but it still isn't stopping the platforms from moving when the player dies. I just added the new scripts that I have to my original post. I know the second one says CoinColliderScript, it's basically the player script. Did I call the booleans incorrectly? \$\endgroup\$
    – Matheson
    Commented Jul 22, 2020 at 4:57
  • \$\begingroup\$ @Matheson Your code looks right. Is it loading the main menu after half a second? If not, maybe your OnTriggerEnter event isn't getting called. Also, check the console logs to see if it is logging "'Dead' changed to false" right after the player dies. \$\endgroup\$
    – Kevin
    Commented Jul 22, 2020 at 5:10
  • \$\begingroup\$ Yeah the main menu is loading so there's no problem there. I'm not getting anything in the console even though I have that "print" in the getter and setter. \$\endgroup\$
    – Matheson
    Commented Jul 22, 2020 at 5:30
  • \$\begingroup\$ @Matheson Try doing your Update() function like I originally described: if (!CoinColliderScript.Dead) transform.Translate(new Vector3(0, 0, -platMoveSpeed * Time.deltaTime)); If that doesn't do it, you must have some other component moving your platforms that you forgot about. \$\endgroup\$
    – Kevin
    Commented Jul 22, 2020 at 6:42
  • \$\begingroup\$ That still isn't working. Does the getter/setter need to be called somewhere or do I need to "return" it? I don't know very much about getters and setters but it doesn't look like it's doing anything the way it is now. And that would make sense because the "print" function isn't running in the console. \$\endgroup\$
    – Matheson
    Commented Jul 22, 2020 at 21:05

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .