Object X pos is drastically changing after screen shake ends - unity3d

I'm using the code below to move my player, named balloon, left and right on the x axis by calculating the difference between where you first touched (or clicked) and where you're currently touching, using ScreenToWorldPoint.
void Update()
{
if (gameStarted)
if (Input.GetMouseButtonDown(0))
{
firstTouch = Camera.main.ScreenToWorldPoint(Input.mousePosition);
startPos = balloon.position;
}
if (Input.GetMouseButton(0))
CheckTouchPosition();
}
}
void CheckTouchPosition()
{
Vector2 currentTouch = Camera.main.ScreenToWorldPoint(Input.mousePosition);
float horizontalDif = currentTouch.x - firstTouch.x;
balloon.position = new Vector2(startPos.x + horizontalDif * 1.2f, balloon.position.y);
}
This works normally except after I run into an obstacle and call my trigger shake function, which performs a typical screen shake. After the screen shake ends the player is translated across the X axis, from what I can tell in the inspector roughly doubling its X position.
public class ScreenShake : MonoBehaviour {
Vector3 initialPosition;
float shakeDuration;
public bool shaking;
[SerializeField] float shakeMagnitude = 0.5f;
[SerializeField] float dampingSpeed = 1.0f;
void Update()
{
if (shakeDuration > 0)
{
shaking = true;
transform.localPosition = initialPosition + Random.insideUnitSphere * shakeMagnitude;
shakeDuration -= Time.unscaledDeltaTime * dampingSpeed;
}
else
{
shakeDuration = 0f;
transform.localPosition = initialPosition;
shaking = false;
}
}
public void TriggerShake(float duration, Vector3 position)
{
shakeDuration = duration;
initialPosition = position;
}
}
I can't figure out why the balloon's X is changing after the screen shake, but it doesn't happen if I don't call that function. I think maybe it has to do with ScreenToWorldPoint being messed up because I'm changing the position of the camera?
EDIT: I forgot to add that the weird repositioning of the balloon ONLY occurs if youre currently holding touching the screen (or holding down the mouse button) when the screen shake occurs. Otherwise everything happens normally.

Related

Changing Y position of player (code runs like the player has two position simultaneously)

I am making a game that runs up infinite stairs.
First, I coded prototype code that can run infinite hallway by manipulating the player's Z position and it works.
Then, I change that code to manipulate the player's Y position.
This is HallWayController script
void FixedUpdate()
{
this.handleInfiniteHallway();
}
private void handleInfiniteHallway()
{
if (this.isPlayerOutOfBounds())
{
float posYmod = HALLWAY_HEIGHT;
if (this.player.position.y > MAX_Y_BOUND)
{
posYmod *= -1;
}
this.player.position = new Vector3(this.player.position.x, this.player.position.y + posYmod, this.player.position.z);
Debug.Log("Player Y position: " + this.player.position.y);
}
}
private bool isPlayerOutOfBounds()
{
return this.player.position.y > MAX_Y_BOUND || this.player.position.y < MIN_Y_BOUND;
}
With this code, the game malfunctions just like the player have two Y position simultaneously.
What I found:
If I use FixedUpdate(), the player's position doesn't change on game play view, but debug.Log says player Y Position has changed. And if player ever reached Y_Bound, code inside if(this.isPlayterOutOfBounds()) infinitely executes.
If I use Update() instead of FixedUpdate(), the player's position does change in game play view and debug.Log, but sometimes the player flashes back and forth between the original position and repositioned position. And if player ever reached Y_Bound code inside if(this.isPlayterOutOfBounds()) infinitely executes.
This is Player Controller script that linked to the player game object
using UnityEngine;
[RequireComponent(typeof(CharacterController))]
public class PlayerController : MonoBehaviour
{
[SerializeField] private float playerSpeed = 10.0f;
[SerializeField] private float jumpHeight = 1.0f;
[SerializeField] private float gravityValue = -9.81f;
private bool isFlashLightOn = true;
public GameObject lightSource;
private CharacterController controller;
private Vector3 playerVelocity;
private bool groundedPlayer;
private InputManager inputManager;
private Transform cameraTransform;
private void Start()
{
controller = gameObject.GetComponent<CharacterController>();
inputManager = InputManager.Instance;
cameraTransform = Camera.main.transform;
lightSource.gameObject.SetActive(true);
isFlashLightOn = true;
}
void FixedUpdate()
{
groundedPlayer = controller.isGrounded;
if (groundedPlayer && playerVelocity.y < 0)
{
playerVelocity.y = 0f;
}
Vector2 movement = inputManager.GetPlayerMovement();
Vector3 move = new Vector3(movement.x, 0, movement.y);
move = cameraTransform.forward * move.z + cameraTransform.right * move.x;
move.y = 0f;
controller.Move(move * Time.deltaTime * playerSpeed);
// Changes the height position of the player..
if (inputManager.PlayerJumped() && groundedPlayer)
{
playerVelocity.y += Mathf.Sqrt(jumpHeight * -3.0f * gravityValue);
}
playerVelocity.y += gravityValue * Time.deltaTime;
controller.Move(playerVelocity * Time.deltaTime);
}
void Update()
{
if (inputManager.PlayerFlashLightOn())
{
isFlashLightOn = !isFlashLightOn;
lightSource.gameObject.SetActive(isFlashLightOn);
}
}
}
Hmm, I think I quess what is the problem here. See comments I added
// You may call this twice on each frame, depending on your frame rate
void FixedUpdate()
{
this.handleInfiniteHallway();
}
private void handleInfiniteHallway()
{
if (this.isPlayerOutOfBounds())
{
// Problem is probably here. When your object hits another limit, you move it all HALLWAY_HEIGHT, so it hits another limit
// If you move just half of the height, your character returns to the middle.
// Original float posYmod = HALLWAY_HEIGHT;
float posYmod = HALLWAY_HEIGHT / 2;
if (this.player.position.y > MAX_Y_BOUND)
{
posYmod *= -1;
}
this.player.position = new Vector3(this.player.position.x, this.player.position.y + posYmod, this.player.position.z);
Debug.Log("Player Y position: " + this.player.position.y);
}
}
private bool isPlayerOutOfBounds()
{
return this.player.position.y > MAX_Y_BOUND || this.player.position.y < MIN_Y_BOUND;
}
If you call FixedUpdate method, it is run twice a frame so position is moved back and forth during one frame. Update method would be called each frame player is jumping between borders.

