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)); } }