I have a problem in keeping the character facing the same direction he was facing its always turn to the z direction of the world coordinate I hope to find way to fix this problem.
I tried to stop this with using Quaternion.LookRotation() and Vector3.RotateToward() but still when stop he rotate in idle animation to the world z direction.
public class MovementController : MonoBehaviour
{
Vector3 _CharacterDirection;
Quaternion _CharacterRotation=Quaternion.identity;
Animator _CharacterAnim;
Rigidbody _CharacterRigidbody;
public float TurnSpeed;
void Start()
{
_CharacterAnim = GetComponent<Animator>();
_CharacterRigidbody = GetComponent<Rigidbody>();
}
void FixedUpdate()
{
CharacterMovement();
}
void CharacterMovement()
{
float h = Input.GetAxis("Horizontal");
float v = Input.GetAxis("Vertical");
_CharacterDirection.Set(h, 0, v);
_CharacterDirection.Normalize();
bool _IsHorizontalChange = !Mathf.Approximately(h, 0f);
bool _IsVerticalChange = !Mathf.Approximately(v, 0);
bool _IsWalking = _IsHorizontalChange || _IsVerticalChange;
_CharacterAnim.SetBool("IsWalking", _IsWalking);
Vector3 _DesairdForward = Vector3.RotateTowards(Vector3.forward, _CharacterDirection, TurnSpeed * Time.deltaTime, 0);
_CharacterRotation = Quaternion.LookRotation(_DesairdForward);
_CharacterRigidbody.MovePosition(_CharacterRigidbody.position + _CharacterDirection * Time.deltaTime);
_CharacterRigidbody.MoveRotation(_CharacterRotation);
}
}
Related
Unity2D
How to make game object to face opposite from the position of another game object?
I have a fish that is going always forward and randomly rotating to make semi random movement,
and i want that in range of player(shark) the fish change direction opposite to shark and start moving faster(trying to escape). I have speed increase already but i doknt know how to make the opposite direction.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class FishMove : MonoBehaviour
{
Rigidbody2D rb;
int rotZ = 0;
[SerializeField]
Transform target;
float speed;
bool move=true;
bool rotace = true;
[SerializeField]
int smerRotace;
[SerializeField]
float casRotace;
float nula;
[SerializeField]
Transform shark;
float fearRange=4;
void Start()
{
rb = GetComponent<Rigidbody2D>();
}
void FixedUpdate()
{
if (rotace)
{
rotace = false;
smerRotace = Random.Range(-1, 2);
if (smerRotace == 0) nula = 0.2f;
Invoke("Rotace", Random.Range(3.0f*nula, 9.0f*nula));
nula = 1;
}
rotZ += 2 * smerRotace;
float distance = Vector2.Distance(transform.position, shark.position);
if (distance < fearRange)
{
speed = 0.1f;
}
else
{
transform.rotation = Quaternion.Euler(0, 0, rotZ);
}
transform.position = Vector2.MoveTowards(transform.position, target.position, speed);
speed = 0.05f;
}
void Rotace()
{
rotace = true;
}
}
Notice: at the part when I am saying to add/subtract 90 (you’ll know when you get there), try adding 90, if that doesn’t work, try subtracting 90 to get the right result.
To make it move fully the opposite direction, you should do a few things. First, I will tell you about Mathf.Atan2(float y, float x). Atan2 is arctangent. Arctangent takes a position, and finds the amount of rotations to rotate at that object, in radians. Then, you would want to multiply by Mathf.Rad2Deg, or radians to degrees. It converts radians to degrees, which unity uses. Then, you would add some degrees to face the opposite direction.
Here is a way to make an object look away from the the mouse:
using UnityEngine;
using System;
using System.Collections.Generic;
public class LookAtMouse : MonoBehaviour
{
public GameObject obj;
Vector3 offset;
Vector3 mousePosition;
float rotation;
void Update()
{
mousePosition = Camera.main.ScreenToWorldPoint(Input.mousePosition);
offset = mousePosition - obj.transform.position;
rotation = Mathf.Atan2(offset.y, offset.x) * Mathf.Rad2Deg - 90f;
obj.transform.rotation = Quaternion.Euler(0f, 0f, rotation);
}
}
Basically, the script gets the mouse position, and stores it in mousePosition. Then, it gets the offset of the mouse relative to obj. The rotation is the product of the arctangent of the offset and the amount of degrees in a radian (unity uses degrees, not radians), minus 90. Arctangent is 90 degrees off of the target, so people usually add 90 to get it to look at the target. We are looking away from the target, so we subtract 90 to be 180 degrees away, or half way.
We would do the same thing for your script; here it is:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class FishMove : MonoBehaviour
{
Rigidbody2D rb;
int rotZ = 0;
[SerializeField] Transform target;
float speed;
bool move=true;
bool rotace = true;
[SerializeField] int smerRotace;
[SerializeField] float casRotace;
float nula;
[SerializeField] Transform shark;
float fearRange=4;
void Start()
{
rb = GetComponent<Rigidbody2D>();
}
Vector3 offset;
float rotation;
void FixedUpdate()
{
if (rotace)
{
rotace = false;
smerRotace = Random.Range(-1, 2);
if (smerRotace == 0) nula = 0.2f;
Invoke("Rotace", Random.Range(3.0f*nula, 9.0f*nula));
nula = 1;
}
rotZ += 2 * smerRotace;
float distance = Vector2.Distance(transform.position, shark.position);
if (distance < fearRange)
{
speed = 0.1f;
offset = transform.position - shark.transform.position;
rotation = Mathf.Atan2(offset.y, offset.x) * Mathf.Rad2Deg - 90f;
transform.rotation = Quaternion.Euler(0f, 0f, rotation);
}
else
{
transform.rotation = Quaternion.Euler(0, 0, rotZ);
}
transform.position = Vector2.MoveTowards(transform.position, target.position, speed);
speed = 0.05f;
}
void Rotace()
{
rotace = true;
}
}
Tell me in the comments if it works or if it doesn't work.
Here's my code. Currently, the player moves forwards relative to a fix plane. Rotating the player/camera has no affect on which direction they travel when I press the "go forward" key.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class MainController : MonoBehaviour
{
public float speed;
float jumpSpeed = 0.5f;
bool isGrounded;
private Rigidbody rb;
public GameObject player;
// Start is called before the first frame update
void Start()
{
rb = GetComponent<Rigidbody>();
}
// Update is called once per frame
void Update()
{
}
void FixedUpdate()
{
float moveHorizontal = Input.GetAxis("Horizontal");
float moveVertical = Input.GetAxis("Vertical");
Vector3 movement = new Vector3(moveHorizontal, 0.0f, moveVertical);
if (Input.GetButtonDown("Jump") || Input.GetAxis("Right Trigger") > 0f && isGrounded)
{
rb.AddForce(Vector3.up * jumpSpeed, ForceMode.Impulse);
isGrounded = false;
}
if (isGrounded)
{
rb.AddForce(movement * speed * Time.deltaTime);
}
else
{
rb.AddForce((movement/4) * speed * Time.deltaTime);
}
}
void OnCollisionStay()
{
isGrounded = true;
}
void OnCollisionExit()
{
isGrounded = false;
}
}
How do I make it so that the player moves relative to the camera's direction?
It's because RigidBody.AddForce() adds force in absolute direction, no matter which direction the gameobject is looking.
You should try using RigidBody.AddRelativeForce(), like:
if (isGrounded)
{
rb.AddRelativeForce(movement * speed * Time.deltaTime);
}
I think there is a better way to do this, but see if it results in the expected behavior:
void FixedUpdate()
{
float moveHorizontal = Input.GetAxis("Horizontal");
float moveVertical = Input.GetAxis("Vertical");
Vector3 looking = (transform.rotation * Vector3.forward).normalized;
Vector3 perpendicular = Vector2.Perpendicular(new Vector2(looking.x, looking.z));
perpendicular.z = perpendicular.y;
perpendicular.y = looking.y;
Vector3 vertical = moveVertical * looking;
Vector3 horizontal = moveHorizontal * perpendicular;
Vector3 movement = vertical - horizontal;
...
}
So i'm having issues with a script I have, what it does is basically rotate the player graphics depending on where the mouse is aiming at. This works fine and as intended but my issue is that when I want to shoot on the opposite direction, that being the Left direction, it shoots the player instead of where it's aiming at.
I've decided to record a small video to show the problem.
https://streamable.com/02zqz
Here's the code to both the rotation and weapon script.
Rotating
public class Rotating : MonoBehaviour
{
public PlayerController player;
public float x;
public Vector3 flipArm;
void Start()
{
x = transform.localScale.x;
flipArm = transform.localScale;
player = GetComponentInParent<PlayerController>();
}
void Update()
{
Vector3 difference = Camera.main.ScreenToWorldPoint(Input.mousePosition ) - transform.position;
difference.Normalize();
float rotZ = Mathf.Atan2(difference.y, difference.x) * Mathf.Rad2Deg;
transform.rotation = Quaternion.Euler(0f, 0f, rotZ + 0);
if(difference.x >= 0)
{
transform.rotation = Quaternion.Euler(0f, 0f, rotZ);
player.armRight = true;
}
else
{
transform.rotation = Quaternion.Euler(0f, 0f, rotZ+180);
player.armRight = false;
}
}
}
Weapon
public class Weapon : MonoBehaviour
{
public float shootDelay = 0;
public float damage = 1;
public LayerMask whatToHit;
public Transform firePoint;
public GameObject bullet;
// Start is called before the first frame update
void Start()
{
firePoint = transform.Find("FirePoint");
}
// Update is called once per frame
void Update()
{
shootDelay += Time.deltaTime;
if(shootDelay >= 0.1f)
{
if(Input.GetMouseButton(0))
{
shootDelay = 0;
Shot();
}
}
}
public void Shot()
{
Vector2 mousepos = new Vector2(Camera.main.ScreenToWorldPoint(Input.mousePosition).x, Camera.main.ScreenToWorldPoint(Input.mousePosition).y);
Vector2 firepointpos = new Vector2(firePoint.position.x, firePoint.position.y);
Instantiate(bullet, firepointpos, transform.rotation);
Debug.DrawLine(firepointpos, (mousepos - firepointpos) * 100, Color.cyan);
}
}
Try this:
transform.rotation = Quaternion.LookRotation ( end - start );
Also don't forget to check where the player is facing because you don't want to shoot from back. Using the above euler angles, one side is 90 and another 270 degrees in y component.
For the entire day, I been trying to find a good solution to completely stop the player from going offscreen without hard coding.
I have this script called player controller and all it does so far is allow the player to move along the x-axis. It also has an additional function that clamps the player's movement in the x-axis. Here it is.
using UnityEngine;
public class PlayerController : MonoBehaviour
{
public const float MAX_SPEED = 5.0f;
// Update is called once per frame
void Update()
{
transform.Translate(Input.GetAxis("Horizontal") * MAX_SPEED * Time.deltaTime, 0.0f, 0.0f);
clampPlayerMovement();
}
void clampPlayerMovement()
{
Vector3 pos = Camera.main.WorldToViewportPoint(transform.position);
pos.x = Mathf.Clamp01(pos.x);
transform.position = Camera.main.ViewportToWorldPoint(pos);
}
}
The problem with this script is that it doesn't completely stops the player from going offscreen(half of the player's body still goes offscreen).
So this is what I tried next.
using UnityEngine;
public class PlayerController : MonoBehaviour
{
public const float MAX_SPEED = 5.0f;
private float xLeft;
private float xRight;
void Start()
{
float pivotX = GetComponent<SpriteRenderer>().sprite.pivot.x;
float pixelsPerunit = GetComponent<SpriteRenderer>().sprite.pixelsPerUnit;
float textureWidth = GetComponent<SpriteRenderer>().sprite.texture.width;
//Units on the left from the sprite's pivot.
xLeft = pivotX / pixelsPerunit;
//Units on the right from the sprite's pivot.
xRight = (textureWidth - pivotX) / pixelsPerunit;
}
// Update is called once per frame
void Update()
{
transform.Translate(Input.GetAxis("Horizontal") * MAX_SPEED * Time.deltaTime, 0.0f, 0.0f);
clampPlayersMovement();
}
void clampPlayersMovement()
{
Vector3 pos = transform.position;
Vector3 posMin = transform.position;
Vector3 posMax = transform.position;
posMin.x = posMin.x - xLeft;
posMax.x = posMax.x + xRight;
pos = Camera.main.WorldToViewportPoint(pos);
posMin = Camera.main.WorldToViewportPoint(posMin);
posMax = Camera.main.WorldToViewportPoint(posMax);
pos.x = Mathf.Clamp(pos.x, posMin.x, posMax.x);
transform.position = Camera.main.ViewportToWorldPoint(pos);
}
}
Unfortunately, this code is no good. In fact, it is even worse because it does not stop the player from going offscreen at all.
So at this point I'm stuck between a rock and a hard place. Any suggestions would be vastly appreciated.
After long searching I finally found an answer.
using UnityEngine;
public class PlayerController : MonoBehaviour
{
public const float MAX_SPEED = 5.0f;
private float halfPlayerSizeX;
void Start()
{
halfPlayerSizeX = GetComponent<SpriteRenderer>().bounds.size.x / 2;
}
// Update is called once per frame
void Update()
{
transform.Translate(Input.GetAxis("Horizontal") * MAX_SPEED * Time.deltaTime, 0.0f, 0.0f);
clampPlayerMovement();
}
void clampPlayerMovement()
{
Vector3 position = transform.position;
float distance = transform.position.z - Camera.main.transform.position.z;
float leftBorder = Camera.main.ViewportToWorldPoint(new Vector3(0, 0, distance)).x + halfPlayerSizeX;
float rightBorder = Camera.main.ViewportToWorldPoint(new Vector3(1, 0, distance)).x - halfPlayerSizeX;
position.x = Mathf.Clamp(position.x, leftBorder, rightBorder);
transform.position = position;
}
}
The only thing that I don't get is why do I need to subtract the z position from both the gameobject and the camera? why not the x position?
I am learning Unity Game development .. I was following https://unity3d.com/learn/tutorials/projects/survival-shooter/player-character?playlist=17144
Did everything same but,
I want the player object to rotate towards the mouse pointer. But it's not rotating towards mouse pointer..
using UnityEngine;
public class PlayerMovement : MonoBehaviour
{
Vector3 movement;
Animator anim;
Rigidbody playerRigidbody;
int floormask;
float camraylength = 100f;
float speed = 10f;
void Awake()
{
anim = GetComponent<Animator>();
floormask = LayerMask.GetMask("floor");
playerRigidbody = GetComponent<Rigidbody>();
}
void FixedUpdate()
{
float h = Input.GetAxisRaw("Horizontal");
float v = Input.GetAxisRaw("Vertical");
moving(h, v);
tunning();
animationz(h, v);
}
void moving(float h, float v)
{
movement = new Vector3(h, 0, v);
movement = movement.normalized * speed * Time.deltaTime;
playerRigidbody.MovePosition(transform.position + movement);
}
void tunning()
{
Ray camray = Camera.main.ScreenPointToRay(Input.mousePosition);
RaycastHit floorhit;
if(Physics.Raycast(camray,out floorhit, camraylength, floormask))
{
Vector3 playertomouse = floorhit.point - transform.position;
playertomouse.y = 0f;
Quaternion newrotate = Quaternion.LookRotation(playertomouse);
playerRigidbody.MoveRotation(newrotate);
}
}
void animationz(float h, float v)
{
bool walking = h != 0f || v != 0f;
anim.SetBool("IsWalking", walking);
}
}
The tunning() method is in the above code
If anything more you want then please comment. Thank you for the help...
I suggest you check several stuff to find the source of the problem:
You need to make sure you are using a Quad not a Plane and that the correct face is upwards
Make sure the layer of the quad is "floor" (it's case sensitive)
Make sure the camera is not further than the 100f of the ray you are casting
And finally add a Debug.Log() inside the if condition to check if the ray hits the floor at all.