Hello! I’m a bit new to Unity, so I’ve been doing my best to solve problems without going to the forums for every little issue. There is one bug that I just cannot figure out how to get past.
While trying to create a heart management system, the majority of code already reaches proper breakpoint conditions (in the debugger) and does as it should, which means my heart management system in about 70% of the way there. However, the same OnCollisionEnter2D script that works in sections like LivesManager and PlayerMovement, does not work in the GameManager, which means my array for managing hearts does not work. Since my array is in Update and GameManager, having the OnCollisionEnter2D working there is essential. Would anyone have a good fix for this problem that matches the syntax I have going? Everything is rather simple for the code that supports this function, which I’ll document briefly below in two parts:
Part 1:
For PlayerMovement, the function that exists for OnCollisionEnter2D is a valid breakpoint when lives are lost so when I run into a trap, the debugger is happy:
public class PlayerMovement : MonoBehaviour
{
private Rigidbody2D rb;
private BoxCollider2D coll;
private SpriteRenderer sprite;
private Animator anim;
private GameManager _theGM;
public LivesManager _theLM;
public int defaultLives;
public int livesCounter;
[SerializeField] private LayerMask jumpableGround;
private float dirX = 0f;
[SerializeField] private float moveSpeed = 7f;
[SerializeField] private float jumpForce = 14f;
private enum MovementState { idle, running, jumping, falling }
[SerializeField] private AudioSource jumpSoundEffect;
private void Start()
{
_theLM = FindObjectOfType<LivesManager>();
livesCounter = defaultLives;
rb = GetComponent<Rigidbody2D>();
coll = GetComponent<BoxCollider2D>();
sprite = GetComponent<SpriteRenderer>();
anim = GetComponent<Animator>();
}
private void Update()
{
dirX = Input.GetAxisRaw("Horizontal");
rb.velocity = new Vector2(dirX * moveSpeed, rb.velocity.y);
if (Input.GetButtonDown("Jump") && IsGrounded())
{
jumpSoundEffect.Play();
rb.velocity = new Vector2(rb.velocity.x, jumpForce);
}
UpdateAnimationState();
}
private void UpdateAnimationState()
{
MovementState state;
if (dirX > 0f)
{
state = MovementState.running;
sprite.flipX = false;
}
else if (dirX < 0f)
{
state = MovementState.running;
sprite.flipX = true;
}
else
{
state = MovementState.idle;
}
if (rb.velocity.y > .1f)
{
state = MovementState.jumping;
}
else if (rb.velocity.y < -.1f)
{
state = MovementState.falling;
}
anim.SetInteger("state", (int)state);
}
private bool IsGrounded()
{
return Physics2D.BoxCast(coll.bounds.center, coll.bounds.size, 0f, Vector2.down, .1f, jumpableGround);
}
private void OnCollisionEnter2D(Collision2D collision)
{
if(collision.gameObject.tag == "Trap")
{
GameManager.health -=1;
_theLM.TakeLife();
}
}
}
Part 2:
My LivesManager should be setup correctly (everything debugs as it should), which already takes into account whenever the player runs into “Trap” tagged objects; so Collision is functioning perfectly. You can see my syntax approach best, here:
public class LivesManager : MonoBehaviour
{
public int defaultLives;
public int livesCounter;
public GameObject heart0, heart1, heart2, heart3;
public Text livesText;
[SerializeField] private GameManager _theGM;
[SerializeField] LivesManager _theLM;
[SerializeField] private Text LivesCounterText;
[SerializeField] private GameObject LivesSprite;
void Start()
{
livesCounter = defaultLives;
_theGM = FindObjectOfType<GameManager>();
}
void Update()
{
livesText.text = "Hearts " + livesCounter;
if(livesCounter <1)
{
_theGM.GameOver();
}
}
public void TakeLife()
{
livesCounter--;
}
}
The GameManager Problem
Here’s where the problem is, and it is only part of the script that is the culprit. After testing all my code to make sure it is working as it should, it all leads back to an issue in GameManager. Because the OnCollisionEnter2D is not initializing, the array cannot be updated properly. This makes the hearts reset from 3, back to 4 after the game resets.
public class GameManager : MonoBehaviour
{
public List<GameObject> HeartUiObjects = new();
public int defaultLives;
public int livesCounter;
public PlayerMovement thePlayer;
private Vector2 playerStart;
public GameObject gameOverScreen;
public GameObject victoryScreen;
public static int health;
private GameManager _theGM;
public LivesManager _theLM;
void Start()
{
_theLM = FindObjectOfType<LivesManager>();
livesCounter = defaultLives;
defaultLives = health;
playerStart = thePlayer.transform.position;
health = 4;
gameOverScreen.gameObject.SetActive(false);
}
void Update()
{
// In this loop, we expect HeartUiObjects to have a count of 4.
// Thus, i will start at 0 and iterate { 0, 1, 2, 3 }
for(int i = 0; i < HeartUiObjects.Count; i++)
{
// if we don't add 1 to i we will see an off-by-one error
if(health < i + 1)
{
HeartUiObjects[i].SetActive(false);
victoryScreen.gameObject.SetActive(false);
}
else
{
HeartUiObjects[i].SetActive(true);
victoryScreen.gameObject.SetActive(false);
}
}
if(health <= 0)
{
gameOverScreen.gameObject.SetActive(true);
victoryScreen.gameObject.SetActive(false);
Time.timeScale = 0;
}
}
private void OnCollisionEnter2D(Collision2D collision)
{
if(collision.gameObject.tag == "Trap")
{
GameManager.health -=1;
_theLM.TakeLife();
}
}
public void Victory()
{
victoryScreen.SetActive(true);
thePlayer.gameObject.SetActive(false);
gameOverScreen.SetActive(false);
}
public void GameOver()
{
victoryScreen.SetActive(false);
gameOverScreen.SetActive(true);
thePlayer.gameObject.SetActive(false);
}
public void Reset()
{
victoryScreen.SetActive(false);
gameOverScreen.SetActive(false);
thePlayer.gameObject.SetActive(true);
thePlayer.transform.position = playerStart;
}
}
The issue may be that Collision needs to reference “The Player” and “Trap” tag so that they can collide and it registers, but I don’t know how I’d go about doing that? Everything else but this area (OnCollision2D for GameManager) runs smoothly, so I’d like to avoid rewriting a lot of this code if possible. I am rather new, so I’m still learning exactly how to setup objects to interact with each other correctly.
Any help would be appreciated!