How do I randomise specific colours on Processing - arrays

I am looking for some help to randomize specific colors on Processing using the Array functions. For example I only want the colors to be a specifically red, blue, yellow and green. How can I ensure that when each single letter bounces off the wall, the letter's color changes to one of these colors?
Below is my code, really appreciate the help.
String word = "bounce";
char[] letters;
ArrayList<Letter> letterObjects;
boolean ballFall = false;
PFont font;
color randColour = color (0);
Letter l;
void setup () {
size (500, 500);
pixelDensity(displayDensity());
textAlign(CENTER);
textSize(30);
letters = word.toCharArray();
letterObjects = new ArrayList<Letter>();
font = createFont("AvenirNext-Medium", 50);
textFont(font);
//iterate over the letter array
//for each letter create a new object
//add this object to an ArrayLost
for (int i = 0; i<letters.length; i++) {
char currentLetter = letters[i];
float currentPosition = i * 30;
letterObjects.add(new Letter(currentLetter, 180 + currentPosition, height/2));
}
}
void draw () {
background(255);
for (Letter l : letterObjects) {
l.display();
}
if (ballFall == true) {
for (Letter l : letterObjects) {
l.move();
l.bounce();
}
}
}
void mouseClicked() {
ballFall = true;
}
The Letter class
class Letter {
char character;
float x, y;
float xSpeed, ySpeed;
float distance;
Letter(char _c, float _x, float _y) {
character = _c;
x = _x;
y = _y;
//x = random(width);
//y = random(height);
xSpeed = random(1, 3);
ySpeed = random(1, 3);
}
void move () {
x += xSpeed*2;
y += ySpeed*2;
}
void bounce () {
if (x<0 || x>width) {
xSpeed *=-1;
randColour = color (random(255), random (255), random(255));
}
if (y<0 || y>height) {
ySpeed *=-1;
randColour = color (random(255), random (255), random(255));
}
}
void display () {
fill(randColour);
text(character, x, y);
}
}

Make a list of the colors you want to choose from
color red = #FF0000;
color blue = #0000FF;
color yellow = #FFFF00;
color green = #00FF00;
color[] colors = { red, blue, yellow, green };
Then use the random method to pick an index in the array. And use the color at that index:
For your case, you can write your Letter class this way:
Assuming the rest of the code using the Letter class works properly
class Letter {
char character;
float x, y;
float xSpeed, ySpeed;
float distance;
// Declare the colors you want to use in a an array
color red = #FF0000;
color blue = #0000FF;
color yellow = #FFFF00;
color green = #00FF00;
color[] colors = { red, blue, yellow, green };
color randColor;
Letter(char _c, float _x, float _y) {
character = _c;
x = _x;
y = _y;
//x = random(width);
//y = random(height);
xSpeed = random(1, 3);
ySpeed = random(1, 3);
// Pick a random initial color
randColor = colors[int(random(colors.length))];
}
void move () {
x += xSpeed*2;
y += ySpeed*2;
}
void bounce () {
if (x<0 || x>width) {
xSpeed *= -1;
// Pick a random color
randColor = colors[int(random(colors.length))];
} else if (y<0 || y>height) {
ySpeed *= -1;
// Pick a random color
randColor = colors[int(random(colors.length))];
}
}
void display () {
fill(randColor);
text(character, x, y);
}
}

Related

How can i stop the rotation of an object in an array? P5.JS

