Object doesn't move to another hemisphere in unity - c#

I'm trying to realize moving on an object round sphere (walk on it), but when it gets to the equator of the sphere, it stops moving.
public Transform planet;
public bool AlignToPlanet;
public float gravityConstant = -9.8f;
void FixedUpdate()
{
Vector3 toCenter = planet.position - transform.position;
toCenter.Normalize();
GetComponent<Rigidbody>().AddForce(toCenter * 9.8f, ForceMode.Acceleration);
if (AlignToPlanet)
{
Quaternion q = Quaternion.FromToRotation(-transform.up, -toCenter);
q = q * transform.rotation;
transform.rotation = Quaternion.Slerp(transform.rotation, q, 1);
}
Debug.Log(CrossPlatformInputManager.GetAxis("Vertical"));
GetComponent<Rigidbody>().AddForce(transform.forward * 2, ForceMode.Impulse);
}

First off, you should avoid calling GetComponent more than necessary. Just call it once to get the Rigidbody in Awake then refer to the result in FixedUpdate.
Second, once you determine the object's up direction, you can use cross products to determine what would be the forward that is closest to the previous forward while still maintaining that up.
Then, you can use Quaternion.LookRotation to set that up and forward.
Finally, you should use Rigidbody.MoveRotation to set the rotation.
Altogether:
private Rigidbody rb;
public Transform planet;
public bool AlignToPlanet;
public float gravityConstant = -9.8f;
void Awake()
{
rb = GetComponent<Rigidbody>();
}
void FixedUpdate()
{
Vector3 toCenter = planet.position - transform.position;
toCenter.Normalize();
rb.AddForce(toCenter * 9.8f, ForceMode.Acceleration);
if (AlignToPlanet)
{
Vector3 newUp = -toCenter;
Vector3 newRight = Vector3.Cross(newUp, transform.forward);
Vector3 newForward = Vector3.Cross(newRight, newUp);
Quaternion newRot = Quaternion.LookRotation(newForward, newUp);
rb.MoveRotation(q);
}
Debug.Log(CrossPlatformInputManager.GetAxis("Vertical"));
rb.AddForce(transform.forward * 2, ForceMode.Impulse);
}

I set up a new project with your script, and it works fine for me.
The only things I changed (beside the AddForce on the forward to test it) are :
The FromToRotationin which you pass opposite vectors (one to the up, and one to the down)
The Slerp I removed, it is useless since you pass a value of 1.
So, it looks like this :
if (AlignToPlanet)
{
// removed the minus in front of toCenter
Quaternion q = Quaternion.FromToRotation(-transform.up, toCenter);
transform.rotation = q * transform.rotation;
}
EDIT
I agree with #Ruzhim : the LookRotation is a better way to compute your new rotation, since it takes also the forward of your object.
(And for the fact to not use the GetComponent in any Update)

Related

How can I apply scripts in new camera which is child of a gameobject

