Vector3.MoveTowards while also following cursor? - unity3d

I'm making a character that follows my mouse position.
I also have enemies that are being instantiated and would like that character to move towards the location of the enemy but be a few feet higher than the enemy.
Since my character is a flying enemy I'm unsure how to use move towards in unity.
When my enemies are destroyed I would also like the character to continue following the cursor.
public class FollowCursor : MonoBehaviour
{
// Use this for initialization
void Start ()
{
}
// Update is called once per frame
void Update ()
{
if(GameObject.FindWithTag("Enemy"))
{
transform.position = Vector3.MoveTowards.GameObject.FindWithTag("Enemy").transform.position;
}
else
{
transform.position = Camera.main.ScreenToWorldPoint( new Vector3(Input.mousePosition.x,Input.mousePosition.y,8.75f));
}
}
}

I understand you wish to move towards a flying enemy and/or have the flying enemy move towards your character.
I also understand that you wish to use the MoveTowards method to do this.
You should be able to do this by ignoring the Y position or setting it to a fixed value.
Like this.
//Method used: Vector3 MoveTowards(Vector3 current, Vector3 target, float maxDistanceDelta);
//Set movespeed/steps
float speed = 5f;
float step = speed * Time.deltaTime;
//Define y position
float yourFixedYValue = 8.75f;
//Find target
Vector3 enemyPosition = GameObject.FindWithTag("Enemy").transform.position;
Vector3 target = new Vector3(enemyPosition.x, yourFixedYValue, enemyPosition.z);
//Move from current position towards target with step increment.
transform.position = Vector3.MoveTowards(transform.position, target, step);
Please elaborate what you mean if this didn't answer your question.
EDIT:
To move towards the mouse you could use a Raycast something like this inside your Update method.
if (Input.GetMouseButtonDown(0))
{ //If left mouse clicked
RaycastHit hit;
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition); //Fire ray towards where mouse is clicked, from camera.
if (Physics.Raycast(ray, out hit)) //If hit something
target = hit.point; //point is a vector3 //hit.point becomes your target
}
That "something" can be any collider, also an enemy one. So can be used to move around in general and to move towards enemies.

Related

Unity2D raycast pointing at the wrong target

I am working on a script which makes a raycast going in the direction of the mouse. But for some reason it doesn't follow the mouse, it goes directly forward.
void Update()
{
if (Input.GetMouseButtonDown(0))
{
CastRay();
}
void CastRay()
{
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
RaycastHit2D hit = Physics2D.Raycast(ray.origin, ray.direction, Mathf.Infinity);
if (hit.collider != null)
{
Debug.Log(hit.collider.gameObject.name);
}
}
}
The way I understand this question is that you'd like to cast a ray from the player position towards mouse position in 2D. If that is not the case then you should edit your question and give more context on what exactly you want to achieve.
When I understood correctly then the answer is that you construct the wrong ray. What you're doing is casting a ray from the cameras perspective, you can think of it as casting a ray through your monitor towards the game world.
To get a ray from the player characters perspective, the ray should be from the players position towards the mouse position in screen space.
// get the player position in screen space
var playerScreenSpacePosition = Camera.main.WorldToScreenPoint(playerPosition);
// calculate ray direction (to - from = direction)
var rayDirection = Input.mousePosition - playerScreenSpacePosition;
// if direction vectors length should be ignored then normalize
rayDirection.Normalize();
// construct the ray with the player being the origin
// (if needed could be Ray2D as well by ignoring 'Z' axis, needs converting position and direction to Vector2)
var ray = new Ray(playerPosition, rayDirection);
// cast for a hit
var hit = Physics2D.Raycast(ray.origin, ray.direction, Mathf.Infinity);
// alternatively: if the length of the raycast shall be defined by the directions magnitude
// (only if direction not normalized, otherwise the rays length will always be one)
hit = Physics2D.Raycast(ray.origin, ray.direction, ray.direction.magnitude);

How to prevent the player from going on top of object when moving?

