A run away behavior


#1

hi everyone, i trie to make an run away behavior for my creature in my ecosystem.

the situation is, if a predator (my mouse for now) come too close of a creature, the creature move away.

i was wondering if i can use my boundaries method for that.

public void boundaries(){
                int d = 150;
		PVector desired = null;
		
		if(position.x < d){
			desired = new PVector(maxspeed,velocity.y);
		}
		else if(position.x > 2000 - d){
			desired = new PVector(-maxspeed, velocity.y);
		}
		
		if(position.y < d){
			desired = new PVector(velocity.x, maxspeed);
		}
		else if(position.y > 2000 -d){
			desired = new PVector(velocity.x, -maxspeed);
		}
		
		if(desired != null){
			desired.normalize();
			desired.mult(maxspeed);
			PVector steer = PVector.sub(desired, velocity);
			steer.limit(maxforce);
			applyForce(steer);
		}
	}

(2000 is the dimension of my world and the “d” represent the limit)

but i dont know how to modify it.

so what i imagine, you have a creature with a circle around it (150 pixel) and when a predator (my mouse for now) enter the circle, the creature move in the opposit way (like when my creature come too close of my boundaries)

Thanks for yours time guys.


#2

It looks like you are trying to initiate a new PVector in draw(). Which is a very bad idea. Very bad. What you want to do is initiate it in setup(), and use it in draw.

Also, I think you want to use dist(). Check it out in the reference: processing.org/reference


#3

yeah i know, my code is way bigger than this exemple, i used it as an exemple.


#4

maybe my exemple is a bit confusing, i dont know if my explanation is correct.


#5

It doesn’t matter if it is just an example, but it have to be correct. Otherwise it won’t work. Usually I make minimal working sketch to explain my problem. Include only as much as is needed to show your problem/your thought, but as much as is needed to make it run. Because if it won’t run it can be difficult to understand what you are trying to accomplish.

Did you look at the function I reccomended?


#6

ok i based my exemple on the work of Daniel Shiffman here is his exemple:


I like it because its flexible.

exemple

so, on the left is what the boundarie do, on the right its what i want.

my questions are; can i use (with modification) his code ? and how to modify it ?


#7

Okey, now everything makes a lot more sense. So what you have is that the ball stays within the screen. And what you want next is to make it move away from the mouse. Ha e I underdtood?

I still think you should use dist. You can just expand the function you are currently using. First thing you do is to measure the distance between the mouseposition and the position of the ball. Then you check if the distance is less than the predermined distance. See if you can manage to do that.

https://processing.org/reference/dist_.html


#8

yes thats what i imagine.

i get the dist but i dont how to make it move properly.

public void runaway(){
		PVector desired = null;
		PVector mouse = new PVector(parent.mouseX, parent.mouseY);
		int distance = 150;
		float dist = PVector.dist(mouse, position);
		
		if(dist < distance){
			if(position.x < distance){
				desired = new PVector(maxspeed, velocity.y);
			}
			else if(position.x > distance){
				desired = new PVector(-maxspeed, velocity.y);
			}
			if(position.y < distance){
				desired = new PVector(velocity.x, maxspeed);
			}
			else if(position.y > distance){
				desired = new PVector(velocity.x, -maxspeed);
			}
			
			if(desired != null){
				desired.normalize();
				desired.mult(maxspeed);
				PVector steer = PVector.sub(desired, velocity);
				steer.limit(maxforce);
				applyForce(steer);
			}
		}
	}

it doesnt work


#9

If the distance form the mouse is too close to your creature then you want it to move in the opposite direction.

To do that, simply create a Vector like this:

PVector desiredDirection = new PVector(position.x - mouseX, position.y - mouseY);

Then normalize it and multiply by your speed:

desiredDirection.normalize().mult(speed);

And now you can simply add that vector to your position to move it.


#10

Great! You know how dist() work! That’s very good. Now that you have calculated the distance and checked if it below the magic number, you shouldn’t check the other things yet. Now you want to go the opposite way of the mouse. So if mouseX>position.x you want to go left. Which means you can say that the new vector is (position.x - mouseX)


#11

so something like this ?