this is for a project in my p5.js class.
I have a class that creates a 3D shape and i call it in my draw function in a for loop. In this for loop i create the shape and it has a rotation. If i press the the "a" button, it creates a new shape. My problem is, that i want to stop the rotation of the previous shape when i create a new shape, but i can't find a solution.
this is my code:
let BLACK;
let GRAY;
let LIGHTGRAY;
let WHITE;
let RED;
let forms = [];
let coorX, coorY, coorZ, colour;
let COL = [];
let ran;
function setup() {
createCanvas(586, 810, WEBGL);
BLACK = color(0);
GRAY = color(70);
LIGHTGRAY = color(180);
WHITE = color(255);
RED = color(217, 4, 33);
COL = [BLACK, WHITE, GRAY, RED, RED\]
ran = random(0.01, 0.1)
}
function draw() {
background(80);
pointLight(250, 250, 250, 250);
for (let i = 0; i < forms.length; i++) {
newSpeed = 0.05 + i * ran
forms[i].create(newSpeed, 0.01);
if (forms.length > 1) {
rotateX(0);
}
}
if (forms.length > 10) {
//Array limited on 10 objects
forms.splice(0, 1)
}
}
function keyTyped() {
if (key === 'a') {
coorX = int(random(-100, 100))
coorY = int(random(-100, 100))
coorZ = int(random(-200, 200))
forms.push(new Shape(coorX, coorY, coorZ));
}
if (key === 'd') {
forms.pop()
}
}
class Shape {
constructor(posX, posY, posZ, colour) {
this.x = 50; //width
this.y = 50; //height
this.z = 50; // depth
this.x1 = 0;
this.y1 = 500;
this.z1 = 80;
this.posX = posX;
this.posY = posY;
this.posZ = posZ;
this.rand = int(random(0, 5));
this.colour = colour;
}
create (speed, rotation) {
//create a new shape
stroke(0);
strokeWeight(0);
push();
translate(this.posX, this.posY, this.posZ)
//rotate the shape
this.speed = speed;
this.rotation = rotation;
rotateX((frameCount * this.rotation) * speed)
rotateY((frameCount * this.rotation) * speed)
if (this.rand == 1) {
fill(RED)
box(50, 50, 50)
}
if (this.rand == 2) {
fill(LIGHTGRAY);
sphere(50, 10)
}
if (this.rand == 3) {
fill(WHITE);
cylinder(5, 280, 15)
}
if (this.rand == 4) {
fill(GRAY);
torus(90, 24, 3)
}
pop();
}
}
I tried separating the rotation and the creation function, but then it rotated the whole canvas and not the shapes individually.
In fact, in p5.js approach is completely different, and You need to analyze this example: https://p5js.org/examples/simulate-multiple-particle-systems.html
But, to solve Your problem in 'object style':
1 - You need to memorize state of the object, in this case the frameCount of the last frame when the key a was pressed,
2 - draw all shapes with memorized lastActiveFrame and one just with recent frameCount.
let BLACK;
let GRAY;
let LIGHTGRAY;
let WHITE;
let RED;
let forms = [];
let coorX, coorY, coorZ, colour;
let COL = [];
let ran;
function setup() {
createCanvas(586, 810, WEBGL);
BLACK = color(0);
GRAY = color(70);
LIGHTGRAY = color(180);
WHITE = color(255);
RED = color(217,4,33);
COL = [BLACK, WHITE, GRAY, RED, RED]
ran = random(0.01,0.1)
coorX = int(random(-100,100))
coorY = int(random(-100,100))
coorZ = int(random(-200,200))
forms.push(new Shape(coorX, coorY, coorZ));
}
function draw() {
background(80);
pointLight(250, 250, 250, 250);
for(let i = 0; i < forms.length-1; i++) {
newSpeed = 0.05 + i * ran
forms[i].show(newSpeed, 0.01);
}
forms[forms.length-1].rotate(2.5, 0.01);
if (forms.length > 10){
//Array limited on 10 objects
forms.splice(0,1)
}
}
function keyTyped() {
if (key === 'a'){
coorX = int(random(-100,100))
coorY = int(random(-100,100))
coorZ = int(random(-200,200))
forms.push(new Shape(coorX, coorY, coorZ));
}
if (key === 'd'){
forms.pop()
}
}
class Shape {
constructor(posX, posY, posZ, colour){
this.posX = posX;
this.posY = posY;
this.posZ = posZ;
this.rand = int(random(0,5));
this.colour = colour;
this.lastActiveFrame = frameCount;
}
rotate(speed, rotation){
//create a new shape
stroke(0);
strokeWeight(0);
push();
translate(this.posX, this.posY, this.posZ)
//rotate the shape
this.lastActiveFrame = frameCount;
rotateX(frameCount * rotation * speed)
rotateY(frameCount * rotation * speed)
if (this.rand == 1){
fill(RED)
box(50,50,50)
}if(this.rand == 2) {
fill(LIGHTGRAY);
sphere(50,10)
}if(this.rand == 3){
fill(WHITE);
cylinder(5,280,15)
}if(this.rand == 4){
fill(GRAY);
torus(90,24,3)
}
pop();
}
show(speed, rotation){
//create a new shape
stroke(0);
strokeWeight(0);
push();
translate(this.posX, this.posY, this.posZ)
//rotate the shape
rotateX(this.lastActiveFrame * rotation * speed)
rotateY(this.lastActiveFrame * rotation * speed)
if (this.rand == 1){
fill(RED)
box(50,50,50)
}if(this.rand == 2) {
fill(LIGHTGRAY);
sphere(50,10)
}if(this.rand == 3){
fill(WHITE);
cylinder(5,280,15)
}if(this.rand == 4){
fill(GRAY);
torus(90,24,3)
}
pop();
}
}
In the console, p5.js says that the 4th argument of pointLight() must be a Vector. That argument is used to tell in which direction the light will point, as for the arguments 1 - 3, they tell where is the pointLight.
Vector reference
pointLight reference

