my code:
using UnityEngine;
using System.Collections;
[RequireComponent(typeof(Controller2D))]
public class Player : MonoBehaviour
{
public float jumpHeight = 4;
public float timeToJumpApex = .4f;
float accelerationTimeAirborne = .2f;
float accelerationTimeGrounded = .1f;
float moveSpeed = 6;
float gravity;
float jumpVelocity;
Vector3 velocity;
float velocityXSmoothing;
Controller2D controller;
void Start()
{
controller = GetComponent<Controller2D>();
gravity = -(2 * jumpHeight) / Mathf.Pow(timeToJumpApex, 2);
jumpVelocity = Mathf.Abs(gravity) * timeToJumpApex;
print("Gravity: " + gravity + " Jump Velocity: " + jumpVelocity);
}
void Update()
{
if (controller.collisions.above || controller.collisions.below)
{
velocity.y = 0;
}
Vector2 input = new Vector2(Input.GetAxisRaw("Horizontal"), Input.GetAxisRaw("Vertical"));
if (Input.GetKeyDown(KeyCode.Space) && controller.collisions.below)
{
velocity.y = jumpVelocity;
}
float targetVelocityX = input.x * moveSpeed;
velocity.x = Mathf.SmoothDamp(velocity.x, targetVelocityX, ref velocityXSmoothing, (controller.collisions.below) ? accelerationTimeGrounded : accelerationTimeAirborne);
velocity.y += gravity * Time.deltaTime;
controller.Move(velocity * Time.deltaTime);
}
}
Controller2D code:
using UnityEngine;
using System.Collections;
[RequireComponent(typeof(BoxCollider2D))]
public class Controller2D : MonoBehaviour
{
public LayerMask collisionMask;
const float skinWidth = .015f;
public int horizontalRayCount = 4;
public int verticalRayCount = 4;
float horizontalRaySpacing;
float verticalRaySpacing;
new BoxCollider2D collider;
RaycastOrigins raycastOrigins;
internal object collisions;
void Start()
{
collider = GetComponent<BoxCollider2D>();
CalculateRaySpacing();
}
public void Move(Vector3 velocity)
{
UpdateRaycastOrigins();
if (velocity.x != 0)
{
HorizontalCollisions(ref velocity);
}
if (velocity.y != 0)
{
VerticalCollisions(ref velocity);
}
transform.Translate(velocity);
}
void HorizontalCollisions(ref Vector3 velocity)
{
float directionX = Mathf.Sign(velocity.x);
float rayLength = Mathf.Abs(velocity.x) + skinWidth;
for (int i = 0; i < horizontalRayCount; i++)
{
Vector2 rayOrigin = (directionX == -1) ? raycastOrigins.bottomLeft : raycastOrigins.bottomRight;
rayOrigin += Vector2.up * (horizontalRaySpacing * i);
RaycastHit2D hit = Physics2D.Raycast(rayOrigin, Vector2.right * directionX, rayLength, collisionMask);
Debug.DrawRay(rayOrigin, Vector2.right * directionX * rayLength, Color.red);
if (hit)
{
velocity.x = (hit.distance - skinWidth) * directionX;
rayLength = hit.distance;
}
}
}
void VerticalCollisions(ref Vector3 velocity)
{
float directionY = Mathf.Sign(velocity.y);
float rayLength = Mathf.Abs(velocity.y) + skinWidth;
for (int i = 0; i < verticalRayCount; i++)
{
Vector2 rayOrigin = (directionY == -1) ? raycastOrigins.bottomLeft : raycastOrigins.topLeft;
rayOrigin += Vector2.right * (verticalRaySpacing * i + velocity.x);
RaycastHit2D hit = Physics2D.Raycast(rayOrigin, Vector2.up * directionY, rayLength, collisionMask);
Debug.DrawRay(rayOrigin, Vector2.up * directionY * rayLength, Color.red);
if (hit)
{
velocity.y = (hit.distance - skinWidth) * directionY;
rayLength = hit.distance;
}
}
}
void UpdateRaycastOrigins()
{
Bounds bounds = collider.bounds;
bounds.Expand(skinWidth * -2);
raycastOrigins.bottomLeft = new Vector2(bounds.min.x, bounds.min.y);
raycastOrigins.bottomRight = new Vector2(bounds.max.x, bounds.min.y);
raycastOrigins.topLeft = new Vector2(bounds.min.x, bounds.max.y);
raycastOrigins.topRight = new Vector2(bounds.max.x, bounds.max.y);
}
void CalculateRaySpacing()
{
Bounds bounds = collider.bounds;
bounds.Expand(skinWidth * -2);
horizontalRayCount = Mathf.Clamp(horizontalRayCount, 2, int.MaxValue);
verticalRayCount = Mathf.Clamp(verticalRayCount, 2, int.MaxValue);
horizontalRaySpacing = bounds.size.y / (horizontalRayCount - 1);
verticalRaySpacing = bounds.size.x / (verticalRayCount - 1);
}
struct RaycastOrigins
{
public Vector2 topLeft, topRight;
public Vector2 bottomLeft, bottomRight;
}
}
When I hover over "above" and "below" it give me the error
c# does not contain a definition for and no extension method,
can anyone see what I have done wrong?
internal object collisions;
Here you define collisions as object. Which means it does not have above nor below boolean properties.
Perhaps you need to define a new struct or class called collisions and define internal or public boolean properties above and below.
Related
The main character from the Unity 3D tutorials that I followed, I believe not from the site, are producing a wobbly left foot. I did not put a foot IK because the issue is not placement. It seems like an origin point thing, but not sure so I turned here for help.
I tried to have the full range of motion of the Mecanim character but was unable to produce foot bones on the rig that seem to work even though I just imported the model and code.
Third Person Character code :
using System;
using System.Collections;
using UnityEngine;
namespace UnityStandardAssets.Characters.ThirdPerson
[RequireComponent(typeof(Rigidbody))]
[RequireComponent(typeof(CapsuleCollider))]
[RequireComponent(typeof(Animator))]
public class ThirdPersonCharacter : MonoBehaviour
{
[SerializeField] float m_MovingTurnSpeed = 360;
[SerializeField] float m_StationaryTurnSpeed = 180;
[SerializeField] float m_JumpPower = 12f;
[Range(1f, 4f)][SerializeField] float m_GravityMultiplier = 2f;
[SerializeField] float m_RunCycleLegOffset = 0.2f;
[SerializeField] float m_MoveSpeedMultiplier = 1f;
[SerializeField] float m_AnimSpeedMultiplier = 1f;
[SerializeField] float m_GroundCheckDistance = 0.1f;
Rigidbody m_Rigidbody;
Animator m_Animator;
bool m_IsGrounded;
float m_OrigGroundCheckDistance;
const float k_Half = 0.5f;
float m_TurnAmount;
float m_ForwardAmount;
Vector3 m_GroundNormal;
float m_CapsuleHeight;
Vector3 m_CapsuleCenter;
CapsuleCollider m_Capsule;
bool m_Crouching;
void Start()
{
m_Animator = GetComponent<Animator>();
m_Rigidbody = GetComponent<Rigidbody>();
m_Capsule = GetComponent<CapsuleCollider>();
m_CapsuleHeight = m_Capsule.height;
m_CapsuleCenter = m_Capsule.center;
m_Rigidbody.constraints = RigidbodyConstraints.FreezeRotationX | RigidbodyConstraints.FreezeRotationY | RigidbodyConstraints.FreezeRotationZ;
m_OrigGroundCheckDistance = m_GroundCheckDistance;
}
public void Move(Vector3 move, bool crouch, bool jump)
{
if (move.magnitude > 1f) move.Normalize();
move = transform.InverseTransformDirection(move);
CheckGroundStatus();
move = Vector3.ProjectOnPlane(move, m_GroundNormal);
m_TurnAmount = Mathf.Atan2(move.x, move.z);
m_ForwardAmount = move.z;
ApplyExtraTurnRotation();
if (m_IsGrounded)
{
HandleGroundedMovement(crouch, jump);
}
else
{
HandleAirborneMovement();
}
ScaleCapsuleForCrouching(crouch);
PreventStandingInLowHeadroom();
UpdateAnimator(move);
}
void ScaleCapsuleForCrouching(bool crouch)
{
if (m_IsGrounded && crouch)
{
if (m_Crouching) return;
m_Capsule.height = m_Capsule.height / 2f;
m_Capsule.center = m_Capsule.center / 2f;
m_Crouching = true;
}
else
{
Ray crouchRay = new Ray(m_Rigidbody.position + Vector3.up * m_Capsule.radius * k_Half, Vector3.up);
float crouchRayLength = m_CapsuleHeight - m_Capsule.radius * k_Half;
if (Physics.SphereCast(crouchRay, m_Capsule.radius * k_Half, crouchRayLength, Physics.AllLayers, QueryTriggerInteraction.Ignore))
{
m_Crouching = true;
return;
}
m_Capsule.height = m_CapsuleHeight;
m_Capsule.center = m_CapsuleCenter;
m_Crouching = false;
}
}
void PreventStandingInLowHeadroom()
{
if (!m_Crouching)
{
Ray crouchRay = new Ray(m_Rigidbody.position + Vector3.up * m_Capsule.radius * k_Half, Vector3.up);
float crouchRayLength = m_CapsuleHeight - m_Capsule.radius * k_Half;
if (Physics.SphereCast(crouchRay, m_Capsule.radius * k_Half, crouchRayLength, Physics.AllLayers, QueryTriggerInteraction.Ignore))
{
m_Crouching = true;
}
}
}
void UpdateAnimator(Vector3 move)
{
m_Animator.SetFloat("Forward", m_ForwardAmount, 0.1f, Time.deltaTime);
m_Animator.SetFloat("Turn", m_TurnAmount, 0.1f, Time.deltaTime);
m_Animator.SetBool("Crouch", m_Crouching);
m_Animator.SetBool("OnGround", m_IsGrounded);
if (!m_IsGrounded)
{
m_Animator.SetFloat("Jump", m_Rigidbody.velocity.y);
}
float runCycle =
Mathf.Repeat(
m_Animator.GetCurrentAnimatorStateInfo(0).normalizedTime + m_RunCycleLegOffset, 1);
float jumpLeg = (runCycle < k_Half ? 1 : -1) * m_ForwardAmount;
if (m_IsGrounded)
{
m_Animator.SetFloat("JumpLeg", jumpLeg);
}
if (m_IsGrounded && move.magnitude > 0)
{
m_Animator.speed = m_AnimSpeedMultiplier;
}
else
{
m_Animator.speed = 1;
}
}
void HandleAirborneMovement()
{
Vector3 extraGravityForce = (Physics.gravity * m_GravityMultiplier) - Physics.gravity;
m_Rigidbody.AddForce(extraGravityForce);
m_GroundCheckDistance = m_Rigidbody.velocity.y < 0 ? m_OrigGroundCheckDistance : 0.01f;
}
void HandleGroundedMovement(bool crouch, bool jump)
{
if (jump && !crouch && m_Animator.GetCurrentAnimatorStateInfo(0).IsName("Grounded"))
{
m_Rigidbody.velocity = new Vector3(m_Rigidbody.velocity.x, m_JumpPower, m_Rigidbody.velocity.z);
m_IsGrounded = false;
m_Animator.applyRootMotion = false;
m_GroundCheckDistance = 0.1f;
}
}
void ApplyExtraTurnRotation()
{
float turnSpeed = Mathf.Lerp(m_StationaryTurnSpeed, m_MovingTurnSpeed, m_ForwardAmount);
transform.Rotate(0, m_TurnAmount * turnSpeed * Time.deltaTime, 0);
}
public void OnAnimatorMove()
{
if (m_IsGrounded && Time.deltaTime > 0)
{
Vector3 v = (m_Animator.deltaPosition * m_MoveSpeedMultiplier) / Time.deltaTime;
v.y = m_Rigidbody.velocity.y;
m_Rigidbody.velocity = v;
}
}
void CheckGroundStatus()
{
RaycastHit hitInfo;
Debug.DrawLine(transform.position + (Vector3.up * 0.1f), transform.position + (Vector3.up * 0.1f) + (Vector3.down * m_GroundCheckDistance));
if (Physics.Raycast(transform.position + (Vector3.up * 0.1f), Vector3.down, out hitInfo, m_GroundCheckDistance))
{
m_GroundNormal = hitInfo.normal;
m_IsGrounded = true;
m_Animator.applyRootMotion = true;
}
else
{
m_IsGrounded = false;
m_GroundNormal = Vector3.up;
m_Animator.applyRootMotion = false;
}
}
}
I have GameObject with Scroll Rect and Rect Mask in my canvas and there is an image in it. I want to zoom in and zoom out of that image. However I don't want to scale Main Camera because there will be other objects in the screen that I don't want to zoom. I searched it but all the tutorials are doing that by scaling Main Camera.
This video is exactly what I want but it doesn't work in android. https://www.youtube.com/watch?v=BFX3FpUnoio&ab_channel=JasonWeimann
This is the script in that video which is added to "image". I tried to modify it but I messed it up. How can I make it work in mobile?
using UnityEngine;
using UnityEngine.EventSystems;
public class UIZoomImage : MonoBehaviour, IScrollHandler
{
private Vector3 initialScale;
[SerializeField]
private float zoomSpeed = 0.1f;
[SerializeField]
private float maxZoom = 10f;
private void Awake()
{
initialScale = transform.localScale;
}
public void OnScroll(PointerEventData eventData)
{
var delta = Vector3.one * (eventData.scrollDelta.y * zoomSpeed);
var desiredScale = transform.localScale + delta;
desiredScale = ClampDesiredScale(desiredScale);
transform.localScale = desiredScale;
}
private Vector3 ClampDesiredScale(Vector3 desiredScale)
{
desiredScale = Vector3.Max(initialScale, desiredScale);
desiredScale = Vector3.Min(initialScale * maxZoom, desiredScale);
return desiredScale;
}
}
-------UPDATE---------
I found this in Unity forum: https://answers.unity.com/questions/1280592/pinch-and-zoom-functionality-on-canvas-ui-images.html
It almost works but I need to pinch the screen 2-3 to zoom in or zoom out. On first touch nothing happens. It's so annoying. I tried to change _minZoom, _maxZoom, speed and sensitivity values but didn't work.
This is the script there:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class PinchableScrollRect : ScrollRect
{
[SerializeField] float _minZoom = .1f;
[SerializeField] float _maxZoom = 10;
[SerializeField] float _zoomLerpSpeed = 10f;
float _currentZoom = 1;
bool _isPinching = false;
float _startPinchDist;
float _startPinchZoom;
Vector2 _startPinchCenterPosition;
Vector2 _startPinchScreenPosition;
float _mouseWheelSensitivity = 1;
bool blockPan = false;
protected override void Awake()
{
Input.multiTouchEnabled = true;
}
private void Update()
{
if (Input.touchCount == 2)
{
if (!_isPinching)
{
_isPinching = true;
OnPinchStart();
}
OnPinch();
}
else
{
_isPinching = false;
if (Input.touchCount == 0)
{
blockPan = false;
}
}
//pc input
float scrollWheelInput = Input.GetAxis("Mouse ScrollWheel");
if (Mathf.Abs(scrollWheelInput) > float.Epsilon)
{
_currentZoom *= 1 + scrollWheelInput * _mouseWheelSensitivity;
_currentZoom = Mathf.Clamp(_currentZoom, _minZoom, _maxZoom);
_startPinchScreenPosition = (Vector2)Input.mousePosition;
RectTransformUtility.ScreenPointToLocalPointInRectangle(content, _startPinchScreenPosition, null, out _startPinchCenterPosition);
Vector2 pivotPosition = new Vector3(content.pivot.x * content.rect.size.x, content.pivot.y * content.rect.size.y);
Vector2 posFromBottomLeft = pivotPosition + _startPinchCenterPosition;
SetPivot(content, new Vector2(posFromBottomLeft.x / content.rect.width, posFromBottomLeft.y / content.rect.height));
}
//pc input end
if (Mathf.Abs(content.localScale.x - _currentZoom) > 0.001f)
content.localScale = Vector3.Lerp(content.localScale, Vector3.one * _currentZoom, _zoomLerpSpeed * Time.deltaTime);
}
protected override void SetContentAnchoredPosition(Vector2 position)
{
if (_isPinching || blockPan) return;
base.SetContentAnchoredPosition(position);
}
void OnPinchStart()
{
Vector2 pos1 = Input.touches[0].position;
Vector2 pos2 = Input.touches[1].position;
_startPinchDist = Distance(pos1, pos2) * content.localScale.x;
_startPinchZoom = _currentZoom;
_startPinchScreenPosition = (pos1 + pos2) / 2;
RectTransformUtility.ScreenPointToLocalPointInRectangle(content, _startPinchScreenPosition, null, out _startPinchCenterPosition);
Vector2 pivotPosition = new Vector3(content.pivot.x * content.rect.size.x, content.pivot.y * content.rect.size.y);
Vector2 posFromBottomLeft = pivotPosition + _startPinchCenterPosition;
SetPivot(content, new Vector2(posFromBottomLeft.x / content.rect.width, posFromBottomLeft.y / content.rect.height));
blockPan = true;
}
void OnPinch()
{
float currentPinchDist = Distance(Input.touches[0].position, Input.touches[1].position) * content.localScale.x;
_currentZoom = (currentPinchDist / _startPinchDist) * _startPinchZoom;
_currentZoom = Mathf.Clamp(_currentZoom, _minZoom, _maxZoom);
}
float Distance(Vector2 pos1, Vector2 pos2)
{
RectTransformUtility.ScreenPointToLocalPointInRectangle(content, pos1, null, out pos1);
RectTransformUtility.ScreenPointToLocalPointInRectangle(content, pos2, null, out pos2);
return Vector2.Distance(pos1, pos2);
}
static void SetPivot(RectTransform rectTransform, Vector2 pivot)
{
if (rectTransform == null) return;
Vector2 size = rectTransform.rect.size;
Vector2 deltaPivot = rectTransform.pivot - pivot;
Vector3 deltaPosition = new Vector3(deltaPivot.x * size.x, deltaPivot.y * size.y) * rectTransform.localScale.x;
rectTransform.pivot = pivot;
rectTransform.localPosition -= deltaPosition;
}
}
This script does the trick if the camera projection is set to ortho. From this
source.
using UnityEngine;
public class Zoom : MonoBehaviour {
public float zoomSpeed = 1;
public float targetOrtho;
public float smoothSpeed = 2.0f;
public float minOrtho = 1.0f;
public float maxOrtho = 20.0f;
void Start() {
targetOrtho = Camera.main.orthographicSize;
}
void Update () {
float scroll = Input.GetAxis ("Mouse ScrollWheel");
if (scroll != 0.0f) {
targetOrtho -= scroll * zoomSpeed;
targetOrtho = Mathf.Clamp (targetOrtho, minOrtho, maxOrtho);
}
Camera.main.orthographicSize = Mathf.MoveTowards (Camera.main.orthographicSize, targetOrtho, smoothSpeed * Time.deltaTime);
}
}
Why don't you scale the Image?!
private void MoveToNewFormation()
{
squadMembers = GameObject.FindGameObjectsWithTag("Squad Member");
float step = speed * Time.deltaTime;
for (int i = 0; i < squadMembers.Length; i++)
{
squadMembers[i].transform.LookAt(newpos[i]);
squadMembers[i].transform.position = Vector3.MoveTowards(squadMembers[i].transform.position, newpos[i], step);
//squadMembers[i].transform.rotation = qua[i];
}
}
And calling it in the Update:
void Update()
{
if (Input.GetKeyDown(KeyCode.F))
{
ChangeFormation();
}
if (move == true)
MoveToNewFormation();
}
Once when one of the squadMembers reached to the newpos then i want to make
squadMembers[i].transform.rotation = qua[i];
qua is a List and i want to rotate the squad member once he reached the newpos.
Inside MoveToNewFormation i thought to add after the loop the line:
if (squadMembers[i].transform.position == newpos[i])
{
squadMembers[i].transform.rotation = qua[i];
}
But it's after the loop so 'i' not exist.
This is the complete script:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class SquadFormation : MonoBehaviour
{
enum Formation
{
Square, Circle, Triangle
}
public Transform squadMemeber;
public int columns = 4;
public int squareSpace = 10;
public int circleSpace = 40;
public int numberOfObjects = 20;
public float yOffset = 0;
public float speed = 3;
private Formation formation;
private GameObject[] squadMembers;
private List<Quaternion> qua = new List<Quaternion>();
private List<Vector3> newpos = new List<Vector3>();
private bool move = false;
// Use this for initialization
void Start()
{
formation = Formation.Square;
ChangeFormation();
}
// Update is called once per frame
void Update()
{
if (Input.GetKeyDown(KeyCode.F))
{
ChangeFormation();
}
if (move == true)
MoveToNewFormation();
}
private void ChangeFormation()
{
switch (formation)
{
case Formation.Square:
FormationSquare();
break;
case Formation.Circle:
FormationCircle();
break;
}
}
private Vector3 FormationSquarePositionCalculation(int index) // call this func for all your objects
{
float posX = (index % columns) * squareSpace;
float posY = (index / columns) * squareSpace;
return new Vector3(posX, posY);
}
private void FormationSquare()
{
for (int i = 0; i < numberOfObjects; i++)
{
Transform go = Instantiate(squadMemeber);
Vector3 pos = FormationSquarePositionCalculation(i);
go.position = new Vector3(transform.position.x + pos.x, 0, transform.position.y + pos.y);
go.Rotate(new Vector3(0, -90, 0));
go.tag = "Squad Member";
}
formation = Formation.Circle;
}
private Vector3 FormationCirclePositionCalculation(Vector3 center, float radius, int index, float angleIncrement)
{
float ang = index * angleIncrement;
Vector3 pos;
pos.x = center.x + radius * Mathf.Sin(ang * Mathf.Deg2Rad);
pos.z = center.z + radius * Mathf.Cos(ang * Mathf.Deg2Rad);
pos.y = center.y;
return pos;
}
private void FormationCircle()
{
Vector3 center = transform.position;
float radius = (float)circleSpace / 2;
float angleIncrement = 360 / (float)numberOfObjects;
for (int i = 0; i < numberOfObjects; i++)
{
Vector3 pos = FormationCirclePositionCalculation(center, radius, i, angleIncrement);
var rot = Quaternion.LookRotation(center - pos);
pos.y = Terrain.activeTerrain.SampleHeight(pos);
pos.y = pos.y + yOffset;
newpos.Add(pos);
qua.Add(rot);
}
move = true;
formation = Formation.Square;
}
private void MoveToNewFormation()
{
squadMembers = GameObject.FindGameObjectsWithTag("Squad Member");
float step = speed * Time.deltaTime;
for (int i = 0; i < squadMembers.Length; i++)
{
squadMembers[i].transform.LookAt(newpos[i]);
squadMembers[i].transform.position = Vector3.MoveTowards(squadMembers[i].transform.position, newpos[i], step);
//squadMembers[i].transform.rotation = qua[i];
}
//if (squadMembers[i].transform.position == newpos[i])
}
}
You can use a threshold and check the distance using that threshold.
Define threshold like this at start of script.
public float threshold = 0.1f;
Then change the MoveToNewFormation() function like this:
private void MoveToNewFormation()
{
squadMembers = GameObject.FindGameObjectsWithTag("Squad Member");
float step = speed * Time.deltaTime;
for (int i = 0; i < squadMembers.Length; i++)
{
squadMembers[i].transform.LookAt(newpos[i]);
squadMembers[i].transform.position =
Vector3.MoveTowards(squadMembers[i].transform.position, newpos[i], step);
if(Vector3.Distance(squadMembers[i].transform.position,newpos[i])<threshold){
squadMembers[i].transform.rotation = qua[i];
}
}
//if (squadMembers[i].transform.position == newpos[i])
}
I can use W S A D or arrow keys to turn the ship. But when i press on Z the ship fast moving up. When i press on X it will stop the ship on place.
I can't figure out how to make the ship move forward.
But nothing make the ship move forward.
I used a break point and i see in Start in the SpacecraftControl script on the line:
Debug.Log("Transform forward is : " + transform.forward);
Whem i put the mouse cursor on the forward of transform i see: 0.0,1.0,0.0
And inside the forward i see: x = 0 y = 0 and z = -1.192093E-07
Here is a small short video clip i recorded now showing what happen when running the game and then pressing on Z.
Please watch all the video the the Z pressing is start from second 14.
Video Clip
In my ship inspector i have: Transform, Local Rotation, Mesh Filter, Mesh Renderer, Animator, RigidBody > Gravity unchecked, Mesh Collider > Convex is checked and the scripts: Spacecraft Control and UserInput.
Then in the menu i went to: Edit > Project Settings > Input
In Input i addeed a new place one size to 19. And called the new Axes: Throttle
And the scripts first the SpacecraftControl:
using UnityEngine;
using System.Collections;
[RequireComponent(typeof(Rigidbody))]
public class SpacecraftControl : MonoBehaviour
{
public float MaxEnginePower = 40f;
public float RollEffect = 50f;
public float PitchEffect = 50f;
public float YawEffect = 0.2f;
public float BankedTurnEffect = 0.5f;
public float AutoTurnPitch = 0.5f;
public float AutoRollLevel = 0.1f;
public float AutoPitchLevel = 0.1f;
public float AirBreaksEffect = 3f;
public float ThrottleChangeSpeed = 0.3f;
public float DragIncreaseFactor = 0.001f;
private float Throttle;
private bool AirBrakes;
private float ForwardSpeed;
private float EnginePower;
private float cur_MaxEnginePower;
private float RollAngle;
private float PitchAngle;
private float RollInput;
private float PitchInput;
private float YawInput;
private float ThrottleInput;
private float OriginalDrag;
private float OriginalAngularDrag;
private float AeroFactor = 1;
private bool Immobolized = false;
private float BankedTurnAmount;
private Rigidbody _rigidbody;
Collider[] cols;
void Start()
{
_rigidbody = GetComponent<Rigidbody> ();
OriginalDrag = _rigidbody.drag;
OriginalAngularDrag = _rigidbody.angularDrag;
for (int i = 0; i < transform.childCount; i++)
{
foreach (var componentsInChild in transform.GetChild(i).GetComponentsInChildren<WheelCollider>())
{
componentsInChild.motorTorque = 0.18f;
}
}
Debug.Log("Transform forward is : " + transform.forward);
}
public void Move(float rollInput, float pitchInput, float yawInput, float throttleInput, bool airBrakes)
{
this.RollInput = rollInput;
this.PitchInput = pitchInput;
this.YawInput = yawInput;
this.ThrottleInput = throttleInput;
this.AirBrakes = airBrakes;
ClampInput ();
CalculateRollandPitchAngles ();
AutoLevel ();
CalculateForwardSpeed ();
ControlThrottle ();
CalculateDrag ();
CalculateLinearForces ();
CalculateTorque ();
if (Throttle < 0.1f)
{
Vector3 currentVelocity = _rigidbody.velocity;
Vector3 newVelocity = currentVelocity * Time.deltaTime;
_rigidbody.velocity = currentVelocity - newVelocity;
}
}
void ClampInput()
{
RollInput = Mathf.Clamp (RollInput, -1, 1);
PitchInput = Mathf.Clamp (PitchInput, -1, 1);
YawInput = Mathf.Clamp (YawInput, -1, 1);
ThrottleInput = Mathf.Clamp (ThrottleInput, -1, 1);
}
void CalculateRollandPitchAngles()
{
Vector3 flatForward = transform.forward;
flatForward.y = 0;
if (flatForward.sqrMagnitude > 0)
{
flatForward.Normalize ();
Vector3 localFlatForward = transform.InverseTransformDirection (flatForward);
PitchAngle = Mathf.Atan2 (localFlatForward.y, localFlatForward.z);
Vector3 flatRight = Vector3.Cross (Vector3.up, flatForward);
Vector3 localFlatRight = transform.InverseTransformDirection (flatRight);
RollAngle = Mathf.Atan2 (localFlatRight.y, localFlatRight.x);
}
}
void AutoLevel()
{
BankedTurnAmount = Mathf.Sin (RollAngle);
if (RollInput == 0)
{
RollInput = -RollAngle * AutoRollLevel;
}
if (PitchInput == 0f)
{
PitchInput = -PitchAngle * AutoPitchLevel;
PitchInput -= Mathf.Abs (BankedTurnAmount * BankedTurnAmount * AutoTurnPitch);
}
}
void CalculateForwardSpeed()
{
Vector3 localVelocity = transform.InverseTransformDirection (_rigidbody.velocity);
ForwardSpeed = Mathf.Max (0, localVelocity.z);
}
void ControlThrottle()
{
if (Immobolized)
{
ThrottleInput = -0.5f;
}
Throttle = Mathf.Clamp01 (Throttle + ThrottleInput * Time.deltaTime * ThrottleChangeSpeed);
EnginePower = Throttle * MaxEnginePower;
}
void CalculateDrag()
{
float extraDrag = _rigidbody.velocity.magnitude * DragIncreaseFactor;
//_rigidbody.drag = (AirBrakes ? (OriginalDrag + ) * AirBreaksEffect : OriginalDrag * extraDrag);
_rigidbody.drag = AirBrakes ? (OriginalDrag * AirBreaksEffect) : OriginalDrag;
_rigidbody.drag *= extraDrag;
_rigidbody.angularDrag = OriginalAngularDrag * ForwardSpeed / 1000 + OriginalAngularDrag;
}
void CalculateLinearForces()
{
Vector3 forces = Vector3.zero;
forces += EnginePower * transform.forward;
_rigidbody.AddForce (forces);
}
void CalculateTorque()
{
Vector3 torque = Vector3.zero;
torque += PitchInput * PitchEffect * transform.right;
torque += YawInput * YawEffect * transform.up;
torque += -RollInput * RollEffect * transform.forward;
torque += BankedTurnAmount * BankedTurnEffect * transform.up;
_rigidbody.AddTorque (torque * AeroFactor);
}
public void Immobilize()
{
Immobolized = true;
}
public void Reset()
{
Immobolized = false;
}
}
And the UserInput script:
using UnityEngine;
using System.Collections;
public class UserInput : MonoBehaviour {
SpacecraftControl _spacecraftcontrol;
// Use this for initialization
void Start ()
{
_spacecraftcontrol = GetComponent<SpacecraftControl> ();
}
void FixedUpdate()
{
float roll = Input.GetAxis ("Horizontal");
float pitch = Input.GetAxis ("Vertical");
bool airBrakes = Input.GetButton ("Fire1");
float throttle = Input.GetAxis ("Throttle");
_spacecraftcontrol.Move (roll, pitch, 0, throttle, airBrakes);
}
}
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.