繁体   English   中英

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

[英]Flicker on movement (Not using JPanel or Swing)

如果您的确是错的话,请原谅我,但我有点不高兴。 -我的计算机科学课上让我们从头开始制作了自己的游戏/程序,但是我们的老师特别忽略了挥杆的存在,并说这是他的境界来教球,所以从我的阅读中看来,好像一个游戏几乎就要用完了问题,到目前为止,我写的主要内容和调试信息在按键输入上剧烈闪烁。 有没有解决的办法?

我知道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变量,然后减去它,因为它是如此之快,就好像它从未移动过。我没想到

我编辑了您的代码:

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键事件之类的方法旨在快速执行。 我仅在EDT处理完所有排队事件后才使用invokeLater暂停。 (我知道这个线程主题无处不在,只要忍受我吧)。

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

  • state应该是一个enum或接近它的东西,而不是随机数。
  • 在绘制对象时使用Shape而不是指定其参数。

双缓冲实现说明:

您将在屏幕offscreen创建一个屏幕offscreen Image对象,并在其上绘制一个Graphics对象bufferGraphics paint内部,您仅对 bufferGraphics使用bufferGraphics 实际上,即使paint属于gamePanel (或任何其他对象及其paint ),您实际上还是在offscreen paint ,这有些令人困惑。 当您在屏幕外完成绘制所有内容时,您可以使用g.drawImage(offscreen...)将其全部放入屏幕,后者使用gamePanelGraphics对象g

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

当前,屏幕外图像是整个applet的大小,而不仅仅是游戏面板的大小,但差别不大。

Swing方法相关的差异:

  • JLabel替换Label ,用JPanel替换Panel等。
  • Swing组件自动实现双重缓冲(请参见JComponentsetDoubleBufferedisDoubleBuffered )。 删除所有这些屏幕外的恶作剧,并直接使用Graphics g绘制。 也无需覆盖update
  • Swing中的paint是在paintComponent完成的,而不是在paint
  • Swing从自己的线程运行,而不是从EDT运行(不是自动运行,但很容易完成)。 我暂时不会对此有一些好处。
  • 通过键绑定(仅限于Swing)而不是通过键侦听器,可以更好地处理键事件。 这表现为响应能力,本机环境独立性以及更多(例如,并发键事件)。

@ user1803551好的,一切都又回到了原来的样子。 -滚动的背景在其中(仅需要从您的帖子中进行一些调整),我知道最后一行“ gamePanel.repaint();”会刷新屏幕上的所有内容,因为背景需要更新每个按键输入,它不应该局限于代码中的微小方块,对吗?现在可以刷新整个屏幕,但是我认为这不是所需要的,因为它只会导致闪烁,底部的绿色矩形不会闪烁,所以我的假设是转换

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

进入缓冲图形?

-编辑-将主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();
    }
}

}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM