- Home /
How can I keep randomly moving enemies within a certain area (top-down 2D RPG)?
EDIT: I was unclear when I initially posted this. This is for a top-down 2D RPG game.
I've managed to create enemies that move in a random direction for a certain duration, stop for a certain duration then pick another random direction, move, pause, rinse, repeat, thanks to some helpful people here. Now I'm looking for some advice and/or solutions to keep these randomly moving enemies within a certain area. My first thought is to maybe use clamp around a particular set of coordinates, and while that might work, I'm going to end up having the enemies no doubt pushing up against an invisible barrier. I'd rather avoid that, but I'm at a loss as to what to try next.
Any ideas?
Answer by xxmariofer · Feb 28, 2019 at 08:19 AM
transform.position teleports the gameobject from one position to another while the rigidbody adds a force to the rigidbody, unless you need collisions with that body you can use transform.position.
change the ifs for this
if (transform.position.x < minX || transform.position.x > maxX) movementPerSecond.x = -movementPerSecond.x;
if (transform.position.y < minY || transform.position.y > maxY) movementPerSecond.y = -movementPerSecond.y;
if (transform.position.z < minZ|| transform.position.z > maxZ)movementPerSecond.z = -movementPerSecond.z;
That appears to have done it! I could swear that I tried that exact thing (as I mentioned above) when trying to adapt your initial response to my code, but for whatever reason, it didn't work. Still, it looks like it is behaving the way I want now.
And thanks for the quick explanation between transform.position and rigidbody.velocity! Very helpful :).
EDIT: This isn't giving me the option to mark this as the answer, even though I want to :(.
i have changed the last comment to an anser so you can mark that one :)
Answer by tinylord202 · Feb 26, 2019 at 02:53 AM
I would suggest using a navmesh.
First you would want to bake a navmesh for the scene.
From there, define the location you wish to have the enemies patrol. You could do this through a minimum and maximum Vector3().
Put a Navmesh Agent on the enemies, and set the stopping distance greater than 0, I would suggest 0.1 to 0.3.
Start a new C# script, and at the top where it says
Using UnityEngine;
you would put underneath it`Using UnityEngine.AI;`Next would be to add funtionality.
A simple example would beUsing UnityEngine; Using UnityEngine.AI Public class EnemyControl : Monobehavior { NavmeshAgent agent; public Vector3 minPos; public Vector3 maxPos; void Start() { agent = GetComponent<NavmeshAgent>(); } void Update() { if(!agent.hasPath) agent.SetDestination("Random value between the two Vector3s Min and Max"); else if(agent.remainingDistance >= agent.stoppingDistance) agent.SetDestination("Random value between the two Vector3s Min and Max");
For finding the value you could find a random value for each coordinate using Random.Range with each axis of min and max as the respective parameters. Or you could use Mathf.Lerp(minimum x value, maximum x value, Random.value) and so forth.
I haven't been able to try to apply this just yet, but I've read up on it a bit. I'll report back once I've been able to fully jump in :).
I started looking into the Nav$$anonymous$$esh, then realized that it is for a 3D game. I apologize, but I forgot to mention that this was for a top-down 2D RPG. Near as I can tell, the Nav$$anonymous$$esh is meant for 3D games, not 2D. However, if there is a way to apply this to my project that I missed, I'm all ears :).
Answer by xxmariofer · Feb 26, 2019 at 08:47 AM
hello,continuing your previous question, try add this lines inside the update
if (transform.position.x < minX || transform.position.x > maxX) rb.velocity.x = -rb.velocity.x;
if (transform.position.y < minY || transform.position.y > maxY) rb.velocity.y = -rb.velocity.y;
if (transform.position.z < minZ|| transform.position.z > maxZ) rb.velocity.z = -rb.velocity.z;
the minx miny maxx.... are the vars that control the limits of the area you need to assign them in the inspector for example.
I'm liking how this looks. I'll have to rework some of the code since I'm adjusting the transform.position rather than rigidBody.velocity, but I'll do that and let you know :).
I've been trying since last night to integrate this into my code (see below), but I haven't had any luck. You used rb.velocity where the code I found online is using transform.position moveSpeed Time.deltaTime. So what I did was try to use your if statements and reverse x or y (don't have to mess with z in this 2D game) on the appropriate transform.position variables, but that didn't work. I had some partial luck with simply calling the Calculate$$anonymous$$ovementVector() in those if statements. It kept the enemy nearby, but didn't work too well to smoothly keep it in bounds.
Part of this is my trying to understand the difference between using transform.position versus rigidBody.velocity. Any pros and/or cons for using one or the other?
Here is my current code that uses $$anonymous$$athf.Clamp:
public float waitTime = 2f;
public float directionChangeTime = 1f;
private float latestDirectionChangeTime;
private Vector2 movementDirection;
private Vector2 movementPerSecond;
private bool isWaiting;
public Vector3 bottomLeftLimit;
public Vector3 topRightLimit;
protected override void Start()
{
rigidBody = GetComponent<Rigidbody2D>();
animator = GetComponent<Animator>();
isWaiting = false;
latestDirectionChangeTime = 0f;
CalcuateNew$$anonymous$$ovementVector();
}
protected override void Update()
{
// If the changeTime was reached, calculate a new movement vector
if (Time.time - latestDirectionChangeTime > directionChangeTime && !isWaiting)
{
isWaiting = true;
Invoke("InvokeIsWaiting", waitTime);
movementPerSecond = Vector3.zero;
}
// $$anonymous$$ove enemy
transform.position = new Vector2(transform.position.x + (movementPerSecond.x * Time.deltaTime), transform.position.y + (movementPerSecond.y * Time.deltaTime));
// $$anonymous$$eep the enemy inside the bounds of a particular area
transform.position = new Vector3($$anonymous$$athf.Clamp(transform.position.x, bottomLeftLimit.x, topRightLimit.x),
$$anonymous$$athf.Clamp(transform.position.y, bottomLeftLimit.y, topRightLimit.y), transform.position.z);
}
void InvokeIsWaiting()
{
latestDirectionChangeTime = Time.time;
CalcuateNew$$anonymous$$ovementVector();
isWaiting = false;
}
void CalcuateNew$$anonymous$$ovementVector()
{
// Create a random direction vector with the magnitude of 1, later multiply it with the velocity of the enemy
movementDirection = new Vector2(Random.Range(-1.0f, 1.0f), Random.Range(-1.0f, 1.0f)).normalized;
movementPerSecond = movementDirection * moveSpeed;
}
Your answer
Follow this Question
Related Questions
Camera Boundry when changing orthographic size 0 Answers
Object Boundaries C# help please 1 Answer
How to get RenderTexture non-square? 2 Answers
door script problems 2 Answers