移动时闪烁(不使用JPanel或Swing)

时间:2014-09-23 09:29:21

标签: java applet awt

首先在这里发帖,请原谅我,如果这是绝对错误的事情,但我只是一点点腌菜。 - 我的计算机科学课让我们从零开始制作我们自己的游戏/程序,但是我们的老师特别忽略了挥杆的存在,并且说从我的读数开始教它是不可能的,似乎游戏几乎已经出局了问题,到目前为止我写的主要精灵和调试信息在关键输入上猛烈地闪烁。有没有解决的办法?

我知道JPanel / JFrame / Swing会解决这个问题,但是我们没有教过它,到目前为止我读到的所有内容都让我感到困惑,如果有人能够帮助我转换我的代码来使用它这将是惊人的,因为我从解剖它更容易学习..这可能看起来有点狡猾,但它确实是最容易学习的方法。到目前为止我的代码是;

public class GameThing extends Applet implements KeyListener {

    Image rightsprite, picture;
    Image leftsprite, picture2;
    Image spritedead, picture3;
    Image background, picture4;

    boolean left;
    boolean dead;
    boolean wall;
    boolean menu;

    int widthX, heightY;
    int bgx, bgy;
    String sr = " ";
    char ch = '*';
    Graphics bufferGraphics;
    Image offscreen;
    Dimension dim;

    @Override
    public void init() {
        rightsprite = getImage(getDocumentBase(), "SpriteRight.png");
        leftsprite = getImage(getDocumentBase(), "SpriteLeft.png");
        spritedead = getImage(getDocumentBase(), "Sprite.png");
        background = getImage(getDocumentBase(), "Background.png");
        requestFocus();
        addKeyListener(this);
        left = false;
        menu = true;
        setSize(600, 380);
        dim = getSize();
        offscreen = createImage(dim.width, dim.height);
        bufferGraphics = offscreen.getGraphics();
        bgx = 0;
        bgy = 0;
    }

    public void pause(final int delay) { // PAUSE COMMAND LIFTED FROM RAY
        // waits a while
        try {
            Thread.sleep(delay);
        } catch (InterruptedException e) {
            return;
        }
    }

    public GameThing() { // SPRITE INITIAL SPAWN LOCATION
        widthX = 100;
        heightY = 300;
    }

    @Override
    public void paint(final Graphics g) { // DRAW MAIN CHARACTER SPRITE AND BACKGROUND
        bufferGraphics.setColor(Color.black); // DRAW GROUND (REPLACE WITH BLOCKS SOON)
        bufferGraphics.drawRect(0, 334, 500, 50);
        bufferGraphics.setColor(Color.green);
        bufferGraphics.fillRect(0, 335, 500, 50);
        g.drawImage(offscreen, 0, 0, this);
        if (menu == true) {
            pause(500);
            g.drawString("Side Scroller Test.", 180, 250);
            pause(1500);
            menu = false;
        }

        if (left == false) { // LEFT KEY MOVEMENT COMMANDS
            g.drawImage(rightsprite, widthX, heightY, this);
            g.drawString("Sprites Current X Location is: " + widthX, 20, 30);
            g.drawString("Sprites Current Y Location is: " + heightY, 20, 50);
            g.drawString("Background X location is: " + bgx, 20, 90);
            g.drawString("Currently: " + sr, 20, 70);

        }

        if (left == true) { // RIGHT KEY MOVEMENT COMMANDS
            g.drawImage(leftsprite, widthX, heightY, this);
            g.drawString("Sprites Current X Location is: " + widthX, 20, 30);
            g.drawString("Sprites Current Y Location is: " + heightY, 20, 50);
            g.drawString("Background X location is: " + bgx, 20, 90);
            g.drawString("Currently: " + sr, 20, 70);
        }

        if (dead == true) { // COMMANDS TO EXECUTE WHEN MAIN CHARACTER DIES
            widthX = 506;
            heightY = 314;
            g.drawImage(spritedead, widthX, heightY, this);
            pause(500);
            g.setColor(Color.white);
            g.drawRect(widthX, heightY, widthX, heightY);
            g.fillRect(widthX, heightY, widthX, heightY);
            pause(500);
            widthX = 100;
            heightY = 300;
            bgx = 0;
            left = true;
            dead = false;
        }

    }

