I want you to turn the cube to the targeted angle. But as you will turn every angle, the concept of "Space.World" is confused. How can I integrate "Space.World" into the "RotateToward" function.
I need to use "localPosition & eulerAngles" in code ?
etc:
targetRotate = new Vector3(0,180,0);
transform.rotation = Quaternion.RotateTowards (getRotate (), Quaternion.Euler (targetRotate), rotateTime * Time.deltaTime);
Code in Gist
Related
I have a skeleton game object which I make move by increasing its velocity on the Update function, like this:
body.velocity = new Vector2((isFacingLeft ? -1 : 1) * speed, body.velocity.y);
Which is also controlled by a direction isFacingLeft, which determines movement for the skeleton from left to right.
int direction = isFacingLeft ? -1 : 1;
But, since my skeleton is in a platform, I want to use a ray cast to ensure I detect whenever no platform is in front (so the cast points diagonally down in front of the skeleton), so I prepare a few variables to ensure I have a proper position for the ray cast. Then, if no floor has been found, the isFacingLeft variable is flipped, so the skeleton moves in the opposite direction as it approaches an edge:
Vector2 beginFloorCast = new Vector2(transform.position.x + ((enemyWidth / 2) * direction), transform.position.y - enemyHeight / 2);
Vector2 floorCastDirection = transform.TransformDirection(new Vector2(1 * (direction), -1));
float floorCastLength = 1f;
RaycastHit2D hit = Physics2D.Raycast(beginFloorCast, floorCastDirection, floorCastLength);
if (!hit) {
isFacingLeft = !isFacingLeft;
}
While this all works, I am now trying to draw a debug ray so I can visualize in debug mode how long the floor ray is (and so I can use this in the future to detect if the player is in range of the skeleton with another ray), so I use the following:
Debug.DrawRay(beginFloorCast, floorCastDirection.normalized * floorCastLength, Color.green, 5f);
This also works, but in the Scene mode, the ray is drawn once for every Update call:
Is there a way for me to clear the debug screen after the Update function is done? Or what could I change in my code to make sure I only call it once and that the ray follows the skeleton?
First off: I am very new to Unity, as in VERY new.
I want to do the following: I want to rotate a cube around a stationary point (in my case a camera) with a radius that is adjustable in the inspector. The cube should always have its Z-axis oriented towards the camera's position. While the cube is orbiting around the camera, it should additionally follow a sine function to move up and down with a magnitude of 2.
I have some working code, the only problem is an increase in distance over time. The longer the runtime, the higher the distance between the cube and the camera.
Here is what I currently have:
void Awake()
{
cameraPosition = GameObject.FindGameObjectWithTag("MainCamera").transform;
transform.position = new Vector3(x: transform.position.x,
y: transform.position.y,
z: cameraPosition.position.z + radius);
movement = transform.position;
}
I instantiate some variables in the Awake()-method and set the cube's position to where it should be (do you instantiate in Awake()?). I'll use the Vector3 movement later in my code for the "swinging" of the cube.
void Update()
{
transform.LookAt(cameraPosition);
transform.RotateAround(cameraPosition.position, cameraPosition.transform.up, 30 * Time.deltaTime * rotationSpeed);
MoveAndRotate();
}
Here I set the orientation of the cube's z-axis and rotate it around the camera. 30 is just a constant i am using for tests.
void MoveAndRotate()
{
movement += transform.right * Time.deltaTime * movementSpeed;
transform.position = movement + Vector3.up * Mathf.Sin(Time.time * frequency) * magnitude;
}
To be quite frank, I do not understand this bit of code completely. I do however understand that this includes a rotation as it moves the cube along it's x-axis as well as along the world's y-axis. I have yet to get into Vector and matrices, so if you could share your knowledge on that topic as well I'd be grateful for that.
It seems like I have found the solution for my problem, and it is an easy one at that.
First of all we need the initial position of our cube because we need to have access to its original y-coordinate to account for offsets.
So in Awake(), instead of
movement = transform.position;
We simply change it to
initialPosition = transform.position;
To have more readable code.
Next, we change our MoveAndRotate()-method to only be a single line long.
void MoveAndRotate()
{
transform.position = new Vector3(transform.position.x,
Mathf.Sin(Time.time * frequency) * magnitude + initialPosition.y,
transform.position.z);
}
What exactly does that line then? It sets the position of our cube to a new Vector3. This Vector consists of
its current x-value
our newly calculated y-value (our height, if you want to say so) + the offset from our original position
its current z value
With this, the cube will only bop up and down with distancing itself from the camera.
I have also found the reason for the increase in distance: My method of movement does not describe a sphere (which would keep the distance the same no matter how you rotate the cube) but rather a plane. Of course, moving the cube along a plane will automatically increase the distance for some points of the movement.
For instantiating variables in Awake it should be fine, but you could also do it in the Start(){} Method that Unity provides if you wanted to.
For the main problem itself I'm guessing that calling this function every frame is the Problem, because you add on to the position.
movement += transform.right * Time.deltaTime * movementSpeed;
Would be nice if you could try to replace it with this code and see if it helped.
movement = transform.right * Time.deltaTime * movementSpeed;
In the image above
the red vector is the spider's forward vector
the blue vector is the vector representing the direction between the spider and it's target
In the code below, orientation is a vector that's representing the normal of the terrain, so that the spider gets aligned to it:
Vector3 orientation = GetTerrainNormal();
Quaternion rotationNeeded = Quaternion.FromToRotation(Vector3.up, orientation);
transform.rotation = Quaternion.RotateTowards(
transform.rotation,
rotationNeeded,
RotationSpeed * Time.deltaTime
);
My issue is that I cannot manage to make the spider face its target... When I add any code that would make it rotate towards it, then it's not aligned with the terrain's normals anymore, it says straight...
So basically, how can I make the spider rotate on the Y world axis (I think), while still then being rotated to match the slope?
Full answer
In case it helps someone else, here's the full answer:
Vector3 orientation = GetTerrainNormal();
Vector3 directionToTarget = (target.position - transform.position).Y(0);
float d = Vector3.Dot(directionToTarget, orientation);
directionToTarget -= d * orientation;
if (directionToTarget.sqrMagnitude > 0.00001f) {
directionToTarget.Normalize();
Quaternion rotationNeeded = Quaternion.LookRotation(directionToTarget, orientation);
transform.rotation = Quaternion.RotateTowards(
transform.rotation,
rotationNeeded,
xRotationSpeed * Time.deltaTime
);
}
This answer on the unity forums was extremely helpful: https://forum.unity.com/threads/look-at-object-while-aligned-to-surface.515743/
Try this
Vector3 directionToTarget = target.transform.position - transform.position;
Quaternion rotationNeeded = Quaternion.LookRotation(directionToTarget, orientation);
First of all, I'm not sure why you need a code to orient the spider manually to the terrain. You can make the spider a Rigidbody and the Unity engine will take care of it for you.
Regardless, you want to rotate the spider around the local Y-Axis (this will keep the current orientation).
You can do this using transform.LookAt() (referring to the blue vector in the picture) (documented here) and passing the up vector as the 2nd argument.
I've been trying for some time now with different tutorials to get a nice firstperson (cockpit view) spaceship controll system. I tried using mouse only, keyboard only and combinations but I keep encountering the same problem with all tutorials. even this simple line of code does it:
transform.position += transform.forward * Time.deltaTime * 90f;
transform.Rotate( Input.GetAxis("Vertical"), Input.GetAxis("Horizontal"), 0.0f);
The problem I keep getting is that if I pitch its ok. it I yaw its ok. But If I do both (so I go diagonaly) it also rotates my ship on the Z axis and messes up my orientation. I tried locking the z rotation in the rigidbody but that does'nt help either. I tried making code myself alternating with apply torque and simply rotating, followed some tutorials including this one: Tutorial but keep getting the rotation problem.
What I want to make is a game that controlls like the old game Helbender
Does anyone of you know of a way that I can get spaceship controlls to work?
----EDIT-----
Got a bit further now. It doenst turn on my z axis anymore becouse I keep setting it to 0. Only problem now is that if I try to make a looping the ship flips around instead of nicely looping.
if (Input.GetKey("up"))
{
transform.Rotate(transform.right * -ShipPanSpeed * Time.deltaTime, Space.World);
}
if (Input.GetKey("down"))
{
transform.Rotate(transform.right * ShipPanSpeed * Time.deltaTime, Space.World);
}
if (Input.GetKey("left"))
{
transform.Rotate(transform.up * -ShipPanSpeed * Time.deltaTime,Space.World);
}
if (Input.GetKey("right"))
{
transform.Rotate(transform.up * ShipPanSpeed * Time.deltaTime,Space.World);
}
float z = transform.eulerAngles.z;
transform.Rotate(0, 0, -z);
You could always try to make one parent object for the Controls and then a child object (the spaceshit) that you can rotate for the pivot but not attach any movement beside rotation.
What i mean is that you can rotate the parent on the Y axis to make it rotate and move the transform forward or backward at the same time. If you want to pivot up or down you can transform forward at the sametime you transform up/down multiplied with the axis you want to pivot with
Example:
private void Update(){
//PARENT--------------------------------------------
// MOVING FORWARD AND BACKWARD
transform.position += transform.forward * Input.GetAxis("Vertical") * speed * Time.deltaTime();
// MOVING RIGHT AND LEFT
transform.position += transform.right * Input.GetAxis("Horizontal") * speed * Time.deltaTime();
//PIVOT UP AND DOWN
transform.position += transform.up * -Input.GetAxis("Mouse Y") * speed * Time.deltaTime();
//ROTATE AROUND THE Y AXIS
tranform.Rotate(0f, Input.GetAxis("Horizontal") * rotationspeed, 0f);
}
For the spaceship (child) for the pivot i would recommend you to make a emptyobject and set the chip to lookAt that object based on the input axis you use to move up/down and forward/backward.
Hope this helped or at least gave you a idea of how to make it :)
I have already this function from this question. I changed the sign of the rotation:
void rotateBotConnector()
{
Vector3 diff = (player.transform.position - botConnector.transform.position).normalized;
float rot_z = Mathf.Atan2(diff.y, diff.x) * Mathf.Rad2Deg;
botConnector.transform.localRotation = Quaternion.Euler(0f, 0f, -(rot_z - 90f));
}
But the problem is, that now my object follows the player on the XZ plane but when the rotation reaches a certain degree, left or right, the object stops to rotate towards my player.
For better understanding: http://imgur.com/vWaqc31
Why not just use:
var target : Transform;
transform.LookAt(Vector3(target.transform.position.x, target.transform.position.y, transform.position.z);
It seems a lot easier than using euler. This way you look at target's x & y but transform your z.
Also I'm no expert with euler but it seems like it is limited to a 90 degree turn and I think this may be the reason why:
Quaternion.Euler(0f, 0f, -(rot_z - 90f));
Unless you have absolute necessity to rotate via angles maybe you'd rather go with manipulating the forward vector of the object, it's easier to understand the logic this way:
void rotateBotConnector()
{
Vector3 targetForwad = botConnector.transform.position - player.transform.position;
targetForward.y= 0f;
targetForward.Normalize(); // <-- this is very expensive function try avoid using it whenever possible
botConnector.forward = Vector3.Lerp(botConnector.forward, targetForward, Time.deltaTime));
}
once again, if you are short on cpu cycles you may want to go for trying to calculate angles instead of vectors. But in most cases this is ok. (the code needs a spell checking)