//
import render.*;
public class Actor extends Geometry
{
static public void clearActors() { nActors = 0; }
//----- STUFF THAT'S UNIQUE TO EACH INDIVIDUAL Actor
// CONSTRUCTOR
public Actor() {
index = nActors++;
}
public Actor setSize(double X, double Y, double Z) {
sizeX = X; sizeY = Y; sizeZ = Z; setP(); return this;
}
public Actor setSize(double Size) {
sizeX = sizeY = sizeZ = Size; setP(); return this;
}
public Actor setPosition(double X, double Z) {
x = X; z = Z; setP(); return this;
}
public Actor setGaze(Geometry g) {
Matrix m = g.getMatrix();
return setGaze(m.get(0,3),m.get(1,3),m.get(2,3));
}
public Actor setGaze(double X, double Y, double Z) {
gx = X;
gy = Y;
gz = Z;
return this;
}
public Actor setGazeWeight(double W) {
gw_target = W;
return this;
}
public Actor setDirection(double Theta) {
theta = Theta; return this;
}
public Actor avoidActors(boolean state) {
avoidingActors = state; return this;
}
public Actor avoidWalls(boolean state) {
avoidingWalls = state; return this;
}
public Actor setThrottle(double t) {
throttle = t; return this;
}
void setP() {
p[index][AX] = p[index][BX] = x;
p[index][AZ] = p[index][BZ] = z;
p[index][SIZE] = sizeZ;
}
// ANIMATE ONE FRAME
public void animate(double time) {
// COMPUTE ELAPSED TIME SINCE LAST FRAME
if (prevTime == 0) prevTime = time - 1;
elapsed = time - prevTime;
prevTime = time;
// SMOOTH OUT TIME-VARYING CONTROL PARAMETERS
gw = smooth(gw, gw_target);
// TRAVEL FORWARD
double travel = sizeZ * getTravel(elapsed);
double tz = travel * Math.cos(theta);
double tx = travel * Math.sin(theta);
x += tx * throttle;
z += tz * throttle;
setP();
p[index][BX] = x + tx * throttle;
p[index][BZ] = z + tz * throttle;
// TURN AWAY FROM OBSTACLES
double R = repulse(x,z,sizeZ,index);
if (R > 0) {
double Rx = (repulse(x+.01,z,sizeZ,index) - R) / .01;
double Rz = (repulse(x,z+.01,sizeZ,index) - R) / .01;
if (Rx*tx > -Rz*tz) // IF FACING WALL
theta += Rx*tz < Rz*tx ? R : -R; // TURN MORE AWAY
}
// SET TRANSLATION, ROTATION AND SCALE
matrix.identity();
matrix.translate(x,0,z);
matrix.rotateY(Math.PI + theta);
matrix.scale(sizeX,sizeY,sizeZ);
}
double smooth(double t, double target) {
return lerp(2 * elapsed, t, target);
}
// COMPUTE HOW FAR FORWARD ACTOR TRAVELS IN A SMALL TIME INTERVAL
public double getTravel(double elapsed) { return 0; }
// INSTANCE DATA
int index;
double elapsed=0, prevTime=0, x=0, z=0, theta=0, sizeX=1, sizeY=1, sizeZ=1;
double gx=0, gy=0, gz=0, gw=0; // GAZE X,Y,Z,WEIGHT
double gw_target=0;
boolean avoidingActors = true, avoidingWalls = true;
double throttle = 1;
//----- DEFINING STATIC WALLS IN THE SCENE FOR ALL ACTORS TO AVOID
// ADD A WALL, OR CLEAR ALL WALLS
static public void addWall(double wall[]) { w[nWalls++] = wall; }
static public void clearWalls() { nWalls = 0; }
double repulse(double x, double z, double size, int index) {
double R = 0;
// REPULSION FROM ALL WALLS
if (avoidingWalls)
for (int i = 0 ; i < nWalls ; i++) {
int n = w[i].length/2 - 1;
for (int j = 0 ; j < n ; j++)
R += repulse(w[i][2*j ]-x, w[i][2*j+1]-z,
w[i][2*j+2]-x, w[i][2*j+3]-z, j==0, j==n-1, size);
}
// REPULSION FROM OTHER POLLYS
if (avoidingActors)
for (int i = 0 ; i < nActors ; i++)
if (i != index)
R += repulse(p[i][AX]-x,p[i][AZ]-z,
p[i][BX]-x,p[i][BZ]-z,true,true,.6*(size+p[i][SIZE]));
return R;
}
// COMPUTE REPULSION FORCE FROM ONE WALL SECTION
static double repulse(double ax,double az,double bx,double bz,
boolean aE,boolean bE, double size) {
// COMPUTE UNIT VECTOR BETWEEN THE WALL'S TWO END POINTS
double dx = bx - ax, dz = bz - az;
if (dx == 0 && dz == 0) dz = .1;
double len = Math.sqrt(dx*dx + dz*dz);
dx /= len;
dz /= len;
// REPULSION DROPS OFF WITH DISTANCE AWAY FROM PLANE OF WALL
double t = ax * dz - az * dx;
t = Math.max(0, 2.2*size - Math.abs(t)) / (2.2*size);
// REPULSION ALSO DROPS OFF AT THE TWO ENDS OF THE WALL
return t*t * Math.max(0,Math.min(1, (aE?1:.5) - .5*(ax*dx + az*dz))) *
Math.max(0,Math.min(1, (bE?1:.5) + .5*(bx*dx + bz*dz))) ;
}
static double lerp(double t, double a, double b) { return a + t * (b - a); }
// STATIC DATA
static int nWalls = 0;
static double w[][] = new double[100][];
final static int AX=0,AZ=1,BX=2,BZ=3,SIZE=4;
static int nActors = 0;
static double p[][] = new double[100][5];
}