How can I stop my character Going Up Automatically? - c#

Why my character going up automatically though I'm not pressing any button?
I want to control my player jump movement.
But I cant do it.
What is the solution?
Please explain.
Can you also suggest how can I customise my jump, like jump twice? etc
public class movement: MonoBehaviour {
public float speed = 10;
private Rigidbody2D rb;
public float jumpSpeed = 1;
void Start() {
rb = GetComponent < Rigidbody2D > ();
}
// Update is called once per frame
void Update() {
Jump();
var inputX = Input.GetAxis("Horizontal");
Vector3 movement = new Vector3(inputX, 0, 0) * speed;
movement *= Time.deltaTime;
transform.Translate(movement);
Vector3 characterScale = transform.localScale;
if (inputX < 0) {
transform.localScale = new Vector3(5, transform.localScale.y, transform.localScale.z);
}
if (inputX > 0) {
transform.localScale = new Vector3(-5, transform.localScale.y, transform.localScale.z);
}
}
void Jump() {
if (Input.GetKeyDown(KeyCode.Space));
rb.velocity = Vector2.up * jumpSpeed;
}
}

Your issue is with the if statement in Jump. If there are no curly braces after an if statement, only the first statement is enclosed within the if.
if (something)
do_stuff(); // This will execute if something evaluates to true
do_other_stuff(); // This will execute no matter what
In your case, the next statement looks like this:
if (Input.GetKeyDown(KeyCode.Space))
;
The semicolon is an empty statement. Then, the second line rb.velocity = Vector2.up * jumpSpeed; executes normally.
This is in java, but the same logic applies to C#
Proper code will look like:
if (Input.GetKeyDown(KeyCode.Space)) {
rb.velocity = Vector2.up * jumpSpeed;
}
Note that there is no semicolon on the line of the if statement.

Related

Unity AI character controller gravity

I am trying to add gravity to my "residents" of a town builder game. Basically the residents just walk around to a random location, wait 2 seconds then do it again. I am trying to add gravity to them so they don't float.
controller = GetComponent<CharacterController>();
moveDirection = Vector3.zero;
moveDirection.y -= gravity * Time.deltaTime;
controller.Move(moveDirection * Time.deltaTime);
These four lines are the gravity lines I tried added and very weird things happen such as the resident teleporting up if it touches anything, even the ground. What can I do? I basically just want the residents not to float above the ground and follow the slopes of the land like regular walking.
Below is the whole code if its needed to help solve my problem.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Resident : MonoBehaviour
{
private Vector3 location;
private Quaternion rotation;
private int speed;
private Vector3 moveDirection = Vector3.zero;
private bool canRotate = true;
Vector3 moveVector;
CharacterController controller;
// Start is called before the first frame update
void Start()
{
transform.rotation *= Quaternion.Euler(-90, 0, 0);
controller = GetComponent<CharacterController>();
speed = 5;
SetRandomPos();
StartCoroutine(ExampleCoroutine());
}
void Update()
{
int gravity = 20;
moveDirection = Vector3.zero;
//Check if cjharacter is grounded
moveDirection.y -= gravity * Time.deltaTime;
// Move the controller
controller.Move(moveDirection * Time.deltaTime);
float step = speed * Time.deltaTime;
transform.position = Vector3.MoveTowards(transform.position, location, step);
if (canRotate)
{
transform.LookAt(location);
transform.rotation *= Quaternion.Euler(-90, 90, 0);
canRotate = false;
}
if (transform.position == location)
{
StartCoroutine(ExampleCoroutine());
}
}
void SetRandomPos()
{
location = new Vector3(Random.Range(transform.position.x - 10f, transform.position.x + 10f), transform.position.y, Random.Range(transform.position.z - 10f, transform.position.z + 10f));
canRotate = true;
}
IEnumerator ExampleCoroutine()
{
//yield on a new YieldInstruction that waits for 5 seconds.
yield return new WaitForSeconds(2);
//After we have waited 5 seconds print the time again.
if (transform.position == location)
{
SetRandomPos();
}
}
}
I am not exactly clear what you intend to do, but saw a few issues with the code and tried to fix them. The snippet is untested, I just added what I believe to be the correction that should fix your issues.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
private Vector3 location;
private Coroutine changeMovement = null;
private float speed;
private Vector3 playerVelocity = Vector3.zero;
CharacterController controller;
// Start is called before the first frame update
void Start()
{
controller = GetComponent<CharacterController>();
speed = 5;
SetRandomPos();
}
void Update()
{
bool groundedPlayer = controller.isGrounded;
if (groundedPlayer && playerVelocity.y < 0)
{
playerVelocity.y = 0f;
}
Vector3 move = (transform.position - location).normalized;
controller.Move(move * Time.deltaTime * speed);
if (move != Vector3.zero)
{
gameObject.transform.forward = move;
}
// check if we are close to our goal, then change the goal
if (changeMovement == null && Vector3.Distance(transform.position,location) < 0.1f)
{
changeMovement = StartCoroutine(ExampleCoroutine());
}
playerVelocity.y += gravityValue * Time.deltaTime;
controller.Move(playerVelocity * Time.deltaTime);
}
void SetRandomPos()
{
location = new Vector3(Random.Range(transform.position.x - 10f, transform.position.x + 10f), transform.position.y, Random.Range(transform.position.z - 10f, transform.position.z + 10f));
}
IEnumerator ExampleCoroutine()
{
//yield on a new YieldInstruction that waits for 5 seconds.
yield return new WaitForSeconds(2);
SetRandomPos();
changeMovement = null;
}
Edit: I changed the code and used the CharacterController.Move as a base.

