-1
\$\begingroup\$

I have player and walls. When the player hits the wall, its not moving.

This is the code for moving:

void MoveTileBased()
{
    transform.position = Vector3.MoveTowards(
       transform.position, 
       destination, 
       Time.deltaTime * speed);

    if (Input.GetKeyDown(KeyCode.W))
    {
        nextPos = Vector3.forward;
    }

    if (Input.GetKeyDown(KeyCode.S))
    {
        nextPos = Vector3.back;
    }

    if (Input.GetKeyDown(KeyCode.A))
    {
        nextPos = Vector3.left;
    }

    if (Input.GetKeyDown(KeyCode.D))
    {
        nextPos = Vector3.right;
    }

    if(Vector3.Distance(destination, transform.position) < 0.01f)
    {
        destination = transform.position + nextPos;
    }
}

This is collision script:

private void OnCollisionEnter(Collision collision)
{
    player.speed = 0f;
}

Walls collider:

enter image description here

Player rigidbody and collider:

enter image description here

\$\endgroup\$
1
  • 2
    \$\begingroup\$ If someone tries to improve the readability of your code, then you should probably not revert their edits as a more-readable post increases the chances of others actually reading it and helping you. \$\endgroup\$
    – Vaillancourt
    Jun 23, 2021 at 18:48

3 Answers 3

2
\$\begingroup\$

When the player hits (enters the collider of) the wall, does the speed == 0 and does the player stop moving?

If this is the case, then the problem is that you're setting the player speed to 0 if they're in the wall, but because their speed is now 0 there's no way for them to escape the wall.

Solutions

There's many ways you could go about solving this, here are some options.

Unity Physics System

The simplest and probably most robust solution, unless you have very specific needs or need a lot of control, is just to use Unity's Physics system. You would add physics colliders to the walls and player (along with corresponding rigidbodies). In your code, you would replace all instances of transform.position = target with myRigidBody.MovePosition(target).

Vector3 target = Vector3.MoveTowards(transform.position, destination, Time.deltaTime * speed);

//instead of this
//transform.position = target;

//use this
myPlayerRigidBody.MovePosition = target 

RigidBody.MovePosition(Vector3 v) will automatically resolve collisions for you, so rigidbodies will never overlap. You could also just change the rigidbody's velocity, instead of using your own speed variable, but then you would have less control over the movement.

Custom

The other solution(s), is to perform your own intersection/resolution logic. This can be done in countless ways, with varying levels of robustness and complexity (eventually you could end up creating your own custom Physics system).

The minimum viable behavior I'd start with, would be preemptively check if a destination or target is within a wall (this could be achieved using Physics.OverlapSphere): if it is overlapping, don't move that frame and set your speed to 0; if there is no overlap, then move to the destination and keep whatever speed you have.

This is a huge topic though, and the complexity will vary with what type of movement (3D/2D) and colliders you want to support.

\$\endgroup\$
8
  • \$\begingroup\$ Yes. This is the problem. But ıdk how to deal with that @Charly \$\endgroup\$
    – Apoleytaa
    Jun 23, 2021 at 16:44
  • \$\begingroup\$ (great, I'll offer a couple of solutions within the hour) \$\endgroup\$
    – Charly
    Jun 23, 2021 at 16:45
  • \$\begingroup\$ Really thanks. It would be very awesome @Charly \$\endgroup\$
    – Apoleytaa
    Jun 23, 2021 at 16:46
  • \$\begingroup\$ Btw. I'm adding collision script because player is vibrating when it hits the wall. Of you have any other solution to not vibrate after collision ıt's fine by me @Charly \$\endgroup\$
    – Apoleytaa
    Jun 23, 2021 at 16:57
  • \$\begingroup\$ Thanks for you answer. I wıll try to implement Physics system. But there is one problem about that. The player should move grid to grid in the game. It shouldn't move between grids I mean For example when I press another direction button when it moves to a direction, it shouldn't change its direction immediately. It should finish the tile it's in and then should start moving. It should never stay between grids. And the other thing is I don't have "target" variable in my script. Did you mean "destination" ? @Charly \$\endgroup\$
    – Apoleytaa
    Jun 23, 2021 at 21:16
1
\$\begingroup\$

Here you go my dude.

public float speed;
[SerializeField]
private Vector3 nextPos;
[SerializeField]
private Vector3 destination;
[SerializeField]
private KeyCode lastKey;
[SerializeField]
private KeyCode preventKey = KeyCode.None;


private void Update()
{
    MoveTileBased();   
}

void MoveTileBased()
{
    KeyCode[] keycodes = new KeyCode[] { KeyCode.W, KeyCode.A, KeyCode.S, KeyCode.D };

    if (Input.GetKeyDown(KeyCode.W))
        nextPos = Vector3.forward;
    if (Input.GetKeyDown(KeyCode.S))
        nextPos = Vector3.back;
    if (Input.GetKeyDown(KeyCode.A))
        nextPos = Vector3.left;
    if (Input.GetKeyDown(KeyCode.D))
        nextPos = Vector3.right;

    for (int i = 0; i < keycodes.Length; i++)
    {
        if (Input.GetKeyDown(keycodes[i]))
        {
            if (keycodes[i] != preventKey)
            {
                preventKey = KeyCode.None;

                Debug.Log("Pressed " + keycodes[i]);
                lastKey = keycodes[i];
                destination = transform.position + nextPos;
                StartCoroutine(MoveFromTo(this.transform, transform.position, destination, speed));
            }
        }
    }
}

IEnumerator MoveFromTo(Transform objectToMove, Vector3 a, Vector3 b, float speed)
{
    float step = (speed / (a - b).magnitude) * Time.fixedDeltaTime;
    float t = 0;
    while (t <= 1.0f)
    {
        t += step; // Goes from 0 to 1, incrementing by step each time
        objectToMove.position = Vector3.Lerp(a, b, t); // Move objectToMove closer to b
        yield return new WaitForFixedUpdate();         // Leave the routine and return here in the next frame
    }
    objectToMove.position = b;
}

private void OnCollisionEnter(Collision collision)
{
    Debug.Log("Collision!");
    preventKey = lastKey;
    StopAllCoroutines();
}
\$\endgroup\$
2
  • \$\begingroup\$ known issue, it will get confused if last key was not directly toward wall (ie around corners) \$\endgroup\$ Jun 23, 2021 at 18:40
  • \$\begingroup\$ Thanks. But ıts kind of confusing. I'm gonna give it a try \$\endgroup\$
    – Apoleytaa
    Jun 23, 2021 at 21:18
0
\$\begingroup\$

I don't really have enough information to help, but here are some tips to try

  1. You might try reorganizing this method into a coroutine

  2. If it is a collider issue, try replacing the box collider with an edge collider

  3. You might try assigning physics materials

  4. How are you calling the "MoveTileBased" Method? If it is not being called in the update function, it won't register.

  5. Is the missing script on "Left Wall" Important at all?

Last thing... Why not just use rigidbodies and add force instead?

\$\endgroup\$
1
  • \$\begingroup\$ First of all thx for answer. 1) I think coroutine is not relevant 2) It doesn't matter edge or box collider because main problem is that player always touching the wall and speed is always being 0. 3) I dont want to move object with rigidbody 4) İts in update 5) No, its not important \$\endgroup\$
    – Apoleytaa
    Jun 23, 2021 at 16:33

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .