0
\$\begingroup\$

http://www.gamasutra.com/blogs/AdamWinkels/20140220/211306/DevLog_7_Learning_How_to_Walk.php

Following the link above I have been able to get my character to move and rotate very smoothly over angled surfaces up-to 80 degrees. Anything over that and it begins to clip and wobble when traveling down the surface. The spiders rotation only reaches half of the desired angle. So at 85 degrees it only rotates to 42.5. Going up is a mess, but I have not implemented the fix for that from the link above, so I am less worried about that. Any suggestions?

private float RayDuration = 0;
private float RayAngle = 5f;
private float RayLength;
Vector2 MovementDirection;
float OffSetY  = 5;
float OffSetX = .5f;
int GroundMask = 1 << 8;

 void Start()
{
    SpiderRect = GetComponent<RectTransform>();
    RayLength = SpiderRect.rect.height;
}

private void TouchHeld(CustomEvent customEvent)
{

    if (Input.mousePosition.x > 400)
    {
        MovementDirection = transform.right;
    }
    else
    {
        MovementDirection = -transform.right;
    }

    Vector2 transformUp = transform.up;
    Vector2 position = transform.position;

    Vector2 rightRayPosition = new Vector2(transform.position.x + OffSetX, transform.position.y + OffSetY);
    Quaternion rightOffSetAngle = Quaternion.AngleAxis(-RayAngle, new Vector3(0, 0, 1));
    Vector2 rightRayAngle = rightOffSetAngle * Vector2.down ;

    Vector2 leftRayPosition = new Vector2(transform.position.x - OffSetX, transform.position.y + OffSetY);
    Quaternion leftOffSetAngle = Quaternion.AngleAxis(RayAngle, new Vector3(0, 0, 1));
    Vector2 leftRayAngle = leftOffSetAngle * Vector2.down;

    RaycastHit2D rightHit = Physics2D.Raycast(rightRayPosition, rightRayAngle, RayLength, GroundMask);
    RaycastHit2D leftHit = Physics2D.Raycast(leftRayPosition, leftRayAngle, RayLength, GroundMask);

    #region move
    if (rightHit && leftHit)
    {

        Debug.DrawRay(rightRayPosition, rightRayAngle, Color.red, RayDuration);
        Debug.DrawRay(rightRayPosition, rightHit.normal, Color.green, RayDuration);

        Debug.DrawRay(leftRayPosition, leftRayAngle, Color.yellow, RayDuration);
        Debug.DrawRay(leftRayPosition, leftHit.normal, Color.magenta, RayDuration);

        Vector2 averagePoint = (leftHit.point + rightHit.point) / 2;
        Debug.DrawRay(averagePoint, -transform.up, Color.cyan, RayDuration);

        Vector2 averageNormal = (leftHit.normal + rightHit.normal) / 2;
        Debug.DrawRay(averagePoint, averageNormal, Color.cyan, RayDuration);

        Quaternion targetRotation = Quaternion.FromToRotation(Vector3.up, averageNormal);
        Quaternion finalRotation = Quaternion.RotateTowards(transform.rotation, targetRotation, 10);
        transform.rotation = Quaternion.Euler(0, 0, finalRotation.eulerAngles.z);

        transform.position = Vector2.MoveTowards(transform.position, averagePoint + MovementDirection, .15f);
    }
    else
    {
        Debug.Log("What");
    }
\$\endgroup\$
6
  • \$\begingroup\$ It looks like you're setting up your ray starting positions and directions in world space, rather than rotating them with the character like in the linked example. (So even if the character is on a 45-degree angle, the rays still fire in the direction of global down instead of "in the direction of the character's bottom") Is that intentional? \$\endgroup\$
    – DMGregory
    Commented Jun 17, 2017 at 17:26
  • \$\begingroup\$ Are you saying use -transform.up instead of Vector2.down when setting the ray angle? If so I get much worse results when i do that. It wont make it over any angle with that. It just jitters back and forth \$\endgroup\$ Commented Jun 17, 2017 at 19:17
  • \$\begingroup\$ You'd need to change the starting points too, if matching the article example is your goal. I just thought I should clarify in case you deliberately chose to keep the sensing in a fixed worldspace orientation for some reason. \$\endgroup\$
    – DMGregory
    Commented Jun 17, 2017 at 19:19
  • \$\begingroup\$ I'm confused , I thought I was setting the position the same as the article, with transform.position. What am I missing? \$\endgroup\$ Commented Jun 17, 2017 at 19:30
  • \$\begingroup\$ You're missing everything they do with transformUp and transformRight. (Although myself, I'd use transform.TransformPoint() instead to do it in one step) \$\endgroup\$
    – DMGregory
    Commented Jun 17, 2017 at 19:35

