package creeper_Behavior_P3;
import processing.core.*;
import java.util.ArrayList;
import java.util.List;
import toxi.color.*;
import java.util.Random;
import creeper_Behavior_P3.ImprovedPerlinNoise;
public class Creeper{
public PVector loc;
public PVector speed;
private PVector acc = new PVector();
public ArrayList<PVector> creeperTrails;
public List<Creeper> creeperCollection;
public List<List<PVector>> trailData;
public List<ArrayList> trailColors;
private float width;
private float height;
public float searchRad;
public float av;
public float sv;
public float cv;
public float connThresh;
public float connect;
public float max;
public boolean swarm;
public boolean perlin;
public boolean hybrid;
public boolean bounds;
private boolean needsRefresh;
public boolean applyMap;
public boolean applyColor;
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(1.0f / 255.0f, 53.0f / 255.0f, 103.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 ToneMap toneMapA;
public boolean simulate;
public float strokeWidth, transparency;
public int trailResolution;
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 width, float height) {
this.loc = origin;
this.creeperTrails = new ArrayList<PVector>();
this.speed = speed;
this.width = width;
this.height = height;
this.creeperCollection = new ArrayList<Creeper>();
gradA.addColorAt(0.0f, colorA);
gradA.addColorAt(255.0f, colorC);
toneMapA = new ToneMap(0.0f, 1.0f, gradA);
}
// ALL FUNCTIONS
// ---------------------------------------------------------------------------------------------------------
public void action() {
this.r = new Random();
if (this.simulate) {
if (this.swarm || (this.hybrid && this.blend == 1.0)) {
flocking();
bounce();
this.loc.add(speed);
this.creeperTrails.add(new PVector(loc.x, loc.y, 0));
acc = new PVector();
}
if (this.perlin || (this.hybrid && this.blend == 0.0)) {
perlinNoise();
if (this.bounds) {
checkLoc();
}
speed = new PVector();
speed.add(acc);
this.loc.add(speed);
this.creeperTrails.add(new PVector(loc.x, loc.y, 0));
acc = new PVector();
}
if (this.hybrid && (this.blend != 0.0 && this.blend != 1.0)) {
speed.add(acc);
speed.limit(this.max);
this.loc.add(speed);
this.creeperTrails.add(new PVector(loc.x, loc.y, 0));
acc = new PVector();
perlinNoise();
flocking();
bounce();
}
if (!this.swarm && !this.perlin && !this.hybrid) {
this.acc = new PVector(1.0f, 0, 0);
}
trails();
}
}
private void checkLoc_B() {
Float w = width;
Double dW = (double) w;
Float h = height;
Double dH = (double) h;
this.needsRefresh = false;
if (loc.x > width || this.loc.x < 0 || this.loc.y > height || this.loc.y < 0) {
this.needsRefresh = true;
}
}
private void checkLoc() {
Float w = width;
Double dW = (double) w;
Float h = height;
Double dH = (double) h;
this.needsRefresh = false;
if (loc.x > width || this.loc.x < 0 || this.loc.y > height || this.loc.y < 0) {
this.needsRefresh = true;
float x = GetRandomNumbers(0.0f, dW, this.r);
float y = GetRandomNumbers(0.0f, dH, this.r);
this.loc = new PVector(x, y, 0);
this.creeperTrails = new ArrayList<PVector>();
}
}
// BOUNCE METHOD
// ------------------------------------------------------------------------------------------------------------
private void bounce() {
if (loc.x > width) {
speed.x = speed.x * -1;
}
if (loc.x < 0) {
speed.x = speed.x * -1;
}
if (loc.y > height) {
speed.y = speed.y * -1;
}
if (loc.y < 0) {
speed.y = speed.y * -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;
float fX = (float) rX;
float fY = (float) rY;
rando.x = fX;
rando.y = fY;
rando.z = 0.00f;
return rando;
}
private void perlinNoise() {
if (!this.applyMap) {
PVector multSpeed = GetRandomNumber(-this.multiplier, this.multiplier, this.r);
double noiseVal = ImprovedPerlinNoise.noise(this.loc.x / (Float) this.scale, this.loc.y / (Float) this.scale, 0.0)
* 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);
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);
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);
}
// 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.velocity);
}
}
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)));
}
}
// TRAIL FUNCTION
// ---------------------------------------------------------------------------------------------------------------------------------
private void trails() {
this.trailData = new ArrayList<List<PVector>>();
this.trailColors = new ArrayList<ArrayList>();
int counter = 0;
List<PVector> 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){
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));
}
}