Earlier I was facing problem regarding the unity camera problem it always stuck on 0,0,0.08 and also find a solution so I first create an empty gameobject and then drag the camera in that empty gameobject but after doing this the scripts which I applied to the gameobject is working fine but the script which I place in camera is not working at all
Camera Script
public float MovementAmplitude = 0.1f;
public float MovementFrequency = 2.25f;
void Update()
{
transform.position = new Vector3(
transform.position.x,
Mathf.Cos(transform.position.z * MovementFrequency) * MovementAmplitude,
transform.position.z
);
}
Player Script
public float speed = 4.5f;
public float JumpingForcec = 450f;
void Update()
{
transform.position += speed * Vector3.forward * Time.deltaTime;
if (Input.GetKeyDown("space"))
{
Debug.Log("SPace is pressed");
Debug.Log(GetComponent<Rigidbody>());
GetComponent<Rigidbody>().AddForce(Vector3.up * JumpingForcec);
}
}
First of all when dealing with a Rigidbody (or the Physics in general) you shouldn't set a position directly through the Transform component but rather use Rigidbody.position or in your case for a smooth movement even rather Rigidbody.MovePosition, both in FixedUpdate.
In general anything related to the Physics (so also everything using Rigidbody) should be done in FixedUpdate while the check for GetKeyDown has to be done in Update.
PlayerScript
public class PlayerScript : MonoBehaviour
{
public float speed = 4.5f;
public float JumpingForcec = 450f;
// If possible reference this in the Inspector already
[SerializeField] private Rigidbody rigidBody;
private bool jumpWasPressed;
private void Awake()
{
if (!rigidBody) rigidBody = GetComponent<Rigidbody>();
}
private void FixedUpdate()
{
rigidBody.MovePosition(transform.position + speed * Vector3.forward * Time.deltaTime);
if (!jumpWasPressed) return;
Debug.Log("SPace was pressed");
rigidBody.AddForce(Vector3.up * JumpingForcec);
jumpWasPressed = false;
}
private void Update()
{
// Note that currently you can multijump .. later you will want to add
// an additional check if you already jump again
if (Input.GetKeyDown(KeyCode.Space)) jumpWasPressed = true;
}
}
Make sure that Is Kinematic is disabled in the Rigidbody component! Otherwise AddForce is not processed.
If isKinematic is enabled, Forces, collisions or joints will not affect the rigidbody anymore.
The camera movement I would move to LateUpdate in order to make sure it is the last thing calculated after the other Update calls have finished. Especially after all user input has been processed (in your case maybe not that relevant since movement is processed in FixedUpdate but in general).
Second problem: Here you are not taking the changed Y position by jumping into account so rather add the "wobbling" effect to the player's transform.position.y and rather use the localPosition for the Camera:
public class CameraScript : MonoBehaviour
{
public float MovementAmplitude = 0.1f;
public float MovementFrequency = 2.25f;
// reference the player object here
public Transform playerTransform;
private float originalLocalPosY;
private void Start()
{
if(!playerTransform) playerTransform = transform.parent;
originalLocalPosY = transform.localPosition.y;
}
private void LateUpdate()
{
transform.localPosition = Vector3.up * (originalLocalPosY + Mathf.Cos(playerTransform.position.z * MovementFrequency) * MovementAmplitude);
}
}
Maybe you want to disable the wobbling effect during a jump later, though ;)
Try to put all the update stuff in the same method, it should work both (theorically, not tested) so you have to fix your code in order to get what you want:
void Update() {
// Camera update
transform.position = new Vector3(
transform.position.x,
Mathf.Cos(transform.position.z * MovementFrequency) * MovementAmplitude,
transform.position.z
);
// Player update
transform.position += speed * Vector3.forward * Time.deltaTime;
if (Input.GetKeyDown("space"))
{
Debug.Log("SPace is pressed");
Debug.Log(GetComponent<Rigidbody>());
GetComponent<Rigidbody>().AddForce(Vector3.up * JumpingForcec);
}
}
Hope this helps you, cheers!

unity 3d rotate object (space.self) toward player

i need your help please.
i want an object to rotate in Y axis (space.self) toward the player position.
i have already tried this code, it works but i think there is a bug in it because the object keep changing position slowly.
public Transform _Playertrs;
public float RotationSpeed = 10f;
private Quaternion _LookRotation;
private Vector3 _direction;
private bool Patroling = true;
// Use this for initialization
void Start () {
}
// Update is called once per frame
void Update () {
_direction = (_Playertrs.position - transform.position).normalized;
_LookRotation = Quaternion.LookRotation(_direction);
transform.rotation = Quaternion.Slerp(transform.rotation, _LookRotation, Time.deltaTime * RotationSpeed);
}
thank you guys for your answers, the rotation is working perfectly now, but the problem is the object keep moving from its position even that i don't have any movement code, watch the video to understand pls
https://www.youtube.com/watch?v=Gys5xYQ5psw&feature=youtu.be
If you want it to be instantaneous, replace
transform.rotation = Quaternion.Slerp(transform.rotation, _LookRotation, Time.deltaTime * RotationSpeed);
by
transform.rotation = _LookRotation;
The Slerp function gives an intermediate point between the to rotation to make a smooth effect.
Here, this is taken from the Unity Quaternion.LookRotation() official documentation, you can just simply apply the Quaternion that you have _LookRotation and apply it to your desired transform.rotation as such transform.rotation = _LookRotation;
using UnityEngine;
using System.Collections;
public class ExampleClass : MonoBehaviour
{
public Transform target;
void Update() {
Vector3 relativePos = target.position - transform.position;
Quaternion rotation = Quaternion.LookRotation(relativePos);
transform.rotation = rotation;
}
}

How do I move the Rigidbody in FixedUpdate, but still have my character be affected by gravity?

So
Below you see what I initially used to control my characters movement.
_RigidBody.velocity = _ConstantWalkingSpeed * direction.normalized;
This works for walking around in 4 directions. However, if my character falls over an edge, he falls veeeeeery slowly. If I then in mid air disable the walking script, gravity picks up and goes at normal speed.
This leads me to believe that my movement script somehow affects the gravity effect.
As such I tried this solution:
_RigidBody.velocity = _ConstantWalkingSpeed * direction.normalized + new Vector3(0f, _RigidBody.velocity.y, 0f);
That didn't work either, so I tried this:
_RigidBody.velocity = _ConstantWalkingSpeed * direction.normalized + new Vector3(0f, _RigidBody.velocity.y, 0f) + Physics.gravity;
That did make the gravity work, but then the gravity became so strong that I can't move.
I tried only adding Physics.gravity and skipping the new vector part, but then the gravity is still too strong.
TL;DR
The movement script I use affects the players downward gravity, which it shouldn't. I want him to move around but still be affected by gravity. Ideas I have tried didn't work.
Please note that I'd prefer to keep the gravity at -9.81.
Hoping you guys have a suggestion that works :-)
Instead of setting or modifying the velocity, You can use RigidBody.movePositon:
Here is a quick example script I wrote up:
using UnityEngine;
public class simpleMoveRB : MonoBehaviour {
public Rigidbody myBody;
public float _constantWalkSpeed = 3.0f;
Vector3 moveDirection = Vector3.zero;
// Use this for initialization
void Start () {
}
// Update is called once per frame
void Update() {
if (Input.GetKey(KeyCode.A))
{
moveDirection.x = -1.0f;
}
else if(Input.GetKey(KeyCode.D))
{
moveDirection.x = 1.0f;
}
else
{
moveDirection.x = 0.0f;
}
if(Input.GetKeyDown(KeyCode.Space))
{
myBody.AddForce(Vector3.up * 500.0f);
}
}
private void FixedUpdate()
{
myBody.MovePosition(transform.position + moveDirection * _constantWalkSpeed * Time.deltaTime);
}
}
You can handle movement using this script, and still have gravity work on your object.
Instead of setting the velocity, modify the velocity.
You're overwriting any velocity applied by the physics engine (e.g. gravity) with your input.
_RigidBody.velocity += _ConstantWalkingSpeed * direction.normalized;
You may also want to cap the velocity X and Z values to a maximum:
Vector3 vel = _RigidBody.velocity;
vel.x = Mathf.Min(vel.x, ConstantWalkingSpeed);
vel.z = Mathf.Min(vel.z, ConstantWalkingSpeed);
_RigidBody.velocity = vel;

Unity bouncing when colliding with object

