How to detect if player is moving Left/Right/Back/Forward - c#

My player can only move along straight horizontal and vertical lines. I want to detect whether they are moving left, right, back, or forward at any given point in time. They can rotate any way they like in the game.
I've tried detecting this when users press the arrows keys and then checking if the current player position along the X or Y (z transform) planes is different than it was before. That didn't seem to work.
I also tried using this code from Unity answers where a similar question was asked but it isn't working for me:
float dot = Vector3.Dot(transform.forward, Vector3.forward);
if(dot > 0.9) // going forward direction
else if (dot < - 0.9) // going opposite to forward direction
else{
Vector3 cross = Vector3.Cross(transform.forward, Vector3.forward);
// This could be the other way around...never remember which order
if(cross.y < 0) // going right
else // going left
}

The best way would be to check the velocity if your Character gets moved by Physics. If your Character moves with something where velocity does not fulfill the job, then you would save the last position and check it with the new one like your first idea was.
Velocity
So like I said when your Character moves with Physics you could check the direction like this:
public RigidBody rb; // Add the rigidbody of your Player to your script
void Update() {
// What ever your code is here
Vector3 vel = transform.rotation * rb.velocity;
if(vel.z > 0) {
// forward
} else if(vel.z < 0) {
// backwards
}
if(vel.x > 0) {
// right
} else if(vel.x < 0) {
// left
}
}
Position
You can also check the movement by position. For this you need to compare not only old Pos and new Pos but also old Rotation and new Rotation.
What I could think of is:
(Not tested)
Vector3 oldPos;
Quaternion oldRot;
Update() {
Vector3 movement = oldRot * (transform.position - oldPos));
if(movement.z > 0) {
// forward
} else if(movement.z < 0) {
// backwards
}
if(movement.x > 0) {
// right
} else if(movement.x < 0) {
// left
}
oldPos = transform.position;
oldRot = transform.rotation;
}

Related

How can I prevent the enemy from following me if we are not in the same tube?

I am making a game where a mouse is followed by a snake in some tubes.
I got down the part where the mouse gets followed, the problem I am having is that sometimes the snake follows the snake even though we are in 2 different tubes, just because I am in front of him from the calculation I am making.
How can I detect if the snake has a wall in front of him, and not the mouse?
This is my code so far:
Vector3 distance = player.position - transform.position;
float dot = Vector3.Dot(distance, transform.forward);
if (dot < 5 && dot > 3)
{
agent.destination = player.position;
}
else
{
agent.destination = goals[0].transform.position;
}
Sounds to me like you want the agent to only follow you while it can "see" you
=> You could probably check this via a Physics.LineCast
Returns true if there is any collider intersecting the line between start and end.
Also btw those 3 < dot < 5 sounds quite arbitrary. I would rather normalize the vectors and then Vector3.Dot
For normalized vectors Dot returns 1 if they point in exactly the same direction, -1 if they point in completely opposite directions and 0 if the vectors are perpendicular.
var distance = player.position - transform.position;
var dot = Vector3.Dot(distance.normalized, transform.forward);
// tweak this value according to your needs
if (dot >= 0.5f) // = 45°
{
<SEE BELOW>
}
else
{
agent.destination = goals[0].transform.position;
}
or alternatively you could also directly check angles if this reads easier for you
var distance = player.position - transform.position;
var angle = Vector3.Angle(distance, transform.forward);
// tweak this value according to your needs
if (angle <= 45f)
{
<SEE BELOW>
}
else
{
agent.destination = goals[0].transform.position;
}
Then replace <SEE BELOW> by e.g.
// now additionally check if there is a wall in between
if(Physics.LineCast(transform.position, player.position, WallsLayerMask))
{
agent.destination = goals[0].transform.position;
}
else
{
agent.destination = player.position;
}

Objects not colliding in Unity 3D

