Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. We have updated the language to the Editor Terms based on feedback from our employees and community. Learn more.
    Dismiss Notice
  3. Join us on November 16th, 2023, between 1 pm and 9 pm CET for Ask the Experts Online on Discord and on Unity Discussions.
    Dismiss Notice

2D Game Proper Way To Keep Player On Screen

Discussion in '2D' started by SheldonS, Oct 15, 2016.

  1. SheldonS

    SheldonS

    Joined:
    Jul 23, 2015
    Posts:
    21
    Hello everyone. I am using Unity 5.4.1 while I do the developer challenges from the Super Space Shooter tutorial. In the videos they started off with a 3D project, I started off as 2D, which created some challenges but it helped me learn. One of the developer challenges is to prevent the player from moving off screen. Doing some searches I found many suggestions and settled on one that seemed the most straight forward.

    I would like to make sure this is correct and see if I can get some feedback on some odd behavior when I play it. First the code. Of course this is a bit more code that is needed to see how movement is done, but I like to make sure you have the full picture.

    In the Ship.cs Start method I set the movement min/max range.

    The Player.cs moves in the Update method but I try to prevent off screen movement in the LateUpdate method.

    The Ship.cs
    Code (CSharp):
    1. using UnityEngine;
    2.  
    3. public class Ship : MonoBehaviour
    4. {
    5.  
    6.     public int hitPoints = 30;
    7.     public float fireDelay;
    8.     public float speed;
    9.     public bool enemyShip = false;
    10.  
    11.     public GameObject laserPrefab;
    12.     public GameObject shieldPrefab;
    13.     public float laserDistanceForward;
    14.     public float laserDistanceRight;
    15.     public Vector3 laserRotation;
    16.    
    17.     protected Vector3 movementRangeMin;
    18.     protected Vector3 movementRangeMax;
    19.  
    20.     // Start is called just before any of the Update methods is called the first time
    21.     public void Start()
    22.     {
    23.         //Find out the boundaries of the viewalbe screen
    24.         SpriteRenderer renderer = gameObject.GetComponentInChildren<SpriteRenderer>();
    25.         Vector3 bottomLeftWorldCoordinates = Camera.main.ViewportToWorldPoint(Vector3.zero);
    26.         Vector3 topRightWorldCoordinates = Camera.main.ViewportToWorldPoint(new Vector3(1, 1, 0));
    27.  
    28.         movementRangeMin = bottomLeftWorldCoordinates + renderer.bounds.extents;
    29.         movementRangeMax = topRightWorldCoordinates - renderer.bounds.extents;
    30.     }
    31.  
    32.     protected bool canShoot = true;
    33.  
    34.     protected void ShootLaser()
    35.     {
    36.         if (enemyShip)
    37.         {
    38.             GameObject.Instantiate(laserPrefab, transform.position + Vector3.down * laserDistanceForward + Vector3.right * laserDistanceRight, Quaternion.Euler(laserRotation));
    39.         }
    40.         else
    41.         {
    42.             GameObject.Instantiate(laserPrefab, transform.position + Vector3.up * laserDistanceForward + Vector3.right * laserDistanceRight, Quaternion.Euler(laserRotation));
    43.         }
    44.         Invoke("EnableShoot", fireDelay);
    45.     }
    46.  
    47.     protected void EnableShoot()
    48.     {
    49.         canShoot = true;
    50.     }
    51.  
    52.     public virtual void CalculateHit(int amount)
    53.     {
    54.         hitPoints -= amount;
    55.     }
    56. }
    57.  
    The Player.cs
    Code (CSharp):
    1. using UnityEngine;
    2.  
    3. public class Player : Ship
    4. {
    5.     public EnvironmentManager environmentManager;
    6.     public GameManager gameManager;
    7.     public float backgroundMultiplier = 0.008f;
    8.     [Range(0, 3)]
    9.     private int playerLives;
    10.  
    11.     void Update()
    12.     {
    13.         if (Input.GetAxis("Horizontal") < 0)
    14.         {
    15.             // Left
    16.             transform.position = Vector2.Lerp(transform.position, transform.position + Vector3.left, speed * Time.deltaTime);
    17.             environmentManager.SetMovingHorizontalMultiplier(backgroundMultiplier);
    18.         }
    19.         else if (Input.GetAxis("Horizontal") > 0)
    20.         {
    21.             // Right
    22.             transform.position = Vector2.Lerp(transform.position, transform.position + Vector3.right, speed * Time.deltaTime);
    23.             environmentManager.SetMovingHorizontalMultiplier(-backgroundMultiplier);
    24.         }
    25.         else
    26.         {
    27.             environmentManager.SetMovingHorizontalMultiplier(0);
    28.         }
    29.  
    30.         if (Input.GetAxis("Vertical") > 0)
    31.         {
    32.             // Forward
    33.             transform.position = Vector2.Lerp(transform.position, transform.position + Vector3.up, speed * Time.deltaTime);
    34.             environmentManager.SetMovingVerticallyMultiplier(-backgroundMultiplier);
    35.         }
    36.         else if (Input.GetAxis("Vertical") < 0)
    37.         {
    38.             // Backwards
    39.             transform.position = Vector2.Lerp(transform.position, transform.position + Vector3.down, speed * Time.deltaTime);
    40.             environmentManager.SetMovingVerticallyMultiplier(backgroundMultiplier);
    41.         }
    42.         else
    43.         {
    44.             environmentManager.SetMovingVerticallyMultiplier(0);
    45.         }
    46.  
    47.         if (Input.GetAxis("Fire") > 0 && canShoot)
    48.         {
    49.             canShoot = false;
    50.             ShootLaser();
    51.         }
    52.     }
    53.  
    54.     // LateUpdate is called every frame, if the Behaviour is enabled
    55.     public void LateUpdate()
    56.     {
    57.         //Keep the player from going off screen
    58.         Vector3 newPosition = transform.position;
    59.         newPosition.x = Mathf.Clamp(newPosition.x, movementRangeMin.x, movementRangeMax.x);
    60.         newPosition.y = Mathf.Clamp(newPosition.y, movementRangeMin.y, movementRangeMax.y);
    61.         transform.Translate(newPosition - transform.position);
    62.     }
    63.  
    64.     public override void CalculateHit(int amount)
    65.     {
    66.         int startHP = hitPoints;
    67.         base.CalculateHit(amount);
    68.         if (hitPoints < startHP)
    69.         {
    70.             gameManager.oUI.DecreasePlayerHealth();
    71.         }
    72.         if (hitPoints <= 0)
    73.         {
    74.             playerLives--;
    75.             gameManager.oUI.DecreasePlayerLife();
    76.             if (playerLives < 0)
    77.             {
    78.                 gameManager.EndGame();
    79.             }
    80.             else
    81.             {
    82.                 gameManager.oUI.ResetPlayerHealth();
    83.                 hitPoints = 30;
    84.             }
    85.         }
    86.     }
    87.  
    88.     public void SetPlayerLives(int amount)
    89.     {
    90.         playerLives = amount;
    91.     }
    92. }
    93.  
    The odd behavior happens when you keep trying to move to the left or down or both and you try to fire. It seems like the laser is being fired just before the LateUpdate fixes the player's position, so the laser hits the player's collider. If I increase the spawn distance of the laser from the player, it then appears the laser is not coming from the gun on the ship as its position left/right is wrong. Is there a good way to handle that behavior?
     
  2. LiterallyJeff

    LiterallyJeff

    Joined:
    Jan 21, 2015
    Posts:
    2,802
    Last edited: Oct 17, 2016
    SheldonS likes this.
  3. SheldonS

    SheldonS

    Joined:
    Jul 23, 2015
    Posts:
    21
    Thank you very much! Both for the IgnoreCollision tip and the compliment on my clamping.