[Silverlight动画]转向行为 - 避开行为

 

避开行为与寻找行为彻底相反。实际上,除了代码最后一行用相减代替了相加以外,其它都一样。
public void flee(Vector2D target) {
    Vector2D desiredVelocity = target.subtract(_postion);
    desiredVelocity.normalize();
    desiredVelocity = desiredVelocity.multiply(_maxSpeed);
    Vector2D force = desiredVelocity.subtract(_velocity);
    _steeringForce = _steeringForce.subtract(force);
}
由于和寻找几乎一样,所以就不详细解释了。最后一句的含义是“很好,既然发现了目标,那就调头往回走吧。”在此为避开做一个简单的测试:
<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"
	mc:Ignorable="d"
	x:Class="Steer.FleeTest"
	d:DesignWidth="640" d:DesignHeight="480">

	<Grid x:Name="LayoutRoot" Background="White">
		<local:SteeredVehicle x:Name="myStar" HorizontalAlignment="Left" Height="40" VerticalAlignment="Top" Width="40" RenderTransformOrigin="0.5,0.5">
			<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>
	</Grid>
</UserControl>
	public partial class FleeTest : UserControl
    {
        double mouseX = 0;
        double mouseY = 0;
		public FleeTest()
		{
			// Required to initialize variables
            InitializeComponent();
            Loaded += new RoutedEventHandler(SeekTest_Loaded);
        }

        void SeekTest_Loaded(object sender, RoutedEventArgs e)
        {
            myStar.position = new Vector2D(100, 100);
            myStar.edgeBehavior = Vehicle.BOUNCE;
            myStar.velocity.length = 5;
            myStar.velocity.angle = Math.PI / 4;

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

        void CompositionTarget_Rendering(object sender, EventArgs e)
        {
            myStar.flee(new Vector2D(mouseX, mouseY));
            myStar.update();
        }

        void SeekTest_MouseMove(object sender, MouseEventArgs e)
        {
            mouseX = e.GetPosition(null).X;
            mouseY = e.GetPosition(null).Y;
        }
    }
抛开代码中调用的函数名称不谈,最主要的不同是,用两行代码将机车的初始位置放在离场景边缘有一段距离的地方,并且把接触场景边缘后的反应改为反弹。删除这两行再测试,就知道为什么要加这两行了。机车会为了避开鼠标在角落间来回切换,导致近似看不见。
现在我们有了一对正反行为,接下来要做的是为这对行为创建一对机车来看看情况。
<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"
	mc:Ignorable="d"
	x:Class="Steer.SeekFleeTest1"
	d:DesignWidth="640" d:DesignHeight="480">

	<Grid x:Name="LayoutRoot" Background="White">
		<local:SteeredVehicle x:Name="mySeek" HorizontalAlignment="Left" Height="40" VerticalAlignment="Top" Width="40" RenderTransformOrigin="0.5,0.5" Margin="84,50,0,0">
			<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="myflee" HorizontalAlignment="Left" Height="40" VerticalAlignment="Top" Width="40" RenderTransformOrigin="0.5,0.5">
			<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>
	</Grid>
</UserControl>
	public partial class SeekFleeTest1 : UserControl
	{
		public SeekFleeTest1()
		{
			// Required to initialize variables
            InitializeComponent();
            Loaded += new RoutedEventHandler(SeekTest_Loaded);
        }

        void SeekTest_Loaded(object sender, RoutedEventArgs e)
        {
            mySeek.position = new Vector2D(200, 200);
            mySeek.edgeBehavior = Vehicle.BOUNCE;

            myflee.position = new Vector2D(100, 300);
            myflee.edgeBehavior = Vehicle.BOUNCE;

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

        void CompositionTarget_Rendering(object sender, EventArgs e)
        {
            mySeek.seek(myflee.position);
            myflee.flee(mySeek.position);
            mySeek.update();
            myflee.update();
        }
	}
这对机车叫寻找者(_seeker)和避开者(_fleer)。我相信不用再解释寻找者寻找避开者,避开者避开寻找者了吧。先运行一下看看两辆机车互动的效果,然后尝试改变它们的各种参数,再看看会发生什么。
我们还可以把两个行为同时用于一辆机车上。下面的例子中,机车A同时寻找和避开机车B,机车B同时寻找和避开机车C,机车C同时的寻找和避开机车A。这三辆机车会因为追捕各自的目标而形成一个圆。
<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"
	mc:Ignorable="d"
	x:Class="Steer.SeekFleeTest2"
	d:DesignWidth="640" d:DesignHeight="480">

	<Grid x:Name="LayoutRoot">
		<local:SteeredVehicle x:Name="myA" HorizontalAlignment="Left" Height="40" VerticalAlignment="Top" Width="40" RenderTransformOrigin="0.5,0.5">
			<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="myB" HorizontalAlignment="Left" Height="40" VerticalAlignment="Top" Width="40" RenderTransformOrigin="0.5,0.5">
			<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="myC" HorizontalAlignment="Left" Height="40" VerticalAlignment="Top" Width="40" RenderTransformOrigin="0.5,0.5">
			<ed:RegularPolygon Fill="#FFCEFF00" 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>
	</Grid>
</UserControl>
	public partial class SeekFleeTest2 : UserControl
	{
		public SeekFleeTest2()
		{
			// Required to initialize variables
            InitializeComponent();
            Loaded += new RoutedEventHandler(SeekTest_Loaded);
		}
        void SeekTest_Loaded(object sender, RoutedEventArgs e)
        {

            myA.position = new Vector2D(200, 200);
            myA.edgeBehavior = Vehicle.BOUNCE;
            myB.position = new Vector2D(400, 200);
            myB.edgeBehavior = Vehicle.BOUNCE;
            myC.position = new Vector2D(300, 260);
            myC.edgeBehavior = Vehicle.BOUNCE;

            CompositionTarget.Rendering += new EventHandler(CompositionTarget_Rendering);
        }
        void CompositionTarget_Rendering(object sender, EventArgs e)
        {
            myA.seek(myB.position);
            myA.flee(myC.position);

            myB.seek(myC.position);
            myB.flee(myA.position);

            myC.seek(myA.position);
            myC.flee(myB.position);

            myA.update();
            myB.update();
            myC.update();
        }
	}
记得再试试改变各种参数,观察发生的变化。如果这些都没问题了,那就开始探索下一个行为:到达。
posted @ 2010-06-23 00:41 王喆(nasa) 阅读(...) 评论(...) 编辑 收藏