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

I’m making a game where the player’s movement is bound by a second screen inside the main screen.

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:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerMovement : MonoBehaviour
{

    [SerializeField] private float speed;
    [SerializeField] private float rotation;
public Rigidbody2D rb;
public float xStartPos;
public float yStartPos;
// Start is called before the first frame update
void Start()
    {
speed = 4.0f;
rotation = 1.5f;
    }
// Update is called once per frame
void Update()
    {
//Project settings using WSAD for Input Axis instead of Arrow Keys
float xMov = Input.GetAxisRaw("Horizontal");
float yMov = Input.GetAxisRaw("Vertical");
rb.velocity = new Vector2(xMov * speed, yMov * speed);
if(Input.GetKey(KeyCode.RightArrow)){
transform.Rotate(new Vector3(0,0,1), -rotation);
        }
if(Input.GetKey(KeyCode.LeftArrow)){
transform.Rotate(new Vector3(0,0,1), rotation);
        }
    }
}

Boundaries.cs (for the player):

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Boundaries : MonoBehaviour
{
    [SerializeField] private float xBound;
    [SerializeField] private float yBottomBound;
    [SerializeField] private float yTopBound;
void Start(){
xBound = 4.05f;
yBottomBound = 2.6f;
yTopBound = 2.85f;
    }
// Update is called once per frame
void Update()
    {
transform.position = new Vector3(Mathf.Clamp(transform.position.x, -xBound, xBound),
Mathf.Clamp(transform.position.y, -yBottomBound, yTopBound), transform.position.z);
    }
}

Enemy.cs (I was trying to come up with something here to no avail):

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Enemy : MonoBehaviour
{
// Start is called before the first frame update
void Start()
    {

    }
// Update is called once per frame
void Update()
    {
Vector2 limit = new Vector2(Random.Range(-4.05f, 4.05f), Random.Range(-2.6f, 2.85f));
//mudar o transform.position dentro do MoveTowards para algo que represente o centro da tela
transform.position = Vector2.MoveTowards(transform.position, limit, );
/*
            O inimigo vai girando numa direção que esteja dentro dos
            limites do jogador.

            Ele surge em um canto aleatório da tela, pequeno e escurecido,
            ficando maior e mais claro conforme se aproxima do centro da
            tela.
        */
    }
}

Hi @PedroZM

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.

Hi @eses

Do you mean the struct Bounds? That’s all I found when searching for “unity bounds”:

“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.

public class BoundsTest : MonoBehaviour
{
    public Bounds bounds;
    public SpriteRenderer spriteRenderer;
    public Transform otherTra;

    void Start() =>
        bounds = new Bounds(spriteRenderer.bounds.center, spriteRenderer.bounds.size);

    void Update()
    {
        if (bounds.Contains(otherTra.position))
            Debug.Log("Transform in bounds area.");
    }
}

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:

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:

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

public class StageBoundaries : MonoBehaviour
{
    public Vector3 bounds;
    public SpriteRenderer stage;
    public float xLimiter;
    public float yTopLimiter;
    public float yBottomLimiter;
    private void Start() {
        stage = GameObject.FindWithTag("Stage").GetComponent<SpriteRenderer>();
        xLimiter = 0.35f;
        yTopLimiter = 0.27f;
        yBottomLimiter = 0.44f;
    }

    private void Update() {
        float maxBoundX = stage.sprite.bounds.max.x - xLimiter;
        float minBoundX = stage.sprite.bounds.min.x + xLimiter;
        float maxBoundY = stage.sprite.bounds.max.y - yTopLimiter;
        float minBoundY = stage.sprite.bounds.min.y + yBottomLimiter;

        transform.position = new Vector3(Mathf.Clamp(transform.position.x, minBoundX, maxBoundX),
            Mathf.Clamp(transform.position.y, minBoundY, maxBoundY), transform.position.z);
       
        bounds = transform.position;
    }
   
}

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:

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

//gerador aleatório de inimigos:
public class EnemySpawner : MonoBehaviour
{
   
    //requer um tipo de inimigo,
    public GameObject enemy;
    Vector3 whereToSpawn;

    StageBoundaries stageBoundaries;


    //contadores para gerenciar os spawns.
    public float spawnRate = 5.0f;
    float nextSpawn = 0.0f;
   
    //a cada frame:
    void Update()
    {
        //se o tempo do jogo ultrapassar o tempo do próximo spawn:
        if (Time.time > nextSpawn)
        {
            //o próximo spawn recebe o tempo do jogo + x segundos da taxa de spawn (o que o fará acontecer de novo),
            nextSpawn = Time.time + spawnRate;
           
            whereToSpawn = stageBoundaries.bounds;
            //o spawn é executado.
            Instantiate(enemy, whereToSpawn, Quaternion.identity);
        }
    }

}

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)