Rotate Player in Relation to Rotated Rectangle

I'm trying to build a game where the player can stand on rotated rectangles. Take the example if a rectangular platform is rotated 20 degrees, then the player would be standing on the platform at a 20 degree angle as well, and could move along that rotated axis. Perhaps this image will clear this up:
Therefore, I need to:
Make the platform solid so the player can stand on it
Make the player rotate to the same angle as the platform
Make the player move on the rotated axis
I've tried to do this, but I've failed. Here's my code that I tried:
#include "raylib.h"
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#define WIDTH 1200
#define HEIGHT 800
typedef struct {
const int width;
const int height;
int FPS;
} Window;
Window window = {
.FPS = 60,
};
typedef struct {
Vector2 pos;
Vector2 acc;
Vector2 vel;
int width;
int height;
double accSpeed;
int maxVel;
double friction;
double rotation;
double scale;
float jumpForce;
float gravity;
bool canJump;
} Player;
Player player = {
.pos = {WIDTH/2, HEIGHT/2},
.acc = {0, 0},
.vel = {0, 0},
.width = 50,
.height = 100,
.accSpeed = 0.15,
.maxVel = 7,
.friction = 0.2,
.rotation = 0,
.scale = 0.5,
.jumpForce = 15,
.gravity = 0.5,
.canJump = true,
};
void movePlayerX();
void movePlayerY();
int rectCollide();
int main() {
InitWindow(WIDTH, HEIGHT, "Window");
SetTargetFPS(window.FPS);
//Rectangle playerArea = {player.pos.x, player.pos.y, playerImg.width*player.scale, playerImg.height*player.scale};
Rectangle playerArea;
Rectangle rect1 = {500, 600, 100, 250};
while (!WindowShouldClose()) {
playerArea = (Rectangle) {
player.pos.x,
player.pos.y,
player.width,
player.height,
};
BeginDrawing();
ClearBackground(RAYWHITE);
DrawRectanglePro(rect1, (Vector2) {0, 0}, 20, BLUE);
DrawRectanglePro(playerArea, (Vector2) {0, 0}, player.rotation, RED);
movePlayerX();
/*if (CheckCollisionRecs(playerArea, rect1)) {
if (player.vel.x < 0) { // If the player moved left and collided with the right side of block
player.pos.x = rect1.x + rect1.width;
} else { // If the player moved right and collided with the left side of block
player.pos.x = rect1.x - playerArea.width;
}
player.vel.x = 0;
}*/
movePlayerY();
if (CheckCollisionRecs(playerArea, rect1)) {
if (player.vel.y < 0) { // If the player hit their head
player.pos.y = rect1.y + rect1.height;
player.vel.y *= -0.5; // Not -1 because collisions are not perfectly elastic
} else {
player.pos.y = rect1.y - player.height;
player.rotation = 20;
player.vel.y = 0;
player.acc.y = 0;
player.canJump = true;
}
}
if (player.pos.y >= HEIGHT - player.height) {
player.canJump = true;
player.pos.y = HEIGHT - player.height;
player.vel.y = 0;
}
EndDrawing();
}
}
void movePlayerX() {
if (IsKeyDown(KEY_LEFT) && player.vel.x > -player.maxVel) {
player.acc.x = -player.accSpeed;
} else if (IsKeyDown(KEY_RIGHT) && player.vel.x < player.maxVel) {
player.acc.x = player.accSpeed;
} else if (abs(player.vel.x) > 0.2) {
if (player.vel.x < 0) {
player.acc.x = player.friction;
} else {
player.acc.x = -player.friction;
}
} else {
player.vel.x = 0;
player.acc.x = 0;
}
player.vel.x += player.acc.x;
player.pos.x += player.vel.x;
}
void movePlayerY() {
if (IsKeyPressed(KEY_UP) && player.vel.y == 0 && player.acc.y == 0 && player.canJump) {
player.canJump = false;
player.vel.y = -player.jumpForce;
}
player.acc.y += player.gravity;
player.vel.y += player.acc.y;
player.pos.y += player.vel.y;
player.acc.y = 0;
}
As can be seen from the code, after I call the player movement functions, movePlayerX() and movePlayerY(), I'm trying to detect if the player is colliding with the rectangle. However, I'm just using the regular built in CheckCollisionRecs() function, which detects collision on a non-rotated rectangle, which won't work.
Therefore, I was wondering: how can I get a function to detect the player's collison on a rotated rectangle, then rotate and move the player upon that rotated angle?
Thanks.

