I am currently making an FPS game and I have some problems with camera movement. When I add a child object to the camera, and when I rotate the camera, the child object deforms.
I followed this tutorial to get my FPS movement. https://www.youtube.com/watch?v=XAC8U9-dTZU/
Here is my camera movement script and my player movement one:
using UnityEngine;
public class MoveCamera : MonoBehaviour {
public Transform player;
void Update() {
transform.position = player.transform.position;
}
}
// Some stupid rigidbody based movement by Dani
using System;
using UnityEngine;
public class PlayerMovement : MonoBehaviour {
//Assingables
public Transform playerCam;
public Transform orientation;
//Other
private Rigidbody rb;
//Rotation and look
private float xRotation;
private float sensitivity = 150f;
private float sensMultiplier = 1f;
//Movement
public float moveSpeed = 4500;
public float maxSpeed = 20;
public bool grounded;
public LayerMask whatIsGround;
public float counterMovement = 0.175f;
private float threshold = 0.01f;
public float maxSlopeAngle = 35f;
//Crouch & Slide
private Vector3 crouchScale = new Vector3(1, 0.5f, 1);
private Vector3 playerScale;
public float slideForce = 400;
public float slideCounterMovement = 0.2f;
//Jumping
private bool readyToJump = true;
private float jumpCooldown = 0.25f;
public float jumpForce = 550f;
//Input
float x, y;
bool jumping, sprinting, crouching;
//Sliding
private Vector3 normalVector = Vector3.up;
private Vector3 wallNormalVector;
void Awake() {
rb = GetComponent<Rigidbody>();
}
void Start() {
playerScale = transform.localScale;
Cursor.lockState = CursorLockMode.Locked;
Cursor.visible = false;
}
private void FixedUpdate() {
Movement();
}
private void Update() {
MyInput();
Look();
}
/// <summary>
/// Find user input. Should put this in its own class but im lazy
/// </summary>
private void MyInput() {
x = Input.GetAxisRaw("Horizontal");
y = Input.GetAxisRaw("Vertical");
jumping = Input.GetButton("Jump");
crouching = Input.GetKey(KeyCode.LeftControl);
//Crouching
if (Input.GetKeyDown(KeyCode.LeftControl))
StartCrouch();
if (Input.GetKeyUp(KeyCode.LeftControl))
StopCrouch();
}
private void StartCrouch() {
transform.localScale = crouchScale;
transform.position = new Vector3(transform.position.x, transform.position.y - 0.5f, transform.position.z);
if (rb.velocity.magnitude > 0.5f) {
if (grounded) {
rb.AddForce(orientation.transform.forward * slideForce);
}
}
}
private void StopCrouch() {
transform.localScale = playerScale;
transform.position = new Vector3(transform.position.x, transform.position.y + 0.5f, transform.position.z);
}
private void Movement() {
//Extra gravity
rb.AddForce(Vector3.down * Time.deltaTime * 10);
//Find actual velocity relative to where player is looking
Vector2 mag = FindVelRelativeToLook();
float xMag = mag.x, yMag = mag.y;
//Counteract sliding and sloppy movement
CounterMovement(x, y, mag);
//If holding jump && ready to jump, then jump
if (readyToJump && jumping) Jump();
//Set max speed
float maxSpeed = this.maxSpeed;
//If sliding down a ramp, add force down so player stays grounded and also builds speed
if (crouching && grounded && readyToJump) {
rb.AddForce(Vector3.down * Time.deltaTime * 3000);
return;
}
//If speed is larger than maxspeed, cancel out the input so you don't go over max speed
if (x > 0 && xMag > maxSpeed) x = 0;
if (x < 0 && xMag < -maxSpeed) x = 0;
if (y > 0 && yMag > maxSpeed) y = 0;
if (y < 0 && yMag < -maxSpeed) y = 0;
//Some multipliers
float multiplier = 1f, multiplierV = 1f;
// Movement in air
if (!grounded) {
multiplier = 0.5f;
multiplierV = 0.5f;
}
// Movement while sliding
if (grounded && crouching) multiplierV = 0f;
//Apply forces to move player
rb.AddForce(orientation.transform.forward * y * moveSpeed * Time.deltaTime * multiplier * multiplierV);
rb.AddForce(orientation.transform.right * x * moveSpeed * Time.deltaTime * multiplier);
}
private void Jump() {
if (grounded && readyToJump) {
readyToJump = false;
//Add jump forces
rb.AddForce(Vector2.up * jumpForce * 1.5f);
rb.AddForce(normalVector * jumpForce * 0.5f);
//If jumping while falling, reset y velocity.
Vector3 vel = rb.velocity;
if (rb.velocity.y < 0.5f)
rb.velocity = new Vector3(vel.x, 0, vel.z);
else if (rb.velocity.y > 0)
rb.velocity = new Vector3(vel.x, vel.y / 2, vel.z);
Invoke(nameof(ResetJump), jumpCooldown);
}
}
private void ResetJump() {
readyToJump = true;
}
private float desiredX;
private void Look() {
float mouseX = Input.GetAxis("Mouse X") * sensitivity * Time.fixedDeltaTime * sensMultiplier;
float mouseY = Input.GetAxis("Mouse Y") * sensitivity * Time.fixedDeltaTime * sensMultiplier;
//Find current look rotation
Vector3 rot = playerCam.transform.localRotation.eulerAngles;
desiredX = rot.y + mouseX;
//Rotate, and also make sure we dont over- or under-rotate.
xRotation -= mouseY;
xRotation = Mathf.Clamp(xRotation, -90f, 90f);
//Perform the rotations
playerCam.transform.localRotation = Quaternion.Euler(xRotation, desiredX, 0);
orientation.transform.localRotation = Quaternion.Euler(0, desiredX, 0);
}
private void CounterMovement(float x, float y, Vector2 mag) {
if (!grounded || jumping) return;
//Slow down sliding
if (crouching) {
rb.AddForce(moveSpeed * Time.deltaTime * -rb.velocity.normalized * slideCounterMovement);
return;
}
//Counter movement
if (Math.Abs(mag.x) > threshold && Math.Abs(x) < 0.05f || (mag.x < -threshold && x > 0) || (mag.x > threshold && x < 0)) {
rb.AddForce(moveSpeed * orientation.transform.right * Time.deltaTime * -mag.x * counterMovement);
}
if (Math.Abs(mag.y) > threshold && Math.Abs(y) < 0.05f || (mag.y < -threshold && y > 0) || (mag.y > threshold && y < 0)) {
rb.AddForce(moveSpeed * orientation.transform.forward * Time.deltaTime * -mag.y * counterMovement);
}
//Limit diagonal running. This will also cause a full stop if sliding fast and un-crouching, so not optimal.
if (Mathf.Sqrt((Mathf.Pow(rb.velocity.x, 2) + Mathf.Pow(rb.velocity.z, 2))) > maxSpeed) {
float fallspeed = rb.velocity.y;
Vector3 n = rb.velocity.normalized * maxSpeed;
rb.velocity = new Vector3(n.x, fallspeed, n.z);
}
}
/// <summary>
/// Find the velocity relative to where the player is looking
/// Useful for vectors calculations regarding movement and limiting movement
/// </summary>
/// <returns></returns>
public Vector2 FindVelRelativeToLook() {
float lookAngle = orientation.transform.eulerAngles.y;
float moveAngle = Mathf.Atan2(rb.velocity.x, rb.velocity.z) * Mathf.Rad2Deg;
float u = Mathf.DeltaAngle(lookAngle, moveAngle);
float v = 90 - u;
float magnitue = rb.velocity.magnitude;
float yMag = magnitue * Mathf.Cos(u * Mathf.Deg2Rad);
float xMag = magnitue * Mathf.Cos(v * Mathf.Deg2Rad);
return new Vector2(xMag, yMag);
}
private bool IsFloor(Vector3 v) {
float angle = Vector3.Angle(Vector3.up, v);
return angle < maxSlopeAngle;
}
private bool cancellingGrounded;
/// <summary>
/// Handle ground detection
/// </summary>
private void OnCollisionStay(Collision other) {
//Make sure we are only checking for walkable layers
int layer = other.gameObject.layer;
if (whatIsGround != (whatIsGround | (1 << layer))) return;
//Iterate through every collision in a physics update
for (int i = 0; i < other.contactCount; i++) {
Vector3 normal = other.contacts[i].normal;
//FLOOR
if (IsFloor(normal)) {
grounded = true;
cancellingGrounded = false;
normalVector = normal;
CancelInvoke(nameof(StopGrounded));
}
}
//Invoke ground/wall cancel, since we can't check normals with CollisionExit
float delay = 3f;
if (!cancellingGrounded) {
cancellingGrounded = true;
Invoke(nameof(StopGrounded), Time.deltaTime * delay);
}
}
private void StopGrounded() {
grounded = false;
}
}
Thank you in advance.
Related
i want to multiply a float. in the unity editor everything is ok too, in the build it is going up slower all of a sudden.
i tried reimporting all assets and restart my pc but that does not help either.
I tried to build it again but that did not help.
I do not know what to do now, does anyone know how to fix this problem?
here is my build output: https://i.stack.imgur.com/ry5PI.png
code:
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.SceneManagement;
public class PlayerController : MonoBehaviour
{
[Header("")]
[Header("Move Settings")]
[Header("")]
public float MovementSpeed = 5f;
public float SprintSpeed = 7f;
public float JumpForce = 5f;
public float minJumpForce = 3f;
[Header("")]
[Header("Stamina Settings")]
[Header("")]
public float fillStamina = 1f;
public float MaxStamina = 10000f;
public float Stamina = 10000f;
public Slider staminaBar;
public GameObject SliderFill;
public GameObject SliderB;
[Header("")]
[Header("Health Settings")]
[Header("")]
public float fillHealth = 1f;
public float MaxHealth = 100f;
public float Health = 100f;
public Slider HealthBar;
[Header("")]
[Header("Player Settings")]
[Header("")]
Rigidbody2D body;
public static PlayerController instance;
public GameObject DeathObj;
float horizontal;
float vertical;
private Rigidbody2D _rigidbody;
private bool Sprint = false;
//private bool ActivateLowStamina = false;
//private bool LowStamina = false;
private float move;
private void Awake()
{
instance = this;
}
void Start()
{
_rigidbody = GetComponent<Rigidbody2D>();
//body = GetComponent<Rigidbody2D>();
Stamina = MaxStamina;
staminaBar.maxValue = MaxStamina;
staminaBar.value = MaxStamina;
HealthBar.maxValue = MaxHealth;
HealthBar.value = MaxHealth;
//ActivateLowStamina = false;
//lowTxt.gameObject.SetActive(false);
}
void Update()
{
horizontal = Input.GetAxisRaw("Horizontal");
vertical = Input.GetAxisRaw("Vertical");
//transform.rotation = Quaternion.identity;
staminaBar.value = Stamina;
HealthBar.value = Health;
//var movement = Input.GetAxis("Horizontal");
if (Health < 1)
{
Die();
}
if (Stamina <= 0)
{
Stamina = 0;
}
if(Health <= 0)
{
Health = 0;
}
if (Stamina < 3000)
{
SliderFill.GetComponent<Image>().color = new Color32(213, 217, 0, 255);
SliderB.GetComponent<Image>().color = new Color32(11, 217, 0, 47);
}
else
{
SliderFill.GetComponent<Image>().color = new Color32(11, 217, 0, 255);
SliderB.GetComponent<Image>().color = new Color32(0, 255, 12, 47);
}
if (Input.GetKey("left shift"))
{
Sprint = true;
}
//if(Stamina < 100)
//{
// ActivateLowStamina = false;
//}
//else
//{
// ActivateLowStamina = true;
//}
//if(ActivateLowStamina == true)
// {
// lowTxt.gameObject.SetActive(true);
// }
if (Mathf.Abs(_rigidbody.velocity.x) == 0f && Stamina < MaxStamina && Mathf.Abs(_rigidbody.velocity.y) == 0f)
{
Stamina += fillStamina;
}
Health += fillHealth;
if (Input.GetButtonDown("Jump") && Mathf.Abs(_rigidbody.velocity.y) < 0.001f) {
if(Stamina > 10)
{
_rigidbody.AddForce(new Vector2(0, JumpForce), ForceMode2D.Impulse);
//_rigidbody.AddForce(Vector2.up * JumpForce);
UseStamina(700);
}
else
{
_rigidbody.AddForce(new Vector2(0, minJumpForce), ForceMode2D.Impulse);
//_rigidbody.AddForce(Vector2.up * JumpForce);
UseStamina(300);
}
}
}
public void UseStamina(float amount)
{
if (Stamina - amount >= 0)
{
Stamina -= amount;
}
}
private void FixedUpdate()
{
move = Input.GetAxis("Horizontal");
if (Sprint == true && Stamina > 10)
{
_rigidbody.velocity = new Vector2(move * SprintSpeed, _rigidbody.velocity.y);
if (Mathf.Abs(_rigidbody.velocity.x) != 0f)
{
UseStamina(10);
}
Sprint = false;
}
else
{
if (Stamina > 10)
{
_rigidbody.velocity = new Vector2(move * MovementSpeed, _rigidbody.velocity.y);
if(Mathf.Abs(_rigidbody.velocity.x) != 0f)
{
UseStamina(2f);
}
}
else
{
_rigidbody.velocity = new Vector2(move * 1f, _rigidbody.velocity.y);
}
}
//if(Mathf.Abs(_rigidbody.velocity.x) != 0f)
//{
//Stamina -= 1;
//}
}
public void Die()
{
if(Health < 1)
{
Time.timeScale = 0;
DeathObj.SetActive(true);
//SceneManager.LoadScene(SceneManager.GetActiveScene().name);
}
}
}
//_rigidbody.velocity = new Vector2(horizontal * MovementSpeed, vertical * SprintSpeed);
//transform.position += new Vector3(movement, 0, 0) * Time.deltaTime * SprintSpeed;
//transform.Translate(new Vector3(-3f, 0, 0) * Time.deltaTime);
//_rigidbody.velocity = new Vector2(MovementSpeed, 0);
//_rigidbody.AddForce(new Vector2(MovementSpeed, MovementSpeed));
//transform.position += new Vector3(movement, 0, 0) * Time.deltaTime * MovementSpeed;
//_rigidbody.velocity = new Vector2(horizontal * MovementSpeed, vertical * MovementSpeed);
//transform.position += new Vector3(movement, 0, 0) * Time.deltaTime * 3f;
//body.velocity = new Vector2(horizontal * MovementSpeed, vertical * MovementSpeed);
//var movement = Input.GetAxis("Horizontal"); ```
What you experience is the typical frame-rate dependent code.
Every frame you do
Stamina += fillStamina;
and
Health += fillHealth;
However, what if on one device you have 60 frames per second, on another weaker device only 30?
On the weaker device it will take twice as long to raise the value.
Therefore you should use Time.deltaTime which is the time passed since the last frame was rendered.
By multiplying
X * Time.deltaTime
you convert a value X from value per frame into a value per second which is now independent of the capacity of the device and the frame-rate. Across all devices it will now always take the same effective time in seconds.
You will of course have to tweak your values but in general you would do e.g.
Stamina += fillStaminaPerSecond * Time.deltaTime;
and accordingly
Health += fillHealthPerSecond * Time.deltaTime;
And accordingly also for the continous usages
UseStamina(10 * Time.deltaTime);
and
UseStamina(2f * Time.deltaTime);
as said you might have to adjust the values since now they are more or less decided by 60 (whatever the frame-rate is).
However, for the single event calls for the jump you do not want/need the Time.deltaTime since these are no continous calls.
Btw instead of using GetComponent over and over again rather do it once in Awake or Start and store the reference in a field and later reuse it!
And instead of
[Header("")]
you should probably rather use
[Space]
;)
I have a 3D object that I want to rotate with mouse/finger swipe, so I made the script below.
The object's rotation looks smooth on editor, but when playing the game on real device (android), the rotation didn't follow the finger movement immediately, it takes some milliseconds to follow finger, it isn't smooth and the controls become hard and frustrating!
float sensitivity = 0.8f;
Vector2 firstPressPos;
Vector2 secondPressPos;
void Update()
{
if (Input.GetMouseButtonDown(0))
{
//save began touch 2d point
firstPressPos = new Vector3(Input.mousePosition.x, Input.mousePosition.y);
}
if (Input.GetMouseButton(0))
{
//save ended touch 2d point
secondPressPos = new Vector3(Input.mousePosition.x, Input.mousePosition.y);
if (firstPressPos != secondPressPos)
{
float RotX = Input.GetAxis("Mouse X") * sensitivity * Time.deltaTime;
float RotY = Input.GetAxis("Mouse Y") * sensitivity * Time.deltaTime;
transform.RotateAround(Vector3.up, RotX);
transform.RotateAround(Vector3.right, -RotY);
}
}
}
try this code
// Screen Touches
Vector2?[] oldTouchPositions = {
null,
null
};
// Rotation Speed
public float rotSpeed = 0.5f;
public void Update()
{
if (Input.touchCount == 0)
{
oldTouchPositions[0] = null;
oldTouchPositions[1] = null;
}
else if (Input.touchCount == 1)
{
if (oldTouchPositions[0] == null || oldTouchPositions[1] != null)
{
oldTouchPositions[0] = Input.GetTouch(0).position;
oldTouchPositions[1] = null;
}
else
{
Vector2 newTouchPosition = Input.GetTouch(0).position;
float distanceX = (oldTouchPositions[0] - newTouchPosition).Value.x;
float distanceY = (oldTouchPositions[0] - newTouchPosition).Value.y;
float rotX = distanceX * rotSpeed * Mathf.Deg2Rad;
float rotY = distanceY * rotSpeed * Mathf.Deg2Rad;
transform.Rotate(Vector3.up, rotX * 5, Space.Self);
transform.Rotate(Vector3.left, rotY * 5, Space.Self);
oldTouchPositions[0] = newTouchPosition;
}
}
else
{
if (oldTouchPositions[1] == null)
{
oldTouchPositions[0] = Input.GetTouch(0).position;
oldTouchPositions[1] = Input.GetTouch(1).position;
}
else
{
}
}
}
Here's a script I found a few years back that manipulates X axis spin with Mouse or Touches. It seems to work well with touches, but not as good with Mouse. Try it and let me know if it behaves a bit better. This one should adjust the spinning speed dynamically:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class SpinDrag : MonoBehaviour {
float f_lastX = 0.0f;
float f_difX = 0.5f;
float f_steps = 0.0f;
int i_direction = 1;
// Use this for initialization
void Start()
{
}
// Update is called once per frame
void Update()
{
if (Input.GetMouseButtonDown(0))
{
f_difX = 0.0f;
}
else if (Input.GetMouseButton(0))
{
f_difX = Mathf.Abs(f_lastX - Input.GetAxis("Mouse X"));
if (f_lastX < Input.GetAxis("Mouse X"))
{
i_direction = -1;
transform.Rotate(Vector3.up, -f_difX);
}
if (f_lastX > Input.GetAxis("Mouse X"))
{
i_direction = 1;
transform.Rotate(Vector3.up, f_difX);
}
f_lastX = -Input.GetAxis("Mouse X");
}
else
{
if (f_difX > 0.5f) f_difX -= 0.05f;
if (f_difX < 0.5f) f_difX += 0.05f;
transform.Rotate(Vector3.up, f_difX * i_direction);
}
}
}
I'm doing this thing where an object is moving on a plane, and the camera is in the center of it. I got it so the camera rotates along with the mouse, and when the main camera sees the game object, it stops. So I was using the onbecamevisible() and onbecameinvisible() functions, but that applies to any camera, including the scene view. How do I make it so the objects stops when seen only by the main game camera?
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class cubeMove : MonoBehaviour,moveObject
{
Camera cam;
public Transform checkedObject;
void Start()
{
cam = GetComponent<Camera>();
}
void Update()
{
Vector3 viewPos = cam.WorldToViewportPoint(checkedObject.position);
if ()
move();
}
public void move()
{
transform.Rotate(new Vector3(15, 30, 45) * Time.deltaTime);
}
}
Here's my Camera Script
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Camera : 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 rotationX = 0F;
float rotationY = 0F;
private List<float> rotArrayX = new List<float>();
float rotAverageX = 0F;
private List<float> rotArrayY = new List<float>();
float rotAverageY = 0F;
public float frameCounter = 20;
Quaternion originalRotation;
void Update()
{
if (axes == RotationAxes.MouseXAndY)
{
rotAverageY = 0f;
rotAverageX = 0f;
rotationY += Input.GetAxis("Mouse Y") * sensitivityY;
rotationX += Input.GetAxis("Mouse X") * sensitivityX;
rotArrayY.Add(rotationY);
rotArrayX.Add(rotationX);
if (rotArrayY.Count >= frameCounter)
{
rotArrayY.RemoveAt(0);
}
if (rotArrayX.Count >= frameCounter)
{
rotArrayX.RemoveAt(0);
}
for (int j = 0; j < rotArrayY.Count; j++)
{
rotAverageY += rotArrayY[j];
}
for (int i = 0; i < rotArrayX.Count; i++)
{
rotAverageX += rotArrayX[i];
}
rotAverageY /= rotArrayY.Count;
rotAverageX /= rotArrayX.Count;
rotAverageY = ClampAngle(rotAverageY, minimumY, maximumY);
rotAverageX = ClampAngle(rotAverageX, minimumX, maximumX);
Quaternion yQuaternion = Quaternion.AngleAxis(rotAverageY, Vector3.left);
Quaternion xQuaternion = Quaternion.AngleAxis(rotAverageX, Vector3.up);
transform.localRotation = originalRotation * xQuaternion * yQuaternion;
}
else if (axes == RotationAxes.MouseX)
{
rotAverageX = 0f;
rotationX += Input.GetAxis("Mouse X") * sensitivityX;
rotArrayX.Add(rotationX);
if (rotArrayX.Count >= frameCounter)
{
rotArrayX.RemoveAt(0);
}
for (int i = 0; i < rotArrayX.Count; i++)
{
rotAverageX += rotArrayX[i];
}
rotAverageX /= rotArrayX.Count;
rotAverageX = ClampAngle(rotAverageX, minimumX, maximumX);
Quaternion xQuaternion = Quaternion.AngleAxis(rotAverageX, Vector3.up);
transform.localRotation = originalRotation * xQuaternion;
}
else
{
rotAverageY = 0f;
rotationY += Input.GetAxis("Mouse Y") * sensitivityY;
rotArrayY.Add(rotationY);
if (rotArrayY.Count >= frameCounter)
{
rotArrayY.RemoveAt(0);
}
for (int j = 0; j < rotArrayY.Count; j++)
{
rotAverageY += rotArrayY[j];
}
rotAverageY /= rotArrayY.Count;
rotAverageY = ClampAngle(rotAverageY, minimumY, maximumY);
Quaternion yQuaternion = Quaternion.AngleAxis(rotAverageY, Vector3.left);
transform.localRotation = originalRotation * yQuaternion;
}
}
void Start()
{
Rigidbody rb = GetComponent<Rigidbody>();
if (rb)
rb.freezeRotation = true;
originalRotation = transform.localRotation;
}
public static float ClampAngle(float angle, float min, float max)
{
angle = angle % 360;
if ((angle >= -360F) && (angle <= 360F))
{
if (angle < -360F)
{
angle += 360F;
}
if (angle > 360F)
{
angle -= 360F;
}
}
return Mathf.Clamp(angle, min, max);
}
}
SphereMove
public class sphereMove : MonoBehaviour,moveObject {
public float delta = 1.5f;
public float speed = 2.0f;
private Vector3 startPos;
public UnityEngine.Camera cam;
public Transform checkedObject;
bool isMoving;
void Start()
{
isMoving = true;
cam = Camera.main;
}
void Update()
{
Vector3 viewPos = cam.WorldToViewportPoint(checkedObject.position);
if (viewPos.x > 0 && viewPos.x <= 1 && viewPos.y >= 0 && viewPos.y <= 1 && viewPos.z > 0)
isMoving = false;
else
isMoving = true;
if (isMoving)
move();
}
public void move()
{
Vector3 v = startPos;
v.x += delta * Mathf.Sin(Time.time * speed);
transform.position = v;
}
}
You can use the Camera.WorldToViewport function, using your Main Camera to call it and giving in parameter the position of the object your are checking. If the x and y coordinates values of the result vector are between 0 and 1 and the z value is superior to 0, it means the center of your object is seen by your camera.
UnityEngine.Camera cam;
bool isMoving;
void Start()
{
cam = UnityEngine.Camera.main;
isMoving = true;
}
void Update()
{
Vector3 viewPos = cam.WorldToViewportPoint(checkedObject.position);
if (viewPos.x >= 0 && viewPos.x <= 1 && viewPos.y >= 0 && viewPos.y <= 1 && viewPos.z > 0)
{
// Your object is in the range of the camera, you can apply your behaviour
isMoving = false;
}
else
isMoving = true;
if(isMoving)
Move();
}
Methods suggested does not work in your case because you've made a class called Camera which has exactly the same name as Unity's Camera component.
I would suggest you use the approach from the community wiki. It's simple enough to understand and lets you check visibility for each camera.
You can create an extension class for the Camera component :
public static class CameraEx
{
public static bool IsObjectVisible(this UnityEngine.Camera #this, Renderer renderer)
{
return GeometryUtility.TestPlanesAABB(GeometryUtility.CalculateFrustumPlanes(#this), renderer.bounds);
}
}
The you can call that from each object separately like such :
// UnityEngine.Camera cam1;
// UnityEngine.Camera cam2;
void Update()
{
bool isVisibleForCamera1 = cam1.IsObjectVisible(GetComponent<MeshRenderer>());
bool isVisibleForCamera2 = cam2.IsObjectVisible(GetCoponent<SpriteRenderer>());
}
Here you can find whole documentation about GeometryUtility
so for the past few days I've been working on a character controller in Unity3D using mecanim. It's not based off of my own code, but off of a tutorial I found online, of course that tutorial was meant for Unity 4, so I am running in to small problems here and there, but nothing I couldn't fix up until now.
So the basic problem is that my character seems to (without reason) stop all his momentum and slowly turns around when I try to make a hard 180 degrees turn, afterwards he continues to run like normal again, but I don't see why he would suddenly stop turning.
Here is my character logic script:
using UnityEngine;
using System.Collections;
public class characterLogic : MonoBehaviour {
[SerializeField]
private Animator animator;
[SerializeField]
private FollowCamera gamecam;
[SerializeField]
private float directionSpeed = 1.5f;
[SerializeField]
private float directionDampTime = 0.25f;
[SerializeField]
private float rotationDegreePerSecond = 120f;
[SerializeField]
private float speedDampTime = 0.05f;
private float speed = 0.0f;
private float direction = 0.0f;
private float charAngle = 0f;
private float horizontal = 0.0f;
private float vertical = 0.0f;
private AnimatorStateInfo stateInfo;
private AnimatorTransitionInfo transInfo;
private int m_LocomotionId = 0;
private int m_LocomotionPivotLId = 0;
private int m_LocomotionPivotRId = 0;
private int m_LocomotionPivotLTransId = 0;
private int m_LocomotionPivotRTransId = 0;
public Animator Animator
{
get
{
return this.animator;
}
}
public float Speed
{
get
{
return this.speed;
}
}
public float LocomotionThreshold { get { return 0.2f; } }
// Use this for initialization
void Start () {
animator = GetComponent<Animator>();
if(animator.layerCount >= 2)
{
animator.SetLayerWeight(1, 1);
}
m_LocomotionId = Animator.StringToHash("Base Layer.Locomotion");
m_LocomotionPivotLId = Animator.StringToHash("Base Layer.LocomotionPivotL");
m_LocomotionPivotRId = Animator.StringToHash("Base Layer.LocomotionPivotR");
m_LocomotionPivotLTransId = Animator.StringToHash("Base Layer.Locomotion -> Base Layer.LocomotionPivotL");
m_LocomotionPivotRTransId = Animator.StringToHash("Base Layer.Locomotion -> Base Layer.LocomotionPivotR");
}
public void keysToWorldSpace (Transform root, Transform camera, ref float directionOut, ref float speedOut, ref float angleOut, bool isPivoting){
Vector3 rootDirection = root.forward;
Vector3 keyDirection = new Vector3 (horizontal, 0, vertical);
speedOut = keyDirection.sqrMagnitude;
//get camera rotation
Vector3 cameraDirection = camera.forward;
cameraDirection.y = 0.0f;
Quaternion referentialShift = Quaternion.FromToRotation (Vector3.forward, cameraDirection);
//convert key input to world space coordinates
Vector3 moveDirection = referentialShift * keyDirection;
Vector3 axisSign = Vector3.Cross (moveDirection, rootDirection);
Debug.DrawRay (new Vector3(root.position.x, root.position.y + 2f, root.position.z), moveDirection, Color.green);
Debug.DrawRay (new Vector3(root.position.x, root.position.y + 2f, root.position.z), axisSign, Color.red);
Debug.DrawRay (new Vector3(root.position.x, root.position.y + 2f, root.position.z), rootDirection, Color.magenta);
Debug.DrawRay (new Vector3(root.position.x, root.position.y + 2f, root.position.z), keyDirection, Color.blue);
float angleRootToMove = Vector3.Angle(rootDirection, moveDirection) * (axisSign.y >= 0 ? -1f : 1f);
if (!isPivoting)
{
angleOut = angleRootToMove;
}
angleRootToMove /= 180f;
directionOut = angleRootToMove * directionSpeed;
}
// Update is called once per frame
void Update () {
if (animator) {
stateInfo = animator.GetCurrentAnimatorStateInfo(0);
transInfo = animator.GetAnimatorTransitionInfo(0);
horizontal = Input.GetAxis("Horizontal");
vertical = Input.GetAxis("Vertical");
charAngle = 0f;
direction = 0f;
keysToWorldSpace (this.transform, gamecam.transform, ref direction, ref speed, ref charAngle, isInPivot());
animator.SetFloat ("Speed", speed);
animator.SetFloat ("Direction", direction, directionDampTime, Time.deltaTime);
if(speed > LocomotionThreshold){
if(!isInPivot()){
Animator.SetFloat("Angle", charAngle);
}
}
if(speed < LocomotionThreshold && Mathf.Abs(horizontal) < 0.05f){
animator.SetFloat("Direction", 0f);
animator.SetFloat("Speed", speed, speedDampTime, Time.deltaTime);
}
Debug.Log(Speed);
Debug.Log(charAngle);
}
}
void FixedUpdate() {
if (IsInLocomotion () && ((direction >= 0 && horizontal >= 0) || (direction < 0 && horizontal < 0))) {
Vector3 rotationAmount = Vector3.Lerp(Vector3.zero, new Vector3(0f, rotationDegreePerSecond * (horizontal < 0f ? -1f : 1f), 0f), Mathf.Abs(horizontal));
Quaternion deltaRotation = Quaternion.Euler(rotationAmount * Time.deltaTime);
this.transform.rotation = (this.transform.rotation * deltaRotation);
}
}
public bool isInPivot(){
return stateInfo.fullPathHash == m_LocomotionPivotLId ||
stateInfo.fullPathHash == m_LocomotionPivotRId ||
transInfo.nameHash == m_LocomotionPivotLTransId ||
transInfo.nameHash == m_LocomotionPivotRTransId;
}
public bool IsInLocomotion(){
return stateInfo.fullPathHash == m_LocomotionId;
}
}
I believe it either has to do something with this script or with the transitions within mecanim. I also ported the finished product (found here: https://github.com/jm991/UnityThirdPersonTutorial ) of the tutorial over to Unity 5 and didn't experience the same problem there, I am not entirely sure what the difference is which gives me this problem, but if any of you know or find out, please let me know.
I found the problem myself already!
Here is the new code in case anyone is interested in the future:
using UnityEngine;
using System.Collections;
public class characterLogic : MonoBehaviour {
[SerializeField]
private Animator animator;
[SerializeField]
private FollowCamera gamecam;
[SerializeField]
private float directionSpeed = 1.5f;
[SerializeField]
private float directionDampTime = 0.25f;
[SerializeField]
private float rotationDegreePerSecond = 120f;
[SerializeField]
private float speedDampTime = 0.05f;
[SerializeField]
private float fovDampTime = 3f;
private float horizontal = 0.0f;
private float vertical = 0.0f;
private float speed = 0.0f;
private float direction = 0.0f;
private float charAngle = 0f;
private const float SPRINT_SPEED = 2.0f;
private const float SPRINT_FOV = 75.0f;
private const float NORMAL_FOV = 60.0f;
private const float WALK_SPEED = 0.1f;
private AnimatorStateInfo stateInfo;
private AnimatorTransitionInfo transInfo;
private int m_LocomotionId = 0;
private int m_LocomotionPivotLId = 0;
private int m_LocomotionPivotRId = 0;
private int m_LocomotionPivotLTransId = 0;
private int m_LocomotionPivotRTransId = 0;
public Animator Animator
{
get
{
return this.animator;
}
}
public float Speed
{
get
{
return this.speed;
}
}
public float LocomotionThreshold { get { return 0.2f; } }
// Use this for initialization
void Start () {
animator = GetComponent<Animator>();
if(animator.layerCount >= 2)
{
animator.SetLayerWeight(1, 1);
}
m_LocomotionId = Animator.StringToHash("Base Layer.Locomotion");
m_LocomotionPivotLId = Animator.StringToHash("Base Layer.LocomotionPivotL");
m_LocomotionPivotRId = Animator.StringToHash("Base Layer.LocomotionPivotR");
m_LocomotionPivotLTransId = Animator.StringToHash("Base Layer.Locomotion -> Base Layer.LocomotionPivotL");
m_LocomotionPivotRTransId = Animator.StringToHash("Base Layer.Locomotion -> Base Layer.LocomotionPivotR");
}
public void keysToWorldSpace (Transform root, Transform camera, ref float directionOut, ref float speedOut, ref float angleOut, bool isPivoting){
Vector3 rootDirection = root.forward;
Vector3 keyDirection = new Vector3 (horizontal, 0, vertical);
speedOut = keyDirection.sqrMagnitude;
//get camera rotation
Vector3 cameraDirection = camera.forward;
cameraDirection.y = 0.0f;
Quaternion referentialShift = Quaternion.FromToRotation(Vector3.forward, Vector3.Normalize(cameraDirection));
//convert key input to world space coordinates
Vector3 moveDirection = referentialShift * keyDirection;
Vector3 axisSign = Vector3.Cross (moveDirection, rootDirection);
Debug.DrawRay (new Vector3(root.position.x, root.position.y + 2f, root.position.z), moveDirection, Color.green);
Debug.DrawRay (new Vector3(root.position.x, root.position.y + 2f, root.position.z), axisSign, Color.red);
Debug.DrawRay (new Vector3(root.position.x, root.position.y + 2f, root.position.z), rootDirection, Color.magenta);
Debug.DrawRay (new Vector3(root.position.x, root.position.y + 2f, root.position.z), keyDirection, Color.blue);
float angleRootToMove = Vector3.Angle(rootDirection, moveDirection) * (axisSign.y >= 0 ? -1f : 1f);
if (!isPivoting)
{
angleOut = angleRootToMove;
}
angleRootToMove /= 180f;
directionOut = angleRootToMove * directionSpeed;
}
// Update is called once per frame
void Update () {
if (animator) {
stateInfo = animator.GetCurrentAnimatorStateInfo(0);
transInfo = animator.GetAnimatorTransitionInfo(0);
horizontal = Input.GetAxis("Horizontal");
vertical = Input.GetAxis("Vertical");
charAngle = 0f;
direction = 0f;
float charSpeed = 0f;
keysToWorldSpace (this.transform, gamecam.transform, ref direction, ref charSpeed, ref charAngle, isInPivot());
if (Input.GetButton("Sprint"))
{
speed = Mathf.Lerp(speed, SPRINT_SPEED, Time.deltaTime);
gamecam.GetComponent<Camera>().fieldOfView = Mathf.Lerp(gamecam.GetComponent<Camera>().fieldOfView, SPRINT_FOV, fovDampTime * Time.deltaTime);
}
else
{
speed = charSpeed;
gamecam.GetComponent<Camera>().fieldOfView = Mathf.Lerp(gamecam.GetComponent<Camera>().fieldOfView, NORMAL_FOV, fovDampTime * Time.deltaTime);
}
if (Input.GetButton("Walk"))
{
speed = Mathf.Lerp(speed, WALK_SPEED, Time.deltaTime);
}
else
{
speed = charSpeed;
}
animator.SetFloat("Speed", speed, speedDampTime, Time.deltaTime);
animator.SetFloat("Direction", direction, directionDampTime, Time.deltaTime);
if(speed > LocomotionThreshold){
if(!isInPivot()){
Animator.SetFloat("Angle", charAngle);
}
}
if(speed < LocomotionThreshold && Mathf.Abs(horizontal) < 0.05f){
animator.SetFloat("Direction", 0f);
animator.SetFloat("Speed", speed, speedDampTime, Time.deltaTime);
}
Debug.Log(Speed);
Debug.Log(charAngle);
}
}
void FixedUpdate() {
if (IsInLocomotion () && ((direction >= 0 && horizontal >= 0) || (direction < 0 && horizontal < 0))) {
Vector3 rotationAmount = Vector3.Lerp(Vector3.zero, new Vector3(0f, rotationDegreePerSecond * (horizontal < 0f ? -1f : 1f), 0f), Mathf.Abs(horizontal));
Quaternion deltaRotation = Quaternion.Euler(rotationAmount * Time.deltaTime);
this.transform.rotation = (this.transform.rotation * deltaRotation);
}
}
public bool isInPivot(){
return stateInfo.fullPathHash == m_LocomotionPivotLId ||
stateInfo.fullPathHash == m_LocomotionPivotRId ||
transInfo.nameHash == m_LocomotionPivotLTransId ||
transInfo.nameHash == m_LocomotionPivotRTransId;
}
public bool IsInLocomotion(){
return stateInfo.fullPathHash == m_LocomotionId;
}
}
It turned out that the guy who made the original code was using a dampTime on his speed due to which he wouldn't instantly stand still if he'd let go off a button. It's something he hadn't explained in his tutorial yet, so I must have missed it. Anyways I hope this might help anyone in the future with a similar problem.
I have created a player inside of Unity 3D with a Character Controller, I got him all configured to walk, look around and such. So when using a normal vector3 the player starts of smoothly until it's at his max speed. When I don't normalize it, you can walk faster by pressing W and D/A at the same time, you go about 50% faster than normal. But when I normalize it, the player is immediately at it's max speed. Which looks very weird.
How would I do it so the player starts smoothed out before it's at it max speed?
Here's my full script, incase you need it:
using UnityEngine;
using System.Collections;
public class FirstPersonController : MonoBehaviour {
CharacterController cc;
public float baseSpeed = 3.0f;
public float mouseSensitivity = 1.0f;
public bool inverted = false;
public bool gravityOn = true;
public bool lockMouse = true;
float mouseRotX = 0,
mouseRotY = 0;
float curSpeed = 3.0f;
float invertion = 1.0f;
float gravitySpeed = 0;
string h = "Horizontal";
string v = "Vertical";
void Start () {
cc = gameObject.GetComponent<CharacterController>();
if (lockMouse && Debug.isDebugBuild)
Screen.lockCursor = true;
if (!Debug.isDebugBuild)
Screen.lockCursor = true;
}
void FixedUpdate () {
curSpeed = baseSpeed;
if (inverted)
invertion = -1.0f;
else
invertion = 1.0f;
mouseRotX = Input.GetAxis("Mouse X") * mouseSensitivity;
mouseRotY -= invertion * Input.GetAxis("Mouse Y") * mouseSensitivity;;
mouseRotY = Mathf.Clamp(mouseRotY, -90.0f, 90.0f);
float forwardMovement = Input.GetAxis(v);
float strafeMovement = Input.GetAxis(h);
Vector3 speed = new Vector3(strafeMovement, 0, forwardMovement);
speed = transform.rotation * speed;
Debug.Log(speed.normalized);
//Applying Gravity
if (cc.isGrounded)
{
gravitySpeed = 0.0f;
}
else if (gravityOn)
{
if (gravitySpeed >= 20.0f)
{
gravitySpeed = 20.0f;
}
if (cc.isGrounded == false)
{
gravitySpeed += Physics.gravity.y * Time.deltaTime;
}
cc.Move(new Vector3(0, gravitySpeed, 0) * Time.deltaTime);
}
//Applying movement and rotation.
cc.Move(speed.normalized * curSpeed * Time.deltaTime);
transform.Rotate(0, mouseRotX, 0);
Camera.main.transform.localRotation = Quaternion.Euler(mouseRotY, 0 ,0);
}
}
The feature you want to get is uniformly accelerated motion.
You need something like this:
Vector3 _speed = Vector3.zero;
const float KDrag = 0.25f;
void FixedUpdate ()
{
float forwardMovement = Input.GetAxis(v);
float strafeMovement = Input.GetAxis(h);
Vector3 acceleration = cc.transform.right * strafeMovement + cc.transform.forward * forwardMovement;
_speed += acceleration * Time.fixedDeltaTime;
_speed -= _speed * KDrag * Time.fixedDeltaTime;
cc.Move( _speed * Time.fixedDeltaTime );
}