Reverse movement done with transform.RotateAround() - unity3d

I am making a third person mobile game with the help of joysticks. I have it set up where joystick.vertical moves the character forward or backwards depending on where he is looking and joystick.horizontal turns the character. Since the camera is parented to the character the camera always stays behind the character.
Swiping across the screen rotates the camera around the player with a touch panel using Camera.main.transform.RotateAround() function and the transform.LookAt() ensures I am looking at my character always.
My issue: I would like when the swipe is let go the camera to return to its original position behind the character but in a smooth motion or at a set speed moving around the player.
My Solution 1: To make an empty gameObject parented to the character and place it in the position where I want the camera to revert back to and call this position when the mouse is let go.
float spanCamera = -Joystick.Horizontal;
Camera.main.transform.LookAt(rb.transform.position);
if (spanCamera != 0)
Camera.main.transform.RotateAround(rb.position, Vector3.up, spanCamera * Time.fixedDeltaTime * spanSpeed);
else if (Input.touchCount <= 1)
{
float var6 = var5 * Time.deltaTime;
Camera.main.transform.position = camPos.transform.position;
Camera.main.transform.LookAt(camLookAt.transform.position);
}
This piece of code moves the camera back to the start position immediately without smoothing.
Solution 2: use a Vector3.MoveTowards() instead
// Camera.main.transform.position = camPos.transform.position;
Camera.main.transform.position = Vector3.MoveTowards(Camera.main.transform.position, camPos.transform.position, var6);
This code allows me to smoothly move to the start position in a straight line. I want it to go around the player.
So I tried a different method where I assign a float value 1 if the camera turns right and check if the rotate button is let go and if the value is 1 within an if block.
public float axisDir;
...
else if (spanCamera == 0 && axisDir == 1)
{
Camera.main.transform.RotateAround(rb.position, Vector3.up, -1 * Time.fixedDeltaTime * spanSpeed);
}
But this results in an infinite spin because I do not know how to check if the desired position has been reached.
I hope someone can help. This is quite a long post. :(

You could have an dummy gameObject as a child of the player, and the camera as a child of the dummy.
That way, the camera is looking at the centre of the gameObject: where the player is. The camera would also rotate with the player, so it would always be behind the player.
Now, you know that when Mathf.Approximately(dummy.transform.localEulerAngles.y, 0.0f), the camera is behind the player. [1][2]
Knowing that, you can check when the player stopped swiping and start slowly rotating it back.
// If the player let go and camera is not behind the player
if (!playerIsSwiping && !Mathf.Approximately(dummy.transform.localEulerAngles.y, 0.0f))
{
// Slowly rotate until the camera is behind the player
dummy.transform.RotateAround(Vector3.zero, Vector3.up, rotationSpeed * Time.deltaTime);
}

try this buddy :
// Maximum turn rate in degrees per second.
public float turningRate = 30f;
// Rotation we should blend towards.
private Quaternion _targetRotation = Quaternion.identity;
// Call this when you want to turn the object smoothly.
public void SetBlendedEulerAngles(Vector3 angles)
{
_targetRotation = Quaternion.Euler(angles);
}
private void Update()
{
// Turn towards our target rotation.
transform.rotation = Quaternion.RotateTowards(transform.rotation, _targetRotation, turningRate * Time.deltaTime);
}
i found it here
from my own experience using LERP works quite well, you lookin for a smooth transition, or between two points, known as interpolation, in this case linear interpolation.

Related

Rotating player is messing up my movement

I wrote a simple player movement script which moves my player like this:
private void MovePlayer()
{
// Initialize Directions For Player Movement
movement = transform.right * horizontal * playerSpeed + transform.forward * vertical * playerSpeed;
// Move Player
rb.AddForce(movement, ForceMode.Acceleration);
}
and I am trying to rotate my player towards the axes, for example if the player is pressing a the horizontal will be -1 and I want to rotate my player left horizontal * 90f, now when I try this, my horizontal axis is acting like my vertical, if I press A it will bring my player backwards, if I press D it will do the same thing, this is how I rotate the player:
// buggy code:
private void RotatePLayerTowardsAxis()
{
// Rotate PLayer Horizontaly
transform.rotation = Quaternion.Euler(0f, horizontal * 90, 0f);
}
is there a way I can do this?
Edit:
The vertical is still pushing me up and down.
First, it is important to check if you are looking at the scene in Local or Global view. Check your axes in Local mode:
If your character model faces towards the blue axis, then everything should be okay.
If you want to rotate your character only by 90 degrees all the time, then it can be done somehow like this:
transform.rotation = Quaternion.Euler(0, 90, 0);
You can use the following as well, but this might not fit your needs:
transform.Rotate(transform.up, 90);
This will make your character rotate by 90 degrees AROUND the up axis. If you want it to rotate always around the world up axis:
transform.Rotate(Vector3.up, 90);
However, transform.rotation = Quaternion.Euler(0, 90, 0); might be better for you, as it always "resets" the rotation when you overwrite it. This will make the character fixed to a direction. So if you press left, the charater will always look into the left by 90 degree. And if you press right after the left turn, your character will do a 180° turn instead of looking forward. I hope you get what I'm trying to say. This means, that your character will be bound to the world axis instead of its own. To modify this (if you want to), write something like this:
transform.rotation += Quaternion.Euler(0, 90, 0);
Hope I could help!

How to make a model appear in front of AR Camera after the session starts using ARFoundation?

I was looking to update the ARcamera position.I am doing ImageTracking project.It detects an image and a corresponding prefab is shown in front of the camera.It starts playing an animation.After the animation I want the prefab to come really close towards the camera.When I give the code prefab.position=ARcamera.position; after animation code,I think the prefab goes to the initial position where the ARCamera was when the app had started that is (0,0,0).
How to make the prefab come really close towards the front camera.
speed = 10f;
float step = speed * Time.deltaTime;
Showprefabs.transform.GetChild(0).position = Vector3.MoveTowards(Showprefabs.transform.GetChild(0).position,
new Vector3(Arcam.transform.position.x, Arcam.transform.position.y + 0.2f,
Arcam.transform.position.z + 6.3f), step);
//The values 0.2f and 6.3f I added using the Editor to make the prefab come near the camera(But in world position it is different.)
First of all I hope by "prefab" you mean already Instantiated GameObject. It makes no sense to move a prefab ;)
You tried to calculate the target position but did it with World-Space coordinates.
You probably want to do something like
var targetObject = Showprefabs.transform.GetChild(0);
var currentPosition = targetObject.position;
var targetPosition = Arcam.transform.position
// Place it 60cm in front of the camera
+ Arcam.transform.forward * 0.6f
// additionally move it "up" 20cm perpendicular to the view direction
+ Arcam.transform.up * 0.2f;
targetObject.position = Vector3.MoveTowards(currentPosition, targetPosition, step * Time.deltaTime);
If you want that movement a bit smoother so it moves slower if already close and faster if further away you might be interested in rather using Vector3.Lerp here
public float smoothFactor = 0.5f;
targetObject.position = Vector3.Lerp(currentPosition, targetPosition, smoothFactor);
Where a smoothFactor of 0.5 reads: Every frame set the object to a position in the center of the currentPosition and targetPosition. A value closer to 0 results in slower movement, closer to 1 in faster reaching the targetPosition.
Note that actually this approach will never really fully arrive at the targetPosition but only come very very close but usually this doesn't matter in AR where the Camera constantly moves a bit anyway.

