0
votes

I'm working on a game right now (first 3D styled game), and I have a problem with my character colliding. I have a Player object, which has another object(s) as the real moveable characters (now I have only one). I have rigidbody and box collider too attached to my character. I have made a level (with hand-placed platforms), and I would like avoid my character of falling of the platforms, while the user control it. I have tried to place a cube on the side of the platform(s), with box collider attached to it, but the character not detect the colliding for some reasons. I would like my character to be stopped by the collider "cube", but it doesn't happen.

I use this script to move my object (attached to my character Player object) :

public class Bounce : MonoBehaviour {


float lerpTime;
float currentLerpTime;
float perc = 1;

Vector3 startPos;
Vector3 endPos;

bool firstInput;
public bool justJump;

public GameObject player;


// Update is called once per frame
void Update () {
    if (Input.GetButtonDown("up") || Input.GetButtonDown("down") || Input.GetButtonDown("left") || Input.GetButtonDown("right")) {
        if (perc == 1) {
            lerpTime = 1;
            currentLerpTime = 0;
            firstInput = true;
            justJump = true;
        }
    }
    startPos = gameObject.transform.position;


    if (Input.GetButtonDown("up") && gameObject.transform.position == endPos) {
        endPos = transform.position + player.transform.rotation * (new Vector3(0, 0, 1f));

    }
    if (Input.GetButtonDown("down") && gameObject.transform.position == endPos) {
        endPos = transform.position + player.transform.rotation * (new Vector3(0, 0, -1f));
    }

    if (firstInput == true) {
        currentLerpTime += Time.deltaTime * 5;
        perc = currentLerpTime / lerpTime;
        gameObject.transform.position = Vector3.Lerp(startPos, endPos, perc);
        if (perc > 0.8f)  {
            perc = 1;
        }

        if (Mathf.Round(perc) == 1) {
            justJump = false;
        }
    }


}

void OnCollisionEnter(Collision collision) {
    Debug.Log("!!!!!!!");
}
}

And I use this script on the character itself: (to rotate and animate it)

Code (csharp):

public class AnimationController : MonoBehaviour {

Animator anim;
public GameObject thePlayer;

// Use this for initialization
void Start () {
    anim = gameObject.GetComponent<Animator>();
}

// Update is called once per frame
void Update () {
    Bounce bounceScript = thePlayer.GetComponent<Bounce>();
    if (bounceScript.justJump == true) {
        anim.SetBool("Jump", true);
    }
    else {
        anim.SetBool("Jump", false);
    }

    if (Input.GetButtonDown("right")) {
        //transform.rotation *= Quaternion.Euler(0,30,0);
        transform.RotateAround(transform.position, Vector3.up, 90);
    }
    if (Input.GetButtonDown("left")) {
        transform.Rotate (0, -90, 0, 0);
    }
}
}

It's only colliding when the cube not isKinematic, but it doesn't stop my player from getting through the cube for some reason.

I have read some sites about problems like this, but nothing helped yet.

It would be great if you can give me any code improvements :)

EDIT1:

Sorry, for answering so late, I couldn't do anything with my game in the last few days. Today I have tried to do something with raycasts, you can see my code, for my first try just in the update method:

void Update () {
        if (Input.GetButtonDown("up") || Input.GetButtonDown("down") || Input.GetButtonDown("left") || Input.GetButtonDown("right")) {
            if (perc == 1) {
                lerpTime = 1;
                currentLerpTime = 0;
                firstInput = true;
                justJump = true;
            }
        }
        startPos = gameObject.transform.position;

    /*  if (Input.GetButtonDown("right") && gameObject.transform.position == endPos) {
            //endPos = new Vector3(transform.position.x + 0.5f, transform.position.y, transform.position.z);

        }
        if (Input.GetButtonDown("left") && gameObject.transform.position == endPos) {
            endPos = new Vector3(transform.position.x - 0.5f, transform.position.y, transform.position.z);
        }*/


        Vector3 fwd = player.transform.TransformDirection(Vector3.forward);
        RaycastHit objectHit;

        if (Physics.Raycast(player.transform.position, fwd, out objectHit, 2)) {
            if (objectHit.collider.tag == "Wall") {
                Debug.Log("WALL RAYCAST HIT!");
            }
        }


        if (Input.GetButtonDown("up") && gameObject.transform.position == endPos) {
            endPos = transform.position + player.transform.rotation * (new Vector3(0, 0, 1f));

        }
        if (Input.GetButtonDown("down") && gameObject.transform.position == endPos) {
            //endPos = transform.position + player.transform.rotation * (new Vector3(0, 0, -1f)); 
        }


        if (firstInput == true) {
                currentLerpTime += Time.deltaTime * 5;
                perc = currentLerpTime / lerpTime;
                gameObject.transform.position = Vector3.Lerp(startPos, endPos, perc);
                if (perc > 0.8f)  {
                    perc = 1;
                }

                if (Mathf.Round(perc) == 1) {
                    justJump = false;
                }
            }
    }

