//
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]; }