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;
}
}
}
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.
there is a circle, it needs to be rotated by pressing the button, with a certain speed along the z axis, and when it turns 90, the rotation will stop, but for some reason the rotation is not working properly
public GameObject Circle;
private bool RotationActive;
//rotation value at which the circle stops rotation
private float RotatePost;
private float RotationSpeed;
private float CircleRotateZ;
void Start()
{
RotationActive = false;
RotationSpeed = 0.5f;
RotatePost = 90;
}
//function is bound to a button
public void RotateActive(){
RotationActive = true;
}
void FixedUpdate()
{
if (RotationActive == true)
{
CircleRotateZ = Circle.transform.rotation.z;
//if the circle along the z axis is rotated more than Rotation Post...
if (CircleRotateZ >= RotatePost )
{
RotatePost = CircleRotateZ + 90;
RotationActive = false;
}
//assignment of a new coordinate
Circle.transform.Rotate(new Vector3(0,0,RotationSpeed + CircleRotateZ));
}
}
You are trying to grab the rotation from the Quaternion which is not the angle of the object. Instead you should use:
CircleRotateZ = Circle.transform.eulerAngles.z;
Also the way you are currently rotating will make it speed up over time. The Rotate functions rotates the object by the amount, not to the amount given, so if you only want to rotate by the rotation speed you should use:
Circle.transform.Rotate(new Vector3(0, 0, RotationSpeed));
What do you mean by not working properly. You mean it doesn't move at all? If it doesn't move at all, check if you dragged the circle game object to the game object field in the Inspector. One more thing, why didn't you call the 'RotateActive' function?
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.
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
}
}
I have an orthographic camera and would like to implement a zoom feature to a specific point. I.e., imagine you have a picture and want to zoom to a specific part of the picture.
I know how to zoom in, the problem is to move the camera to a position that has the desired zone in focus.
How can I do so?
The camera's orthographicSize is the number of world space units in the top half of the viewport. If it's 0.5, then a 1 unit cube will exactly fill the viewport (vertically).
So to zoom in on your target region, center your camera on it (by setting (x,y) to the target's center) and set orthographicSize to half the region's height.
Here is an example to center and zoom to the extents of an object. (Zoom with LMB; 'R' to reset.)
public class OrthographicZoom : MonoBehaviour
{
private Vector3 defaultCenter;
private float defaultHeight; // height of orthographic viewport in world units
private void Start()
{
defaultCenter = camera.transform.position;
defaultHeight = 2f*camera.orthographicSize;
}
private void Update()
{
if (Input.GetMouseButtonDown(0))
{
Collider target = GetTarget();
if(target != null)
OrthoZoom(target.bounds.center, target.bounds.size.y); // Could directly set orthographicSize = bounds.extents.y
}
if (Input.GetKeyDown(KeyCode.R))
OrthoZoom(defaultCenter, defaultHeight);
}
private void OrthoZoom(Vector2 center, float regionHeight)
{
camera.transform.position = new Vector3(center.x, center.y, defaultCenter.z);
camera.orthographicSize = regionHeight/2f;
}
private Collider GetTarget()
{
var hit = new RaycastHit();
Physics.Raycast(camera.ScreenPointToRay(Input.mousePosition), out hit);
return hit.collider;
}
}
hope you find this code example useful, should be a copy / paste.
Note: this script assume it's attached to the camera object, otherwise you should adjust the transform to the camera object reference.
private float lastZoomDistance = float.PositiveInfinity; // remember that this should be reset to infinite on touch end
private float maxZoomOut = 200;
private float maxZoomIn = 50;
private float zoomSpeed = 2;
void Update() {
if (Input.touchCount >= 2) {
Vector2 touch0, touch1;
float distance;
Vector2 pos = new Vector2(transform.position.x, transform.position.y);
touch0 = Input.GetTouch(0).position - pos;
touch1 = Input.GetTouch(1).position - pos;
zoomCenter = (touch0 + touch1) / 2;
distance = Vector2.Distance(touch0, touch1);
if(lastZoomDistance == float.PositiveInfinity) {
lastZoomDistance = distance;
} else {
if(distance > lastZoomDistance && camera.orthographicSize + zoomSpeed <= maxZoomOut) {
this.camera.orthographicSize = this.camera.orthographicSize + zoomSpeed;
// Assuming script is attached to camera - otherwise, change the transform.position to the camera object
transform.position = Vector3.Lerp(transform.position, zoomCenter, Time.deltaTime);
} else if(distance < lastZoomDistance && camera.orthographicSize - zoomSpeed >= maxZoomIn) {
this.camera.orthographicSize = this.camera.orthographicSize - zoomSpeed;
transform.position = Vector3.Lerp(transform.position, zoomCenter, Time.deltaTime);
}
}
lastZoomDistance = distance;
}
}