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 :(
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 have a laser turret in Unity3D, which I'd like to turn towards the enemies. The turret consists of a "leg" and a "head" (selected on the picture 1). The head can pan and tilt around a spherical joint.
I do the following:
Vector3 targetDir = collision.gameObject.transform.position - turretHead.transform.position;
float step = turnSpeed * Time.deltaTime;
Vector3 newDir = Vector3.RotateTowards(turretHead.transform.forward, targetDir, step, 0.0f);
turretHead.transform.rotation = Quaternion.LookRotation(newDir);
The problem is that since the pivot of the head is not aligned with the laser beam, the turret turns into the almost right direction, but it shoots above the target. (It would hit perfectly, if the laser would come out of the red axis of the pivot.)
Is there a builtin method or some trick to achieve the correct functionality other then doing the calculation myself?
Okay, here's the quick and easy way to do this. It's probably "better" to do it with proper trig, but this should give you the result you want pretty quick:
If you don't already have a transform aligned with the barrel, then create an empty GameObject and line it up (make sure it's a child of the turret so they move together). Add a reference to your script for it's transform.
Then, in your first line, calculate from the new Barrel transform instead of the turretHead transform. Leave everything else the same. This way it calculates from the turret barrel, but moves the turret head.
Now, this approach isn't perfect. If the pivot center is too offset from the barrel transform, then it would be less accurate over large moves, or when aiming at something close by, because the expected position when aiming would be different than the initial position due to the rotation pivot being elsewhere. But this can be solved with iteration, as the calculation would become more accurate the closer it is to it's desired goal.
Overview
I've been looking around for a while and haven't found an answer so hopefully the community here can help me out. I am re-working my look-at camera (written pre 2000) and am having trouble getting rid of an issue where the look-at and up vectors become aligned causing the camera to spin wildly out of control. I originally understood this to be gimbal lock, but now I'm not so sure of that.
From my understanding of gimbal lock, when pitch becomes aligned with roll, pitch becomes roll; and in essence this is what it appears to be, but the problem is that the rate of change shouldn't increase just because the axes become aligned, I should just get a smooth roll. Instead I get a violent roll in which I can't really tell which way the roll is going.
Updating the Camera's Position
When the user moves the mouse I move the camera based on the mouse's X and Y coordinates:
Vector2 mousePosition = new Vector2(e.X, e.Y);
Vector2 delta = mousePosition - mouseSave;
mouseSave = mousePosition;
ShiftOrbit(delta / moveSpeed);
Within the ShiftOrbit method, I calculate the new position based on the look-at, right, and up vectors in relationship to the delta passed from the mouse event above:
Vector3 lookAt = Position - Target;
Vector3 right = Vector3.Normalize(Vector3.Cross(lookAt, Up));
Vector3 localUp = Vector3.Normalize(Vector3.Cross(right, lookAt));
Vector3 worldYaw = right * delta.X * lookAt.Length();
Vector3 worldPitch = localUp * delta.Y * lookAt.Length();
Position = Vector3.Normalize(Position + worldYaw + worldPitch) * Position.Length();
This works smoothly as it should and moves the camera around its target in any direction of my choosing.
The View Matrix
This is where I experience the problem mentioned in the overview above. My Up property was previously set to always be 0, 0, 1 due to my data being in ECR coordinates. However, this is what causes the axis alignment as I move the camera around and the view matrix is updated. I use the SharpDX method Matrix.CreateLookAtRH(Position, Target, Up) to create my view matrix.
After discovering that the Up vector used when creating the view matrix should be updated instead of always being 0, 0, 1, I encountered another issue. I now caused roll when yaw and pitch were introduced. This shouldn't occur due to a requirement so I immediately began pursing a fix.
Originally I performed a check to see if was coming close to being axis aligned, if I was, then I set the Up used to create my view matrix to the local up of the camera, and if I wasn't then I used only the Z axis of the local up to ensure that up was either up or down.
float dot = Math.Abs(Vector3.Dot(Up, Position) / (Up.Length() * Position.Length()));
if (dot > 0.98)
Up = localUp;
else
Up = new Vector3(0, 0, localUp.Z);
However, this was a bit jumpy and still didn't seem quite right. After some trial and error, along with some extensive research on the web trying to find potential solutions, I remembered how linear interpolation can transition smoothly from one value to another over a period of time. I then moved to using Vector3.Lerp instead:
float dot = Math.Abs(Vector3.Dot(Up, Position) / (Up.Length() * Position.Length()));
Up = Vector3.Lerp(new Vector3(0, 0, localUp.Z), localUp, dot);
This is very smooth, and only causes any roll when I am very near to being axis aligned which isn't enough to be noticeable by the every day user.
The Problem
My camera also has the ability to attach to a point other than 0, 0, 0, and in this case, the up vector for the camera is set to the normalized position of the target. This causes the original issue in the overview when using Vector3.Lerp as above; so, in the case where my camera is attached to a point other than 0, 0, 0 I do the following instead:
Up = Vector3.Lerp(Vector3.Normalize(Target), localUp, dot);
However, even this doesn't work and I have no idea how to get it to do so. I've been working at this problem for a few days now and have made an extensive effort to fix it, and this is a big improvement so far.
What can I do to prevent the violent spinning using Vector3.Lerp when the up isn't equivalent to 0, 0, z?
Imagine a vertical plane that is rotated around the vertical axis by yaw (ϕ):
The camera is only allowed to rotate with the plane or in the plane, its in-plane orientation given by the pitch (θ):
ϕ and θ should be stored and incremented with the input delta. With this setup, the camera will never tilt, and the local up direction can always be computed:
d and u are the local front and up directions respectively, and are always perpendicular (so alignment won't be an issue). The target can of course be taken as the position + d.
But wait, there's a catch.
Suppose if you move your mouse to the right; ϕ increases, and you observe:
If the camera is upright, the view rotates to the right.
If the camera is upside-down, the view rotates to the left.
Ideally this should be consistent regardless of the vertical orientation.
The solution is to flip the sign of increments to ϕ when the camera is upside down. One way would be to scale the increments by cos(θ), which also smoothly reduces the sensitivity as θ approaches 90 / 270 degrees so that there is no sudden change in horizontal rotational direction.
To give you the setting: I'm making a Vive game in zero-g, where the player moves by grabbing handles and propelling themselves.
What I'd like is for the player to be able to rotate themselves, by grabbing a handle with both hands. Imagine how you'd move in zero-g if you held on to a bar with both hands.
To illustrate:
On the left hand side the player has grabbed a handlebar with both hands. Left arm extended, right arm bent.
In the right hand side picture the player has now extended their right arm, which has rotated the player around the bar.
I guess it's easier to see it as if the player would be moving the entire world, when they do this.
My question is: How can I do this in Unity in 3 dimensions, either through math of Unity-trickery? It needs to roll, yaw and position the player relative to the hands.
Thank you!
Record the average of the three vectors. Then in the next frame, get the difference from the previous average. The difference can be used as euler angles to apply constant force to a rigidbody (or rotate an object by that amount, or other possibilities, depending on your goals).
https://docs.unity3d.com/ScriptReference/Transform.Rotate.html
https://docs.unity3d.com/ScriptReference/Rigidbody.AddForce.html
Vector3 previousCenterPoint;
void Update() {
Vector3 newCenterPoint = (leftHand.transform.position + rightHand.transform.position + player.transform.position) / 3f;
if (previousCenterPoint != null)
{
Vector3 someEulerAngles = newCenterPoint - previousCenterPoint;
someRigidBody.AddForce(someEulerAngles, ForceMode.VelocityChange);
}
previousCenterPoint = newCenterPoint;
}
Im making a 2D game where the player controls a tank.
I can make the tank, and all, but whats really messing with my mind is how to make it rotate accordingly.
I want it to behave just like the Wii game, Tanks.
Fixed directions, and with no real front and back on the tank.
Driving up, then left should make it rotate to the left.
Driving up, then down should not make it rotate, just drive the other direction.
I red a tutorial a while back about some way to do that by dividing the degrees into 2 180 degree parts. But i have simply not been able to find that damn site again.
I hope you guys are able to understand what im trying to say.
Thanks in advance :)
I assume you're drawing your tank as a sprite? In that case there's an overload of the SpriteBatch.Draw method that allow you to specify the rotation angle around the origin.
SpriteBatch.Draw overload
Here's an example on how to use it from MSDN
The example above will keep rotating your sprite, so you will need to add some custom logic so it will only rotate it according to keyboard input. Here's a simple example on how to check for keyboard input. So add logic that checks if the right or left button has been pressed, and update the rotation angle if they have. If it's the up or down button that has been pressed you simply modify the position of your sprite.
I hope it makes sense, otherwise just let me know.
I think what you're looking for is simply the best way to minimize the rotation of the tank, modulo 180 degrees.
I would use the angle between the desired movement direction and the tank's current direction to start. Make sure this is the minimum angle, then compare that with the angle between the tank's current direction + 180 degrees. Something like:
// smallest angle between the current direction and the desired direction
minAngle1 = Math.Abs(Math.Min(tankAngle - desiredAngle, desiredAngle - tankAngle));
// smallest angle between the opposite direction and the desired direction
oppositeAngle = (tankAngle + 180) % 360;
minAngle2 = Math.Abs(Math.Min(oppositeAngle - desiredAngle, desiredAngle - oppositeAngle));
// get the smaller of two to rotate to
if (minAngle1 < minAngle2) {
// we know that we should rotate the current direction to the desired direction
} else {
// rotate the opposing direction to the desired direction
}
Note you'll need to play with your rotation signs to ensure you're rotating the right way. Also, I've assumed you know your rotation angles, if you have vectors you can simplify this a little bit by using the dot product between the two vectors instead of the angle for comparisons.
Is your problem with the direction of movement based on the angle they have rotated?
Vector2 moveDir = new Vector2(Math.Cos(rotation), Math.Sin(rotation));
position += (moveDir * speed);
Speed here would be a number for how fast you want to move in that direction. position is another Vector2 for the position of the sprite. As Tchami says you can draw it with the rotation using the SpriteBatch.Draw overload. Rotation for the the Cos and Sin methods should be in radians but I think Draw should be in degrees if I remember correctly. MathHelper.ToRadians(degrees) and MathHelper.ToDegrees(radians) should solve that.
There is lots of XNA tutorials and examples on the site http://creators.xna.com/en-US/education/catalog/