    @Override
    public void update(final Graphics g) { // KEEPS BACKGROUND STATIC
        paint(g);
    }

    public void keyPressed(final KeyEvent e) {
        sr = "blank!";
        ch = '1';
        if (e.getKeyCode() == 39) {
            sr = "Moving Right!";
            widthX = widthX + 7;

            if (widthX <= 121) {
                bgx = bgx;
            } else {
                bgx = bgx - 7;
            }

            left = false;

            if ((widthX > 490) && (heightY > 300)) { // FALL DEATH

                sr = "You Died!";
                widthX = 900;
                heightY = 900;
                dead = true;
            }

            if (widthX == 499) {
                heightY = heightY + 7;
            }
        }

        if (widthX == 2) {
            wall = true;
        }

        if (e.getKeyCode() == 37) {

            if (wall == true) {
                sr = "Wall!";
                if (widthX > 2) {
                    wall = false;
                }
            }
            if (wall == false) {
                sr = "Moving Left!";
                widthX = widthX - 7;
                if (bgx >= 0) {
                    bgx = bgx;
                } else {
                    bgx = bgx + 7;
                }
                left = true;
            }
        }

        if (e.getKeyCode() == 38) {
            sr = "Jumping!";
        }
        repaint();
    }

    public void keyTyped(final KeyEvent e) {
        ch = e.getKeyChar();
        repaint();
    }

    public void keyReleased(final KeyEvent e) {
    } // key released
}

ps:使用向上键跳转也是一个问题,我不能简单地添加到Y变量然后减去,因为它变得如此之快,就好像它从未移动过一样。 sidecroller的基础知识比我预期的要多得多。

2 个答案:

答案 0 :(得分:0)

我编辑了你的代码:

public class GameThing extends Applet {

    // External resources
    BufferedImage rightSprite, leftSprite, spriteDead, backgroundImg;

    // Game data
    int state = 1; //0 = left, 1 = right, 2 = dead

    // Geometry
    int locX = 100, locY = 300;
    int bgX = 0, bgY = 0;
    int groundX = 0, groundY = 334, groundW = 500, groundH = 50;
    int appletW = 600, appletH = 480;
    int wallW = 20, wallH = 40, wallX = 20, wallY = groundY - wallH;
    final int STEP_SIZE = 7;

    // Information
    final String X_LOC_STR = "Sprites Current X Location is: ";
    final String Y_LOC_STR = "Sprites Current Y Location is: ";
    final String STATE_STR = "Currently: ";
    final String X_BG_STR = "Background X location is: ";
    String stateString = "";

    // Double buffering
    Image offscreen;
    Graphics bufferGraphics;
    Dimension dim;

    // GUI components
    Panel gamePanel;
    Panel statusPanel = new Panel();
    Label xLocLabel = new Label();
    Label yLocLabel = new Label();
    Label stateLabel = new Label();
    Label xBGLocLabel = new Label();

