The move includes simple movements and also a Jump movement. but How do I do it. Gravity is enabled.
Because I’ve been trying to figure this out for a while and Unity answers don’t contain much of this kind of knowledge I’m giving you this what I wroted and gathered in a month, …
It’s still a robust code but my updates are not in it yet
all you need is:
GameObject with: Character controller (prefered sphere height), Movement script
child GameObject with: Graphics, MouseLookX script
child GameObject with: Camera, MouseLookY script
Scripts:
Mouse Look X
using UnityEngine;
using System.Collections;
public class MouseLookX : MonoBehaviour {
public float MouseSensitivityX = 1;
void Update (){
transform.localEulerAngles += new Vector3( 0, Input.GetAxis("Mouse X") * MouseSensitivityX, 0);
}
}
Mouse Look Y
using UnityEngine;
using System.Collections;
public class MouseLookY : MonoBehaviour {
public float MouseSensitivityY = 1;
void Update(){
transform.localEulerAngles += new Vector3 (Input.GetAxis("Mouse Y") * MouseSensitivityY, 0, 0);
}
}
Some added Math functions:
using UnityEngine;
using System.Collections;
public struct MathFunctions {
// always positive
public float Positive (float FloatToChange){
if (FloatToChange < 0){
return (FloatToChange * (-1) );
}
return FloatToChange;
}
// always negative
public float Negative (float FloatToChange){
return Positive(FloatToChange) * -1;
}
// V3 Distance
public float V3Distance (Vector3 From, Vector3 To){
float TempX;
float TempY;
float TempZ;
TempX = From.x - To.x; TempX *= TempX;
TempY = From.y - To.y; TempY *= TempY;
TempZ = From.z - To.z; TempZ *= TempZ;
return Mathf.Sqrt(TempX + TempY + TempZ);
}
// V3 Point
public Vector3 DirectionDistancePoint (Vector3 From, Vector3 To, float Length){
return (From + (To.normalized * Length) );
}
// Distance / sec
public float Vector3SpeedPerSec (Vector3 From, Vector3 To, float InTime){
return Positive( (V3Distance(From, To) ) / InTime );
}
// Direction
public Vector3 Direction (Vector3 From, Vector3 To){
return (To - From).normalized;
}
// V2 Angle
public float V2Angle (Vector2 From, Vector2 To){
// float DotProduct = From.x * To.x + From.y * To.y;
// float MagnA = From.x * From.x + From.y * From.y;
// float MagnB = To.x * To.x + To.y * To.y;
// MagnA = Mathf.Sqrt(MagnA);
// MagnB = Mathf.Sqrt(MagnB);
Vector3 Cross = Vector3.Cross(From, To);
float ang = Vector2.Angle(From, To);//Mathf.Acos( (DotProduct / (MagnA*MagnB) ) ) * Mathf.Rad2Deg;
if (Cross.z > 0){
ang = 360 - ang;
}
return ang;
}
}
Movement Script
using UnityEngine;
using System.Collections;
public class Movement : MonoBehaviour {
// mathematic functions
MathFunctions MF;
// orientation transforms
public Transform Planet; // to rotate to
public Transform LocalOrientation; // graphics
CharacterController Controller;
Vector3 LookAtPlanet = Vector3.zero; // direction
// Movement
public bool AccelerationMovement = true;
Vector3 TempInputVelocity = Vector3.zero;
Vector3 MovementVelocity = Vector3.zero;
float MovingTime = 0; // dinamic one in between start and stop movement
// Start Moving
public bool StillInMovement = false;
// for bullet
public bool MaxMovementVelocity = false;
float MovingStartTime = 0;
public float AccelerationTime = 1; // how much time till full speed
// Stop Moving
public bool StoppingMovement = false;
float MovingStartStopTime = 0;
// Jump
public bool StillJumping = false;
Vector3 JumpVelocity = Vector3.zero;
float JumpStartDistance = 0; // distance from planet
float PlanetDistance = 0; // our current distance to planet /*we only need it on jump function*/
public float JumpStrength = 10; // how strong we jump
public float JumpHeight = 20; // what's the max distance we can jump
// Gravity
public bool Grounded = false;
public bool LandedOnSlope = false;
Vector3 GravityVelocity = Vector3.zero;
public Vector3 LastGroundTestPosition = Vector3.zero;
public Vector3 LastSlopeTestPosition = Vector3.zero;
float LastHitTime = 0; // CharacterController hit time
public float GravityStrength = 10;
// Move Char
public float MovementSpeed = 9; // m/s || points/s
// Complicated AI
public bool AI = false;
public bool AIForward = false;
public bool AIBackward = false;
public bool AIRight = false;
public bool AILeft = false;
public bool AIJump = false;
// bullet
public bool Bullet = false;
public bool BulletFire = false; // How many frames will it fire it // - WHAT???
public float BulletSpeed = 50; // m/s
// I need to learn how to implement it
public AnimationCurve slopeSpeedMultiplier = new AnimationCurve (new Keyframe(-90, 1), new Keyframe(0, 1), new Keyframe(90, 0));
// actually I already have it since I'm walking through wall and going more through wall is slower than linear walking
void Start(){
Controller = GetComponent("CharacterController") as CharacterController;
// so we don't end up teleporting at x0y0z0 if something unexpected happenes
LastSlopeTestPosition = transform.position;
}
// why fixed update? had something in my mind that I need it forgot it why, ... seems to be working well with normal update too less calculations to be made with it
// if I'm wrong something might not be sinhronized, ... don't know, ...
void Update() {
// Align to planet without south pole maddness :)
Ray ray = new Ray(transform.position, -transform.up);
RaycastHit hit;
if (Planet.collider.Raycast(ray, out hit,
MF.V3Distance(transform.position, Planet.transform.position) ) ){
transform.rotation = Quaternion.LookRotation( Vector3.Cross(transform.right, hit.normal) , hit.normal);
// south pole maddness = transform.rotation = Quaternion.FromToRotation (Vector3.up, -(Planet.position - transform.position) );
}
LookAtPlanet = -transform.up;
if (Grounded){
// 1/2 Grounded false if not colliding
IsStillGrounded();
}
//DEBUG!!!
//Grounded = true; // debug so if we are in air we can still move
// we check if we are still grounded. // bullet needs a starter fire in mid air
if (Grounded || BulletFire || LandedOnSlope){
InputMoveMotion();
// inside 2/2 Grounded false if press a key
if (! Bullet && ! BulletFire && ! LandedOnSlope){
InputJumpMotion();
}
}
// if we jump we are still not using gravity
if (! StillJumping){
GravityMotion();
}
if (StillJumping){
ContinueJumpMotion();
}
//DEBUG!!!
//IsStillGrounded(); // debug so gravity all the time works
MoveChar();
}
void IsStillGrounded (){
// we are not moving OR we are in air
if (LastHitTime < (Time.time - Time.deltaTime * 2) ){
// we are moving in mid air
if (LastGroundTestPosition != transform.position){
// grounded was 100% true
Grounded = false;
// we start accelerationg from 0
GravityVelocity = Vector3.zero;
}
//else {we aren't in motion}
}
LastGroundTestPosition = transform.position;
}
public void InputMoveMotion(){
Vector3 ImputVelocity = Vector3.zero;
if (AI || BulletFire){
if (AIForward){
ImputVelocity += ( LocalOrientation.transform.forward);
}
if (AIBackward){
ImputVelocity += ( -LocalOrientation.transform.forward);
}
if (AILeft){
ImputVelocity += ( -LocalOrientation.transform.right);
}
if (AIRight){
ImputVelocity += ( LocalOrientation.transform.right);
}
// we want to make only 1 time movement propably
if (MaxMovementVelocity){
BulletFire = false;
}
}
else if (! AI && ! Bullet) {
if (Input.GetKey(KeyCode.UpArrow)){
ImputVelocity += ( LocalOrientation.transform.forward);
}
if (Input.GetKey(KeyCode.DownArrow)){
ImputVelocity += ( -LocalOrientation.transform.forward);
}
if (Input.GetKey(KeyCode.LeftArrow)){
ImputVelocity += ( -LocalOrientation.transform.right);
}
if (Input.GetKey(KeyCode.RightArrow)){
ImputVelocity += ( LocalOrientation.transform.right);
}
}
// direction length to 1 unit
ContinueMoveMotion(ImputVelocity.normalized);
}
void ContinueMoveMotion(Vector3 InputVelocity){
if (! AccelerationMovement){
MovementVelocity = InputVelocity;
return ;
}
// seems to be working more tests need to be done, ...
/****** "START" START MOVING ******/
if (InputVelocity != Vector3.zero){
TempInputVelocity = InputVelocity;
// we didn't ended the stop
if (StoppingMovement){
StoppingMovement = false;
MovingStartTime = Time.time - MovingTime;
}
// we are just starting to move
else if (LastGroundTestPosition == transform.position && ! StillInMovement){
MovingStartTime = Time.time;
}
StillInMovement = true;
// we've reached the top speed
if (AccelerationTime > (Time.time - MovingStartTime)){
MovingTime = (Time.time - MovingStartTime);
MaxMovementVelocity = true; // needed for bullet
}
else {
MovingTime = AccelerationTime;
}
// where we will move, / AccelerationTime so moving time is a % of full throtle
MovementVelocity = InputVelocity * MovingTime / AccelerationTime;
}
/****** "END" START MOVING ******/
/****** "START" STOP MOVING ******/
else {
if (StillInMovement && ! StoppingMovement){
StoppingMovement = true;
MaxMovementVelocity = false; // don't need it ATM but I'll do it anyway since I need only the max for bullet
MovingStartStopTime = Time.time + MovingTime;
}
// I don't need this but so it doesn't calculate all the time but just veryfy the bool
if (StoppingMovement){
MovingTime = MovingStartStopTime - Time.time;
}
// if we are inside stopping time
if (MovingTime >= 0){
// AccelerationTime so moving time is a % of full throtle
MovementVelocity = TempInputVelocity * MovingTime / AccelerationTime;
}
// if we stopped totally
else {
MovementVelocity = Vector3.zero;
StillInMovement = false;
StoppingMovement = false;
}
}
/******"END" STOP MOVING******/
}
void InputJumpMotion(){
// 2/2 if we jump we know we aren't grounded
if ( (Input.GetMouseButton(2) && ! AI) || (AI && AIJump)){
JumpVelocity = transform.up * JumpStrength;
// grounded was 100% true
Grounded = false;
// we must start accelerationg from 0
GravityVelocity = Vector3.zero;
StillJumping = true;
JumpStartDistance = MF.V3Distance(transform.position, Planet.position);
}
}
void ContinueJumpMotion(){
PlanetDistance = MF.V3Distance(transform.position, Planet.position);
// if we stop pressing jump we stop getting in air
if (Input.GetMouseButtonUp(2)){
StillJumping = false;
JumpVelocity = Vector3.zero;
}
// if we reached our jump height we stop getting more in height
else if (JumpStartDistance + JumpHeight < PlanetDistance){
StillJumping = false;
JumpVelocity = Vector3.zero;
}
else if (StillJumping){
JumpVelocity -= (-transform.up * 0.3f * Time.deltaTime);
}
}
void GravityMotion (){
ContinueGravityMotion(MF.Direction(transform.position, Planet.position).normalized);
// GravityVelocity = MF.Direction(transform.position, Planet.position).normalized * GravityStrength;
}
void ContinueGravityMotion(Vector3 GravityDirection){
GravityVelocity += GravityDirection * GravityStrength * Time.deltaTime;
}
void MoveChar(){
if (StillJumping){
GravityVelocity = Vector3.zero;
}
if (Grounded){
Controller.Move( (MovementVelocity * MovementSpeed) * Time.deltaTime);
}
else {
Controller.Move( ( (MovementVelocity * MovementSpeed) + JumpVelocity + GravityVelocity) * Time.deltaTime);
}
}
private Vector3 LandedOn = Vector3.zero;
void OnControllerColliderHit (ControllerColliderHit hit){
// bullet stops
if (Bullet){
AIForward = false;
AIBackward = false;
AIRight = false;
AILeft = false;
}
// the only indicator we are grounded
// if it's less than 45° we are grounded
float CurrentSlope = (Vector3.Angle(LookAtPlanet, hit.normal) -180 )*-1;
if (Controller.slopeLimit > CurrentSlope){
Grounded = true;
LastHitTime = Time.time;
LastSlopeTestPosition = transform.position;
// we sucessfully went down from slope now we reset it so we don't teleport back to the end of slope
if (LandedOnSlope){
LandedOnSlope = false;
LandedOn = Vector3.zero;
}
}
// if we are still grounded and are on 45° + slope we must teleport back
else if (Grounded && Controller.slopeLimit < CurrentSlope){
// we need to teleport back to slope below 45°
transform.position = LastSlopeTestPosition;
}
// if we aren't grounded means we landed on 45° + slope
else if (! Grounded){
LandedOnSlope = true;
// we mark where we landed
if (LandedOn == Vector3.zero){
LandedOn = transform.position;
}
// if we are trying to climb we teleport back
else if ( MF.V3Distance(LandedOn, Planet.position) <
MF.V3Distance(transform.position, Planet.position) ) {
transform.position = LandedOn;
}
// we aren't climbing but are going down
else {
LandedOn = transform.position;
}
}
/****** START DEBUG Hit COMPONENTS ******
// world point
// Debug.Log("Point: " + hit.point);
// oposite of direction
// Debug.Log("Normal: " + hit.normal); // World Direction
// direction witch was forced back
// Debug.Log("MoveDirection: " + hit.moveDirection); // Local Direction & something strange unexplained about it
// more length that's stopped bigger number it'll return
// Debug.Log("moveLength: " + hit.moveLength);
// Platform = hit.transform;
/****** END DEBUG Hit COMPONENTS ******/
}
}
I’m posting this because there’s not even 1 complete answer on unity sites but just fractions of this code
like how to go around planet and 1 line, …
I had to find all this fractions and combine everything in to 1 big script ALSO I helped my self with already done 1 java scripted (I hate java) and modified it in to 3D instead of 2D (standart asset character controllers)
I’ve wanted to go doing it several ways until I found correct way witch works
EDIT: AS promised I updated the code since you accepted my answer, BTW I still haven’t finished my code so it’s compleating each day more and more, …
and thanks for a question like write me a script, … DOH, …
BTW I reject that kind of questions like yours