package creeper_Behavior_P3_2_3D_SET3;
import processing.core.*;
import java.util.ArrayList;
import java.util.List;
import toxi.color.*;
import java.util.Random;
import creeper_Behavior_P3_2_3D_SET3.ImprovedPerlinNoise;
public class Creeper {
// Location
public PVector loc;
// Speed
private PVector chaser_speed;
public PVector speed;
// Acceleration
private PVector acc = new PVector();
// Agent Trails
public ArrayList<PVector> creeperTrails;
public List<Creeper> creeperCollection;
public List<List<PVector>> trailData;
public List<List<PVector>> followerTrailData = new ArrayList<List<PVector>>();
public List<ArrayList> followerColorData = new ArrayList<ArrayList>();
public List<ArrayList> trailColors;
public List<Boolean> birthType;
public List<PVector> pvecList;
public List<PVector> copyTrail = new ArrayList<PVector>();;
public float dwidth, ddepth, dheight;
public float searchRad, av, sv, cv;
public float connThresh, connect, max, baseSpeed, modMult;
public boolean swarm, perlin, hybrid, bounds, needsRefresh, applyMap, applyColor, modPerlin, dual, modPerlinHybrid,
modType_0, modType_1, modType_2, modType_3, tailChase, enableInfluencers;
public boolean twoD, threeD, flock_bounds, bounceRebirth, hybrid_bounds, bounce_Spawn;
// ----------------Tail Chaser Variables---------------------
public float tailViewAngle, tailCohMag, tailCohViewRange, tailSepMag, tailSepViewRange;
private PVector tailPerip = new PVector();
private float tailAngle, tailVAngle;
private PVector FutVec;
private PVector FutLocation;
private float futLocMag = 10.0f;
public int Tcount = 0;
public float maxConn, connDist;
public int TStep = 6;
public float maxRepel, maxAttract, rep, att;
public PVector repeller, att_A, att_B;
// ----------------------------------------------------------
public PImage img;
private List<PVector> otherPtsList;
private List<PVector> otherMoveValues;
private List<Float> allDist;
private PVector cummVec, alignVector, separateVector, cohesionVector;
private TColor colorA = TColor.newRGB(255.0f / 255.0f, 0.0f / 255.0f, 0.0f / 255.0f);
private TColor colorB = TColor.newRGB(120.0f, 0.0f, 0.0f);
private TColor colorB2 = TColor.newRGB(0.0f, 255.0f, 255.0f);
private TColor colorC = TColor.newRGB(187.0f / 255.0f, 216.0f / 255.0f, 40.0f / 255.0f);
private ColorGradient gradA = new ColorGradient();
private ColorGradient gradB = new ColorGradient();
private ToneMap toneMapA, toneMapB;
public boolean simulate;
public float strokeWidth, transparency;
public int trailResolution, currentCount;
private float newMap;
public boolean mapAV, mapSV, mapCV, mapPS, mapPSC, mapPM;
// -----Noise Fields-------
public float multiplier, scale, strength, velocity, blend;
private Random r;
// CONSTRUCTOR - INITIALIZE THE CLASS
// -------------------------------------------------------------------------------------
public Creeper(PVector origin, PVector speed, float dwidth, float ddepth) {
this.loc = origin;
this.creeperTrails = new ArrayList<PVector>();
this.speed = speed;
this.dwidth = dwidth;
this.ddepth = ddepth;
this.creeperCollection = new ArrayList<Creeper>();
chaser_speed = speed;
gradA.addColorAt(0.0f, colorA);
gradA.addColorAt(255.0f, colorC);
toneMapA = new ToneMap(0.0f, 1.0f, gradA);
gradB.addColorAt(0.0f, colorB);
gradB.addColorAt(255.0f, colorB2);
toneMapB = new ToneMap(0.0f, 1.0f, gradB);
}
// CONSTRUCTOR - INITIALIZE THE CLASS
// -------------------------------------------------------------------------------------
public Creeper(PVector origin, PVector speed, float dwidth, float ddepth, int dheight) {
this.loc = origin;
this.creeperTrails = new ArrayList<PVector>();
this.speed = speed;
this.dwidth = dwidth;
this.dheight = dheight;
this.ddepth = ddepth;
this.creeperCollection = new ArrayList<Creeper>();
chaser_speed = speed;
gradA.addColorAt(0.0f, colorA);
gradA.addColorAt(255.0f, colorC);
toneMapA = new ToneMap(0.0f, 1.0f, gradA);
gradB.addColorAt(0.0f, colorB);
gradB.addColorAt(255.0f, colorB2);
toneMapB = new ToneMap(0.0f, 1.0f, gradB);
}
// ALL FUNCTIONS
// ---------------------------------------------------------------------------------------------------------
public void action() {
this.r = new Random();
if (this.simulate) {
if (this.swarm) {
if (this.tailChase) {
chaser_speed.limit(this.max);
this.loc.add(this.chaser_speed);
acc = new PVector();
if (this.flock_bounds) {
if (this.bounceRebirth) {
chaser_bounce();
} else {
checkLoc();
}
}
drawChasedTrails();
FutLoc();
getAngle();
if (this.enableInfluencers) {
seek(att_A);
seek(att_B);
repel(repeller);
}
} else {
flocking();
if (this.flock_bounds) {
if (this.bounceRebirth) {
bounce();
} else {
checkLoc();
}
}
this.loc.add(speed);
if (this.twoD) {
this.creeperTrails.add(new PVector(loc.x, loc.y, 0));
} else if (this.threeD) {
this.creeperTrails.add(new PVector(loc.x, loc.y, loc.z));
}
}
}
if (this.perlin || this.modPerlin) {
if (this.modPerlin) {
if (this.modType_0) {
this.scale = GetRandomNumbers(this.scale, this.scale * this.modMult / 2, this.r);
}
if (this.modType_1) {
this.scale = GetRandomNumbers(-this.scale, this.scale * this.modMult, this.r);
}
if (this.modType_2) {
this.strength = GetRandomNumbers(this.strength, this.strength * this.modMult, this.r);
}
}
perlinNoise();
if (this.bounds) {
checkLoc();
}
speed = new PVector();
speed.add(acc);
this.loc.add(speed);
this.creeperTrails.add(new PVector(loc.x, loc.y, loc.z));
acc = new PVector();
}
if (this.hybrid) {
if (this.modPerlinHybrid) {
if (this.modType_0) {
this.scale = GetRandomNumbers(this.scale, this.scale * this.modMult / 2, this.r);
}
if (this.modType_1) {
this.scale = GetRandomNumbers(-this.scale, this.scale * this.modMult, this.r);
}
if (this.modType_2) {
this.strength = GetRandomNumbers(this.strength, this.strength * this.modMult, this.r);
}
}
perlinNoise();
flocking();
if (this.hybrid_bounds) {
if (bounce_Spawn) {
bounce();
} else {
checkLoc();
}
}
speed.add(acc);
speed.limit(this.max);
this.loc.add(speed);
this.creeperTrails.add(new PVector(loc.x, loc.y, loc.z));
acc = new PVector();
}
if (!this.swarm && !this.perlin && !this.hybrid) {
this.acc = new PVector(1.0f, 0, 0);
}
trails();
}
}
private void checkLoc() {
if (this.twoD) {
if (loc.x > dwidth || this.loc.x < 0 || this.loc.y > ddepth || this.loc.y < 0) {
this.needsRefresh = true;
float x = GetRandomNumbers(0.0f, dwidth, this.r);
float y = GetRandomNumbers(0.0f, ddepth, this.r);
this.loc = new PVector(x, y, 0);
this.creeperTrails = new ArrayList<PVector>();
}
} else if (this.threeD) {
if (loc.x > dwidth || this.loc.x < 0 || this.loc.y > ddepth || this.loc.y < 0 || this.loc.z > dheight
|| this.loc.z < 0) {
this.needsRefresh = true;
if (this.birthType.get(1)) {
float x = GetRandomNumbers(0.0f, dwidth, this.r);
float y = GetRandomNumbers(0.0f, ddepth, this.r);
float z = GetRandomNumbers(0.0f, dheight, this.r);
this.loc = new PVector(x, y, z);
} else if (this.birthType.get(2)) {
float x = GetRandomNumbers(0.0f, dwidth, this.r);
float y = GetRandomNumbers(0.0f, ddepth, this.r);
this.loc = new PVector(x, y, 0);
}
this.creeperTrails = new ArrayList<PVector>();
}
}
}
private void chaser_bounce() {
if (this.twoD) {
if (loc.x > dwidth) {
this.chaser_speed.x = this.chaser_speed.x * -1;
}
if (loc.x < 0) {
this.chaser_speed.x = this.chaser_speed.x * -1;
}
if (loc.y > ddepth) {
this.chaser_speed.y = this.chaser_speed.y * -1;
}
if (loc.y < 0) {
this.chaser_speed.y = this.chaser_speed.y * -1;
}
} else if (this.threeD) {
if (loc.x > dwidth) {
this.chaser_speed.x = this.chaser_speed.x * -1;
}
if (loc.x < 0) {
this.chaser_speed.x = this.chaser_speed.x * -1;
}
if (loc.y > ddepth) {
this.chaser_speed.y = this.chaser_speed.y * -1;
}
if (loc.y < 0) {
this.chaser_speed.y = this.chaser_speed.y * -1;
}
if (loc.z > dheight) {
this.chaser_speed.z = this.chaser_speed.z * -1;
}
if (loc.z < 0) {
this.chaser_speed.z = this.chaser_speed.z * -1;
}
}
}
// BOUNCE METHOD
// ------------------------------------------------------------------------------------------------------------
private void bounce() {
if (this.twoD) {
if (loc.x > dwidth) {
speed.x = speed.x * -1;
}
if (loc.x < 0) {
speed.x = speed.x * -1;
}
if (loc.y > ddepth) {
speed.y = speed.y * -1;
}
if (loc.y < 0) {
speed.y = speed.y * -1;
}
} else if (this.threeD) {
if (loc.x > dwidth) {
speed.x = speed.x * -1;
}
if (loc.x < 0) {
speed.x = speed.x * -1;
}
if (loc.y > ddepth) {
speed.y = speed.y * -1;
}
if (loc.y < 0) {
speed.y = speed.y * -1;
}
if (loc.z > dheight) {
speed.z = speed.z * -1;
}
if (loc.z < 0) {
speed.z = speed.z * -1;
}
}
}
private float GetRandomNumbers(double minimum, double maximum, Random r) {
double rX = this.r.nextDouble() * (maximum - minimum) + minimum;
float fX = (float) rX;
return fX;
}
private PVector GetRandomNumber(double minimum, double maximum, Random r) {
PVector rando = new PVector();
double rX = this.r.nextDouble() * (maximum - minimum) + minimum;
double rY = this.r.nextDouble() * (maximum - minimum) + minimum;
double rZ = this.r.nextDouble() * (maximum - minimum) + minimum;
float fX = (float) rX;
float fY = (float) rY;
float fZ = (float) rZ;
rando.x = fX;
rando.y = fY;
if (this.threeD) {
rando.z = fZ;
} else {
rando.z = 0.0f;
}
return rando;
}
private void perlinNoise() {
if (!this.applyMap) {
PVector multSpeed = GetRandomNumber(-this.multiplier, this.multiplier, this.r);
double noiseVal = 1.0;
double noiseValZ = 1.0;
float offset = 0;
float stepOver = 1;
if (this.twoD) {
noiseVal = ImprovedPerlinNoise.noise(this.loc.x / (Float) this.scale, this.loc.y / (Float) this.scale,
0.0) * this.strength;
} else if (this.threeD) {
noiseVal = ImprovedPerlinNoise.noise(this.loc.x / (Float) this.scale, this.loc.y / (Float) this.scale,
this.loc.z / (Float) this.scale) * this.strength;
noiseValZ = ImprovedPerlinNoise.noise(this.loc.x / (Float) this.scale + offset,
this.loc.y / (Float) this.scale, this.loc.z / (Float) this.scale) * this.strength;
}
double angle = noiseVal;
double angleZ = noiseValZ;
PVector dir = new PVector();
if (this.twoD) {
double ddX = Math.cos(angle);
float dX = (float) ddX;
double ddY = Math.sin(angle);
float dY = (float) ddY;
dir = new PVector(dX, dY, 0);
}
if (this.threeD) {
double ddX = Math.cos(angleZ) * Math.cos(angle) * stepOver;
float dX = (float) ddX;
double ddY = Math.sin(angleZ);
float dY = (float) ddY;
double ddZ = Math.cos(angleZ) * Math.sin(angle) * stepOver;
float dZ = (float) ddZ;
dir = new PVector(dX, dY, dZ);
}
if (this.hybrid) {
dir.mult(this.baseSpeed);
} else {
dir.mult(this.velocity);
}
dir.add(multSpeed);
this.acc.add(dir);
} else {
if (this.loc.x <= img.width && this.loc.x >= 0 && this.loc.y >= 0 && this.loc.y <= img.height) {
getColorValue();
} else {
this.newMap = 0;
}
PVector multSpeed;
if (this.mapPM) {
multSpeed = GetRandomNumber(-this.multiplier * this.newMap, this.multiplier * this.newMap, this.r);
} else {
multSpeed = GetRandomNumber(-this.multiplier, this.multiplier, this.r);
}
if (this.mapPSC) {
if (this.newMap == 0.0f) {
this.newMap = 0.1f;
}
this.scale *= this.newMap;
}
if (this.mapPS) {
this.strength *= this.newMap;
}
if (this.mapPS && this.mapPSC) {
this.scale *= this.newMap;
this.strength *= this.newMap;
}
double noiseVal = ImprovedPerlinNoise.noise(this.loc.x / (Float) this.scale,
this.loc.y / (Float) this.scale, 0.0f) * (this.strength);
double angle = noiseVal;
double ddX = Math.cos(angle);
float dX = (float) ddX;
double ddY = Math.sin(angle);
float dY = (float) ddY;
PVector dir = new PVector(dX, dY, 0);
if (this.hybrid) {
dir.mult(this.baseSpeed);
} else {
dir.mult(this.velocity);
}
dir.add(multSpeed);
this.acc.add(dir);
}
}
private void getColorValue() {
double f = Math.floor(this.loc.y) * img.width + Math.floor(this.loc.x);
Integer i = (int) f;
Integer col = img.pixels[i];
float red = col >> 16 & 0xFF; // Very fast to calculate
float green = col >> 8 & 0xFF; // Very fast to calculate
float blue = col & 0xFF; // Very fast to calculate
int greyscale = (int) Math.round(red * 0.222 + green * 0.707 + blue * 0.071);
newMap = map(greyscale, 0, 255, 0, 1);
}
public void getFollowers(List<PVector> field) {
this.otherPtsList = new ArrayList<PVector>();
this.otherMoveValues = new ArrayList<PVector>();
this.allDist = new ArrayList<Float>();
for (int i = 0; i < field.size(); i++) {
PVector other = field.get(i);
float distance = this.loc.dist(other);
if (distance > 0 && distance < tailCohViewRange) {
tailPerip = PVector.sub(field.get(i), loc);
tailAngle = PVector.angleBetween(tailPerip, this.chaser_speed);
if (tailAngle < 0) {
tailAngle += (Math.PI * 2);
}
if (Math.abs(tailAngle) < tailVAngle) {
this.otherPtsList.add(other);
this.allDist.add(distance);
}
}
}
if (this.otherPtsList.size() > 0) {
this.cummVec = new PVector();
// ----------Separate-----------------
trailSeparate();
if (this.separateVector.mag() > 0) {
this.separateVector.normalize();
}
this.separateVector.mult(tailSepMag);
// ----------Cohesion-----------------
trailCohesion();
if (this.cohesionVector.mag() > 0) {
this.cohesionVector.normalize();
}
this.cohesionVector.mult(tailCohMag);
// -----------------------------------
this.cummVec.add(this.separateVector);
this.cummVec.add(this.cohesionVector);
this.chaser_speed.add(this.cummVec);
this.chaser_speed.normalize();
this.chaser_speed.mult(this.velocity);
}
}
private void trailCohesion() {
this.cohesionVector = new PVector();
for (int i = 0; i < this.otherPtsList.size(); i++) {
this.cohesionVector.add(this.otherPtsList.get(i));
}
PVector scaleVec = PVector.mult(this.cohesionVector, (1.00f / this.otherPtsList.size()));
float dist = this.loc.dist(scaleVec);
this.cohesionVector = PVector.mult(PVector.sub(scaleVec, this.loc), tailCohViewRange / dist);
}
// -----------Method Computes the separation----------------------------
private void trailSeparate() {
this.separateVector = new PVector();
for (int i = 0; i < this.otherPtsList.size(); i++) {
this.separateVector.add(PVector.mult(PVector.sub(this.loc, this.otherPtsList.get(i)),
tailSepViewRange / this.allDist.get(i)));
}
}
// FLOCK METHOD
// ---------------------------------------------------------------------------------------------------------------
private void flocking() {
if (this.applyMap) {
if (this.loc.x <= img.width && this.loc.x >= 0 && this.loc.y >= 0 && this.loc.y <= img.height) {
getColorValue();
if (this.mapAV) {
this.av *= this.newMap;
}
if (this.mapSV) {
this.sv *= this.newMap;
}
if (this.mapCV) {
this.cv *= this.newMap;
}
} else {
this.newMap = 0;
}
}
this.otherPtsList = new ArrayList<PVector>();
this.otherMoveValues = new ArrayList<PVector>();
this.allDist = new ArrayList<Float>();
for (int i = 0; i < this.creeperCollection.size(); i++) {
Creeper other = (Creeper) creeperCollection.get(i);
float distance = this.loc.dist(other.loc);
if (distance > 0 && distance < this.searchRad) {
this.otherPtsList.add(this.creeperCollection.get(i).loc);
this.allDist.add(distance);
this.otherMoveValues.add(this.creeperCollection.get(i).speed);
}
}
if (this.otherPtsList.size() > 0) {
this.cummVec = new PVector();
// ----------Align-----------------
align();
if (this.alignVector.mag() > 0) {
this.alignVector.normalize();
}
this.alignVector.mult(this.av);
// ----------Separate-----------------
separate();
if (this.separateVector.mag() > 0) {
this.separateVector.normalize();
}
this.separateVector.mult(this.sv);
// ----------Cohesion-----------------
cohesion();
if (this.cohesionVector.mag() > 0) {
this.cohesionVector.normalize();
}
this.cohesionVector.mult(this.cv);
// -----------------------------------
this.cummVec.add(this.alignVector);
this.cummVec.add(this.separateVector);
this.cummVec.add(this.cohesionVector);
if (this.hybrid) {
if (this.blend != 0.0 && this.blend != 1.0) {
acc.add(this.cummVec);
float newVal = 1.0f - this.blend;
this.acc.mult(newVal);
} else if (this.blend == 1.0) {
this.acc = new PVector();
this.speed.add(this.cummVec);
this.speed.normalize();
this.speed.mult(this.baseSpeed);
}
} else {
this.speed.add(this.cummVec);
this.speed.normalize();
this.speed.mult(this.velocity);
}
}
}
// COHESION
// ---------------------------------------------------------------------------------------------------------------------
// -----------Method Computes the cohesion-----------------------------
private void cohesion() {
this.cohesionVector = new PVector();
for (int i = 0; i < this.otherPtsList.size(); i++) {
this.cohesionVector.add(this.otherPtsList.get(i));
}
PVector scaleVec = PVector.mult(this.cohesionVector, (1.00f / this.otherPtsList.size()));
float dist = this.loc.dist(scaleVec);
this.cohesionVector = PVector.mult(PVector.sub(scaleVec, this.loc), this.searchRad / dist);
}
// -----------Method Computes the separation----------------------------
private void separate() {
this.separateVector = new PVector();
for (int i = 0; i < this.otherPtsList.size(); i++) {
this.separateVector.add(PVector.mult(PVector.sub(this.loc, this.otherPtsList.get(i)),
this.searchRad / this.allDist.get(i)));
}
}
// -----------Method Computes the alignment----------------------------
private void align() {
this.alignVector = new PVector();
for (int i = 0; i < this.otherPtsList.size(); i++) {
this.alignVector.add(PVector.mult(this.otherMoveValues.get(i), this.searchRad / this.allDist.get(i)));
}
}
// --------------------------------------------------------PREDICT FUT LOC
private void FutLoc() {
FutVec = this.chaser_speed.copy();
FutVec.normalize();
FutVec.mult(futLocMag);
this.FutLocation = FutVec.add(loc);
}
private void drawChasedTrails() {
followerTrailData = new ArrayList<List<PVector>>();
followerColorData = new ArrayList<ArrayList>();
Tcount++;
if (Tcount > TStep) {
this.copyTrail.add(loc.copy());
Tcount = 0;
}
if (this.copyTrail.size() > maxConn) {
this.copyTrail.remove(0);
}
int counter = 0;
for (int i = 1; i < copyTrail.size(); i++) {
List<PVector> followerVecList = new ArrayList<PVector>();
ArrayList followerColList = new ArrayList();
PVector a = copyTrail.get(i - 1);
PVector b = copyTrail.get(i);
if (a.dist(b) < connDist) {
followerVecList.add(a);
followerVecList.add(b);
int c = toneMapA.getARGBToneFor(i / (1.0f * copyTrail.size()));
float d = map(i, 0.0f, copyTrail.size(), 0.5f, this.strokeWidth);
float e = map(i, 0.0f, copyTrail.size(), 0.0f, this.transparency);
followerColList.add(d);
followerColList.add(c);
followerColList.add(e);
followerTrailData.add(counter, followerVecList);
followerColorData.add(counter, followerColList);
counter++;
}
}
}
public void seek(PVector target) {
float distanceT = target.dist(loc);
if (distanceT > 0 && distanceT < 500) {
PVector desired = PVector.sub(target, loc);
desired.normalize();
desired.mult(att);
PVector steerTarget = PVector.sub(desired, chaser_speed);
steerTarget.setMag(maxAttract);
chaser_speed.add(steerTarget);
}
}
// -----------------------------------REPEL TARGET
public void repel(PVector target) {
float distanceT = target.dist(loc);
if (distanceT > 0 && distanceT < 150) {
PVector desired = PVector.sub(target, loc);
desired.normalize();
desired.mult(rep);
PVector steerTarget = PVector.sub(desired, chaser_speed);
steerTarget.limit(maxRepel);
steerTarget.mult(-1);
chaser_speed.add(steerTarget);
}
}
private void getAngle() {
double conv = Math.toRadians(tailViewAngle);
float angl = (float) conv;
tailVAngle = angl;
}
// TRAIL METHOD
// ---------------------------------------------------------------------------------------------------------------------------------
private void trails() {
this.trailData = new ArrayList<List<PVector>>();
this.trailColors = new ArrayList<ArrayList>();
int counter = 0;
this.pvecList = new ArrayList<PVector>();
for (int k = 0; k < creeperTrails.size(); k++) {
if (counter % this.trailResolution == 0) {
pvecList.add(creeperTrails.get(k));
}
counter++;
}
if (pvecList.size() > 0) {
for (int j = 0; j < pvecList.size(); j++) {
if (j != 0) {
List<PVector> vecList = new ArrayList<PVector>();
ArrayList colList = new ArrayList();
PVector pos = pvecList.get(j);
PVector prevpos = pvecList.get(j - 1);
vecList.add(pos);
vecList.add(prevpos);
trailData.add(j - 1, vecList);
if (this.applyColor) {
if (this.dual && this.currentCount >= this.creeperCollection.size() / 2) {
int a = toneMapA.getARGBToneFor(j / (1.0f * pvecList.size()));
float value = map(j / (1.0f * pvecList.size()), 0, 1.0f, 0, this.strokeWidth);
float value2 = map(j / (1.0f * pvecList.size()), 0, 1.0f, 10, this.transparency);
colList.add(value);
colList.add(a);
colList.add(value2);
} else if (this.dual && this.currentCount < this.creeperCollection.size() / 2) {
int a = toneMapB.getARGBToneFor(j / (1.0f * pvecList.size()));
float value = map(j / (1.0f * pvecList.size()), 0, 1.0f, 0, this.strokeWidth);
float value2 = map(j / (1.0f * pvecList.size()), 0, 1.0f, 10, this.transparency);
colList.add(value);
colList.add(a);
colList.add(value2);
} else {
int a = toneMapA.getARGBToneFor(j / (1.0f * pvecList.size()));
float value = map(j / (1.0f * pvecList.size()), 0, 1.0f, 0, this.strokeWidth);
float value2 = map(j / (1.0f * pvecList.size()), 0, 1.0f, 10, this.transparency);
colList.add(value);
colList.add(a);
colList.add(value2);
}
trailColors.add(j - 1, colList);
}
}
}
}
}
static public final float map(float value, float istart, float istop, float ostart, float ostop) {
return ostart + (ostop - ostart) * ((value - istart) / (istop - istart));
}
}