Unity, script for rotating the camera by swiping (3d)

using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class CameraScript : MonoBehaviour
{
[SerializeField] private float sensitivityHor = 9.0f;
[SerializeField] private float sensitivityVert = 9.0f;
[SerializeField] private float minimumVert = -45.0f;
[SerializeField] private float maximumVert = 45.0f;
private float _rotationX = 0;
private Rigidbody PlayerRigidbody;
void Start()
{
PlayerRigidbody = GetComponent<Rigidbody>();
if (PlayerRigidbody != null)
{
PlayerRigidbody.freezeRotation = true;
}
}
void Update()
{
_rotationX -= Input.GetAxis("Mouse Y") * sensitivityVert;
_rotationX = Mathf.Clamp(_rotationX, minimumVert, maximumVert);
float delta = Input.GetAxis("Mouse X") * sensitivityHor;
float rotationY = transform.localEulerAngles.y + delta;
transform.localEulerAngles = new Vector3(_rotationX, rotationY, 0);
}
}
Good evening. I have written a script to rotate the camera by swiping a finger across the screen
(it is on my camera), everything works correctly with one finger, but if you touch with two fingers at the same time, the application will react incorrectly (suddenly change the camera rotation). How can I fix it using Input.GetAxis or what can I use to write a script for multiple touches?
You may use only the first touch for your movement, so that if there is a second nothing happens and change Input.GetAxis("Mouse Y") by Input.GetTouch(0).deltaPosition.y with x and y respectively. Like this:
if (Input.touchCount > 0) {
_rotationX -= Input.GetTouch(0).deltaPosition.y * sensitivityVert;
_rotationX = Mathf.Clamp(_rotationX, minimumVert, maximumVert);
float delta = Input.GetTouch(0).deltaPosition.x * sensitivityHor;
float rotationY = transform.localEulerAngles.y + delta;
transform.localEulerAngles = new Vector3(_rotationX, rotationY, 0);
}
Code not debugged, as its just your code with the substitution.
If handling the first touch acts weird, you can handle the rotation with the middle point maybe. Like this:
//get the touch middle when the second finger touches
if (Input.GetTouch(1).phase == TouchPhase.Began) {
touchMiddle = (Input.GetTouch(0).position +
Input.GetTouch(1).position) / 2;
touchDistSqr = (Input.GetTouch(0).position -
Input.GetTouch(1).position).sqrMagnitude;
return;
}
if (Input.touchCount == 2) {
var deltaMidde = touchMiddle - (Input.GetTouch(0).position + Input.GetTouch(1).position) / 2;
transform.localEulerAngles = new Vector3(deltaMidde.x, deltaMidde.y, 0);
}
All the code in the LateUpdate().
Preferably camera movements needs to be done in the LateUpdate() for the objects that might have moved inside Update to be at their final state for each frame. As per adviced in the documentation.
Not really relevant but note that you can use Vector2 instead of Vector3for the screen operations most of the time.
Also it is very interesting in the Update or LateUpdate operations to have them multiplied by Time.deltaTime so that the movement is frame rate independent.