When I want my Player to jump he is flying (Unity2d)

Hello I want to make my first game in 2D but when i want to Jump, my Player is flying and he doesnt come back to the ground. I don't know why it doesnt work. Hopefully someone can help me. Thank you. Here is my Code:
using UnityEngine;
using System.Collections;
public class Move2D : MonoBehaviour
{
public float speed = 5f;
public float jumpSpeed = 8f;
private float movement = 0f;
private Rigidbody2D rigidBody;
// Use this for initialization
void Start()
{
rigidBody = GetComponent<Rigidbody2D>();
}
// Update is called once per frame
void Update()
{
movement = Input.GetAxis("Horizontal");
if (movement > 0f)
{
rigidBody.velocity = new Vector2(movement * speed, rigidBody.velocity.y);
}
else if (movement < 0f)
{
rigidBody.velocity = new Vector2(movement * speed, rigidBody.velocity.y);
}
else
{
rigidBody.velocity = new Vector2(0, rigidBody.velocity.y);
}
if (Input.GetButtonDown("Jump"))
{
rigidBody.velocity = new Vector2(rigidBody.velocity.x, jumpSpeed);
}
}
}
You set the y velocity on jump but never set it back to anything else. I suggest that for jump you use rigidBody.AddForce:
rigidBody.AddForce(transform.up * jumpSpeed, ForceMode2D.Impulse);
I also have to say that your first if..else if...else seems to be redundant.
If movement > 0, you do X, is movement is < 0, you do exactly the same, and
if movement == 0, you still do the same even tho you write it differently. (If movement == 0 then movement * speed is also 0). So you could just state that
rigidBody.velocity = new Vector2(movement * speed, rigidBody.velocity.y);
without using if at all.
edit: I accidentally wrote wrong line for what to use, fixed it now.
edit2: So after both of these changes your Update function would be like:
void Update()
{
movement = Input.GetAxis("Horizontal");
rigidBody.velocity = new Vector2(movement * speed, rigidBody.velocity.y);
if (Input.GetButtonDown("Jump"))
{
rigidBody.AddForce(transform.up * jumpSpeed, ForceMode2D.Impulse);
}
}

unity Character jump and fall more then the value that I put

