[Silverlight动画]转向行为 - 追捕行为

对于追捕行为,它非常类似寻找行为。其实追捕的最后一个动作就是调用寻找。追捕的本质是预测目标所要到达的位置并事先赶到。

那么,该如何预测目标的位置呢?其实是以目标的当前速度不变为前提,算出未来一段时刻后目标所在的位置。但是需要计算多久的未来才合适呢?我们把这 段时间叫做预测时间(look ahead time)。如果算到很久以后(较长的预测时间)可能就会超越目标,如果只往后算一点点(较短的预测时间)可能仍然落后于目标。而实际上,寻找行为就是一个预测时间为零的追捕行为。
一个策略是基于两机车间的距离来判断预测时间。如果目标太远,需要花一段时间才能赶上,就预测长一点,如果很接近,马上就能达到,就预测短一点。把这个技术用于转向机车,就像这样:
        public void pursue(Vehicle target) {
            double lookAheadTime = position.dist(target.position) / _maxSpeed;
            Vector2D predictedTarget = target.position.add(target.velocity.multiply(lookAheadTime));
            seek(predictedTarget);
        }

首先通过两者间距离除以最大速率计算出预测时间。这就得到了追上目标所需要的时间间隔(假设目标不再移动)。通过目标的速度乘以时间间隔得到预测移动距离,再加到当前位置上就是预测位置。最后,把这个预测位置作为寻找点。

 

测试一下。这次要创建三辆机车。一个是只顾移动的机车,其作为目标,另外两个转向机车,一个用寻找行为,一个用追捕行为。如果一切正常,追捕者靠着优越的算法会胜出。 

<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.PursueTest"
    mc:Ignorable="d"
    d:DesignHeight="300" d:DesignWidth="400">
    
    <Grid x:Name="LayoutRoot" Background="White">

    	<local:SteeredVehicle x:Name="mySeeker" HorizontalAlignment="Left" Height="40" VerticalAlignment="Top" Width="40" RenderTransformOrigin="0.5,0.5" d:IsHidden="True">
    		<ed:RegularPolygon Fill="#FFFF0C00" Height="40" InnerRadius="1" PointCount="3" Stretch="Fill" Stroke="Black" UseLayoutRounding="False" Width="40" RenderTransformOrigin="0.5,0.5" StrokeThickness="0">
    			<ed:RegularPolygon.RenderTransform>
    				<CompositeTransform Rotation="90"/>
    			</ed:RegularPolygon.RenderTransform>
    		</ed:RegularPolygon>
    	</local:SteeredVehicle>
    	<local:SteeredVehicle x:Name="myPursuer" HorizontalAlignment="Left" Height="40" VerticalAlignment="Top" Width="40" RenderTransformOrigin="0.5,0.5" d:IsHidden="True">
    		<ed:RegularPolygon Fill="Blue" Height="40" InnerRadius="1" PointCount="3" Stretch="Fill" Stroke="Black" UseLayoutRounding="False" Width="40" RenderTransformOrigin="0.5,0.5" StrokeThickness="0">
    			<ed:RegularPolygon.RenderTransform>
    				<CompositeTransform Rotation="90"/>
    			</ed:RegularPolygon.RenderTransform>
    		</ed:RegularPolygon>
    	</local:SteeredVehicle>
    	<local:SteeredVehicle x:Name="myTarget" HorizontalAlignment="Left" Height="40" VerticalAlignment="Top" Width="40" RenderTransformOrigin="0.5,0.5">
    		<ed:RegularPolygon Fill="#FFFD00FF" Height="40" InnerRadius="1" PointCount="5" Stretch="Fill" Stroke="Black" StrokeThickness="0" UseLayoutRounding="False" Width="40"/>
    	</local:SteeredVehicle>

    </Grid>
</UserControl>

    public partial class PursueTest : UserControl
    {
        public PursueTest()
        {
            InitializeComponent();
            Loaded += new RoutedEventHandler(PursueTest_Loaded);
        }

        void PursueTest_Loaded(object sender, RoutedEventArgs e)
        {
            mySeeker.x = 400;
            myPursuer.x = 400;
            myTarget.position = new Vector2D(200, 100);
            myTarget.velocity.length = 15;
            myTarget.velocity.angle = Math.PI / 4;

            CompositionTarget.Rendering += new EventHandler(CompositionTarget_Rendering);
        }

        void CompositionTarget_Rendering(object sender, EventArgs e)
        {
            mySeeker.seek(myTarget.position);
            mySeeker.update();

            myPursuer.pursue(myTarget);
            myPursuer.update();

            myTarget.update();
        }
    }

两辆转向机车开始于同一起点,但是寻找者向目标当前的位置移动,而追捕者则直接奔向目标的前方来拦截它。
对于这个测试,需要明确一点,有很多潜在的参数值会影响到结果。接下来的行为是:躲避。 
posted @ 2010-06-25 23:26  王喆(nasa)  阅读(1190)  评论(0编辑  收藏  举报