📄 pathfollower.java
字号:
yPosition = (float) nextPoint.y;
orientationAngle = nextAngle;
// if this is a recreated trajectory do we have to turn to get the right
// final orientation ?
if(useEndingOrientationValue && realisticRotations) {
nextAngle = (float) endingOrientation;
turningAlongPath = true;
return;
}
useEndingOrientationValue=false;
stopMovement();
return;
}
// Next Point reached...
prevPoint = getPosition();
nextPoint = (Point) path.elementAt( pathIndex );
updateAngularNode();
}
}
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
// MOVEMENT CONTROL
/** To set a player's movement : movement from current position to the given point.
*/
public void moveTo( Point endPosition, WorldManager wManager ) {
// Test if xPosition,yPosition is a valid point
Point startPt = new Point( (int)xPosition, (int)yPosition );
if ( !AStarDouble.isValidStart(startPt) ) {
Debug.signal(Debug.WARNING,this,"PathFollower : invalid start point");
// We reset the position
WotlasLocation location = player.getLocation();
// We search for a valid insertion point
ScreenPoint pReset = null;
if ( location.isRoom() )
pReset = player.getMyRoom().getInsertionPoint();
else {
if ( location.isTown() ) {
TownMap myTown = wManager.getTownMap( location );
if (myTown!=null)
pReset = myTown.getInsertionPoint();
}
else if ( location.isWorld() ) {
WorldMap myWorld = wManager.getWorldMap( location );
if (myWorld!=null)
pReset = myWorld.getInsertionPoint();
}
}
if (pReset==null) {
pReset = new ScreenPoint(0, 0);
Debug.signal(Debug.CRITICAL,this,"Could not find a valid start point !");
} else
Debug.signal(Debug.NOTICE,this,"Found a new valid start point...");
player.setX(pReset.x);
player.setY(pReset.y);
startPt.x = pReset.x;
startPt.y = pReset.y;
}
path = findPath( startPt, new Point( endPosition.x, endPosition.y ),player.getLocation().isRoom() );
if( path==null ) {
if( walkingAlongPath )
stopMovement(); // a message is sent : we were moving...
else
resetMovement(); // no message sent : we were already still...
return; // no movement
}
updateMovementAspect();
initMovement( path );
if(player.isMaster())
player.sendMessage( new PathUpdateMovementMessage( this, player.getPrimaryKey(), player.getSyncID() ) );
}
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
/** To rotate the player on itself.
* @param finalOrientation final orientation to reach
*/
public void rotateTo( double finalOrientation ) {
orientationAngle = finalOrientation;
if( player.isMaster() )
player.sendMessage( new PathUpdateMovementMessage( this, player.getPrimaryKey(), player.getSyncID() ) );
}
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
/** To recreate a trajectory from a dest. point & a DeltaTime.
*/
public void recreateTrajectory( Point pDst, int movementDeltaTime ) {
path = findPath( new Point( (int)xPosition, (int)yPosition ),
new Point( pDst.x, pDst.y ), player.getLocation().isRoom() );
if( path==null ) {
Debug.signal( Debug.ERROR, this, "Failed to re-create path !" );
if(player.isMaster())
stopMovement();
else
resetMovement();
return;
}
updateMovementAspect();
if(movementDeltaTime>500)
initMovement( path, movementDeltaTime );
else
initMovement( path );
}
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
/** Initialize a path movement from the start. This is the most method you should
* use the most. This method modifies the entire state of the PathFollower.
* To test if the movement is finished, call the isMoving method after each tick.
*
* @param path a valid path returned by the Astar algorithm.
*/
synchronized public void initMovement( List path ) {
// 1 - Control
if( path==null || path.size()<1 ) {
Debug.signal(Debug.ERROR, this, "Invalid Path !!!! "+path);
return;
}
// 2 - Path Inits
this.path = path;
pathIndex = 1;
lastUpdateTime = System.currentTimeMillis();
movementTimeStamp = lastUpdateTime;
prevPoint = getPosition();
nextPoint = (Point) path.elementAt(pathIndex);
updateAngularNode();
// 3 - We validate the movement...
walkingAlongPath = true;
}
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
/** Given a path followed by a player (1) and an elapsed time since the movement begun (2)
* we initialize our path movement at the computed "current" position.
*
* The "current" position is totaly dependent from the speed at which we move. So be
* sure to correctly initialize the PathFollower's speed BEFORE calling this method.
*
* @param path current path followed by a player.
* @param deltaTime deltaTime in ms since the player begun to follow the path (starting
* at the first point given in the path parameter)
*/
synchronized public void initMovement( List path, int deltaTime ) {
// 1 - Control
if(path==null || path.size()<1 ) {
resetMovement();
Debug.signal(Debug.ERROR, this, "Invalid Path !!!! "+path);
return;
}
if(path.size()==1) {
resetMovement();
return; // no movement
}
this.path = path;
// 2 - Position evaluation
float totalDistance = (deltaTime/1000.0f)*speed;
double d = 0.0f;
Point a0 = null;
Point a1 = (Point)path.elementAt(0);
for( int i=0; i<path.size()-1; i++ ) {
a0 = a1;
a1 = (Point)path.elementAt(i+1);
d += distance( a0, a1 );
// have we found the last point crossed by our entity ?
if( d >= totalDistance ) {
// Path approved !
this.path = path;
pathIndex = i;
orientationAngle = angle( a0, a1 );
xPosition = (float)(a1.x - (d-totalDistance)*Math.cos(orientationAngle) );
yPosition = (float)(a1.y - (d-totalDistance)*Math.sin(orientationAngle) );
prevPoint = a0;
nextPoint = a1; //(Point) path.elementAt(pathIndex);
lastUpdateTime = System.currentTimeMillis();
movementTimeStamp = lastUpdateTime;
updateAngularNode();
// We validate the movement
walkingAlongPath = true;
return;
}
}
// 3 - If we arrive here it means that the movement is over !
// We set the PathFollower state to the end of the path
a0 = (Point)path.elementAt(path.size()-2);
a1 = (Point)path.elementAt(path.size()-1);
orientationAngle = angle( a0, a1 );
xPosition = (float)a1.x;
yPosition = (float)a1.y;
if(player.isMaster())
stopMovement();
else
resetMovement();
}
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
/** To update the angular movement at a Path node.
*/
private void updateAngularNode() {
nextAngle = angle( prevPoint, nextPoint );
angularDirection = 1;
while( nextAngle-orientationAngle > Math.PI )
nextAngle = (float)(nextAngle-2*Math.PI);
while( nextAngle-orientationAngle < -Math.PI )
nextAngle = (float)(nextAngle+2*Math.PI);
if( orientationAngle > nextAngle )
angularDirection = -1;
if (realisticRotations)
turningAlongPath = true; // we will turn progressively, using the angularSpeed
else {
turningAlongPath = false;
orientationAngle = nextAngle; // We update the angle right now
}
}
/*------------------------------------------------------------------------------------*/
/** Helper. Returns the distance between two points
* @param a first point
* @param b second point
* @return distance between the two points.
*/
public static float distance( Point a, Point b ) {
if(a==null || b==null) return 0f;
return (float) Math.sqrt( (b.y-a.y)*(b.y-a.y)+(b.x-a.x)*(b.x-a.x) );
}
/*------------------------------------------------------------------------------------*/
/** Helper. Returns the angle between the given line and the horizontal.
* @param first point of the line
* @param second point of the line
* @return angle in radian in the [-pi,pi] range.
*/
public static float angle( Point a, Point b ) {
if(b.x==a.x) {
if(b.y>a.y) return (float) Math.PI/2;
else if (b.y<a.y) return (float) -Math.PI/2;
return 0.0f;
}
float angle = (float) Math.atan( (double)(b.y-a.y)/(b.x-a.x) );
if(b.x<a.x) {
if(angle>=0) return (float) ( angle-Math.PI );
if(angle<0) return (float) ( angle+Math.PI );
}
return angle;
}
/*------------------------------------------------------------------------------------*/
/** write object data with serialize.
*/
public void writeExternal(java.io.ObjectOutput objectOutput)
throws java.io.IOException {
objectOutput.writeInt( ExternalizeGetVersion() );
objectOutput.writeFloat( xPosition );
objectOutput.writeFloat( yPosition );
objectOutput.writeLong( movementTimeStamp );
objectOutput.writeBoolean( walkingAlongPath );
objectOutput.writeDouble( orientationAngle );
}
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
/** read object data with serialize.
*/
public void readExternal(java.io.ObjectInput objectInput)
throws java.io.IOException, java.lang.ClassNotFoundException {
int IdTmp = objectInput.readInt();
if( IdTmp == ExternalizeGetVersion() ){
xPosition = objectInput.readFloat();
yPosition = objectInput.readFloat();
movementTimeStamp = objectInput.readLong();
walkingAlongPath = objectInput.readBoolean();
orientationAngle = objectInput.readDouble();
} else {
// to do.... when new version
}
}
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
/** id version of data, used in serialized persistance.
*/
public int ExternalizeGetVersion(){
return 1;
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -