Unity BoxCollider2D rotation not the same as GameObject rotation - unity3d

I'm having a bit of an issue with a BoxCollider2D I have on my GameObject. When I rotate the GameObject, the BoxCollider2D rotates with it, but not as fast. Is there a way to get the BoxCollider2D to move at the same rate as the GameObject? I feel like I'm missing something obvious.
Before Rotation
After Rotation
Below is my code for the movement of the player:
Animator anim;
Rigidbody2D rbody;
float speed = 0f;
public float moveSpeed = 0.6f;
public float acceleration = 0.2f;
public int turnSpeed = 20;
bool sails = false;
// Use this for initialization
void Start () {
anim = GetComponentInChildren<Animator> ();
rbody = GetComponent<Rigidbody2D> ();
}
// Update is called once per frame
void Update () {
if (sails) {
rbody.transform.Translate (transform.right * (speed * Time.deltaTime));
speed += acceleration * Time.deltaTime;
if (speed > moveSpeed)
speed = moveSpeed;
if (Input.GetKey (KeyCode.LeftArrow)) {
rbody.transform.Rotate (0,0,turnSpeed * Time.deltaTime);
}
if (Input.GetKey (KeyCode.RightArrow)) {
rbody.transform.Rotate (0,0,-turnSpeed * Time.deltaTime);
}
}
if (!sails) {
rbody.transform.Translate (transform.right * (speed * Time.deltaTime));
speed += -acceleration * Time.deltaTime;
if (speed < 0f)
speed = 0f;
}
if (Input.GetKeyDown (KeyCode.Space)) {
sails = !sails;
anim.SetBool ("sailsDown", sails);
}
}

The problem is not your rotation, but how you are applying the the movement.
You are using transform.right which is the local right of the object. But then, when applying the translate you apply it to the object locally too.
For example, if your ship is facing down (rotation.Z = -90), transform.right value is (0,-1,0), in World coordinates this is equal to "down".
But then you use rbody.transform.Translate(vector) which will translate the object using local coordinates. This means that if you pass it the "down" vector, it will be moving down locally, which in the case of being rotated -90 inthe Z axis, means moving "left" relative to the world.
You have to change this line:
rbody.transform.Translate(transform.right * (speed * Time.deltaTime));
To:
rbody.transform.Translate(transform.right * (speed * Time.deltaTime),Space.World);
Or:
rbody.transform.Translate(Vector2.right * (speed * Time.deltaTime));

Related

How can I get this jumping and movement code to work together?

I'm trying to use the Character Controller component in Unity and I managed to make the movement code, however, I was unable to add jumping and gravity or at least have them work together so my temporary solution was to just break them into 2 different methods. This probably isn't ideal so how could I get this to work properly?
void Update()
{
GetInput();
JumpingCode();
MovementCode();
}
void JumpingCode()
{
// Jumping
if (jumpPressed && characterController.isGrounded)
velocityY = Mathf.Sqrt(jumpHeight * -2f * (gravity * gravityScale));
// Gravity
velocityY += gravity * gravityScale * Time.deltaTime;
Vector3 direction = new Vector3(horizontalInput, velocityY, verticalInput).normalized;
characterController.Move(direction * walkSpeed * Time.deltaTime);
}
void MovementCode()
{
Vector3 direction = new Vector3(horizontalInput, 0f, verticalInput).normalized;
if (direction.magnitude > 0.1f)
{
float targetAngle = Mathf.Atan2(direction.x, direction.z) * Mathf.Rad2Deg + playerCamera.eulerAngles.y;
float angle = Mathf.SmoothDampAngle(transform.eulerAngles.y, targetAngle, ref turnSmoothVelocity, turnSmoothTime);
Vector3 moveDirection = Quaternion.Euler(0f, targetAngle, 0f) * Vector3.forward;
transform.rotation = Quaternion.Euler(0f, angle, 0f);
characterController.Move(moveDirection.normalized * walkSpeed * Time.deltaTime);
}
}
I can't understand how you're arriving at the values you're using there, but the solution would be to accumulate the outputs and then do the .Move() action once at the end, like:
void Update()
{
Vector3 motion;
GetInput();
motion += JumpingCode();
motion += MovementCode();
characterController.Move(motion*Time.deltaTime);
}
private Vector3 JumpingCode()
{
// stuff
return direction * walkSpeed;
}
private Vector3 MovementCode()
{
// stuff
return direction * walkSpeed;
}
Noteworthy there is that I dropped Time.deltaTime from your functions, but I don't know how you were using it in the code you provided.

Player Sprinting with LeftShift in Unity