The player goes on top of some objects when he walks toward them, how can I prevent that from happening? Here is an example image of that:
I did not jump to be on the couch but yet it still goes on top of it when I walk to it. Here is my player information:
I don't want to change the player's movement, but I don't want it to go on top of objects when I'm walking.
Make the Step Offset in character controller 0. More info on it here
The character controller Step Offset solves this problem by increasing it value, but you may find that after adding the value, the character controller does not generate any gravitational force on its own.
To solve the problem of gravity, it is enough to first get the component.
private CharacterController controller;
public void Start()
{
controller = GetComponent<CharacterController>();
}
And then apply gravity to the object with the following instructions, you have already obtained the moveInput axis with the Input.GetAxis method.
private Vector3 velocity;
private void Update()
{
var moveInput = new Vector3(Input.GetAxis("Horizontal"), 0f, Input.GetAxis("Vertical"));
// === AFTER CALCULATING MOVE INPUT
controller.Move(moveInput*Time.deltaTime);
velocity += Physics.gravity * Time.deltaTime;
controller.Move(velocity); // Apply Gravity
if (controller.isGrounded) velocity = Vector3.zero;
}

Top Down Shooter Animations Unity, how do you get the right directional animations to play when moving?

i'm not really sure how to phrase the question sorry about that. I have encountered this hurdle while setting up animations on a character for learning a top down character controller (No rigid body) I've seen this question asked on Reddit and unity forums like a decade ago, but I don't really understand their answers.
My problem right now is that I can't find out a way to tell mecanim if the player is moving towards the direction they're facing. For example, if the player is moving left and aiming to the left, the moveForward animation should be played. If the player is moving left but aiming to the right, the moveBackwards animation should be played.
This is the first time i'm posting a question. I am sorry if my formatting is wrong.
Here is the code I have, I would greatly appreciate any help.
public class CharacterMovement : MonoBehaviour
{
private Vector3 velocity;
private Vector3 PlayerMoveInput;
Animator animationS;
[SerializeField] CharacterController characterrController;
[SerializeField] private float MoveSpeed;
[SerializeField] private float JumpHeight;
[SerializeField] private float Gravity = -9.81f;
// Start is called before the first frame update
void Start()
{
animationS = GetComponent<Animator>();
}
// Update is called once per frame
void Update()
{
PlayerMoveInput = new Vector3(Input.GetAxis("Horizontal"), 0f, Input.GetAxis("Vertical")); //collects the input for the player
MovePlayer();
PlayerRotation();
}
private void MovePlayer()
{
if (characterrController.isGrounded)
{
velocity.y = -1f;
}
if (Input.GetKeyDown(KeyCode.Space) && characterrController.isGrounded)
{
velocity.y = JumpHeight;
}
///
else
{
velocity.y -= Gravity * -2f * Time.deltaTime;
}
Vector3 MoveVector = transform.TransformDirection(PlayerMoveInput);
characterrController.Move(MoveSpeed * Time.deltaTime * MoveVector);
characterrController.Move(velocity * Time.deltaTime);
float velocityX = Vector3.Dot(PlayerMoveInput, transform.forward);
float velocityZ = Vector3.Dot(PlayerMoveInput, transform.right);
animationS.SetFloat("velocityX", velocityZ, 0.1f, Time.deltaTime);
animationS.SetFloat("velocityZ", velocityX, 0.1f, Time.deltaTime);
}
void PlayerRotation()
{
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
RaycastHit hit;
Debug.DrawRay(ray.origin, ray.direction, Color.yellow);
if (Physics.Raycast(ray, out hit))
{
Vector3 targetPosition = new Vector3(hit.point.x, transform.position.y, hit.point.z);
Quaternion rotation = Quaternion.LookRotation(targetPosition - transform.position);
transform.rotation = Quaternion.Lerp(transform.rotation, rotation, Time.deltaTime * 10.0f);
}
}
}
This isn't the exact implementation that would be used with your code but should give you a good start.
// get the angle between where the player is pointing, and where he is moving
float angle = Vector3.Angle(MoveVector, targetPosition - transform.position);
if (angle < 90f){
//move forward animation
} else {
//move back animation
}
I haven't tested this code but the idea is that if the angle between the direction the player is facing and the direction the player is moving is less than 90 degrees, then he is moving forward. Also the variables used here: MoveVector and targetPosition are private so you will need to fix that issue before this method can be implemented.
With mechanim, its very common to have 4 separate float value params in your animator. Two are used for movement info, two are for look direction info. This lets you use blend trees based on those functions that handle alot of the pain, all you need to do is update the values in the animator with the correct ones on each update/lateupdate depending on what you are doing.
This is how my animator params are layed out as well as the locomotion blend tree, I have another on a separate layer just for the head that uses Head left right, and head updown params to, you know, control the head.
And here is the code (or at least some of it) that sets the values on the animator component
EDIT:
Sorry, forgot to mention that the function i call "LerpFloat" on the anim variable is an extention method i defined myself for the animator component, all it does is gets the float value, lerps it, then sets the float value back. It just uses Mathf.Lerp.
Thank you both for your answers, the problem was the settings of the animation clips.....
Where you tick
Root transform Rotation
Root transform position (Y)
Root transform position (XZ)
I had ticked all of them, where just the root transform rotation was needed.
I will need to be more careful with the animator and animation clips in the future to avoid headaches.