Unity ortographic camera panning within boundaries issue

I have an ortographic camera and I need to create panning with mouse within boundaries. I currently have this code which works fine with one problem. When user drags camera out of bounds, mouse position still gets updated and user needs to first move the mouse back within the bounds before camera is panning again. E.g. let's say the max bounds of x axis is 140. If the user moves the mouse to 150, the camera's position is clamped to 140 which is fine. However, if the user pans the camera back without releasing button, the camera is stuck at 140 until the mouse position reaches 140 again. Any ideas how to implement this adjustment?
public class CameraDragMouse : MonoBehaviour
{
private Vector3 Origin;
private Vector3 Diference;
private bool Drag;
private float minPanningBoundaryX;
private float maxPanningBoundaryX;
private float minPanningBoundaryZ;
private float maxPanningBoundaryZ;
private Camera mainCamera;
private void Start()
{
mainCamera = this.GetComponentInChildren<Camera>();
CameraCenter.CenterCameraOnPosition(new Vector3(24, 0, 24));
minPanningBoundaryX = gameObject.transform.position.x - 40;
maxPanningBoundaryX = gameObject.transform.position.x + 40;
minPanningBoundaryZ = gameObject.transform.position.z - 40;
maxPanningBoundaryZ = gameObject.transform.position.z + 40;
}
void LateUpdate()
{
if (Input.GetMouseButton(0))
{
Ray rr = Camera.main.ScreenPointToRay(Input.mousePosition);
if (Physics.Raycast(rr, out RaycastHit hit, Mathf.Infinity, Constants.LAYER_MASK_TERRAIN))
{
Diference = hit.point - gameObject.transform.position;
}
if (Drag == false)
{
Drag = true;
Origin = hit.point;
}
}
else
{
Drag = false;
}
if (Drag == true)
{
Vector3 newCameraPosition = Origin - Diference;
newCameraPosition.x = Mathf.Clamp(newCameraPosition.x, minPanningBoundaryX, maxPanningBoundaryX);
newCameraPosition.z = Mathf.Clamp(newCameraPosition.z, minPanningBoundaryZ, maxPanningBoundaryZ);
gameObject.transform.position = newCameraPosition;
}
}
}

(Big unity noob here) I can jump while in the air, and I can't jump while moving on the x-axis

Have tried a few things but they didn't seem to work, so I was hoping that you guys could help me.
I've trying to make this demo for a little time now, but I can't seem to get the jumping to work.
When I try to jump while running, I can't. But I can however jump forever when i get up in the air, which is something that I would like to remove from the game.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class movement : MonoBehaviour
{
Rigidbody2D rb2d;
public float moveVelocity = 8f;
public float jumpVelocity = 15f;
public float fallMultiplier = 2.5f;
public float lowJumpMultiplier = 2f;
public const string RIGHT = "right";
public const string LEFT = "left";
public const string UP = "up";
string buttonPressed;
void Start()
{
rb2d = GetComponent<Rigidbody2D>();
}
void Update()
{
if (rb2d.velocity.y < 0)
{
rb2d.velocity += Vector2.up * Physics2D.gravity.y * (fallMultiplier - 1) *
Time.deltaTime;
}
else if (rb2d.velocity.y > 0 && !Input.GetButton ("Jump"))
{
rb2d.velocity += Vector2.up * Physics2D.gravity.y * (lowJumpMultiplier - 1) *
Time.deltaTime;
}
if (Input.GetKey(KeyCode.RightArrow))
{
buttonPressed = RIGHT;
}
else if (Input.GetKey(KeyCode.LeftArrow))
{
buttonPressed = LEFT;
}
else if (Input.GetKey(KeyCode.UpArrow))
{
buttonPressed = UP;
}
else
{
buttonPressed = null;
}
}
private void FixedUpdate()
{
if (buttonPressed == RIGHT)
{
rb2d.velocity = new Vector2(moveVelocity, rb2d.velocity.y);
}
else if (buttonPressed == LEFT)
{
rb2d.velocity = new Vector2(-moveVelocity, rb2d.velocity.y);
}
else if (buttonPressed == UP)
{
rb2d.velocity = Vector2.up * jumpVelocity;
}
else
{
rb2d.velocity = new Vector2(0, rb2d.velocity.y);
}
}
}
I am not sure why you are trying to control the gravity of the player when gravity is already applied to any gameObject with the RigidBody or RigidBody2D component attached to it. It is good that you are reading input in the Update() function and applying the motion inside of the FixedUpdate(). Here is a slight tweak to your current code, let me know how this goes.
Rigidbody2D rb2d;
public float moveVelocity = 8f;
public float jumpVelocity = 15f;
private float horizontalInput = 0.0f;
// did the player just try to jump
private bool justJumped = false;
void Start()
{
rb2d = GetComponent<Rigidbody2D>();
}
void Update()
{
// grab how the player is moving - this value is mapped to your arrow keys
// so horizontal is left / right arrow and Vertical is up/down arrow
// the value is between [-1, 1] respectively
horizontalInput = Input.GetAxis("Horizontal");
// player tried to jump, we are not currently jumping and the player is grounded
if(IsGrounded() && Input.GetKeyDown(KeyCode.UpArrow))
{
justJumped = true;
}
}
private void FixedUpdate()
{
// handle our jump
if(justJumped)
{
// we just applied a jump so do not apply it again
justJumped = false;
// you can either apply the jump by setting velocity, but I would recommend using AddForce instead
rb2d.AddForce(Vector2.up * jumpVelocity);
}
// we are moving in either the left or right direction
if(horizontalInput != 0)
{
// move in the horizontal axis, but keep our Y component of velocity the same in case we jumped
rb2d.velocity = new Vector2 (horizontalInput * moveVelocity, rigidBody.velocity.y);
}
else
{
// just in case we are not moving, assure this by setting the horizontal component of velocity to 0
rb2d.velocity = new Vector2 (0f, rigidBody.velocity.y);
}
}
// determines if this object is currently touching another object that is marked as ground
private bool IsGrounded() {
// our current position (the player)
Vector2 position = transform.position;
// the direction we are going to aim the raycast (down as that is where the ground is)
Vector2 direction = Vector2.down;
// the ground should be close, so check it very close to the player
float distance = 1.0f;
// check if we hit anything that is on the layer of just ground - ignore all other layers
// IMPORTANT:: Make sure to make a Layer and set all of your ground to this layer
RaycastHit2D hit = Physics2D.Raycast(position, direction, distance, LayerMask.GetMask("GroundLayer"));
// we hit a ground collider, so we are grounded
if (hit.collider != null) {
return true;
}
return false;
}
Let me know if this works for you. I changed a few things around such as using GetAxis() instead of using the arrow keys as in Unity, these are the same. I also changed your jump to use an AddForce2D instead of setting velocity. The one addition was I added a IsGrounded() which will detect if whatever object this script is on (I assume it is on your player object) is near or touching objects below them that are marked as GroundLayer. If you have questions comment below.

