Call function with UI buttons instead of using keyboard buttons - c#

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

Related

Sprite not Appearing in Unity 2D Game

I'm creating a 2D Top Down game for practice and I need a little bit of help. For context, it's a 2D Top Down Shooter game, where you can move and shoot enemies. The enemies have a basic radius system where if the player gets within the radius, it'll approach the player.
Now I'm making a game mechanic where the player can hide in a cardboard box, the player can press 'E' and he'll suddenly become a cardboard box, where if the player is in the cardboard box, the enemy doesn't detect him even if the player's within the radius. Yes, just like in Metal Gear. Now I've created the prefabs and everything and functionality-wise, it works perfectly. If you press 'E' the enemy cannot detect you.
Now the small problem is that the cardboard box didn't appear, so it's just the player disappearing entirely. I do not know what caused this problem.
For context, these are my scripts. Feel free to read them, or not :)
PlayerController:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerController : MonoBehaviour
{
public float moveSpeed;
public GameObject bulletPrefab;
public GameObject player;
private Rigidbody2D rb2d;
private Vector2 moveDirection;
[SerializeField] private Camera cam;
[SerializeField] private GameObject gunPoint;
public bool isHiding = false;
[SerializeField] private GameObject cardboardBox;
[SerializeField] private GameObject gunSprite;
// Start is called before the first frame update
void Start()
{
rb2d = GetComponent<Rigidbody2D>();
cardboardBox.SetActive(false); // Hide the cardboard box when the game starts
gunSprite.SetActive(true); // Show the gun sprite when the game starts
}
// Update is called once per frame
void Update()
{
CheckCursor();
ProcessInputs();
// Make the camera follow the player
cam.transform.position = new Vector3(player.transform.position.x, player.transform.position.y, cam.transform.position.z);
// Check if player pressed the "E" key to toggle the cardboard box
if (Input.GetKeyDown(KeyCode.E))
{
isHiding = !isHiding; // Toggle the isHiding variable
cardboardBox.SetActive(isHiding); // Show/hide the cardboard box accordingly
// If player is hiding, stop player movement
if (isHiding)
{
moveDirection = Vector2.zero;
player.GetComponent<SpriteRenderer>().enabled = false;
cardboardBox.GetComponent<SpriteRenderer>().enabled = true;
gunSprite.SetActive(false); // Hide the gun sprite when the player is hiding
}
else
{
player.GetComponent<SpriteRenderer>().enabled = true;
cardboardBox.GetComponent<SpriteRenderer>().enabled = false;
gunSprite.SetActive(true); // Show the gun sprite when the player is not hiding
}
}
}
private void FixedUpdate()
{
if (!isHiding) // Only allow player to move if they are not hiding in the cardboard box
{
Movement();
}
}
private void CheckCursor()
{
Vector3 mousePos = cam.ScreenToWorldPoint(Input.mousePosition);
Vector3 characterPos = transform.position;
if (mousePos.x > characterPos.x)
{
this.transform.rotation = new Quaternion(0, 0, 0, 0);
}
else if (mousePos.x < characterPos.x)
{
this.transform.rotation = new Quaternion(0, 180, 0, 0);
}
}
private void Movement()
{
// TODO : Implementasi movement player
rb2d.velocity = new Vector2(moveDirection.x * moveSpeed, moveDirection.y * moveSpeed);
}
private void ProcessInputs()
{
float moveX = Input.GetAxisRaw("Horizontal");
float moveY = Input.GetAxisRaw("Vertical");
moveDirection = new Vector2(moveX, moveY);
if (Input.GetMouseButtonDown(0))
{
Shoot();
}
}
private void Shoot()
{
Vector3 mousePos = cam.ScreenToWorldPoint(Input.mousePosition);
Vector3 gunPointPos = gunPoint.transform.position;
Vector3 direction = (mousePos - gunPointPos).normalized;
GameObject bullet = Instantiate(bulletPrefab, gunPointPos, Quaternion.identity);
bullet.GetComponent<Bullet>().Init(direction);
}
}
EnemyController script:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class EnemyController : MonoBehaviour
{
public Transform player;
public float moveSpeed = 5f;
public float detectionRadius = 5f;
public int maxHealth = 1;
private int currentHealth;
private Rigidbody2D rb2d;
private Vector2 movement;
private void Start()
{
rb2d = this.GetComponent<Rigidbody2D>();
currentHealth = maxHealth;
}
private void Update()
{
float distanceToPlayer = Vector2.Distance(transform.position, player.position);
if (player != null && distanceToPlayer <= detectionRadius && !player.GetComponent<PlayerController>().isHiding)
{
Vector3 direction = player.position - transform.position;
float angle = Mathf.Atan2(direction.y, direction.x) * Mathf.Rad2Deg;
rb2d.rotation = angle;
direction.Normalize();
movement = direction;
}
else
{
movement = Vector2.zero;
}
}
void FixedUpdate()
{
moveCharacter(movement);
}
private void moveCharacter(Vector2 direction)
{
rb2d.MovePosition((Vector2)transform.position + (direction * moveSpeed * Time.deltaTime));
}
public void DestroyEnemy()
{
Destroy(gameObject);
}
}
Bullet script:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Bullet : MonoBehaviour
{
// Start is called before the first frame update
[SerializeField] private float speed;
[SerializeField] private Vector3 direction;
public void Init(Vector3 direction)
{
this.direction = direction;
this.transform.SetParent(null);
transform.rotation = Quaternion.Euler(0, 0, Mathf.Atan2(direction.y, direction.x) * Mathf.Rad2Deg);
}
// Update is called once per frame
void Update()
{
this.transform.position += transform.right * speed * Time.deltaTime;
}
// TODO : Implementasi behaviour bullet jika mengenai wall atau enemy
private void OnTriggerEnter2D(Collider2D other)
{
switch(other.gameObject.tag)
{
case "Wall":
Destroy(gameObject);
break;
case "Enemy":
Destroy(gameObject);
other.gameObject.GetComponent<EnemyController>().DestroyEnemy();
break;
}
}
}
I've tried tinkering my scripts, I've tried checking if there are any missing components in the cardboard box game object but to no avail. Although I might be wrong on the Unity part since I'm fairly certain that the script isn't the problem here, again might be wrong.
I appreciate all the help I can get, thank you for reading until here

