[Silverlight动画]转向行为 - 群落

说到群落,很难不引用Craig Reynolds和他的"boilds"模拟系统。Reynolds很牛的将一个看似非常恐怖的复杂过程,拆成了几个比较简单的行为。

想想鸟群,它含有三个主要角色:

首先,鸟们都保持在同一个区域。如果有只鸟离队伍远了,就该马上归队。这叫凝聚。如图

其次,尽管鸟们都在一起飞,但是要避免不会互相碰到。为此,它们各自都有一个空间来预防其它鸟太接近。这叫分离。

最后,鸟们飞行在同一个方向。当然各自的角度不一定相同,但是大方向是差不多的。这叫队列。

这三个行为凝聚分离队列组成了复杂的群落行为。

当考虑鸟群时,就以整个群落是一条心去想象,或者认为每个鸟都充分认识群中的其它鸟。我不想为此去争论什么,但我要说,当开始理解这三个行为,何以促成群落 行为时,你会发现,每个鸟根本不需要知道多少东西,也不需要什么民主集中一条心来指挥群落。实际上,每个鸟就只需要看看临近的几只伙伴。如果靠太近就离远 点,如果方向差太多就转过来点,最终以此形成了传说中的群落行为。

尽管群落行为技术上被拆成了三个子行为,然而它们几乎总是捆绑出现的。一般不太会只对角色使用其中一两个行为,所以就把这仨放于同一个函数中好了。这样效率也高,避免要做三次循环。

        public void flock(List<Vehicle> vehicles) {
            Vector2D averageVelocity = _velocity.clone();
            Vector2D averagePosition = new Vector2D(0, 0);
            int inSightCount = 0;
            for (int i = 0; i < vehicles.Count; i++)
            {
                Vehicle vehicle = vehicles[i];
                if (vehicle!=this&&inSight(vehicle))
                {
                    averageVelocity = averageVelocity.add(vehicle.velocity);
                    averagePosition = averagePosition.add(vehicle.position);
                    if (tooClose(vehicle))
                    {
                        flee(vehicle.position);
                        inSightCount++;
                    }
                }
            }
            if (inSightCount>0)
            {
                averageVelocity = averageVelocity.divide(inSightCount);
                averagePosition = averagePosition.divide(inSightCount);
                seek(averagePosition);
                _steeringForce.add(averageVelocity.subtract(_velocity));
            }
        }

首先,传递一个持有机车的数组。通过遍历这个数组找出进入视野的其它机车。把进入视野的机车的速度和位置都加起来,然后统计次数,最后以此求得平均值。如果机车靠太近,用避开函数离开之,以此实现分离。唯一要注意的地方就是处理过程中对自身的忽略。

当走完整个数组,算出平均速度和位置后,寻找平均位置,叠加平均转向力即完成任务。

似乎没啥了不起,不过有几个函数我们还没介绍呢,视野中(inSight)和太接近(tooClose):

inSight 函数判定一个机车是否能看到另一个机车。为此,先要检测两者间距离是否在视野范围内,如果不是就返回false。接着用向量的数学运算判断机车的前后关 系,这里采用的实现方式比较死板,只认前方的机车,在后面就当作看不见。这个做做例子够用了,如果要作改进,可以先考虑做一个可变化的视野范围。窄的视野 范围意味着角色只能沿着视野方向,注意不到两边,宽的视野意味着角色可以看到边上的一些东西。不同的视野范围,会导致不同的群落模式。

再来是tooClose函数,这个简单的不想说了。

        private double _inSightDist = 200;
        private double _tooCloseDist = 60;

        private bool tooClose(Vehicle vehicle)
        {
            return _postion.dist(vehicle.position) < _tooCloseDist;
        }

        private bool inSight(Vehicle vehicle)
        {
            if (_postion.dist(vehicle.position)>_inSightDist)
            {
                return false;
            }
            Vector2D heading = _velocity.clone().normalize();
            Vector2D difference = vehicle.position.subtract(_postion);
            double dotProd = difference.dotProd(heading);
            if (dotProd<0)
            {
                return false;
            }
            return true;
        }

测试:

<UserControl
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    xmlns:local="clr-namespace:Steer" xmlns:ed="http://schemas.microsoft.com/expression/2010/drawing" x:Class="Steer.FlockTest"
    mc:Ignorable="d"
    d:DesignHeight="300" d:DesignWidth="400">
    
    <Grid x:Name="LayoutRoot" Background="White">


    </Grid>
