Character Controller moves at constant speed - need it to stop when collision occurs

When you press a key, the character moves forward at a constant speed, however, when you hit a wall, the Debug.Log message appears, but canMove = false never completes, the Debug.Log message just keeps incrementing, I’m obviously doing something completely stupid here, I just want my character controller to stop when it hits a wall, and then wait for the next keypress ( when I add in alternate directions ) ?

Here is my code so far : -

using UnityEngine;
using System.Collections;

[RequireComponent(typeof(CharacterController))]

public class NPlayMove : MonoBehaviour {

    [Header("Can Player Move ?")]
    public bool canMove = false;

    const float constantMotion = 1;

    private CharacterController controller;
    private float gravity = 9.8f;

    public void Start () {
        controller = GetComponent<CharacterController>();
    }

    public void Update () {
        if (Input.GetKeyDown (KeyCode.UpArrow) || (canMove == true)) {
            Vector3 moveDirection = new Vector3(0, 0, constantMotion);
            moveDirection.y -= gravity * Time.deltaTime;

            controller.Move(moveDirection * Time.deltaTime); // Move character in moveDirection
            canMove = true;
        }
    }

    void OnControllerColliderHit ( ControllerColliderHit hit) {
        if (hit.collider.tag == "Wall") {
            Debug.Log ("Hit Wall");
            canMove = false;
        }
    }
}

You have an “or” in your Update, it should be an “and”.

Thanks, I was using || ( or ) because I was implementing someone’s else code from a similar questions asked, changing it to && ( and ) breaks the script, because now it no longer moves forward at a constant rate, just sits there ? :face_with_spiral_eyes:

You have to make the variable canMove = true; at the start. It’s set to false, so nothing happens.

yes, same, even with that set to True. Still only sits there, I can move it tiny fractional amounts if I keep pressing the upArrow, I should be able to press the upArrow once and then have it move forward at a constant speed. This isn’t happening.

Post your reworked code. If it’s falling with an “or”, then it will fall with an “and” if it is true, because the falling code is working.

Not much has changed in the code, it has nothing to do with falling, it should move FORWARD at a constant rate after pressing the UPARROW once, UNTIL it hits a BARRIER, then STOP, it doesn’t…

The code logic seems to be at fault here.

using UnityEngine;
using System.Collections;

[RequireComponent(typeof(CharacterController))]

public class NPlayMove : MonoBehaviour {

    [Header("Can Player Move ?")]
    public bool canMove = true;

    const float constantMotion = 1;

    private CharacterController controller;
    private float gravity = 9.8f;

    public void Start () {
        controller = GetComponent<CharacterController>();
    }

    public void Update () {
        if (Input.GetKeyDown (KeyCode.UpArrow) && (canMove == true)) {
            Vector3 moveDirection = new Vector3(0, 0, constantMotion);
            moveDirection.y -= gravity * Time.deltaTime;

            controller.Move(moveDirection * Time.deltaTime); // Move character in moveDirection
            canMove = true;
        }
    }

    void OnControllerColliderHit ( ControllerColliderHit hit) {
        if (hit.collider.tag == "Wall") {
            Debug.Log ("Hit Wall");
            canMove = false;
        }
    }
}

Make canMove a private, or check the editor to see if it’s set to false because the editor overrides. Either that or the collider is setting it false. If it’s true, it will keep moving. It did with the or and it’s logically the same if it’s true. It’s just a true/false that makes it run the rest of the code.

Thanks for all the help, I’ll keep digging away at this, and post back if I fix it, not likely though, I’ve think I’ve went through every possible way of moving an object forward at a constant rate and then having it collide and stop in the way I want, without just about every technique Unity provides failing in every situation because of collision or physics interactions. It’s quite maddening. :rage:

No, it’s because you are using GetKeyDown. That only fires once and is reset. You have to use GetKey

The or was actually bypassing the input, so it didn’t matter. Don’t give up so easy. Eventually, you figure it out.

1 Like

I know, I’ve been digging at this for about a week now…

using GetKey means I have to keep the button pressed down, kind of defeats the purpose of being able to press only once and have the player move forward until it hits a wall. This is actually a secondary thing I’m looking into, because I was having so much difficulty in my 3d sokoban like concept mockup, thread here that showcases some of the crap I’ve been dealing with :

Ok, then you do need the or and the false. I see that. I thought you were holding down the key. That actually should have worked that way with keydown. I have to think on it a bit.
It did say “hit wall” in the console?

Yeah, the code logically works that way. For collision you need it to have a rigid body. I set it to is Kinematic, and turned off use gravity. I used a trigger, but shouldn’t matter.

Yes, it was showcasing the “Hit Wall” in the console, anyway…

Sometime later…

In the interim, I went back to one of the original methods I was trying out using Rigidbody, and reworked my collision code, and I’ve managed to figure out something workable ! yay !! :smile:

One keypress, constant motion ( kind of, velocity based ), stops at wall, transform values are rounded up. Disabled user input when in motion, lovely …

Now to fix the sokoban code from the other thread !

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class playerMove : MonoBehaviour {

    [Header("Player Properties")]
    public Rigidbody playerRigidbody;
    public int playerSpeed = 20;

    private bool canMove = true;

    void Start () {
        playerRigidbody = GetComponent<Rigidbody>();
    }

    void FixedUpdate () {

        if (Input.GetKeyDown (KeyCode.LeftArrow) && canMove == true){
            canMove = false;
            playerRigidbody.velocity = new Vector3(-playerSpeed, 0, 0);
        }
        if (Input.GetKeyDown (KeyCode.RightArrow) && canMove == true){
            canMove = false;
            playerRigidbody.velocity = new Vector3(playerSpeed, 0, 0);
        }
        if (Input.GetKeyDown (KeyCode.UpArrow) && canMove == true){
            canMove = false;
            playerRigidbody.velocity = new Vector3(0, 0, playerSpeed);
        }
        if (Input.GetKeyDown (KeyCode.DownArrow) && canMove == true){
            canMove = false;
            playerRigidbody.velocity = new Vector3(0, 0, -playerSpeed);
        }
    }

    void OnCollisionEnter (Collision collision)
    {
        if (collision.collider.tag == "Wall") {
            float x = transform.position.x;
            float y = transform.position.y;
            float z = transform.position.z;

            x = (int)x;
            z = (int)z;

            y = 0.5f;

            Vector3 away = new Vector3(x, y, z);
            playerRigidbody.position = away;

            canMove = true;
        }
    }
}

It’s good you got it working. It should have worked the way you had it. I don’t know why it didn’t, but it’s a good thing there are alternative ways to do things.

1 Like