I have made a script with movement, that finally works as i want it to, except one thing... I want it to be a first person game, but the way the movement works now, is on the global axis, which means that W is always torwards one specific direction, no matter what direction my camera is turning... How do i fix this? i want the movement to stay how it is, but with the W key to always be forward depending on the way the camera or player is looking.
Please let me know how my script would look edited, or atleast what part i have to change.
I would also like to add that i would love to be able to do a wall jump, but i am not sure how to add that behavior.
Here is my movement script:
public class MovementScript : MonoBehaviour {
public float speed;
public float jumpforce;
public float gravity = 25;
private Vector3 moveVector;
private Vector3 lastMove;
private float verticalVelocity;
private CharacterController controller;
// Use this for initialization
void Start () {
controller = GetComponent<CharacterController> ();
//Låser og gemmer musen
Cursor.lockState = CursorLockMode.Locked;
}
// Update is called once per frame
void Update () {
//Låser musen op
if (Input.GetKeyDown ("escape"))
Cursor.lockState = CursorLockMode.None;
moveVector = Vector3.zero;
moveVector.x = Input.GetAxis("Horizontal");
moveVector.z = Input.GetAxis("Vertical");
if (controller.isGrounded) {
verticalVelocity = -1;
if (Input.GetButton("Jump")) {
verticalVelocity = jumpforce;
}
} else {
verticalVelocity -= gravity * Time.deltaTime;
moveVector = lastMove;
}
moveVector.y = 0;
moveVector.Normalize ();
moveVector *= speed;
moveVector.y = verticalVelocity;
controller.Move (moveVector * Time.deltaTime);
lastMove = moveVector;
}
}
You need to go from local to world space:
for example when you want to move on the x-axis regarding the player's orientation, the local vector is (1, 0, 0), which you get from your input axis, but the CharacterController need a world based direction (see the doc of the Move function)
A more complex move function taking absolute movement deltas.
To get this, use Transform.TransformDirection like this
worldMove = transform.TransformDirection(moveVector);
controller.Move (worldMove * Time.deltaTime);
EDIT regarding your issue with the controller moving a bit after releasing the input:
That's because GetAxis gives you a smoothed value. Replace GetAxis by GetAxisRaw and it should work
Modify the final moving code to
controller.Move(moveVector.z * transform.forward * Time.deltaTime);
controller.Move(moveVector.x * transform.right * Time.deltaTime);
controller.Move(moveVector.y * transform.up * Time.deltaTime);
Alternatively, suppose your character is only rotated about the Y axis, you can look into rotating your moveVector by your character's Y rotation so moveVector's forward points parallel to your chracter's forward.
I found a good explaination of rotating a vector here: https://answers.unity.com/questions/46770/rotate-a-vector3-direction.html
Rotating a vector:
moveVector = Quaternion.Euler(0, transform.eulerAngles.y, 0) * moveVector;

transform.Translate isn't cutting it and rigidbody.AddRelativeForce doesn't move my character (Unity and c#)

I'm making a game in Unity 5 (3D) and am using c# for scripting. So I basically have a third person dude running around with 8 direction controls (WASD) and the way I have set it up now is like this (ignore all the public variables for testing):
public class Player8D : MonoBehaviour
{
public float moveSpeed;
public float moveSpeedMax = 13.5F;
public float turnSpeed = 4F;
public float transitionSpeed = 10F;
private float moveSmooth = 0.0F;
public float moveSmoothTime = 10F;
private Animator anim;
private Rigidbody rb;
private CharacterController cc;
void Start()
{
anim = gameObject.GetComponentInChildren<Animator>();
rb = gameObject.GetComponentInChildren<Rigidbody>();
cc = gameObject.GetComponentInChildren<CharacterController>();
}
void Update()
{
Vector3 NextDir = new Vector3(Input.GetAxisRaw("Horizontal"), 0, Input.GetAxisRaw("Vertical"));
if (NextDir != Vector3.zero) //When movement input is happening
{
anim.SetInteger("Run", 1); //Animation stuff
transform.rotation = Quaternion.Slerp(transform.rotation, Quaternion.LookRotation(NextDir), Time.deltaTime * turnSpeed);
moveSpeed = Mathf.SmoothDamp(moveSpeed, moveSpeedMax, ref moveSmooth, moveSmoothTime / 100);
} else
{
moveSpeed = Mathf.SmoothDamp(moveSpeed, 0.00F, ref moveSmooth, transitionSpeed / 100);
anim.SetInteger("Run", 0); //Animation stuff
anim.CrossFade("Idle", transitionSpeed / 100);
}
transform.Translate(Vector3.forward * Time.deltaTime * moveSpeed); //Movement code
}
}
This gave me the best feeling due to how it moves in the direction it's facing, rather than in 8 distinct world directions like with cc.Move. That being said it has the caveat of not being in physics, which I kinda need for OnTriggerEnter and falling realistically and it makes going uphill strange. I have no idea how to manage the rb.AddForce or AddRelativeForce functions, as they don't move my character when I replace transform.Translate with them, no matter how great the force is.
How do I change the code and components to get my character moving through physics?
Here is a screenshot of my scene hierarchy:

Categories