Game Development Asked by Matheson on November 2, 2021
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");
}
}
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
.
Answered by Kevin on November 2, 2021
Get help from others!
Recent Answers
Recent Questions
© 2024 TransWikia.com. All rights reserved. Sites we Love: PCI Database, UKBizDB, Menu Kuliner, Sharing RPP