I'm making a 2d game using unity the character only can jump and fall by 5 so the player should only jump and fall between the range y max is 5 and min is -5 it works but if I press to jump or fall more than two it across the range
how can I made the player can jump and fall only in the range that I put it?
this is my code :
public float speed;
public float increment;
public float maxY;
public float minY;
private Vector2 targetPos;
private void FixedUpdate()
{
transform.position = Vector2.MoveTowards(transform.position, targetPos, speed * Time.deltaTime);
if (Input.GetKeyDown(KeyCode.UpArrow) && transform.position.y <= maxY)
{
Instantiate(moveEffect, transform.position, Quaternion.identity);
targetPos = new Vector2(transform.position.x, transform.position.y + increment);
}
else if (Input.GetKeyDown(KeyCode.DownArrow) && transform.position.y >= minY)
{
Instantiate(moveEffect, transform.position, Quaternion.identity);
targetPos = new Vector2(transform.position.x, transform.position.y - increment);
}
}
You could afterwards simply limit the targetValue by clamping the y component using Mathf.Clamp like
private void FixedUpdate ()
{
...
targetPos.y = Mathf.Clamp(targetPos.y, minY, maxY);
}
I am also just guessing but you using FixedUpdate suggests that there might be a Rigidbody2D involved here.
In this case you should not set the position through the Transform component but rather use rb.MovePosition like
private Rigidbody2D rb;
private void Awake()
{
rb = GetComponent<Rigidbody2D>();
}
private void FixedUpdate()
{
rb.MovePosition(Vector2.MoveTowards(transform.position, targetPos, speed * Time.deltaTime));
...
}
If it is not the case rather move your code to Update as FixedUpdate is only used for stuff related to the game Physics (see also Update and FixedUpdate)
Whenever you see repetitive called, it is usually a good indication to write a function to reduce the duplicate code.
What you need to do is to clamp the values. Perhaps something like this would work?
public Vector2 GetVerticalPosition(Vector3 position, bool jump = true){
Instantiate(moveEffect, transform.position, Quaternion.identity);
var maxReach = 0f;
var clamp = 0f;
if(jump){
maxReach = transform.position.y + increment;
clamp = maxReach > maxY ? maxY : maxReach;
} else {
maxReach = transform.position.y - increment;
clamp = maxReach < minY ? minY : maxReach;
}
return new Vector2(position.x, clamp);
}
So your update would look like this.
Vector2 clampedPosition = null;
private void FixedUpdate(){
if (Input.GetKeyDown(KeyCode.UpArrow)){
clampedPosition = GetVerticalPosition(transform.position);
transform.position = Vector2.MoveTowards(transform.position, clampedPosition, speed * Time.deltaTime);
}
if (Input.GetKeyDown(KeyCode.DownArrow)){
clampedPosition = GetVerticalPosition(transform.position, false);
transform.position = Vector2.MoveTowards(transform.position, clampedPosition, speed * Time.deltaTime);
}
}

Delay before jump

I'm learning Unity, and I'm doing a character move, but the animation of the jump has a delay for the character to literally jump, a 0.30s until it picks up, how do I add this delay in the code?
Like, I thought of doing somehow that when you hit "Space" release the animation, count 0.20s and make the jump. it's viable? How can I do this?
In short, the character jumps before the animation.
Animation Video:
https://imgur.com/a/LgzkSKi
public class PlayerController : MonoBehaviour {
public float moveSpeed;
public float jumpForce;
public CharacterController controller;
private Vector3 moveDirection;
public float gravityScale;
public Animator animator;
void Start() {
controller = GetComponent<CharacterController>();
}
void Update() {
float yStore = moveDirection.y;
moveDirection = (transform.forward * Input.GetAxis("Vertical")) + (transform.right * Input.GetAxis("Horizontal"));
moveDirection = moveDirection.normalized * moveSpeed;
moveDirection.y = yStore;
jump();
controller.Move(moveDirection * Time.deltaTime);
animator.SetFloat("Speed", (Mathf.Abs(Input.GetAxis("Vertical"))));
}
void jump() {
if (controller.isGrounded) {
moveDirection.y = 0f;
if (Input.GetButtonDown("Jump")) {
moveDirection.y = jumpForce;
Debug.Log("jump");
}
}
moveDirection.y = moveDirection.y + (Physics.gravity.y * gravityScale * Time.deltaTime);
animator.SetBool("isGrounded", controller.isGrounded);
}
}
In your jump() function don't apply the jump force. Instead, set the next time the character is supposed to jump.
float nextJumpTime;
bool todoJump;
void jump() {
if (!todoJump && Input.GetButtonDown("Jump")) {
// Remember we have to jump and when
nextJumpTime = Time.time + 0.2f;
todoJump = true;
}
// Execute the jump
if (todoJump && Time.time >= nextJumpTime) {
todoJump = false;
moveDirection.y = jumpForce;
}
}
Either that or read on coroutines. Start a coroutine on input, yield return new WaitForSecond(0.2f); in the coroutine and then execute the jump.
To what One Man Mokey Squad suggest I think you should also consider to get a new jump animation or trim the current animation.
I think it's not a great idea to create a custom code for that broken jump animation because you will not be able to reuse your script.

