[Java2D] Drawing enimies with an arraylist. How to call thier methods

I’m using Java2D for a small basic game I started a while ago. I have an enemy class that draws and moves a rectangle. The thing is, I don’t want to make a ton of enemies using:

Enemy e1 = new Enemy; Enemy e2 = new Enemy;

and so on. I’m not too good with ArrayLists so bare with me. I used:

private ArrayList <Enemy> e;

to create the arraylist of enemies. In my

init()

or initialization method I used:

ArrayList <Enemy> e = new ArrayList();
		e.add(0, null);
		e.add(1, null);

to initialize and add enemies. null is the type of enemy that is never defined. The problem may lay with that but in rendering method I used:

e.draw(g);

which obviously gave an error. How do I call a method from an arraylist’s class.

I tried researching some arraylists help which was good but not what I needed

the easiest way would be to use an enhanced for loop to draw each enemy:


ArrayList <Enemy> enemies = new ArrayList();
      enemies.add(0, null);
      enemies.add(1, null);

      for (Enemy e : enemies){
             e.draw();
      }

Did your research include the JavaDocs??
No need to specify an index for [icode]add()[/icode] if you’re adding them in order anyway, just add them normally: [icode]e.add(null);
e.add(null);[/icode] (Also, why add null elements?)

To “get” an entry back out of the list, you use (gasp) [icode]get()[/icode]:


Enemy first = e.get(0);
Enemy second = e.get(1);
Enemy last = e.get(e.size() - 1);

if(first != null) // if first is null, dereferencing it to call draw() will throw a NullPointerException as you would expect, so don't if it's null
    first.draw(g);
...

I’m afraid that is not how it works. ArrayList is like an array, but you can easily add/remove components from it, not being worried about the size of the array at all.

When adding components to an array, you cannot add null. This alone should give you null pointer exception.

If you want to render all the enemies in the array, you need to render each guy individually.

For example:


		List<Enemy> enemies=new ArrayList<Enemy>();
		
		enemies.add(new Enemy());
		
		for(int i=0;i<enemies.size();i++) {
			enemies.get(i).draw();
		}

There are other ways to do it as you like, but since you’re beginner you wouldn’t be able to wrap your head around it, since its very very abstract.

Thanks, and it gives me an error if I don’t put null in there. I think it’s an object type declaration

Thanks, this is great! It is more efficient

Do you mean this?


Enemy guy;

enemyList.add(guy); // The local variable guy may not have been initialized

That means you need to initialize the variable: [icode]guy = new Enemy(); // alternatively: guy = null;[/icode]

What’s more efficient about it? I’m asking as I don’t want you to have any more misconceptions than you may already have.

Oh I see. I didn’t initialize spereate enimies. That may be why I get the error:

xception in thread "Thread-2" java.lang.NullPointerException
	at main.Panel.draw(Panel.java:116)
	at main.Panel.run(Panel.java:78)

I still get an error. Based off my question, here is the Panel class:

package main;


import java.awt.*;
import java.awt.image.BufferedImage;
import java.awt.event.*;
import java.util.ArrayList;

import javax.swing.JPanel;

import objects.Enemy;
import objects.Player;


public class Panel extends JPanel implements Runnable, KeyListener{	
	private static final long serialVersionUID = -5122190028751177848L;

	
	// dimensions
	public static final int WIDTH = 320;
	public static final int HEIGHT = 240;
	public static final int SCALE = 2;
	
	// game thread
	private Thread thread;
	private boolean running;
	
	// image
	private BufferedImage image;
	private Graphics2D g;
	
	private Player p;
	Enemy a;
	private ArrayList <Enemy> e;
	
	public Panel() {
		super();
		setPreferredSize(new Dimension(WIDTH * SCALE, HEIGHT * SCALE));
		setFocusable(true);
		requestFocus();
	}
	// DRAWS PANEL TO FRAME
	public void addNotify() {
		super.addNotify();
		if(thread == null) {
			thread = new Thread(this);
			addKeyListener(this);
			thread.start();
		}
	}
	
	private void init() {
		
		image = new BufferedImage(
					WIDTH, HEIGHT,
					BufferedImage.TYPE_INT_RGB
				);
		g = (Graphics2D) image.getGraphics();
		p = new Player(100, 100);
		
		a = new Enemy(100, 50);
		
		ArrayList<Enemy> e = new ArrayList<Enemy>();
	      
	      e.add(a);
	      
	      
		
		running = true;
	}
	
	public void run() {
		
		init();
		
		
		// game loop
		while(running) {
			
			update();
			draw();
			drawToScreen();	 
			System.out.println("ELAPSED :" + System.nanoTime()/ 1000000 + " Seconds");
			
			try {
				Thread.sleep(10);
			}
			catch(Exception e) {
				e.printStackTrace();
			}
		
		}
		
	}
	
