Unity - character starts to fly up when there should be gravity - c#

I am developing a 2D platform game, where the character is a ball and should be able to move right and left, and to jump. It now does all that, but for some reason which i do not understand (as i am complitely new to Unity) sometimes it flies up like if the gravity was negative.
Here is the code of my first script Move2D:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Move2D : MonoBehaviour
{
public float moveSpeed = 5f;
public bool isGrounded = false;
[SerializeField] private Rigidbody2D rigidbody;
private Vector2 currentMoveDirection;
private void Awake()
{
rigidbody = GetComponent<Rigidbody2D>();
currentMoveDirection = Vector2.zero;
}
public void Jump()
{
if (isGrounded)
{
rigidbody.AddForce(new Vector3(0f, 5f), ForceMode2D.Impulse);
}
}
private void FixedUpdate()
{
rigidbody.velocity = (currentMoveDirection + new Vector2(0f, rigidbody.velocity.y)).normalized * moveSpeed;
}
public void TriggerMoveLeft()
{
currentMoveDirection += Vector2.left;
}
public void StopMoveLeft()
{
currentMoveDirection -= Vector2.left;
}
public void TriggerMoveRight()
{
currentMoveDirection += Vector2.right;
}
public void StopMoveRight()
{
currentMoveDirection -= Vector2.right;
}
}
And this is the code of the second script:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.EventSystems;
using UnityEngine.UI;
public class ContinuesButton : MonoBehaviour, IPointerDownHandler, IPointerUpHandler
{
[SerializeField] private Button targetButton;
[SerializeField] private Move2D playerMovement;
[SerializeField] private bool movesLeft;
private readonly bool isHover;
private void Awake()
{
if (!targetButton) targetButton = GetComponent<Button>();
}
public void OnPointerDown(PointerEventData eventData)
{
if (movesLeft)
{
playerMovement.TriggerMoveLeft();
} else
{
playerMovement.TriggerMoveRight();
}
}
public void OnPointerUp(PointerEventData eventData)
{
if (movesLeft)
{
playerMovement.StopMoveLeft();
} else
{
playerMovement.StopMoveRight();
}
}
}
I noticed that the ball starts to fly up as soon as the movement controller or some collider makes it go up a bit. For example when i make it jump, it just keeps going up, or when in the game i try to make it "walk" up a hill, it immediately starts flying up.
Any help or information is really appreciated, I really do not see the problem.

The issue I lies in normalized. This might unexpectedly increase the Y velocity. Especially in cases when you set the X velocity to 0 the Y component is taken into account to much.
I guess you should rather use something like
currentDirection * moveSpeed + Vector2.up * rigidbody.velocity.y;
In order to simply keep the current Y velocity.
Also be careful with these currentDirection += ...! I would suggest rather use single methods and use fixed values like e.g.
public void DoMove(bool right)
{
currentDirection = (right ? 1 : -1) * Vector2.right;
}
public void StopMove()
{
currentDirection = Vector2.zero;
}
And then rather call them like
public void OnPointerDown(PointerEventData eventData)
{
playerMovement.DoMove(!movesLeft);
}
public void OnPointerUp(PointerEventData eventData)
{
playerMovement.StopMove();
}

Related

My Bullet is not getting instantiated where my Player is. It is getting instantiated from center only

