Wayback Machinekoobas.hobune.stream
May JUN Jul
Previous capture 13 Next capture
2021 2022 2023
1 capture
13 Jun 22 - 13 Jun 22
sparklines
Close Help
  • Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
  • Asset Store
  • Get Unity

UNITY ACCOUNT

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account
  • Blog
  • Forums
  • Answers
  • Evangelists
  • User Groups
  • Beta Program
  • Advisory Panel

Navigation

  • Home
  • Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
    • Blog
    • Forums
    • Answers
    • Evangelists
    • User Groups
    • Beta Program
    • Advisory Panel

Unity account

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account

Language

  • Chinese
  • Spanish
  • Japanese
  • Korean
  • Portuguese
  • Ask a question
  • Spaces
    • Default
    • Help Room
    • META
    • Moderators
    • Topics
    • Questions
    • Users
    • Badges
  • Home /
avatar image
2
Question by DavidDebnar · Apr 24, 2013 at 06:09 PM · raycastspherecast

A question about procedural ledge grabbing.

I'm making a procedural ledge grabbing script. This is what happens so far:

1st the code checks, if there is a wall nearby and if the character is in the air. Then it SphereCasts from 10m above the character down and checks if the character is close enough to the top of the surface to grab it.

Edit:

(should I move this to the forums, since it looks like this is more a discussion type question, instead of the regular Q->A type?)

I've fixed a huge chunk of the code, but in some cases it still doesn't work. These are the movements that work:

Diagonal movement and transitions to different angles.

alt text

Curved movement:

alt text

And the movements that kinda work:

Circular movement.... This is a though one. It works, but since the cylinder's base isn't a perfect circle, it's kinda jittery. I'd need to make a code just for smoothing out transitions between vertices.

alt text

And the thoughest one - cutting 90 degree edges. It sometimes works, sometimes doesn't, it's a problem with the player's forward axis (I think, anyways) not being properly aligned when it disconnects from the old ledge and connects to the new one, that's perpendicular to the old one.

alt text

