0
votes

What I want to do is to make a kind of 2.5D runner game in Unity, which the character's all three rotation axises are frozen and the position on Z axis is also frozen. I don't know how to make the character moving forward nicely on the seesaw. (I create the seesaw by using HingeJoint.)

I create a struct to detect the CapsuleCollider status by using Physics.Raycast() function and that works fine.

 private struct ColliderStatus
    {
        public bool headed;  //colliding up
        public bool footed;  //colliding down
        public bool onPlane; //colliding down && the obstacle colliding does not have slope angle
        public bool lefted;  //colliding left
        public bool righted; //colliding right
        public bool inAir;   //not colliding anything
    }

I've tried these ways:

  1. Add force on Rigidbody to move forward

    //To move character rigidbody move forward automatically in runner game 
    //when the speed is lower than the minimum speed and it's on plane or in air.
    if (rigidbody.velocity.x < minForwardSpeed && (colliderStatus.onPlane || colliderStatus.inAir))
    {
        rigidbody.AddForce(20f * Vector3.right);
    }
    
    //Add gravity to player
    Vector3 gravityForce = new Vector3(0f, -gravityOnPlayer, 0f);
    rigidbody.AddForce(gravityForce);
    

It doesn't work well because the character continue going up when it's on the seesaw though the seesaw starts to tilt. And there will be a velocity loss when the character fall to ground from a higher plane or after jumping and what it looks like is that the character will stunned for a little moment on the landing point and then begin to accelerate.

  1. Use transform.Translate() to move forward && change the way of adding gravity

    //Use transform.Translate() to move forward
    //I recognize that by this way, there will be no velocity loss
    //when the character falling down to the ground at the landing point
    //If I don't use this condition, my character will stuck on the
    //right vertical wall
    if (!colliderStatus.righted)
    {
         transform.Translate(new Vector2(minForwardSpeed, 0f) * Time.deltaTime);
    }
    

I don't know why I can't write like this since it will cause the velocity doesn't react correctly:

    //Use transform.Translate() to move forward
    if (!colliderStatus.righted && rigidbody.velocity.x < minForwardSpeed)
    {
         transform.Translate(new Vector2(minForwardSpeed, 0f) * Time.deltaTime);
    }

To change the way of adding gravity, I use a function SlopeAngleVector() to calculate the slope vector the character is running on.

    private Vector3 SlopeAngleVector()
    {
    Vector3 nextStepPositon = new Vector3(transform.position.x + 0.01f, transform.position.y, 0f);
    Ray nextPosRay = new Ray(nextStepPositon, Vector3.down);
    Ray nowPosRay = new Ray(transform.position, Vector3.down);
    RaycastHit nextPosHit;
    RaycastHit nowPosHit;
    Vector3 slopeAngle = Vector3.zero;

    Physics.Raycast(nowPosRay, out nowPosHit, 5f, obstaclesLayerMask);
    if (Physics.Raycast(nextPosRay, out nextPosHit, 5f, obstaclesLayerMask))
    {
        slopeAngle = new Vector3(nextPosHit.point.x - nowPosHit.point.x, nextPosHit.point.y - nowPosHit.point.y, 0f).normalized;
    }
    return slopeAngle;
    }

Then I add the gravity by calculate the gravity projection on the slope vector:

    private void AddGravity()
    {
    Vector3 gravityForce = new Vector3(0f, -gravityOnPlayer, 0f);
    //my character could be collided by the long vertical wall(colliderStatus.righted)
    //so I set the condition as "!colliderStatus.footed"
    //otherwise, I would use "colliderStatus.inAir"
    if (!colliderStatus.footed)
    {
        gravityForce = new Vector3(0f, -gravityOnPlayer, 0f);
    }
    else
    {
        gravityForce = Vector3.Project(Vector3.down * gravityOnPlayer, SlopeAngleVector());
    }
    rigidbody.AddForce(gravityForce);
    }

Now my character can slide down from the seesaw but it will keep going backwards. And it cannot make it through when on the low slope angle seesaw.

How to make a good behavior script for the runner on seesaw?

1
Have you tried chaning the velocity instead of adding force?Juan Bayona Beriso

1 Answers

0
votes

I'd suggest looking at some of the Unity standard asset character controllers, I believe they take slopes into account for their character movement. It may give you some ideas.

I'd also recommend modifying the way your code calculates the angle of the slope. The raycast hit will give you back a surface normal, you should then be able to use the Vector3.Cross to figure out the angle of the slope.

It'll be something like: Vector3.Cross(normal, (vector that points away from screen)).

You may need to tweak it to get it working correctly but this can give you the slope angle in one raycast. It may also eliminate potential issues of your move to position being just below the see saw.

As a general tip, try not to mix transform and rigidbody stuff together, if you want to move the rigidbody, move the rigidbody directly, not indirectly through the transform.