We are about to switch to a new forum software. Until then we have removed the registration on this forum.
So I'm working on porting some of Dan Shiffman's code from p5.js to Processing. I'm using IntelliJ instead of the Processing IDE because of intellisense etc.
The error is occurring in the display() function. In short, I'm aware of what a NullPointerException is, but am unable to figure out a circumstance in which the object used in display() is uninstantiated, and don't know what to change to fix it. I'm likely overlooking something, and would like some help.
The code is in two files, a main class and a vehicle class.
This is the vehicle class
import processing.core.PApplet;
import processing.core.PVector;
import java.util.ArrayList;
import static java.lang.Float.POSITIVE_INFINITY;
public class Vehicle extends PApplet {
private PVector acceleration;
private PVector velocity;
PVector position;
private int r;
private float maxspeed;
private float maxforce;
private float health;
private float[] dna;
Vehicle(float _x, float _y, float[] _dna) {
float mutationRate = 0.01f;
acceleration = new PVector(0,0);
velocity = new PVector(0,-2);
position = new PVector(_x, _y);
r = 4;
maxspeed = 5f;
maxforce = 0.5f;
health = 1f;
dna = _dna;
if (dna == null) {
dna = new float[4];
for (int i = 0; i < 2; i++) {
dna[i] = random(-2,2);
}
for (int i = 2; i < 4; i++) {
dna[i] = random(0,100);
}
} else {
for (int i = 0; i < 2; i++) {
dna[i] = _dna[i];
if (random(1) < mutationRate) {
dna[i] += random(-0.1f, 1.0f);
}
}
for (int i = 2; i < 4; i++) {
dna[i] = _dna[i];
if (random(1) < mutationRate) {
dna[i] += random(-10, 10);
}
}
}
}
void update() {
health -= 0.005f;
velocity.add(acceleration);
velocity.limit(maxspeed);
position.add(velocity);
acceleration.mult(0);
}
private void applyForce(PVector _force) {
acceleration.add(_force);
}
void behaviors(ArrayList<PVector> _good, ArrayList<PVector> _bad) {
PVector steerG = eat(_good, 0.2f, dna[2]);
PVector steerB = eat(_bad, -1, dna[3]);
steerG.mult(dna[0]);
steerB.mult(dna[1]);
applyForce(steerG);
applyForce(steerB);
}
Vehicle reproduce() {
if (random(1) < 0.002f) {
return new Vehicle(position.x, position.y, dna);
} else {
return null;
}
}
private PVector eat(ArrayList<PVector> _list, float _nutrition, float _perception) {
float record = POSITIVE_INFINITY;
PVector closest = new PVector();
for (int i = _list.size() - 1; i >= 0; i--) {
float d = position.dist(_list.get(i));
if (d < maxspeed) {
_list.remove(i);
health += _nutrition;
} else if (d < record && d < _perception) {
record = d;
closest = _list.get(i);
}
}
if (closest != null) {
return seek(closest);
}
return new PVector(0,0);
}
private PVector seek (PVector _target) {
PVector desired = PVector.sub(_target, position);
desired.setMag(maxspeed);
//steering = desired - velocity
PVector steer = PVector.sub(desired, velocity);
steer.limit(maxforce);
return steer;
}
boolean dead () {
return (health < 0);
}
void display() {
float angle = velocity.heading() + PI / 2;
translate(this.position.x, this.position.y);
rotate(angle);
int gr = color(0,255,0);
int rd = color(255,0,0);
int col = lerpColor(rd,gr,health);
fill(col);
stroke(col);
strokeWeight(1);
beginShape();
vertex(0, -this.r * 2);
vertex(-this.r, this.r * 2);
vertex(this.r, this.r * 2);
endShape(CLOSE);
}
void boundaries() {
int d = 25;
PVector desired = new PVector();
if (position.x < d) {
desired = new PVector(maxspeed, velocity.y);
} else if (position.x > width - d) {
desired = new PVector(-maxspeed, velocity.y);
}
if (position.y < d) {
desired = new PVector(velocity.x, maxspeed);
} else if (position.y > health - d) {
desired = new PVector(velocity.x, -maxspeed );
}
PVector newPVector = new PVector();
if (desired != newPVector) {
desired.normalize();
desired.mult(maxspeed);
PVector steer = PVector.sub(desired, velocity);
steer.limit(maxforce);
applyForce(steer);
}
}
}
This is the main class
import processing.core.PApplet;
import processing.core.PVector;
import java.util.ArrayList;
public class MainApp extends PApplet{
private ArrayList<Vehicle> vehicles;
private ArrayList<PVector> food;
private ArrayList<PVector> poison;
public static void main(String[] args) {
PApplet.main("MainApp", args);
}
public void settings() {
size(800,800);
}
public void setup() {
vehicles = new ArrayList<>(40);
for (int i = 0; i < 40; i++) {
Vehicle tmp = new Vehicle(random(0,width),random(0,height),null);
vehicles.add(i, tmp);
}
food = new ArrayList<>(40);
for (int i = 0; i < 40; i++) {
PVector tmp = new PVector(random(width), random(height));
food.add(i, tmp);
}
poison = new ArrayList<>(20);
for (int i = 0; i < 20; i++) {
PVector tmp = new PVector(random(width), random(height));
poison.add(i, tmp);
}
}
public void draw() {
background(51);
if (random(1) < 0.1) {
PVector tmp = new PVector(random(width), random(height));
food.add(tmp);
}
if (random(1) < 0.1) {
PVector tmp = new PVector(random(width), random(height));
poison.add(tmp);
}
for (PVector item : poison) {
fill(255,0,0);
noStroke();
ellipse(item.x, item.y, 4, 4);
}
for (PVector item : food) {
fill(0,255,0);
noStroke();
ellipse(item.x, item.y, 4, 4);
}
for (int i = vehicles.size() - 1; i >= 0; i--) {
vehicles.get(i).boundaries();
vehicles.get(i).behaviors(food, poison);
vehicles.get(i).update();
vehicles.get(i).display();
Vehicle newVehicle = vehicles.get(i).reproduce();
if (newVehicle != null) {
vehicles.add(newVehicle);
}
if (vehicles.get(i).dead()) {
PVector tmp = new PVector(vehicles.get(i).position.x, vehicles.get(i).position.y);
food.add(tmp);
vehicles.remove(i);
}
}
}
}
The code returns this issue
java.lang.NullPointerException
at processing.core.PApplet.translate(PApplet.java:13017)
at Vehicle.display(Vehicle.java:127)
at MainApp.draw(MainApp.java:69)
at processing.core.PApplet.handleDraw(PApplet.java:2438)
at processing.awt.PSurfaceAWT$12.callDraw(PSurfaceAWT.java:1547)
at processing.core.PSurfaceNone$AnimationThread.run(PSurfaceNone.java:316)
Process finished with exit code 1
Answers
The Vehicle class must NOT extend PApplet. You are doing this to gain access to the PApplet methods, instead you should modify the Vehicle class to have an attribute of type PApplet like this
The display method would be modified to
To create a vehicle object from the main file
Vehicle tmp = new Vehicle(this, random(0, width), random(0, height), null);
At the moment there is no point in looking for the NPE because it is caused by the Vehicle class incorrectly inheriting from PApplet.
I am going to take a shot at this....
Your Vehicle class extends PApplet but how is it connected to your current running PApplet aka. MainApp? What you are missing is something like this:
Then when you call translate, for example line 119:
ap.translate(this.position.x, this.position.y);
Code not tested.... I hope this helps,
Kf
Many thanks to both of you, this was the issue, and it is now fixed.