// BIRTHDAY PARTY
// guthrie
// party girl == kelley
// takes a while to download, sorry.
// "shift-click" (and drag) to duplicate
// "control-click" to delete
// "UP arrow" to change location
// "d" to go back to default arrangement
// characters are movable and are more active when closer to other characters
boolean dragging=false;
int count=0; // increments every frame, for animation speed
int prevMouse=-1; // fixes double-clicking bug
int buffer=15;
int friendDistance=60;
int currentLocation=0; // background
int frameLocation=0;
int numPersons=4;
int numCharacters=1;
int numActions=3;
int numFrames=2;
int numLocations=3;
Person[] person = new Person[buffer];
PImage[][][] right = new PImage[numCharacters][numActions][numFrames]; // [which character][which action][which frame]
PImage[][][] left = new PImage[numCharacters][numActions][numFrames];
PImage[][] location = new PImage[numLocations][numFrames];
float mx = 0.0;
float my = 0.0;
void setup()
{
framerate(30);
size(600,300);
colorMode(HSB,1);
angleMode(DEGREES);
loadImages();
orig();
}
void draw()
{
mouse();
image(location[currentLocation][frameLocation],0,0); // background image
if(dragging) // we are dragging someone
{
person[numPersons-1].drag();
}
for(int i=0; i<numPersons; i++)
{
closest(); // it might make more sense to make this function a part of the person class
person[i].update();
person[i].draw();
}
frameLocation++; // cycle through background frames
if(frameLocation==numFrames)
frameLocation=0;
count++; // master count
}
void mousePressed()
{
boolean deleted=false;
for(int i=numPersons-1; i>=0 && !dragging && !deleted; i--) // only if we aren't dragging anyone...count backwards so top get priority
{
if(person[i].isInside(mouseX,mouseY))
{
if(keyPressed && keyCode==SHIFT && numPersons<buffer) // A NEW PERSON IS BORN
{
person[i].startDrag();
person[i].duplicate();
person[numPersons].startDrag();
dragging=true;
numPersons++;
}
else if(keyPressed && keyCode==CONTROL && numPersons>1 && (count-prevMouse)>4) // A PERSON IS DELETED
{
prevMouse=count;
if(i==numPersons-1)
{
person[i]=person[numPersons-1];
numPersons--;
}
else
{
for(int j=i+1; j<numPersons; j++)
{
person[j-1]=person[j];
}
deleted=true;
numPersons--;
}
}
else
{
if(numPersons-1!=i) // if i isn't already on top or tobedragged
{
Person oldtop=person[numPersons-1];
Person newtop=person[i];
for(int j=i+1; j<numPersons-1; j++)
{
person[j-1]=person[j];
}
person[numPersons-1]=newtop;
person[numPersons-2]=oldtop;
}
dragging=true;
person[numPersons-1].startDrag();
}
}
}
}
void mouseReleased()
{
dragging=false;
}
void keyPressed()
{
if(keyCode==UP)
{
currentLocation++;
if(currentLocation>=numLocations)
currentLocation=0;
}
else if(key == 'd' || key == 'D')
{
orig();
}
}
void orig()
{
numPersons=3;
person[1] = new Person(70,10,0,0,1,true,1.2);
person[0] = new Person(-30,40,0,0,1,false,.4);
person[2] = new Person(320,40,0,0,1,true,.001);
// person[2] = new Person(250,0,0,0,1,false,.2);
}
void mouse()
{
float speed=4.0;
float difY = mouseY - my;
if(abs(difY) > 1.0) {
my = my + difY/speed;
}
my = constrain(my, 0, height);
float difX = mouseX - mx;
if(abs(difX) > 1.0) {
mx = mx + difX/speed;
}
mx = constrain(mx, 0, width);
}
void loadImages()
{
for(int i=0; i<numCharacters; i++)
{
for(int j=0; j<numActions; j++)
{
for(int k=0; k<numFrames; k++)
{
right[i][j][k]=loadImage("right_" + i + "_" + j + "_" + k + ".gif");
left[i][j][k]=reflectImage(right[i][j][k]);
}
}
}
for(int i=0; i<numLocations; i++)
{
for(int j=0; j<numFrames; j++)
{
location[i][j]=loadImage("location_" + i + "_" + j + ".gif");
}
}
}
PImage reflectImage(PImage reflectMe) // reflecting images with transparency == a pain
{
PImage returnMe = new PImage(reflectMe.width,reflectMe.height);
PImage alphaChannel = new PImage(reflectMe.width,reflectMe.height);
for(int i=0; i<reflectMe.height; i++)
{
for(int j=0; j<reflectMe.width; j++)
{
if(reflectMe.get(j,i)==color(1,0,1,0))
{
returnMe.set(reflectMe.width-j-1,i,color(1,0,1,0));
alphaChannel.set(reflectMe.width-j-1,i,color(1,1,0,1));
}
else
{
returnMe.set(reflectMe.width-j-1,i,reflectMe.get(j,i));
alphaChannel.set(reflectMe.width-j-1,i,color(1,0,1,0));
}
}
}
alpha(returnMe,alphaChannel);
return returnMe;
}
void closest()
{
// what about if there are only 2 or only 1 persons?
if(numPersons==2)
{
person[0].setClosest(1);
person[1].setClosest(0);
if(person[0].distance(1)<friendDistance)
{
person[0].friendMode(true);
person[1].friendMode(true);
}
else
{
person[0].friendMode(false);
person[1].friendMode(false);
}
}
else if(numPersons==1)
{
person[0].setClosest(-1);
person[0].friendMode(false);
}
else
{
for(int i=numPersons-1; i>=0; i--)
{
int closestIndex = numPersons-1;
if(i==closestIndex)
closestIndex--;
for(int j=numPersons-2; j>=0; j--) // compare i to everyone else (the j's)
{
if(j!=i)
{
if(person[i].distance(j)<person[i].distance(closestIndex))
closestIndex = j;
}
}
person[i].setClosest(closestIndex);
if(person[closestIndex].giveClosest()==i && person[i].distance(closestIndex)<friendDistance)
{
person[i].friendMode(true);
person[closestIndex].friendMode(true);
}
else
person[i].friendMode(false);
}
}
}
class Person
{
// dont forget to pay attention to z-index, when something is clicked, etc
int x,y;
int dragX,dragY;
int character; // following 3 refer to PImage left and right
int action;
int frame;
boolean isLeft; // will face right if this is false, left if true
float speed;
int closest=-1; // index of closest person
boolean friend=false;
Person(int myX, int myY, int myCharacter, int myAction, int myFrame, boolean myIsLeft, float mySpeed)
{
character=myCharacter;
action=myAction;
frame=myFrame;
isLeft=myIsLeft;
speed=mySpeed;
x=myX;
y=constrain(myY,height-right[character][action][frame].height,height-20);
}
void draw()
{
if(isLeft)
image(left[character][action][frame],x,y);
else
image(right[character][action][frame],x,y);
}
void update()
{
// messy code for alternating between blowers and regular action
if(random(0,1)>.98)
{
if(action==1)
action=0;
}
else if(random(0,1)>.99)
{
if(action==1)
action=0;
else if(action==0)
action=1;
}
if(closest>=0) // closest != -1 and therefore null
{
if(person[closest].giveCenterX()<giveCenterX())
isLeft=true;
else
isLeft=false;
}
else
{
if(random(0,1)>.99)
isLeft=!isLeft;
}
if(closest>=0) // if its not null
speed=distance(closest)/145.0;
else // if no defined closest, probably only person alive
speed=2.2;
if(count%random(2.0,2.6)>speed)
frame++;
if(frame==numFrames)
frame=0;
}
boolean isInside(int myX, int myY)
{
if(myX>=x && myX<(x+right[character][action][frame].width) && myY>=y && myY<(y+right[character][action][frame].height))
{
if(right[character][action][frame].get(myX-x,myY-y)!=color(1,0,1,0))
return true;
}
return false;
}
void startDrag()
{
mx=mouseX;
my=mouseY;
dragX=mouseX-x;
dragY=mouseY-y;
}
void drag()
{
x=constrain(int(mx)-dragX,20-right[character][action][frame].width,width-20);
y=constrain(int(my)-dragY,height-right[character][action][frame].height,height-20);
}
void setClosest(int myClosest)
{
closest = myClosest;
}
int giveClosest()
{
return closest;
}
int giveCenterX()
// WARNING: GIVES CENTER X
{
return (x+(right[character][action][frame].width/2));
}
int distance(int index)
{
return (abs(giveCenterX()-person[index].giveCenterX()));
}
void duplicate()
{
person[numPersons] = new Person(mouseX-dragX,mouseY-dragY,character,action,frame,false,.2);
}
void friendMode(boolean which)
{
if(!friend && which)
{
action=2;
}
else if(friend && !which)
{
action=0;
}
friend=which;
}
}