Unity: Infinite While Loop in Coroutine

Okay so I'm trying to create a small dash coroutine for my 2d character. When the coroutine calls, gravity switches off, he lerps between 2 speeds over a time. The issue is within my Dash coroutine, the while loop checks when time.time(current time) > start time + dash duration.
While debugging this with Mono, I'm finding that my variable currentTime is not changing after being set, even though I can clearly see the while loop running more than once. This puts me in an infinite loop.
Any suggestions?
void Update () {
MoveAndJump ();
CheckDash ();
}
void MoveAndJump(){
if(dashing){
return;
}
Vector2 moveDir = new Vector2 (Input.GetAxisRaw ("Horizontal") * moveSpeed, rb.velocity.y);
rb.velocity = moveDir;
// Consider Switching to an overlap circle based on the actual character graphic. This currently uses a rectangle
// This can also use 4 points to create a more complex box shape. This only works well when using at least about 1 unit size. any smaller and it is innacurate
isGrounded = Physics2D.OverlapArea (groundPoint_right.position, groundPoint_left.position, groundMask);
Debug.Log (isGrounded);
if (Input.GetAxisRaw ("Horizontal") == 1) {
transform.localScale = new Vector3 (1 , 1 * transform.localScale.y, 1* transform.localScale.z);
} else if (Input.GetAxisRaw ("Horizontal") == -1) {
transform.localScale = new Vector3 (-1, 1* transform.localScale.y, 1* transform.localScale.z);
}
if(Input.GetKeyDown(KeyCode.Space) && isGrounded){
rb.AddForce (new Vector2 (0, jumpHeight));
}
}
void CheckDash(){
if(Input.GetKeyDown(KeyCode.W) && !dashing && Time.time > nextdashtime){
dashing = true;
StartCoroutine ("Dash");
}
}
IEnumerator Dash(){
//Before dash loop
rb.gravityScale = 0f;
float startDashTime = Time.time;
float endDashTime = startDashTime + dashDuration;
float currentDashTime;
//Dash Loop
while(Time.time < (startDashTime + dashDuration)){
currentDashTime = Time.time;
// The value to lerp by should be the % that time.time is between start time and end time
rb.velocity = new Vector2 (Mathf.Lerp (startDashSpeed, endDashSpeed, ((currentDashTime - startDashTime) / (endDashTime - startDashTime))),0f);
}
//When dash loop is complete
nextdashtime = Time.time + dashcooldown;
dashing = false;
rb.gravityScale = 1;
yield return null;
}
// FOR CHECKING GROUND CHECK LIMITS
/*void OnDrawGizmos(){
Gizmos.color = Color.red;
Gizmos.DrawLine (groundPoint_left.position, groundPoint_right.position);
}*/
}
You don't need all that for dashing !
If you use rigid bodies then the following code will do:
using UnityEngine;
public class CubeController : MonoBehaviour
{
private Rigidbody _rigidbody;
public float Force = 10;
private void Start()
{
_rigidbody = GetComponent<Rigidbody>();
}
private void FixedUpdate()
{
ForceMode? forceMode = null;
if (Input.GetKeyDown(KeyCode.W)) // normal
forceMode = ForceMode.Force;
else if (Input.GetKeyDown(KeyCode.S)) // dash
forceMode = ForceMode.Impulse;
if (forceMode.HasValue)
_rigidbody.AddRelativeForce(Vector3.forward*Force, forceMode.Value);
}
}
This is an example using 3D but you have the same for 2D : https://docs.unity3d.com/ScriptReference/Rigidbody2D.html
Steps:
add rigidbody component to your ground, set it as kinematic
add rigidbody component to your player
sketch the above component for your player using Rigidbody2D class
adjust the parameters as you'd like
you should have a simple and robust dashing by now :)
I forgot a yield return null within my while loop that stuck me in an infinite loop. Works fine now.
while(Time.time < (startDashTime + dashDuration)){
currentDashTime = Time.time;
// The value to lerp by should be the % that time.time is between start time and end time
rb.velocity = new Vector2 (Mathf.Lerp (startDashSpeed, endDashSpeed, ((currentDashTime - startDashTime) / (endDashTime - startDashTime))),0f);
yield return null;
}

Categories