My Project is a First Person Jump&Run, I want my Player to Sprint by pressing Horizonzal or Vertical combined with Shift.
I already made a new Input, called Sprint, with negative Button "left shift"
My Player does normal move, but he doesn't Sprint.
Thanks a lot.
public class PlayerMovement : MonoBehaviour
{
public CharacterController controller;
public float speed = 12f;
public float sprint;
public float gravity = -9.81f;
public float jumpHeight = 3f;
public Transform groundCheck;
public float groundDistance = 0.4f;
public LayerMask groundMask;
Vector3 velocity;
bool isGrounded;
// Update is called once per frame
void Update()
{
isGrounded = Physics.CheckSphere(groundCheck.position, groundDistance, groundMask);
if(isGrounded && velocity.y < 0) {
velocity.y = -2f;
}
float x = Input.GetAxis("Horizontal");
float z = Input.GetAxis("Vertical");
Vector3 move = transform.right * x + transform.forward * z;
controller.Move(move * speed * Time.deltaTime);
if (Input.GetButtonDown("Jump") && isGrounded)
{
velocity.y = Mathf.Sqrt(jumpHeight * -2f * gravity);
}
velocity.y += gravity * Time.deltaTime;
controller.Move(velocity * Time.deltaTime);
// Noch nicht fertig -> Noch ausstehend
if (Input.GetButtonDown("Horizontal") && Input.GetButtonDown("Sprint") || Input.GetButtonDown("Vertical") && Input.GetButtonDown("Sprint"))
{
controller.Move(move * (speed + sprint) * Time.deltaTime);
}
}
There are most likely problems with how the Input is being handled.
My assumption is that GetButtonDown only returns true for the single frame when you press shift down. Use GetKey instead:
Input.GetKey(KeyCode.LeftShift)
If that doesn't work, try those 2 instead:
Input.GetKeyDown("left shift")
Input.GetKeyDown(KeyCode.LeftShift)
But there might be the same problem with those 2 as with "GetButtonDown".
Also, I think it'd help people understand your code better if you use english comments instead of german. I'm able to read it but most probably don't. Don't worry though, that also happened to me!

Delay when calculating a players movement direction

I am trying to determine the direction of a transform. I originally tried to do this by tracking the rigidbody.velocity but that property seems unreliable so I am having to calculate the direction manually. The yellow line draws fine and it does point in the wrong direction however it appears to be delayed
I am calling the following method in my update method:
void DetermineMovementDirection()
{
currentLoc = (transform.position - prevLoc) / Time.deltaTime;
Vector3 t = (prevLoc + currentLoc).normalized;
Debug.DrawLine(transform.position, transform.position + t * 5, Color.yellow);
}
I would expect the yellow line to always point in the direction the player was moving rather than have a long delay. How can I fix this?
As requested the movement function:
void Update()
{
float inputZ = Input.GetAxis("Horizontal");
float inputX = Input.GetAxis("Vertical");
if (movementAllowed)
if (inputZ != 0 || inputX != 0)
{
transform.eulerAngles = new Vector3(0, Mathf.Atan2(inputZ, inputX) * 180 / Mathf.PI, 0);
transform.Translate(moveSpeed * inputZ * Time.deltaTime, 0f, moveSpeed * inputX * Time.deltaTime, Space.World);
}
}
And I am simply updating at the end of the update method:
prevLoc = transform.position;

Moving camera around an object in Unity

Previous posts here did not seem to address my problem.
I'm trying to get my camera to move around a specific point called "target". Target is an empty gameobject set at the center of my game. The idea is that the camera would not move any closer to or farther from target and would simply rotate around the target as though it were moving around an invisible sphere. The camera should always point at target. transform.LookAt(target) does just fine keeping the camera trained on the target, but I cant get the movement correct. Whether I'm moving along the horizontal or vertical axes, it always spirals directly into the target rather than just moving around it. Any ideas?
public class CameraController : MonoBehaviour {
public float speed;
public Transform target;
void Update () {
transform.LookAt(target);
if(Input.GetAxis("Vertical") != 0)
{
transform.Translate(transform.up * Input.GetAxis("Vertical") * Time.deltaTime * speed); //.up = positive y
}
if(Input.GetAxis("Horizontal") != 0)
{
transform.Translate(transform.right * Input.GetAxis("Horizontal") * Time.deltaTime * speed); //.right = positive x
}
}
}
To rotate around a specific point I use Transform.RotateAround:
transform.RotateAround(target.position, transform.right, -Input.GetAxis("Mouse Y") * speed);
transform.RotateAround(target.position, transform.up, -Input.GetAxis("Mouse X") * speed);
Or, if your target moves and you want to keep the same distance between the camera and your target, you can use this piece of code from my answers.unity3d.com page :
public class SphericalCam
: MonoBehaviour
{
public float MinDist, CurrentDist, MaxDist, TranslateSpeed, AngleH, AngleV;
public Transform Target;
public void Update()
{
AngleH += Input.GetAxis("Mouse X");
AngleV -= Input.GetAxis("Mouse Y");
CurrentDist += Input.GetAxis("Mouse ScrollWheel");
}
public void LateUpdate()
{
Vector3 tmp;
tmp.x = (Mathf.Cos(AngleH * (Mathf.PI / 180)) * Mathf.Sin(AngleV * (Mathf.PI / 180)) * CurrentDist + Target.position.x;
tmp.z = (Mathf.Sin(AngleH * (Mathf.PI / 180)) * Mathf.Sin(AngleV * (Mathf.PI / 180)) * CurrentDist + Target.position.z;
tmp.y = Mathf.Sin(AngleV * (Mathf.PI / 180)) * CurrentDist + Target.position.y;
transform.position = Vector3.Slerp(transform.position, tmp, TranslateSpeed * Time.deltaTime);
transform.LookAt(Target);
}
}
Camera rotation around target horizontally:
transform.RotateAround(target.position, target.forward, Time.deltaTime * speed);
Vertically:
transform.RotateAround(target.position, target.right, Time.deltaTime * speed);

How to prevent tilting over in a unity object

I've got a hover tank and I'm working on a controller for it. The goal is to have the float above the ground, but I don't want it to tilt over more the a degree or two. I want it to basically stay level all the time.
I'm using a Rigidbody on the tank to control it with .MovePosition and .MoveRotation. You can see the FixedUpdate function below. I've got a section below to keep thinks level, where I check if there tank is tipping past its maxTilt amount. If it is, the keep it at the max.
This makes the tank very jittery all the time. It looks like it's bouncing up and down quickly. I think its due to the hover forces, but I'm not sure.
How can I keep the tank level while still letting it hoover?
FixedUdpate
void FixedUpdate () {
if (!isServer) {
return;
}
CheckGrounded ();
Hoover ();
if (_moveForward) {
float moveAmount = moveSpeed * Time.deltaTime;
_rigidbody.MovePosition(_rigidbody.position + _rigidbody.transform.forward * moveAmount);
}
if (_moveBackward) {
float moveAmount = (-moveSpeed * 0.6f) * Time.deltaTime;
_rigidbody.MovePosition(_rigidbody.position + _rigidbody.transform.forward * moveAmount);
}
if (_turnLeft) {
Quaternion rotateAmount = Quaternion.Euler(new Vector3(0f, -angularSpeed, 0f) * Time.deltaTime);
_rigidbody.MoveRotation(_rigidbody.rotation * rotateAmount);
}
if (_turnRight) {
Quaternion rotateAmount = Quaternion.Euler(new Vector3(0f, angularSpeed, 0f) * Time.deltaTime);
_rigidbody.MoveRotation(_rigidbody.rotation * rotateAmount);
}
if (_jump && _isGrounded) {
_isJumping = true;
}
if (_isJumping && _jumpTimeLeft > 0) {
float moveAmount = jumpSpeed * Time.deltaTime;
_rigidbody.MovePosition(_rigidbody.position + _rigidbody.transform.up * moveAmount);
_jumpTimeLeft -= Time.deltaTime;
} else if (_isJumping) {
_isJumping = false;
_jumpTimeLeft = jumpTime;
}
// Keep things level
Vector3 rotation = _rigidbody.rotation.eulerAngles;
if (rotation.x > maxTilt) {
rotation.x = maxTilt;
} else if (rotation.x < -maxTilt) {
rotation.x = -maxTilt;
}
if (rotation.y > maxTilt) {
rotation.y = maxTilt;
} else if (rotation.y < -maxTilt) {
rotation.y = -maxTilt;
}
if (rotation.z > maxTilt) {
rotation.z = maxTilt;
} else if (rotation.z < -maxTilt) {
rotation.z = -maxTilt;
}
Quaternion q = new Quaternion ();
q.eulerAngles = rotation;
_rigidbody.rotation = q;
}
Hoover
void Hoover() {
foreach (Transform hoverPoint in hooverPoints) {
Ray ray = new Ray (hoverPoint.position, -hoverPoint.up);
RaycastHit hitInfo;
if (Physics.Raycast (ray, out hitInfo, hooverHeight)) {
float distance = Vector3.Distance (hoverPoint.position, hitInfo.point);
if (distance < hooverHeight) {
_rigidbody.AddForceAtPosition (hoverPoint.up * hooverForce * (1f - distance / hooverHeight), hoverPoint.position, ForceMode.Force);
}
}
}
}
I'm thinking that the reason you are seeing 'jitters' is because...
All physics calculations and updates occur immediately after FixedUpdate.
https://docs.unity3d.com/Manual/ExecutionOrder.html
Because you are adjusting the tilt in FixedUpdate(), which is then immediately followed by the Physics Engine running its calculations this will sometimes alter the tilt value giving a 'jitter'. The reason I say sometimes is because FixedUpdate() can run multiple times per frame (FPS dependant), which potentially means the following call order for a single frame:
FixedUpdate() // start frame
PhysicsEngine
FixedUpdate() // end frame
In the case above, there would be no jitter because you re-correct the tilt after the physics engine has done its thing - by complete fluke. However when you don't get a second FixedUpdate() call on a frame, you will have:
FixedUpdate() // start frame
PhysicsEngine // end frame
Which will result in your jitter.
So my suggestion is to break up your FixedUpdate() and offset any tilt corrections to LateUpdate(). Becuase LateUpdate() is always the last update call prior to the rendering of the frame.