天天看點

類似繩索的鍊子用C#模拟實作

    為了實作類似于實體引擎中的關節連接配接的效果,但是又不想用那臃腫的引擎因為好多的費時費力的效果都用不到,就想自己實作一個類似的效果,其實目的是為了一個遊戲的的特殊效果,大概是類似于一條蛇的動物的爬行或者是一條龍的飛行效果,目前隻是實作了關節點的連動效果,沒有限制各關節之間的角度關系,後面會實作在關節之間加入扭矩這個實體量來達到關節點之間的角度問題,下面是效果圖,這條鍊會跟着滑鼠的位置連動起來。小面講一下原理吧:

類似繩索的鍊子用C#模拟實作
類似繩索的鍊子用C#模拟實作

其實原理很簡單,先得出兩個小球之間的連動關系然後就有第二個小球以同樣的效果去影響他後面的小球,

類似繩索的鍊子用C#模拟實作
類似繩索的鍊子用C#模拟實作

兩個小球的影響關系如上圖所示,a,b兩個小球的距離固定為L,當b從b1位置移動到b2 的位置時就要計算這個時候a小球的位置,因為計算機模拟的時候是離散的數值計算,b的位置也是離散的出現在計算關系中,那麼就不可能實作b對a的連續影響(至少不會這麼簡單吧);那麼我就假設a的新位置在b2與a1的延長線上并且他們之間的距離不變,那麼就是個很簡單的計算題了,ok!就這樣了實作了小面貼下代碼給有興趣的朋友分享一下吧,

class Vec2
    {
       //static float gen2=1.41421356f;
        private float x;
        public float X
        {
            get { return x; }
            set { bAngleChgd = true; x = value; }
        }
        private  float y;
        public float Y
        {
            get { return y; }
            set { bAngleChgd = true; y = value; }
        }
        private float sin;
        private float cos;
        private float angle=0;
        private float length = 0;
        public float Angle
        {
            get {
                if (bAngleChgd) { CAngel(); bAngleChgd = false; }
                return angle; 
               } 
        }
        public float Sin
        {
            get {
                  if (bAngleChgd) { CAngel(); bAngleChgd = false; }
                  return sin; 
                }
        }
        public float Cos
        {
            get
            {
                if (bAngleChgd) { CAngel(); bAngleChgd = false; }
                return cos;
            }
        }
        public float Length
        {
            get
            {
                return length;
            }
        }
        public void setValue(float x,float y)
        {
            this.x = x;
            this.y = y;
            CAngel();
        }
        public void setValue(Vec2 v)
        {
            this.x = v.x; this.y = v.y;
        }
        public void add(Vec2 v)
        {
            this.y += v.y;
            this.x += v.x;
        }
        Boolean bAngleChgd=false;
        public void CAngel()
        {
            float le = (float)Math.Sqrt( x * x + y * y);
            length = le;
            cos = x / le;
            sin = y / le;

            //z\這裡留着些關于扭矩的實作
            //angle = (float)Math.Asin(sin); 
        }
    }
           
這就是實作的類似于關節的類Joint有點像個連結清單。真心很簡單哈,代碼都不超過一百行,但這是我思考了很久才想到的哦!
           
class Joint
    {
        private Vec2 pos=new Vec2();
        private float Lengh=20f;
        private Joint next=null;
        private Vec2 Angle=new Vec2();
        public void setLength(float leght)
        {
            this.Lengh = leght;
        }
        public void setPos(Vec2 vPos)
        {
            pos.setValue(vPos);
            if (next == null) return;
            Angle.setValue(next.pos.X-pos.X,next.pos.Y-pos.Y);
             next.pos.setValue(Lengh*Angle.Cos,Lengh*Angle.Sin);
        }
        public void setPos(float x,float y)
        {
            pos.setValue(x,y);
            if (next == null) return;
              Angle.setValue(next.pos.X - pos.X, next.pos.Y - pos.Y);
              if( Angle.Length>Lengh)
              {
                next.setPos(Lengh * Angle.Cos+pos.X, Lengh * Angle.Sin+pos.Y);
              }
        }
        public void Show( Graphics g,Image img)
        {
            
            g.DrawImage(img, pos.X, pos.Y);
            if (next != null)
                next.Show(g,img);
        }
        public void addNext(Joint next)
        {
            this.next = next;
        }
    }
           
這個是測試窗體代碼就不說什麼了;
           
public partial class Joint_Test : Form
    {
        Joint joints=new Joint();
        public Joint_Test()
        {
            InitializeComponent();
            joints.setPos(Width/2,Height/2);
            Joint jt=joints;
            Joint new_joint;
            for (int i = 0; i < 24; i++)
            {
                new_joint = new Joint();
                new_joint.setPos(Width/2,Height/2+(i+1)*10);
                new_joint.setLength(9);
                jt.addNext(new_joint);
                jt = new_joint;
            }
            img = ResourceMedium.joint_point;
            DoubleBuffered = true;
        }
        private void Form1_MouseMove(object sender, MouseEventArgs e)
        { 
            Point formPoint = this.PointToClient(Control.MousePosition);
            joints.setPos(formPoint.X,formPoint.Y);
        }


        private void Joint_Load(object sender, EventArgs e)
        {


        } 
        private void timer_click_Tick(object sender, EventArgs e)
        {
            this.Invalidate();
        }
        Image img=null;
        private void Joint_Test_Paint(object sender, PaintEventArgs e)
        {
            joints.Show(e.Graphics,img);
        }
    }
           

所有的代碼都在這裡了,有問題希望大家指出來分享分享哈,就不提供什麼下載下傳了,如果有需要後面會繼續更新哦!

繼續閱讀