System Inputs - How to make my game object jump?

I'm making a simple platformer with a rolling ball that rolls around and collects coins to win each level. I'm using Unity's System input from Unity's package manager to help me with controls and key binding and have successfully gotten my ball to roll around with ease and collect coins with a nice UI setup. However, I would like to implement harder levels where the ball jumps. I can not figure out how to make the ball jump. I know there are others ways to go about this but I just can't figure out how to make it work in the system inputs.
(I know an if statement is needed to test if the ball is grounded however again I'm new and still learning)
Gameplay | OnJump in player input is for jumping | KeyBindings
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.InputSystem;
using TMPro;
public class PlayerController: MonoBehaviour
{
public float speed = 0;
public bool isGrounded;
public float jumpForce;
public TextMeshProUGUI countText;
public GameObject winTextObject;
private Rigidbody rb;
private int count;
private float movementX;
private float movementY;
// Start is called before the first frame update
void Start()
{
rb = GetComponent<Rigidbody>();
SetCountText();
winTextObject.SetActive(false);
}
private void OnMove(InputValue movementValue)
{
Vector2 movementVector = movementValue.Get<Vector2>();
movementX = movementVector.x;
movementY = movementVector.y;
}
private void onJump(InputValue value)
{
}
void SetCountText()
{
countText.text = "Count: " + count.ToString();
if(count >= 12)
{
winTextObject.SetActive(true);
}
}
private void FixedUpdate()
{
Vector3 movement = new Vector3(movementX, 0.0f, movementY);
rb.AddForce(movement * speed);
}
private void OnTriggerEnter(Collider other)
{
if(other.gameObject.CompareTag("PickUp"))
{
other.gameObject.SetActive(false);
count = count + 1;
SetCountText();
}
}
}
Make sure you create a new tag called Ground and put it on everything you want your player to be able to jump on (the ground).
public float jumpHeight = 5f;
public bool isGrounded;
void Update()
{
if (isGrounded)//Checks if is on ground
{
if (Input.GetButtonDown("Jump"))//If the space is pressed
{
rb.AddForce(Vector3.up * jumpHeight)
}
}
}
void OnCollisionEnter(Collision other)//If touch other object
{
if (other.gameObject.tag == "Ground")//If other object has Ground tag
{
isGrounded = true;
}
}
void OnCollisionExit(Collision other)
{
if (other.gameObject.tag == "Ground")
{
isGrounded = false;
}
}
You can also do if (Input.GetButtonDown("Jump")) as
if (Input.GetKeyDown("space"))
or
if (Input.GetKeyDown(KeyCode.Space))

Object not touching ground when moving platform is falling in Unity

I'm using Unity to make my character jump from a moving platform where it goes up & down infinitely. The problem I'm facing is when the moving platform goes up, the jump is working perfectly but when the platform is going down, my character can't jump most often & I can see the platform is "vibrating" a bit which is weird.
Here are my codes:
Moving Platform Script [NB - Rigidbody2D is set to Kinematic]
public class Moveground : MonoBehaviour
{
[SerializeField] private Transform posTop, posBot;
private float maxTop = -0.5f;
private float maxBot = -5.0f;
[SerializeField] private float speed;
[SerializeField] private Transform startPos;
private Vector2 nextPos;
private void Start()
{
nextPos = startPos.position;
}
private void FixedUpdate()
{
if (transform.position == posTop.position)
{
nextPos = posBot.position;
}
if (transform.position == posBot.position)
{
nextPos = posTop.position;
}
transform.position = Vector2.MoveTowards(transform.position, nextPos, speed*Time.deltaTime);
}
}
PlayerController.cs (Only Jump part)
[SerializeField] private LayerMask ground;
private Collider2D coll;
private void Start()
{
coll = GetComponent<Collider2D>();
}
private void Update()
{
InputManager();
}
private void InputManager()
{
if (Input.GetButtonDown("Jump") && coll.IsTouchingLayers(ground)) // Moving Platform's layer is also "ground"
{
Jump();
}
}
private void Jump() {
rb.velocity = new Vector2(rb.velocity.x, jumpforce); // jumpforce is a float number
}
How can I resolve this issue? I'm new to Unity.
Instead of "IsTouchingLayers" try something like this in the PlayerController class:
public bool IsGrounded()
{
return Physics2D.Raycast(transform.position, Vector3.down, 0.1f, ground);
}
and play around with the distance argument, which is the 0.1f one.
If your player transform is not at the bottom of the player, you can also put in something like this instead of 0.1f:
coll.bounds.extents.y + 0.1f

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

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();
}