2D Raylib Texture Collisions

I was wondering how to properly handle collisions in Raylib. After setting up the basics, like a window, I would first load in the player texture, like so:
Texture2D playerTexture = LoadTexture("Player.png");
After that, I would draw the texture, with the Raylib function DrawTextureEx which allows me to adjust the rotation and scale of the texture. Then, I would add a simple movement script for the player, and that would be pretty much it.
As for collisions, I would just be testing the player collision on a rectangle. To get the area for the rectangle, I would just create a simple Rectangle struct like this:
Rectangle rect1 = {100, 100, 50, 50};
As for getting the player area, I would make something similar:
Rectangle playerArea = {player.x, player.y, playerTexture.width*player.scale, playerTexture.height*player.scale} //Values are stored in Player struct
However, when I try to check the collisons like this, nothing happens:
if (CheckCollisionRecs(playerArea, rect1)) {
DrawText("Collided", 5, 5, 25, BLACK);
}
Here's my full code, if needed:
#include "raylib.h"
#include <stdio.h>
#include <stdlib.h>
#define WIDTH 1200
#define HEIGHT 800
typedef struct {
const int width;
const int height;
int FPS;
} Window;
Window window = {
.FPS = 60,
};
typedef struct {
Vector2 pos;
Vector2 acc;
Vector2 vel;
int width;
int height;
double accSpeed;
int maxVel;
double friction;
double rotation;
double scale;
} Player;
Player player = {
.pos = {WIDTH/2, HEIGHT/2},
.acc = {0, 0},
.vel = {0, 0},
.width = 25,
.height = 25,
.accSpeed = 0.15,
.maxVel = 7,
.friction = 0.2,
.rotation = 0,
.scale = 0.5,
};
void movePlayer();
int rectCollide();
int main() {
InitWindow(WIDTH, HEIGHT, "Window");
SetTargetFPS(window.FPS);
Texture2D playerImg = LoadTexture("Player.png");
Rectangle playerArea = {player.pos.x, player.pos.y, playerImg.width*player.scale, playerImg.height*player.scale};
Rectangle rect1 = {100, 100, 50, 50};
Camera2D camera = { 0 };
camera.target = (Vector2){ player.pos.x + 20.0f, player.pos.y + 20.0f };
camera.offset = (Vector2){WIDTH/2.0f, HEIGHT/2.0f };
camera.rotation = 0.0f;
camera.zoom = 1.0f;
if (CheckCollisionRecs(playerArea, rect1)) {
DrawText("Collided", 5, 5, 25, BLACK);
}
while (!WindowShouldClose()) {
BeginDrawing();
ClearBackground(SKYBLUE);
movePlayer();
camera.target = (Vector2){ player.pos.x + 20, player.pos.y + 20 };
BeginMode2D(camera);
DrawRectangle(100, 100, 50, 50, BLACK);
DrawTextureEx(playerImg, player.pos, player.rotation, player.scale, RAYWHITE);
EndMode2D();
EndDrawing();
}
UnloadTexture(playerImg);
CloseWindow();
return 0;
}
void movePlayer() {
if (IsKeyDown(KEY_LEFT) && player.vel.x > -player.maxVel) {
player.acc.x = -player.accSpeed;
} else if (IsKeyDown(KEY_RIGHT) && player.vel.x < player.maxVel) {
player.acc.x = player.accSpeed;
} else if (abs(player.vel.x) > 0.2) {
if (player.vel.x < 0) {
player.acc.x = player.friction;
} else {
player.acc.x = -player.friction;
}
} else {
player.vel.x = 0;
player.acc.x = 0;
}
player.vel.x += player.acc.x;
player.pos.x += player.vel.x;
if (IsKeyDown(KEY_UP) && player.vel.y > -player.maxVel) {
player.acc.y = -player.accSpeed;
} else if (IsKeyDown(KEY_DOWN) && player.vel.x < player.maxVel) {
player.acc.y = player.accSpeed;
} else if (abs(player.vel.y) > 0.2) {
if (player.vel.y < 0) {
player.acc.y = player.friction;
} else {
player.acc.y = -player.friction;
}
} else {
player.vel.y = 0;
player.acc.y = 0;
}
player.vel.y += player.acc.y;
player.pos.y += player.vel.y;
}
int rectCollide(int x1, int y1, int w1, int h1, int x2, int y2, int w2, int h2) {
return x1 + w1 > x2 && x1 < x2 + w2 && y1 + h1 > y2 && y1 < y2 + h2;
}
And so, I was wondering: first of all, is there a better way to get the area of the texture, without having to create a Rectangle struct for each texture, and multiply the scale by the texture width and height? Secondly, I was wondering why my collisions aren't being detected. What is wrong with my code?
The collision check
if (CheckCollisionRecs(playerArea, rect1))
precedes the event loop.
Even moving it inside the loop will not have any effect, as playerArea is never updated in your event loop.
A quick fix would be to update the collision box after moving the player.
(example snippet of main, without images)
Rectangle playerArea;
Rectangle rect1 = {100, 100, 50, 50};
while (!WindowShouldClose()) {
movePlayer();
playerArea = (Rectangle) {
player.pos.x,
player.pos.y,
player.width,
player.height,
};
camera.target = (Vector2){ player.pos.x + 20, player.pos.y + 20 };
BeginDrawing();
ClearBackground(SKYBLUE);
BeginMode2D(camera);
DrawRectangleRec(rect1, RED);
DrawRectangle(player.pos.x, player.pos.y, player.width, player.height, RAYWHITE);
EndMode2D();
if (CheckCollisionRecs(playerArea, rect1))
DrawText("Collided", 5, 5, 25, BLACK);
EndDrawing();
}

