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. Dismiss Notice

How to make enemy step into the player's boundaries during movement?

Discussion in '2D' started by PedroZamp, Dec 20, 2020.

  1. PedroZamp

    PedroZamp

    Joined:
    May 22, 2020
    Posts:
    6
    I'm making a game where the player's movement is bound by a second screen inside the main screen.

    Sem título.png

    The player is the black and white square at the center of the screen and the enemy, in this case, is the golden key at the corner.

    I want to make the enemy appear from a random corner of the main screen and move in a straight or diagonal line to another random corner, where it will disappear and be destroyed.

    The thing is, I need to make sure that during its movement, the enemy steps into the player's boundaries, so that the player has the chance of interacting with it. How can I pull this off?

    Here are the scripts I've made so far:

    PlayerMovement.cs:
    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4. public class PlayerMovement : MonoBehaviour
    5. {
    6.  
    7.     [SerializeField] private float speed;
    8.     [SerializeField] private float rotation;
    9. public Rigidbody2D rb;
    10. public float xStartPos;
    11. public float yStartPos;
    12. // Start is called before the first frame update
    13. void Start()
    14.     {
    15. speed = 4.0f;
    16. rotation = 1.5f;
    17.     }
    18. // Update is called once per frame
    19. void Update()
    20.     {
    21. //Project settings using WSAD for Input Axis instead of Arrow Keys
    22. float xMov = Input.GetAxisRaw("Horizontal");
    23. float yMov = Input.GetAxisRaw("Vertical");
    24. rb.velocity = new Vector2(xMov * speed, yMov * speed);
    25. if(Input.GetKey(KeyCode.RightArrow)){
    26. transform.Rotate(new Vector3(0,0,1), -rotation);
    27.         }
    28. if(Input.GetKey(KeyCode.LeftArrow)){
    29. transform.Rotate(new Vector3(0,0,1), rotation);
    30.         }
    31.     }
    32. }
    Boundaries.cs (for the player):
    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4. public class Boundaries : MonoBehaviour
    5. {
    6.     [SerializeField] private float xBound;
    7.     [SerializeField] private float yBottomBound;
    8.     [SerializeField] private float yTopBound;
    9. void Start(){
    10. xBound = 4.05f;
    11. yBottomBound = 2.6f;
    12. yTopBound = 2.85f;
    13.     }
    14. // Update is called once per frame
    15. void Update()
    16.     {
    17. transform.position = new Vector3(Mathf.Clamp(transform.position.x, -xBound, xBound),
    18. Mathf.Clamp(transform.position.y, -yBottomBound, yTopBound), transform.position.z);
    19.     }
    20. }
    Enemy.cs (I was trying to come up with something here to no avail):
    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4. public class Enemy : MonoBehaviour
    5. {
    6. // Start is called before the first frame update
    7. void Start()
    8.     {
    9.  
    10.     }
    11. // Update is called once per frame
    12. void Update()
    13.     {
    14. Vector2 limit = new Vector2(Random.Range(-4.05f, 4.05f), Random.Range(-2.6f, 2.85f));
    15. //mudar o transform.position dentro do MoveTowards para algo que represente o centro da tela
    16. transform.position = Vector2.MoveTowards(transform.position, limit, );
    17. /*
    18.             O inimigo vai girando numa direção que esteja dentro dos
    19.             limites do jogador.
    20.  
    21.             Ele surge em um canto aleatório da tela, pequeno e escurecido,
    22.             ficando maior e mais claro conforme se aproxima do centro da
    23.             tela.
    24.         */
    25.     }
    26. }
     
  2. eses

    eses

    Joined:
    Feb 26, 2013
    Posts:
    2,637
    Hi @PedroZamp

    Why bother calculating everything manually - there already exists Bounds that can be used to define areas and then you see if your position is inside that area.

    Usually it would be nice to post your code so that it is properly formatted. Pasting code with code tags is already better, but indentation will make the code easy to read.
     
  3. PedroZamp

    PedroZamp

    Joined:
    May 22, 2020
    Posts:
    6
    Hi @eses

    Do you mean the struct Bounds? That's all I found when searching for "unity bounds":
    https://docs.unity3d.com/ScriptReference/Bounds.html
     
  4. eses

    eses

    Joined:
    Feb 26, 2013
    Posts:
    2,637
    "Do you mean the struct Bounds?"

    Yes. Something like this (an example, nothing else).

    In this case I used spriteRenderer as source to get the "screen" dimensions.
    Code (CSharp):
    1. public class BoundsTest : MonoBehaviour
    2. {
    3.     public Bounds bounds;
    4.     public SpriteRenderer spriteRenderer;
    5.     public Transform otherTra;
    6.  
    7.     void Start() =>
    8.         bounds = new Bounds(spriteRenderer.bounds.center, spriteRenderer.bounds.size);
    9.  
    10.     void Update()
    11.     {
    12.         if (bounds.Contains(otherTra.position))
    13.             Debug.Log("Transform in bounds area.");
    14.     }
    15. }
    It is only AABB / an axis-aligned bounding box.

    BTW - you didn't explain what you used for your characters and screen visuals... sprites or UI elements... that would also make a difference.

    I addition to Bounds, there is also Rect which could be useful:
    https://docs.unity3d.com/ScriptReference/Rect.html
     
  5. PedroZamp

    PedroZamp

    Joined:
    May 22, 2020
    Posts:
    6
    About that, I'm using sprites.

    I've made a StageBoundaries script implementing the second screen's sprite's bound with some limiters so the player can't reach past the corners of screen:

    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4.  
    5. public class StageBoundaries : MonoBehaviour
    6. {
    7.     public Vector3 bounds;
    8.     public SpriteRenderer stage;
    9.     public float xLimiter;
    10.     public float yTopLimiter;
    11.     public float yBottomLimiter;
    12.     private void Start() {
    13.         stage = GameObject.FindWithTag("Stage").GetComponent<SpriteRenderer>();
    14.         xLimiter = 0.35f;
    15.         yTopLimiter = 0.27f;
    16.         yBottomLimiter = 0.44f;
    17.     }
    18.  
    19.     private void Update() {
    20.         float maxBoundX = stage.sprite.bounds.max.x - xLimiter;
    21.         float minBoundX = stage.sprite.bounds.min.x + xLimiter;
    22.         float maxBoundY = stage.sprite.bounds.max.y - yTopLimiter;
    23.         float minBoundY = stage.sprite.bounds.min.y + yBottomLimiter;
    24.  
    25.         transform.position = new Vector3(Mathf.Clamp(transform.position.x, minBoundX, maxBoundX),
    26.             Mathf.Clamp(transform.position.y, minBoundY, maxBoundY), transform.position.z);
    27.        
    28.         bounds = transform.position;
    29.     }
    30.    
    31. }
    32.  
    I've also made a public Vector3 bounds within that script. My plan was to apply it to my EnemySpawner script so that the enemies could be instantiated and move towards the player's reach:

    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4.  
    5. //gerador aleatório de inimigos:
    6. public class EnemySpawner : MonoBehaviour
    7. {
    8.    
    9.     //requer um tipo de inimigo,
    10.     public GameObject enemy;
    11.     Vector3 whereToSpawn;
    12.  
    13.     StageBoundaries stageBoundaries;
    14.  
    15.  
    16.     //contadores para gerenciar os spawns.
    17.     public float spawnRate = 5.0f;
    18.     float nextSpawn = 0.0f;
    19.    
    20.     //a cada frame:
    21.     void Update()
    22.     {
    23.         //se o tempo do jogo ultrapassar o tempo do próximo spawn:
    24.         if (Time.time > nextSpawn)
    25.         {
    26.             //o próximo spawn recebe o tempo do jogo + x segundos da taxa de spawn (o que o fará acontecer de novo),
    27.             nextSpawn = Time.time + spawnRate;
    28.            
    29.             whereToSpawn = stageBoundaries.bounds;
    30.             //o spawn é executado.
    31.             Instantiate(enemy, whereToSpawn, Quaternion.identity);
    32.         }
    33.     }
    34.  
    35. }
    36.  
    But "whereToSpawn = stageBoundaries.bounds;" doesn't seem to work, as I get the following exception:

    NullReferenceException: Object reference not set to an instance of an object
    EnemySpawner.Update () (at Assets/Scripts/EnemySpawner.cs:29)