antonkudin

SnekSolver

Sep 28th, 2017
813
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C# 5.22 KB | None | 0 0
  1. using System.Collections;
  2. using System.Collections.Generic;
  3. using UnityEngine;
  4.  
  5. public class SnekSolver : MonoBehaviour {
  6.  
  7.     public Transform targetT;
  8.     [Header("Joints")]
  9.     public int totalJoints = 10;
  10.     [Space]
  11.     public float maxLength = 1;
  12.     public float minLength = .95f;
  13.     [Header("Solver")]
  14.     [Range(1,100)] public int iterations = 1;
  15.     [Space]
  16.     public bool useTipAngle;
  17.     public bool useBaseAngle;
  18.     [Space]
  19.     public BaseFixType baseFixType;
  20.     [Range(0,1)]public float bodyStretch=.8f;
  21.     [Space]
  22.     public JointAngleRestrictType restrict = JointAngleRestrictType.Adaptive;
  23.    
  24.     [Range(0,180)] public float maxJointAngle = 90;
  25.     [Range(0,60)] public float angleRestrictSpeed;
  26.  
  27.     Vector2[] path;
  28.     float pTime;
  29.     public enum BaseFixType { None, Reach, Stretch };
  30.     public enum JointAngleRestrictType { None, Dumb, Adaptive, Instant };
  31.  
  32.    
  33.     void OnDrawGizmos() {
  34.        
  35.         if(targetT==null){
  36.             GameObject targetGO = new GameObject("target");
  37.             targetT = targetGO.transform;
  38.             targetT.position = (Vector2)transform.position + Random.insideUnitCircle*5;
  39.         }
  40.        
  41.         Vector2 target=targetT.position;
  42.         Vector2 start=transform.position;
  43.        
  44.         if(path==null || path.Length!=totalJoints){
  45.             path = new Vector2[totalJoints];
  46.             for(int p=0;p<totalJoints;p++){
  47.                 path[p]=Vector2.Lerp( start,target,(float)p/totalJoints);
  48.             }          
  49.         }
  50.        
  51.         float dt = Mathf.Clamp(time-pTime, .0166f,.04f);
  52.        
  53.         for(int i=0;i<iterations;i++){
  54.            
  55.             path[totalJoints-1] = target;
  56.            
  57.             for(int p=totalJoints-1;p>0;p--){
  58.                
  59.                 Vector2 direction = path[p]-path[p-1];
  60.                 float length = direction.magnitude;
  61.                
  62.                 if(useTipAngle && p==totalJoints-1){
  63.                     path[p-1] = path[p] - RotateVector2(new Vector2(0,length), targetT.eulerAngles.z);         
  64.                     direction = (path[p]-path[p-1]).normalized;
  65.                 }
  66.                
  67.                 if(useBaseAngle && p==1){
  68.                     path[p-1] = path[p] - RotateVector2(new Vector2(0,length), transform.eulerAngles.z);           
  69.                     direction = (path[p]-path[p-1]).normalized;
  70.                 }
  71.                
  72.                 direction.Normalize();
  73.                
  74.                 if(restrict!=JointAngleRestrictType.None && p<totalJoints-1){
  75.                    
  76.                     float dirAngle = angle(direction);
  77.                    
  78.                     Vector2 prevDirection = path[p+1]-path[p];
  79.                     float prevAngle = angle(prevDirection);
  80.                    
  81.                     float angleDiff = Mathf.DeltaAngle(dirAngle, prevAngle);
  82.  
  83.                     switch(restrict){
  84.                        
  85.                         case JointAngleRestrictType.Instant:
  86.                        
  87.                             if(angleDiff>maxJointAngle)
  88.                                 path[p-1] = path[p] - RotateVector2(new Vector2(0,length), prevAngle-maxJointAngle);
  89.                             else if(angleDiff<-maxJointAngle)
  90.                                 path[p-1] = path[p] - RotateVector2(new Vector2(0,length), prevAngle+maxJointAngle);
  91.                            
  92.                         break;
  93.                        
  94.                         case JointAngleRestrictType.Dumb:
  95.                        
  96.                             if(angleDiff>maxJointAngle)
  97.                                 path[p-1] = path[p] - RotateVector2(new Vector2(0,length), dirAngle+angleRestrictSpeed*dt*360);
  98.                             else if(angleDiff<-maxJointAngle)
  99.                                 path[p-1] = path[p] - RotateVector2(new Vector2(0,length), dirAngle-angleRestrictSpeed*dt*360);
  100.                        
  101.                         break;
  102.                        
  103.                         case JointAngleRestrictType.Adaptive:
  104.                        
  105.                             if(angleDiff>maxJointAngle)
  106.                                 path[p-1] = path[p] - RotateVector2(new Vector2(0,length), dirAngle+angleRestrictSpeed*dt*Mathf.Clamp(angleDiff-maxJointAngle,-90,90));
  107.                             else if(angleDiff<-maxJointAngle)
  108.                                 path[p-1] = path[p] - RotateVector2(new Vector2(0,length), dirAngle+angleRestrictSpeed*dt*Mathf.Clamp(maxJointAngle+angleDiff,-90,90));
  109.                        
  110.                         break;
  111.                     }
  112.                    
  113.                     direction = (path[p]-path[p-1]).normalized;
  114.                 }
  115.                
  116.                 if(length<minLength)
  117.                     path[p-1] = path[p] - direction*minLength;
  118.                 else if(length>maxLength)
  119.                     path[p-1] = path[p] - direction*maxLength;
  120.                
  121.             }
  122.            
  123.             switch(baseFixType){
  124.                 case BaseFixType.Reach:{
  125.                     Vector2 od = start-path[0];
  126.                     for(int p=0;p<totalJoints;p++) path[p] += od;
  127.                 }break;
  128.                
  129.                 case BaseFixType.Stretch:{
  130.                     Vector2 od = start-path[0];
  131.                     for(int p=0;p<totalJoints;p++)
  132.                         path[p] += od * Mathf.Pow(1-(float)p/(totalJoints-1), bodyStretch);
  133.                 }break;
  134.             }
  135.         }
  136.    
  137.         pTime = time;
  138.    
  139.    
  140.         // drawDebugs.ddPath(path, Color.white, type:drawDebugs.ddPathType.Capsules);      
  141.        
  142.         Gizmos.color = Color.yellow;
  143.         for(int p=1;p<totalJoints;p++)
  144.             Gizmos.DrawLine(path[p-1],path[p]);
  145.     }
  146.    
  147.     void OnValidate(){
  148.         maxLength = Mathf.Max(maxLength, 0);
  149.         minLength = Mathf.Clamp(minLength, 0, maxLength);
  150.     }
  151.    
  152.     public static float time {get{
  153.         #if UNITY_EDITOR
  154.         if(!Application.isPlaying)
  155.             return (float)UnityEditor.EditorApplication.timeSinceStartup;
  156.         #endif
  157.         return Time.time;
  158.     }}
  159.    
  160.    
  161.     Vector2 RotateVector2(Vector2 v, float degrees) {
  162.  
  163.         if(degrees<0 || degrees>=360) degrees = Mathf.Repeat(degrees, 360);
  164.  
  165.         if(degrees.Equals(0)) return v;
  166.         else if(degrees.Equals(90)) return new Vector2(-v.y,v.x);
  167.         else if(degrees.Equals(180)) return new Vector2(-v.x, -v.y);
  168.         else if(degrees.Equals(270)) return new Vector2(v.y,-v.x);
  169.  
  170.         float sin = Mathf.Sin(degrees * Mathf.Deg2Rad);
  171.         float cos = Mathf.Cos(degrees * Mathf.Deg2Rad);
  172.        
  173.         float tx = v.x;
  174.         float ty = v.y;
  175.         v.x = (cos * tx) - (sin * ty);
  176.         v.y = (sin * tx) + (cos * ty);
  177.  
  178.         return v;
  179.     }
  180.  
  181.     float angle(Vector2 v){
  182.         return Mathf.Atan2(v.y,v.x)*Mathf.Rad2Deg - 90f;
  183.     }
  184.  
  185. }
Advertisement
Add Comment
Please, Sign In to add comment