Eliminating camera jitters caused by repositioning camera within defined bounds

This is the image of what I'm trying to achieve, in a 3D space. I want the object to follow my finger within the green zone, but stay on the edge of the green zone if I move my finger outside of it. I have achieved this with the code below, but when moving my finger around the red zone a lot of jitters and clipping occurs as the object keeps snapping back within it's bounds. The jitters I'm seeing are caused when holding my finger in the red zone out of the players circle bounds. Instead of being "stuck" in the bounds the player is trying to continue and then being positioned back within the bounds, causing jitters. I'm looking for a way to limit the movement of the player within the bounds without having to reset it's position. My main camera is attached to the moving object so it's important that I eliminate the jitters. How can I smooth this out?
public class Player : MonoBehaviour
{
public Camera movementCam;
readonly float radius = 0.45f;
readonly float speed = 3f;
Ray firstTouchPos;
Vector2 playerPos;
[SerializeField] Vector3 targetPosition;
readonly float followDelay = 20f;
void Update()
{
if (Input.GetMouseButtonDown(0))
{
firstTouchPos = movementCam.ScreenPointToRay(Input.mousePosition);
playerPos = transform.position;
}
if (Input.GetMouseButton(0))
{
Ray currentTouchPos = movementCam.ScreenPointToRay(Input.mousePosition);
Vector2 direction = currentTouchPos.origin - firstTouchPos.origin;
float distance = Vector3.Distance(transform.position, Vector3.zero);
targetPosition = distance >= radius ? (Vector3) . (direction.normalized * radius) : (Vector3)(playerPos + direction * speed);
}
transform.position = Vector3.Lerp(transform.position, targetPosition, followDelay);
}
}
Your issue is incorrectly clamping, a simple fix would be:
if (Input.GetMouseButton(0))
{
Ray currentTouchPos = movementCam.ScreenPointToRay(Input.mousePosition);
Vector2 direction = currentTouchPos.origin - firstTouchPos.origin;
float distance = Vector3.Distance(transform.position, Vector3.zero);
targetPosition = (Vector3)(playerPos + direction * speed);
if (targetPosition.sqrMagnitude > radius * radius) //if our calculated position is greater than the radius...
targetPosition = targetPosition.normalized * radius; //set our calculated position to be exactly on the radius.
}
The jitter was caused by your object leaving the radius one frame, and on the next frame would be clamped back to the radius, only for it to attempt to move outside the radius again the next frame.
This way removes the ternary operator, which means it will behave consistently across frames, rather than switching between clamp and movement each frame.
Here are some additional pieces of advice for this issue, once you fix the above problem:
You should multiply speed and followDelay by time.deltaTime in order to smooth them across frames correctly.
You should probably apply your camera motion during LateUpdate() instead of Update(), LateUpdate() happens after all your updates happen, what can happen is during Update() objects can move around before and after your camera code is called, causing it to behave slightly inconsistently from frame to frame, applying the motion in LateUpdate() to the camera means your camera moves only when all your objects have 'settled' into place after their update, making it behave more consistently.
Additionally you're technically using Lerp() wrong here, it shouldn't cause jitter but it's not exactly how lerp should be used. Are you sure you don't want Vector3.MoveTowards() instead?