Updated code. It does compile, but I didn't test it, because it's a stripped down version of the real lady, which I had to strip down, because it contains a lot of other stuff that'd just distract you from the problem (just joking, the real reason is because I don't wnat you to have my super algorithms that calculate and proove the real mass of photons! :evil:). DrawSphere is a custom method, that draws debug spheres (hurrdurr) :

 #pragma strict
 
 public var isGrabbingALedge : boolean = false;
 private var lastLedgeDirection : Vector3;
 private var isGrounded : boolean = false;
 
 function Start () {
     var prim : GameObject = GameObject.CreatePrimitive(PrimitiveType.Sphere);
     sphereMesh = new prim.GetComponent.<MeshFilter>().sharedMesh;
     Destroy(prim);
     sphereMeshMaterial = new Material(Shader.Find("Diffuse"));
 }
 
 function Update () {
     
     var hitInfo : RaycastHit;
 
     isGrounded = Physics.SphereCast(collider.bounds.center,0.4,-transform.up,hitInfo,0.6);
 
     var move = Vector3.zero;
     move.z = Input.GetAxisRaw("Vertical");
     move.x = Input.GetAxisRaw("Horizontal");
 
     move = move.normalized * (isGrounded ? 1 : .3);
 
     rigidbody.drag = isGrounded ? 2 : .5;
 
     DetectLedge();
 
     if(!isGrabbingALedge) {
         rigidbody.velocity = move * 10;
         if(Physics.CapsuleCast(transform.position,transform.position-transform.up,0.5,transform.TransformDirection(move),hitInfo,0.55))
             move = Vector3.zero;
     }
     else {
         rigidbody.velocity = lastLedgeDirection * -move.x * 10;
         transform.localEulerAngles.y = Mathf.LerpAngle(transform.localEulerAngles.y,(Quaternion.LookRotation(Vector3.Cross(transform.up, lastLedgeDirection))).eulerAngles.y,Time.deltaTime*5);
     }
 
     if(Input.GetKeyDown(KeyCode.Space) 
     && (isGrounded || isGrabbingALedge)) {
 
         if(isGrabbingALedge) {
             isGrabbingALedge = false;
             ledgeDetectPause = 0.5;
         }
 
         rigidbody.velocity.y = 0;
         rigidbody.AddForce(Vector3.up*10,ForceMode.Impulse);
     }
 }
 
 public var ledgeDetectPause : float = 0;
 function DetectLedge() {
 
     if(ledgeDetectPause > 0) {
         ledgeDetectPause -= Time.deltaTime;
         return;
     } else ledgeDetectPause = 0;
 
     if(!isGrounded) {
 
         var l = ~((1 << (LayerMask.NameToLayer("Player") ) | (1 << LayerMask.NameToLayer("Physics"))));
 
         var colliders : Collider[] = Physics.OverlapSphere(transform.position,1, l);
 
         if(colliders.Length > 0) {
             
             DrawSphere(transform.position, 1, Quaternion.identity, Color.green);
 
             var hit : RaycastHit;
 
             Physics.Linecast(transform.position, colliders[0].transform.position,hit,l);
 
             var point : Vector3 = hit.point;
 
             if(Physics.SphereCast(point + transform.up * 10, 0.5, -transform.up, hit, 10, l)) {
                 
                 var normal : Vector3 = hit.normal;
                 point = hit.point;
 
                 if(Physics.Raycast(transform.position, transform.forward, hit, 0.75, l)) {
 
                     DrawSphere(hit.point, 1, Quaternion.identity, Color.magenta);
 
                     if((normal.y <= 0.2 || normal.y >= 0.8)) {
 
                         var direction : Vector3 = Vector3.Cross(-hit.normal, normal);
 
                         DrawSphere(point, 1, Quaternion.identity, Color.green);
                         DrawSphere(point - direction, 1, Quaternion.identity, Color(0,0.5,1));
                         DrawSphere(point + direction, 1, Quaternion.identity, Color(0,0.5,1));
 
                         if(((point - transform.position).sqrMagnitude < 1 && rigidbody.velocity.y <= 0 && !isGrabbingALedge)) {
                             isGrabbingALedge = true;
                             lastLedgeDirection = direction;
                             var localPoint : Vector3 = transform.InverseTransformPoint(point);
                             localPoint.z -= collider.bounds.extents.z;
                             localPoint.y = 0;
                             localPoint.x = 0;
                             transform.position = transform.TransformPoint(localPoint);
                             rigidbody.velocity = Vector3.zero;
                         }
                         if(isGrabbingALedge && direction != lastLedgeDirection) {
                             lastLedgeDirection = direction;
                         }
                     }
                     else {
                         DrawSphere(point, 1, Quaternion.identity, Color.red);
                         isGrabbingALedge = false;
                     }
                 }
                 else
                     isGrabbingALedge = false;
             }
             else
                 isGrabbingALedge = false;
         }
         else
             DrawSphere(transform.position, 1, Quaternion.identity, Color.red);
     }
 }
 
 private var sphereMesh : Mesh;
 private var sphereMeshMaterial : Material;
 function DrawSphere (position : Vector3, size : float, rotation : Quaternion, color : Color) {
 
     //if(!Application.isEditor) return;
 
     var mat : Material = new Material(sphereMeshMaterial);
     mat.color = color;
 
     var mes : Mesh = Instantiate(sphereMesh);
     var verts = mes.vertices;
 
     for(var i = 0; i < verts.Length; i++)
         verts[i] *= size;
     mes.vertices = verts;
 
     Graphics.DrawMesh(mes, position, rotation, mat, LayerMask.NameToLayer("Default"), Camera.main);
 }
 
 function FixedUpdate () {
     
     if(isGrabbingALedge) // Don't apply gravity
         return;
     else //Apply gravity
         rigidbody.AddForce(-Vector3.up * 9.81, ForceMode.Acceleration);
 }

OLD PROBLEMS

alt text

