dongryun jeong
dongryun jeong

Reputation: 45

Exception in thread "AWT-EventQueue-0" java.lang.ArrayIndexOutOfBoundsException: No such child

enter image description hereum.. I made a simple shooting game and I had a problem. this Exception.

Exception in thread "AWT-EventQueue-0" java.lang.ArrayIndexOutOfBoundsException: No such child: 22
  at java.awt.Container.getComponent(Container.java:334)
  at javax.swing.JComponent.rectangleIsObscured(JComponent.java:4390)
  at javax.swing.JComponent.paint(JComponent.java:1054)
  at javax.swing.JComponent.paintToOffscreen(JComponent.java:5210)
  at javax.swing.RepaintManager$PaintManager.paintDoubleBuffered(RepaintManager.java:1579)
  at javax.swing.RepaintManager$PaintManager.paint(RepaintManager.java:1502)
  at javax.swing.RepaintManager.paint(RepaintManager.java:1272)
  at javax.swing.JComponent._paintImmediately(JComponent.java:5158)
  at javax.swing.JComponent.paintImmediately(JComponent.java:4969)
  at javax.swing.RepaintManager$4.run(RepaintManager.java:831)
  at javax.swing.RepaintManager$4.run(RepaintManager.java:814)
  at java.security.AccessController.doPrivileged(Native Method)
  at java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:80)
  at javax.swing.RepaintManager.paintDirtyRegions(RepaintManager.java:814)
  at javax.swing.RepaintManager.paintDirtyRegions(RepaintManager.java:789)
  at javax.swing.RepaintManager.prePaintDirtyRegions(RepaintManager.java:738)
  at javax.swing.RepaintManager.access$1200(RepaintManager.java:64)
  at javax.swing.RepaintManager$ProcessingRunnable.run(RepaintManager.java:1732)
  at java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:311)
  at java.awt.EventQueue.dispatchEventImpl(EventQueue.java:756)
  at java.awt.EventQueue.access$500(EventQueue.java:97)
  at java.awt.EventQueue$3.run(EventQueue.java:709)
  at java.awt.EventQueue$3.run(EventQueue.java:703)
  at java.security.AccessController.doPrivileged(Native Method)
  at java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:80)
  at java.awt.EventQueue.dispatchEvent(EventQueue.java:726)
  at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:201)
  at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:116)
  at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:105)
  at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:101)
  at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:93)
  at java.awt.EventDispatchThread.run(EventDispatchThread.java:82)

If there is something unusual,Exception occurs when I shoot a lot of bullets. what is this? I do not know what is wrong because it works well.

package com.thread;

import javax.swing.*;
import java.awt.*;
import java.awt.event.*;

public class ShootingGame extends JFrame{
    Container c;
    Enemy enemy;
    Thread th;
    public ShootingGame() {
        setTitle("Shooting Game");
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setSize(500,360);
        c = getContentPane();

        enemy = new Enemy(new ImageIcon("images/enemy_plane.png"));
        Player player = new Player(new ImageIcon("images/player.png"));

        c.add(player, BorderLayout.SOUTH);
        c.add(enemy, BorderLayout.NORTH);
        c.addKeyListener(new KeyAdapter() { // listener for player move, bullet firing
            boolean leftControl = true;  // for only one move input receive
            boolean rightControl = true; // for only one move input receive
            @Override
            public void keyPressed(KeyEvent e) {  // player move, shoot occur
                if(e.getKeyCode() == KeyEvent.VK_LEFT && leftControl && rightControl) {  // Only one movement input is received.
                    leftControl = false;
                    player.pSpeed = -5;  // direction is left.
                    th = new Thread(player);  // player move while hoding key
                    th.start();
                } else if(e.getKeyCode() == KeyEvent.VK_RIGHT && rightControl && leftControl) {  // Only one movement input is received.
                    rightControl = false;
                    player.pSpeed = 5;  // direction is right
                    th = new Thread(player);  // player move while hoding key
                    th.start();
                }
                if(e.getKeyCode() == KeyEvent.VK_SPACE) {  // shoot bullet
                    Bullet bul = new Bullet(new ImageIcon("images/bullet.png"));
                    bul.setSize(16,16);
                    bul.setLocation(player.getX()+c.getWidth()/2-10,player.getY());
                    c.add(bul);
                    c.repaint();
                }
            }
            @Override
            public void keyReleased(KeyEvent e) { // if keyReleased, ready to receive right or left move input
                if (e.getKeyCode() == KeyEvent.VK_LEFT || e.getKeyCode() == KeyEvent.VK_RIGHT) {   
                    th.interrupt();  // quit move thread.
                    leftControl = true;  // ready to receive move input
                    rightControl = true;  // readt to receive move input
                }
            }
        });
        setVisible(true);
        c.requestFocus();
    }
    class Enemy extends JLabel implements Runnable{ // enemyplane info
        int speed;
        public Enemy(ImageIcon enemyplane) {
            super(enemyplane);
            this.setSize(64,64);
            this.setVerticalAlignment(TOP);
            this.setHorizontalAlignment(LEFT);
            Thread th = new Thread(this);
            th.start();
        }