How to move yoke in the vertical axis

I am trying to move an airplane yoke in the vertical axis. I am using the mouse pointer to move yoke in vertical axis up and down and clamped the value. When I run the script the yoke is positioned some ever and not moving up and down. The yoke is not moving up and down. How to move yoke up and down as shown in the image using below code.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace plane
{
public class IP_AirplaneThrottle_Physical : MonoBehaviour
{
#region Variables
public float maxZOffset = -0.5f;
public float sensitivity = 0.001f;
public float smoothSpeed = 8f;
public bool isHitting = false;
public float wantedDelta;
private Vector3 startPos;
private Vector3 wantedPos;
private Vector2 lastMousePosition;
#endregion
#region Builtin Methods
// Use this for initialization
void Start()
{
//Get the lever starting position
startPos = transform.position;
}
// Update is called once per frame
void Update()
{
HandleRaycast();
HandleInteraction();
}
#endregion
#region Custom Methods
void HandleRaycast()
{
//Build a ray so we can see if we are hitting the lever
Ray curRay = Camera.main.ScreenPointToRay(Input.mousePosition);
RaycastHit hit;
//Do our Raycast into the scene
if(Physics.Raycast(curRay, out hit, 1000f))
{
if(hit.transform.GetInstanceID() == this.transform.GetInstanceID())
{
Debug.Log("Hitting the Lever!");
if(Input.GetMouseButtonDown(0))
{
//We are hitting so get the start mouse position
isHitting = true;
lastMousePosition = Input.mousePosition;
print ("123");
}
}
}
//If we let go of the left mouse button then stop everything
if(isHitting && Input.GetMouseButton(0) == false)
{
isHitting = false;
}
}
void HandleInteraction()
{
if(isHitting)
{
//Calculate the delta for Z offset
wantedDelta = (lastMousePosition.y - Input.mousePosition.y) * Time.deltaTime * sensitivity;
startPos.z += wantedDelta;
//make sure we dont go to far
startPos.z = Mathf.Clamp(startPos.z, maxZOffset, 0f);
wantedPos = startPos;
//Get the New Mouse Position every frame while we are holding
lastMousePosition = Input.mousePosition;
}
else
{
//Clear out the Delta value
wantedDelta = 0f;
}
//Move the lever
transform.position = Vector3.Lerp(transform.position, wantedPos, Time.deltaTime * smoothSpeed);
}
#endregion
}
}