Unity - How can I fix this code so it works without transform.position = newPosition? - c#

so my character has to walk around a tower, simple
but me being stupid can only work it out by using transform.position in update so jumping and collisions ofc, dont work
here is the tower concept ( see image )
Tower
here is how it works rn (see video: https://streamable.com/7tmq1l)
You will see in the clip how bad it breaks if i comment the transform.position = newposition to allow for jumping
Here is my code I used:
public class Movement : MonoBehaviour
{
[SerializeField] private float radius = 7;
[SerializeField] private float angleSpeed = 28;
[SerializeField] private float jumpForce = 5;
private float angle;
Rigidbody rb;
private void Start()
{
rb = GetComponent<Rigidbody>();
}
void Update()
{
transform.rotation = Quaternion.Euler(0, angle, 0);
float horizontalInput = Input.GetAxis("Horizontal");
angle -= horizontalInput * angleSpeed * Time.deltaTime;
Vector3 newPosition = Quaternion.Euler(0, angle, 0) * new Vector3(0, 0, radius);
transform.position = newPosition;
//jump
if(Input.GetKeyDown(KeyCode.Space)|| Input.GetKeyDown(KeyCode.W))
{
Debug.Log("Jumping!");
rb.AddForce(Vector3.up * jumpForce, ForceMode.Impulse);
}
}
Ofc the jumping doesnt work because of this

adjust the XZ position using the rigidBody and let the rb adjust the Y axis.
Vector3 newPosition = Quaternion.Euler(0, angle, 0) * radius;
newPosition.Y = rb.position.Y; // leave Y unchanged to allow for jumps
rb.position = newPosition;

Related

How to Rotate 2D Sprite Towards Moving Direction?

I have been searching all day and reading forums but I can't find a way that works. I'm making a top-down view horror game. When my player walks normally he can look around with the cursor in any direction, but when he wants to run he switches to "tank" controls and rotates toward the running direction. I need something like this.
My player movement script so far:
public float walkSpeed;
public float runSpeed;
public float turnSpeed;
private Rigidbody2D rb;
public Camera cam;
private Vector2 moveDirection;
void Start()
{
rb = GetComponent<Rigidbody2D>();
}
void Update()
{
ProcessInput();
}
void FixedUpdate()
{
Move();
}
private void ProcessInput()
{
float moveX = Input.GetAxisRaw("Horizontal");
float moveY = Input.GetAxisRaw("Vertical");
moveDirection = new Vector2(moveX, moveY).normalized;
}
void Move()
{
if (Input.GetKey(KeyCode.LeftShift))
{
//Looking toward movement direction should be applied here
} else {
rb.velocity = new Vector2(moveDirection.x * walkSpeed, moveDirection.y * walkSpeed);
Vector3 mousePosition = cam.ScreenToWorldPoint(Input.mousePosition);
Vector2 direction = mousePosition - transform.position;
float angle = Vector2.SignedAngle(Vector2.right, direction) - 90f;
Vector3 targetRotation = new Vector3(0, 0, angle);
transform.rotation = Quaternion.RotateTowards(transform.rotation, Quaternion.Euler(targetRotation), turnSpeed * Time.deltaTime);
}
}
Any help is greatly appreciated! Thanks in advance!
This problem can be solved by substituting moveDirection instead of the mouse look direction, here it is enough to define a hypothetical variable called direction to detect the correct direction in each of these conditions.
var direction = new Vector2();
var currentSpeed = walkSpeed;
if (Input.GetKey(KeyCode.LeftShift))
{
direction = moveDirection;
currentSpeed = runSpeed;
} else {
direction = cam.ScreenToWorldPoint(Input.mousePosition) - transform.position;
}
var angle = Vector2.SignedAngle(Vector2.right, direction) - 90f;
var targetRotation = new Vector3(0, 0, angle);
var lookTo = Quaternion.Euler(targetRotation);
rb.velocity = new Vector2(moveDirection.x, moveDirection.y) * runSpeed *Time.deltaTime;
transform.rotation = Quaternion.RotateTowards(transform.rotation, lookTo , turnSpeed * Time.deltaTime);

Navmesh Agent rotate with mouse

I would like to rotate my NavigationMeshAgent with reference to the mouse position. Following is my code to do so.
public class Navcontroller : MonoBehaviour
{
// Start is called before the first frame update
private NavMeshAgent _agent;
void Start()
{
_agent = GetComponent<NavMeshAgent>();
}
// Update is called once per frame
void Update()
{
float horInput = Input.GetAxis("Horizontal");
float verInput = Input.GetAxis("Vertical");
Vector3 movement = new Vector3(horInput, 0f, verInput);
Vector3 moveDestination = transform.position + movement;
_agent.destination = moveDestination;
}
}
Unforutnately , the rotation is weird and it can look all over the place as I move the mouse. what am I missing?
UPDATE:
I have updated my code with the mouse position as follows,
public class Navcontroller : MonoBehaviour
{
// Start is called before the first frame update
private NavMeshAgent _agent;
float mouseX, mouseY;
float rotationSpeed = 1;
void Start()
{
_agent = GetComponent<NavMeshAgent>();
Cursor.visible = false;
Cursor.lockState = CursorLockMode.Locked;
}
// Update is called once per frame
void Update()
{
float horInput = Input.GetAxis("Horizontal");
float verInput = Input.GetAxis("Vertical");
Vector3 movement = new Vector3(horInput, 0f, verInput);
Vector3 moveDestination = transform.position + movement ;
mouseX += Input.GetAxis("Mouse X") * rotationSpeed;
mouseY -= Input.GetAxis("Mouse Y") * rotationSpeed;
_agent.destination = moveDestination;
_agent.transform.rotation = Quaternion.Euler(mouseY, mouseX, 0);
}
}
Now that the agent rotates with the camera. But the agent is not moving in the same direction where he is looking at.
Based on the comment
Vector3 mousePosition = Input.mousePosition; // Get mouse position
mousePosition = Camera.main.ScreenToWorldPoint(mousePosition); //Transfom it to game space - form screen space
Vector2 direction = new Vector2(
mousePosition.x - transform.position.x,
mousePosition.y - transform.position.y
); // create new direction
transform.up = direction; // Rotate Z axis
Because based on the comment this has nothing to do with NavigationMeshAgent or AI. Then to move forward you do
if(Input.GetKey(Key.W)){
transform.forward += Speed * Time.deltaTime;
}
EDIT
Your _agent.destination = moveDestination; needs to match your rotation so you need to multiply it by the rotation. _agent.destination = Quaternion.Euler(mouseY, mouseX, 0) * moveDestination where moveDestination should be relative to its rotation (not absolute as you probably have now) so better use _agent.destination = Quaternion.Euler(mouseY, mouseX, 0) * Vector3.forward

When I hit play, my Sprite character rotates. Why?

I am making a top down game on Unity, so I am using the x and z axis as my plane. I have my character rotated x 90, y 0, z 0 so that it is flat on the plane. As soon as I hit play the character is rotated vertical?! I think it has something to do with my script to face the mouse position.
What it should look like:
When I hit play:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerMovement : MonoBehaviour
{
public static float moveSpeed = 10f;
private Rigidbody rb;
private Vector3 moveInput;
private Vector3 moveVelocity;
// Update is called once per frame
void Start()
{
rb = GetComponent<Rigidbody>();
mainCamera = FindObjectOfType<Camera>();
}
void Update()
{
// Setting up movement along x and z axis. (Top Down Shooter)
moveInput = new Vector3(Input.GetAxis("Horizontal"), 0f, Input.GetAxis("Vertical"));
moveVelocity = moveInput * moveSpeed;
//Make character look at mouse.
var dir = Input.mousePosition - Camera.main.WorldToScreenPoint(transform.position);
var angle = Mathf.Atan2(dir.y, dir.x) * Mathf.Rad2Deg;
transform.rotation = Quaternion.AngleAxis(angle, Vector3.up);
}
void FixedUpdate()
{
// Allows character to move.
rb.velocity = moveVelocity;
}
}
Figured it out: I am answering my own question to help others.
Vector3 difference = Input.mousePosition - Camera.main.WorldToScreenPoint(transform.position);
float rotZ = Mathf.Atan2(difference.y, difference.x) * Mathf.Rad2Deg;
transform.rotation = Quaternion.Euler(90f, 0f, rotZ -90);
This does EXACTLY what I wanted!

Rotating Rigidbody controller

There is my script Rigidbody controller -
public float Speed = 5f;
public float JumpHeight = 2f;
public float GroundDistance = 0.2f;
public float DashDistance = 5f;
public LayerMask Ground;
private Rigidbody _body;
private Vector3 _inputs = Vector3.zero;
private bool _isGrounded = true;
private Transform _groundChecker;
void Start()
{
_body = GetComponent<Rigidbody>();
_groundChecker = transform.GetChild(0);
}
void Update()
{
_isGrounded = Physics.CheckSphere(_groundChecker.position, GroundDistance, Ground, QueryTriggerInteraction.Ignore);
_inputs = Vector3.zero;
_inputs.x = Input.GetAxis("Horizontal");
_inputs.z = Input.GetAxis("Vertical");
if (_inputs != Vector3.zero)
transform.forward = _inputs;
if (Input.GetButtonDown("Jump") && _isGrounded)
{
_body.AddForce(Vector3.up * Mathf.Sqrt(JumpHeight * -2f * Physics.gravity.y), ForceMode.VelocityChange);
}
if (Input.GetButtonDown("Sprint"))
{
Vector3 dashVelocity = Vector3.Scale(transform.forward, DashDistance * new Vector3((Mathf.Log(1f / (Time.deltaTime * _body.drag + 1)) / -Time.deltaTime), 0, (Mathf.Log(1f / (Time.deltaTime * _body.drag + 1)) / -Time.deltaTime)));
_body.AddForce(dashVelocity, ForceMode.VelocityChange);
}
}
void FixedUpdate()
{
_body.MovePosition(_body.position + _inputs * Speed * Time.fixedDeltaTime);
}
What the best way to make a turn on y in the direction of the camera ? That is,the player turns to the side where the mouse is turned? Is it in fixedUpdate or update?
This is the camera script:
public float Smoothness = 0.3F;
public Vector2 Sensitivity = new Vector2(4, 4);
public Vector2 LimitX = new Vector2(-70, 80);
private Vector2 NewCoord;
public Vector2 CurrentCoord;
private Vector2 vel;
public GameManager GameMangerS;
public Transform Target;
public float TransformSpeed;
public Animator CameraAnimator;
void Update()
{
NewCoord.x = Mathf.Clamp(NewCoord.x, LimitX.x, LimitX.y);
NewCoord.x -= Input.GetAxis("Mouse Y") * Sensitivity.x;
NewCoord.y += Input.GetAxis("Mouse X") * Sensitivity.y;
CurrentCoord.x = Mathf.SmoothDamp(CurrentCoord.x, NewCoord.x, ref vel.x, Smoothness / 2);
CurrentCoord.y = Mathf.SmoothDamp(CurrentCoord.y, NewCoord.y, ref vel.y, Smoothness / 2);
transform.rotation = Quaternion.Euler(CurrentCoord.x, CurrentCoord.y, 0);
}
And added this line to the controller script -
void FixedUpdate()
{
_body.MovePosition(_body.position + _inputs * Speed * Time.fixedDeltaTime);
transform.rotation = Quaternion.Euler(0, MainCamera.CurrentCoord.y, 0);
}
When I'm standing the player normally rotates, but when I start to move, all rotations are reset and the player is not moving.
Update
Simple Rotation can be achieved using transform.Rotate().
Example:
this.transform.Rotate(Vector3.up, 30);
This example is gonna rotate the transform by 30° around the Vector that points upwards.
LookAtMouse:
To make your object turn towards the mouse, you need the ScreenToWorldSpace() method from your camera. In order to convert the ScreenCoordinates into your WorldCoordinates.
Example:
Please note:
You have to set the camera instance! If you don't add that, you'll get a NullReferenceException.
This Snippets shall only show the steps needed to achieve the behavior you wish.
You will have to find out yourself how to integrate that lines of code into your code to make it work. Consider what Programmer told you in the comment when integrating that.
Vector3 mousePosition = Input.mousePosition; //get the screenSpaceMousePosition
Vector3 worldPosition = this.camera.ScreenToWorldPoint(mousePosition); //convert it into worldSpacePosition
Vector3 calculatedDirection = worldPosition - transform.position; //calucate the looking direction
calculatedDirection.y = 0;
Quaternion rotation = Quaternion.LookRotation(calculatedDirection);
transform.rotation = Quaternion.Slerp(transform.rotation, rotation, Time.deltaTime);

How can i rotate a spaceship back to it's original rotation to face the original position?

The spaceship start moving from point A. The spaceship is facing the moving direction.
Now when i click one on the L key i want that the spaceship will rotate and will face to the original position it was start moving from. But even if the spaceship is now rotated by axis Z or Y or X to rotate it first to the regular rotation values and to face to the start moving position.
using UnityEngine;
using System.Collections;
public class Control : MonoBehaviour
{
public int rotationSpeed = 75;
public int movementspeed = 10;
public int thrust = 10;
private bool isPKeyDown = false;
private float acceleration = .0f;
private Vector3 previousPosition = Vector3.zero;
private Rigidbody _rigidbody;
private Vector3 originalPosition;
private Quaternion originalRotation;
// Use this for initialization
void Start()
{
originalPosition = transform.position;
originalRotation = transform.rotation;
_rigidbody = GetComponent<Rigidbody>();
Debug.Log("Acc Speed: " + thrust);
}
// Update is called once per frame
void Update()
{
var v3 = new Vector3(Input.GetAxis("Vertical"), Input.GetAxis("Horizontal"), 0.0f);
transform.Rotate(v3 * rotationSpeed * Time.deltaTime);
transform.position += transform.forward * Time.deltaTime * movementspeed;
if (Input.GetKey(KeyCode.Z))
transform.Rotate(Vector3.forward * rotationSpeed * Time.deltaTime);
if (Input.GetKey("p"))
{
isPKeyDown = Input.GetKey("p");
float distance = Vector3.Distance(previousPosition, transform.position);
acceleration = distance / Mathf.Pow(Time.deltaTime, 2);
previousPosition = transform.position;
_rigidbody.AddRelativeForce(0f, 0f, thrust, ForceMode.Acceleration);
}
if (Input.GetKey("l"))
{
transform.rotation = Quaternion.Slerp(transform.rotation, originalRotation, 0);
//StartCoroutine(TurnShip(transform, transform., originalRotation.eulerAngles, 1));
//transform.position += transform.forward * Time.deltaTime * movementspeed;
}
}
IEnumerator TurnShip(Transform ship, Vector3 startAngle, Vector3 endAngle, float smooth)
{
float lerpSpeed = 0;
while (lerpSpeed < 1)
{
ship.eulerAngles = Vector3.Lerp(startAngle, endAngle, lerpSpeed);
lerpSpeed += Time.deltaTime * smooth;
yield return null;
}
}
void OnGUI()
{
if (isPKeyDown)
{
GUI.Label(new Rect(100, 100, 200, 200), "Acc Speed: " + acceleration);
}
}
}
This is where i click the L button but i tried some things but can't yet find how to do it.
The main goal is if i click once on L the spaceship should automatic rotate if needed and move back to the original position and then land on ground. L stand for landing that's the main goal.
Add a variable on top -
...
private Vector3 originalPosition;
private Quaternion originalRotation;
private bool landShip = false;
...
And use following code in update function -
if (Input.GetKey("l"))
{
landShip = true;
//StartCoroutine(TurnShip(transform, transform., originalRotation.eulerAngles, 1));
//transform.position += transform.forward * Time.deltaTime * movementspeed;
}
if(landShip){
transform.rotation = Quaternion.Slerp(transform.rotation, originalRotation, 0.5f);
}
Once the spaceship lands, set the landShip value back to false.

Categories