Mathf.Clamp is messing with my camera movement script - c#

i am making a game that uses the WASD keys to move the camera between different objects and am using Mathf.Clamp to limit it but it now makes it so the movement doesn't work and i only move diagonal which shouldn't be possible without multiple key presses.
{
public Vector3 startPos;
public float moveDistance = 1;
public float minX;
public float minZ;
public float maxX;
public float maxZ;
void Start()
{
transform.position = startPos;
}
// Update is called once per frame
void Update()
{
if (Input.GetKeyDown(KeyCode.W))
{
transform.position += new Vector3(0, 0, moveDistance);
}
else if (Input.GetKeyDown(KeyCode.S))
{
transform.position += new Vector3(0, 0, -moveDistance);
}
else if (Input.GetKeyDown(KeyCode.D))
{
transform.position += new Vector3(moveDistance, 0, 0);
}
else if (Input.GetKeyDown(KeyCode.A))
{
transform.position += new Vector3(-moveDistance, 0, 0);
}
transform.position = new Vector3(Mathf.Clamp(transform.position.x, minX, maxX), transform.position.y, Mathf.Clamp(transform.position.x, minZ, maxZ));
}
}

looks like Ruzihm already answered your question.
I recently ran into some problems with Mathf.Clamp with negative numbers.
So I wanted to share the solution.
Cannot remember where I found it so sorry I can't credit the person who made it.
public float ClampAngle(float angle, float minAngle, float maxAngle)
{
if (angle < 90 || angle > 270)
{ // if angle in the critic region...
if (angle > 180) angle -= 360; // convert all angles to -180..+180
if (maxAngle > 180) maxAngle -= 360;
if (minAngle > 180) minAngle -= 360;
}
angle = Mathf.Clamp(angle, minAngle, maxAngle);
if (angle < 0) angle += 360; // if angle negative, convert to 0..360
return angle;
}

Related

Clamping my camera to a min and max value

I tried many approaches, watched tutorials but can't wrap my head around to make the clamp work with my code that I have right now.
So I can zoom in and out but infinitely, how to clamp the camera to max value -5 which is slightly above my player, and min value around -15 which is far above my player.
// Control the distance between the object && camera
private void ZoomIntoObject(float maxZoom, float minZoom)
{
float scrollInput = Input.GetAxis("Mouse ScrollWheel");
//zPos = scrollInput;
// zPos = Mathf.Clamp(zPos, minZoom, maxZoom);
// While scrollwheel
if (scrollInput > 0.0f)
{
// Move forward on the z-as && Clamp maxZoom
transform.position += transform.forward;
} else if (scrollInput < 0.0) {
// Move forward on the z-as && Clamp maxZoom
transform.position -= transform.forward;
}
Debug.Log(zPos);
}
Calculate your new position, clamp its z component, then assign to position.
private void ZoomIntoObject(float maxZoom, float minZoom)
{
float scrollInput = Input.GetAxis("Mouse ScrollWheel");
Vector3 newPos = transform.position;
if (scrollInput > 0.0f)
{
newPos += transform.forward;
} else if (scrollInput < 0.0) {
newPos -= transform.forward;
}
newPos.z = Mathf.Clamp(newPos.z, minZoom, maxZoom);
transform.position = newPos;
}

Change Object's Scale Smoothly with Swipe

