【问题标题】:How to make a KeyListener draw an Image for a Java applet如何让 KeyListener 为 Java 小程序绘制图像
【发布时间】:2013-12-24 04:21:01
【问题描述】:

我正在尝试为类制作一个 Java 小程序游戏,允许用户上下输入以移动“玩家”图像并使用空格键射击“僵尸”。我有一个“子弹”图像并且正在尝试使用 KeyListener 以便当用户按下空格键时,“子弹”图像会显示在玩家当前位置的屏幕上并穿过屏幕。但是,当按下空格时,我得到一个运行时错误并且不显示项目符号图像。如果有人能告诉我如何解决这个问题,我将不胜感激!

import java.applet.*;
import java.awt.*;
import java.awt.event.*;

public class ZombieAttackMain extends Applet implements Runnable, KeyListener{

    private Image background, normalZombie, fastZombie, tankyZombie,player,bullet, bloodSplat, cow;

    private Graphics bufferGraphics;
    private Graphics g;
    private Image offScreen;

    private final int POSITION_1_Y = 100;
    private final int POSITION_2_Y = 255;
    private final int POSITION_3_Y = 400;
    private final int POSITION_4_Y = 550;

    private final int PLAYER_X_POSITION = 250;
    private int playerYPosition = POSITION_3_Y;

    private int zombieStartingXPosition = 1000; //change to 1100 later
    private final int NORMAL_ZOMBIE_DX = -2;    //not final
    private final int FAST_ZOMBIE_DX = -3;      //not final
    private final int TANKY_ZOMBIE_DX = -1;     //not final
    private int zombieYPosition; //depends on the zombieYPositionRandom

    private int bulletStartingXPosition = 405;
    private int bulletYPosition;    //depends on player position
    private final int BULLET_DX = 5;    //not final

    private int bloodSplatX, bloodSplatY; //depend on dead zombie position

    //Called when applet starts
    public void init(){
        setSize(1100, 700);
        normalZombie = getImage(getCodeBase(), "NormalZombie.png");
        tankyZombie = getImage(getCodeBase(), "TankyZombie.png");
        fastZombie = getImage(getCodeBase(), "FastZombie.png");
        player = getImage(getCodeBase(), "Player.png");
        bullet = getImage(getCodeBase(), "Bullet.png");
        bloodSplat = getImage(getCodeBase(), "BloodSplat.png");
        background = getImage(getCodeBase(), "Background.jpg");
        cow = getImage(getCodeBase(), "Cow.png");
        addKeyListener(this);
    }
    //Called after init, sets up thread and starts it
    public void start() {
        Thread thread = new Thread(this);
        thread.start();
    }

