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.
Related
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.
I create a game, like minigolf/pool. I want to have a camera which follow player.
Position is normally ok, I get the ball direction and I lerp.
Rotation is almost ok. Currently, rotation by Y axis is ok, but camera look straigth forward, and don't look down to the player :
I already try many thing , quaternion angleToaxis, quarternion lookat ... but doesn't look good, the camera go look away ...
Here my code
namespace CameraManagerNameSpace
{
public class CameraManager : MonoBehaviour
{
public float cameraHeight=13f;
public PlayerNameSpace.Player playerToFollow;
public float followSpeed = 3f;
public float rotationSpeed = 1f;
float distance;
Vector3 position;
Vector3 newPos;
Quaternion rotation;
Quaternion newRot;
Vector3 playerPrevPos, playerMoveDir;
bool firstMoveDone=false;
void Start()
{
playerPrevPos = playerToFollow.player_transform.position;
distance = Vector3.Distance(transform.position,playerToFollow.player_transform.position);
}
void FixedUpdate()
{
if(Vector3.Distance(playerToFollow.player_transform.position ,playerPrevPos)>0.5f || firstMoveDone)
{
playerMoveDir = playerToFollow.player_transform.position - playerPrevPos;
firstMoveDone = true;
}
else
{
playerMoveDir = new Vector3(0,0,0);
}
if (playerMoveDir != Vector3.zero)
{
playerMoveDir.Normalize();
newPos = playerToFollow.player_transform.position - playerMoveDir * distance;
newRot =Quaternion.LookRotation(playerMoveDir,Vector3.up);
position = Vector3.Lerp(transform.position, new Vector3(newPos.x,newPos.y+cameraHeight,newPos.z), followSpeed * Time.deltaTime);
rotation = Quaternion.Lerp(transform.rotation, newRot, rotationSpeed * Time.deltaTime);
transform.position = position;
transform.rotation = rotation;
playerPrevPos = playerToFollow.player_transform.position;
}
}
}
}
Also, I don't know why, but after the balls stop the camera continue to do some movement very jerky, jolting, halting.
Well in
newRot = Quaternion.LookRotation(playerMoveDir,Vector3.up);
you are saying the camera to look in the same direction the player is moving ... not to look at the player. This would work if you wouldn't give the camera an extra position offset in the Y axis.
You might want to rather try
// vector pointing from the camera towards the player
var targetDirection = playerToFollow.player_transform.position - transform.position;
newRot = Quaternion.LookRotation(targetDirection, Vector3.up);
You should also rather use Update since FixedUpdate is only used for physics related stuff (also see Update & FixedUpdate)
the problem is that if the player touches something that rotate, the player automatically starting rotating too because the object that is rotation right now pushed the player's colliders and and player starting rotating. I want to make my player un rotatable to another objects in the game but rotatable if the player rotate by himself
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class camera : MonoBehaviour
{
public enum RotationAxis
{
MouseX = 1,
MouseY = 2
}
public RotationAxis axes = RotationAxis.MouseX;
public float minimumVert = -45.0f;
public float maximumVert = 45.0f;
public float sensHorizontal = 10.0f;
public float sensVertical = 10.0f;
public float _rotationX = 0;
// Update is called once per frame
void Update()
{
if (axes == RotationAxis.MouseX)
{
transform.Rotate(0, Input.GetAxis("Mouse X") * sensHorizontal, 0);
}
else if (axes == RotationAxis.MouseY)
{
_rotationX -= Input.GetAxis("Mouse Y") * sensVertical;
_rotationX = Mathf.Clamp(_rotationX, minimumVert, maximumVert); //Clamps the vertical angle within the min and max limits (45 degrees)
float rotationY = transform.localEulerAngles.y;
transform.localEulerAngles = new Vector3(_rotationX, rotationY, 0);
}
}
}
You could store the rotation in a field and thus making sure the only thing changing it is your script:
move it to LateUpdate in order for it to be the last thing called in a frame (also see Order of Execution for Event Functions)
float xRotation;
float yRotation;
void Start()
{
xRotation = transform.localEulerAngles.x;
yRotation = transform.localEulerAngles.y;
}
void LateUpdate()
{
if (axes == RotationAxis.MouseX)
{
yRotation += Input.GetAxis("Mouse X") * sensHorizontal;
}
else if (axes == RotationAxis.MouseY)
{
xRotation -= Input.GetAxis("Mouse Y") * sensVertical;
//Clamps the vertical angle within the min and max limits (45 degrees)
xRotation= Mathf.Clamp(lastXRotation , minimumVert, maximumVert);
}
// always overwrite with fixed values instead of using transform.rotation based ones
transform.localRotation = Quaternion.Euler(xRotation, yRotation, 0);
}
just to be sure you could also additionally but it to FixedUpdate in order to also reset changes from the Physics. If there is any RigidBody in play this should be the way to go anyway but then not using the Transform but rather the Rigidbody component.
void FixedUpdate()
{
transform.localRotation = Quaternion.Euler(xRotation, yRotation, 0);
}
Note however: As you currently have it setup you will get unexpected rotations. Rotating around the two axis here has the problem of also rotating along the local coordinate system.
In general you should rather have a parent object for the Y rotation and only do the X rotation on the object itself.
I have a problem with the Fixed joystick when I apply rotation to the main camera. The controls are mixed. How can I resolve this problem? Do I need to use other type of joystick? Where I should put "-" ? in front of which number
using System.Collections.Generic;
using UnityEngine;
[AddComponentMenu("Camera-Control/Mouse Look")]
public class MouseLook : MonoBehaviour
{
public enum RotationAxes { MouseXAndY = 0, MouseX = 1, MouseY = 2 }
public RotationAxes axes = RotationAxes.MouseXAndY;
public float sensitivityX = 15F;
public float sensitivityY = 15F;
public float minimumX = -360F;
public float maximumX = 360F;
public float minimumY = -60F;
public float maximumY = 60F;
float rotationY = 0F;
void Update()
{
if (Input.touchCount > 0)
{
Touch touch = Input.GetTouch(0);
float turnAngleChange = (touch.deltaPosition.x / Screen.width) * sensitivityX;
float pitchAngleChange = (touch.deltaPosition.y / Screen.height) * sensitivityY;
// Handle any pitch rotation
if (axes == RotationAxes.MouseXAndY || axes == RotationAxes.MouseY)
{
rotationY = Mathf.Clamp(rotationY + pitchAngleChange, minimumY, maximumY);
transform.localEulerAngles = new Vector3(-rotationY, transform.localEulerAngles.y, 0f);
}
// Handle any turn rotation
if (axes == RotationAxes.MouseXAndY || axes == RotationAxes.MouseX)
{
transform.Rotate(0f, turnAngleChange, 0f);
}
}
void Start()
{
//if(!networkView.isMine)
//enabled = false;
// Make the rigid body not change rotation
//if (rigidbody)
//rigidbody.freezeRotation = true;
}
}
}
I don't really get your question so I'm gonna answer both of my interpretations.
If the rotation of the camera is inverted (if you put your stick to the left the camera rotates to the right) you just need to add a minus in front of the speed you're rotating the camera with.
If the rotation of the camera happens when you use the left stick and you want to use the right stick. Then you should define in your input a field called something like camera-rotation-x and use the axis shown on the following pictures in the article here: https://gamedev.stackexchange.com/questions/150323/unity3d-how-to-use-controller-joystick-to-look-around If you follow that article, your camera rotation should work.
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.