Rotating a 3D character on when they move

I want to start with a little 3D platformer on Unity. When I move, I want the character looking to the moving direction. So when I press Left/"A" I want the character instantly turning left and walking forward. Same for the other directions. The problem is that the character turns back to the default rotation when I leave the key.
The important code:
private void FixedUpdate()
{
float inputX = Input.GetAxis("Horizontal"); // Input
float inputZ = Input.GetAxis("Vertical"); // Input
if (GroundCheck()) // On the ground?
{
verticalVelocity = -gravity * Time.deltaTime; // velocity on y-axis
if (Input.GetButtonDown("Jump")) // Jump Key pressed
{
verticalVelocity = jumpPower; // jump in the air
}
}
else // Player is not grounded
{
verticalVelocity -= gravity * Time.deltaTime; // Get back to the ground
}
Vector3 movement = new Vector3(inputX, verticalVelocity, inputZ); // the movement vector
if (movement.magnitude != 0) // Input given?
{
transform.rotation = Quaternion.LookRotation(new Vector3(movement.x, 0, movement.z)); // Rotate the Player to the moving direction
}
rigid.velocity = movement * movementSpeed; // Move the character
}
The second thing is, at
transform.rotation = Quaternion.LookRotation(new Vector3(movement.x, 0, movement.z));
there is 0 on the y-axis. It says the viewing Vector is zero. When I pass in another number like movement.y the character tilts to the floor. So I do not know what to pass in there.
As for resetting when you let go of the key: your line
if (movement.magnitude != 0) // Input given?
is a good idea, but there's a good chance your controller is reporting slightly off of 0, so your character's direction will change even when you're not actually moving. I would change this to
if (movement.magnitude >.1f) // Input given?
or some other number close to (but not exactly) zero. While working on this, I would add Debug.Log(movement.magnitude); to this function and make sure that the values are in the range you expect.
On the second topic:
while it is important to have verticalVelocity in your movement vector for when you apply it to rigidBody.velocity, you don't want it in your character facing vector. If you want your character to only look in a single plane, it makes perfect sense to only give it two dimensions to consider; adding a third dimension would make it look at the sky or the ground as you mentioned. Furthermore, I would change your input-checking line to use this as well, because you only want to change facing based on whether the character is moving horizontally or not. This would make your code look something like this:
Vector3 movement = new Vector3(inputX, verticalVelocity, inputZ); // the movement vector
Vector3 horizontalMovement = new Vector3(inputX, 0f, inputZ);
if (horizontalMovement.magnitude != 0) // Input given?
{
transform.rotation = Quaternion.LookRotation(horizontalMovement); // Rotate the Player to the moving direction
}
rigid.velocity = movement * movementSpeed; // Move the character
And one final note, when you are grounded, you might want to set verticalVelocity to 0, rather than -gravity*deltaTime. This error may not be visible (the physics engine will push your character back up out of the floor), but if the user alt-tabs and there's too long between frames, your character will teleport through the floor!
Good luck.