    public void run() {
        while(true){
            repaint();
            try {
                Thread.sleep(17);     //about 60 fps
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }


    public void update(Graphics g){
        if(offScreen == null){
            offScreen = createImage(this.getWidth(), this.getHeight());
            bufferGraphics = offScreen.getGraphics();
        }
        bufferGraphics.setColor(getBackground());
        bufferGraphics.fillRect(0,0,this.getWidth(),this.getHeight());

        bufferGraphics.setColor(getForeground());
        paint(bufferGraphics);

        g.drawImage(offScreen,0,0,this);
    }

    public void paint(Graphics g){
        g.drawImage(background,0,0,null);
        g.drawImage(cow,-15,115,null);
        g.drawImage(cow,-15,255,null);
        g.drawImage(cow,-15,400,null);
        g.drawImage(cow,-15,550,null);
        g.drawImage(normalZombie,zombieStartingXPosition,100,null);
        g.drawImage(tankyZombie,zombieStartingXPosition,400,null);
        g.drawImage(fastZombie,zombieStartingXPosition,255,null);
        g.drawImage(player,PLAYER_X_POSITION,playerYPosition, null);
        //g.drawImage(bullet,bulletStartingXPosition,336,this);
        g.drawImage(bloodSplat,bloodSplatX,bloodSplatY,null);
    }

    public void moveUp(Image player){
        if(playerYPosition == POSITION_2_Y){
            playerYPosition = POSITION_1_Y;
        }
        if(playerYPosition == POSITION_3_Y){
                playerYPosition = POSITION_2_Y;
        }
        if(playerYPosition == POSITION_4_Y){
            playerYPosition = POSITION_3_Y;
        }
    }

    public void moveDown(Image player){
        if(playerYPosition == POSITION_3_Y){
            playerYPosition = POSITION_4_Y;
        }
        if(playerYPosition == POSITION_2_Y){
            playerYPosition = POSITION_3_Y;
        }
        if(playerYPosition == POSITION_1_Y){
            playerYPosition = POSITION_2_Y;
        }

    }

    public void spawnBullet(){
        g.drawImage(bullet,bulletStartingXPosition, playerYPosition,null);
    }

    public void keyPressed(KeyEvent e) {
        switch(e.getKeyCode()){
        case KeyEvent.VK_UP:
            moveUp(player);
            break;
        case KeyEvent.VK_DOWN:
            moveDown(player);
            break;
        case KeyEvent.VK_SPACE:
            spawnBullet();
            break;
        } 
    }

    public void keyReleased(KeyEvent e) {

    }


    public void keyTyped(KeyEvent e) {

    }

    public void stop() {

    }

    public void destroy() {

    }
}

错误信息:

Exception in thread "AWT-EventQueue-1" java.lang.NullPointerException
    at ZombieAttackMain.spawnBullet(ZombieAttackMain.java:118)
    at ZombieAttackMain.keyPressed(ZombieAttackMain.java:130)
    at java.awt.Component.processKeyEvent(Unknown Source)
    at java.awt.Component.processEvent(Unknown Source)
    at java.awt.Container.processEvent(Unknown Source)
    at java.awt.Component.dispatchEventImpl(Unknown Source)
    at java.awt.Container.dispatchEventImpl(Unknown Source)
    at java.awt.Component.dispatchEvent(Unknown Source)
    at java.awt.KeyboardFocusManager.redispatchEvent(Unknown Source)
    at java.awt.DefaultKeyboardFocusManager.dispatchKeyEvent(Unknown Source)
    at java.awt.DefaultKeyboardFocusManager.preDispatchKeyEvent(Unknown Source)
    at java.awt.DefaultKeyboardFocusManager.typeAheadAssertions(Unknown Source)
    at java.awt.DefaultKeyboardFocusManager.dispatchEvent(Unknown Source)
    at java.awt.Component.dispatchEventImpl(Unknown Source)
    at java.awt.Container.dispatchEventImpl(Unknown Source)
    at java.awt.Component.dispatchEvent(Unknown Source)
    at java.awt.EventQueue.dispatchEventImpl(Unknown Source)
    at java.awt.EventQueue.access$200(Unknown Source)
    at java.awt.EventQueue$3.run(Unknown Source)
    at java.awt.EventQueue$3.run(Unknown Source)
    at java.security.AccessController.doPrivileged(Native Method)
    at java.security.ProtectionDomain$1.doIntersectionPrivilege(Unknown Source)
    at java.security.ProtectionDomain$1.doIntersectionPrivilege(Unknown Source)
    at java.awt.EventQueue$4.run(Unknown Source)
    at java.awt.EventQueue$4.run(Unknown Source)
    at java.security.AccessController.doPrivileged(Native Method)
    at java.security.ProtectionDomain$1.doIntersectionPrivilege(Unknown Source)
    at java.awt.EventQueue.dispatchEvent(Unknown Source)
    at java.awt.EventDispatchThread.pumpOneEventForFilters(Unknown Source)
    at java.awt.EventDispatchThread.pumpEventsForFilter(Unknown Source)
    at java.awt.EventDispatchThread.pumpEventsForHierarchy(Unknown Source)
    at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
    at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
    at java.awt.EventDispatchThread.run(Unknown Source)

【问题讨论】:

  • 好吧,显然我对此很陌生,所以如果你能指出来,那就太好了。谢谢!
  • 他的意思是您应该在问题中包含您遇到的运行时错误。编辑问题并从控制台复制并粘贴错误。
  • 啊,我明白了。这很简单,对不起:P

标签: java image applet keylistener


【解决方案1】:

您的问题是您从未初始化您的private Graphics g。起初这似乎并不明显,因为您的 paint()update() 方法使用 g 就好了,但在这些方法中,g 是一个完全不同的本地 Graphics 对象,它掩盖了您的全局 @987654327 @。我的建议是删除private Graphics g;,因为实际上没有必要让另一个Graphics 对象浮动,并将spawnBullet() 更改为:

public void spawnBullet(){
    bufferGraphics.drawImage(bullet, bulletStartingXPosition, playerYPosition, null);
}

但是,因为每次更新都会清空整个屏幕,所以这不会显示项目符号...最好只在 paint() 方法中绘制,但这完全是另一个话题。

编辑:展示如何让子弹实际显示的示例

private int bulletStartingXPosition = 405;
private int bulletYPosition;    //depends on player position
private final int BULLET_DX = 5;    //not final

// NEW STUFF
private int bulletXPosition;
private boolean showingBullet = false;

public void paint(Graphics g){
    g.drawImage(background,0,0,null);
    g.drawImage(cow,-15,115,null);
    g.drawImage(cow,-15,255,null);
    g.drawImage(cow,-15,400,null);
    g.drawImage(cow,-15,550,null);
    g.drawImage(normalZombie,zombieStartingXPosition,100,null);
    g.drawImage(tankyZombie,zombieStartingXPosition,400,null);
    g.drawImage(fastZombie,zombieStartingXPosition,255,null);
    g.drawImage(player,PLAYER_X_POSITION,playerYPosition, null);
    //g.drawImage(bullet,bulletStartingXPosition,336,this);
    g.drawImage(bloodSplat,bloodSplatX,bloodSplatY,null);

    // NEW STUFF
    if (showingBullet) {
       g.drawImage(bullet,bulletXPosition, playerYPosition, null);
       bulletXPosition += BULLET_DX;
       if (bulletXPosition > 1100) { // if it went off the screen
           showingBullet = false;
       }
    }
}

public void spawnBullet() {

    // NEW STUFF
    if (showingBullet) {
        return; // don't want to reset the bullet if it's already on the screen
    }
    showingBullet = true;
    bulletXPosition = bulletStartingXPosition;
}

【讨论】:

  • 感谢您的回答,现在对我来说很有意义!刚看到最后一部分:P
  • 是的。那是因为您每次更新都会清除屏幕。您应该仅在 paint() 方法中绘制项目符号。有十几种方法可以做到这一点,所以paint() 知道它是否应该画出子弹,但最简单的情况是在spawnBullet() 和@ 中设置一个全局private boolean showingBullet;true 987654339@ 每当它击中某物或离开屏幕时,在paint() 内只绘制子弹if (showingBullet)。您可能也会在此处绘制后立即更新其位置。
  • 您非常有帮助。非常感谢!
  • 我编辑了问题以在代码中演示我在上一条评论中的意思。您显然不必那样做,但这只是一个例子,我很确定应该工作。
  • 我实现了您为我更改的代码。现在子弹出现并在屏幕上移动,我怎样才能使它在玩家跨 y 轴移动时,它在创建时保持在 y 值上?我已经尝试对每个最终 y 位置使用带有四个 if 语句的 for 循环,将 bulletYPosition 设置为等于相应的最终 y 位置,并在每个 if 语句后中断。即使这样,如果玩家也这样做,它仍然会在 y 轴上移动。您无需再输入代码,只需基本想法即可。你帮了很多忙。谢谢!
猜你喜欢
  • 2014-07-06
  • 2016-01-27
  • 2013-01-15
  • 2012-05-29
  • 1970-01-01
  • 1970-01-01
  • 2013-07-03
  • 2014-03-16
  • 1970-01-01
相关资源
最近更新 更多