How to make a player only move in 1 direction (Unity)

I am trying to create a game in Unity where the player can only move in the direction it is facing, but the following code allows the player to move in all 4 directions.
(This is for a 3D project)
Any help would be appreciated! Thanks!
public class PlayerController : MonoBehaviour {
public float speed;
private Rigidbody rb;
void Start() {
rb = GetComponent<Rigidbody>();
}
void FixedUpdate() {
float moveHorizontal = Input.GetAxis("Horizontal");
float moveVertical = Input.GetAxis("Vertical");
Vector3 movement = new Vector3(moveHorizontal, 0.0f, moveVertical);
rb.AddForce(movement * speed);
}
}
So I didn't get what you wanted: first you said you wanted it to move only forward, then the only thing you have to do is get when he pressed a key and move forward while is not unpressed.
If you wanted to say that it can move all directions BUT only one at a time, the you will have to put the same code but with some changes:
First of all to make it move forward you have to get the forward of the transform, otherwise it will move in the same direction if you rotate it (you don't want that, no?).
Vector3 moveDirection = (transform.forward * Input.GetAxis("Vertical") + transform.right * Input.GetAxis("Horizontal")).normalized;
moveDirection.y = 0;
rb.velocity = moveDirection;
Then, to make that it ONLY moves to one direction at a time, you have to put the priority of the greatest axis number and if it's equal then you should think if you want to move forward or right (with it's axis value).
From the code you posted, I'm not sure where you are storing the player's facing-direction. However, I presume that it is stored as a Quaternion. If you have a player rotation quaternion called playerRotation, then you could do this (warning - untested):
Vector3 input = new Vector3(Input.GetAxis("Horizontal"), 0, Input.GetAxis("Vertical"));
Vector3 normal = playerRotation * Vector3.forward;
Vector3 movement = Vector3.Dot(normal, input) * input;
If the game is first-person, then you can take a shortcut and just use Camera.current.transform.forward instead of the normal vector.
This will project the input direction onto the normal with the player's facing direction so that your movement force can only be in that direction.

Unity - Get Local Mouse Position from the center of the Gameobject clicked on

I want to get the mouse clicked position from the center of the gameobject, say a Sphere of Scale(1, 1, 1), for instance. If I click on the center of the sphere it should return the x component as zero, on clicking to the extreme left of the sphere, it should return -0.5 as the x component of the vector3 and 0.5 on clicking the extreme right of the sphere. The below code helps me achieve this when at origin. However, there is one constraint for it. The Sphere has to be positioned at (0, anything, anything) (as I am concerned with the x axis).
Any help on how can I achieve this regardless of the Sphere position?
bool isGameOver = false;
float pointX;
// Update is called once per frame
void Update () {
if(!isGameOver){
RaycastHit hit;
if(Input.GetMouseButtonDown(0)){
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
if(Physics.Raycast(ray, out hit)){
if(hit.transform.tag =="Ball"){
pointX = transform.InverseTransformPoint(hit.point).x;
}
}
}
}
}
Are you using a perspective camera or ortographic?
If you are using perspective and you move your game object to right, you cant hit on the 0,5 of the right side. Because is behide your visible part of ball.
Only can do it with orto camera
Your code is ok for this.
If you need the object position only need to add the transform.localposition to your pointX.
pointX = transform.localPosition.x + transform.InverseTransformPoint(hit.point).x;
Use this code to rotate your gameobject looking for the camera and you get now the right x coordinate you need.
void Update () {
if(!isGameOver)
{
Vector3 offset = transform.position - Camera.main.transform.position;
transform.LookAt(transform.position + offset);
RaycastHit hit;
if(Input.GetMouseButtonUp(0)){
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
if(Physics.Raycast(ray, out hit)){
if(hit.transform.tag =="Ball")
{
pointX = hit.transform.InverseTransformPoint(hit.point);
Debug.Log ("X:" + pointX.ToString());
}
}
}
}
}