public void runaway(){
		PVector desired = null;
		PVector mouse = new PVector(parent.mouseX, parent.mouseY);
		int distance = 150;
		float dist = PVector.dist(mouse, position);
		
		if(dist < distance){
			
			
			desired = new PVector(position.x - parent.mouseX, position.y - parent.mouseY);
			
			if(desired != null){
				desired.normalize();
				desired.mult(maxspeed);
				PVector steer = PVector.sub(desired, velocity);
				steer.limit(maxforce);
				applyForce(steer);
			}
		}
	}

#12

Sure! If you do it like this, you could add the other stuff about the edges like you did before. Perhaps after the if clause that handles the distance.

p

ublic void runaway(){
		PVector desired = null;
		PVector mouse = new PVector(parent.mouseX, parent.mouseY);
		int distance = 150;
		float dist = PVector.dist(mouse, position);
		
		if(dist < distance){
			desired = new PVector(position.x - parent.mouseX, position.y - parent.mouseY);
			}

		if(desired != null){
			desired.normalize();
			desired.mult(maxspeed);
			PVector steer = PVector.sub(desired, velocity);
			steer.limit(maxforce);
			applyForce(steer);
		}
	}

#13

Now put it all together and try to run it. Does it work? If not, post your whole code here and we will solve it together :slight_smile:


#14

ok wow im really sorry guys, first with the exemple i give you and with yours solution its work.

but i dont give you the right exemple i forgot i have changed my wandering behavior.

this is my wandering now(i give you the all code) :

Vehicle wanderer;
boolean debug = true;

void setup() {
  size(640,360);
  wanderer = new Vehicle(width/2,height/2);
}

void draw() {
  background(255);
  wanderer.wander();
  wanderer.run();
}

void mousePressed() {
  debug = !debug;
}
class Vehicle {

  PVector position;
  PVector velocity;
  PVector acceleration;
  float r;
  float wandertheta;
  float maxforce;    // Maximum steering force
  float maxspeed;    // Maximum speed

  Vehicle(float x, float y) {
    acceleration = new PVector(0,0);
    velocity = new PVector(0,0);
    position = new PVector(x,y);
    r = 6;
    wandertheta = 0;
    maxspeed = 2;
    maxforce = 0.05;
  }

  void run() {
    update();
    borders();
    display();
  }

  // Method to update position
  void update() {
    // Update velocity
    velocity.add(acceleration);
    // Limit speed
    velocity.limit(maxspeed);
    position.add(velocity);
    // Reset accelertion to 0 each cycle
    acceleration.mult(0);
  }

  void wander() {
    float wanderR = 25;         // Radius for our "wander circle"
    float wanderD = 80;         // Distance for our "wander circle"
    float change = 0.3;
    wandertheta += random(-change,change);     // Randomly change wander theta

    // Now we have to calculate the new position to steer towards on the wander circle
    PVector circlepos = velocity.get();    // Start with velocity
    circlepos.normalize();            // Normalize to get heading
    circlepos.mult(wanderD);          // Multiply by distance
    circlepos.add(position);               // Make it relative to boid's position

    float h = velocity.heading2D();        // We need to know the heading to offset wandertheta

    PVector circleOffSet = new PVector(wanderR*cos(wandertheta+h),wanderR*sin(wandertheta+h));
    PVector target = PVector.add(circlepos,circleOffSet);
    seek(target);

    // Render wandering circle, etc.
    if (debug) drawWanderStuff(position,circlepos,target,wanderR);
  }

  void applyForce(PVector force) {
    // We could add mass here if we want A = F / M
    acceleration.add(force);
  }
  
  void runaway(){
    PVector desired = null;
    PVector mouse = new PVector(mouseX, mouseY);
    int distance = 150;
    float dist = PVector.dist(mouse, position);
    
    if(dist < distance){
      desired = new PVector(position.x - mouseX, position.y - mouseY);
      
    }

    if(desired != null){
      desired.normalize();
      desired.mult(maxspeed);
      PVector steer = PVector.sub(desired, velocity);
      steer.limit(maxforce);
      applyForce(steer);
    }
  }
  
  

  // A method that calculates and applies a steering force towards a target
  // STEER = DESIRED MINUS VELOCITY
  void seek(PVector target) {
    PVector desired = PVector.sub(target,position);  // A vector pointing from the position to the target

    // Normalize desired and scale to maximum speed
    desired.normalize();
    desired.mult(maxspeed);
    // Steering = Desired minus Velocity
    PVector steer = PVector.sub(desired,velocity);
    steer.limit(maxforce);  // Limit to maximum steering force

    applyForce(steer);
  }