I wrote the code below to change an object's scale (X axis) with mouse swipe, it works but it's not smooth, how can I smooth it?
Script:
Vector3 newScale;
private float _previousSwipePosition;
private float newPosition;
if (Input.GetMouseButton(0))
{
_previousSwipePosition = Input.mousePosition.x;
if (newPosition != _previousSwipePosition)
{
if (newPosition - _previousSwipePosition < -2)
{
if (transform.localScale.x <= 1.4f)
{
newScale = transform.localScale;
newScale.x += 0.06f;
transform.localScale = newScale;
}
}
else if (newPosition - _previousSwipePosition > 2)
{
if (transform.localScale.x >= 0.2f)
{
newScale = transform.localScale;
newScale.x -= 0.06f;
transform.localScale = newScale;
}
}
}
newPosition = Input.mousePosition.x;
}
You can use Input.GetAxis("Mouse X") to get smoothed scale of how much the mouse has moved in the last frame. Multiply that by a speed parameter.
Get the power of 2 by that product to get how much to change the current scale. Then, change the scale and clamp it:
public float scaleSpeed = 1f;
// ...
// ignore first frame mouse is pressed
if (Input.GetMouseButton(0) && !Input.GetMouseButtonDown(0))
{
float scaleFactor = Mathf.Pow(2f, Input.GetAxis("Mouse X")
* scaleSpeed);
float newX = Mathf.Clamp(transform.localScale.x * scaleFactor, 0.2f, 1.4f);
transform.localScale = new Vector3(
newX,
transform.localScale.y,
transform.localScale.z);
}
Use Time.deltaTime to smooth
Vector3 newScale;
private float _previousSwipePosition;
private float newPosition;
private float speed = 6f;
private void Update()
{
if (Input.GetKey(KeyCode.A))
{
if (transform.localScale.x <= 1.4f)
{
newScale = transform.localScale;
newScale.x += speed * Time.deltaTime;
transform.localScale = newScale;
}
}
if (Input.GetKey(KeyCode.B))
{
if (transform.localScale.x >= 0.2f)
{
newScale = transform.localScale;
newScale.x -= speed * Time.deltaTime;
transform.localScale = newScale;
}
}
}

How to clamp camera in Unity3D

My code is not working, I am trying to clamp the camera, but its not working. How to clamp the camera?
using UnityEngine;
using System.Collections;
public class MoveCamera : MonoBehaviour
{
public float sensitivity = 4.0f;
private Vector3 mouseOrigin;
private bool isRotating;
private float speed = 2.0f;
private float minX = -45.0f;
private float maxX = 45.0f;
private float minY = -10.0f;
private float maxY = 10.0f;
float rotationY = 0.0f;
float rotationX = 0.0f;
void Update ()
{
if (Input.GetMouseButtonDown (0)) {
mouseOrigin = Input.mousePosition;
isRotating = true;
}
if (!Input.GetMouseButton (0))
isRotating = false;
if (isRotating) {
Vector3 pos = Camera.main.ScreenToViewportPoint (Input.mousePosition - mouseOrigin);
transform.RotateAround (transform.position, transform.right, -pos.y * sensitivity);
transform.RotateAround (transform.position, Vector3.up, pos.x * sensitivity);
rotationY = Mathf.Clamp (rotationY, minY, maxY);
rotationX = Mathf.Clamp (rotationX, minX, maxX);
transform.localEulerAngles = new Vector3 (-rotationY, rotationX, 0);
}
}
}
You forgot to get the value of rotationX and rotationY from your transform after rotating it. Try this :
if (isRotating) {
Vector3 pos = Camera.main.ScreenToViewportPoint (Input.mousePosition - mouseOrigin);
transform.RotateAround (transform.position, transform.right, -pos.y * sensitivity);
transform.RotateAround (transform.position, Vector3.up, pos.x * sensitivity);
rotationY = Mathf.Clamp (transform.localEulerAngles.y, minY, maxY);
rotationX = Mathf.Clamp (transform.localEulerAngles.x, minX, maxX);
transform.localEulerAngles = new Vector3 (-rotationY, rotationX, 0);
}
Here's the code of Mathf.Clamppublic static float Clamp(float value, float min, float max) {
if (value < min) {
value = min;
} else if (value > max) {
value = max;
}
return value;
}
Use an IL reverse tool such as (EXTERNAL LINK)ILSPY if you are unsure how a call works in .NET (Unity / Mono / etc).
Based on the code you posted and understanding Mathf.Clamp should work as intended, the issue is most probably laying in your code, at least at one point, e.g. here:
rotationY = Mathf.Clamp (rotationX, minY, maxY); //note it's rotation "X" instead of "Y"
rotationX = Mathf.Clamp (rotationX, minX, maxX);
If this still did not sort out the issue, use Debug.Log to see variable values to find where you make the mistake(s).
If you can't sort out like this, you'll have a clear picture what exactly you can't do and can post a much cleaner question and expect a clean answer.
Hope this helps!
OK, So I fixed it. Here is complete code.
using UnityEngine;
using System.Collections;
public class MoveCamera : MonoBehaviour
{
public float sensitivity = 4.0f;
private Vector3 mouseOrigin;
private bool isRotating;
public GameObject cam;
void Start()
{
}
protected float ClampAngle(float angle, float min, float max) {
angle = NormalizeAngle(angle);
if (angle > 180) {
angle -= 360;
} else if (angle < -180) {
angle += 360;
}
min = NormalizeAngle(min);
if (min > 180) {
min -= 360;
} else if (min < -180) {
min += 360;
}
max = NormalizeAngle(max);
if (max > 180) {
max -= 360;
} else if (max < -180) {
max += 360;
}
return Mathf.Clamp(angle, min, max);
}
protected float NormalizeAngle(float angle) {
while (angle > 360)
angle -= 360;
while (angle < 0)
angle += 360;
return angle;
}
void Update ()
{
if (Input.GetMouseButtonDown (0)) {
mouseOrigin = Input.mousePosition;
isRotating = true;
}
if (!Input.GetMouseButton (0))
isRotating = false;
if (isRotating) {
cam.transform.localEulerAngles = new Vector3(0, ClampAngle(cam.transform.localEulerAngles.y, -45, 45), 0);
Vector3 pos = Camera.main.ScreenToViewportPoint (Input.mousePosition - mouseOrigin);
transform.RotateAround (transform.position, transform.right, -pos.y * sensitivity);
transform.RotateAround (transform.position, Vector3.up, pos.x * sensitivity);
}
}
}