Sprite character slides back when near edge of other collider

I am making a 2D game in Unity. I have added a 2D box collider and a circle collider as trigger on my sprite character. The platform on which the character is standing also have a 2D box collider. So, when my character moves near edge of platform, it experiences a force or something that pulls it away from the edge. You can think it as a protective force that helps your character not falling down the plane but the problem is that this force is not part of game and that's why it should not be there. Following is the code I am using to move my character:
// call this method to move the player
void Move(float h)
{
// reduces character velocity to zero by applying force in opposite direction
if(h==0)
{
rigidBody.AddForce(new Vector2(-rigidBody.velocity.x * 20, 0.0f));
}
// controls velocity of character
if(rigidBody.velocity.x < -topSpeed || rigidBody.velocity.x > topSpeed)
{
return;
}
Vector2 movement = new Vector2 (h, 0.0f);
rigidBody.AddForce (movement * speed * Time.deltaTime);
}
Here is image of properties.
If I keep pushing the character it will fall off the edge but if I stop just by edge the unwanted protective force pulls it back on plane.
Also, if the character bumps into another 2D box collider, it bounces back instead of just falling down.
EDIT- Bouncing effect arises mostly when player bump into other objects while jumping. Code for jumping is
void Update()
{
// The player is grounded if a linecast to the groundcheck position hits anything on the ground layer.
grounded = Physics2D.Linecast(transform.position, groundCheck.position, 1 << LayerMask.NameToLayer("Ground"));
// If the jump button is pressed and the player is grounded then the player should jump.
if(Input.GetButtonDown("Jump") && grounded)
jump = true;
}
void Jump()
{
if (jump)
{
jump = false;
rigidBody.AddForce (Vector2.up * jumpSpeed * Time.deltaTime);
}
}
The problem lies in how you're implementing the "drag" force that slows your player down to zero. Because game physics happens in steps rather than continuously, your opposing force can overshoot and briefly cause the character to move in the opposite direction.
In this situation your best bet is to multiply your speed by some fraction each frame (likely between 0.8 and 0.95), or to use Mathf.Lerp to move your X velocity towards zero.
rigidbody.velocity += Vector2.right * rigidbody.velocity.x * -0.1f;
OR
Vector3 vel = rigidbody.velocity; //Can't modify rigidbody.velocity.x directly
vel.x = Mathf.Lerp(vel.x, 0, slowRate * Time.deltaTime);
rigidbody.velocity = vel;
Also give some thought to doing your movement/physics related code within FixedUpdate() instead of Update() and using Time.fixedDeltaTime instead of Time.deltaTime. This will allow for more consistent results independent of framerate.