I am trying to simulate a herd of rabbits in a grass field using processing. As I am a beginner, I decided to skip acceleration while moving, that is the rabbits have a constant magnitude of velocity. Each rabbit has a separation radius in order to keep them separated. For food, I decided to greedily search all the grass objects near me and move towards the closest, however whenever I try to run the program, all the grass objects teleport towards the origin and I can't find the reason for it.
This is the main file.
ArrayList<Rabbit> R = new ArrayList<Rabbit>();
ArrayList<Grass> G = new ArrayList<Grass>();
ArrayList<Grass> K = G;
int grass = 25;
int r_Size = 10;
int day = 0;
int i = 0;
void setup(){
size(1000,8000);
for(int i = 0;i<r_Size;i++){
R.add(new Rabbit());
}
for(int i = 0;i<grass;i++){
G.add(new Grass());
}
}
void draw(){
background(120);
i++;
for(Grass r : G){
r.show();
r.find();
}
for(Rabbit r : R){
r.show();
r.move();
}
fill(255);
text(day,10,100);
if(i >= 10){
day++;
i = 0;
ArrayList<Grass> d = new ArrayList<Grass>();
for(Grass g : G){
if(g.isEaten){
d.add(g);
}
}
for(Grass g : d){
G.remove(g);
}
}
if(day >= 30){
System.out.println(R.size());
for(Grass r : G){
r.update();
}
for(int i = 0;i<10;i++){
G.add(new Grass());
}
ArrayList<Rabbit> dead = new ArrayList<Rabbit>();
for (Rabbit r : R){
r.update();
if(r.isDead == true)
dead.add(r);
}
for(Rabbit r : dead){
R.remove(r);
}
day = 0;
}
}
This is the Grass Class.
class Grass{
PVector pos;
int age = 0;
int side = 20;
boolean isEaten = false;
int perTurn = 10;
Grass(){
pos = new PVector(random(0,width-side),random(0,height-side));
}
void update(){
age++;
}
boolean find(){
if(isEaten)
return true;
for(Rabbit r : R){
if(pos.dist(r.pos) < side){
isEaten = true;
r.hasBeenHungry = 0;
return true;
}
}
return false;
}
void show(){
float c = map(age,0,10,100,255);
fill(0,0+c,0);
noStroke();
square(pos.x,pos.y,side);
}
}
Second is the animal class which I wanted to extend to rabbits and foxes (I will add them later).
class Animal{
PVector pos;
PVector vel;
boolean isDead;
int age;
int gender;
int max_age;
float max_speed;
int hasBeenHungry = 0;
//gender 0 means female and 1 means male;
// update means age in months;
void update(){
this.age++;
hasBeenHungry++;
if(this.age >= max_age){
isDead = true;
}
float k = (int)random(10);
if(k == 0){
isDead = true;
}
if(hasBeenHungry >= 5){
isDead = true;
}
}
void move(){
pos.add(this.vel);
checkBound();
//this.vel.mult(0);
}
void checkBound(){
if(pos.x < 0 || pos.x > width){
vel.x *= -1;
}
if(pos.y < 0|| pos.y > height){
vel.y *= -1;
}
}
}
Finally, the Rabbit class (I think the issue is with the target function).
class Rabbit extends Animal{
Rabbit(){
pos = new PVector(random(0,width),random(0,height));
vel = new PVector(2,1);
int k = (int)(random(0,2));
this.isDead = false;
this.gender = k;
this.max_age = 10;
this.max_speed = 3;
}
void show(){
if(this.gender == 0){
fill(120,0,0 );
}
else{
fill(0,0,120);
}
circle(this.pos.x,this.pos.y,15);
}
void seperate(){
float desiredRadius = 30;
int count = 0;
PVector c = new PVector(0,0);
for(Rabbit r : R){
if(r != this){
float a = pos.dist(r.pos);
if(a > 0 && a < desiredRadius){
PVector diff = PVector.sub(pos, r.pos);
//diff.normalize();
diff.div(a); // Weight by distance
c.add(diff);
count++;
}
}
}
if (count > 0){
c.div((float)count);
vel.add(c);
vel.normalize();
vel.mult(max_speed);
}
}
PVector target(){
//Each rabbit eats grass so we could make a greedy approach where the rabbit focuses on the grass closest to it
PVector mi = new PVector(0,0);
//int distance = 1000;
for(Grass g : G){
float a = this.pos.dist(g.pos);
if(a < pos.dist(mi)){
mi = g.pos;
}
}
return mi;
}
void move(){
super.move();
vel = target();
seperate();
vel.normalize();
vel.mult(max_speed);
}
}
P.S I am a beginner so some implementations may not be up to the mark, if you find any such issue please tell me so that I can improve.