Unity2D Asteroids style game

I am trying to build an asteroids style game in Unity and could really use some help. I believe all my math is correct as far as the ship movement but I am having trouble getting it to work inside Unity. I am having a couple different problems.
The ship does not update with velocity ( if you start moving and then let go, it will stand still)
I am unsure in Unity how to set the ships rotation to my specific angle.
Any help would be greatly appreciated.
public class playerController : MonoBehaviour {
public static float timer;
public static bool timeStarted = false;
Vector2 accel;
Vector2 velocity;
float direction;
float angle;
float shotCooldown;
float speed;
const float pi = 3.141592f;
const float maxSpeed = 300;
const float maxAccel = 500;
void Start () {
timeStarted = true;
}
void Update () {
if (timeStarted == true) {
timer += Time.deltaTime;
}
shotCooldown -= (timer%60);
angle = direction * pi / 180;
if (Input.GetKey(KeyCode.W)) {
accel.y = -Mathf.Cos(angle) * maxAccel;
accel.x = Mathf.Sin(angle) * maxAccel;
velocity += accel * Time.deltaTime;
}
if (Input.GetKey(KeyCode.S)) {
accel.y = -Mathf.Cos(angle) * maxAccel;
accel.x = Mathf.Sin(angle) * maxAccel;
velocity -= accel * Time.deltaTime;
}
if (Input.GetKey(KeyCode.Space)) {
if (shotCooldown <= 0)
{
// Create new shot by instantiating a bullet with current position and angle
shotCooldown = .25f;
}
}
if (Input.GetKey(KeyCode.D)) {
direction += 360 * Time.deltaTime;
}
if (Input.GetKey(KeyCode.A)) {
direction -= 360 * Time.deltaTime;
}
/*
if (this.transform.position.x >= Screen.width && velocity.x > 0) {
this.transform.position.x = 0;
}*/
while (direction < 0) {
direction += 360;
}
while (direction > 360) {
direction -= 360;
}
speed = Mathf.Sqrt( (velocity.x * velocity.x) + (velocity.y * velocity.y));
if (speed > maxSpeed) {
Vector2 normalizedVector = velocity;
normalizedVector.x = normalizedVector.x / speed;
normalizedVector.y = normalizedVector.y / speed;
velocity = normalizedVector * maxSpeed;
}
this.transform.position = velocity * Time.deltaTime;
transform.rotation = Quaternion.AngleAxis(0, new Vector3(0,0,angle));
}
}
It's usually a bad idea to set the position the way you are, because you're not actually using any physics. The way you're doing it, velocity is a new position for the ship, not a speed. Once you let go of the keys, it stops calculating new positions, and thus stops moving.
There are a couple of alternatives which would make for a better result:
1) One way this can be done is by calling: transform.Translate(Vector3.forward * speed * Time.deltaTime) Vector3.forward should correspond to the direction you consider as "forward", but if not, you can change it to whichever works (eg Vector3.up). This means you only really need to calculate a speed and let unity hangle the rest.
2) If you're using a rigidbody on your ship, you could simply do:
rigidbody.AddForce(Vector3.forward * speed * Time.deltaTime) which will automatically accelerate the ship in the given direction by whatever speed you give it.
As for rotation, perhaps try something like this:
if (Input.GetKey(KeyCode.D))
{
Vector3 newRotation = transform.rotation.eulerAngles;
newRotation.z += 10;
transform.rotation = Quaternion.Euler (newRotation);
}
else if (Input.GetKey(KeyCode.A))
{
Vector3 newRotation = transform.rotation.eulerAngles;
newRotation.z -= 10;
transform.rotation = Quaternion.Euler (newRotation);
}

