天天看点

类似绳索的链子用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);
        }
    }
           

所有的代码都在这里了,有问题希望大家指出来分享分享哈,就不提供什么下载了,如果有需要后面会继续更新哦!

继续阅读