I am new to Unity & on Stackoverflow. Need your help as I am stuck in this below mentioned situation.
When I spawn my projectile(Bullet), It should be instantiated at player's current position but It's not getting changed. The bullet is getting generated from Center only(Not from Player's position). Please advise. image is for reference
SpawnobjectController Script
public class SpawnobjectController : MonoBehaviour
{
[SerializeField]
GameObject projectilereference;
[SerializeField]
GameObject enemyreference;
[SerializeField]
GameObject playerreference;
void Start()
{
StartCoroutine(Enemycoroutine());
StartCoroutine(ProjectileCoroutine());
}
void SpawnProjectile()
{
Instantiate(projectilereference, new Vector3(playerreference.transform.position.x,projectilereference.transform.position.y,0.0f), Quaternion.identity);
}
IEnumerator ProjectileCoroutine()
{
while (true)
{
SpawnProjectile();
yield return new WaitForSeconds(2.0f);
}
}
IEnumerator Enemycoroutine()
{
while (true) {
SpawnEnemy();
yield return new WaitForSeconds(1.0f);
}
}
void SpawnEnemy()
{
Instantiate(enemyreference, enemyreference.transform.position, Quaternion.identity);
}
}
PlayerController Scripts
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerController : MonoBehaviour
{
float _horizontalAxisPlayer;
float _playerSpeed = 5f;
float _maxXBoundry = 2.31f;
void Start()
{
}
void Update()
{
ControlPlayerBoundries();
PlayerMovement();
}
void PlayerMovement()
{
_horizontalAxisPlayer = Input.GetAxis("Horizontal")*_playerSpeed*Time.deltaTime;
transform.Translate(new Vector3(_horizontalAxisPlayer, 0.0f, 0.0f));
}
void ControlPlayerBoundries()
{
if (transform.position.x>_maxXBoundry)
{
transform.position = new Vector3(_maxXBoundry,transform.position.y,0.0f);
}
else if (transform.position.x<-_maxXBoundry)
{
transform.position = new Vector3(-_maxXBoundry, transform.position.y, 0.0f);
}
}
}
EnemyController
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class EnemyController : MonoBehaviour
{
[SerializeField]
private float enemeySpeed = 2f;
void Start()
{
}
void Update()
{
transform.Translate(Vector3.down * enemeySpeed * Time.deltaTime);
}
}
ProjectileController Script
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class ProjectileController : MonoBehaviour
{
[SerializeField]
private GameObject Playerref;
[SerializeField]
private float projectile_speed = 2f;
void Start()
{
}
void Update()
{
// print(Playerref.transform.position);
}
private void LateUpdate()
{
transform.Translate(new Vector3(transform.position.x, 0.5f) * projectile_speed * Time.deltaTime);
}
}
Your problem is likely in the script that translates your bullet.
As the code you shared does exactly what you want. Assuming we are in a front view.
I have verified this by using your script and a copy of the enemy script in place of a bullet that moves them in Vector3.Up direction.
Edit:
You are creating a new vector with the transforms x and 0,5f that gets added every frame.
You either set transform.position or use Translate but with a direction only.
Moves the transform in the direction and distance of translation.
transform.Translate(Vector3 translation)
The following line would work instead.
private void LateUpdate()
{
transform.Translate(Vector3.up * projectile_speed* Time.deltaTime);
}

C# Unity 2D Topdown Movement Script not working

I have been working on a unity project where the player controls a ship. I was following along with a tutorial and have made an input script and a movement script that are tied together with unity's event system. As far as I can tell my script and the script in the tutorial are the same, but the tutorial script functions and mine doesn't.
Script to get player input
using UnityEngine;
using System.Collections;
using System;
using UnityEngine.Events;
public class PlayerInput : MonoBehaviour
{
public UnityEvent<Vector2> OnBoatMovement = new UnityEvent<Vector2>();
public UnityEvent OnShoot = new UnityEvent();
void Update()
{
BoatMovement();
Shoot();
}
private void Shoot()
{
if(Input.GetKey(KeyCode.F))
{
OnShoot?.Invoke();
}
}
private void BoatMovement()
{
Vector2 movementVector = new Vector2(Input.GetAxis("Horizontal"), Input.GetAxis("Vertical"));
OnBoatMovement?.Invoke(movementVector.normalized);
}
}
Script to move player
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Events;
public class Movement : MonoBehaviour
{
public Rigidbody2D rb2d;
private Vector2 movementVector;
public float maxspeed = 10;
public float rotatespeed = 50;
private void Awake()
{
rb2d = GetComponent<Rigidbody2D>();
}
public void HandleShooting()
{
Debug.Log("Shooting");
}
public void Handlemovement(Vector2 movementVector)
{
this.movementVector = movementVector;
}
private void FixedUpdate()
{
rb2d.velocity = (Vector2)transform.up * movementVector.y * maxspeed * Time.deltaTime;
rb2d.MoveRotation(transform.rotation * Quaternion.Euler(0, 0, -movementVector.x * rotatespeed * Time.fixedDeltaTime));
}
}
Any help would be appreciated!
You need to attach your Handlers (HandleShooting and Handlemovement) to corresponding events. Easiest way would be to make events static in PlayerInput
public static UnityEvent<Vector2> OnBoatMovement = new UnityEvent<Vector2>();
public static UnityEvent OnShoot = new UnityEvent();
and attach corresponding handlers to them in Movement.Awake
private void Awake(){
rb2d = GetComponent<Rigidbody2D>();
PlayerInput.OnBoatMovement += Handlemovement;
PlayerInput.OnShoot += HandleShooting;
}
Also in PlayerInput.BoatMovement you should probably check
if(movementVector.sqrMagnitude > 0){
OnBoatMovement?.Invoke(movementVector.normalized);
}
Or else random shit may happen when trying to normalize Vector with magnitude 0 (I compare sqr magnitude to aviod calculating root which is never desired)

I am attempting to make a 2D platformer on Unity but my character keeps flying to side without any input from the controller

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.InputSystem;
public class Playerovement : MonoBehaviour
{
PlayerInputActions controls;
public CharacterController2D controller;
public float runSpeed = 40f;
float horizontalMove = 0f;
bool jump = false;
void Awake () {
controls = new PlayerInputActions();
controls.Control.Jump.performed += ctx => Jump();
controls.Control.Horizontal.performed += horizontalMove => Move();
}
void Jump() {
jump = true;
}
void Move() {
controller.Move(horizontalMove * Time.fixedDeltaTime, false, jump);
}
void OnEnable() {
controls.Control.Enable();
}
void OnDisable() {
controls.Control.Disable();
}
void FixedUpdate()
{
jump = false;
}
}
That is my code. The character controller is linked HERE (https://github.com/Brackeys/2D-Character-Controller/blob/master/CharacterController2D.cs). Please help as my character keeps flying away.

Having problems with "OnCollisionEnter2D" in Unity2D

I'm using this code:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;
public class CollisionPlayer : MonoBehaviour
{
public bool alreadyDied = false;
public GameObject player;
public float timeDeath;
public ParticleSystem particles;
public GameObject explosionGO;
private SpriteRenderer sr;
private BoxCollider2D bc;
private PlayerController walkScript;
void Start()
{
sr = GetComponent<SpriteRenderer>();
bc = GetComponent<BoxCollider2D>();
walkScript = GetComponent<PlayerController>();
}
void OnCollisionEnter2D (Collision2D collide)
{
if (collide.gameObject.CompareTag("Dead"))
{
Instantiate(particles, player.transform.position, Quaternion.identity);
Instantiate(explosionGO, player.transform.position, Quaternion.identity);
CinemachineShake.Instance.ShakeCamera(30f, .1f);
alreadyDied = true;
}
}
void Update()
{
if(alreadyDied == true)
{
timeDeath -= Time.deltaTime;
sr.enabled = false;
bc.enabled = false;
walkScript.enabled = false;
}
if(timeDeath <= 0)
{
SceneManager.LoadScene(SceneManager.GetActiveScene().buildIndex);
}
}
}
This is the bullet's code:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class LeftBulletScript : MonoBehaviour
{
// Start is called before the first frame update
public float speed;
public float destructionLeftTime;
public ParticleSystem particles;
private GameObject thisGameObject;
void Start()
{
thisGameObject = this.gameObject;
Destroy(gameObject, destructionLeftTime);
}
void Update()
{
transform.Translate(Vector2.left * speed * Time.deltaTime);
if(destructionLeftTime > 0.05f)
{
destructionLeftTime -= Time.deltaTime;
}
else
{
Instantiate(particles, thisGameObject.transform.position, Quaternion.identity);
}
}
}
This code should spawn some particles and a sound effect when the player gets hit by something with tag "Dead". But that does not happen. I have a box collider 2D on both the bullet (that should kill me) and the player. My Rigidbody2D is dynamic on the player with z freezed. The bullet does not have a rigidbody. I made sure that the bullet actually has the tag "Dead", spelled the exact same way as the way I wrote on the script. The weirdest thing is that I used this code on another game and nothing changed (just the name of a script). Both the player and the bullet are on the same layer. Anyone could tell me what could have happened?

Call function with UI buttons instead of using keyboard buttons

In my 2D Unity game i can control my character with arrow keys and the space bar. Because I want it to be playable on android phones, i would like to use UI buttons instead.
I have already created 3 UI buttons:
Move right;
Move left;
Jump.
I would like to make so that these three buttons would be able to do the same job as the keys do with the code i have now.
This is my Move2D script:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Move2D : MonoBehaviour
{
public float moveSpeed = 5f;
public bool isGrounded = false;
[SerializeField] private Rigidbody2D rigidbody;
// Update is called once per frame
void Update()
{
Jump();
Vector3 movement = new Vector3(Input.GetAxis("Horizontal"), 0f, 0f);
transform.position += movement * Time.deltaTime * moveSpeed;
}
private void Awake()
{
if (!rigidbody) rigidbody = GetComponent<Rigidbody2D>();
}
public void Jump()
{
if (isGrounded && Input.GetButtonDown("Jump"))
{
rigidbody.AddForce(new Vector3(0f, 5f), ForceMode2D.Impulse);
}
}
}
Note: (In this script there are some function calls to another one called Grounded that check if the character is touching the floor).
-
Any information or advice is really appreciated.
Assuming you have read the docs and know how to reference and configure UI.Button in general (otherwise watch the tutorial) you could do it like
public class Move2D : MonoBehaviour
{
public float moveSpeed = 5f;
public bool isGrounded = false;
[SerializeField] private Rigidbody2D rigidbody;
private void Awake()
{
if (!rigidbody) rigidbody = GetComponent<Rigidbody2D>();
}
// this one you simply reference to a normal button
// or you could also use a continues button to auto jump see below
public void Jump()
{
if (isGrounded)
{
rigidbody.AddForce(new Vector3(0f, 5f), ForceMode2D.Impulse);
}
}
private float movement;
// this you reference on the left and right button
public void Move(float value)
{
movement = value;
}
// AND AGAIN
// you should always use MovePosition for RIGIDBODIES as I already told you last time
private void FixedUpdate()
{
rigidbody.MovePosition(rigidbody.position + Vector2.right * movement * Time.deltaTime * moveSpeed);
}
}
Btw: In a 2D game you shouldn't use Vector3 but Vector2 for movement etc.
This one goes to your Buttons so you can extend them with a whilePressed callback:
public class ContinuesButton : MonoBehaviour, IPointerEnterHandler, IPointerExitHandler, IPointerDownHandler, IPointerUpHandler
{
[SerializeField] private Button button;
[SerializeField] private UnityEvent whilePressed;
private bool isHover;
private void Awake()
{
if(!button) button = GetComponent<Button>();
}
public void OnPointerDown(PointerEventData eventData)
{
StartCoroutine(WhilePressed());
}
public void OnPointerUp(PointerEventData eventData)
{
StopAllCoroutines();
}
public void OnPointerExit(PointerEventData eventData)
{
StopAllCoroutines();
}
private IEnumerator WhilePressed()
{
while(true)
{
whilePressed?.Invoke();
yield return null;
}
}
}
Put this on your left and right button and reference the Move method. To the one button pass e.g. -1 to the other button 1 - all via the Inspector.
More about the IPointerXYHandler can be found here
Note: Typed on smartphone so no waranty but I hope the idea gets clear

Categories