I am following along with creating the Obstacle Game from Game Programming with Unity and C# by Casey Hardman. I have reached the point in the first few pages of Chapter 16 where you create a Hazard to kill the player. In the beginning stages, you write code that kills the player object if the player object collides with the hazard. I've followed the instructions (as far as I can tell) to the letter and yet when I created a sphere as a test hazard, assigned the script to it, and ran the player object into it, nothing happened when they collided. I thought maybe there was an error with the Hazard code, so I commented out the "when collide with object on player layer, kill player" code, wrote code to have it just write to the console when they collide, and tested it. Unfortunately, there doesn't seem to be any collision detection when these two objects touch each other. I've Googled "objects not colliding unity" and every combination of "collision not detected in unity" I can think of and none of the answers have helped so I'm posting here in hopes I get an answer. I'm including screenshots of the two objects and their settings, my physics settings in Unity, and the code I've written for both objects in hopes that someone can catch what I'm doing wrong.
The Player Object
The Test Hazard Object
Layer Collision Matrix
The Player Object Script:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Player : MonoBehaviour
{
//References
[Header("References")]
public Transform trans;
public Transform modelTrans;
public CharacterController characterController;
//Movement
[Header("Movement")]
[Tooltip("Units moved per second at maximum speed.")]
public float movespeed = 24;
[Tooltip("Time, in seconds, to reach maximum speed.")]
public float timeToMaxSpeed = .26f;
private float VelocityGainPerSecond{ get { return movespeed / timeToMaxSpeed; }}
[Tooltip("Time, in seconds, to go from maximum speed to stationary.")]
public float timeToLoseMaxSpeed = .2f;
private float VelocityLossPerSecond { get { return movespeed / timeToLoseMaxSpeed; }}
[Tooltip("Multiplier for momentum when attempting to move in a direction opposite the current traveling direction (e.g. trying to move right when already moving left.")]
public float reverseMomentumMultiplier = 2.2f;
private Vector3 movementVelocity = Vector3.zero;
private void Movement()
{
// IF W or the up arrow key is held:
if (Input.GetKey(KeyCode.W) || Input.GetKey(KeyCode.UpArrow))
{
if (movementVelocity.z >= 0) // If we're already moving forward
//Increase Z velocity by VelocityGainPerSecond, but don't go higher than 'moveSpeed':
movementVelocity.z = Mathf.Min(movespeed,movementVelocity.z + VelocityGainPerSecond * Time.deltaTime);
else // Else if we're moving back
//Increase Z velocity by VelocityGainPerSecond, using the reverseMomentumMultiplier, but don't raise higher than 0:
movementVelocity.z = Mathf.Min(0,movementVelocity.z + reverseMomentumMultiplier * Time.deltaTime);
}
//If S or the down arrow key is held:
else if (Input.GetKey(KeyCode.S) || Input.GetKey(KeyCode.DownArrow))
{
if (movementVelocity.z > 0) // If we're already moving forward
movementVelocity.z = Mathf.Max(0,movementVelocity.z - VelocityGainPerSecond * reverseMomentumMultiplier * Time.deltaTime);
else // If we're moving back or not moving at all
movementVelocity.z = Mathf.Max(-movespeed,movementVelocity.z - VelocityGainPerSecond * Time.deltaTime);
}
else //If neither forward nor back are being held
{
//We must bring the Z velocity back to 0 over time.
if (movementVelocity.z > 0) // If we're moving up,
//Decrease Z velocity by VelocityLossPerSecond, but don't go any lower than 0:
movementVelocity.z = Mathf.Max(0,movementVelocity.z - VelocityLossPerSecond * Time.deltaTime);
else //If we're moving down,
//Increase Z velocity (back towards 0) by VelocityLossPerSecond, but don't go any higher than 0:
movementVelocity.z = Mathf.Min(0,movementVelocity.z + VelocityLossPerSecond * Time.deltaTime);
}
if (Input.GetKey(KeyCode.D) || Input.GetKey(KeyCode.RightArrow))
{
if (movementVelocity.x >= 0) //If we're already moving right
//Increase X velocty by VelocityGainPerSecond, but don't go higher than 'movespeed':
movementVelocity.x = Mathf.Min(movespeed,movementVelocity.x + VelocityGainPerSecond * Time.deltaTime);
else //If we're moving left
//Increase X velocity by VelocityGainPerSecond, using the reverseMomentumMultiplier, but don't raise higher than 0:
movementVelocity.x = Mathf.Min(0,movementVelocity.x + VelocityGainPerSecond * reverseMomentumMultiplier * Time.deltaTime);
}
else if (Input.GetKey(KeyCode.A) || Input.GetKey(KeyCode.LeftArrow))
{
if (movementVelocity.x > 0) //If we're already moving right
movementVelocity.x = Mathf.Max(0,movementVelocity.x - VelocityGainPerSecond * reverseMomentumMultiplier * Time.deltaTime);
else // If we're moving left or not at all
movementVelocity.x = Mathf.Max(-movespeed,movementVelocity.x - VelocityGainPerSecond * Time.deltaTime);
}
else //If neither left nor right are being held
{
//We must bring the X Velocity back to 0 over time.
if (movementVelocity.x > 0) //If we're moving right,
//Decrease X velocity by VelocityLossPerSecond, but don't go any lower than 0:
movementVelocity.x = Mathf.Max(0,movementVelocity.x - VelocityLossPerSecond * Time.deltaTime);
else //If we're moving left
//Increase X velocity (back towards 0) by VelocityLossPerSecond, but don't go any higher than 0:
movementVelocity.x = Mathf.Min(0,movementVelocity.x + VelocityLossPerSecond * Time.deltaTime);
}
//If the player is moving in either direction (left/right or up/down):
if (movementVelocity.x != 0 || movementVelocity.z != 0)
{
//Applying the movement velocity:
characterController.Move(movementVelocity * Time.deltaTime);
//Keeping the model holder rotated towards the last movement direction:
modelTrans.rotation = Quaternion.Slerp(modelTrans.rotation, Quaternion.LookRotation(movementVelocity), .18F);
}
}
//Death and Respawning
[Header("Death and Respawning")]
[Tooltip("How long after the player's death, in seconds, before they are respawned?")]
public float respawnWaitTime = 2f;
private bool dead = false;
private Vector3 spawnPoint;
private Quaternion spawnRotation;
private void Update()
{
Movement();
}
void Start()
{
spawnPoint = trans.position;
spawnRotation = modelTrans.rotation;
}
public void Die()
{
if (!dead)
{
dead = true;
Invoke("Respawn", respawnWaitTime);
movementVelocity = Vector3.zero;
enabled = false;
characterController.enabled = false;
modelTrans.gameObject.SetActive(false);
}
}
public void Respawn()
{
modelTrans.rotation = spawnRotation;
dead = false;
trans.position = spawnPoint;
enabled = true;
characterController.enabled = true;
modelTrans.gameObject.SetActive(true);
}
}
The Hazard Object Script:
`using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Hazard : MonoBehaviour
{
private void OnTriggerEnter(Collider other)
{
if (other.gameObject.layer == 8)
{
//Player player = other.GetComponent<Player>();
//if (player != null)
//player.Die();
Debug.Log("Yay!");
}
}
// Start is called before the first frame update
void Start()
{
}
// Update is called once per frame
void Update()
{
}
}`
I have tried:
Adding a separate box collider to the Player Object
Adding a Rigidbody to one, both, and the other objects
Pulling my hair out
Restarting Unity
Restarting my computer
Tagging the Player Object as Player (I saw a question that looked similar to mine so I thought maybe this would help; I'm not very familiar with Unity or C# yet so I'm unsure what or why things would help.)
None of the above has made it seem like Unity is detecting collision between these two objects.
Here's a line from the documentation for OnTriggerEnter:
"Both GameObjects must contain a Collider component. One must have Collider.isTrigger enabled, and contain a Rigidbody."
Have you tried adding the Collider to your player at the same time as the Rigidbody component to your hazard?
For OnTriggerEnter() you need colliders with Is Trigger ticked and a ridig body. But this check
if (other.gameObject.layer == 8)
does not what it looks like. Layer values are used as bit masks, read more about it here.
To check against the correct layer, you need bitwise operations:
int playerMask = LayerMask.GetMask("Player"); // something like 00110101001
int otherLayer = 1 << other.gameObject.layer; // something like 00010000000
if ((playerMask | otherLayer ) != 0) { // we hit the mask ...1.......
Debug.Log("yay");
}
Be careful when using bitwise operators to not get tricked by operator precedences. Short version from above would be
if ((playerMask | (1 << other.gameObject.layer)) != 0) { ... // extra parentheses!
This will succeed for all objects within the player layer. An alternative would be to set the tag of the player object and compare against that tag:
if (other.gameObject.CompareTag("Player")) { ... // "Player" tag is not the same as "Player" layer

How to realistically reflect a 3d sphere in Unity with C#

I've been trying to realistically reflect a 3d sphere on the walls of a box for a while now in Unity. For some reason, the reflection is generally correct, but when the ball hits a wall in certain directions, the reflection is incorrect.
To illustrate what happens to the ball upon hitting a wall: T = top wall, R = right wall, L = left wall, and B = bottom wall. Let r = the ball comes/goes to the right, l = for the left, and s = the ball stops/slows down significantly. The instructions below take this format: Xyz, where X = the wall the ball is about to hit, y = the ball's initial direction, z = the reflection. The game has a top-down perspective, and the instructions are based on the wall's perspective. I'm also new to C#, so the code is potentially eye burning.
Instructions: Tll, Trl; Bll, Brl; Rls or after hitting another wall Rlr, Rrl; Lls or after hitting another wall Llr, Lrl
Generally, when the ball stops, it jumps in the air. I wonder if this is because the angle reflects along the wrong axis, but why would this only sometimes happen? Also, when only one key is held, the ball bounces back and forth until it leaves the arena. I know about discrete and continuous hit detection, and the setting is on discrete, but the walls generally contain the ball well enough, with this case being the exception.
What I tried:
Figuring out how to use Vector3.Reflect. I do not understand what variables this function should contain and how to apply this to my code. I did look at the Unity Documentation page for help, but it did not answer my question.
Changing the negative signs, as the angle has to be a reflection on the y-axis, and this does change how the reflections work, but does not solve the problem. The current way the negatives are ordered are the most ideal I found.
Giving the ball a physics material for bounciness.
Adding a small number to the denominator in the arctan equation to help prevent a division by zero. This did not help at all.
Creating different equations (basically changing the negatives) for varying combinations of positive and negative accelerations. Since there is a certain positive or negative acceleration associated with each button press (see Movement script), and there seems to be an issue with said signs, I wondered if associating each acceleration with its own set of equations could solve the problem. It did not work.
Checked if the walls were at different angles.
Deleting the variables xA and yA, or placing them in different spots.
Experimented with finding the speed of the object, but had no idea how to implement it.
The code for the Movement script for the player named Controller:
public class Movement : MonoBehaviour
{
public static float xAcceleration = 0.0f;
public static float yAcceleration = 0.0f;
// Update is called once per frame
void Update()
{
if (Input.GetKey(KeyCode.W)) //If the key W is pressed:
{
Vector3 position = this.transform.position; //Variable position is set to transform the players placement in the game.
if (yAcceleration >= -5 && yAcceleration <= 5) //If the y vector of the acceleration is >= -5 and <= 5:
{
yAcceleration = yAcceleration + 0.01f; //The y vector of the acceleration increases by 0.01 as long as the key W is pressed.
}
position.z = position.z + (0.1f * yAcceleration); //The position of the object on the z-axis (pretend it is the y-axis in the game world) is transformed by its original position plus its speed times its yAcceleration.
this.transform.position = position; //The gameObject is now transformed to a position equal to the variable position by the z-axis.
}
else //If the key W is let go of:
{
Vector3 position = this.transform.position;
position.z = position.z + (0.1f * yAcceleration);
this.transform.position = position; //The position of the gameObject continues to update, but its acceleration does not change. Basically, it continues to move forward.
}
//The rest of the code is very similar to the above, but I included it just in case there was something wrong.
if (Input.GetKey(KeyCode.S))
{
Vector3 position = this.transform.position;
if (yAcceleration >= -5 && yAcceleration <= 5)
{
yAcceleration = (yAcceleration) - 0.01f;
}
position.z = position.z + (0.1f * yAcceleration);
this.transform.position = position;
}
else
{
Vector3 position = this.transform.position;
position.z = position.z + (0.1f * yAcceleration);
this.transform.position = position;
}
if (Input.GetKey(KeyCode.A))
{
Vector3 position = this.transform.position;
if (xAcceleration >= -5 && xAcceleration <= 5)
{
xAcceleration = (xAcceleration) - 0.01f;
}
position.x = position.x + (0.1f * xAcceleration);
this.transform.position = position;
}
else
{
Vector3 position = this.transform.position;
position.x = position.x + (0.1f * xAcceleration);
this.transform.position = position;
}
if (Input.GetKey(KeyCode.D))
{
Vector3 position = this.transform.position;
if (xAcceleration >= -5 && xAcceleration <= 5)
{
xAcceleration = (xAcceleration) + 0.01f;
}
position.x = position.x + (0.1f * xAcceleration);
this.transform.position = position;
}
else
{
Vector3 position = this.transform.position;
position.x = position.x + (0.1f * xAcceleration);
this.transform.position = position;
}
}
}
This is the code for the collider and reflection:
public class Collider : MonoBehaviour
{
public float xA;
public float yA;
void OnCollisionEnter(Collision collision) //If a gameObject enters the collision of another object, this immediately happens once.
{
if (gameObject.tag == "Boundary") //If the gameObject has a tag named Boundary:
{
yA = -Movement.yAcceleration; //yA stores the value of yAcceleration after being called from script Movement as a negative. Its a reflection.
Movement.xAcceleration = (Movement.xAcceleration * -Mathf.Atan(yA / Movement.xAcceleration)); //xAcceleration is changed based on this equation: A * artan(A_y / A_x). The 0.000001 was here, adding to A_x to help prevent a 0 as the denominator.
xA = Movement.xAcceleration; //This is declared now...
Movement.yAcceleration = (Movement.yAcceleration * Mathf.Atan(Movement.yAcceleration / xA)); //This uses xA because Movement.xAcceleration is changed, and the yAcceleration calculation is based on the xAcceleration prior the collision.
}
}
void OnCollisionStay(Collision collision)
{
if (gameObject.tag == "Boundary")
{
yA = Movement.yAcceleration; //The same thing happens as before.
Movement.xAcceleration = (Movement.xAcceleration * -Mathf.Atan(yA / Movement.xAcceleration));
xA = Movement.xAcceleration;
Movement.yAcceleration = (Movement.yAcceleration * Mathf.Atan(Movement.yAcceleration / xA));
Movement.xAcceleration = -Movement.xAcceleration / 2; //On collision, the ball is reflected across the x-axis at half its speed.
Movement.yAcceleration = Movement.yAcceleration / 2; //yAcceleration is half its original value.
}
}
}
The picture below is the game setup. I apologize that it is a link; I do not have enough Reputation to merit a loaded image on this page. Also, if anything is unclear, please message me.
https://i.stack.imgur.com/VREV4.png
I would really appreciate the help. Thanks!
One very important note here: As soon as there is any Rigidbody involved you do not want to set any values through the .transform - This breaks the physics and collision detection!
Your Movement should rather alter the behavior of the Rigidbody e.g. by simply changing its Rigibody.velocity
I would then also place the collision check directly into the balls's component and check whether you hit a wall ("Boundary")
Then another note: Your code is currently frame-rate dependent. It means that if your target device runs with only 30 frames per second you will add 0.3 per second to the acceleration. If you run however on a more powerful device that manages to run with 200 frames per second then you add 2 per second.
You should rather define the de/increase per second and multiply it by Time.deltaTime
All together maybe something like this
public class Movement : MonoBehaviour
{
// Adjust these settings via the Inspector
[SerializeField] private float _maxMoveSpeed = 5f;
[SerializeField] private float _speedIncreasePerSecond = 1f;
// Already reference this via the Inspector
[SerializeField] private Rigidbody _rigidbody;
private void Awake()
{
if(!_rigidbody) _rigidbody = GetComponent<Rigidbody>();
}
// Get User Input in Update
private void Update()
{
var velocity = _rigidbody.velocity;
velocity.y = 0;
if (Input.GetKey(KeyCode.W) && velocity.z < _maxMoveSpeed)
{
velocity.z += _speedIncreasePerSecond * Time.deltaTime;
}
if (Input.GetKey(KeyCode.S) && velocity.z > -_maxMoveSpeed)
{
velocity.z -= _speedIncreasePerSecond * Time.deltaTime;
}
if (Input.GetKey(KeyCode.A) && velocity.x > -_maxMoveSpeed)
{
velocity.x -= _speedIncreasePerSecond * Time.deltaTime;
}
if (Input.GetKey(KeyCode.D) && velocity.x < _maxMoveSpeed)
{
velocity.x += _speedIncreasePerSecond * Time.deltaTime;
}
// clamp to the max speed in case you move diagonal
if(velocity.magnitude > _maxMoveSpeed)
{
velocity = velocity.normalized * _maxMoveSpeed;
}
_rigidbody.velocity = velocity;
}
}
And then finally simply add a PhysicsMaterial with desired settings to the walls and ball.
I used Friction = 0f and Bounciness = 0.7f for ball and walls. For slow movements you also might want/have to adjust the Bounce Threshold in the Project's Physics Settings otherwise there will be no bouncing if the velocity is smaller then 2 by default.
This depends a bit on your definition of "realistic". I disabled gravity so the ball also has no rotation and angular friction:

How to detect if the game object is left or right from the player

The Debug.Log always returns LEFT while it needs to be only right when it's on the right side of the player.
Now it's showing both left and right (when on the right side of the game object).
if (distance <= 249)
{
if (enemy.transform.position.x > player.transform.position.x)
{
if (waitTime == 0)
{
Debug.Log("LEFT");
FireGunsLeft();
}
}
else
{
if (waitTime == 0)
{
Debug.Log("RIGHT");
FireGunsRight();
}
}
}
Use player.transform.InverseTransformPoint(enemy.transform.position)
You can use Transform.InverseTransformPoint to find the enemy's relative position from the perspective of the player.
Vector3 enemyDirectionLocal = player.transform.InverseTransformPoint(enemy.transform.position);
This Vector3 enemyDirectionLocal is a vector that describes the enemy's position offset
from the player's position along the player's left/right, up/down, and forward/back axes.
What this means is that if enemyDirectionLocal.x is less than zero, it's on the left side of the player (although maybe ahead or behind as well), and if it's greater than zero, it's on the right side. If it's zero, it's directly behind or ahead of the player.
Vector3 enemyDirectionLocal = player.transform.InverseTransformPoint(enemy.transform.position);
if (enemyDirectionLocal.x < 0)
{
if (waitTime == 0)
{
Debug.Log("LEFT");
FireGunsLeft();
}
}
else if (enemyDirectionLocal.x > 0)
{
if (waitTime == 0)
{
Debug.Log("RIGHT");
FireGunsRight();
}
}
Another approach would be to find the Vector between the player's position and the enemy's position var directionToEnemy = enemy.transform.position - player.transform.position and then find its projection on the right vector of the player's transform, having it > 0 when the enemy is on the right of the player:
var directionToEnemy = enemy.transform.position - player.transform.position;
var projectionOnRight = Vector3.Dot(directionToEnemy, player.transform.right);
if (projectionOnRight < 0)
{
if (waitTime == 0)
{
Debug.Log("LEFT");
FireGunsLeft();
}
}
else if (projectionOnRight > 0)
{
if (waitTime == 0)
{
Debug.Log("RIGHT");
FireGunsRight();
}
}
You also might consider doing the waitTime == 0 check before you do the calculations for the relative position.
if Mathf.Approximately(projectionOnRight, 0f) returns true, then the enemy is right in front of the player and you might want to perform FireGunsStraight() or whatever you have for this case.

Moving around GameObject

I'm trying to create MOB AI using rigidbody. I want to make the mob (GameObject) walk around the world using
mobrigid.AddForce((((goal - transform.position).normalized)*speed * Time.deltaTime));
(goal is a random place around mob).
here is where it gets complicated, some mobs fly up in the air at extreme speeds while others move normaly at slow speed. (And yes, I do make sure the goal.Y is a place on the ground and not air). I tried fixing it by changing the drag, but that leads to mobs walking on air and not falling with gravity.
I'm really lost, can't figure out how do I simply move a gameobject around with rigidbody without getting this odd behavior.
Logs of mobs (with Y of goal changed to 0):
Edit:
Image of the mob:
my movement logic:
case MOBTYPE.EARTHMOB:
switch (currentstatus)
{
case MOBSTATUS.STANDING:
if (mobrigid.IsSleeping())
{
mobrigid.WakeUp();
}
goal = this.transform.position;
goal.x = Random.Range(goal.x - 150, goal.x + 150);
goal.z = Random.Range(goal.z -150, goal.z + 150);
goal.y = 0;
currentstatus = MOBSTATUS.WALKING;
// Debug.Log("Transform:"+this.transform.position+ "Goal:" + goal+ "goal-transform:" + (goal - transform.position));
break;
case MOBSTATUS.WALKING:
if (Random.Range(1, 100) == 5)
{
currentstatus = MOBSTATUS.STANDING;
}
if (mobrigid.IsSleeping())
{
mobrigid.WakeUp();
}
mobrigid.AddForce((((goal - transform.position).normalized) * 10000 * Time.deltaTime));
// transform.LookAt(goal);
var distance = Vector3.Distance(goal, gameObject.transform.position);
if (distance <=5)
{
currentstatus = MOBSTATUS.STANDING;
}
break;
}
break;
Terrain Image:
The Rigidbody.AddForce function is used to add force to an Object along a direction. Since you have a position you need to move a Rigidbody to, you have to use the Rigidbody.MovePosition function. You may also want to mark the Rigidbody as kinematic.
A simple coroutine function to move a Rigidbody object to specific position:
IEnumerator MoveRigidbody(Rigidbody rb, Vector3 destination, float speed = 50f)
{
const float destThreshold = 0.4f;
while (true)
{
Vector3 direction = (destination - rb.position).normalized;
rb.MovePosition(rb.position + direction * speed * Time.deltaTime);
float dist = Vector3.Distance(rb.position, destination);
//Exit function if we are very close to the destination
if (dist <= destThreshold)
yield break;
yield return null;
//yield return new WaitForFixedUpdate();
}
}
It better to call this from another coorutine funtion so that you can yield or wait for it to finish then do other task like generating the random postion again and moving the Rigidbody there.
You want to generate new postion then move the Rigidbody there, this is an example of how to call the function above:
IEnumerator StartMoveMent()
{
Rigidbody targetRb = GetComponent<Rigidbody>();
while (true)
{
//Generate random position
Vector3 destination = new Vector3();
destination.y = 0;
destination.x = UnityEngine.Random.Range(0, 50);
destination.z = UnityEngine.Random.Range(0, 50);
//Move and wait until the movement is done
yield return StartCoroutine(MoveRigidbody(targetRb, destination, 30f));
}
}
And to start the StartMoveMent function:
void Start()
{
StartCoroutine(StartMoveMent());
}
While what I said above should work, I do recommend you use Unity's built in pathfinding system. Here is a tutorial for that. It simplifies finding paths to follow towards a destination with NavMesh which can also be baked during run-time.

Categories