Unity platform arm rotation with weapon offset - unity3d

Hello I'm having trouble with calculating the rotation of my characters arm to account for the guns offset from the shoulder pivot to aim the muzzle of the gun at the mouse. But when it rotates the arms it also has to update the new weapon offsets causing the guns rotation to jitter if the mouse position + weapon offset is closer then the muzzle of the gun.
public void rotateArm(){
Vector3 centerPosition = armPivotPos.position;
Vector3 mousePosition = Camera.main.ScreenToWorldPoint(Input.mousePosition)+updatedWeaponOffset();
mousePosition.z = armPivotPos.position.z;
Vector3 dir = centerPosition - mousePosition;
float angle = Mathf.Atan2(dir.y, dir.x) * -Mathf.Rad2Deg;
Quaternion temp = Quaternion.AngleAxis(angle, -Vector3.forward);
armPivotPos.eulerAngles = new Vector3(temp.eulerAngles.x, temp.eulerAngles.y, temp.eulerAngles.z);
}
public vector3 updatedWeaponOffset(){
Vector3 weaponOffset = armPivotPos.position - muzzlePos.position;
return weaponOffset;
}

Related

Point game object to another only on the Local X Axis

I would like to have a Gameobject point to another only on the Local X-axis.
void FixedUpdate()
{
if(started){
Vector3 targetPosition = target.position;
Vector3 direction = Vector3.ProjectOnPlane(targetPosition - transform.position, transform.right);
Quaternion lookRot = Quaternion.LookRotation(direction, transform.right);
transform.rotation = Quaternion.RotateTowards(transform.rotation, lookRot, Time.fixedDeltaTime * 45);
}
On the y-axis it worked with transform.up instead of transform.right, but on the x-axis the Gameobject only rotates permanently around the z-axis.
You could do something like this:
Vector3 beforeRot = transform.eulerAngles;
transform.LookAt(gameObjectToLookAt.transform);
transform.localEulerAngles = new Vector3(transform.localEulerAngles.x, beforeRot.y, beforeRot.z);
This will take a record of the position before looking at the object.
Make it look at the object.
Reset rotation back to its original except the X rotation

How do I get my character to move correctly using New Input System & Rigid Body physics? Unity3D

I have been experimenting with trying to recreate a 3rd person character controller from a Brackeys tutorial, but using the new input system and rigid body physics.
The rotation works properly, but moving forward or back moves me forward compared to the camera, and moving left or right moves me backward.
The desired effect is changing the input should change my rotation to match the input direction relative to the camera and then move in the direction the player model is facing
Here is where I'm at:
private Vector3 GetMoveInput()
{
return new Vector3(_input.MoveInput.x, 0f, _input.MoveInput.y); //convert input Vector2 into a Vector3
}
private void PlayerMove()
{
if (_playerMoveInput.magnitude > 0.01f){ //only update rotation if player is moving
float targetAngle = Mathf.Atan2(_playerMoveInput.x, _playerMoveInput.z) * Mathf.Rad2Deg + _mainCamera.eulerAngles.y;
float angle = Mathf.SmoothDampAngle(transform.eulerAngles.y, targetAngle, ref turnSmoothVelocity, turnSmoothTime);
transform.rotation = Quaternion.Euler(0f, angle, 0f);
//down here is where the problem lies I believe
_playerMoveInput = new Vector3(_playerMoveInput.x * _movementMultiplier * _rigidBody.mass,
_playerMoveInput.y,
_playerMoveInput.z * _movementMultiplier * _rigidBody.mass);
_rigidBody.AddRelativeForce(_playerMoveInput, ForceMode.Force);
}
}
I have tried setting y and z to 0f, multiplying by transform.forward, setting _playerMoveInput to transform.forward, and Quaternion.Euler(0f, angle, 0f) * transform.forward but no positive results.

3rd Person RigidBody Movement Script Using CineMachine

I am trying to create a 3rd person movement script using Cinemachine as camera, I followed Brackeys "THIRD PERSON MOVEMENT in Unity" YouTube tutorial. I then Changed the base of it from character controller to rigidbody and the movement works perfectly fine. However my code sets the velocity of the rigidbody's y axis to 0 when I move the player which fights the gravity making the player jitter slowly to the ground when I move. The Character however does drop to the ground when the player stops moving. All I need is for the script to ignore the y axis and simply listen to unity's gravity.
void Update()
{
if (!photonView.isMine)
{
Destroy(GetComponentInChildren<Camera>().gameObject);
Destroy(GetComponentInChildren<Cinemachine.CinemachineFreeLook>().gameObject);
return;
}
float horizontal = Input.GetAxisRaw("Horizontal");
float vertical = Input.GetAxisRaw("Vertical");
isGrounded = Physics.CheckSphere(new Vector3(transform.position.x, transform.position.y - 1, transform.position.z), 0.01f, layerMask);
Vector3 inputVector = new Vector3(horizontal, 0f, vertical).normalized;
if (inputVector.magnitude >= 0.1f)
{
float targetAngle = Mathf.Atan2(inputVector.x, inputVector.z) * Mathf.Rad2Deg + cam.eulerAngles.y;
float angle = Mathf.SmoothDampAngle(transform.eulerAngles.y, targetAngle, ref turnSmoothVelocity, turnSmoothTime);
transform.rotation = Quaternion.Euler(0f, angle, 0f);
Vector3 moveDir = Quaternion.Euler(0f, targetAngle, 0f) * Vector3.forward;
rb.velocity = moveDir.normalized * speed;
}
if (Input.GetKeyDown(KeyCode.Space) && isGrounded)
{
rb.AddForce(Vector3.up * jumpForce);
}
}
The player jitters because, in your movement section, you set the y velocity to 0, since Vector3.forward returns new Vector3(0, 0, 1) and you only rotate the vector around the y axis. Instead of this, consider doing:
Vector3 moveDir = new Vector3(transform.forward.x, rb.velocity.y, transform.forward.z);
This will preserve the velocity as it was, removing the jittering.
Note: transform.forward automatically gets the forward vector for the player.

Unity - Projectile Motion, find the angle needed to hit coordinates x,y

Plenty of questions asked around the same topic, but nothing seems to be working for me.
The problem is simple, a player and an enemy are on the x,y plane. I want to launch my projectile at a calculated angle in such way that the projectile will hit the enemy at it's coordinates.
I've tried implementing both
Angle of Reach and Angle required to hit x,y
Both of these implementation end up doing the same for me; Shooting but not hitting the target in this manner
Any help or pointers would be much appreciated! Thank you
Here is the code:
public Rigidbody projectile;
public float projectileSpeed;
public float Firerate = 9f;
private float nextfire;
private GameObject enemy;
private float gravity = Physics.gravity.y;
private Vector3 directionalVector;
// Start is called before the first frame update
void Start()
{
enemy = GameObject.FindGameObjectWithTag("enemy");
}
void Update()
{
directionalVector = enemy.transform.position - transform.position;
}
void FixedUpdate()
{
nextfire = Time.time + (1 / Firerate);
float projectileSpeed2 = projectileSpeed * projectileSpeed;
float projectileSpeed4 = projectileSpeed2 * projectileSpeed2;
float x = enemy.transform.position.x;
float y = enemy.transform.position.y;
float x2 = x * x;
float theta = Mathf.Atan(projectileSpeed2-Mathf.Sqrt(projectileSpeed4-gravity*(gravity*x2+2*y*projectileSpeed2))/gravity*x);
print(theta);
Vector3 releaseVector = (Quaternion.AngleAxis(theta, Vector3.up) * directionalVector).normalized;
Debug.DrawRay(transform.position, releaseVector, Color.red,0.5f);
Rigidbody instantiatedProjectile = Instantiate(projectile, transform.position, transform.rotation) as Rigidbody;
instantiatedProjectile.velocity = releaseVector * projectileSpeed;
}
}
Why not avoid the problem of finding the angle, and just move the bullet based on the direction on where it first saw the enemy.
(target.transform.position - transform.position).normalized;
It will return a Vector direction to the target.
When the projectile moves, just move it based on this direction.
No headache needed in calculating angles :)
Edit
I made a function before to 'convert' an angle to direction:
protected Vector2 DetermineBulletMoveDirection(float shootingAngle) {
// Determine the direction of the bullet travel on the x and y axis.
float bulletDirectionX = transform.position.x + Mathf.Sin((shootingAngle * Mathf.PI) / 180);
float bulletDirectionY = transform.position.y + Mathf.Cos((shootingAngle * Mathf.PI) / 180);
// Determines the direction this bullet should be moving.
Vector2 bulletDirection = new Vector2(bulletDirectionX, bulletDirectionY);
return (bulletDirection - (Vector2)transform.position).normalized;
}
It takes in an angle, and converts it into a direction based on where the shooter is currently at.
The angle should start from Vector.down, and rotates clockwise.
The next problem is to find out the angle between you and the enemy.
This is the simplest solution I could think of, here is a diagram first:
Notice that you can use TOACAHSOH on this?
So all you have to do, is to 'virtually' align the Y axis of the shooter to the origin.(Apply the movement to the shooter too!)
Do the same thing for the shooter, but on the x-axis this time.
And you would be able to achieve that state where you have a triangle with a 90-degree.
From there on, you can calculate the angle to rotate from Vector.down to the enemy.
Just make sure you move both of the objects back to it's initial position.
After fighting this for a while I found a solution.
In the end I ended up using the Angle of Reach. The second error was that Mathf.Atan returns radians and not degrees, while Quantion.AngleAxis takes in angles. The third and the final one was the fact that Unity uses left hand coordinate system as opposed to the usual right hand system which I was used to.
Here is the final piece of code:
public class TargetAndShoot : MonoBehaviour
{
public Rigidbody projectile;
public float projectileSpeed;
public float firerate;
private float nextfire;
private GameObject enemy;
private float gravity = Physics.gravity.y;
// Start is called before the first frame update
void Start()
{
enemy = GameObject.FindGameObjectWithTag("enemy");
}
void Update()
{
if (Time.time >= nextfire)
{
nextfire = Time.time + (1 / firerate);
float distance = enemy.transform.position.x - transform.position.x;
Vector3 directionalVector = enemy.transform.position - transform.position;
float v2 = projectileSpeed * projectileSpeed;
float v4 = v2 * v2;
float x = enemy.transform.position.x;
float x2 = x * x;
float y = enemy.transform.position.y;
float theta = 0.5f*Mathf.Asin((gravity * distance) / (projectileSpeed * projectileSpeed));
Vector3 releaseVector = (Quaternion.AngleAxis(theta * Mathf.Rad2Deg, -Vector3.forward) * directionalVector).normalized;
Debug.DrawRay(transform.position, releaseVector*5, Color.cyan, 0.5f);
Rigidbody instantiatedProjectile = Instantiate(projectile, transform.position, transform.rotation) as Rigidbody;
instantiatedProjectile.velocity = releaseVector * projectileSpeed;
}
}
}

