- Home /
The question is answered, right answer was accepted
Push only 1 box around at a time (2D)
Hi all
I am in the proces of learning 2D development in unity, and therefore I am creating a Sokoban game, where the player needs to push blocks/boxes around a game level.
I am using a 2D box collider and Rigidbody2D, to push my boxes around. The box is stopping fine when it is pushed into a wall, but when it is pushed into another box, then the new box also begins move away, when it collides with the pushing box.
I can try eloborate it further.
Player moves into a box, and the box is starting to move away from the player (the push effect)
The box is pushed into another box
The other box is now also pushed away, so the player is now pushing 2 boxes at the same time.
It's here the problem is, since the player may only push one box at a time.
Please help me with how I can achieve that effect.
Answer by acorrow · Apr 22, 2015 at 08:25 PM
Can you just make them Kinematic and only "awake" them when teh player is colliding/touching them? Something like this... Just have it set it back on the CollisionExit2D event as well...
private Rigidbody2D body;
void Start()
{
body = GetComponent<Rigidbody2D> ();
}
void OnCollisionEnter2D(Collision2D coll) {
if (coll.gameObject.tag == "Player")
body.isKinematic = false;
}
Hope that Helps!
Adam
When I try to do that, the OnCollisionExit2D() method is executing directly after the player has collided, and not when he is moving away, so the box is not moving at all... How can I solve that, is it something with the box colliders?
No nothing wrong with them. You said push not pull ;) $$anonymous$$oving away would be pulling. In that case you may want to try a different approach, possibly parenting the box to the player transform, or something to that effect.
$$anonymous$$hh.. I am not sure I understand what you mean... What I mean by pushing is like the logic in this video - https://www.youtube.com/watch?v=TgWibgp2Nw$$anonymous$$
Ok I see what you mean.
Colliders may not be what you want to use here. Try ins$$anonymous$$d using Raycasting to deter$$anonymous$$e where you are in relation to the crate/box to "activate" it (set is kinematic = false) and allow your characters rigidbody to move it once close enough.
So for example, you will want to do a very similar thing to using OnCollisionEnter2D, but just cast a ray and see if that hit:
RaycastHit2D hit = Physics2D.Raycast(frontOf$$anonymous$$yCharacter.transform.position, directionToCastRay, distanceToCastRay, Layer$$anonymous$$askOfWhatToCollideWith);
if (hit)//you hit your crate object
{
hit.rigidbody.is$$anonymous$$inematic = false;
}
This casts a ray, for however long you want, in a direction, and if it collides with the box, sets the box to be not kinematic.
Or you could do the opposite and have the crate raycast on all 4 sides "looking" for the player so that you can make it not kinematic.
Hope that Helps!
Adam
Thank you, I got it working now. I have made my code like this, which is attached to each of the boxes
using UnityEngine;
using System.Collections;
public class BoxCollisionScript : $$anonymous$$onoBehaviour {
//public float movementSpeed = 1.5f;
private Rigidbody2D rb2D;
// Use this for initialization
void Start () {
rb2D = GetComponent<Rigidbody2D>();
}
// Update is called once per frame
void Update () {
CheckForPlayerHit();
}
//Check if the player is hitting a box, from one of its four sides. Set the box is kinematic to false, if player hits.
void CheckForPlayerHit() {
RaycastHit2D hitUp = Physics2D.Raycast (transform.position + new Vector3(0.0f, 0.7f, 0.0f), Vector2.up);
RaycastHit2D hitDown = Physics2D.Raycast (transform.position + new Vector3(0.0f, -0.7f, 0.0f), -Vector2.up);
RaycastHit2D hitRight = Physics2D.Raycast (transform.position + new Vector3(0.7f, 0.0f, 0.0f), Vector2.right);
RaycastHit2D hitLeft = Physics2D.Raycast (transform.position + new Vector3(-0.7f, 0.0f, 0.0f), -Vector2.right);
if (hitUp.collider.gameObject.tag == "Player" || hitDown.collider.gameObject.tag == "Player" ||
hitRight.collider.gameObject.tag == "Player" || hitLeft.collider.gameObject.tag == "Player")
{
rb2D.is$$anonymous$$inematic = false;
}
else
{
rb2D.is$$anonymous$$inematic = true;
}
}
}
Follow this Question
Related Questions
2D box colliders not touching but are colliding, how to fix? 0 Answers
Sprite collision with Tilemap 2 Answers
How do you create complex collision geometry to match 2D sprites? 2 Answers
How do I check if/where in a sprite another sprite is? 0 Answers
Changing sprites from spritesheet on collision. What am I doing wrong? 1 Answer