Now the problems. To detect where the left and right hands are going to be, I do a Cross product of the player transform's forward direction and the normal, but this doesn't really work, because if the player rotates to the left or right, the spheres go off the edge.

alt text

Next problem is detecting if the SphereCast hit an edge or a surface. And the last problem is with SphereCast itself, because the normals don't always return just what I'd want and what I'd need for it properly function is CylinderCast, which doesn't exist.

And just to be clear, this isn't a write-code-for-me question, I'd just like to discuss different ways of procedural ledge grabbing and find a nice solution. But if you feel like writing up some code I won't be mad ;).

-- David

Comment
Add comment · Show 5
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image DavidDebnar · Apr 25, 2013 at 03:53 PM 0
Share

Oh c'mon, 50 views and not even a comment? That's rude! :P

avatar image AlucardJay · Apr 25, 2013 at 04:29 PM 0
Share

We are awestruck by your skills!

Should the player be able to rotate while holding a ledge? If not, when grabbing the ledge, subtly rotate the player so they are perpendicular to the ledge they are grabbing. If so, you may need to have the hand object separate to the player object, keep the hand rotated perpendicular to the ledge.

That's all I've got, sorry. This is some excellent work, well done so far, upvote for nice question =]

avatar image DavidDebnar · Apr 25, 2013 at 05:40 PM 0
Share

Thanks for the positive comment, much appreciated! The hands are gonna be positioned to where the blue spheres are trough I$$anonymous$$, so the animations don't look awkward when grabbing diagonal surfaces. I've also updated my question, since the problems stated in it are already fixed, but as it always has and will be, new bugs were sent to new places where one'd never think they'd ever be and so the new problems were added.

avatar image Loius · Apr 25, 2013 at 06:01 PM 0
Share

That's a beautiful question. :'s

avatar image DavidDebnar · Apr 26, 2013 at 12:44 PM 0
Share

Thanks, means a lot ;). I'll probably just move this to forums, because starting a discussion here failed.

0 Replies

· Add your reply
  • Sort: 

Your answer

Hint: You can notify a user about this post by typing @username

Up to 2 attachments (including images) can be used with a maximum of 524.3 kB each and 1.0 MB total.

Follow this Question

Answers Answers and Comments

13 People are following this question.

avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image

Related Questions

Finding a point that is "visible" to two objects 2 Answers

Using Spherecast to identify objects? 1 Answer

SphereCast misses but RayCast and OverlapSphere don't 1 Answer

Car AI help 0 Answers

SphereCast and CheckSphere failing to catch collisions. 1 Answer


Enterprise
Social Q&A

Social
Subscribe on YouTube social-youtube Follow on LinkedIn social-linkedin Follow on Twitter social-twitter Follow on Facebook social-facebook Follow on Instagram social-instagram

Footer

  • Purchase
    • Products
    • Subscription
    • Asset Store
    • Unity Gear
    • Resellers
  • Education
    • Students
    • Educators
    • Certification
    • Learn
    • Center of Excellence
  • Download
    • Unity
    • Beta Program
  • Unity Labs
    • Labs
    • Publications
  • Resources
    • Learn platform
    • Community
    • Documentation
    • Unity QA
    • FAQ
    • Services Status
    • Connect
  • About Unity
    • About Us
    • Blog
    • Events
    • Careers
    • Contact
    • Press
    • Partners
    • Affiliates
    • Security
Copyright © 2020 Unity Technologies
  • Legal
  • Privacy Policy
  • Cookies
  • Do Not Sell My Personal Information
  • Cookies Settings
"Unity", Unity logos, and other Unity trademarks are trademarks or registered trademarks of Unity Technologies or its affiliates in the U.S. and elsewhere (more info here). Other names or brands are trademarks of their respective owners.
  • Anonymous
  • Sign in
  • Create
  • Ask a question
  • Spaces
  • Default
  • Help Room
  • META
  • Moderators
  • Explore
  • Topics
  • Questions
  • Users
  • Badges