NullPointerException - can't find uninstantiated object [FIXED]

edited April 2017 in Questions about Code

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
Tagged:

Answers

  • Answer ✓

    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

    public class Vehicle extends PApplet { 
        private PApplet app;
        private PVector acceleration;
        private PVector velocity;
        PVector position;
        private int r;
        private float maxspeed;
        private float maxforce;
        private float health;
        private float[] dna;
    
        Vehicle(PApplet _app, float _x, float _y, float[] _dna) {
            app = _app;
            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;
        // rest of the constructor code follows here
    

    The display method would be modified to

    void display() {
    
        float angle = velocity.heading() + PI / 2;
    
        app.translate(this.position.x, this.position.y);
        app.rotate(angle);
    
        int gr = color(0,255,0);
        int rd = color(255,0,0);
        int col = lerpColor(rd,gr,health);
        app.fill(col);
        app.stroke(col);
        app.strokeWeight(1);
        app.beginShape();
        app.vertex(0, -this.r * 2);
        app.vertex(-this.r, this.r * 2);
        app.vertex(this.r, this.r * 2);
        app.endShape(CLOSE);
    }
    

    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.

  • Answer ✓

    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:

    public class Vehicle  {  // CHANGED 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;
    
        PApplet ap;    //CHANGE
    
        Vehicle(PApplet cPa, float _x, float _y, float[] _dna) {    //CHANGE
           ap=cPa;        //CHANGE
    
           THE REST of your class follows
    

    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.

Sign In or Register to comment.