I have a game object that moves and rotates. I want the camera to stay behind the object all the time, so when the user presses w, it will look like the gameobject moves forward.
This is my skript for the camera movement.
public Transform target;
public Vector3 offset;
public void FixedUpdate()
{
transform.position = target.TransformPoint(offset);
transform.LookAt(target);
}
But I camera is not rotating around the player fast enough, so it looks like he is moving sidewards.
This is my player movement script, but I don't see any mistake in there.
public float smoothSpeed = 0.125f;
public float forwardSpeed;
public float sideSpeed;
// Start is called before the first frame update
void Start()
{
}
void FixedUpdate()
{
if (Input.GetKey("w"))
{
Vector3 movement = transform.rotation * Vector3.forward / (100 / forwardSpeed);
transform.Translate(movement);
}
else if (Input.GetKey("s"))
{
Vector3 movement = transform.rotation * Vector3.back / (100 / sideSpeed);
transform.Translate(movement);
}
else if (Input.GetKey("a"))
{
Vector3 movement = transform.rotation * Vector3.left / (100 / sideSpeed);
transform.Translate(movement);
}
else if (Input.GetKey("d"))
{
Vector3 movement = transform.rotation * Vector3.right / (100 / sideSpeed);
transform.Translate(movement);
}
else if (Input.GetKey("e"))
{
transform.Rotate(0, 1, 0);
}
else if (Input.GetKey("q"))
{
transform.Rotate(0, -1, 0);
}
}
Thanks for your help]1
When the object moves sidewards it should move forwards.
Here are my settings in Unity:
Related
I'm creating a Mario clone and I need to keep the player's forward momentum into the jump and then onward into the landing. I can't figure out how to achieve this. Every time I land, the player has to build up momentum again. Any Idea how to fix this? I've tried several solutions to no avail. I'm thinking it has something to do with how I'm adding force and acceleration to the player when holding left or right. Not sure though any help would be much appreciated. thanks in advance.
Here's my code:
Animator animator;
Rigidbody2D rb;
bool isGrounded;
public float moveSpeed;
public Vector2 acceleration;
public float jumpHeight;
public float lowjumpMultiplier;
public Transform groundCheckM;
public Transform groundCheckL;
public Transform groundCheckR;
public float storedValue;
void Start()
{
animator = GetComponent<Animator>();
rb = GetComponent<Rigidbody2D>();
transform.eulerAngles = new Vector3(0, 0, 0);
}
private void Update()
{
if
((Physics2D.Linecast(transform.position,groundCheckM.position, 1 << LayerMask.NameToLayer("Floor/Platforms"))) || //Check if grounded
(Physics2D.Linecast(transform.position, groundCheckL.position, 1 << LayerMask.NameToLayer("Floor/Platforms"))) ||
(Physics2D.Linecast(transform.position, groundCheckR.position, 1 << LayerMask.NameToLayer("Floor/Platforms"))))
{
isGrounded = true;
animator.SetBool("Jump", false);
}
else
{
isGrounded = false;
}
animator.SetFloat("Walk", rb.velocity.x); //Set animation float to x velocity
if (rb.velocity.x <= 0.03f && rb.velocity.x >= -0.03f && isGrounded) //Play "Idle" animation
{
animator.Play("Mario_Idle");
}
if (rb.velocity.x >=4 || rb.velocity.x <=-4)
{
animator.speed = Mathf.Abs(rb.velocity.x / 5.5f); //Increase speed of walking animation with player's walking speed
}
}
void FixedUpdate()
{
if (Input.GetKey("d") || Input.GetKey("right")) //Move player to the right
{
rb.AddForce(acceleration * rb.mass);
transform.rotation = Quaternion.Euler (0, 0, 0);
}
else if (Input.GetKey("a") || Input.GetKey("left")) //Move player to the left
{
rb.AddForce(-acceleration * rb.mass);
transform.rotation = Quaternion.Euler(0, 180, 0);
}
if (rb.velocity.x >= 10)
{
rb.velocity = new Vector2(10, rb.velocity.y); //Cap player speed at 10 when moving right
}
else if (rb.velocity.x <= -10)
{
rb.velocity = new Vector2(-10, rb.velocity.y); //Cap player speed at 10 when moving left
}
if (Input.GetKey("space") && isGrounded) //Player jump
{
rb.velocity += new Vector2(rb.velocity.x, jumpHeight);
animator.SetBool("Jump", true);
}
}
}
I feel dumb but the answer was in the physics material. Once I lowered the friction, it allowed momentum from the jump to carry into the player's run speed. I guess it's a good reminder to tinker directly inside Unity and its built in physics system.
If you want to keep your momentum when jumping, you could store it in a variable that will increase until it reaches the max, or you let go of the key.
float acceleration;
float accelFactor = 0.6f;
float deAccelFactor = 1f;
bool jumping; //you should set it to true when jumping and false, when not.
Rigidbody2D rb;
void Start(){
rb = GetComponent<Rigidbody2D>();
}
void Update(){
if (Input.GetKeyDown(KeyCode.D))
{
Accelerate();
rb.AddForce(acceleration * rb.Mass);
}
else if (jumping)
{
rb.AddForce(acceleration * rb.Mass);
}
else
{
DeAccel();
}
}
void Accelerate(){
acceleration += accelFactor * Time.deltaTime;
acceleration = Mathf.Clamp(acceleration, 0, maxAccel);
}
void DeAccel(){
acceleration -= deAccelFactor * Time.deltaTime;
acceleration = Mathf.Clamp(acceleration, 0, maxAccel);
}
This is what I would recommend using, that is, if I understand what you mean.
So I'm currently learning Unity 3D but I stuck on a problem.
So Iv'e done this code that the player moves with WASD keys. The movement works fine.
I tried to aply some rotation, that way the player can turn back or move to different positions.
But the problem is, I put the rotarion and the player turns but when he does he swap W for S, so basically if I turn back, when I press W to go forward he go backward and when I press S instead of going Backward he goes Forward.
I don't to make a lot of changes in my code because I think it's very "basic" right now and easy to understand. So if someone can explain what I'm doing wrong I would appreciate.
using System.Collections.Generic;
using UnityEngine;
//[RequireComponent(typeof(Rigidbody))]
public class PlayerMov : MonoBehaviour
{
//Player mov speed
float MovSpeed = 10f;
//Player jump, jumpforce, check if is on the ground and rb(rigidbody component)
public Vector3 jump;
public float jumpForce = 2.0f;
public bool isGrounded;
Rigidbody rb;
public float TurnSpeed = 100f;
void Start()
{
rb = GetComponent<Rigidbody>();
jump = new Vector3(0.0f, 2.0f, 0.0f);
}
void OnCollisionStay()
{
isGrounded = true;
}
void Update()
{
if (Input.GetKey(KeyCode.W))
{
transform.position -= Vector3.forward * MovSpeed * Time.deltaTime;
//transform.Translate(Vector3.forward * MovSpeed * Time.deltaTime);
}
if (Input.GetKey(KeyCode.A))
{
transform.position -= Vector3.left * MovSpeed * Time.deltaTime;
}
if (Input.GetKey(KeyCode.S))
{
transform.position -= Vector3.back * MovSpeed * Time.deltaTime;
//transform.Translate(-Vector3.forward * MovSpeed * Time.deltaTime);
}
if (Input.GetKey(KeyCode.D))
{
transform.position -= Vector3.right * MovSpeed * Time.deltaTime;
transform.Rotate(Vector3.up * TurnSpeed * Time.deltaTime);
}
if (Input.GetKeyDown(KeyCode.Space) && isGrounded)
{
rb.AddForce(jump * jumpForce, ForceMode.Impulse);
isGrounded = false;
}
if (Input.GetKey(KeyCode.LeftArrow))
{
transform.Rotate(Vector3.up * TurnSpeed * Time.deltaTime);
}
if (Input.GetKey(KeyCode.RightArrow))
{
transform.Rotate(Vector3.up * TurnSpeed * Time.deltaTime);
}
Why not use the Translate method? Please see its documentation. You can define a which space you want the transform to move in (global or local)
https://docs.unity3d.com/ScriptReference/Transform.Translate.html
As a side note: why check for each separate key? Using Input.GetAxis("Horizontal") and Input.GetAxis("Horizontal") vertical would be simpler.
I am having trouble with aligning my player controlled camera (I use the same class for FPS and TPS) to look at a target (when ResetCamera() is called by another script) and then getting the player to resume control. The main reason I am doing this is so I can switch between FPS and TPS cameras and remain looking at the same target.
I can look at the target fine, but ONLY if I stop setting the rotation based on yaw and pitch (from "Mouse X" and "Mouse Y" inputs) in LateUpdate() after I set the lookAtTarget in ResetCamera(), but that means the player can no longer look around.
However, I cannot figure out how to get the correct yaw and pitch values after this so the player can continue looking around from the new look at target. How could I do this so the player could continue looking around?
public class PlayerCamera : MonoBehaviour {
public float mouseSensitivity = 10f;
public Transform target;
public float dstFromTarget = 2f;
public Vector2 pitchConstraints = new Vector2(-20f, 85f);
public float rotSmoothTime = .12f;
Vector3 rotSmoothVel;
Vector3 currRot;
float yaw;
float pitch;
void LateUpdate() {
yaw += Input.GetAxis("Mouse X") * mouseSensitivity;
pitch -= Input.GetAxis("Mouse Y") * mouseSensitivity;
pitch = Mathf.Clamp(pitch, pitchConstraints.x, pitchConstraints.y);
currRot = Vector3.SmoothDamp(currRot, new Vector3(pitch, yaw), ref rotSmoothVel, rotSmoothTime);
transform.eulerAngles = currRot;
transform.position = target.position - transform.forward * dstFromTarget;
}
public void ResetCamera(Transform lookAtTarget) {
transform.LookAt(lookAtTarget);
// below gets yaw and pitch values that move the camera to look at the
// wrong location
// yaw = transform.eulerAngles.x;
// pitch = transform.eulerAngles.y;
// pitch = Mathf.Clamp(pitch, pitchConstraints.x, pitchConstraints.y);
// currRot = new Vector3(pitch, yaw);
}
}
So, I figured out how to do what I wanted. Below is a script for a third or first person (just adjust the dstFromTarget variable to zero) camera that can be rotated to look at a target by another script with ResetCamera() and the player can resume moving around from that point.
public class PlayerCamera : MonoBehaviour {
public bool isFirstPerson = false;
public float mouseSensitivity = 10f;
public Transform target;
public float dstFromTarget = 2f;
public bool invertedPitch = false;
public float smoothTime = .12f;
public float minimumX = -85f;
public float maximumX = 85f;
// LateUpdate, so the Camera Target will definitely have been set
void LateUpdate () {
// first person updating is handled by Inverse kinematics stuff in my case
if (isFirstPerson) return;
UpdateStuff();
}
public void UpdateStuff() {
float yaw = Input.GetAxisRaw("Mouse X");
float pitch = -Input.GetAxisRaw("Mouse Y");
if (invertedPitch) {
pitch *= -1f;
}
Vector3 yRot = new Vector3(0f, yaw, 0f) * mouseSensitivity;
Vector3 xRot = new Vector3(pitch, 0f, 0f) * mouseSensitivity;
xRot = ClampRotationAroundXAxis(transform.rotation, xRot);
Transform newTrans = transform;
newTrans.Rotate(xRot);
newTrans.Rotate(yRot, Space.World);
transform.rotation = Quaternion.Slerp(transform.rotation, newTrans.rotation, smoothTime * Time.deltaTime);
transform.position = target.position - transform.forward * dstFromTarget;
}
public void ResetCamera(Transform lookAtTarget) {
transform.LookAt(lookAtTarget);
}
Vector3 ClampRotationAroundXAxis(Quaternion q, Vector3 xrot) {
q.x /= q.w;
q.y /= q.w;
q.z /= q.w;
q.w = 1.0f;
float angleX = 2.0f * Mathf.Rad2Deg * Mathf.Atan (q.x);
if (angleX < minimumX && xrot.x < 0f) {
xrot = Vector3.zero;
}
if (angleX > maximumX && xrot.x > 0f) {
xrot = Vector3.zero;
}
return xrot;
}
}
I am trying click on a GameObject and move it at the same rate as the mouse. I am able to get the Object to move, but I have to do some crazy modifications in order for it to not vanish off the screen.
Note: My ultimate goal will be to do this for mobile, but am starting with the mouse.
public class ItemController : MonoBehaviour {
private Vector3 startPos;
private bool ObjectMouseDown = false;
void Update()
{
Debug.Log(Input.mousePosition + new Vector3(0,0,15));
}
void OnMouseDown()
{
startPos = transform.position;
ObjectMouseDown = true;
}
void OnMouseDrag()
{
if (ObjectMouseDown == true)
{
transform.position = Vector3.MoveTowards(transform.position, Input.mousePosition + new Vector3(0, 0, 5), Time.deltaTime * 2f);
// transform.position = Vector3.MoveTowards(transform.position, endPosition, speed * Time.deltaTime);
}
}
void OnMouseUp()
{
ObjectMouseDown = false;
}
}
Notice how I have to add a z-value of 15, so that the object doesn't float up out of the screen.
Any help would be awesome.
Input.mousePosition return the absolute pixel position on the screen and not world position. You need to use Camera.ScreenToWorldPoint something like this
Vector3 mouseWorldPos = Camera.main.ScreenToWorldPoint(Input.position.x, Input.position.y, 15);
transform.position = mouseWorldPos;
You can read more here https://docs.unity3d.com/ScriptReference/Camera.ScreenToWorldPoint.html
I add a CharacterController to Player.But when I test the jump function,I find that the Player will move upwards immediately.
if (Player.isGrounded)
{
if (jump)
{
Move.y = JumpSpeed;
jump = false;
Player.Move (Move * Time.deltaTime);
}
}
Move += Physics.gravity * Time.deltaTime * 4f;
Player.Move (Move * Time.fixedDeltaTime);`
You are calling Player.Move() twice in one frame. This might be an issue.
You are adding gravity to Move vector, which means it will always go upward when you call this code.
naming a variable like Move is not a good convention. It creates confusion while reading because there is already a method of same name. change it to moveDirection.
Here is sample code:
public class ExampleClass : MonoBehaviour {
public float speed = 6.0F;
public float jumpSpeed = 8.0F;
public float gravity = 20.0F;
private Vector3 moveDirection = Vector3.zero;
CharacterController controller;
void Start()
{
controller = GetComponent<CharacterController>();
}
void Update() {
if (controller.isGrounded) {
moveDirection = new Vector3(Input.GetAxis("Horizontal"), 0, Input.GetAxis("Vertical"));
moveDirection = transform.TransformDirection(moveDirection);
moveDirection *= speed;
if (Input.GetButton("Jump"))
moveDirection.y = jumpSpeed;
}
moveDirection.y -= gravity * Time.deltaTime;
controller.Move(moveDirection * Time.deltaTime);
}
}
hope this helps.