How do I make my object disappear when it hits my character in my game? [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 7 years ago.
Improve this question
I'm trying to make a game where my character (Homer Simpson) has to collect falling objects (donuts) and avoid falling toxic-tanks. Right now my score increments every time he gets a donut, but I wish to make the donut disappear afterwards. Can anyone help me with that?
This is my code so far:
PImage bg2; //background image
PImage homer; //image of homer
homer homer1;
int numberOfToxic = 3; //number of falling toxic tanks
int numberOfDonut = 3; //number of falling donuts
int score; //the score
Toxic[] toxic; //array for the toxic that will fall
PImage t;
Donut[] donut; //array for the donuts that will fall
PImage d;
void setup() {
size(600,500); //size of the window
bg2 = loadImage("bg2.jpg"); //uploading the background image
homer = loadImage("homer.gif"); //uploading the character image
t = loadImage("toxictank.png");
d = loadImage("donut.png");
PFont louiseFont;
louiseFont = loadFont("chalk.vlw"); //loading the font I've chosen
textFont(louiseFont); //the current font being used in the game
toxic = new Toxic[numberOfToxic];
for (int i = 0; i < numberOfToxic; i++) {
toxic[i] = new Toxic();
}
donut = new Donut[numberOfDonut];
for(int i = 0; i < numberOfDonut; i++) {
donut[i] = new Donut();
}
score = 0; //the score starts at 0
}
void draw() {
background(bg2);
homer1 = new homer(mouseX-70, 350, 140, 150, homer); //mouseX makes the hero move on the x axis and 350 defines where it is on the y axis. -70 center the mouse on the image/hero
homer1.drawHomer(); //call the function homer(hero)
//Making the taxictanks fall
for(int i = 0; i < toxic.length; i++) {
toxic[i].update();
toxic[i].drawToxic();
if(toxic[i].position.y > 500) {
toxic[i].reset();
}
}
//Making the donuts fall
for(int i = 0; i < donut.length; i++) {
donut[i].update2();
donut[i].drawDonut();
if(donut[i].position2.y > 500) {
donut[i].reset2();
}
//Collecting points if Homer eats donuts
if(abs(donut[i].position2.y - homer1.y) <= 2 && abs(donut[i].position2.x-40 - homer1.x)<=40) {
score ++;
println("ok");
}
}
fill(#0D128B); //color of text
textSize(20); //size of text
text("SCORE: " + nf(score, 1), 20, 40); //score points - tells how to use the text in the game
}
//class with height, width x, y positions and the hero image
class homer {
int x;
int y;
int hWidth;
int hHeight;
PImage homer;
homer(int x, int y, int hWidth, int hHeight, PImage homer) {
this.x = x;
this.y = y;
this.hWidth = hWidth;
this.hHeight = hHeight;
this.homer = homer;
}
void drawHomer() {
image(this.homer, this.x, this.y, this.hWidth, this.hHeight);
}
}
class Toxic { //all the variables for toxic
PImage t;
PVector position;
float speed;
float size;
//constructor of toxic
Toxic() {
t = loadImage("toxictank.png");
position = new PVector(random(width), random(height));
speed = 4;
size = 20;
}
void update() {
position.y += speed;
}
void drawToxic() {
for(int i = 1; i < 3; i++) {
image(t, position.x, position.y);
}
}
void reset() {
position.x = random(width);
position.y = 0 - 50;
speed = 4;
size = 20;
}
}
class Donut { //all variables for donut
PImage d;
PVector position2;
float speed2;
float size2;
boolean falling;
int timeToDisplay;
int fallingSpeed;
Donut() { //constructor of donut
d = loadImage("donut.png");
position2 = new PVector(random(width), random(height));
speed2 = 4;
size2 = 40;
falling = false;
timeToDisplay = (int)random(2.60);
fallingSpeed = (int)random(2.5);
}
void update2() {
position2.y += speed2;
}
void drawDonut() {
for(int i = 1; i < 3; i++) {
image(d, position2.x, position2.y);
}
}
void reset2() {
position2.x = random(width);
position2.y = 0 - 50;
speed2 = 4;
size2 = 20;
}
}
Just set the variables in the instance of Donut so that it goes back to the top of the screen, or isn't drawn at all. You already have a reset2() function that does that. Something like this:
if(abs(donut[i].position2.y - homer1.y) <= 2 && abs(donut[i].position2.x-40 - homer1.x)<=40) {
score ++;
donut[i].reset2();
println("ok");
}

Processing - Flock Boids avoid draggable objects

I'm working on a boids flocking project.
My goal is to have several draggable objects which have to be avoided by the boids.
There are several different flocks with a different starting position.
I managed to get the boids to avoid one draggable object. But I can't seem to make them avoid all. (using a for loop)
I really can't figure out why this won't do the trick..
I hope you could give me some suggestions.
the code:
int initBoidNum = 100; //amount of boids to start the program with
BoidList flock1, flock2, flock3;
Draggable draggable;
NullDraggableObject nullDraggableObject;
ArrayList draggables;
int id;
float[] xposs= new float[10];
float[] yposs= new float[10];
String turn;
void setup() {
size(1000, 700);
//create and fill the list of boids
flock1 = new BoidList(150, 0, 10, 100);
flock2 = new BoidList(150, 255, 10, 200);
flock3 = new BoidList(150, 150, 10, 300);
turn = "turn";
nullDraggableObject = new NullDraggableObject();
draggables = new ArrayList();
for (int i = 0; i < 10; i++) {
draggables.add(new DraggableObject(random(width), random(height/2)));
}
}
void draw() {
background(100, 60);
flock1.run();
flock2.run();
flock3.run();
stroke(255);
noFill();
draggable = nullDraggableObject;
for (id = 0; id < draggables.size (); id++) {
Draggable d = (Draggable)draggables.get(id);
d.draw();
if (d.isBeingMouseHovered()) {
draggable = d;
}
}
}
void mousePressed() {
draggable.mousePressed();
}
void mouseDragged() {
draggable.mouseDragged();
}
void mouseReleased() {
draggable.mouseReleased();
}
interface Draggable {
boolean isBeingMouseHovered();
boolean inside(float ix, float iy);
void draw();
void mousePressed();
void mouseDragged();
void mouseReleased();
}
class NullDraggableObject implements Draggable {
boolean isBeingMouseHovered() {
return false;
}
boolean inside(float ix, float iy) {
return false;
}
void draw() {
}
void mousePressed() {
}
void mouseDragged() {
}
void mouseReleased() {
}
}
public class DraggableObject implements Draggable {
float XX, YY;
float radius;
boolean drag;
float dragX, dragY;
DraggableObject(float _x, float _y) {
XX = _x;
YY = _y;
radius = 50;
drag = false;
dragX = 0;
dragY = 0;
}
boolean isBeingMouseHovered() {
return inside(mouseX, mouseY);
}
boolean inside(float ix, float iy) {
return (dist(XX, YY, ix, iy) < radius);
}
void draw() {
ellipseMode(CENTER);
ellipse(XX, YY, 2*radius, 2*radius);
String space = "__";
println(id);
println(XX);
println(YY);
xposs[id] = XX;
yposs[id] = YY;
}
void mousePressed() {
drag = inside(mouseX, mouseY);
if (drag) {
dragX = mouseX - XX;
dragY = mouseY - YY;
}
}
void mouseDragged() {
if (drag) {
XX = mouseX - dragX;
YY = mouseY - dragY;
}
}
void mouseReleased() {
drag = false;
}
}
class Boid {
//fields
PVector pos, vel, acc, ali, coh, sep; //pos, velocity, and acceleration in a vector datatype
float neighborhoodRadius; //radius in which it looks for fellow boids
float maxSpeed = 1; //maximum magnitude for the velocity vector
float maxSteerForce = .05; //maximum magnitude of the steering vector
float sMod, aMod, cMod; //modifiers for the three forces on the boid
float h; //hue
Boid(PVector inPos) {
pos = new PVector();
pos.set(inPos);
vel = new PVector(random(-1, 1), random(-1, 1));
acc = new PVector(0, 0);
neighborhoodRadius = 20;
sMod = 1;
aMod = 1;
cMod = 4;
}
Boid(PVector inPos, PVector inVel, float r) {
pos = new PVector();
pos.set(inPos);
vel = new PVector();
vel.set(inVel);
acc = new PVector(0, 0);
neighborhoodRadius = r;
}
void run(ArrayList bl) {
for (int i =0; i < 10; i++) {
acc.add(attract(new PVector(width/2, height/2), true));
acc.add(avoid(new PVector(xposs[i], yposs[i]), true));
if (i == 10) i = 0;
}
if (pos.x>width-10)acc.add(bounce(new PVector(width, pos.y), true));
if (pos.x<10) acc.add(bounce(new PVector(0, pos.y), true));
if (pos.y>height-10) acc.add(bounce(new PVector(pos.x, height), true));
if (pos.y<10) acc.add(bounce(new PVector(pos.x, 0), true));
ali = alignment(bl);
coh = cohesion(bl);
sep = seperation(bl);
for (int i =0; i < 10; i++) {
if (PVector.dist(new PVector(xposs[i], yposs[i]), pos)>180) {
acc.add(PVector.mult(ali, aMod));
acc.add(PVector.mult(coh, cMod));
acc.add(PVector.mult(sep, sMod));
}
if (PVector.dist(new PVector(xposs[i], yposs[i]), pos)<80) maxSpeed = 1000;
if (i == 10) i = 0;
}
if (PVector.dist(new PVector(width, height), pos)<60) maxSpeed = 1000;
if (PVector.dist(new PVector(0, 0), pos)<50) {
maxSpeed = 1000;
} else {
maxSpeed = 1;
}
move();
checkBounds();
render();
}
void move() {
vel.add(acc); //add acceleration to velocity
vel.limit(maxSpeed); //make sure the velocity vector magnitude does not exceed maxSpeed
pos.add(vel); //add velocity to position
acc.mult(0); //reset acceleration
}
void checkBounds() {
}
void render() {
pushMatrix();
translate(pos.x, pos.y);
rotate(atan2(vel.y, vel.x)); //rotate drawing matrix to direction of velocity
stroke(0);
noFill();
ellipse(0, 0, neighborhoodRadius/2, neighborhoodRadius/2);
noStroke();
fill(h);
//draw triangle
beginShape(TRIANGLES);
rect(0, 0, 6, 2);
endShape();
popMatrix();
}
//steering. If arrival==true, the boid slows to meet the target. Credit to Craig Reynolds
PVector steer(PVector target, boolean arrival) {
PVector steer = new PVector(); //creates vector for steering
if (!arrival) {
steer.set(PVector.sub(target, pos)); //steering vector points towards target (switch target and pos for avoiding)
steer.limit(maxSteerForce); //limits the steering force to maxSteerForce
} else {
PVector targetOffset = PVector.sub(target, pos);
float distance=targetOffset.mag();
float rampedSpeed = maxSpeed*(distance/100);
float clippedSpeed = min(rampedSpeed, maxSpeed);
PVector desiredVelocity = PVector.mult(targetOffset, (clippedSpeed/distance));
steer.set(PVector.sub(desiredVelocity, vel));
}
return steer;
}
//avoid. If weight == true avoidance vector is larger the closer the boid is to the target
PVector avoid(PVector target, boolean weight) {
PVector steer = new PVector(); //creates vector for steering
steer.set(PVector.sub(pos, target)); //steering vector points away from target
if (weight) steer.mult(1/sq(PVector.dist(pos, target)));
//steer.limit(maxSteerForce); //limits the steering force to maxSteerForce
return steer;
}
PVector attract(PVector target, boolean weight) {
PVector steer = new PVector(); //creates vector for steering
steer.set(PVector.sub(target, pos)); //steering vector points away from target
if (weight) steer.mult(1/sq(PVector.dist(target, pos)));
//steer.limit(maxSteerForce); //limits the steering force to maxSteerForce
return steer;
}
PVector bounce(PVector target, boolean weight) {
PVector steer = new PVector(); //creates vector for steering
steer.set(PVector.sub(pos, target)); //steering vector points away from target
if (weight) steer.mult(1/sq(PVector.dist(pos, target)));
//steer.limit(maxSteerForce); //limits the steering force to maxSteerForce
return steer;
}
PVector seperation(ArrayList boids) {
PVector posSum = new PVector(0, 0);
PVector repulse;
for (int i=0; i<boids.size (); i++) {
Boid b = (Boid)boids.get(i);
float d = PVector.dist(pos, b.pos);
if (d>0&&d<=neighborhoodRadius) {
repulse = PVector.sub(pos, b.pos);
repulse.normalize();
repulse.div(d);
posSum.add(repulse);
}
}
return posSum;
}
PVector alignment(ArrayList boids) {
PVector velSum = new PVector(0, 0);
int count = 0;
for (int i=0; i<boids.size (); i++) {
Boid b = (Boid)boids.get(i);
float d = PVector.dist(pos, b.pos);
if (d>0&&d<=neighborhoodRadius) {
velSum.add(b.vel);
count++;
}
}
if (count>0) {
velSum.div((float)count);
velSum.limit(maxSteerForce);
}
return velSum;
}
PVector cohesion(ArrayList boids) {
PVector posSum = new PVector(0, 0);
PVector steer = new PVector(0, 0);
int count = 0;
for (int i=0; i<boids.size (); i++) {
Boid b = (Boid)boids.get(i);
float d = dist(pos.x, pos.y, b.pos.x, b.pos.y);
if (d>0&&d<=neighborhoodRadius) {
posSum.add(b.pos);
count++;
}
}
if (count>0) posSum.div((float)count);
steer = PVector.sub(posSum, pos);
steer.limit(maxSteerForce);
return steer;
}
}
class BoidList {
ArrayList boids; //will hold the boids in this BoidList
float h; //for color
BoidList(int n, float ih, int xstart, int ystart) {
boids = new ArrayList();
h = ih;
for (int i=0; i<n; i++) {
boids.add(new Boid(new PVector(xstart, ystart)));
}
}
void run() {
for (int i=0; i<boids.size (); i++) {
Boid tempBoid = (Boid)boids.get(i); //create a temporary boid to process and make it the current boid in the list
tempBoid.h = h;
tempBoid.run(boids); //tell the temporary boid to execute its run method
}
}
}

Resources