        @Override
        public void run() {  // enemy plane move on x-Axis not change y-Axis
            speed = -5;
            int homeX = this.getX();
            int homeY = this.getY();
            while (true) {
                this.setLocation(homeX + speed, homeY);
                if (homeX + speed > -60) {
                    speed -= 5;
                } else {
                    speed = 0;
                }
                homeX = c.getWidth(); // to fit in frame size
                try {
                    Thread.sleep(20);  // 20millsecond, move
                } catch (InterruptedException e) {
                    return;
                }
            }
        }
    }
    class Player extends JLabel implements Runnable { // player plane
        int pSpeed;
        public Player(ImageIcon controlPlane) {
            super(controlPlane);
            this.setSize(64,64);
            this.setVerticalAlignment(BOTTOM);
            this.setHorizontalAlignment(CENTER);
        }
        @Override
        public void run() { // player move thread
            int pXPosition = this.getX();
            int pYPosition = this.getY();
            while (true) {
                pXPosition += pSpeed;
                this.setLocation(pXPosition, pYPosition);
                if (pXPosition <= -c.getWidth()/2) { // Move within frame only
                    pXPosition = c.getWidth()/2;
                } else if (pXPosition > c.getWidth()/2) { // Move within frame only
                    pXPosition = -c.getWidth()/2;
                }
                try {
                    Thread.sleep(25);  // 25millsecond, move
                } catch (InterruptedException e) {
                    return;
                }
            }
        }
    }
    class Bullet extends JLabel implements Runnable {
        public Bullet(ImageIcon bullet) {
            super(bullet);
            Thread bulletthread = new Thread(this);
            bulletthread.start();
        }
        @Override
        public void run() {  // bullet is move to top from player.
            int bulXPosition = this.getX();
            int bulYPosition = this.getY();
            while(true) {
                bulYPosition -= 10;
                this.setLocation(bulXPosition,bulYPosition);
                if(bulYPosition <= enemy.getY() + 50 && bulYPosition >= enemy.getY()) {
                    if(bulXPosition <= enemy.getX() + 48 && bulXPosition >= enemy.getX()) {   // if enemy hit, bullet is removed and thread quit
                        enemy.speed = 200;
                        c.remove(this);
                        break;
                    }
                }
                if (bulYPosition < -16) { // if bullet is out of frame, bullet is removed
                    c.remove(this);
                    break;
                }
                try {
                    Thread.sleep(25);  // 25millsecond, move
                } catch (InterruptedException e) {
                    return;
                }
            }
        }
    }
    public static void main(String[] args) {
        new ShootingGame();
    }
}

Upvotes: 1

Views: 1178

Answers (1)

MadProgrammer
MadProgrammer

Reputation: 347332

Swing is NOT thread safe. This means that you should NEVER update the UI from outside the context of the Event Dispatching Thread.

A solution would be to use a single Swing Timer as the core "main-loop" responsible for updating the state of the game a schedule repaints.

A simpler, overall solution, would be not to use components this way and instead, have a single container which can paint "entities" and use a Swing Timer to update the state of these "entities" on a regular bases. Because both the paintComponent and Swing Timer perform there work within the EDT, it's safe to update the UI from (the Timer) and prevents possible thread violations

Start by having a look at Concurrency in Swing and How to use Swing Timers.

You may also find the key bindings API generally more reliable then KeyListener

You could also have a look at something like this example to get a better idea of what I've just described

Upvotes: 2

Related Questions