我有一个池塘,其中的鱼会移动到一个"食物",目前我有问题,使它看起来很现实,当食物被丢弃,所有的鱼移动到它以相同的速度,这是一种"漂移"像汽车漂移,当它接近一个食物,而旋转到它。我可以知道出了什么问题吗?我认为这是因为我施加了阻力,但如果我不施加它,vx和vy加起来会很大。
下面的链接包含.swf,我还附加了使鱼移动所需的必要函数。http://www.swfcabin.com/open/1310970656
package
{
import flash.display.MovieClip;
import flash.display.Stage;
import flash.events.Event;
import flash.filters.DropShadowFilter;
import flash.events.TouchEvent;
import flash.media.Sound;
import flash.text.TextField;
import flash.utils.Timer;
import flash.events.TimerEvent;
import flash.geom.Point;
/**
* ...
* @author Z
* Fish class, makes fishes behaviors, find food.
*/
public class Fish extends MovieClip
{
//food var
private var foodTarget:Food;
public var foodDroppedArray:Array = new Array();
public var foodDistArray:Array = new Array();
private var foodInPond :int = 0;
private var foodLocationDegrees:Number;
//fish variables
private var _fishSwimMax:Number = 3;
private var _fishDrag:Number = 0.95;
private var _fishSwimSpeed:Number;
private var _destinationX:int;
private var _destinationY:int;
private var _minX:Number = 0;
private var _minY:Number = 0;
private var _maxX:Number = 1024;
private var _maxY:Number = 768;
private var _vx:Number = 0;
private var _vy:Number = 0;
private var _dx:Number = 0;
private var _dy:Number = 0;
private var foodropSound:foodSound = new foodSound();
//global
public var otherFishes:Array = new Array();
public var hit :MovieClip;
private var foodRipple:Rippler;
private var _bg:Background;
private var number:Number;
private var _easeSpeed:Number;
public function Fish()
{
foodropSound = new foodSound();
getRandomDestination();
//fish starting settins
this.x = _maxX/2;//Math.random();
this.y = _maxY/2;//Math.random();
_fishSwimSpeed = Math.ceil(Math.random() * 1000) +500;
trace("fish speed "+_fishSwimSpeed);
//set up shadow
setUpShadow();
//adding listener
this.addEventListener(Event.ENTER_FRAME, loop, false, 0, true);
}
public function loop(e:Event):void
{
updateCollision();
//getDistance(this.x - i.x, this.y - i.y)
if(foodDroppedArray.length > 0)
{
moveToFood(getSmallestVal(foodDroppedArray));
trace("moving to smallest distance of all food");
return;
}else
{
swimAround();
}
}
/***
* Fish to move to food with easing.
* */
public function moveToFood(targetFood:Food):void
{
_vx += (targetFood.x - this.x)/_fishSwimSpeed;
_vy += (targetFood.y - this.y) / _fishSwimSpeed;
//food calculations, distance, angle etc
var a:Number = targetFood.x - x;
var b:Number = targetFood.y - y;
var ang:Number = Math.atan2(b, a);
//rotation to food
var foodLoc:Number = (ang * 180 / Math.PI);
var foodFinalLoc:Number = foodLoc - rotation;
if (foodFinalLoc > 180) foodFinalLoc -= 360;
else if (foodFinalLoc < -180) foodFinalLoc += 360;
rotation += foodFinalLoc / 10;
//acceleratin to food
//moving towards food.
_vx *= _fishDrag;
_vy *= _fishDrag;
this.x += _vx;
this.y += _vy;
//removing food when both hit boxes hit
if (hit.hitTestObject(targetFood.hit))
{
foodropSound.play();
foodDroppedArray.splice(foodDroppedArray.indexOf(targetFood), 1);
targetFood.removeSelf();
}
}
/**
* Calculate Position
*/
public function swimAround():void
{
//move to a random destionation point.
_dx = this.x - _destinationX;
_dy = this.y - _destinationY;
// when the fish is near to the distance by * a new dest will be generated.
if (getDistance(_dx, _dy) < 200)
{
getRandomDestination();
}else {
_vx += (_destinationX - this.x) / _fishSwimSpeed;
_vy += (_destinationY - this.y) / _fishSwimSpeed;
//calculation of distance to use for calculation of angle to face to
var a:Number = _destinationX - x;
var b:Number = _destinationY - y;
var ang:Number = Math.atan2(b, a);
//location to face to through the angle calculation.
var targetLoc:Number = (ang * 180 / Math.PI);
var finalRoc:Number = targetLoc - rotation;
if (finalRoc > 180) finalRoc -= 360;
else if (finalRoc < -180) finalRoc += 360;
rotation += finalRoc / 15;
//apply drag then move.
_vx *= _fishDrag;
_vy *= _fishDrag;
this.x += _vx;
this.y += _vy;
}
}
public function foodDropped(foodArray:Array):void
{
foodDroppedArray = foodArray;
trace("food have been dropped and lenghth is "+foodDroppedArray.length);
}
/**
*Get smallest value of food distance in this array
*/
private function getSmallestVal(a:Array):Food
{
//we assume first food is the smallest distance between fish
var n : Food = a[0];
if (a.length == 1)
{
return a[0];
}
else {
for each(var i : Food in a)
{
if (getDistance(this.x - i.x , this.y - i.y) < getDistance(this.x - n.x , this.y - n.y))
{
n = i;
}
}
return n;
}
}
/**
* Get random food
*/
private function getRandomFood():Food
{
var i: int = foodDroppedArray.length;
var n : Number = Math.ceil(i * Math.random()) - 1;
trace(" in random food "+n );
return foodDroppedArray[n];
}
/**
* Calculates a random destination based on stage size
*/
private function getRandomDestination():void
{
_destinationX = (Math.random()* _maxX);
_destinationY = (Math.random() * _maxY);
}
public function getDistance(delta_x:Number, delta_y:Number):Number
{
return Math.sqrt((delta_x*delta_x)+(delta_y*delta_y));
}
}
}
一个简单的解决方案是给每条鱼一个最大速度值,使用到达函数找到鱼所需的速度向量,然后在向量大于最大加速度时将其归一化。
将此应用到你的moveToFood方法中,看起来像这样:
// Deceleration Modifier, determines how fast a fish will slow before reaching target
static private const _DECELERATION_FACTOR:Number = 0.3;
private var _fishMaxSpeed:Number = 2;
private var _speedVector:Point = new Point();
public function moveToFood( targetFood:Food ):void
{
// Calculate fish's desired speed with arrive behavior
_speedVector.x = (targetFood.x - this.x) * _DECELERATION_FACTOR;
_speedVector.y = (targetFood.y - this.y) * _DECELERATION_FACTOR;
// Make sure speed isn't larger than fish's max speed
if ( _speedVector.length > _fishMaxSpeed ) {
_speedVector.normalize( _fishMaxSpeed );
}
//food calculations, distance, angle etc
var a:Number = targetFood.x - x;
var b:Number = targetFood.y - y;
var ang:Number = Math.atan2(b, a);
//rotation to food
var foodLoc:Number = (ang * 180 / Math.PI);
var foodFinalLoc:Number = foodLoc - rotation;
if (foodFinalLoc > 180) foodFinalLoc -= 360;
else if (foodFinalLoc < -180) foodFinalLoc += 360;
rotation += foodFinalLoc / 10;
//moving towards food
_vx = _speedVector.x;
_vy = _speedVector.y;
this.x += _vx;
this.y += _vy;
//removing food when both hit boxes hit
if (hit.hitTestObject(targetFood.hit))
{
foodropSound.play();
foodDroppedArray.splice(foodDroppedArray.indexOf(targetFood), 1);
targetFood.removeSelf();
}
}
你可以修改减速因子常数来获得不同的到达行为(甚至可能给每条鱼一个不同的行为),你也可以随机化每条鱼的最大速度。
带着加速度向物体移动是相当棘手的。这个解决方案意味着你可以完全忽略朝向食物移动时的加速度和阻力,这看起来也不太好。也许这和加速行为的组合将是最好的解决方案。