1 Answer 1

1
\$\begingroup\$

Thanks to DMGregory for the sage advice. I needed to get my vectors into the correct world space coordinates . The working code is below, it needs clean up but it works like a champ.

private float RayDuration = 0;
private float RayAngle = .5f;
private float RayLength;
Vector2 MovementDirection;
Vector2 OffSetYVector;
float OffSetY;
float OffSetX = 5f;
int GroundMask = 1 << 8;
RectTransform SpiderRect;

void Start() {

    SpiderRect = GetComponent<RectTransform>();
    RayLength = SpiderRect.rect.height;
    OffSetY = RayLength;
}

private void TouchHeld(CustomEvent customEvent) {

    if (Input.mousePosition.x > 400)
    {
        MovementDirection = transform.right;
    }
    else
    {
        MovementDirection = -transform.right;
    }

    Vector2 transformUp = transform.up;
    Vector2 transformRight = transform.right;
    Vector2 position = transform.position;
    OffSetYVector = new Vector2(0, transform.position.y + OffSetY);

    Vector2 rightRayPosition = transform.TransformPoint(new Vector2(OffSetX, OffSetY));
    Quaternion rightOffSetAngle = Quaternion.AngleAxis(-RayAngle, new Vector3(0, 0, 1));
    Vector2 rightRayAngle = rightOffSetAngle * -transformUp;

    Vector2 leftRayPosition = transform.TransformPoint(new Vector2(-OffSetX, OffSetY));
    Quaternion leftOffSetAngle = Quaternion.AngleAxis(RayAngle, new Vector3(0, 0, 1));
    Vector2 leftRayAngle = leftOffSetAngle * -transformUp;

    RaycastHit2D rightHit = Physics2D.Raycast(rightRayPosition, rightRayAngle, RayLength, GroundMask);
    RaycastHit2D leftHit = Physics2D.Raycast(leftRayPosition, leftRayAngle, RayLength, GroundMask);
    #region move
    if (rightHit && leftHit)
    {

        Debug.DrawRay(rightRayPosition, rightRayAngle, Color.red, RayDuration);
        Debug.DrawRay(rightRayPosition, rightHit.normal, Color.green, RayDuration);

        Debug.DrawRay(leftRayPosition, leftRayAngle, Color.yellow, RayDuration);
        Debug.DrawRay(leftRayPosition, leftHit.normal, Color.magenta, RayDuration);

        Vector2 averagePoint = (leftHit.point + rightHit.point) / 2;
        Debug.DrawRay(averagePoint, -transform.up, Color.cyan, RayDuration);

        Vector2 averageNormal = (leftHit.normal + rightHit.normal) / 2;
        Debug.DrawRay(averagePoint, averageNormal, Color.cyan, RayDuration);

        Quaternion targetRotation = Quaternion.FromToRotation(Vector3.up, averageNormal);
        Quaternion finalRotation = Quaternion.RotateTowards(transform.rotation, targetRotation, 10);
        transform.rotation = Quaternion.Euler(0, 0, finalRotation.eulerAngles.z);

        transform.position = Vector2.MoveTowards(transform.position, averagePoint + MovementDirection, .15f);
    }
    else
    {
        Debug.Log("What");
    }
    #endregion
\$\endgroup\$
2
  • \$\begingroup\$ Watch out, the code you've shown above applies transform.position TWICE: once in constructing rightRayPosition, and then again in TransformPoint. This has no effect when the character is at (0, 0), but will get increasingly far from what you want as the character moves. It looks like you just want Vector2 rightRayPosition = transform.TransformPoint(new Vector2(OffsetX, OffsetY)); \$\endgroup\$
    – DMGregory
    Commented Jun 17, 2017 at 20:08
  • \$\begingroup\$ Saves the day again! I'll be reading up on world vs local position tonight. This has had me hung up for too long. Thanks again! \$\endgroup\$ Commented Jun 17, 2017 at 20:14

You must log in to answer this question.

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