Issue with smooth camera zoom in Unity - c#

I am trying to make my camera smoothly zoom in and out whenever I use a mouse scroll wheel, but for some reason it zooms instantly and not smoothly.
This is how I update the zoom:
[SerializeField, Range(10, 100)] float scrollSpeed = 10f;
[SerializeField] Vector2 zoomAmount = Vector2.zero;
private float ScrollWheel
{
get { return Input.GetAxis("Mouse ScrollWheel"); }
}
private new Camera camera = null;
void Update()
{
if (camera == null) return;
UpdateZoom();
}
void UpdateZoom()
{
pos = camera.transform.position;
pos = Vector3.Lerp(pos, new Vector3(pos.x, pos.y - scrollSpeed * 10 * ScrollWheel, pos.z), Time.deltaTime * 2);
pos.y = Mathf.Clamp(pos.y, zoomAmount.x, zoomAmount.y);
camera.transform.position = pos;
}

I think you're a little confused about Lerp (I was confused in the same way too when I started using it). When you pass in a 0 for the time argument (the third argument), it will return your "starting" vector. When you pass a value of 1 or more for the time argument, it will return your "ending" vector. However, if you're passing Time.deltaTime * 2, then you'll be returning approximately the same interpolated vector every frame. Lerp doesn't "track" how far it's already interpolated, so by passing in the same time value every frame, Lerp will never actually return your ending vector. So rather than passing Time.deltaTime * 2, you'd need to do something like this
float interpolatedTime = 0;
void Update()
{
var myVector = Vector3.Lerp(vector1, vector2, this.interpolatedTime);
this.interpolatedTime += Time.deltaTime;
}
How about something like this for your camera:
float zoomTime;
float zoomTarget;
float lastScrollWheelDirection;
void Update()
{
// If this camera is currently zooming in and the player started zooming
// out (or vice versa), reset the amount that is remaining to be zoomed
if ((this.lastScrollWheelDirection > 0 && this.ScrollWheel < 0) ||
(this.lastScrollWheelDirection < 0 && this.ScrollWheel > 0))
{
this.zoomTarget = 0;
}
if (this.ScrollWheel != 0)
{
this.lastScrollWheelDirection = this.ScrollWheel;
}
// zoomTarget is the total distance that is remaining to be zoomed.
// Each frame that the scroll wheel is moved, we'll add a little more
// to the distance that we want to zoom
zoomTarget += this.ScrollWheel * this.scrollSpeed;
// zoomTime is used to do linear interpolation to create a smooth zoom.
// Each time the player moves the mouse wheel, we reset zoomTime so that
// we restart our linear interpolation
if (this.ScrollWheel != 0)
{
this.zoomTime = 0;
}
if (this.zoomTarget != 0)
{
this.zoomTime += Time.deltaTime;
// Calculate how much our camera will be moved this frame using linear
// interpolation. You can adjust how fast the camera zooms by
// changing the divisor for zoomTime
var translation = Vector3.Lerp(
new Vector3(0, 0, 0),
new Vector3(0, this.zoomTarget, 0),
zoomTime / 4f); // see comment above
// Zoom the camera by the amount that we calculated for this frame
this.transform.position -= translation;
// Decrease the amount that's remaining to be zoomed by the amount
// that we zoomed this frame
this.zoomTarget -= translation.y;
}
}

Related

How to scale a gameObject with pinch?

How do I scale gameObject (cube) with a pinch (2 fingers) in Android/iOS?. If the pinch is expanding, then the cube's scale (x, y, z) gets bigger and if the pinch is closing down, then the cube's scale gets smaller.
I have a script that was for mouse drag but only scales for 2 axis (x, y).
public class Drag : MonoBehaviour
{
Vector3 lastMousePosition;
float scaleSensitivity = 2f;
void Update()
{
if (Input.GetMouseButtonDown(0)) {
lastMousePosition = Input.mousePosition;
}
if (Input.GetMouseButton(0)) {
transform.localScale += ((Input.mousePosition - lastMousePosition) * Time.deltaTime * scaleSensitivity);
lastMousePosition = Input.mousePosition;
}
}
}
Take a look at Input.Touches : Input.Touches and use difference (Input.Touches[0] - Input.Touches[1]).magnitude, fixing every frame that difference. If it's becoming bigger with every frame, that means user is scaling up, else if it's becoming smaller, that means user is scaling down
float? _prevFrameDiff;
void Update()
{
if (Input.touches.Length < 2)
{
_prevFrameDiff = null;
return;
}
var diff = (Input.touches[0].position - Input.touches[1].position).magnitude;
if (!_prevFrameDiff.HasValue)
{
_prevFrameDiff = diff;
return;
}
else
{
var scaleFactor = diff / _prevFrameDiff.Value;
this.transform.localScale = Vector3.one * scaleFactor;
}
}

