//=========================================================================== // Flocking, Schooling, Herding & Crowd Behavior // April 2, 2009 - Version 20-T // Two agent sexes (MF), five agent types (WCMYK). // (Images for RGB agent types are included.) // With agent path and agent encounter visualization. //=========================================================================== // The Leonardo image is 612 by 612 pixels. // The Voyager images are 100 by 44 pixels. //--------------------------------------------------------------------------- #include #include #pragma hdrstop #include "Unit1.h" #include "stdlib.h" #include // for multimedia #define SEQUENTIAL 0 // for Polling sequence #define RANDOM 1 #define NORTH 0 // wall designatios #define EAST 1 #define SOUTH 2 #define WEST 3 #define BEEP 1 // sound types #define PLAYSOUNDWINDOWS 2 #define PLAYSOUNDPINBALL 3 #define MIDI 4 #define MAXPOP 100 // maximum population array size #define INIPOP 10 // current (and initial) population #define WOMAN 1 #define MAN 0 #define WHITE 0 #define CYAN 1 #define MAGENTA 2 #define YELLOW 3 #define BLACK 4 #define RED 5 #define GREEN 6 #define BLUE 7 #define COIN 99 #define COLORBANK 98 #define BLACKBANK 97 //--------------------------------------------------------------------------- #pragma package(smart_init) #pragma resource "*.dfm" TForm1 *Form1; //--------------------------------------------------------------------------- //--------------------------------------------------------------------------- //=========================================================================== // GLOBAL VARIABLES //=========================================================================== // ------------------------------------------------- your program begins here // Varialbes for a 612 x 612 bitmap image that you may import Graphics::TBitmap* b = new Graphics::TBitmap(); // Holds the bitmap image RGBTRIPLE* t; // Holds one Pixel's R, G, and B values int bmpRed[612][612]; // RED channel of bitmap for environment variables int bmpGreen[612][612]; // GREEN channel of bitmap for environment variables int bmpBlue[612][612]; // BLUE channel of bitmap for environment variables int iterationPath[612][612]; // Paths recorded by iteration int agentPath[612][612]; // Paths recorded by agent int ix, iy; // These commands set up the MIDI functionality int midiport = 0; HMIDIOUT device; union { public: unsigned long word; unsigned char data[4]; } message; int soundType = 0; int instrument; int note; TImage *image[MAXPOP] = {0}; // sets up an array of images for the agents TShape *shape[MAXPOP] = {0}; // sets up an array of shapes for the agents class anAgent { // describes an abstract class for an-agent public: double velocity; double direction; double newDirection; double newDistance; double lastDistance; float x; float y; bool sex; bool flocking; int lastNN; bool active; int encounters[MAXPOP]; int numEncounters; int type; int seeking; } ; anAgent* agent[MAXPOP] = {0}; // creates MAXPOP instances of that class double aveDir, aveVelo, sumXs, sumYs; // average directions & velocities int sumVisibleNeighbors; // visible neighbors int increment = 5; double x, y, z; bool stop = true; bool wasStopped = false; bool showNNs = false; bool collisions = false; bool agentsAreDisplayed = true; bool mouseDown = false; bool behavioralSonification = false; bool wrap = true; bool movePerTimer = true; int iterations; int i; int who; int NNeighborTag; int NNeighborDist; int NThingTag; int NThingDist; int radius = 30; int chosenAgent; int runTo = 50000; int curpop = INIPOP; int lastMouseOver; // Variables required in order to drag and agent int imageDownX, imageDownY; bool agentWasJustChosen = false; // Variables required in order to throw an agent int agentDownX, agentDownY; int agentUpX, agentUpY; double dY, dX; double timeDown, timeUp; int polling = SEQUENTIAL; //=========================================================================== // FUNCTIONS //=========================================================================== //-------------------------------------------------- FILL ARRAYS FROM BITMAP // This fills the Red, Green and Blue arrays from the bitmap. // It converts the color values (0-255) to preferences (0-7). // The conversion divides the color values by 35. // With a gray-scale image the Red, Green and Blue values are identical. void bmpToArray(Graphics::TBitmap* bm) { for (int y = 0; y < 612; y++) { t = (RGBTRIPLE*)bm->ScanLine[y]; for (int x = 0; x < 612; x++) { bmpRed[x][y] = t->rgbtRed; // used for preference 0-4 bmpGreen[x][y] = t->rgbtGreen; // used for distance 0-3 bmpBlue[x][y] = t->rgbtBlue; // used for neighborhood 0-2 t++; } } } //------------------------------------------------------------- RENDER BITMAP // This renders the imported bitmap to the screen. // It does not change the values in any of the arrays. // All it does is confirm that the image has been acquired. void renderBMP(Graphics::TBitmap* bm) { for (int y = 0; y < 612; y++) { t = (RGBTRIPLE*)bm->ScanLine[y]; for (int x = 0; x < 612; x++) { Form1->Canvas->Pixels[x][y]= static_cast(RGB(t->rgbtRed, t->rgbtGreen, t->rgbtBlue)); t++; } } } //--------------------------------------------------- Color Ramp Version 2008 TColor colorRamp(int part, int whole) { if (whole == 0) whole++; // prevent divide by zero int pixelDistanceAlongEdges = (part * 1792) / whole; int red, green, blue; // Which edge of the color cube are we on? if (pixelDistanceAlongEdges < 256) { // from BLACK to BLUE red = 0; green = 0; blue = pixelDistanceAlongEdges; } else if (pixelDistanceAlongEdges < 512) { // from BLUE to CYAN red = 0; green = pixelDistanceAlongEdges - 256; blue = 255; } else if (pixelDistanceAlongEdges < 768) { // from CYAN to GREEN red = 0; green = 255; blue = 255 - (pixelDistanceAlongEdges - 512); } else if (pixelDistanceAlongEdges < 1024) { // from GREEN to YELLOW red = (pixelDistanceAlongEdges - 768); green = 255; blue = 0; } else if (pixelDistanceAlongEdges < 1280) { // from YELLOW to RED red = 255; green= 255-(pixelDistanceAlongEdges - 1024); blue = 0; } else if (pixelDistanceAlongEdges < 1536) { // from RED to MAGENTA red = 255; green= 0; blue = pixelDistanceAlongEdges - 1280; } else { // from MAGENTA to WHITE red = 255; green = pixelDistanceAlongEdges - 1537; blue = 255; } return static_cast(RGB(red, green, blue)); } //----------------------------------------------------------------- visualize void visualize (int i) { // move the agent IMAGE if called for if (Form1->RadioGroupMoveAgentImages->ItemIndex == 0) { image[i]->Left = agent[i]->x - image[i]->Width / 2; image[i]->Top = agent[i]->y - image[i]->Height / 2; } // move the agent CIRCLE if called for if (Form1->RadioGroupMoveAgentShapes->ItemIndex == 0) { shape[i]->Left = agent[i]->x - image[i]->Width / 2 + 10; shape[i]->Top = agent[i]->y - image[i]->Height / 2 + 12; } } //----------------------------------------------------- move targets randomly void moveTargets (void) { image[COLORBANK]->Left = random(540); agent[COLORBANK]->x = image[COLORBANK]->Left + image[COLORBANK]->Width / 2; image[COLORBANK]->Top = random(540); agent[COLORBANK]->y = image[COLORBANK]->Top + image[COLORBANK]->Height / 2; image[BLACKBANK]->Left = random(540); agent[BLACKBANK]->x = image[BLACKBANK]->Left + image[BLACKBANK]->Width / 2; image[BLACKBANK]->Top = random(540); agent[BLACKBANK]->y = image[BLACKBANK]->Top + image[BLACKBANK]->Height / 2; } //------------------------------------------------------------------- shuffle void shuffle (void) { for (int i = 0; i < curpop; i++) { agent[i]->x = random(560) + 30; agent[i]->y = random(510) + 50; visualize(i); agent[i]->direction = (float(random(360)) / 360) * 2 * M_PI; agent[i]->velocity = float(random(1000)) / 1500 + .1; agent[i]->lastNN = NNeighborTag = -1; agent[i]->seeking = random(curpop); while (i == agent[i]->seeking) { // don't seek self agent[i]->seeking = random(curpop); } for (int j = 0; j < curpop; j++) { agent[i]->encounters[j] = 0; } agent[i]->numEncounters = 0; agent[i]->flocking = false; for (int i = 0; i <= curpop; i++) { shape[i]->Brush->Color = colorRamp(shape[i]->Tag, curpop - 1); } } moveTargets(); } //--------------------------------------------------------------------- reset void reset (void) { Form1->Refresh(); iterations = 0; Form1->EditIterations->Text = iterations; shuffle(); for (int i = 0; i < 612; i++) { for (int j = 0; j < 612; j++) { agentPath[i][j] = 0; iterationPath[i][j] = 0; } } } //-------------------------------------------------------------------- circle void circle (void) { Form1->Refresh(); for (int i = 0; i < curpop; i++) { agent[i]->x = 274 + 250 * cos(i * (2 * M_PI / curpop)) + 30; agent[i]->y = 274 + 250 * sin(i * (2 * M_PI / curpop)) + 30; visualize(i); } } //-------------------------------------------------------------------- corner void corner (void) { Form1->Refresh(); for (int i = 0; i < curpop; i++) { // move the agent IMAGE if called for if (Form1->RadioGroupMoveAgentImages->ItemIndex == 0) { image[i]->Left = 7; image[i]->Top = 10; } // move the agent CIRCLE if called for if (Form1->RadioGroupMoveAgentShapes->ItemIndex == 0) { shape[i]->Left = 0; shape[i]->Top = 0; } } } //------------------------------------------------------------- Add New Agent void addNewAgent (int i) { agent[i]->active = true; agent[i]->seeking = random(i); shape[i]->Visible = true; shape[i]->SendToBack(); image[i]->Visible = true; image[i]->BringToFront(); Form1->ImageBackground->SendToBack(); visualize(i); } //------------------------------------------------------------- Kill Old Agent void killOldAgent (int i) { agent[i]->active = false; agent[i]->seeking = random(i); shape[i]->Visible = false; shape[i]->SendToBack(); image[i]->Visible = false; image[i]->BringToFront(); Form1->ImageBackground->SendToBack(); visualize(i); } //----------------------------------- returns a direction from agent A to B double directionFromTo (int from, int to) { x = agent[to]->x - agent[from]->x; y = agent[to]->y - agent[from]->y; return atan2(y, x); } //------------------------------------ returns a distance from agent A to B int distanceFromTo (int from, int to) { x = abs(agent[from]->x - agent[to]->x); y = abs(agent[from]->y - agent[to]->y); if (wrap) { // wrapped world if (x > 280) x = 560 - x; if (y > 255) y = 510 - y; } z = sqrt(x * x + y * y); return z; } //--------------------- calculates average Velocity and Direction of neighbors // within a radius void averageOfNeighbors (int me) { aveDir = 0; // average directions aveVelo = 0; // average velocities sumXs = 0; // x component sums sumYs = 0; // y component sums sumVisibleNeighbors = 0; // number of visible neighbors for (int i = 0; i < curpop; i++) { if (i == me) continue; x = abs(agent[i]->x - agent[me]->x); y = abs(agent[i]->y - agent[me]->y); if (wrap) { // wrapped world if (x > 280) x = 560 - x; if (y > 255) y = 510 - y; } z = sqrt(x * x + y * y); if (z < radius) { // average all visible neighbors sumVisibleNeighbors++; sumYs += agent[i]->velocity * sin(agent[i]->direction); sumXs += agent[i]->velocity * cos(agent[i]->direction); } } if ((sumYs != 0) && (sumXs != 0) && (sumVisibleNeighbors > 0)) { aveDir = atan2(sumYs, sumXs); aveVelo = sqrt(sumXs * sumXs + sumYs * sumYs) / sumVisibleNeighbors; } } //------------------ finds Tag and Distance to Nearest Thing and returns Tag // this only searches things at the end of the agent array // in this instance, agents 97, 98 and 99 (2 banks and 1 coin) int findNThingTo (int who) { NThingTag = 0; // nearest thing NThingDist = 10000; // distance to nearest thing for (int i = 98; i >= 97; i--) { if (i == who) continue; // will never happen x = abs(agent[i]->x - agent[who]->x); y = abs(agent[i]->y - agent[who]->y); if (wrap) { // wrapped world if (x > 280) x = 560 - x; if (y > 255) y = 510 - y; } z = sqrt(x * x + y * y); if (z < NThingDist) { // select nearest thing NThingDist = z; NThingTag = i; } } return NThingTag; } //--------------- finds Tag and Distance to Nearest Neighbor and returns Tag // this only searches active agents from Tag 0 to curpop -1. int findNNeighborTo (int who) { NNeighborTag = 0; // nearest neighbor NNeighborDist = 10000; // distance to nearest neighbor for (int i = 0; i < curpop; i++) { if (i == who) continue; x = abs(agent[i]->x - agent[who]->x); y = abs(agent[i]->y - agent[who]->y); if (wrap) { // wrapped world if (x > 280) x = 560 - x; if (y > 255) y = 510 - y; } z = sqrt(x * x + y * y); if (z < NNeighborDist) { // select nearest neighbor NNeighborDist = z; NNeighborTag = i; } } return NNeighborTag; } //---------------------------------------------------- show nearest neighbor void showNearestNeighbor (int who) { if (agentsAreDisplayed) { // connect the IMAGES of the agents Form1->Canvas->Pen->Width = 1; Form1->Canvas->Pen->Color = clRed; Form1->Canvas->MoveTo(agent[who]->x, agent[who]->y); Form1->Canvas->LineTo(agent[findNNeighborTo(who)]->x, agent[findNNeighborTo(who)]->y); } else { // connect the PATHS of the agents Form1->PaintBox1->Canvas->Pen->Width = 2; Form1->PaintBox1->Canvas->Pen->Color = clWhite; Form1->PaintBox1->Canvas->Ellipse(agent[who]->x - 3, agent[who]->y - 3, agent[who]->x + 3, agent[who]->y + 3); Form1->PaintBox1->Canvas->MoveTo(agent[who]->x, agent[who]->y); Form1->PaintBox1->Canvas->LineTo(agent[findNNeighborTo(who)]->x, agent[findNNeighborTo(who)]->y); } Form1->Canvas->Pen->Width = 1; } //---------------------------------------------------- show perceptual field void showPerceptualField (int me) { Form1->Canvas->Brush->Style = bsClear; Form1->Canvas->Ellipse(agent[me]->x - radius, agent[me]->y - radius, agent[me]->x + radius, agent[me]->y + radius); } //-------------------------------------------------------------------- sonify // different sound types are associated with each of the 4 walls // the user may select Beep(), PlaySound(), or midiOutShortMsg() void sonify (int wall) { if (soundType == BEEP) { if (wall == EAST) { Beep(196, 50); } if (wall == SOUTH) { Beep(261, 50); } if (wall == WEST) { Beep(330, 50); } if (wall == NORTH) { Beep(392, 50); } } if (soundType == PLAYSOUNDWINDOWS) { if (wall == EAST) { PlaySound ("C:\\WINDOWS\\Media\\Windows XP Balloon.wav", "", SND_ASYNC); } if (wall == SOUTH) { PlaySound ("C:\\WINDOWS\\Media\\Windows XP pop-up blocked.wav", "", SND_ASYNC); } if (wall == WEST) { PlaySound ("C:\\WINDOWS\\Media\\Windows XP Balloon.wav", "", SND_ASYNC); } if (wall == NORTH) { PlaySound ("C:\\WINDOWS\\Media\\Windows XP pop-up blocked.wav", "", SND_ASYNC); } } if (soundType == PLAYSOUNDPINBALL) { if (wall == EAST) { PlaySound ("C:\\Program Files\\Windows NT\\Pinball\\SOUND181.wav", "", SND_ASYNC); } if (wall == SOUTH) { PlaySound ("C:\\Program Files\\Windows NT\\Pinball\\SOUND243.wav", "", SND_ASYNC); } if (wall == WEST) { PlaySound ("C:\\Program Files\\Windows NT\\Pinball\\SOUND713.wav", "", SND_ASYNC); } if (wall == NORTH) { PlaySound ("C:\\Program Files\\Windows NT\\Pinball\\SOUND735.wav", "", SND_ASYNC); } } if (soundType == MIDI) { if (wall == EAST) { message.data[0] = 0x90; message.data[1] = 55; message.data[2] = 100; message.data[3] = 0; midiOutShortMsg(device, message.word); } if (wall == SOUTH) { message.data[0] = 0x90; message.data[1] = 60; message.data[2] = 100; message.data[3] = 0; midiOutShortMsg(device, message.word); } if (wall == WEST) { message.data[0] = 0x90; message.data[1] = 64; message.data[2] = 100; message.data[3] = 0; midiOutShortMsg(device, message.word); } if (wall == NORTH) { message.data[0] = 0x90; message.data[1] = 67; message.data[2] = 100; message.data[3] = 0; midiOutShortMsg(device, message.word); } } } //---------------------------------------------------------------------- step void step (void) { iterations++; Form1->EditIterations->Text = iterations; increment = Form1->TrackBarIncrement->Position; for (who = 0; who < curpop; who++) { if (polling == RANDOM) i = random(curpop); if (polling == SEQUENTIAL) i = who; // calculate agent's new position based on velocity and direction agent[i]->x += agent[i]->velocity * cos(agent[i]->direction) * increment; agent[i]->y += agent[i]->velocity * sin(agent[i]->direction) * increment; visualize(i); /////////////////////////////////////////////////////////////////////// ///////////////////// FLOCKING BEHAVIORS BELOW //////////////////////// /////////////////////////////////////////////////////////////////////// // adopt your nearest neighbor's direction 1 if (Form1->RadioGroupFlockingBehavior->ItemIndex == 1) { agent[i]->direction = agent[findNNeighborTo(i)]->direction; } // increment your direction by 1/100 your nearest neighbor's 2 if (Form1->RadioGroupFlockingBehavior->ItemIndex == 2) { agent[i]->direction += agent[findNNeighborTo(i)]->direction / 100; if (agent[i]->direction > 2 * M_PI) { // modulo divide agent[i]->direction = agent[i]->direction - 2 * M_PI; } } // decrement your direction by 1/200 your nearest neighbor's 3 if (Form1->RadioGroupFlockingBehavior->ItemIndex == 3) { agent[i]->direction -= agent[findNNeighborTo(i)]->direction / 200; if (agent[i]->direction > 2 * M_PI) { // modulo divide agent[i]->direction = agent[i]->direction - 2 * M_PI; } } // adopt your nearest neighbor's velocity 4 if (Form1->RadioGroupFlockingBehavior->ItemIndex == 4) { agent[i]->velocity = agent[findNNeighborTo(i)]->velocity; } // seek a random other agent but don't seek yourself 5 if (Form1->RadioGroupFlockingBehavior->ItemIndex == 5 && i != agent[i]->seeking) { if (i % 4 == 0) { agent[i]->direction += 0.002 * directionFromTo(i, agent[i]->seeking); } if (i % 4 == 1) { agent[i]->direction -= 0.003 * directionFromTo(i, agent[i]->seeking); } if (i % 4 == 2) { agent[i]->direction += 0.004* directionFromTo(i, agent[i]->seeking); } if (i % 4 == 3) { agent[i]->direction -= 0.005* directionFromTo(i, agent[i]->seeking); } } // adopt your nearest neighbor's direction and speed 6 if (Form1->RadioGroupFlockingBehavior->ItemIndex == 6) { agent[i]->velocity = agent[findNNeighborTo(i)]->velocity; agent[i]->direction = agent[findNNeighborTo(i)]->direction; } // STRAIGHT COUPLES 7 // if same sex: both reverse direction and take random velocities // if opposite sex: both take average direction and NN velocity if (Form1->RadioGroupFlockingBehavior->ItemIndex == 7) { findNNeighborTo(i); if ((NNeighborDist < radius) && (agent[i]->lastNN != NNeighborTag)) { if (agent[i]->sex == agent[NNeighborTag]->sex) { // leave if (behavioralSonification) { message.data[0] = 0x90; message.data[1] = 55; message.data[2] = 100; message.data[3] = 0; midiOutShortMsg(device, message.word); } agent[i]->direction += M_PI; if (agent[i]->direction > 2 * M_PI) { agent[i]->direction = agent[i]->direction - 2 * M_PI; } agent[NNeighborTag]->direction += M_PI; if (agent[NNeighborTag]->direction > 2 * M_PI) { agent[NNeighborTag]->direction = agent[NNeighborTag]->direction - 2 * M_PI; } agent[i]->velocity = float(random(1000)) / 1500 + .1; agent[NNeighborTag]->velocity = float(random(1000)) / 1500 + .1; } else { // join if (behavioralSonification) { message.data[0] = 0x90; message.data[1] = 67; message.data[2] = 100; message.data[3] = 0; midiOutShortMsg(device, message.word); } sumYs = agent[i]->velocity * sin(agent[i]->direction) + agent[NNeighborTag]->velocity * sin(agent[NNeighborTag]->direction); sumXs = agent[i]->velocity * cos(agent[i]->direction) + agent[NNeighborTag]->velocity * cos(agent[NNeighborTag]->direction); agent[i]->direction = atan2(sumYs, sumXs); agent[NNeighborTag]->direction = agent[i]->direction; agent[i]->velocity = sqrt(sumYs * sumYs + sumXs * sumXs) / 2; agent[NNeighborTag]->velocity = agent[i]->velocity; } agent[i]->lastNN = NNeighborTag; // remember lastNN agent[NNeighborTag]->lastNN = i; agent[i]->encounters[NNeighborTag]++; // remember encounter agent[i]->numEncounters++; agent[NNeighborTag]->encounters[i]++; agent[NNeighborTag]->numEncounters++; } } // GAY/LES COUPLES 8 // if opposite sex: both reverse direction and take random velocities // if same sex: both take average direction and NN velocity if (Form1->RadioGroupFlockingBehavior->ItemIndex == 8) { findNNeighborTo(i); if ((NNeighborDist < radius) && (agent[i]->lastNN != NNeighborTag)) { if (agent[i]->sex != agent[NNeighborTag]->sex) { // leave if (behavioralSonification) { message.data[0] = 0x90; message.data[1] = 55; message.data[2] = 100; message.data[3] = 0; midiOutShortMsg(device, message.word); } agent[i]->direction += M_PI; if (agent[i]->direction > 2 * M_PI) { agent[i]->direction = agent[i]->direction - 2 * M_PI; } agent[NNeighborTag]->direction += M_PI; if (agent[NNeighborTag]->direction > 2 * M_PI) { agent[NNeighborTag]->direction = agent[NNeighborTag]->direction - 2 * M_PI; } agent[i]->velocity = float(random(1000)) / 1500 + .1; agent[NNeighborTag]->velocity = float(random(1000)) / 1500 + .1; } else { // join if (behavioralSonification) { message.data[0] = 0x90; message.data[1] = 67; message.data[2] = 100; message.data[3] = 0; midiOutShortMsg(device, message.word); } sumYs = agent[i]->velocity * sin(agent[i]->direction) + agent[NNeighborTag]->velocity * sin(agent[NNeighborTag]->direction); sumXs = agent[i]->velocity * cos(agent[i]->direction) + agent[NNeighborTag]->velocity * cos(agent[NNeighborTag]->direction); agent[i]->direction = atan2(sumYs, sumXs); agent[NNeighborTag]->direction = agent[i]->direction; agent[i]->velocity = sqrt(sumYs * sumYs + sumXs * sumXs) / 2; agent[NNeighborTag]->velocity = agent[i]->velocity; } agent[i]->lastNN = NNeighborTag; // remember lastNN agent[NNeighborTag]->lastNN = i; agent[i]->encounters[NNeighborTag]++; // remember encounter agent[i]->numEncounters++; agent[NNeighborTag]->encounters[i]++; agent[NNeighborTag]->numEncounters++; } } // Your direction and velocity are the average of those 9 // you can see within a given radius... if (Form1->RadioGroupFlockingBehavior->ItemIndex == 9) { averageOfNeighbors(i); if (aveVelo != 0 && aveDir != 0 && sumVisibleNeighbors > 1) { if (random(2)) { agent[i]->velocity = aveVelo + (float(random(50))/200); } else { agent[i]->velocity = aveVelo - (float(random(50))/200); } if (random(2)) { agent[i]->direction = aveDir + (float(random(10))/360)*2*M_PI; } else { agent[i]->direction = aveDir - (float(random(10))/360)*2*M_PI; } agent[i]->flocking = true; } else if (agent[i]->flocking == TRUE) { agent[i]->direction = (float(random(360))/360)*2*M_PI; agent[i]->velocity = float(random(1000)) / 1500 + .1; agent[i]->flocking = false; } } // Banking 10 // To create some variation, agents do not go directly to their goals, // in fact, each agent's deviation varies with it's Tag if (Form1->RadioGroupFlockingBehavior->ItemIndex == 10) { if (agent[i]->sex) { // female agent[i]->direction = directionFromTo(i, COLORBANK) + i * .07; } else { // male agent[i]->direction = directionFromTo(i, BLACKBANK) - i * .07; } agent[COIN]->x = agent[0]->x; agent[COIN]->y = agent[0]->y; image[COIN]->Left = agent[COIN]->x - 23; image[COIN]->Top = agent[COIN]->y - 55; // calling findNThingTo also calculates the distance // next to last Tag # (a female) to reach the target // she takes the most indirect route so may arrive last, but // she may have the highest velocity and thus arrive first findNThingTo(curpop - 2); // first agent to reach the target // no one else gets the chance to reach the target //findNThingTo(i); if (movePerTimer == false && NThingDist < 1) { moveTargets(); } } /////////////////////////////////////////////////////////////////////// ///////////////////// FLOCKING BEHAVIORS ABOVE /////////////////////// /////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////// WRAP if (wrap) { if (agent[i]->x > 590) { agent[i]->x = 30; sonify(EAST); } if (agent[i]->y > 560) { agent[i]->y = 50; sonify(SOUTH); } if (agent[i]->x < 30) { agent[i]->x = 590; sonify(NORTH); } if (agent[i]->y < 50) { agent[i]->y = 560; sonify(WEST); } visualize(i); } //////////////////////////////////////////////////////////////// BOUNCE else { if (agent[i]->x > 590) { agent[i]->x = 589; agent[i]->direction = M_PI - agent[i]->direction; sonify(EAST); } if (agent[i]->y > 560) { agent[i]->y = 559; agent[i]->direction = 2 * M_PI - agent[i]->direction; sonify(SOUTH); } if (agent[i]->x < 30) { agent[i]->x = 31; agent[i]->direction = M_PI - agent[i]->direction; sonify(WEST); } if (agent[i]->y < 50) { agent[i]->y = 51; agent[i]->direction = 2 * M_PI - agent[i]->direction; sonify(NORTH); } // modular divide direction by one rotation if (agent[i]->direction > 2 * M_PI) { agent[i]->direction = agent[i]->direction - 2 * M_PI; } if (agent[i]->direction < 0) { agent[i]->direction = agent[i]->direction + 2 * M_PI; } } ///////////////////////////////////////////////////////// RECORD A PATH ix = agent[i]->x; iy = agent[i]->y; iterationPath[ix][iy] = iterations; agentPath[ix][iy] = i + 5; } } //----------------------------------------------------------------------- Run void run (void) { Form1->Refresh(); agentsAreDisplayed = true; stop = false; showNNs = false; while (stop == false && iterations < runTo) { step(); Application->ProcessMessages(); } if (!mouseDown) { PlaySound("C:\\WINDOWS\\Media\\chimes.wav", "", SND_ASYNC); } if (showNNs) { for (int i = 0; i < curpop; i++) { showNearestNeighbor(i); } } stop = true; showNNs = false; } //=========================================================================== // EVENT HANDLERS //=========================================================================== //---------------------------- BORLAND will create this EVENT HANDLER for you //------------------------------- Place your VARIABLES and FUNCTIONS ABOVE it // ------------------------------------------ Use this instead of FORM CREATE __fastcall TForm1::TForm1(TComponent* Owner) : TForm(Owner) { curpop = INIPOP; // Double buffering eliminates some screen flicker but takes 30% longer. DoubleBuffered = true; randomize(); // initializes MIDI midiOutOpen(&device, midiport, 0, 0, CALLBACK_NULL); message.data[0] = 0xC0; message.data[1] = 6; message.data[2] = 100; message.data[3] = 0; midiOutShortMsg(device, message.word); for (int i = 0; i < MAXPOP; i++) { agent[i] = new anAgent; agent[i]->x = random(560) + 30; agent[i]->y = random(510) + 50; agent[i]->direction = (float(random(1000)) / 500) * M_PI; agent[i]->velocity = float(random(1000)) / 1500 + .1; agent[i]->flocking = false; if (i % 2 == 0) { agent[i]->sex = WOMAN; } else agent[i]->sex = MAN; if (i % 10 == 0) { agent[i]->type = WHITE; agent[i]->sex = WOMAN; } if (i % 10 == 1) { agent[i]->type = WHITE; agent[i]->sex = MAN; } if (i % 10 == 2) { agent[i]->type = CYAN; agent[i]->sex = WOMAN; } if (i % 10 == 3) { agent[i]->type = CYAN; agent[i]->sex = MAN; } if (i % 10 == 4) { agent[i]->type = MAGENTA; agent[i]->sex = WOMAN; } if (i % 10 == 5) { agent[i]->type = MAGENTA; agent[i]->sex = MAN; } if (i % 10 == 6) { agent[i]->type = YELLOW; agent[i]->sex = WOMAN; } if (i % 10 == 7) { agent[i]->type = YELLOW; agent[i]->sex = MAN; } if (i % 10 == 8) { agent[i]->type = BLACK; agent[i]->sex = WOMAN; } if (i % 10 == 9) { agent[i]->type = BLACK; agent[i]->sex = MAN; } agent[i]->newDirection = 0; agent[i]->newDistance = 0; agent[i]->lastDistance = 0; agent[i]->flocking = 0; agent[i]->lastNN = -1; agent[i]->seeking = random(MAXPOP); while (i == agent[i]->seeking) { // don't seek self agent[i]->seeking = random(MAXPOP); } if (i < curpop) { agent[i]->active = true; } else agent[i]->active = false; for (int j = 0; j < MAXPOP; j++) { agent[i]->encounters[j] = 0; } // defines an array of shapes with properties and events shape[i] = new TShape(Form1); shape[i]->Parent = Form1; //shape[i]->OnMouseDown = ShapeMouseDown; //shape[i]->OnMouseUp = ShapeMouseUp; //shape[i]->OnMouseMove = ShapeMouseMove; shape[i]->Height = 30; shape[i]->Width = 30; shape[i]->Left = 0; shape[i]->Top = 0; shape[i]->Shape = stCircle; shape[i]->Tag = i; shape[i]->Pen->Width = 2; //shape[i]->Pen->Color = colorRamp // (INIPOP - 1 - shape[i]->Tag, INIPOP - 1); shape[i]->Pen->Color = clGray; shape[i]->Brush->Color = colorRamp(shape[i]->Tag, INIPOP - 1); shape[i]->SendToBack(); if (i < curpop) { shape[i]->Visible = true; } else shape[i]->Visible = false; // defines an array of images with properties and events image[i] = new TImage(Form1); image[i]->Parent = Form1; image[i]->OnMouseDown = Form1->ImageMouseDown; image[i]->OnMouseUp = Form1->ImageMouseUp; image[i]->OnMouseMove = Form1->ImageMouseMove; image[i]->AutoSize= true; image[i]->Left = 0; image[i]->Top = 0; if (i % 10 == 0) { image[i]->Picture = Form1->ImageWomanWhite->Picture; } if (i % 10 == 1) { image[i]->Picture = Form1->ImageManWhite->Picture; } if (i % 10 == 2) { image[i]->Picture = Form1->ImageWomanCyan->Picture; } if (i % 10 == 3) { image[i]->Picture = Form1->ImageManCyan->Picture; } if (i % 10 == 4) { image[i]->Picture = Form1->ImageWomanMagenta->Picture; } if (i % 10 == 5) { image[i]->Picture = Form1->ImageManMagenta->Picture; } if (i % 10 == 6) { image[i]->Picture = Form1->ImageWomanYellow->Picture; } if (i % 10 == 7) { image[i]->Picture = Form1->ImageManYellow->Picture; } if (i % 10 == 8) { image[i]->Picture = Form1->ImageWomanBlack->Picture; } if (i % 10 == 9) { image[i]->Picture = Form1->ImageManBlack->Picture; } image[i]->Transparent = true; image[i]->Tag = i; image[i]->BringToFront(); if (i < curpop) { image[i]->Visible = true; } else image[i]->Visible = false; } // create some "thing" agents as the last agents in MAXPOP // the "things" will appear in front of the "humans" image[COIN]->Picture = ImageCoin->Picture; image[COIN]->Visible = false; image[COIN]->Left = 280; agent[COIN]->x = image[COIN]->Left + image[COIN]->Width / 2; image[COIN]->Top = 290; agent[COIN]->y = image[COIN]->Top + image[COIN]->Height / 2; image[COLORBANK]->Picture = ImageBank1->Picture; image[COLORBANK]->Visible = false; image[COLORBANK]->Left = 0; agent[COLORBANK]->x = image[COLORBANK]->Left + image[COLORBANK]->Width / 2; image[COLORBANK]->Top = 290; agent[COLORBANK]->y = image[COLORBANK]->Top + image[COLORBANK]->Height / 2; image[BLACKBANK]->Picture = ImageBank2->Picture; image[BLACKBANK]->Visible = false; image[BLACKBANK]->Left = 540; agent[BLACKBANK]->x = image[BLACKBANK]->Left + image[BLACKBANK]->Width / 2; image[BLACKBANK]->Top = 290; agent[BLACKBANK]->y = image[BLACKBANK]->Top + image[BLACKBANK]->Height / 2; for (int i = 0; i < INIPOP; i++) { image[i]->BringToFront(); } // send the background behind every "thing" and "human" Form1->ImageBackground->SendToBack(); Form1->EditPopulation->Text = INIPOP; shuffle(); } //------------------------------------------------------- On image MOUSE DOWN // An exception to the rule which says "Let Borland write event handlers." // This one you must type in yourself in addition to a reference to it // in Unit1.h (look at the source code in that unit). void __fastcall TForm1::ImageMouseDown(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y) { // Remembers where on the image the mouse was downed TImage *image = dynamic_cast(Sender); // The following will be used for mouseMove and mouseUp events... // Captures the index number of the image that was clicked chosenAgent = image->Tag; // Captures the position within the image that was clicked imageDownX = X; imageDownY = Y; // Captures the position of the agent when its image was clicked agentDownX = agent[chosenAgent]->x; agentDownY = agent[chosenAgent]->y; // remembers if we were stopped or running wasStopped = stop; mouseDown = true; stop = true; if (Button == 0) { // LEFT Button means drag an agent image // Remembers that an image was chosen for mouseMove and mouseUp agentWasJustChosen = true; } else { // RIGHT Button means show nearest neighbor showNearestNeighbor(chosenAgent); showPerceptualField(chosenAgent); } // Capture time on Mouse Down timeDown = Now(); } //------------------------------------------------------- On image MOUSE MOVE // An exception to the rule which says "Let Borland write event handlers." // This one you must type in yourself in addition to a reference to it // in Unit1.h (look at the source code in that unit). void __fastcall TForm1::ImageMouseMove(TObject *Sender, TShiftState Shift, int X, int Y) { TImage *image = dynamic_cast(Sender); chosenAgent = image->Tag; if (agentWasJustChosen) { // drag an agent image // this drags the image along... image->Left = image->Left + X - imageDownX; image->Top = image->Top + Y - imageDownY; agent[chosenAgent]->x = image->Left + image->Width / 2; agent[chosenAgent]->y = image->Top + image->Height / 2; } else if (image->Tag != lastMouseOver) { // probe an agent // agent values are displayed ONLY ONCE per MouseMove Form1->Refresh(); EditAgent->Text = image->Tag; EditX->Text = int(agent[chosenAgent]->x); EditY->Text = int(agent[chosenAgent]->y); EditSeeking->Text = agent[chosenAgent]->seeking; EditEncounters->Text = agent[chosenAgent]->numEncounters; if (agent[chosenAgent]->type == WHITE) EditType->Text = "White"; if (agent[chosenAgent]->type == CYAN) EditType->Text = "Cyan"; if (agent[chosenAgent]->type == MAGENTA) EditType->Text = "Magenta"; if (agent[chosenAgent]->type == YELLOW) EditType->Text = "Yellow"; if (agent[chosenAgent]->type == BLACK) EditType->Text = "Black"; EditDirection->Text = FormatFloat("0.00", agent[chosenAgent]->direction); EditVelocity->Text = FormatFloat("0.00", agent[chosenAgent]->velocity); for (int i = 0; i < curpop; i++) { Form1->Canvas->TextOutA(agent[i]->x - 3, agent[i]->y - 4, agent[chosenAgent]->encounters[i]); if (i == chosenAgent) { Form1->Canvas->TextOutA(agent[i]->x - 7, agent[i]->y - 4, "ME"); } } if (agent[chosenAgent]->sex == WOMAN) { EditSex->Text= "F"; } else EditSex->Text= "M"; EditNN->Text = findNNeighborTo(chosenAgent); lastMouseOver = chosenAgent; } } //--------------------------------------------------------- On image MOUSE UP // An exception to the rule which says "Let Borland write event handlers." // This one you must type in yourself in addition to a reference to it // in Unit1.h (look at the source code in that unit). void __fastcall TForm1::ImageMouseUp(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y) { mouseDown = false; //TImage *image = dynamic_cast(Sender); // this is the end of the drag... agentWasJustChosen = false; EditAgent->Text = chosenAgent; // Capture Position of Agent on Mouse Up agentUpY = agent[chosenAgent]->y; agentUpX = agent[chosenAgent]->x; // Capture Change of Position of Agent dY = agentUpY - agentDownY; dX = agentUpX - agentDownX; // Avoid division by zero in "atan(dY / dX)" below: if (dX == 0) { dX = 0.0000000000001; } // Assign new agent direction: agent[chosenAgent]->direction = atan2(dY, dX); // Capture Time on Mouse Up timeUp = Now(); // Assign New Agent Velocity as "distance / time": agent[chosenAgent]->velocity = (sqrt((dY*dY) + (dX * dX))/(timeUp - timeDown)) / 15000000; Form1->Refresh(); // if we were running before the drag, then run... if (!wasStopped) { run(); } } //---------------------------------------------------------------- Run BUTTON void __fastcall TForm1::ButtonRunClick(TObject *Sender) { PlaySound("C:\\WINDOWS\\Media\\start.wav", "", SND_ASYNC); Form1->LabelPathsBy->Visible = false; if (Form1->RadioGroupFlockingBehavior->ItemIndex == 10) Timer1->Enabled = true; run(); } //--------------------------------------------------------------- Step BUTTON void __fastcall TForm1::ButtonStepClick(TObject *Sender) { PlaySound("C:\\WINDOWS\\Media\\start.wav", "", SND_ASYNC); Form1->LabelPathsBy->Visible = false; Form1->Refresh(); stop = true; step(); } //--------------------------------------------------------------- Stop BUTTON void __fastcall TForm1::ButtonStopClick(TObject *Sender) { PlaySound("C:\\WINDOWS\\Media\\start.wav", "", SND_ASYNC); stop = true; if (Form1->RadioGroupFlockingBehavior->ItemIndex == 10) Timer1->Enabled = false; } //---------------------------------------------------------- Randomize BUTTON void __fastcall TForm1::ButtonResetClick(TObject *Sender) { PlaySound("C:\\WINDOWS\\Media\\start.wav", "", SND_ASYNC); Form1->LabelPathsBy->Visible = false; reset(); } //------------------------------------------------------------- Circle BUTTON void __fastcall TForm1::ButtonCircleClick(TObject *Sender) { PlaySound("C:\\WINDOWS\\Media\\start.wav", "", SND_ASYNC); Form1->LabelPathsBy->Visible = false; circle(); } //----------------------------------------------------------- Sideline BUTTON void __fastcall TForm1::ButtonSidelineClick(TObject *Sender) { PlaySound("C:\\WINDOWS\\Media\\start.wav", "", SND_ASYNC); Form1->LabelPathsBy->Visible = false; corner(); } //--------------------------------------------- Show Nearest Neighbors BUTTON void __fastcall TForm1::ButtonShowNNsClick(TObject *Sender) { PlaySound("C:\\WINDOWS\\Media\\start.wav", "", SND_ASYNC); if (agentsAreDisplayed) Form1->Refresh(); if (stop) { for (int i = 0; i < curpop; i++) { showNearestNeighbor(i); } } else { showNNs = true; stop = true; } } //-------------------------------------------------------- Open Bitmap BUTTON void __fastcall TForm1::ButtonOpenBMPClick(TObject *Sender) { PlaySound("C:\\WINDOWS\\Media\\start.wav", "", SND_ASYNC); if (OpenBitMapDialog->Execute() ) b->LoadFromFile(OpenBitMapDialog->FileName); bmpToArray(b); renderBMP(b); } //------------------------------------------------ Show Paths By Agent BUTTON void __fastcall TForm1::ButtonShowPathsByAgent2dClick(TObject *Sender) { PlaySound("C:\\WINDOWS\\Media\\start.wav", "", SND_ASYNC); agentsAreDisplayed = false; Form1->LabelPathsBy->Visible = true; Form1->LabelPathsBy->Caption = "Paths Colored by Agent"; for (int i = 0; i < 612; i++) { for (int j = 0; j < 612; j++) { Form1->PaintBox1->Canvas->Pixels[i][j] = colorRamp(agentPath[i][j], curpop + 4); } } Form1->LabelPathsBy->BringToFront(); } //------------------------------------------------- Show Paths By Time BUTTON void __fastcall TForm1::ButtonShowPathsByTime2dClick(TObject *Sender) { PlaySound("C:\\WINDOWS\\Media\\start.wav", "", SND_ASYNC); agentsAreDisplayed = false; Form1->LabelPathsBy->Visible = true; Form1->LabelPathsBy->Caption = "Paths Colored by Time"; for (int i = 0; i < 612; i++) { for (int j = 0; j < 612; j++) { Form1->PaintBox1->Canvas->Pixels[i][j] = colorRamp(iterationPath[i][j], iterations); } } Form1->LabelPathsBy->BringToFront(); } //------------------------------------------------------- Add an Agent BUTTON void __fastcall TForm1::ButtonAddAnAgentClick(TObject *Sender) { if (curpop < 100) { PlaySound("C:\\WINDOWS\\Media\\start.wav", "", SND_ASYNC); addNewAgent(curpop); curpop++; Form1->EditPopulation->Text = curpop; } else { PlaySound ("C:\\WINDOWS\\Media\\Windows XP Battery Low.wav", "", SND_ASYNC); } } //------------------------------------------------------ Kill an Agent BUTTON void __fastcall TForm1::ButtonKillAnAgentClick(TObject *Sender) { if (curpop > 2) { PlaySound("C:\\WINDOWS\\Media\\start.wav", "", SND_ASYNC); curpop--; killOldAgent(curpop); Form1->EditPopulation->Text = curpop; } else { PlaySound ("C:\\WINDOWS\\Media\\Windows XP Battery Low.wav", "", SND_ASYNC); } } //--------------------------------------------------- Zeroize Velocity BUTTON void __fastcall TForm1::ButtonZeroizeVelocityClick(TObject *Sender) { for (int i = 0; i < curpop; i++) { agent[i]->velocity = 0; } } //-------------------------------------------------- Zeroize Direction BUTTON void __fastcall TForm1::ButtonZeroizeDirectionClick(TObject *Sender) { for (int i = 0; i < curpop; i++) { agent[i]->direction = 0; } } //------------------------------------------------ Show All Encounters BUTTON void __fastcall TForm1::ButtonShowAllEncountersClick(TObject *Sender) { Form1->Canvas->Pen->Width = 3; int maxEncounters = 0; for (int i = 0; i < curpop; i++) { // find maximum encounters for (int j = 0; j < curpop; j++) { if (agent[i]->encounters[j] > maxEncounters) { maxEncounters = agent[i]->encounters[j]; } } } for (int i = 0; i < curpop; i++) { // show all encounters for (int j = 0; j < curpop; j++) { if (maxEncounters > 0) Form1->Canvas->Pen->Width = 10 * float(agent[i]->encounters[j]) / maxEncounters; else Form1->Canvas->Pen->Width = 0; Form1->Canvas->Pen->Color = colorRamp (agent[i]->encounters[j], maxEncounters); if (agent[i]->encounters[j] > 0) { Form1->Canvas->MoveTo(agent[i]->x, agent[i]->y); Form1->Canvas->LineTo(agent[j]->x, agent[j]->y); } } } } //---------------------------------------------------------- Show Tags BUTTON void __fastcall TForm1::ButtonShowTagsClick(TObject *Sender) { for (int i = 0; i < curpop; i++) { Form1->Canvas->TextOutA(agent[i]->x - 3, agent[i]->y - 4, i); } } //---------------------------------------------- Move Agent Images RADIOGROUP void __fastcall TForm1::RadioGroupMoveAgentImagesClick(TObject *Sender) { PlaySound("C:\\WINDOWS\\Media\\start.wav", "", SND_ASYNC); } //---------------------------------------------- Move Agent Shapes RADIOGROUP void __fastcall TForm1::RadioGroupMoveAgentShapesClick(TObject *Sender) { PlaySound("C:\\WINDOWS\\Media\\start.wav", "", SND_ASYNC); } //---------------------------------------------- Flocking Behavior RADIOGROUP void __fastcall TForm1::RadioGroupFlockingBehaviorClick(TObject *Sender) { PlaySound("C:\\WINDOWS\\Media\\start.wav", "", SND_ASYNC); if (Form1->RadioGroupFlockingBehavior->ItemIndex == 10) { //Form1->Timer1->Enabled = true; image[COIN]->Visible = true; image[COLORBANK]->Visible = true; image[BLACKBANK]->Visible = true; } else { Timer1->Enabled = false; image[COIN]->Visible = false; image[COLORBANK]->Visible = false; image[BLACKBANK]->Visible = false; } } //----------------------------------- Perceptual Field Radius Change TRACKBAR void __fastcall TForm1::TrackBarRadiusChange(TObject *Sender) { Form1->Refresh(); radius = TrackBarRadius->Position; Form1->EditRadius->Text = radius; if (stop == true) { for (int i = 0; i < curpop; i++) { showPerceptualField(i); } } } //--------------------------------------------------------------------- TIMER void __fastcall TForm1::Timer1Timer(TObject *Sender) { Form1->LabelTime->Caption = Now(); if (movePerTimer) { moveTargets(); } } //---------------------------------------------------------------- FORM CLOSE void __fastcall TForm1::FormClose(TObject *Sender, TCloseAction &Action) { midiOutClose(&device); } //-------------------------------------------------------- "That's All Folks" void __fastcall TForm1::N1001Click(TObject *Sender) { PlaySound("C:\\WINDOWS\\Media\\start.wav", "", SND_ASYNC); runTo = 100; } //---------------------------------------------------------- MENU ITEMS BELOW void __fastcall TForm1::N5001Click(TObject *Sender) { PlaySound("C:\\WINDOWS\\Media\\start.wav", "", SND_ASYNC); runTo = 500; } //--------------------------------------------------------------------------- void __fastcall TForm1::N10001Click(TObject *Sender) { PlaySound("C:\\WINDOWS\\Media\\start.wav", "", SND_ASYNC); runTo = 1000; } //--------------------------------------------------------------------------- void __fastcall TForm1::N50001Click(TObject *Sender) { PlaySound("C:\\WINDOWS\\Media\\start.wav", "", SND_ASYNC); runTo = 5000; } //--------------------------------------------------------------------------- void __fastcall TForm1::N100001Click(TObject *Sender) { PlaySound("C:\\WINDOWS\\Media\\start.wav", "", SND_ASYNC); runTo = 10000; } //--------------------------------------------------------------------------- void __fastcall TForm1::N500001Click(TObject *Sender) { PlaySound("C:\\WINDOWS\\Media\\start.wav", "", SND_ASYNC); runTo = 50000; } //--------------------------------------------------------------------------- void __fastcall TForm1::Off1Click(TObject *Sender) { soundType = 0; } //--------------------------------------------------------------------------- void __fastcall TForm1::Beep1Click(TObject *Sender) { soundType = 1; behavioralSonification = false; Form1->Off2->Checked = true; } //--------------------------------------------------------------------------- void __fastcall TForm1::Windows1Click(TObject *Sender) { soundType = 2; behavioralSonification = false; Form1->Off2->Checked = true; } //--------------------------------------------------------------------------- void __fastcall TForm1::Pinball1Click(TObject *Sender) { soundType = 3; behavioralSonification = false; Form1->Off2->Checked = true; } //--------------------------------------------------------------------------- void __fastcall TForm1::Midi1Click(TObject *Sender) { soundType = 4; behavioralSonification = false; Form1->Off2->Checked = true; } //--------------------------------------------------------------------------- void __fastcall TForm1::Off2Click(TObject *Sender) { behavioralSonification = false; } //--------------------------------------------------------------------------- void __fastcall TForm1::On1Click(TObject *Sender) { behavioralSonification = true; soundType = false; Form1->Off1->Checked = true; } //--------------------------------------------------------------------------- void __fastcall TForm1::Sequential1Click(TObject *Sender) { PlaySound("C:\\WINDOWS\\Media\\start.wav", "", SND_ASYNC); polling = SEQUENTIAL; } //--------------------------------------------------------------------------- void __fastcall TForm1::Random1Click(TObject *Sender) { PlaySound("C:\\WINDOWS\\Media\\start.wav", "", SND_ASYNC); polling = RANDOM; } //--------------------------------------------------------------------------- void __fastcall TForm1::Wrap1Click(TObject *Sender) { wrap = true; } //--------------------------------------------------------------------------- void __fastcall TForm1::Bounce1Click(TObject *Sender) { wrap = false; } //--------------------------------------------------------------------------- void __fastcall TForm1::RadioGroupMoveTargetsClick(TObject *Sender) { if (RadioGroupMoveTargets->ItemIndex == 0) { movePerTimer = true; } else movePerTimer = false; } //--------------------------------------------------------------------------- //--------------------------------------------------------------------------- void __fastcall TForm1::TrackBarTimerChange(TObject *Sender) { Timer1->Interval = TrackBarTimer->Position * 1000; Form1->EditTimer->Text = TrackBarTimer->Position; } //---------------------------------------------------------------------------