With this I can get the Debug Log WALL RAYCAST HIT 2-3 times at a time, but only once. As I move the character it won't appear again, for some reason (I think it should because the update method is called in every frame).

Although when I place it in the Input.GetButtonDown("up") method, it won't log anything:

if (Input.GetButtonDown("up") && gameObject.transform.position == endPos) {
             fwd = player.transform.TransformDirection(Vector3.forward);


            if (Physics.Raycast(player.transform.position, fwd, out objectHit, 2)) {
                if (objectHit.collider.tag == "Wall") {
                    Debug.Log("WALL RAYCAST HIT!");
                }
            }
            endPos = transform.position + player.transform.rotation * (new Vector3(0, 0, 1f));

        }
2

2 Answers

0
votes

When you update the transform.position you actually "teleport" yout object to the new position. Even when you do this smoothly, using something like the Lerp function, as you do on your move script, Unity understands that you are teleporting your object to a new coordinate.

This is not wrong, All games work like that. Functions like Lerp just create the ilusion of movement, so the player fell like the character actually moved from one point to another.

What is happening is that your script keeps telling the character to move to a new position, despite any objects on its path. The collision happens, but your Update function still places the character on ints new position.

I can think of two possible ways for you to solve this:

  1. Create an OnCollisionEnter() function for your Move script that somehow stops your movement. By creating a flag like you did with the firstInput you could achieve this.

  2. Instead of updating your transform.position you could use a rigidbody to handle the movement and collisions for your. This way, everytime you need to move your character you will need to add some velocity to the character rigidbody, instead of directly updating the transform.position.

Since your character doesn't move in a constant way, but in a "one step at a time" way, I think the first solution is a better suitted for you.

The code will be something like this

void OnCollisionenter(Collision collision)
{
    collided = true;
}

and the end of your Move script should be updated to

if(!collided)
{
    if (firstInput == true) {
        currentLerpTime += Time.deltaTime * 5;
        perc = currentLerpTime / lerpTime;
        transform.position = Vector3.Lerp(startPos, endPos, perc);
        if (perc > 0.8f)  {
            perc = 1;
        }

        if (Mathf.Round(perc) == 1) {
            justJump = false;
        }
    }
}
else
{
    // Remember to reset this when you stop your character
    endPos = transform.position;
    collided = false;
}

This time I couldn't test the code before writting it here, so you may need to do some changes before it works.

ps: I don't think you need your firstInput variable. Once it is set to true, you never set it to false again. Also, the Input.GetButtonDown() function will only return true on the first frame a button is pressed wich is what I guess you intended when you created firstInput.

ps2: My solution added a collided boolean attribute to your class, so don't forget to add a line private bool collided; with your other class attributes. Also, read that chapter about the state machine pattern I recommended you on your other question. Creating this kind of control attribute suach as the collided boolean is not a good practice and if you had implemented a state machine this could be avoided.

0
votes

Hey I had a similar problem i was using an animated model from Mixamo.com and I notices that for some strange reason the character didn't collide with boundaries despite having collider, for some reason it didn't work until i added a CharacterController to my model instead of a collider just search for the CharacterController and add it as you would add any script or rigid body to your game object.

Hope it Works XD Greetings