Messing up Vectors in C# (Unity Engine)

I'm new to programming in C# in Unity and there is some problems when moving in the z-axis. The problem is that I continue to move when I let go of the up button. However, when I move in the x-axis it is fine, as letting go of the button will stop the player. The code is below:
using UnityEngine;
using System.Collections;
public class Player : MonoBehaviour {
public Vector3 motion = new Vector3();
private CharacterController controller;
private bool onGround;
private float xRot, yRot;
public static float X_ROTATION = 0;
public static float Y_ROTATION = 0;
private const float lookSpeed = 2.0f;
public void Start() {
controller = GetComponent<CharacterController>();
}
public void FixedUpdate() {
if(Screen.lockCursor) {
Vector3 impulse = new Vector3();
if(Input.GetKey(KeyCode.W)) impulse.z+=1;
if(Input.GetKey(KeyCode.A)) impulse.x-=1;
if(Input.GetKey(KeyCode.S)) impulse.z-=1;
if(Input.GetKey(KeyCode.D)) impulse.x+=1;
if(impulse.sqrMagnitude > 0) {
motion += Quaternion.Euler(new Vector3(0, xRot, 0)) * impulse.normalized * 0.05f;
}
if(onGround) {
if(Input.GetKey(KeyCode.Space)) {
motion.y += 0.2f;
}
}
motion.y -= 0.015f;
Vector3 oldMotion = motion;
Vector3 oldPos = controller.transform.localPosition;
controller.Move(motion);
Vector3 newPos = controller.transform.localPosition;
motion = newPos - oldPos;
onGround = oldMotion.y < -0.0001f && motion.y >= -0.0001f;
motion.x *= 0.8f;
motion.y *= 0.8f;
}
}
public void Update() {
if(Screen.lockCursor && Input.GetKeyDown(KeyCode.Escape)) {
Screen.lockCursor = false;
}
if(!Screen.lockCursor && Input.GetMouseButtonDown(0)) {
Screen.lockCursor = true;
}
if(Screen.lockCursor) {
xRot += Input.GetAxis("Mouse X") * lookSpeed;
yRot -= Input.GetAxis("Mouse Y") * lookSpeed;
if(yRot < -90) yRot = -90;
if(yRot > 90) yRot = 90;
if(xRot < -180) xRot += 360;
if(xRot >= 180) xRot -= 360;
controller.transform.localRotation = Quaternion.Euler(new Vector3(yRot, xRot, 0));
}
Player.X_ROTATION = xRot;
}
}
The last few statments in FixedUpdate() where you have coded-
motion.x *= 0.8f;
motion.y *= 0.8f;
should also contain
motion.z *= 0.8f;
and may be u dont need-
motion.y *= 0.8f;
As Gkills said, you should fix the "depletion" of motion.y for motion.z at the end.
Additionally, you should probably want to swap
motion += Quaternion.Euler(new Vector3(0, xRot, 0)) * impulse.normalized * 0.05f;
for
motion += transform.rotation * impulse.normalized * 0.05f;
Then zero out the impulse.y component to prevent the player flying.
Finally you might want to use Time.deltaTime in your Update (so mouse look is frame rate independent)

Categories