	private void update() {
		p.update();
		
		
	}
	private void draw(){
		//// Clear Screen /////
		 g.setColor(Color.BLACK);
		 g.fillRect(0, 0, WIDTH, HEIGHT);
		
		
		// NAME (remember it loops) 
		String name = "2014 Jay H.";
		g.setFont(new Font("Name", 0, 12)); 
		g.setColor(Color.WHITE);
		g.drawString(name, 0, 10);
		g.setColor(Color.BLUE);
		g.fillRect( 0, 10, 65, 5);
		
		
		//DRAW PLAYER
		p.draw(g);
		
		//DRAW ENEMY
		for(int i = 0; i < e.size(); i++) {
	         e.get(i).draw(g);
	      }
		
		g.draw3DRect(20, 20, 50, 50, false);
		
		}
	// SCREEN IMAGE (don't have to use. Just use this^)
	private void drawToScreen() {  
		Graphics g2 = getGraphics();
		g2.drawImage(image, 0, 0,
				WIDTH * SCALE, HEIGHT * SCALE,null);
		g2.dispose(); 
	}
	
	public void keyTyped(KeyEvent key) {}
	
	// PUBLIC KEYRELEASES
	public void keyPressed(KeyEvent key) {
		int KeyCode = key.getKeyCode();
		
		//EXIT SYSTEM
		if(KeyCode == KeyEvent.VK_Q) {System.exit(0);}
		
		
		//UP
		if(KeyCode == KeyEvent.VK_W){p.setDY(-2);}	
		if(KeyCode == KeyEvent.VK_A){p.setDX(-2);}
		if(KeyCode == KeyEvent.VK_S){p.setDY(2);}
		if(KeyCode == KeyEvent.VK_D){p.setDX(2);}

	}
	
	
	// PUBLIC KEYRELEASES
	public void keyReleased(KeyEvent key) {
		int KeyCode = key.getKeyCode();
		
		//UP
		if(KeyCode == KeyEvent.VK_W) {p.setDY(0);}
		if(KeyCode == KeyEvent.VK_A){p.setDX(0);}
		if(KeyCode == KeyEvent.VK_S){p.setDY(0);}
		if(KeyCode == KeyEvent.VK_D){p.setDX(0);}

		

	}

}

You don’t get errors in java. You get exceptions. They help you in debugging your code tremendously. You give us your huge piece of code and say “I still get an error” and don’t even post the error and at which lines it happened…

A [icode]NullPointerException[/icode] means that you tried to do something with an object that is null (doesn’t exist).


Enemy e = null;

e.draw(); //e doesn't exist, you can't call draw() on something that doesn't exist, will throw a NPE

java.lang.Error

But yes, really anytime you ask a question about an exception, you NEED to also give the stacktrace.

EDIT: If it’s causing the stacktrace a post up, then it probably means [icode]p[/icode] is null when [icode]draw()[/icode] was called. The line numbers don’t match up though, so you may have changed something and that’s not the right line anymore.

I posted my error if you didn’t notice. It was in a quote or reply

Found it:

e.get(i).draw(g);

[icode]e[/icode] is null because in your [icode]init()[/icode] method you did this:


private ArrayList <Enemy> e;

private void init() {
      ...
      ArrayList<Enemy> e = new ArrayList<Enemy>(); // this is a local variable, the e outside of init() is still null!
         
      e.add(a);

     ...
   }

There is a setting in eclipse to have it tell you you are overwriting or “hiding” a higher-scoped field with a like-named local variable. You should make sure it’s on.

Thanks a bunch, now I just have to fix my multi threading problem

its generally advisable not to use multi-threading unless you are making very complex programs and really know what you are doing. its not needed for basic-medium sized games.

How else can I make 2 tasks run at once? A timer?

you probably dont need 2 tasks to run at once. you run one, then you run the other, then you render everything, repeat.

I made another topic a few minutes ago asking the question my full code is there except now I use thread.sleep and it freezes. in the topic I used thread.wait(). And I need the enemy to move while the game is running

Look, I don’t mean to shit all over your parade but you REALLY NEED TO STEP BACK, you hence been on this forum for like a week and almost every one if your posts is you heeding trouble with basic Java syntax!

You need to read the docs, do some more tutorials.

Tutorials Point

if you want to make the animation wait, yes use some kind of timer. running multiple threads will cause you all kinds of trouble, specially if you need one for each animation. just use a simple frame counter which waits a certain number of frames before changing, and add +1 to the counter each frame.