    @Override
    public void init() {

        // Load images
        try {
            rightSprite = ImageIO.read(new File(getClass().getResource("SpriteRIght.png").getPath()));
            leftSprite = ImageIO.read(new File(getClass().getResource("SpriteLeft.png").getPath()));
            spriteDead = ImageIO.read(new File(getClass().getResource("SpriteDead.png").getPath()));
            backgroundImg = ImageIO.read(new File(getClass().getResource("Background.png").getPath()));
        } catch (IOException e) {
            e.printStackTrace();
        }

        // Set the panel that displays data
        statusPanel.setLayout(new BoxLayout(statusPanel, BoxLayout.Y_AXIS));
        statusPanel.add(xLocLabel);
        statusPanel.add(yLocLabel);
        statusPanel.add(stateLabel);
        statusPanel.add(xBGLocLabel);

        // Create the panel that draws the game and specify its behavior
        gamePanel = new Panel() {

            // Reduces flickering
            @Override
            public void update(Graphics g) {

                paint(g);
            }

            // DRAW MAIN CHARACTER SPRITE AND BACKGROUND
            @Override
            public void paint(Graphics g) {

                bufferGraphics.clearRect(0, 0, dim.width, dim.width);
                bufferGraphics.drawImage(backgroundImg, bgX, bgY, this);
                bufferGraphics.setColor(Color.BLACK); // DRAW GROUND (REPLACE WITH BLOCKS SOON)
                bufferGraphics.drawRect(groundX, groundY, groundW, groundH);
                bufferGraphics.setColor(Color.GREEN);
                bufferGraphics.fillRect(groundX, groundY + 1, groundW, groundH);
                bufferGraphics.setColor(Color.RED);
                bufferGraphics.fillRect(wallX, wallY, wallW, wallH);

                switch (state) {
                    case 0: bufferGraphics.drawImage(leftSprite, locX, locY, this);
                            break;
                    case 1: bufferGraphics.drawImage(rightSprite, locX, locY, this);
                            break;
                    case 2: bufferGraphics.drawImage(spriteDead, locX, locY, this);
                            // After death wait a bit and reset the game
                            EventQueue.invokeLater(new Runnable() {

                                @Override
                                public void run() {

                                    pause(2000);
                                    reset();
                                }
                            });
                            break;
                }
                g.drawImage(offscreen, 0, 0, this);
            }
        };

        // Set the applet window
        setLayout(new BorderLayout());
        add(statusPanel, BorderLayout.PAGE_START);
        add(gamePanel);

        // Set double buffering
        setSize(appletW, appletH);
        dim = getSize();
        offscreen = createImage(dim.width, dim.height);
        bufferGraphics = offscreen.getGraphics();

        // Set the panel that draws the game
        gamePanel.addKeyListener(new Controls());
        gamePanel.requestFocusInWindow();

        updateLabels();
    }   

    // PAUSE COMMAND LIFTED FROM RAY (who is Ray?)
    // waits a while
    public void pause(int delay) {

        try {
            Thread.sleep(delay);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    // Set to start parameters
    public void reset() {

        locX = 100; locY = 300;
        bgX = 0;
        state = 1;
        gamePanel.repaint(); // These 2 lines automatically restart the game
        updateLabels();      // Remove if you want to stay on the death screen until next press
    }

    public void updateLabels() {

        xLocLabel.setText(X_LOC_STR + locX);
        yLocLabel.setText(Y_LOC_STR + locY);
        stateLabel.setText(STATE_STR + stateString);
        xBGLocLabel.setText(X_BG_STR + bgX);
    }

    private class Controls extends KeyAdapter {

        public void keyPressed(KeyEvent e) {

            switch (e.getKeyCode()) {

                case KeyEvent.VK_RIGHT:
                    stateString = "Moving Right!";
                    locX += STEP_SIZE;
                    state = 1;
                    if (locX > 121)
                        bgX -= STEP_SIZE;
                    // FALL DEATH
                    if ((locX > 490) && (locY > 300)) {
                        stateString = "You Died!";
                        state = 2;
                    }
                    // Start fall
                    if (locX == 499)
                        locY += STEP_SIZE;
                    // Check wall collision
                    if (locX >= wallX && locX <= wallX + wallW) {
                        locX -= STEP_SIZE;
                        stateString = "Wall!";
                    }
                    break;

                case KeyEvent.VK_LEFT:
                    stateString = "Moving Left!";
                    locX -= STEP_SIZE;
                    state = 0;

                    if (bgX < 0) 
                        bgX += STEP_SIZE;
                    // Check wall collision
                    if (locX >= wallX && locX <= wallX + wallW) {
                        locX += STEP_SIZE;
                        stateString = "Wall!";
                    }
                    break;

                case KeyEvent.VK_UP:
                    // Implement jumping
                    stateString = "Jumping!";
                    break;
            }

            // Repaint the game panel and update the data panel
            gamePanel.repaint();
            updateLabels();
        }
    }
}

首先测试并了解更改

  • 我为当前数据显示创建了一个单独的面板,并为游戏创建了一个面板(重新绘制)。
  • 我添加了一些帮助功能。
  • 我做了很多语法更改(例如,多个if else替换为switchVK_UP而不是37等等。
  • 最好将所有值放在一个地方,然后从那里读取它们,而不是将它们分散到各个地方(仍然需要一些工作,但在使用代码时会发生变化)。
  • 制作常数值(不会更改的值)final
  • 在Java约定中,常量以大写和下划线(_)命名(所以Color.RED,而不是Color.red)。
  • 在重写方法时更好地使用@Override,即使编译器理解它也是如此。
  • 不要使用sleep或昂贵的计算阻止事件派发线程(EDT)。像paint键事件这样的方法意味着快速执行。我使用invokeLater仅在EDT处理完所有排队事件后暂停。 (据我所知,这个穿线主题来自一个无处不在的炸弹,只是忍受我)。

期待代码的当前状态(无新功能):

  • state应该是enum或与其接近的内容而不是随机数。
  • 使用Shape绘制对象,而不是在绘画期间指定其参数。

双缓冲实施说明:

您可以创建一个离屏Image对象offscreen和一个Graphics对象来绘制它 - bufferGraphics。在paint内,您只能使用 bufferGraphics作为图纸。事实上,即使offscreen属于paint(或任何其他对象及其gamePanel),您也会使用paint,这有点令人困惑。当您在屏幕外完成所有内容绘制后,您可以使用g.drawImage(offscreen...)使用gamePanel的{​​{1}}对象Graphics将其全部一次性放到屏幕上。

这个想法就像把所有东西都画在纸上,然后把它放在相机前,而不是一点一点地在相机上画画,或类似的......

目前,屏幕外图像是整个applet的大小,而不仅仅是游戏面板,但它没什么区别。

Swing 方法的相关差异:

  • g替换为Label,将JLabel替换为Panel等。
  • Swing组件会自动实现双缓冲(请参阅JComponentJPanelsetDoubleBuffered)。删除所有屏幕外的恶作剧,并直接用isDoubleBuffered绘制。无需覆盖Graphics g
  • Swing中的绘画在update完成,而不在paintComponent
  • Swing从自己的线程运行而不是从EDT运行(不是自动的,但很容易完成)。这有一些好处我现在不会进入。
  • 键事件(仅限Swing)而不是键侦听器可以更好地处理键事件。这体现在响应性,本机环境独立性和更多(例如并发关键事件)。

答案 1 :(得分:0)

@ user1803551好的,所以它都会重新回到原来的状态。 - 滚动的背景在(只需要一些东西需要从你的帖子调整),我明白最后一行“gamePanel.repaint();是什么刷新屏幕上的一切,因为背景需要是更新了每个键输入,它不应该限于代码中的小方块,对吧?现在刷新整个屏幕,但我认为这不是想要的,因为它只会导致闪烁,缓冲图形但是底部的绿色矩形不会闪烁。所以我的假设是转换

g.drawImage(backgroundImg, bgx, bgy,this); 

进入buffergraphics?

CNC中 将主Sprite移动到bufferGraphics以及背景图像。闪烁现在几乎消失了,但是在按住箭头键一点点后,屏幕会闪烁一会儿,然后恢复正常。

public class GameTest extends Applet {
/**
 * 
 */
private static final long serialVersionUID = -1533028791433336859L;
Image rightsprite, leftsprite, spritedead, backgroundImg, offscreen;
boolean left = false, dead = false, wall = false, menu = true;
int locX = 100, locY = 300, width, height, bgx = 0, bgy = 0;
final int STEP_SIZE = 7;
final String X_LOC_STR= "Sprites Current X Location is: ";
final String Y_LOC_STR= "Sprites Current Y Location is: ";
final String STATE_STR= "Currently: ";
final String X_BG_STR= "Background X location is: ";
String sr = " ";
Graphics bufferGraphics;
Dimension dim;
Panel gamePanel;
Panel statusPanel = new Panel();
Label xLoc = new Label(X_LOC_STR);
Label yLoc = new Label(Y_LOC_STR);
Label state = new Label(STATE_STR);
Label xBGLoc = new Label(X_BG_STR);
public void init() {
    try {
        rightsprite = ImageIO.read(new File(getClass().getResource("SpriteRight.png").getPath()));
        leftsprite = ImageIO.read(new File(getClass().getResource("SpriteLeft.png").getPath()));
        spritedead = ImageIO.read(new File(getClass().getResource("SpriteDead.png").getPath()));
        backgroundImg = ImageIO.read(new File(getClass().getResource("Background.png").getPath()));
    } catch (IOException e) {
        e.printStackTrace();
    }
    height = rightsprite.getHeight(this);
    width = rightsprite.getWidth(this);
    statusPanel.setLayout(new BoxLayout(statusPanel, BoxLayout.Y_AXIS));
    statusPanel.add(xLoc);
    statusPanel.add(yLoc);
    statusPanel.add(state);
    statusPanel.add(xBGLoc);
    gamePanel = new Panel() {
        /**
         * 
         */
        private static final long serialVersionUID = 1L;

        // DRAW MAIN CHARACTER SPRITE AND BACKGROUND
        @Override
        public void paint(Graphics g) {
            bufferGraphics.drawImage(backgroundImg,bgx, bgy, this);
            bufferGraphics.setColor(Color.black); // DRAW GROUND (REPLACE WITH BLOCKS SOON)
            bufferGraphics.drawRect(0, 334, 500, 50);
            bufferGraphics.setColor(Color.green);
            bufferGraphics.fillRect(0, 335, 500, 50);




            if (menu == true) {
                pause(500);
                g.drawString("Side Scroller Test.", 180, 250);
                pause(1500);
                menu = false;
            }
            // LEFT KEY MOVEMENT COMMANDS
            if (left == false)
                bufferGraphics.drawImage(rightsprite, locX, locY, this);
            // RIGHT KEY MOVEMENT COMMANDS
            else
                bufferGraphics.drawImage(leftsprite, locX, locY, this);
            // COMMANDS TO EXECUTE WHEN MAIN CHARACTER DIES
            if (dead == true) {
                locX = 506;
                locY = 314;
                bufferGraphics.drawImage(spritedead, locX, locY, this);
                pause(500);
                bufferGraphics.setColor(Color.white);
                bufferGraphics.drawRect(locX, locY, width, height);
                bufferGraphics.fillRect(locX, locY, width, height);
                pause(500);
                locX = 100;
                locY = 300;
                bgx = 0;
                bgy = 0;
                bufferGraphics.clearRect(locX, locY, width, height);
                left = true;
                dead = false;
            }
            g.drawImage(offscreen, 0, 0, this);
            super.paint(g);

        }
    };
    setLayout(new BorderLayout());
    add(statusPanel, BorderLayout.PAGE_START);
    add(gamePanel);
    setSize(600, 480);
    dim = getSize();
    offscreen = createImage(dim.width, dim.height);
    bufferGraphics = offscreen.getGraphics();
    gamePanel.addKeyListener(new Controls());
    gamePanel.requestFocusInWindow();
}
// waits a while
public void pause(int delay) {
    try {
        Thread.sleep(delay);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
}
private class Controls extends KeyAdapter {
    public void keyPressed(KeyEvent e) {
        sr = "blank!";
        if (e.getKeyCode() == KeyEvent.VK_RIGHT) {
            sr = "Moving Right!";
            locX += STEP_SIZE;
            if (locX > 121)
                bgx = bgx - STEP_SIZE;

                left = false;
            // FALL DEATH
            if ((locX > 490) && (locY > 300)) {
                sr = "You Died!";
                locX = 900;
                locY = 900;
                dead = true;
                gamePanel.repaint();
            }
            if (locX == 499) {
                locY += STEP_SIZE;
            }
        }
        if (locX == 2) {
            wall = true;
        }
        else if (e.getKeyCode() == KeyEvent.VK_LEFT) {
            if (wall == true) {
                sr = "Wall!";
                if (locX > 2) {
                    wall = false;
                }
            }
            else {
                sr = "Moving Left!";
                locX -= STEP_SIZE;
                if (bgx < 0) 
                    bgx += STEP_SIZE;
                left = true;
            }
        }
        if (e.getKeyCode() == KeyEvent.VK_UP) {
            sr = "Jumping!";
        }
        xLoc.setText(X_LOC_STR + locX);
        yLoc.setText(Y_LOC_STR + locY);
        state.setText(STATE_STR + sr);
        xBGLoc.setText(X_BG_STR + bgx);
        gamePanel.repaint();
    }
}

}