Describe the problem: So my player is stuck to the wall when he jumps and moves to the right side at the same time. Watch the video below to imagine it better.
Watch the video for better illustration: HERE
If there is anything to do with code, here is the PlayerMovement script:
public class PlayerMovement : MonoBehaviour
{
Vector2 vector2Move;
Rigidbody2D rb2D;
[SerializeField] float playerSpeed;
bool isGrounded;
Collider2D playerCollider;
float theCurrentGravityScale;
private void Awake()
{
rb2D = GetComponent<Rigidbody2D>();
playerCollider = GetComponent<Collider2D>();
}
void Start()
{
theCurrentGravityScale = rb2D.gravityScale;
}
void Update()
{
Run();
}
void OnJump(InputValue value)
{
if (playerCollider.IsTouchingLayers(LayerMask.GetMask("Ground")) && value.isPressed)
{
rb2D.velocity += new Vector2(0f, jumpForce);
animatorPlayer.SetBool("isIdling", false);
}
}
void OnMove(InputValue value)
{
vector2Move = value.Get<Vector2>();
}
void Run()
{
animatorPlayer.SetBool("isRunning", true);
Vector2 playerMovement = new Vector2(vector2Move.x * playerSpeed, rb2D.velocity.y);
rb2D.velocity = playerMovement;
}
private void OnCollisionEnter2D(Collision2D collision)
{
animatorPlayer.SetBool("isGrounded", true);
}
It seems to me like the player collider is getting stuck with the tilemap collider, you can create a new physics material 2D (Assets > Create > 2D > Physics Material 2D) and set the friction to 0
Then you need to assign the material to the Rigid Body of the player, how many colliders do you have on the player?
Related
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
my bird is colliding with the clouds but it only moves them and doesn't trigger it
my character
public float jumpForce = 5f;
public float gravity = -9.81f;
public GameObject gus;
public Transform rotation_checker;
public Transform chekced;
float velocity;
void Start()
{
}
// Update is called once per frame
void Update()
{
gameObject.transform.eulerAngles = new Vector2(0,0);
velocity += gravity * Time.deltaTime;
if (Input.GetKeyDown(KeyCode.W))
{
velocity = jumpForce;
}
rotation_checker.position = chekced.position;
transform.Translate(new Vector2(0, velocity) * Time.deltaTime);
}
private void OnTriggerExit2D(Collider2D collider)
{
Debug.Log(collider.gameObject);
if(collider.gameObject.name == "skybluscene")
{
Destroy(gameObject);
}
}
private void onCollisionEnter2D(Collision2D collision)
{
if (collision.gameObject.tag == "cloud")
{
Destroy(gameObject);
}
}
the cloud
float x = -4f;
void Start()
{
}
// Update is called once per frame
void Update()
{
gameObject.transform.Translate(new Vector2(x, 0) * Time.deltaTime);
}
void OnTriggerExit2D(Collider2D collider)
{
if ( collider.gameObject.tag == "scene")
{
Destroy(gameObject);
}
}
cloud works just fine, it destroys itself when it leaves the scene but bird doesn't destroy itself when it collides with the cloud
both bird and cloud have dynamic rigidbody2d and a collider
First of all: On your character script, your onCollisionEnter2D is misspelled. It needs to start with a capital letter.
Second: all your other methods use tags to identify what GameObject they collided with, but "skybluscene" (which also looks like a typo) is identified by its gameObject name.
Third: I'm not sure, but I find it odd that you're using both triggers and collisions in the same script.
public Rigidbody2D rb;
public Movement mv;
public GameObject shotPrefab;
public Transform FirePoint;
public int direction;
// Update is called once per frame
void Update()
{
Rigidbody2D rb =shotPrefab.GetComponent<Rigidbody2D>();
if(Input.GetKeyDown(KeyCode.Space))
{
Shoot();
}
rb.velocity = transform.up * speed*Time.deltaTime;
}
void Shoot()
{
Instantiate(shotPrefab, FirePoint.position, FirePoint.rotation);
}
This the code of shooting prefab bullet even though the prefab bullet spawns it does move at all I tried other other syntax such as transfrom.translate,rb.Addforce but still no result.
You must apply the force to the newly instantiated object, not the prefab.
void Update() {
if (Input.GetKeyDown(KeyCode.Space)) {
Shoot();
}
}
void Shoot() {
GameObject shot = Instantiate(shotPrefab, FirePoint.position, FirePoint.rotation);
Rigidbody2D rb = shot.GetComponent<Rigidbody2D>();
rb.AddForce(transform.up * speed, ForceMode2D.Impulse);
}
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
I just started using Unity am trying to make a simple 3D platformer, before I can get to that, I need to get movement down. My problem comes in when the player jumps. When they jump, they can jump in the air as much as they want. I want it to only jump once. Can anybody help?
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Playermovement : MonoBehaviour
{
public Rigidbody rb;
void Start ()
}
void Update()
{
bool player_jump = Input.GetButtonDown("DefaultJump");
if (player_jump)
{
rb.AddForce(Vector3.up * 365f);
}
}
}
}
You can use a flag to detect when the player is touching the ground then only jump the player is touching the floor. This can be set to true and false in the OnCollisionEnter and OnCollisionExit functions.
Create a tag named "Ground" and make the GameObjects use this tag then attach the modified code below to the player that is doing the jumping.
private Rigidbody rb;
bool isGrounded = true;
public float jumpForce = 20f;
void Start()
{
rb = GetComponent<Rigidbody>();
}
private void Update()
{
bool player_jump = Input.GetButtonDown("DefaultJump");
if (player_jump && isGrounded)
{
rb.AddForce(Vector3.up * jumpForce);
}
}
void OnCollisionEnter(Collision collision)
{
if (collision.gameObject.CompareTag("Ground"))
{
isGrounded = true;
}
}
void OnCollisionExit(Collision collision)
{
if (collision.gameObject.CompareTag("Ground"))
{
isGrounded = false;
}
}
Sometimes, using OnCollisionEnter and OnCollisionExit may not be fast enough. This is rare but possible. If you run into this then use Raycast with Physics.Raycast to detect the floor. Make sure to throw the ray to the "Ground" layer only.
private Rigidbody rb;
public float jumpForce = 20f;
void Start()
{
rb = GetComponent<Rigidbody>();
}
private void Update()
{
bool player_jump = Input.GetButtonDown("DefaultJump");
if (player_jump && IsGrounded())
{
rb.AddForce(Vector3.up * jumpForce);
}
}
bool IsGrounded()
{
RaycastHit hit;
float raycastDistance = 10;
//Raycast to to the floor objects only
int mask = 1 << LayerMask.NameToLayer("Ground");
//Raycast downwards
if (Physics.Raycast(transform.position, Vector3.down, out hit,
raycastDistance, mask))
{
return true;
}
return false;
}