</UserControl>
    public partial class FlockTest : UserControl
    {
        private List<Vehicle> _vehicles;
        private int _numVehicles = 30;
        public FlockTest()
        {
            InitializeComponent();
            Loaded += new RoutedEventHandler(FlockTest_Loaded);
        }

        void FlockTest_Loaded(object sender, RoutedEventArgs e)
        {
            _vehicles = new List<Vehicle>();
            for (int i = 0; i < _numVehicles; i++)
            {
                SteeredVehicle vehicle = new SteeredVehicle();
                RegularPolygon rp = new RegularPolygon();
                rp.Width = 15;
                rp.Height = 15;
                rp.Fill = new SolidColorBrush(Colors.Blue);
                rp.PointCount = 3;
                TransformGroup tf = new TransformGroup();
                CompositeTransform ct = new CompositeTransform();
                tf.Children.Add(ct);
                rp.RenderTransform = tf;
                ct.Rotation = 90;
                vehicle.Children.Add(rp);
                vehicle.Width = 15;
                vehicle.Height = 15;
                vehicle.HorizontalAlignment = HorizontalAlignment.Left;
                vehicle.VerticalAlignment = VerticalAlignment.Top;
                LayoutRoot.Children.Add(vehicle);
                _vehicles.Add(vehicle);
            }
            CompositionTarget.Rendering += new EventHandler(CompositionTarget_Rendering);
        }

        void CompositionTarget_Rendering(object sender, EventArgs e)
        {
            foreach (SteeredVehicle vehicle in _vehicles)
            {
                vehicle.flock(_vehicles);
                vehicle.update();
            }
        }
    }

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏C语言及其他语言

【每日一题】问题 1429[蓝桥杯][历届试题]兰顿蚂蚁

题目描述 ? 兰顿蚂蚁,是于1986年,由克里斯·兰顿提出来的,属于细胞自动机的一种。 平面上的正方形格子被填上黑色或白色。在其中一格正方形内有...

29660
来自专栏余林丰

初学数据挖掘——相似性度量(二)

  上一篇中介绍了四个算法,并用四个算法分别计算了两个人的相似度。这篇就来讲讲相似性算法在实际当中怎么用。第一:将指定的人与其他人作相似性比较,并从高到低进行排...

25260
来自专栏窗户

怀念Galois

  我的第一篇谈到具体学科的博客,还是献给我最钟爱的数学。   个人比较喜欢离散数学,并非因为曲高和寡,而是因为数学分析、概率论、拓扑学、泛函之类的高手实在太多...

19950
来自专栏大数据文摘

手把手 | 用StackOverflow访问数据实现主成分分析(PCA)

15970
来自专栏奇点大数据

遗传算法(2)

在遗传算法中我们再举一个求极大值的例子。这种例子也是比较多见的,只要我们把一些数据关系描述成函数之后就会有一些求极大值或者极小值的问题。 其实极大值和极小值是一...

360120
来自专栏WOLFRAM

偶述 Wolfram 中文分词算法

从 2000 年开始学习和使用 Mathematica,《Mathematica 演示项目笔记》作者,发表Wolfram Demonstrations Proj...

18120
来自专栏大数据挖掘DT机器学习

利用主成分分析构建股票指数

作者:谢佳标 中国R语言大会讲师,高级数据分析师,8年以上数据挖掘建模工作实战经验 https://ask.hellobi.com/blog/xiejiabi...

30590
来自专栏数据科学与人工智能

【机器学习】机器学习大白话

买芒果 嘴馋的你想吃芒果了,于是你走到水果摊,挑了几个让老板过过秤,然后你再根据芒果的斤两付钱走人。 显然,买芒果你当然是挑着最甜、最熟的来买(因为你是根据重量...

26150
来自专栏hadoop学习笔记

Hanlp自然语言处理工具的使用演练

Hanlp是由一系列模型与算法组成的工具包,目标是普及自然语言处理在生产环境中的应用。Hanlp具备功能完善、性能高效、架构清洗、语料时新、可自定义的特点;提供...

20620
来自专栏大数据文摘

机器学习单挑数学界:最新算法仲裁数列之美(附论文)

它揭示了表面看似无关的数学领域之间的深层联系,是数学界的伟大奇观之一。而这也指出了数学之美的另一个组成部分:数学模式必须在某种角度上是有趣的。

11340

扫码关注云+社区

领取腾讯云代金券