I want to make an object (let's say a cube), rotate at a steady rate on the same axis that's it's moving on. So if it changes direction from X to Z then the rotation would lerp from X axis into the Z axis and then continue rotating on Z axis.
How would I achieve this? Here's what I have at the moment, the cube just rotates on the z axis back and forth within a certain degrees.
public float Angle;
public float Period;
void Update()
{
Animate();
}
void Animate()
{
_time = _time + Time.deltaTime;
float phase = Mathf.Sin(_time / Period);
transform.localRotation = Quaternion.Euler(new Vector3(0f, 0f, phase * Angle));
}
Just use
RotateAround
Note generally NEVER use Quaternion for any reason.
there are 1000s of questions on using RotateAround so just google. In your case it sounds like you'll be changing (lerping, whatever) the axis of rotation itself.
Related
I'm working on a top down concept where the gun revolves around the player and flips according to the side your crosshair is on (similar to ZERO Sievert). I'm trying to have my bullet sprite have the correct rotation when firing in relation to my players weapon.
Below is how I'm instantiating the bullet in a shooting script which fires the correct way but the sprite itself is not rotated correctly.
void Shoot()
{
GameObject bullet = Instantiate(bulletPrefab, firingPoint.position, firingPoint.rotation);
Rigidbody2D rb = bullet.GetComponent<Rigidbody2D>();
rb.AddForce(firingPoint.right * bulletForce, ForceMode2D.Impulse);
}
and in my weapon handling script this is my implementation of the weapon rotation, I am flipping the weapons y scale to correct the sprite for now.
private void FixedUpdate()
{
RotateWeapon();
if (crosshair.transform.position.x < 0)
{
FlipWeapon();
}
}
void RotateWeapon()
{
float AngleRad = Mathf.Atan2(crosshair.transform.position.y - currentWeapon.transform.position.y, crosshair.transform.position.x - currentWeapon.transform.position.x);
float AngleDeg = (180 / Mathf.PI) * AngleRad;
currentWeapon.transform.rotation = Quaternion.Euler(0, 0, AngleDeg);
}
void FlipWeapon()
{
currentScale = transform.parent.localScale;
currentScale.y *= -1;
currentWeapon.transform.localScale = currentScale;
}
I'm currently at a standstill on how to achieve this as most resources I've come across for top down shooting have the player turning up to a full 360 degrees where my player only faces left or right and the weapon itself only has a range of motion of 180 degrees on either side before its set to flip.
Maybe you can try and add an offset so when you Instantiate the bullet it will look something like this:
GameObject bullet = Instantiate(bulletPrefab, firingPoint.position, firingPoint.rotation + offset);
here offset will be a rotational x y z coordinate so you would want to rotate it on the z coordinate (try all of them until you fin the right one) and rotate it either -90 degrees or 90 deegrees. You might have to rotate it 180 degress but dont use 270 instead use -90. Trust me it will help in your later days in coding. Also make sure to set offset as a variable:
private Vector3 offset = 0, 0, -90;
!Remember you can change the x y z coordinates!
For a school assignment I am trying to make a tank point and shoot game, where I need align the tank to the plane normal using raycasting. But when I do this the Y axis rotaton gets locked and I can't rotate it any more.
The idea is that if a plane is angled, the tank is sticking to it and the transform.up is defined by the plane normal and the tank is able to go up and down the plane and also rotate on it.
This is the code.
public class PlayerController : MonoBehaviour
{
public GameObject player;
public float movementSpeed;
public float rotationSpeed;
RaycastHit hitinfo;
public float hoverHeight = 0.7f;
float offsetdistance;
//public Vector2 moveVal;
public Vector2 moveVal;
public Vector3 Dir;
public float moveSpeed;
//get OnMovie input and put it in a vector to be used later on
void OnMove(InputValue value)
{
moveVal = value.Get<Vector2>();
}
void Update()
{
//moves player
PlayerHover();
player.transform.Translate(new Vector3(0, 0, moveVal.y) * moveSpeed * Time.deltaTime);
player.transform.Rotate(0, moveVal.x * rotationSpeed * Time.deltaTime, 0, Space.Self);
}
void PlayerHover()
{
if (Physics.Raycast(transform.position, -Vector3.up, out hitinfo, 20f))
{
offsetdistance = hoverHeight - hitinfo.distance;
transform.up = hitinfo.normal;
transform.position = new Vector3(transform.position.x, transform.position.y + offsetdistance, transform.position.z);
}
}
You are probably using the wrong overload of transform.Rotate, you should probably be using:
public void Rotate(Vector3 axis, float angle, Space relativeTo = Space.Self);
Where the axis parameter should be the plane normal. Assuming you want to rotate around the plane normal
If you want to set the rotation directly you might need to use SetPositionAndRotation, you should be able to get the quaternion from LookDirection using the plane normal for the forward parameter, but you may need to play around with the axes or apply a 90-degree rotation to get the desired axis to point in the right direction.
In general if you want to rotate an object so that one axis matches up to some other axis you can:
Calculate the angle between the axes, i.e. compute the dot-product and apply the ACos function. Or use any built in methods.
Calculate an orthogonal vector by taking the cross-product between the two vectors
Use this axis and angle in the Rotate function above to produce the desired rotation. Or any other functions that produce a rotation that take an axis and angle.
Use the up-direction of your tank and the plane normal as input axes for the algorithm above if you want to rotate your tank to be orientated to the plane.
I'm working on a simple AR Vuforia application. How can I implement the rotation of an object along all three axes with one finger swipe?
The code I'm currently using has one bug: the rotation of the object depends on its local axes. For example, if I look at the object from the front, everything works as it should, but if I look at the object from the back side, the finger swipe upwards makes it rotate downwards and vice versa.
Here is this script:
public float rotSpeed = 30f;
void OnMouseDrag()
{
float rotX = Input.GetAxis("Mouse X")*rotSpeed*Mathf.Deg2Rad;
float rotY = Input.GetAxis("Mouse Y")*rotSpeed*Mathf.Deg2Rad;
transform.Rotate(Vector3.up, -rotX);
transform.Rotate(Vector3.right, -rotY);
}
This is not what I need, how can I rotate the object according to the finger swipe direction regardless of the angle from which I look at it?
Update
A simple non-AR example, which may help you understand what I need is an iOS game "Space Frontier 2". After a successful launch of the rocket, it lands on the planet and you can rotate the planet with your finger swipe.
Here is the video demo: https://youtu.be/OiNPP1WNIAI
This works nice regardless of your object's rotation, and regardless of your camera position relative to the object:
public float rotSpeed = 30f;
void OnMouseDrag()
{
float rotX = Input.GetAxis("Mouse X") * rotSpeed;
float rotY = Input.GetAxis("Mouse Y") * rotSpeed;
Camera camera = Camera.main;
Vector3 right = Vector3.Cross(camera.transform.up, transform.position - camera.transform.position);
Vector3 up = Vector3.Cross(transform.position - camera.transform.position, right);
transform.rotation = Quaternion.AngleAxis(-rotX, up) * transform.rotation;
transform.rotation = Quaternion.AngleAxis(rotY, right) * transform.rotation;
}
Make sure your camera has the "MainCamera" tag, or assign the camera externally if necessary.
I do not have the exact code with me right now.
But if you did not update your point of view coordinates, this should be the expected result.
Consider a real ball with 2 colors, blue and red, separated vertically.
When you are in front of it, seeing only the blue side, stroking it up will make the blue side go up and the red side appear from the bottom.
Now move behind it, seeing only the red side, and stroke it up again.
The blue face will go down and appear from the bottom.
Unity applies physics to virtual objects the same way we interact with real objects.
So you need to consider your camera position with the object orientation when you apply movements to it.
You need to apply a transformation matrix to your movement based on your camera location related to the object origin orientation.
I hope this is clear enough to put you on tracks to fix it.
I think you have to somehow clamp the rotation to have the desired behaviour. I wrote a script recently to do just that. I did a little modification though.
public float rotSpeed = 30f;
float ClampAngle(float _angle, float _min, float _max)
{
if (_angle < 0f) _angle = 360 + _angle;
if (_angle > 180f) Mathf.Max(_angle, 360 + _min);
return Mathf.Min(_angle, _max);
}
USAGE:
void RotateGameObject()
{
float h = Input.GetTouch(0).deltaPosition.x * Time.deltaTime * rotSpeed*Mathf.Deg2Rad;
float v = Input.GetTouch(0).deltaPosition.y * Time.deltaTime * rotSpeed*Mathf.Deg2Rad;
Vector3 rot = transform.rotation.eulerAngles + new Vector3(-v, h, 0f);
//Change the y & z values to match your expected behaviour.
rot.x = ClampAngle(rot.x, -5f, 20f);
//Clamp rotation on the y-axis
rot.y = ClampAngle(rot.y, -20f, 20f);
transform.eulerAngles = rot;
}
See if that works and of course, try to play with the values.
Im trying to get a sprite rotation by key input (arrow down or up).
The point is lifting the arrow (sprite) to choose the angle. Its like a system of a golf game, actually.
So far i tried:
void Update () {
if (Input.GetKey(KeyCode.UpArrow)){
transform.Rotate (Vector3.forward * -2); }
if (Input.GetKey(KeyCode.DownArrow)){
transform.Rotate (Vector3.forward * +2); }
}
I will need the angle, since it will be related to a "shot" part i will be doing next. My point is setting the right angle with the keys up and down.
I can move the "arrow" sprite with my code, but i cannot set the max angle (90), minimum (0) and get the angle to use in the shot ^^
Hard question to answer without just simply giving you the code. This code works by assuming your character's forward vector is actually it's right vector (common in 2d sprite games) in order to shoot in the other direction, rotate your objects y axis 180.
float minRotation = 0f;
float maxRotation = 90f;
float rotationSpeed = 40f; //degrees per second
//get current rotation, seeing as you're making a sprite game
// i'm assuming camera facing forward along positive z axis
Vector3 currentEuler = transform.rotation.eulerAngles;
float rotation = currentEuler.z;
//increment rotation via inputs
if (Input.GetKey(KeyCode.UpArrow)){
rotation += rotationSpeed * Time.deltaTime;
}
else if (Input.GetKey(KeyCode.DownArrow)){
rotation -= rotationSpeed * Time.deltaTime;
}
//clamp rotation to your min/max
rotation = Mathf.Clamp(rotation, minRotation, maxRotation );
//set rotation back onto transform
transform.rotation = Quaternion.Euler( new Vector3(currentEuler.x, currentEuler.y, rotation));
If you were making a golf game, you'd set the ball's velocity to be transform.right * shotPower
Currently I have the following code, and it works 100% for a 3D game, but I can't get it to work for a 2D game.
What it is supposed to do, is once the object gets to the waypoint, it is supposed to rotate towards the new waypoint. What is actually happening is that it is rotating around the x and y axis, and not the z axis. What can I do to make it only rotate on the z axis? The object is supposed to turn as it moves forward based on the turn speed. It shouldn't be an instant turn, unless the turnspeed is a high number. But anyways, again I ask how do I get this code to only roate on the z axis?
void Update () {
if(toWaypoint > -1){
Vector3 targetDir = wayPoints[toWaypoint].position - transform.position;
Vector3 newDir = Vector3.RotateTowards(transform.forward, targetDir, turnSpeed * Time.deltaTime, 0.0f);
transform.rotation = Quaternion.LookRotation(newDir);
}
if(!usePhysics && toWaypoint != -1){
transform.Translate(Vector3.forward * Time.deltaTime * speed);
next();
}
}
Look rotation is not dependable for 2D games as the forward axis is different. One workaround is to parent the sprite to an empty GameObject with the z axis (blue arrow) pointed in the direction that the sprite will be rotating.
Looks like you're using Unity3D, which leaves me wondering why you're messing around with the Z-axis in the first place if you're making a game in 2D editing mode. The Z-axis does literally nothing in that mode, unless you set your two axes to include it somehow. My suggestion to you is to switch to 2D editing if you haven't already, then use Vector2s instead of Vector3s.
Also, try using one of the other axes as your axis of rotation (transform.right or .up instead of .forward).
I found what I was looking for:
void Update () {
if(toWaypoint > -1){
Vector3 vectorToTarget = wayPoints[toWaypoint].position - transform.position;
float angle = Mathf.Atan2(vectorToTarget.y, vectorToTarget.x) * Mathf.Rad2Deg;
Quaternion q = Quaternion.AngleAxis(angle, Vector3.forward);
transform.rotation = Quaternion.Slerp(transform.rotation, q, Time.deltaTime * turnSpeed);
}
if(!usePhysics && toWaypoint != -1){
transform.Translate(Vector3.right * Time.deltaTime * speed);
next();
}
}