Tilt Control Similar to Temple run

I want to create tilt effect just like temple run.I have a character controller(player) in the game that is moving on its forward by controller.Move(transform.forward) after which I am apply tilt to it to lean it left and right .Previously for the tilt I tried modifying the player position by using transform.translate /tranform.position directly through the accelerometer readings like this :
mytransform.translate(acceleration.x*Time.delaTime*5.0f);
but that had a problem that when I shake the device my camera starts to jerk and the player also then I used the following code to create tilt on positive Z axis
Vector3 dir = new Vector3(accel.x*8f, 0,0);
if (dir.sqrMagnitude > 1)
{
dir.Normalize();
}
dir.x = Mathf.Round(dir.x * 10f) / 10f;
//mytemp is used for temp storage of player position added with the acceleration
mytemp = mytransform.position+(mytransform.right*dir.x*Time.deltaTime*5.0f);
Vector3 diffVec=Vector3.zero;
///position of the element on which the player is colliding;
Vector3 col_pos=Collidingelement.transform.position;
Vector3 unitvec=new Vector3(1,0,0);
//removing x and z of the collider
diffVec= Vector3.Scale(col_pos,unitvec);
//nullify the y,z of the updated mytransform position so that the distance is only measured on X
Vector3 ppos = Vector3.Scale(mytemp,unitvec);
//calculate the distance between player & colliding element
disti=Vector3.Distance( ppos,diffVec);
disti=Mathf.Clamp(disti,-1.5f,1.5f);
disti = Mathf.Round(disti * 10f) / 10f;
//update the player position and apply tilt to it if the distance is less than 1.5f
if(disti<=1.50f)
{
mytransform.position=mytemp;
}
now this has a problem that if lets say I have a value of 0.1 in the acceleration its keep on update my temp and if the distance is less my player will start leaning towards a side though I held my device on same position and acceleration value was always 0.1
Why don't you just calculate delta acceleration.
bool isMoved = false;
Vector2 lastAccel = Vector2.Zero;
Vector2 margin = new Vector2(0.05f, 0.05f); //not processing if its in margin.
Vector2 deltaAccel = currAccel - lastAccel ;
if(deltaAccel.x < margin.x)
{
//don't process
isMove = false;
}
else
{
isMove = true;
lastAccel = currAccel;
}
if(isMove)
{
//Process with deltaAccel here
}