Reduce input sensitivity in unity

I've made an Isometric character controller so it can move and head on an isometric based perspective. The problem is that when I try to move using 2 keys (W + D, A + S...) and release those keys, the player tends to face the very last key that was released, so it is difficult to head a diagonal direction. This makes the character flip its rotation in the very last moment the keys are released.
I've been thinking of using a kind of sleep or coroutine checking if two keys were pressed and released in a short period of time just not rotate it.
There exist any not too rustic solution for this?
Here is my code (I just copied it from here: https://www.studica.com/blog/isometric-camera-unity)
private void SetIsometricDirections() {
vertical = Camera.main.transform.forward;
vertical.y = 0;
vertical = Vector3.Normalize(vertical);
horizontal = Quaternion.Euler(new Vector3(0, 90, 0)) * vertical;
}
private void Move() {
Vector3 horizontalMovement = horizontal * moveSpeed * Time.deltaTime * Input.GetAxis("HorizontalKey");
Vector3 verticalMovement = vertical * moveSpeed * Time.deltaTime * Input.GetAxis("VerticalKey");
Vector3 heading = Vector3.Normalize(horizontalMovement + verticalMovement);
Heading(heading);
transform.position += (horizontalMovement + verticalMovement);
}
private void Heading(Vector3 heading) {
transform.forward = heading;
}
The heading trick it's in the "Heading" method, obviously.
I finally found a solution.
I'll post it just in case any one else needs it in the future.
I calculate the current rotation based on the movement.
private void SetRotation() {
currentRotation = Quaternion.LookRotation(movement);
}
Then, I created a second Quaternion to store the last rotation if is not the same than the current. I also use a counter to store the time a rotation has been faced before stopping the movement or changing the direction.
private void CheckSameRotation() {
if (lastRotation != currentRotation || movement == Vector3.zero) {
sameRotationTime = 0;
lastRotation = currentRotation;
}
else {
sameRotationTime += Time.deltaTime;
}
}
Then, I used a bool to check if the time is high enough to make the rotation happen.
private void TimeAtSameRotation() {
canRotate = (sameRotationTime < 0.015f) ? false : true;
}
And then, I finally rotate the object if the movement is not zero and the condition "canRotate" is true.
private void Rotate() {
if (movement != Vector3.zero && canRotate) {
transform.rotation = currentRotation;
}
}

Keeping my object from rolling out of the screen

I am using the tilt function on a phone to control an object to roll left and right. I do not want it roll anything beyond the screen width.
As in the simple illustration below, the dotted lines represent the width of the screen. The 'O' is the object and the Max signs indicate the maximum point the object is allowed to roll to.
Max--------O--------Max
But currently using my code, the object still rolls out of the screen. Also tried testing both height n width and ended up the same result where the object rolls out of the screen. Please advice what I am doing wrong. Thank you.
public float speed = 10.0F;
void Update()
{
Vector3 dir = Vector3.zero;
dir.x = Input.acceleration.x;
if (dir.sqrMagnitude > 1)
dir.Normalize();
dir *= Time.deltaTime;
if (!(Mathf.Round(dir.x) > Mathf.Round(Screen.width/2)) || !(Mathf.Round(dir.x) < -Mathf.Round(Screen.width/2)))
{
transform.Translate(dir * speed);
}
}
**Updated
public float speed = 10.0F;
void Update()
{
Vector3 dir = Vector3.zero;
dir.x = Input.acceleration.x;
if (dir.sqrMagnitude > 1)
dir.Normalize();
dir *= Time.deltaTime;
//transform.Translate(dir * speed);
if (transform.position.x < 0)
{
transform.position = new Vector3(0, this.transform.position.y, this.transform.position.z);
}
else if (transform.position.x > Screen.width)
{
transform.position = new Vector3(Screen.width, this.transform.position.y, this.transform.position.z);
}
else
{
transform.Translate(dir * speed);
}
}
I think thereare several ways you can go about checking the transfomrs position.
first off if you were using a 2d camera you could use a method like
leftBounds = Camera.x - (Camera.pixelWidth/2);
however because ortho camera angles are not set at any particulare size at x distace from camera they are hard to calculate.
i have seen some instances were coliders on the camera just outside the render rand were placed as camera children
adding a colision mask to only affect the appropriate game object would be best.

Camera Jitters Matrix Camera

I am using a translation matrix to move the screen but when the player collides with an object the player will jitter as if it wants to be in 2 places at once. It looks like velocity wants to keep going down while the block pushes it up, how would I go by fixing this?
Video: Here
Camera class:
class Camera
{
public Vector2 Position;
Viewport viewPort;
public Vector2 cameraBounds;
public float wasGround;
public Matrix Transform()
{
var translationMatrix = Matrix.CreateTranslation(new Vector3(-Position.X, -Position.Y, 0));
return translationMatrix;
}
public Player thing(Player player)
{
cameraBounds.X = player.Position.X - Game1.offset.X;
if (cameraBounds.X > 0)
Position.X = player.Position.X - Game1.offset.X;
else
Position.X = 0;
//Problem
cameraBounds.Y = player.Position.Y - Game1.offset.Y;
if (cameraBounds.Y > 0)
{
Position.Y = player.Position.Y - Game1.offset.Y;
if (player.goingUp == false && (wasGround != player.ground))
Position.Y = player.ground - Game1.offset.Y;
wasGround = player.ground;
}
else
Position.Y = 0;
return player;
}
public Camera(Viewport viewport)
{
viewPort = viewport;
}
}
I tried to fix the problem by adding in player goingUp and ground if statements but that did not help.
I solved it. It is about sequence of operations. Just move method camera.thing() as shown below:
// TODO: Add your update logic here
HandleInput(Keyboard.GetState());
player.Update(gameTime);
// delete from here
Time += (float)gameTime.ElapsedGameTime.TotalSeconds;
foreach (Block b in Blocks)
{
player = b.BlockCollision(player);
}
// place here
camera.thing(player);
Explanation: You have to set camera position after all collisions have done.
what i can see while you stand still on some object, velocity changes. so try to convert camera position to integer. or make velocity exact 0 if is near 0.
cameraBounds.X = cInt(cameraBounds.X)
cameraBounds.y = cInt(cameraBounds.y)

Enemy following player in XNA and stop within 20 pixels

I'm trying to get my enemies to follow the player and stop within 20 pixels, I have tried a number of algorithms including the Vector2.Lerp(); method to try and fix this but it keeps breaking the build. Any help would be greatly appreciated. The code is below.
public void Update(GameTime gameTime)
{
if (this.IsAlive)
{
float elapsed = (float)gameTime.ElapsedGameTime.TotalSeconds;
double distanceToPlayer = Math.Sqrt(Math.Pow(Level.Player.Position.X - this.Position.X, 2) + Math.Pow(Level.Player.Position.Y - this.Position.Y, 2));
// Calculate tile position based on the side we are walking towards.
float posX = Position.X + localBounds.Width / 2 * (int)direction;
int tileX = (int)Math.Floor(posX / Tile.Width) - (int)direction;
int tileY = (int)Math.Floor(Position.Y / Tile.Height);
if (waitTime > 0)
{
// Wait for some amount of time.
waitTime = Math.Max(0.0f, waitTime - (float)gameTime.ElapsedGameTime.TotalSeconds);
if (waitTime <= 0.0f)
{
// Then turn around.
direction = (FaceDirection)(-(int)direction);
}
}
else
{
// If we are about to run into a wall or off a cliff, start waiting.
if (Level.GetCollision(tileX + (int)direction, tileY - 1) == TileCollision.Impassable || Level.GetCollision(tileX + (int)direction, tileY) == TileCollision.Passable) //is the enemy is close and is not attacking, attack and turn!
{
waitTime = MaxWaitTime;
}
else
{
// Move in the current direction.
Vector2 velocity = new Vector2((int)direction * MoveSpeed * elapsed, 0.0f);
position = position + velocity;
}
}
dtAttack += gameTime.ElapsedGameTime;
AttackPlayer();
}
else
{
dt += gameTime.ElapsedGameTime;
if (dt.TotalSeconds > (sprite.Animation.FrameCount * sprite.Animation.FrameTime))
this.Remove = true;
}
}
Does it have to be 20 pixels on the screen? Seems strange.
You could try to calculate the euclidean distance between the player and the enemy, using the Vector2.Distance method. If the distance is 20 or lower, stop the enemy. If not, keep following the player.

Categories

Resources