Move player on touch Unity C#

I created a simple script to move player on Keyboard input, though now I want to move player on touch input, how do I do this ?
Here's my code, so how do I edit this code to make it work ? I have jump working, but dunno how to do it for moving ?
using UnityEngine;
using System.Collections;
public class MoveGround : MonoBehaviour
{
public float y = 0f;
public Rigidbody2D rb;
//public float x = 0f;
//public float z = 0f;
// Use this for initialization
void Start()
{
rb = GetComponent<Rigidbody2D>();
}
// Update is called once per frame
void Update()
{
//move function
if (Input.GetKey(KeyCode.W))
{
rb.velocity = new Vector2(0, y);
}
if (!Input.GetKey(KeyCode.W))
{
rb.velocity = new Vector2(0, 0);
}
if (Input.GetKey(KeyCode.S))
{
rb.velocity = new Vector2(0, -y);
}
//move function end
}
public void Move()
{
}
}
How do you want to move your character using touch input instead of keyboard input? Your current code moves the character depending on whether the "W" or "S" keys are being pushed.
You could make two UI buttons that correspond to "forward" and "backward" keys.
Add an Event Trigger component to those buttons. Add two event types to the buttons: "Pointer Down" and "Pointer Up."
Add a function to the list of each of those events.
Put this code onto an object in your scene.
bool movingForward;
bool movingBackward;
public float speed = 0f;// set this either here in code or in the editor
public Rigidbody2D rb;
void Start (){
rb = GetComponent<Rigidbody2D>();
movingForward = false;
movingBackward = false;
}
// Your forward button will call this function
public void moveForward (){
movingForward = true;
movingBackward = false;
}
// Your backwardbutton will call this function
public void moveBackward (){
movingForward = false;
movingBackward = true;
}
//
public void stopMoving(){
movingForward = false;
movingBackward = false;
}
void Update () {
if(movingForward || movingBackward ){// we're moving
if(movingForward ){// forward
rb.velocity = new Vector2(0, speed);
}else if(movingBackward ){// backward
rb.velocity = new Vector2(0, -speed);
}
}else{// we're moving neither forward nor backward
rb.velocity = new Vector2(0, 0);// so stand still
}
}
Point each function to that object. In the Pointer Down event, choose the "moveForward" function for the button you want to move your character forward, and the "moveBackward" function for the other button.
In the Pointer Up event for both, just choose the "stopMoving" function.
It's really simplistic, but it will work.
I agree with #PolakięGames. The best way to do it is creating two UI buttons with EventTriggers attached and assigning the methods MoveForward and MoveBackwards to PointerDown and StopMoving to PointerDown. Although I would implement it differently:
using UnityEngine;
[RequireComponent(typeof(Rigidbody))]
public class MoveExample : MonoBehaviour {
public float Acceleration = 4f;
public float Speed = 4f;
private Vector2 _velocity = Vector2.zero;
private Rigidbody _rigidbody;
private void Start() {
_rigidbody = GetComponent<Rigidbody>();
}
// movement methods
public void Move(float velocity) { _velocity.x = velocity * Speed; }
public void MoveForward() { Move(1f); }
public void MoveBackwards() { Move(-1f); }
public void StopMoving() { Move(0f); }
private void Update() {
_rigidbody.velocity = Vector2.Lerp(_rigidbody.velocity, _velocity, Time.deltaTime * Acceleration);
}
}
That way your object will move smootly and you can control the speed and acceleration. You have to change Rigidbody to Rigidbody2D if you intend to use it with 2D Physics.

Categories