So I\'m making a game and I have the EnemyAI as well as the player and they both extend JPanel. The world has a null layo
This is a normal behavior and it's why you can't modify state inside paintComponent. We don't have control over when repaints happen: the system does them on its own sometimes.
Here's an example of what I mean, which you shouldn't be doing:
public class PlayerPane extends JPanel{
...
public void paintComponent(Graphics g){
...
// modifying index
if(index == images.length-1){
index = 0;
} else {
index++;
}
}
}
You need to go through all of your code looking for every place you've modified a variable like this inside paintComponent, and move it out to somewhere else.
As a side note, you should also move your ImageIO.read calls so they are not inside paintComponent. Load your images once when the program starts, in to static variables or something like that.
And as a general tip, you should look in to animation with just painting instead of trying to animate components. It will do you huge favors in the long run for a game.
So in summary:
paintComponent stateless.paintComponent.Here's a minimal example which demonstrates this by animating shapes falling down the window:

import java.net.*;
import javax.swing.*;
import javax.imageio.*;
import java.awt.image.*;
import java.awt.event.*;
import java.awt.Dimension;
import java.awt.Color;
import java.awt.Graphics;
import java.util.List;
import java.util.ArrayList;
import java.util.Random;
class FallingShapes implements Runnable {
public static void main(String[] args) {
SwingUtilities.invokeLater(new FallingShapes());
}
@Override
public void run() {
List<Entity> entities = new ArrayList<Entity>();
int w = 0;
int h = 0;
for (BufferedImage img : Resources.images) {
entities.add(new Entity(img));
w += img.getWidth();
h += img.getHeight();
}
PaintPanel p = new PaintPanel(entities);
p.setPreferredSize(new Dimension(w, (2 * h)));
JFrame f = new JFrame();
f.setContentPane(p);
f.pack();
f.setLocationRelativeTo(null);
f.setResizable(false);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setVisible(true);
new Animator((1000 / 60), p, entities).start();
}
static class Animator implements ActionListener {
int period;
JPanel context;
int height;
List<Entity> entities;
Animator(int period, JPanel context, List<Entity> entities) {
this.context = context;
this.height = context.getHeight();
this.period = period;
this.entities = entities;
}
@Override
public void actionPerformed(ActionEvent a) {
for (Entity e : entities) {
double dist =
(period / 1000.0) * (height * e.rate);
e.y += dist;
e.y %= height;
}
context.repaint();
}
void start() {
Random r = new Random();
int x = 0;
for (Entity e : entities) {
e.x = x;
e.y = r.nextInt(height);
e.rate = (0.25 + (0.75 * r.nextDouble()));
x += e.width;
}
new Timer(period, this).start();
}
}
static class Entity {
BufferedImage img;
double x, y, rate;
int width, height;
Entity(BufferedImage img) {
this.img = img;
this.width = img.getWidth();
this.height = img.getHeight();
}
void paint(Graphics g, JPanel context) {
int x = (int) Math.round(this.x);
int y = (int) Math.round(this.y);
g.drawImage(img, x, y, null);
int cHeight = context.getHeight();
if ((y + height) > cHeight) {
g.drawImage(img, x, y - cHeight, null);
}
}
}
static class PaintPanel extends JPanel {
List<Entity> entities;
PaintPanel(List<Entity> entities) {
this.entities = entities;
setBackground(Color.white);
}
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
for (Entity e : entities) {
e.paint(g, this);
}
}
}
static class Resources {
static final String[] paths = {
"http://i.stack.imgur.com/wCF8S.png",
"http://i.stack.imgur.com/5v2TX.png",
"http://i.stack.imgur.com/F0JHK.png",
"http://i.stack.imgur.com/4EVv1.png",
"http://i.stack.imgur.com/xj49g.png",
};
static final List<BufferedImage> images =
new ArrayList<BufferedImage>();
static {
for (String path : paths) {
try {
images.add(ImageIO.read(new URL(path)));
} catch (Exception e) {
throw new AssertionError(e);
}
}
}
}
}
(Images from here.)
Other useful examples of animation and painting: