I'm working on a new control scheme for the Oculus Rift that utilizes the tilt of the headset to move the player. Meaning, you tilt your head back and forth to go forwards and backwards, and from side to side to strafe. The camera is tied to a rolling sphere, as that gave it a nice sense of acceleration, and feels a bit like kind of flying around. So far, it's working quite well, but only on the global axis. So if you turn to the left and tilt your head forward, you still go forward according to the starting position (Which if you're facing to the left means you'll go right). I'm trying to fix it so that you can go forward and strafe relative to the direction the camera is facing, but with no luck. I have a strong sense that it's something ridiculously simple, but I just can't seem to find it. Any help is very much appreciated!
Here is what I have on the rolling sphere right now:
public GameObject RightCamera;
void FixedUpdate(){
float angleX = RightCamera.transform.eulerAngles.x;
angleX = (angleX > 180) ? angleX - 360 : angleX;
float angleZ = RightCamera.transform.eulerAngles.z;
angleZ = (angleZ > 180) ? angleZ - 360 : angleZ;
Vector3 movement = new Vector3 (-angleZ, 0, angleX);
GetComponent<Rigidbody>().AddForce (movement);
}
There's an easy way to do this. Given the orientation expressed as a quaternion (or 3x3 Matrix) compose it with a unit Y axis vector.
The resulting vec3's X and Z values are your forces. No need to involve Euler angles, which will almost certainly start hurting you as your approach a 90 degree angle from vertical.
Finally solved it! I used
GetComponent<Rigidbody> ().AddForce (RightCamera.transform.forward * angleX);
GetComponent<Rigidbody> ().AddForce (-RightCamera.transform.right * angleZ);
And now the sphere rolls relative to the camera.
Related
i am creating a 3d top down shooter with unity and wanted to create an aim assist for it since hitting enemies is difficult. my idea was to create a trigger that slows down the rotation of the joystick on the weapon when the player aims at an enemy. i implement my rotation as follows:
float eulerY = (Mathf.Atan2(_JoystickShoot.Direction.x, _JoystickShoot.Direction.y) * 180 / Mathf.PI);
However, I don't know how to implement the slowdown now. The player should rotate slower than the actual rotation of the joystick.
My approaches have not really been successful so far.
does anyone have any idea?
thanks :)
You can add a variable that scales the rotation. Set it to 1, except when you're pointing at an enemy, where you set it to a value between 0 and 1 that feels good for you.
float eulerY = rotationScaling * (Mathf.Atan2(_JoystickShoot.Direction.x, _JoystickShoot.Direction.y) * 180 / Mathf.PI);
If you want to draw the crosshair towards an enemy, you can calculate the angle (or distance) to the closest enemy. If it is below a certain threshold you can adjust your rotation function to favor rotations towards the enemy over rotations away from it. You can use something like this:
float eulerY = (Mathf.Atan2(_JoystickShoot.Direction.x, _JoystickShoot.Direction.y) * 180 / Mathf.PI);
if (closest enemy is within threshold range)
if (eulerY * (difference in Y angle to closest enemy) < 0) // if we rotate away from the enemy we scale the rotation down
eulerY *= 0.5;
else // if we rotate towards the enemy we scale it up
eulerY *= 1.5;
You can adjust this for multiple angles as well, but just doing the same calculation for X and Y direction might feel a bit awkward. The reason is that in that case you have to compare it against the "true" angle/distance, not against the X and Y angles/distances individually.
I think it is more useful to talk about 'direction' rather than 'rotation'.
Presumably your ship travels and/or shoots in the same direction as the joystick is pointing in. This is a natural and intuitive relationship. "slowing down rotation" will most likely break this, making your interface less intuitive to use. There are also usually ways to go directly from a direction-vector to a rotation, for example Quaternion.LookRotation, avoiding the need to deal angles directly.
You could instead check if there is any enemy within a small arc, select the enemy closest to the center of the arc, and use the direction towards that enemy to fire in. Note that this can fail if enemies are moving and shots are slow, since it can prevent 'leading' your shots.
Other alternatives could be to simply make your enemies easier to hit. Make the enemies or shots larger, or possibly, just make the hitboxes larger. Or increase fire-rate and/or dispersion.
I am making a rolling ball game, and the way I want it to work is based on constant forward movement and rotation based turning.
I'm using force, which then has the ball roll forward.
My Issue here is that I would like the ball to move forward based on where it's "facing". Using Vector3.forward only moves it according to world space and transform.forward will start going backwards because the ball rolls over, upside down.
How can I make it so transform.forward ignores my forward turning, only being effected by the sideways turning?
"forward" is hard to imagine on a sphere.
You add speed when rotating around the X-axis (ball moves "forward")
For direction control, you rotate around global Y-axis.
The transform.forward will spin around the object. But the transform.right (local x-axis so to say) stays stable.
So we only need the Vector3.Cross Product of the transform.right and the global Vector3.Up.
Vector3 forward = Vector3.Cross(transform.right, Vector3.up);
You can use vector math for this. Take the cross product between the local right and the world up:
private static Vector3 GetRollingForward(Vector3 localRight)
{
return Vector3.Cross(localRight, Vector3.up);
}
// ...
void Update()
{
Debug.DrawLine(transform.position, transform.position
+ GetRollingForward(transform.right));
}
Im making a space exploration game and I'm trying to have an arrow rotating around the player, pointing towards the sun in the center of the level. This is to make the game more readable.
The "arrow" is for now just a cylinder with a sphere on it - with the sphere representing the arrow point. The rotation around the player is working, but I can't get it to point towards the sun, consistently. As seen in the image here, the arrow is pointing almost opposite of where I want it to.
The code I'm using is as follows
playerPos = transform.position;
sunPos = sun.transform.position;
// Cast ray from player to sun
Ray ray = new Ray(playerPos, sunPos - playerPos);
RaycastHit hitInfo;
if (Physics.Raycast(ray, out hitInfo, 400, mask))
Debug.DrawLine(ray.origin, sunPos, Color.green);
Debug.Log("Distance" + hitInfo.distance);
// Rotate arrow around player.
arrow.transform.position = playerPos + ray.direction.normalized*2;
// Point arrow towards sun. This is not working
arrow.transform.rotation = Quaternion.FromToRotation(gameObject.transform.position, sunPos);
In addition to Quaternion.FromToRotation I have also tried using LookAt, which also gave me weird results. (I tried all the different up directions, i.e. LookAt(sun, Vector3.left) and (sun, Vector3.back), etc.
Hoping some clever minds can help. Thanks in advance.
Theory
You can use
Quaternion.FormToRotation
It create a quaternion (thing who handle the rotation of your gameobject) by giving a direction vector and the "0" vector. With these informations it'll know how to rotate your transform.
Exemple
I would do something like :
Vector3 direction = sunPos - playerPos;
transform.rotation = Quaternion.FromToRotation(direction, Vector3.right);
Vector3.right = (1f,0f,0f) and you should use the standard direction of your arrow. For exemple if when arrow have no rotation it point up (0f,1f,0f), you should use Vector3.up insteed.
As I said on comment you don't need raycast for this. (Maybe you need it later on your code)
Vector3 delta = sunPos - playerPos;
Vector3 direction = delta.normalized;
float distance = delta.magnitude;
I am trying to make a spin wheel that is divided into 6 sections. Each section is marked with a gameObject that is centered in that section. After the player spins the wheel, it will rotate until its starts stopping and then the wheel moves and stops in the center based on the section that was selected (Randomly). I used the following code to rotate the wheel towards the 0 on X axis. this code works fine and the wheel rotates fine, but only if the selected section was on the positive X axis.
float rotateFloat = (((randomReward + 1) * 60) - 30) - transform.rotation.z;
Quaternion targetRotation = Quaternion.Euler(new Vector3(0, 0, rotateFloat));
transform.rotation = Quaternion.RotateTowards(transform.rotation, targetRotation, f_difX * Time.deltaTime);
I did some digging and found that Quaternion.RotateTowards()finds the closest way towards the target and rotates using that direction (This caused a problem with the direction of rotation).
Example (Follow image): The player swipes and randomReward (Number 5 on spin wheel) and the wheel starts rotating. When the wheel slows down, it starts moving towards the center. Then it will stop spinning along the direction of the swipe and will rotate towards the other side (Because the distance to the center is closer from the left side).
How can I set it to follow the same direction of the swipe regardless of which is closer to the center. And maybe if there is a better way to do this, please enlighten me. Thanks.
I think the easiest way to rotate a GameObject is by using:
float Speed = 1f;
void Update()
{
// Rotate the object around its local X axis at 1 degree per second
transform.Rotate(Vector3.right * Time.deltaTime * Speed);
}
You can read more about his here
It can happen sometimes the center of the GameObject it´s not placed in the center of the mesh or sprite. If you can´t modify this for any reason, what you can do is place this model/sprite as a child of an Empty GameObject and then attach the rotation script to the Empty GameObject.
While i understand that you don't want people to rotate the disk to the reward they want. Why do you use a random reward and go through the trouble of lining the rotation to the reward?
You should be able to say catch a 'swipe time', then do some math to it (say so it turns at least once if the screen touch time is very short) and then add a random range to it, that is within the circumference of the disk. Then when the disk is done spinning do a ray cast at the top location to determine the reward? (could also link the spinning time to the swipe-time, so that the reward is offered in somewhat the same time interval).
//this comment would have been made as a comment if i would have had the rights to do so, as i think this response may help the question asker, it is provided as an answer instead. i do hope this doesn't piss any one off to much :(
Actually, i'm programming a little spaceshooter game (2.5D, Topdown View). The player can move along the XZ Axies and rotate the spaceship via right ministick (gamepad) or look to the cursor position (keyboard + mouse).
So, the movement and rotation (Y-Axies, Yaw) are seperated.
The whole thing works fine and looks good - but now i want to do the following:
If the spaceship moves sideways, it should rotate around the X / Pitch axies / lean left and right a bit, dependent on the sideways speed.
So, i have to compute the sideways speed from the following, given input:
Velocity Vector (Movement on X and Z Axies, Y is always '0')
Direction Vector (Rotation on Y Axies, X and Z are always '0')
And with the amount of sideways speed, i could rotate my spaceship around the X axies and multiply the resulting quaternion by the rotation around the y axies.
Anyone who has a solution for this?
Solution: Just "rotate" the velocity vector by the heading of the spaceship and use the "roll/z" axis as the sideways rotation about the X axis (the axis, where your ships nose points towards):
Quaternion Rotation = Quaternion.Euler(0, mHeading.y, 0);
Vector3 RealVeloctiy = Quaternion.Euler(0, -mHeading.y, 0) * Velocity;
float Angle = RealVeloctiy.z * 2.5f;
Rotation = Rotation * Quaternion.Euler(Angle, 0, 0);
A couple of possibilities:
Compare the velocity vector with local left direction of the spaceship (make sure they're in the same coordinate space first). You could use the Vector3.Angle function, or a dot product to do the comparison. Scale the result appropriately, and apply a local rotation around the forward axis.
Take user input directly. If the user is strafing in a direction, apply a roll value. You could use a float between -1 and +1, along with a rate of change. If they're strafing left, move the value towards -1 at that rate, or if they're strafing left, to +1. If neither key is being pressed, move the value back towards 0. (You might like to play around with the Lerp, SmoothStep and SmoothDamp functions too). Scale the value to apply an appropriate rotation about the relevant axis.