  void display() {
    // Draw a triangle rotated in the direction of velocity
    float theta = velocity.heading2D() + radians(90);
    fill(127);
    stroke(0);
    pushMatrix();
    translate(position.x,position.y);
    rotate(theta);
    beginShape(TRIANGLES);
    vertex(0, -r*2);
    vertex(-r, r*2);
    vertex(r, r*2);
    endShape();
    popMatrix();
  }

  // Wraparound
  void borders() {
    if (position.x < -r) position.x = width+r;
    if (position.y < -r) position.y = height+r;
    if (position.x > width+r) position.x = -r;
    if (position.y > height+r) position.y = -r;
  }
}


// A method just to draw the circle associated with wandering
void drawWanderStuff(PVector position, PVector circle, PVector target, float rad) {
  stroke(0);
  noFill();
  ellipseMode(CENTER);
  ellipse(circle.x,circle.y,rad*2,rad*2);
  ellipse(target.x,target.y,4,4);
  line(position.x,position.y,circle.x,circle.y);
  line(circle.x,circle.y,target.x,target.y);
}

of course my runaway behavior dont work with that.

im really sorry i feel like i have wasted your time.

i gonna search alone, if i cant find a solution i will come for help.

thanks for your help guys :).


#15

What you can do is have 2 behaviors and chose the one you want depending on the mouse position.

Consider having your draw like so:

void draw() {
  background(255);
  if (wanderer.isInDanger()) {
    wanderer.escape();
  } else {
    wanderer.wander();
  }
  wanderer.run();
}

I included 2 new methods. the isInDanger() one check if the mouse is close enough to your vehicle:

boolean isInDanger() {
  return dist(position.x, position.y, mouseX, mouseY) < 150;
}

The second one escape() apply a force in the opposite direction of your vehicle:

void escape() {
  PVector desired = new PVector(position.x - mouseX, position.y - mouseY);

  desired.normalize();
  desired.mult(maxspeed);
  PVector steer = PVector.sub(desired, velocity);
  steer.limit(maxforce);
  applyForce(steer);
}

#16

well i used your idea, its work great on processing but when i use it in eclipse with java it do nothing(no bug)

		Iterator<Herbivor4F> H4F = herb4f.iterator();
		while(H4F.hasNext()){
			Herbivor4F h4f = H4F.next();
			h4f.run(parent);
			h4f.boundaries();
			h4f.display(parent);
			if(h4f.dead()){
				H4F.remove();
			}
			
			
			if(h4f.isInDanger()){
				h4f.runaway();
			}
			else {
				h4f.wander(parent);
			}
			
		}
	public boolean isInDanger(){
		
		return PApplet.dist(position.x, position.y, parent.mouseX, parent.mouseY) < 150;
		
	}
	
	public void runaway(){
		PVector desired = new PVector(position.x - parent.mouseX, position.y - parent.mouseY);
		
		desired.normalize();
		desired.mult(maxspeed);
		PVector steer = PVector.sub(desired, velocity);
		steer.limit(maxforce);
		applyForce(steer);
	}

i cant figured why


#17

It is because you are using the run method before the runaway one so it just ignores it.


#18

i tried that way but it dont work

		Iterator<Herbivor4F> H4F = herb4f.iterator();
		while(H4F.hasNext()){
			Herbivor4F h4f = H4F.next();
			
			h4f.boundaries();
			h4f.display(parent);
			if(h4f.dead()){
				H4F.remove();
			}
			
			
			if(h4f.isInDanger()){
				h4f.runaway(r);
				
			}
			else {
				h4f.wander(parent);
				
			}
			h4f.run(parent);
		}

#19

i think i find whats wrong, i come back when i find the solution


#20

ok i found what’s wrong, what you gave me work perfectly.
The problem come from the coordonates of my mouse, my previous “world” was contained in the screen of my program so the coordonates was fine.

But now in my new world, wich is bigger than the screen the coordonates of my mouse are not the same than my world (they are based on my screen) so of course its not working.

i tried with others creatures in my world and its work.

Thanks you guys for the help and advices and sorry if i was like “just give me the answer”.