?? unit.java
字號:
/*
Netwar
Copyright (C) 2002 Daniel Grund, Kyle Kakligian, Jason Komutrattananon, & Brian Hibler.
This file is part of Netwar.
Netwar is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
Netwar is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Netwar; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package netwar.game;
import java.awt.*;
import netwar.utils.Assert;
/** Abstract class which defines a mobile GameObject.
* This provides default implementation of the following behaviors:
* <BR> Guard mode in which the Unit scans for nearby enemies.
* <BR> Move mode in which the Unit tries to reach a particular Hex.
* <BR> Pursuit mode in which the Unit moves toward a particular GameObject,
* up to a range less than the weapon range, and fires repeatedly if that
* GameObject is a damagable object which is not part of the same team.
* <BR> Receiving damage using the standard health/armor model.
* <BR> Navigating obstacles using a simple alternate direction system.
* @author Group N2 - Project Netwar
* @author Daniel Grund
*/
public abstract class Unit extends GameObject {
/** A value indicating the amount of damage still needed to destroy this Unit. */
protected int health = maxHealth();
/** A value indicating the number of frames to remain paralyzed. */
protected int stun = 0;
/** A code number indicating the direction that the Unit is facing */
protected int f = 4;
//Adjacent hex reservation data
/** X part of the Hex coord reserved for this Unit to move into another Hex. */
protected int resX;
/** Y part of the Hex coord reserved for this Unit to move into another Hex. */
protected int resY;
/** The facing this Unit should have when moving into the reserved Hex. */
protected int resF;
/** True if the Unit has a Hex reserved to move into. */
protected boolean reserved = false;
//If traceMode = 0, use classic pathfinding intelligence.
//If traceMode = 1, use Keep-Obstacles-On-Your-Right mode.
//If traceMode = -1, use Keep-Obstacles-On-Your-Left mode.
private int traceMode = 0;
private boolean validSubPlan = false;
private int subPlanDirection;
private int subPlanBias;
/** Sets the facing of the Unit when it is created */
protected void param(int p) {
f = p;
resX = x;
resY = y;
}
//Default setGoal()s for a mobile Unit.
/** Sets the unit to Guard Mode */
public void setGoal() {
//Set to 0 (remain stationary)
mode = 0;
traceMode = 0;
}
/** Sets the unit to Move Mode
* @param gx The X part of the Hex coordinate to move to.
* @param gy The Y part of the Hex coordinate to move to.
*/
public void setGoal(int gx, int gy) {
//Set to 1 (go to destination)
mode = 1;
traceMode = 0;
goalX = gx;
goalY = gy;
}
/** Sets the Unit to Pursuit Mode
* @param u The GameObject to approach/pursue and attack (if not an ally).
*/
public void setGoal(GameObject u) {
//Set to 2 (pursue target)
mode = 2;
traceMode = 0;
target = u;
targetSSMDS = firstSSMDS.getTarget(this, target);
goalX = u.x;
goalY = u.y;
}
//Default update for a mobile unit.
/** Called once per time-step to perform necessary processing.
* Provides default logic to determine what animation is in place,
* fire a weapon if possible, etc.
*/
protected void update() {
if(isDead()) {
animateDie();
return;
}
if(stun > 0) {
stun--;
return;
}
//Firing logic.
if(reload > 0) {
reload--;
aim();
}else{
if(aim())
{
if(targetSSMDS.getDistanceSquared() <= weaponRangeSquared()) {
if(fire())
reload = weaponDelay();
}
}
}
if(frame == 0) { //AI decision frame.
if(!reserved) {
//Don't know where I'm going, so I'd better think
think(); //separate function for subclasses to overload
}
//If I know where I'm going next, I'll go.
if(reserved) //Reserved the next hex already, check if I can move.
{
if(resF == f) //facing toward the hex. Now just wait for the unit to move.
{
if(Hex.getHex(resX, resY).isEmpty()) {
action = 3; frame = framesToMove();
}else //Wait for the hex to be clear.
action = 0;
}else{ //need to rotate toward the destination.
if((resF - f > 0 && resF - f < 3) || resF - f < -3){
//rotate left
action = 1; frame = framesToRotate();
}else{
//rotate right
action = 2; frame = framesToRotate();
}
}
}
}
switch(action)
{
case 1: //Turn left
animateRotateLeft();
frame--;
if(frame == 0)
f++;
if(f == 6) f = 0;
break;
case 2: //Turn right
animateRotateRight();
frame--;
if(frame == 0)
f--;
if(f == -1) f = 5;
break;
case 3: //Move forward
animateMove();
if(firstSSMDS != null){
//Update SSMDSs for this unit. Note, that this is not simple because the things reorder themselves when updated.
SelfSortingMutualDistanceSquared ssmds[] = new SelfSortingMutualDistanceSquared[GameObjects.getLength() - 1];
if(ssmds.length > 0) {
int i = 0;
SelfSortingMutualDistanceSquared curr = firstSSMDS;
for(; i < ssmds.length; i++)
{
ssmds[i] = curr;
curr = curr.getNext(this);
}
for(i = 0; i < ssmds.length; i++)
{
ssmds[i].update();
}
}
}
frame--;
if(frame == 0) {
Hex.getHex(x,y).leave(this);
switch(f)
{
case 0: x++; y++; break;
case 1: y++; break;
case 2: x--; break;
case 3: x--; y--; break;
case 4: y--; break;
case 5: x++; break;
}
Hex.getHex(x,y).enter(this);
reserved = false; //Remember: The hex I am in is still reserved for me.
confirmSubPlan(goalX, goalY);
if(mode == 1 && x == goalX && y == goalY)
mode = 0;
think(); //Try to decide on a new space to be in, so this one can be unreserved.
}
break;
case 4: //Making
animateMake();
frame--;
break;
default:
frame = 0;
}
}
/** Returns the facing code for the 'best' direction to head.
* Assumes the Unit is going from its current location to (gx, gy)
* with no obstacles in between. Other code will adjust for obstacles.
* @param gx The x part of the destination hex coordinate.
* @param gy The y part of the destination hex coordinate.
* @return The idealized facing code.
*/
protected int bestDirection(int gx, int gy){
int dxy;
if(validSubPlan)
return subPlanDirection;
gx -= x;
gy -= y;
dxy = gx - gy;
if(gx == 0) {//Goal is vertically aligned.
if(gy == 0) { //Already at goal.
subPlanDirection = f;
subPlanBias = 1;
}else if(gy < 0) { //Goal is south (facing 4)
subPlanDirection = 4;
subPlanBias = 1;
}else{ //Goal is north (facing 1)
subPlanDirection = 1;
subPlanBias = 1;
}
}else if(gx > 0) {//Goal is somewhere to the east.
if(gy == 0) { //Goal is south-east (facing 5)
subPlanDirection = 5;
subPlanBias = 1;
}else if(gy < 0) { //Goal is between facings 4 and 5
if(gx > -1 * gy) { //Goal is closer to facing 5
subPlanDirection = 5;
subPlanBias = -1;
}else{
subPlanDirection = 4;
subPlanBias = 1;
}
}else{ //Goal is between facings 5 and 1. First compare against facing 0.
if(dxy == 0) { //Goal is north-east (facing 0)
subPlanDirection = 0;
subPlanBias = 1;
}else if(dxy < 0) { //Goal is between facings 0 and 1
if(gy > 2 * gx) { //Goal is closer to facing 1
subPlanDirection = 1;
subPlanBias = -1;
}else{
subPlanDirection = 0;
subPlanBias = 1;
}
}else{ //Goal is between facings 5 and 0
if(gx > 2 * gy) { //Goal is closer to facing 5
subPlanDirection = 5;
subPlanBias = 1;
}else{
subPlanDirection = 0;
subPlanBias = -1;
}
}
}
}else{ //Goal is somewhere to the west.
if(gy == 0) { //Goal is north-west (facing 2)
subPlanDirection = 2;
subPlanBias = 1;
}else if(gy > 0) { //Goal is between facings 1 and 2
if(gy > -1 * gx) { //Goal is closer to facing 1
subPlanDirection = 1;
subPlanBias = 1;
}else{
subPlanDirection = 2;
subPlanBias = -1;
}
}else{ //Goal is between facings 2 and 4. First compare against facing 3.
if(dxy == 0) { //Goal is south-west (facing 3)
subPlanDirection = 3;
subPlanBias = 1;
}else if(dxy > 0) { //Goal is between facings 3 and 4
if(gy < 2 * gx) { //Goal is closer to facing 4
subPlanDirection = 4;
subPlanBias = -1;
}else{
subPlanDirection = 3;
subPlanBias = 1;
}
}else{ //Goal is between facings 2 and 3
if(gx < 2 * gy) { //Goal is closer to facing 2
subPlanDirection = 2;
subPlanBias = 1;
}else{
subPlanDirection = 3;
subPlanBias = -1;
}
}
}
}
validSubPlan = true;
return subPlanDirection;
}
/** Checks to make sure that the idealized direction to get to the destination is still good.
* If the previously calculated best direction would no longer cause the Unit to get
* closer to its destination, a flag is set to calculate a new direction the next time
* the direction is checked.
* @param gx The (updated) x part of the goal hex coordinate.
* @param gy The (updated) y part of the goal hex coordinate.
*/
protected void confirmSubPlan(int gx, int gy) {
//Used when either the goal changes, or the unit moves.
//Makes sure the current subPlan direction still makes sense.
//If not, invalidate it so that it will be recalculated.
int dxy;
gx -= x;
gy -= y;
dxy = gx - gy;
switch(subPlanDirection) {
case 0:
if(gx <= 0 || gy <= 0) validSubPlan = false;
break;
case 1:
if(gy <= 0 || dxy >= 0) validSubPlan = false;
break;
case 2:
if(dxy >= 0 || gx >= 0) validSubPlan = false;
break;
case 3:
if(gx >= 0 || gy >= 0) validSubPlan = false;
break;
case 4:
if(gy >= 0 || dxy <= 0) validSubPlan = false;
break;
case 5:
if(dxy <= 0 || gx <= 0) validSubPlan = false;
break;
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -