I just started coding 3 days ago and in my game I only want 4 movement-directions instead of 8.
I have a fully working code with animations and walking logic, but I am to nooby make a Code by my own, because I just started.
So could someone modify my code, so that I can only go in 4-directions.
Thank you :)
using UnityEngine;
public class PlayerMovement : MonoBehaviour
{
private Animator anim;
private float x, y;
private bool isWalking;
public float moveSpeed;
void Start()
{
anim = GetComponent<Animator>();
}
void Update()
{
x = Input.GetAxis("Horizontal");
y = Input.GetAxis("Vertical");
if (x != 0 || y != 0)
{
if (!isWalking)
{
isWalking = true;
anim.SetBool("isWalking", isWalking);
}
Move();
}
else
{
if (isWalking)
{
isWalking = false;
anim.SetBool("isWalking", isWalking);
}
}
}
private void Move()
{
anim.SetFloat("X", x);
anim.SetFloat("Y", y);
transform.Translate(x * Time.deltaTime * moveSpeed,
y * Time.deltaTime * moveSpeed,
0);
}
}
I wrote 2 different (but fairly similar) options for moving in just 4 directions.
First option, just pick which axis has the highest value and move that direction (if using a controller, this may or may not be work the way you want).
Second and simpler option, keep moving the player on its current axis regardless if another axis has a higher value.
Both code options are there and you can play around with either option. Hopefully this helps start you on which path you want to take.
public class PlayerMovement : MonoBehaviour {
private Animator anim;
private float x, y;
private bool isWalking;
private bool movingX = false;
public float moveSpeed;
void Start() {
anim = GetComponent<Animator>();
}
void Update() {
x = Input.GetAxis("Horizontal");
y = Input.GetAxis("Vertical");
if (x != 0 || y != 0) {
if (!isWalking) {
isWalking = true;
anim.SetBool("isWalking", isWalking);
}
Move();
} else {
if (isWalking) {
isWalking = false;
anim.SetBool("isWalking", isWalking);
}
}
}
private void Move() {
// whichever direction has the highest value, will be the direction we go.
///*
if (Mathf.Abs(x) > Mathf.Abs(y)) {
movingX = true;
y = 0;
} else if (Mathf.Abs(x) < Mathf.Abs(y)) {
movingX = false;
x = 0;
} else {
// keeps going same direction if both maxed.
if (movingX) {
y = 0;
} else {
x = 0;
}
}
//*/
// or simple, just keep going in same direction until player stops using axis.
/*
if (x != 0 && y == 0) {
movingX = true;
} else if (x == 0 && y != 0) {
movingX = false;
}
if (movingX) {
y = 0;
} else {
x = 0;
}
*/
anim.SetFloat("X", x);
anim.SetFloat("Y", y);
transform.Translate(x * Time.deltaTime * moveSpeed,
y * Time.deltaTime * moveSpeed,
0);
}
}
Use XOR operator.
if (x != 0 ^ y != 0)
{
// moving..
}
Related
I am using Sebastian Graves' Dark Souls in Unity series in order to make a game with souls-like mechanics and reached episode 4 but in comparison to his video, my player is tuck in place when using rolling or backstepping.
The problem seems to be coming from the AnimatorHandler script:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace Game
{
public class AnimatorHandler : MonoBehaviour
{
public Animator anim;
public InputHandler inputHandler;
public PlayerLocomotion playerLocomotion;
int vertical;
int horizontal;
public bool canRotate;
public void Initialize()
{
anim = GetComponent<Animator>();
inputHandler = GetComponentInParent<InputHandler>();
playerLocomotion = GetComponentInParent<PlayerLocomotion>();
vertical = Animator.StringToHash("Vertical");
horizontal = Animator.StringToHash("Horizontal");
}
public void UpdateAnimatorValues(float verticalMovement, float horizontalMovement)
{
float v = 0;
if (verticalMovement > 0 && verticalMovement < 0.55f)
{
v = 0.5f;
}
else if (verticalMovement > 0.55f)
{
v = 1;
}
else if (verticalMovement < 0 && verticalMovement > -0.55f)
{
v = -0.5f;
}
else if (verticalMovement < -0.55f)
{
v = -1;
}
else
{
v = 0;
}
float h = 0;
if (horizontalMovement > 0 && horizontalMovement < 0.55f)
{
h = 0.5f;
}
else if (horizontalMovement > 0.55f)
{
h = 1;
}
else if (horizontalMovement < 0 && horizontalMovement > -0.55f)
{
h = -0.5f;
}
else if (horizontalMovement < -0.55f)
{
h = -1;
}
else
{
h = 0;
}
anim.SetFloat(vertical, v, 0.1f, Time.deltaTime);
anim.SetFloat(horizontal, h, 0.1f, Time.deltaTime);
}
public void PlayTargetAnimation(string targetAnim, bool isInteracting)
{
anim.applyRootMotion = isInteracting;
anim.SetBool("isInteracting", isInteracting);
anim.CrossFade(targetAnim, 0.2f);
}
public void CanRotate()
{
canRotate = true;
}
public void StopRotation()
{
canRotate = false;
}
private void OnAnimatorMove()
{
if (inputHandler.isInteracting == false)
return;
float delta = Time.deltaTime;
playerLocomotion.rigidbody.drag = 0;
Vector3 deltaPosition = anim.deltaPosition;
deltaPosition.y = 0;
Vector3 velocity = deltaPosition / delta;
playerLocomotion.rigidbody.velocity = velocity;
// ???
}
}
}
The only method I found to make the player able to move was to delete playerLocomotion.rigidbody.velocity = velocity;
, but this generates another problem, as I am now able to change roll direction mid-animation.
How can I make this work?
So decided to give game dev a try, picked up unity,Now I decided to create a simple ping pong game.
My game has Bat.cs class, ball.cs, and GameHandler.cs.
The GameHandler.cs initializes the batRight, batLeft, ball using the Bat.cs, Ball.cs class and prefabs, it also keeps track of if someone scores then starts a serve by stopping the rally:
public class GameHandler : MonoBehaviour
{
public Bat bat;
public Ball ball;
public Score score;
public static Vector2 bottomLeft;
public static Vector2 topRight;
public static bool rallyOn = false;
public static bool isServingLeft = true;
public static bool isServingRight = false;
public static bool isTwoPlayers = true;
static Bat batRight;
static Bat batLeft;
public static Ball ball1;
static Score scoreLeft;
static Score scoreRight;
// Start is called before the first frame update
void Start()
{
//Convert screens pixels coordinate into games coordinate
bottomLeft = Camera.main.ScreenToWorldPoint(new Vector2(0, 0));
topRight = Camera.main.ScreenToWorldPoint(new Vector2(Screen.width, Screen.height));
ball1 = Instantiate(ball) as Ball;
//Debug.Log("GameHandler.Start");
batRight = Instantiate(bat) as Bat;
batRight.Init(true);
batLeft = Instantiate(bat) as Bat;
batLeft.Init(false);
ball1.transform.position = new Vector3(batLeft.transform.position.x + ball1.getRadius() * 2, batLeft.transform.position.y);
//Instatiate scores
scoreLeft = Instantiate(score, new Vector2(-2, -4), Quaternion.identity) as Score;
scoreRight = Instantiate(score, new Vector2(2, -4), Quaternion.identity) as Score;
}
private void Update()
{
if (isServingLeft)
{
ball1.transform.position = new Vector3(batLeft.transform.position.x + ball1.getRadius() * 2, batLeft.transform.position.y);
if (Input.GetKey(KeyCode.LeftControl))
{
rallyOn = true;
isServingLeft = false;
}
}
if (isServingRight)
{
ball1.transform.position = new Vector3(batRight.transform.position.x - ball1.getRadius() * 2, batRight.transform.position.y);
if (isTwoPlayers && Input.GetKey(KeyCode.RightControl))
{
rallyOn = true;
isServingRight = false;
}
else
{
StartCoroutine(batRight.serveAi());
if (GameHandler.rallyOn)
{
StopCoroutine(batRight.serveAi());
}
}
}
}
public static void increaseScoreByOne(bool isRight)
{
rallyOn = false;
if (isRight)
{
scoreRight.increaseScore();
isServingRight = true;
}
else
{
scoreLeft.increaseScore();
isServingLeft = true;
}
}
}
The ball.cs listens to the static GameHandler.rallyOn and starts moving the ball accordingly, it also changes direction of the ball if it hits a vertical wall or the bat:
public class Ball : MonoBehaviour
{
[SerializeField]
float speed;
float radius;
public Vector2 direction;
public Vector3 ballPosition;
// Start is called before the first frame update
void Start()
{
direction = Vector2.one.normalized; // direction is (1, 1) normalized
//Debug.Log("direction * speed * Time.deltaTime:" + direction * speed * Time.deltaTime);
radius = transform.localScale.x / 2;
}
// Update is called once per frame
void Update()
{
ballPosition = transform.position;
if (GameHandler.rallyOn)
{
startRally();
}
}
void startRally()
{
transform.Translate(direction * speed * Time.deltaTime);
Debug.Log("direction * speed * Time.deltaTime:" + direction * speed * Time.deltaTime);
if ((transform.position.y + radius) > GameHandler.topRight.y && direction.y > 0)
{
direction.y = -direction.y;
}
if ((transform.position.y + radius) < GameHandler.bottomLeft.y && direction.y < 0)
{
direction.y = -direction.y;
}
if ((transform.position.x + radius) > GameHandler.topRight.x && direction.x > 0)
{
// Left player scores
GameHandler.increaseScoreByOne(false);
//For no, just freeza the script
// Time.timeScale = 0;
//enabled = false;
}
if ((transform.position.x - radius) < GameHandler.bottomLeft.x && direction.x < 0)
{
// right player scores
GameHandler.increaseScoreByOne(true);
}
}
void OnTriggerEnter2D(Collider2D collision)
{
if(collision.tag == "Bat")
{
if (collision.GetComponent<Bat>().isRight && direction.x > 0)
{
direction.x = -direction.x;
}
if (!collision.GetComponent<Bat>().isRight && direction.x < 0)
{
direction.x = -direction.x;
}
}
}
public float getRadius()
{
return radius;
}
}
The bat.cs initiazes the two paddles, and either listens to user input if its 2 players or listens to player and use AI if it is player vs CPU.:
public class Bat : MonoBehaviour
{
float height;
[SerializeField] // this make this appear on editor without making this field public
float speed;
string input;
public bool isRight;
string PLAYER1_INPUT = "PaddleLeft";
string PLAYER2_INPUT = "PaddleRight";
// Start is called before the first frame update
void Start()
{
height = transform.localScale.y;
}
// Update is called once per frame
void Update()
{
if (GameHandler.isTwoPlayers)
{
if (isRight)
{
movePaddleonUserInput(PLAYER2_INPUT);
}
else
{
movePaddleonUserInput(PLAYER1_INPUT);
}
}
else
{
if (isRight)
{
movePaddleAi();
}
else
{
movePaddleonUserInput(PLAYER1_INPUT);
}
}
}
void movePaddleAi()
{
if (isRight && GameHandler.ball1.direction.x > 0 && GameHandler.ball1.ballPosition.x > 0)
{
//transform.Translate(direction * speed * Time.deltaTime);
if ((transform.position.y) > GameHandler.ball1.ballPosition.y && GameHandler.ball1.direction.y < 0)
{
transform.Translate(GameHandler.ball1.direction * speed * Time.deltaTime * Vector2.up);
}
if ((transform.position.y) < GameHandler.ball1.ballPosition.y && GameHandler.ball1.direction.y > 0)
{
transform.Translate(GameHandler.ball1.direction * speed * Time.deltaTime * Vector2.up);
}
}
}
void movePaddleonUserInput(string input)
{
// move = (-1 -> 1) * speed * timeDelta(this keep move framerate independent)
float move = Input.GetAxis(input) * speed * Time.deltaTime;
//Debug.Log((transform.position.y + height / 2) + " > "+ GameHandler.topRight.y+ "&&" + move +" > 0");
//Restrict paddle movement to to the screen
// (top edge of paddle > Screen top and we are moving up)
if ((transform.position.y + height / 2) > GameHandler.topRight.y && move > 0)
{
move = 0;
}
// (bottom edge of paddle < Screen top and we are moving down)
if ((transform.position.y - height / 2) < GameHandler.bottomLeft.y && move < 0)
{
move = 0;
}
transform.Translate(move * Vector2.up);
}
public void Init(bool isRightPaddle)
{
isRight = isRightPaddle;
Vector2 pos;
if (isRightPaddle)
{
isRight = isRightPaddle;
pos = new Vector2(GameHandler.topRight.x, 0);
// offset since center is the anchor
pos -= Vector2.right * transform.localScale.x;
input = "PaddleRight";
}
else
{
pos = new Vector2(GameHandler.bottomLeft.x, 0);
// offset since center is the anchor
pos += Vector2.right * transform.localScale.x;
input = "PaddleLeft";
}
transform.name = input;
transform.position = pos;
}
public IEnumerator serveAi()
{
yield return new WaitForSecondsRealtime (2f);
GameHandler.rallyOn = true;
GameHandler.isServingRight = false;
}
}
Now I also have score.cs and mainMenu scene , but no need to include that for this question, What I am struggling with now is the AI not stopping after it scores a point, I want the AI paddle to stop for a few seconds before it serves.
As you can see in the code, I added a yield return new WaitForSecondsRealtime(2f);
public IEnumerator serveAi()
{
yield return new WaitForSecondsRealtime (2f);
GameHandler.rallyOn = true;
GameHandler.isServingRight = false;
}
But this only cause the paddle to wait for the first time it scores , and then if it scores again in quick interval, it doesn't wait at all.
Not sure what I doing wrong here, thanks for your time.
The more plausible explanation to me would be that GameHandler.rallyOn and isServing* aren't all being reset to the correct values to prevent the serve from occurring before the coroutine even begins, or another check is needed somewhere to prevent a serve from occurring if all of the correct booleans aren't set. Try placing appropriate breakpoints and stepping through in a debugger.
You'd probably be better off using WaitForSeconds rather than WaitForSecondsRealtime, by the way, at least if there's a chance you might want to allow the game to be paused in the future.
Realized that the coroutine is called multiple times even before its finished due do it being called from update function in GameHandler.cs. Needed a way to check if the co-routine is already running and not start a new one from update if so, used the Game.isServing variable to do so:
public IEnumerator serveAi()
{
GameHandler.isServingRight = false; // coroutine started , no need to start new one
yield return new WaitForSecondsRealtime (2f);
GameHandler.rallyOn = true;
}
And my update in GameHandler is already checking for that variable before starting the coroutine:
private void Update()
{
if (isServingLeft)
{
ball1.transform.position = new Vector3(batLeft.transform.position.x + ball1.getRadius() * 2, batLeft.transform.position.y);
if (Input.GetKey(KeyCode.LeftControl))
{
rallyOn = true;
isServingLeft = false;
}
}
if (isServingRight)
{
ball1.transform.position = new Vector3(batRight.transform.position.x - ball1.getRadius() * 2, batRight.transform.position.y);
if (isTwoPlayers && Input.GetKey(KeyCode.RightControl))
{
rallyOn = true;
isServingRight = false;
}
else
{
StartCoroutine(batRight.serveAi());
}
}
}
My problem is, that when Im moving against a wall, that there is a little bouncing effect. Here is a video of it:
https://www.dropbox.com/s/t5drxu4aw60nq59/meem.mp4?dl=0
I dont know how to fix it, I already tried everything. I hope someone know a solution for this. Thank you
Here is the movement script:
public class PlayerMovement : MonoBehaviour
{
public float speed;
public float x;
public float y;
public bool canMove;
void FixedUpdate()
{
if (canMove)
{
if (Input.GetKey(KeyCode.UpArrow) || Input.GetKey(KeyCode.W))
{
GoUp();
}
else if (Input.GetKey(KeyCode.DownArrow) || Input.GetKey(KeyCode.S))
{
GoDown();
}
else if (Input.GetKey(KeyCode.RightArrow) || Input.GetKey(KeyCode.D))
{
GoRight();
}
else if (Input.GetKey(KeyCode.LeftArrow) || Input.GetKey(KeyCode.A))
{
GoLeft();
}
if (Input.GetKey(KeyCode.UpArrow) && Input.GetKey(KeyCode.RightArrow))
{
GoUp();
GoRight();
}
else if (Input.GetKey(KeyCode.UpArrow) && Input.GetKey(KeyCode.LeftArrow))
{
GoUp();
GoLeft();
}
else if (Input.GetKey(KeyCode.DownArrow) && Input.GetKey(KeyCode.RightArrow))
{
GoDown();
GoRight();
}
else if (Input.GetKey(KeyCode.DownArrow) && Input.GetKey(KeyCode.LeftArrow))
{
GoDown();
GoLeft();
}
this.transform.position = new Vector2(this.transform.position.x + x, this.transform.position.y + y);
x = 0;
y = 0;
}
}
public void GoUp()
{
y = Time.deltaTime * speed;
}
public void GoDown()
{
y = Time.deltaTime * (-speed);
}
public void GoRight()
{
x = Time.deltaTime * speed;
}
public void GoLeft()
{
x = Time.deltaTime * (-speed);
}
}
Find two suggestions to handle stop going right example. Note they are going to be not debugued code, as I dont know your project details. Also no the most correct in many aspects for the saem reason. Just to give you the idea.
1.- With distance control
public GameObject wall; //ref to wall set in editor
float playerHalfSize = 0f;
float wallHalfSize = 0f;
float bodiesTotDist = 0f;
Start() {
playerHalfSize = transform.scale.x / 2;
wallHalfSize = wall.scale.x / 2; // supposing size is set with scale. Preferably get the size with a collider or the mesh renderer Bounds class inside the respective collider or MeshRenderer classes
bodiesTotDist = playerHalfSize + wallHalfSize;
}
float getDistanceToWall(wall) {
float distance = Vector3.Distance(transform.position, wall.transform.position) - bodiesTotDist;
}
public void GoRight()
{
if (getDistanceToWall() > 0) //this avoids your player x move further to the right
x = Time.deltaTime * speed;
}
If you might still see the bouncing you can try to adjust manually a threshold distance, for example getDistanceToWall() > 0.5f or adjunting the collider.
2.- With a trigger: If you put a trigger a little bit bigger that your wall, when the wall touches the player you can handle in the code also to avoid further x right set.
bool isRightWallTouching = false;
void OnTriggerEnter2D(Collider2D col)
{
if (col.gameObject == wall) //for the right wall
isRightWallTouching = true;
}
void OnTriggerExit2D(Collider2D other)
{
isRightWallTouching = false;
}
public void GoRight()
{
if (isRightWallTouching > 0) //this avoids your player x move further to the right
x = Time.deltaTime * speed;
}
As told, not debugged code so might have some failures and the chance that you might have many walls, so this suggestion may lead to a lots of bools dirty solution, but hope it can provide you some inspiration to put your game to work and move on :)
I have created a twin stick movement system for mobile. I have a character moving under the influence of one joystick correctly. The other joystick, the design I want is:
When the shoot JS is moved, look in that direction.
When the shoot JS is released, shoot in the last aimed direction.
What's happening is, the character shoots continuously when the game starts and if I move the ShootJS, the character spins in circles. I'm completely flummoxed as to why this is happening.
Here is my code. Thanks in advance to anybody for any help you provide.
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.AI;
using Ludiq;
using Bolt;
public class PlayerJSControlSc : MonoBehaviour
{
public GameObject player;
public NavMeshAgent nav;
public Text stateText;
public float moveSpeed;
public Animator animator;
public FloatingJoystick moveJS;
public FloatingJoystick shootJS;
public float rotationSpeed = 10;
public int ammo;
public int mag;
public Transform shotSpawn;
public GameObject bullet;
public float reloadTime;
public Text ammoCount;
[HideInInspector]
int currentMag;
// Start is called before the first frame update
void Start()
{
stateText.text = "";
nav = player.GetComponent<NavMeshAgent>();
animator = player.GetComponent<Animator>();
moveJS = GameObject.Find("Floating JS_Move").GetComponent<FloatingJoystick>();
shootJS = GameObject.Find("Floating JS_Shoot").GetComponent<FloatingJoystick>();
}
// Update is called once per frame
void Update()
{
movePlayer();
playerShoot();
ammoCount.text = currentMag+ "/" + ammo;
}
public void movePlayer()
{
//float x = Input.GetAxis("Horizontal");
//float y = Input.GetAxis("Vertical");
float x = moveJS.Horizontal;
float y = moveJS.Vertical;
nav.velocity = new Vector3(x * moveSpeed, 0, y * moveSpeed);
if (nav.velocity.x != 0 || nav.velocity.z != 0)
{ animator.SetBool("isRunning", true); }
else { animator.SetBool("isRunning", false); }
}
public void playerShoot()
{
bool isAiming = false;
float x = shootJS.Horizontal; float z = shootJS.Vertical;
if (x != 0 || z != 0)
{
isAiming = true;
/* Vector3 lookDir = new Vector3(x, 0, z);
Quaternion lookRotation = Quaternion.LookRotation(lookDir, Vector3.up);
float step = rotationSpeed * Time.deltaTime;
player.transform.rotation = Quaternion.RotateTowards(lookRotation, transform.rotation, step);*/
float myAngle = Mathf.Atan2(x, z) * Mathf.Rad2Deg;
float bodyRotation = myAngle + player.transform.eulerAngles.y;
player.transform.Rotate( 0,myAngle,0,Space.World);
}
else { shoot();isAiming = false; }
}
void shoot()
{
if (currentMag > 0)
{
Instantiate(bullet, shotSpawn.position, shotSpawn.rotation);
currentMag--;
}
else if (currentMag=0)
{
StartCoroutine(reload());
}
else
return;
}
IEnumerator reload()
{
ammo = ammo - mag;
currentMag = mag;
yield return new WaitForSeconds(reloadTime);
}
}
well you are calling every frame playerShoot() -> not moving -> shoot().
And in the same way also playerShoot() -> not moving -> player.transform.Rotate( 0,myAngle,0,Space.World);.
I think what you rather should do is
doing the shoot only in the very first frame where both inputs are 0
for the move rather set the rotation instead of increasing it
Something like
private bool lastFrameMoved;
public void playerShoot()
{
float x = shootJS.Horizontal;
float z = shootJS.Vertical;
if (x != 0 || z != 0)
{
var lookDir = new Vector3(x, 0, z);
var lookRotation = Quaternion.LookRotation(lookDir, Vector3.up);
player.transform.rotation = lookRotation;
lastFrameMoved = true;
}
else
{
if(lastFrameMoved)
{
shoot();
}
lastFrameMoved = false;
}
}
I solved the look rotation in Bolt (because it helps me visualize). I'll solve the shoot part soon. I'm using the wonderful Joystick Pack by Fenerax Studios.
https://assetstore.unity.com/publishers/32730
CurrentlyGrounded Should flip to true and false. Instead, visual studio is reporting that it "Doesn't exist in the current context". How do I force this variable to exist EVERYWHERE in the script?
Making it public did absolutely nothing.
The problem occurs in the private void GroundCheck() method on Line 267.
using System;
using UnityEngine;
using UnityStandardAssets.CrossPlatformInput;
namespace UnityStandardAssets.Characters.FirstPerson
{
[RequireComponent(typeof (Rigidbody))]
[RequireComponent(typeof (CapsuleCollider))]
public class RigidbodyFirstPersonController : MonoBehaviour
{
[Serializable]
public class MovementSettings
{
public float ForwardSpeed = 8.0f; // Speed when walking forward
public float BackwardSpeed = 4.0f; // Speed when walking backwards
public float StrafeSpeed = 4.0f; // Speed when walking sideways
public float AirForwardSpeed = 8.0f; // Speed when flying forward
public float AirBackwardSpeed = 4.0f; // Speed when flying backwards
public float AirStrafeSpeed = 4.0f; // Speed when flying sideways
public bool CurrentlyGrounded = true;
public float RunMultiplier = 2.0f; // Speed when sprinting
public KeyCode RunKey = KeyCode.LeftShift;
public float JumpForce = 30f;
public AnimationCurve SlopeCurveModifier = new AnimationCurve(new Keyframe(-90.0f, 1.0f), new Keyframe(0.0f, 1.0f), new Keyframe(90.0f, 0.0f));
[HideInInspector] public float CurrentTargetSpeed = 8f;
#if !MOBILE_INPUT
private bool m_Running;
#endif
public void UpdateDesiredTargetSpeed(Vector2 input)
{
if (input == Vector2.zero) return;
if (input.x > 0 || input.x < 0 && CurrentlyGrounded == true)
{
//strafe
CurrentTargetSpeed = StrafeSpeed;
}
else if (input.x > 0 || input.x < 0 && CurrentlyGrounded == false)
{
//strafe
CurrentTargetSpeed = AirStrafeSpeed;
}
if (input.y < 0 && CurrentlyGrounded == true)
{
//backwards
CurrentTargetSpeed = BackwardSpeed;
}
else if (input.y < 0 && CurrentlyGrounded == false)
{
//backwards
CurrentTargetSpeed = AirBackwardSpeed;
}
if (input.y > 0 && CurrentlyGrounded == true)
{
//forwards
//handled last as if strafing and moving forward at the same time forwards speed should take precedence
CurrentTargetSpeed = ForwardSpeed;
}
else if (input.y > 0 && CurrentlyGrounded == false)
{
//forwards
//handled last as if strafing and moving forward at the same time forwards speed should take precedence
CurrentTargetSpeed = AirForwardSpeed;
}
#if !MOBILE_INPUT
if (Input.GetKey(RunKey))
{
CurrentTargetSpeed *= RunMultiplier;
m_Running = true;
}
else
{
m_Running = false;
}
#endif
}
#if !MOBILE_INPUT
public bool Running
{
get { return m_Running; }
}
#endif
}
[Serializable]
public class AdvancedSettings
{
public float groundCheckDistance = 0.01f; // distance for checking if the controller is grounded ( 0.01f seems to work best for this )
public float stickToGroundHelperDistance = 0.5f; // stops the character
public float slowDownRate = 20f; // rate at which the controller comes to a stop when there is no input
public bool airControl; // can the user control the direction that is being moved in the air
[Tooltip("set it to 0.1 or more if you get stuck in wall")]
public float shellOffset; //reduce the radius by that ratio to avoid getting stuck in wall (a value of 0.1f is nice)
}
public Camera cam;
public MovementSettings movementSettings = new MovementSettings();
public MouseLook mouseLook = new MouseLook();
public AdvancedSettings advancedSettings = new AdvancedSettings();
private Rigidbody m_RigidBody;
private CapsuleCollider m_Capsule;
private float m_YRotation;
private Vector3 m_GroundContactNormal;
private bool m_Jump, m_PreviouslyGrounded, m_Jumping, m_IsGrounded;
public Vector3 Velocity
{
get { return m_RigidBody.velocity; }
}
public bool Grounded
{
get { return m_IsGrounded; }
}
public bool Jumping
{
get { return m_Jumping; }
}
public bool Running
{
get
{
#if !MOBILE_INPUT
return movementSettings.Running;
#else
return false;
#endif
}
}
private void Start()
{
m_RigidBody = GetComponent<Rigidbody>();
m_Capsule = GetComponent<CapsuleCollider>();
mouseLook.Init (transform, cam.transform);
}
private void Update()
{
RotateView();
if (CrossPlatformInputManager.GetButtonDown("Jump") && !m_Jump)
{
m_Jump = true;
}
}
private void FixedUpdate()
{
GroundCheck();
Vector2 input = GetInput();
if ((Mathf.Abs(input.x) > float.Epsilon || Mathf.Abs(input.y) > float.Epsilon) && (advancedSettings.airControl || m_IsGrounded))
{
// always move along the camera forward as it is the direction that it being aimed at
Vector3 desiredMove = cam.transform.forward*input.y + cam.transform.right*input.x;
desiredMove = Vector3.ProjectOnPlane(desiredMove, m_GroundContactNormal).normalized;
desiredMove.x = desiredMove.x*movementSettings.CurrentTargetSpeed;
desiredMove.z = desiredMove.z*movementSettings.CurrentTargetSpeed;
desiredMove.y = desiredMove.y*movementSettings.CurrentTargetSpeed;
if (m_RigidBody.velocity.sqrMagnitude <
(movementSettings.CurrentTargetSpeed*movementSettings.CurrentTargetSpeed))
{
m_RigidBody.AddForce(desiredMove*SlopeMultiplier(), ForceMode.Impulse);
}
}
if (m_IsGrounded)
{
m_RigidBody.drag = 5f;
if (m_Jump)
{
m_RigidBody.drag = 0f;
m_RigidBody.velocity = new Vector3(m_RigidBody.velocity.x, 0f, m_RigidBody.velocity.z);
m_RigidBody.AddForce(new Vector3(0f, movementSettings.JumpForce, 0f), ForceMode.Impulse);
m_Jumping = true;
}
if (!m_Jumping && Mathf.Abs(input.x) < float.Epsilon && Mathf.Abs(input.y) < float.Epsilon && m_RigidBody.velocity.magnitude < 1f)
{
m_RigidBody.Sleep();
}
}
else
{
m_RigidBody.drag = 0f;
if (m_PreviouslyGrounded && !m_Jumping)
{
StickToGroundHelper();
}
}
m_Jump = false;
}
private float SlopeMultiplier()
{
float angle = Vector3.Angle(m_GroundContactNormal, Vector3.up);
return movementSettings.SlopeCurveModifier.Evaluate(angle);
}
private void StickToGroundHelper()
{
RaycastHit hitInfo;
if (Physics.SphereCast(transform.position, m_Capsule.radius * (1.0f - advancedSettings.shellOffset), Vector3.down, out hitInfo,
((m_Capsule.height/2f) - m_Capsule.radius) +
advancedSettings.stickToGroundHelperDistance, Physics.AllLayers, QueryTriggerInteraction.Ignore))
{
if (Mathf.Abs(Vector3.Angle(hitInfo.normal, Vector3.up)) < 85f)
{
m_RigidBody.velocity = Vector3.ProjectOnPlane(m_RigidBody.velocity, hitInfo.normal);
}
}
}
private Vector2 GetInput()
{
Vector2 input = new Vector2
{
x = CrossPlatformInputManager.GetAxis("Horizontal"),
y = CrossPlatformInputManager.GetAxis("Vertical")
};
movementSettings.UpdateDesiredTargetSpeed(input);
return input;
}
private void RotateView()
{
//avoids the mouse looking if the game is effectively paused
if (Mathf.Abs(Time.timeScale) < float.Epsilon) return;
// get the rotation before it's changed
float oldYRotation = transform.eulerAngles.y;
mouseLook.LookRotation (transform, cam.transform);
if (m_IsGrounded || advancedSettings.airControl)
{
// Rotate the rigidbody velocity to match the new direction that the character is looking
Quaternion velRotation = Quaternion.AngleAxis(transform.eulerAngles.y - oldYRotation, Vector3.up);
m_RigidBody.velocity = velRotation*m_RigidBody.velocity;
}
}
/// sphere cast down just beyond the bottom of the capsule to see if the capsule is colliding round the bottom
private void GroundCheck()
{
m_PreviouslyGrounded = m_IsGrounded;
RaycastHit hitInfo;
if (Physics.SphereCast(transform.position, m_Capsule.radius * (1.0f - advancedSettings.shellOffset), Vector3.down, out hitInfo,
((m_Capsule.height/2f) - m_Capsule.radius) + advancedSettings.groundCheckDistance, Physics.AllLayers, QueryTriggerInteraction.Ignore))
{
m_IsGrounded = true;
CurrentlyGrounded = true;
m_GroundContactNormal = hitInfo.normal;
}
else
{
m_IsGrounded = false;
CurrentlyGrounded = false;
m_GroundContactNormal = Vector3.up;
}
if (!m_PreviouslyGrounded && m_IsGrounded && m_Jumping)
{
m_Jumping = false;
}
}
}
}
What should be happening is that it's seen and changes as expected.
Instead, it's reported as nonexisting in the current context.
Don't listen to people who want to make everything static just to access stuff "more easily".
This actually might cause a lot of trouble as soon as you have more than exactly one instances of that class (e.g. if there are two players, or an AI uses the same component).
Another bad side effect is that you won't be able anymore to configure it via the Inspector e.g. for debugging or to give it the desired start value.
What you want to use instead is
moventSettings.CurrentlyGrounded
to access the value of your MovementSettings instance.
Just the same way you did it e.g. in
movementSettings.Running
You can assign it to a global variable.
public static class Globals
{
public static String value = "Sample Value"; // Modifiable
public static readonly String CODE_PREFIX = "TEST-"; // Unmodifiable
}
You can then retrieve the defined values anywhere in your code
String code = Globals.CODE_PREFIX + value.ToString();