Двойная буферизация игры Java-апплета прервана оператором switch

Я только начинаю делать игры, и я сделал апплет HelloWorld, затем проверил свою идею прокрутки на нем, и в конце концов он начал превращаться в игру в стиле «вертолета». Теперь все работало нормально, пока я не решил добавить несколько операторов switch для обработки состояний (титульный экран, запуск и окончание игры). Код, который работал раньше, не изменился, и мой новый «вводный экран» работает нормально, но когда вы переключаетесь в состояние игры, двойная буферизация, кажется, выходит из строя. Передний план игры быстро включается и выключается, из него вырезаются треугольники, а фон практически не отображается. Я просто изучаю основные принципы кодирования игр, так что это не элегантно, не модульно или что-то в этом роде, но должно работать...

[EDIT] Я знаю, что апплеты и AWT в целом, вероятно, плохой путь, но я начал это так, и я просто хочу узнать, как это работает и что я делаю неправильно, чтобы я мог быть удовлетворен и двигаться дальше.

package testStuff;


import java.awt.*;
import java.applet.*;
import java.io.File;
import java.io.IOException;

import javax.imageio.ImageIO;


public class HelloWorld extends Applet implements Runnable{

//game time counter
int count = 0;

//controller object
Controller control;

//accesses images and creates image variables
File wavesource = new File("C:\\sourceimages\\waves.jpg");
File playerSource = new File("C:\\sourceimages\\plane3.png");
Image player = null;
Image waves = null;

//font for score
Font myFont;

//double buffer objects
Graphics bground;
Image bgImage = null;
private int bgx = 0;

//player position
private int xPos=0;
private int yPos=50;

//arrays for tunnel locations
private int[] topTunnel = new int[200];
private int[] botTunnel = new int[200];

//size of tunnel
private int tunnelSize;

//boolean determines direction of tunnel movement
private boolean tunUp;

//state
private int state;


//"constructor"
public void init(){

    //set state
    state = 0;
    //instantiates controller adds it to the applet
    control = new Controller();
    this.addKeyListener(control);
    //instantiates images
    try {
        waves = ImageIO.read(wavesource);
    } catch (IOException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
    try {
        player = ImageIO.read(playerSource);
    } catch (IOException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
    //instantiates arrays and tunnel size
    for(int i=0;i<199;i++){
        topTunnel[i]=-1;
        botTunnel[i]=-1;
    }
    topTunnel[199]=20;
    botTunnel[199]=179;
    tunnelSize = botTunnel[199]-topTunnel[199];
    tunUp = false;
}
public void paint(Graphics g){
    switch(state){
    case 0:
        g.setColor(Color.black);
        myFont = new Font("Courier", Font.BOLD+Font.ITALIC, 12);
        g.setFont(myFont);
        g.drawString("DON'T CRASH THE PLANE BRO", 10, 100);
        myFont = new Font("Courier", Font.PLAIN, 8);
        g.setFont(myFont);
        g.drawString("Press Spacebar to Play", 40, 150);
        break;
    case 1:
        g.drawImage(player, xPos, yPos, null);
        g.setColor(Color.red);
        for(int i=0;i<200;i++){
            g.fillRect(i, 0, 1, topTunnel[i]);
            g.fillRect(i, botTunnel[i], 1, botTunnel[i]);
        }
        g.setColor(Color.cyan);
        myFont = new Font("Helvetica", Font.PLAIN, 12);
        setFont(myFont);
        if(count<170)
            g.drawString("SCORE: " + 0, 0, 12);
        else
            g.drawString("SCORE: " + (this.count-170), 0, 12);
        break;
    }
}

public void start(){
    Thread thread = new Thread(this);
    thread.start();
}

@Override
public void run(){
    while(true){
        switch(state){
        case 0:
            //increases count
            count++;

            //paints
            this.repaint();

            try {
                    Thread.sleep(1000/30);
                } catch (InterruptedException e1) {
                    // TODO Auto-generated catch block
                    e1.printStackTrace();
                }
            if(control.spaceDown()){
                state = 1;
                count = 0;
            }
            break;

        case 1:
            //increases count
            count++;

            //handles scrolling
            if(xPos<75){
                xPos++;
            }
            else{
                if(bgx>-600){
                    bgx--;
                }
                else{
                    bgx=0;
                }
            }
            //handles input
            if(control.spaceDown()==true&&yPos>=0){
                yPos--;
            }
            else if(yPos<180){
                yPos++;
            }
            //repositions tunnel
            if(xPos>=75){
                for(int i=1;i<200;i++){
                    topTunnel[i-1]=topTunnel[i];
                    botTunnel[i-1]=botTunnel[i];
                }
            }
            //defines new tunnel space
            if(topTunnel[199]<=0 || !tunUp)
                topTunnel[199]++;
            if(botTunnel[199]>=200 || tunUp)
                topTunnel[199]--;
            botTunnel[199] = topTunnel[199]+tunnelSize;

            //randomly chooses direction to move tunnel
            double randomNum = Math.random();
            if(randomNum>.5)
                tunUp = true;
            else
                tunUp = false;

            //narrows tunnel
            if(count%20 == 0)
                tunnelSize--;

            //calls update
            this.repaint();
            //handles framerate
            try {
                Thread.sleep(1000/30);
            } catch (InterruptedException e) {
                 //TODO Auto-generated catch block
                e.printStackTrace();
            }
            break;
        }
    }
}

public void update(Graphics g){

    //instantiates image and graphics on first tick
    if(bgImage == null){
        bgImage = createImage(this.getSize().width, this.getSize().height);
        bground = bgImage.getGraphics();
    }
    //create background based on state
    switch(state){
    case 0:
        //flashing colors!
        if(count%20<10){
            bground.setColor(Color.yellow);
            bground.fillRect(0, 0, 200, 200);
        }
        else{
            bground.setColor(Color.orange);
            bground.fillRect(0, 0, 200, 200);
        }
        break;
    case 1:
        //draws background image(s)
        bground.drawImage(waves,bgx,0,this);
        if(bgx<-399)
            bground.drawImage(waves,bgx+600,0,this);
        break;
    }
    //paint over the background then draw it to screen
    paint(bground);
    g.drawImage(bgImage, 0, 0, this);
}
 }

person spastic_walrus    schedule 24.01.2013    source источник
comment
Нам действительно нужно читать и анализировать весь этот код, чтобы найти вашу проблему?? Можете ли вы сократить его до той части, которая ломается?   -  person lc.    schedule 24.01.2013
comment
Я знаю, что апплеты и AWT в целом, вероятно, плохой путь, но я начал это так и просто хочу узнать, как это работает. Обучение намного проще осуществить с помощью Swing и JFrame - по многим причинам, включая песочницу апплета при загрузке изображений и тенденцию компонентов Swing иметь встроенную двойную буферизацию. Кроме того, этот код сломается во время выполнения File wavesource = new File("C:\\sourceimages\\waves.jpg"); Доступ к ресурсам в апплетах должен осуществляться по URL-адресу.   -  person Andrew Thompson    schedule 24.01.2013
comment
Не забудьте избавиться от своего графического контекста, когда закончите с ним (это означает, что вам придется воссоздать его, когда он вам снова понадобится) - это не то же самое, что создание нового изображения. Также помните, не забывайте очищать/заполнять графику при каждом обновлении.   -  person MadProgrammer    schedule 24.01.2013
comment
Извините, я хотел сделать это более кратким, но я, честно говоря, вообще не уверен, в чем проблема. Как я уже сказал, все это работало до того, как были введены операторы switch, поэтому проблема не может заключаться в доступе к файлам изображений (до этого все было хорошо). @MadProgrammer Вы имеете в виду очищать графику в каждом кадре?   -  person spastic_walrus    schedule 24.01.2013
comment
Да. Возможно, из-за того, что вам нужно обновить графику между кадрами, она рисует то, что на ней стоит.   -  person MadProgrammer    schedule 24.01.2013


Ответы (2)


Вам нужно "очистить" графику на каждом кадре, иначе вы рисуете на том, что было нарисовано ранее...

В приведенном ниже примере я заполнил графический контекст во время его «воспроизведения», но оставил без изменений, когда он был приостановлен, вы должны увидеть разницу...

public class HelloWorld extends Applet implements Runnable {

    private int direction = 4;
    private int state = 0;
    private Image bgImage;
    private Graphics bground;
    private int count;

    private int x = 0;

//"constructor"
    public void init() {
        addKeyListener(new KeyAdapter() {

            @Override
            public void keyPressed(KeyEvent e) {
                if (e.getKeyCode() == KeyEvent.VK_SPACE) {
                    if (state == 0) {
                        state = 1;
                    } else if (state == 1) {
                        state = 0;
                    }
                }
            }

        });
    }

    public void paint(Graphics g) {
        switch (state) {
            case 0:
                g.setColor(Color.black);
                g.drawString("DON'T CRASH THE PLANE BRO", 10, 100);
                g.drawString("Press Spacebar to Play", 40, 150);
                break;
            case 1:
                break;
        }
    }

    public void start() {
        Thread thread = new Thread(this);
        thread.start();
    }

    @Override
    public void run() {
        while (true) {
            switch (state) {
                case 0:
                    count++;
                    this.repaint();
                    break;
                case 1:

                    x += direction;
                    if (x < 0) {
                        x = 0;
                        direction *= -1;
                    } else if (x > getWidth()) {
                        x = getWidth();
                        direction *= -1;
                    }

                    //calls update
                    this.repaint();
                    //handles framerate
                    try {
                        Thread.sleep(1000 / 30);
                    } catch (InterruptedException e) {
                        //TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                    break;
            }
        }
    }

    public void update(Graphics g) {

        //instantiates image and graphics on first tick
        if (bgImage == null) {
            bgImage = createImage(this.getSize().width, this.getSize().height);
            bground = bgImage.getGraphics();
        }
        //create background based on state
        switch (state) {
            case 0:
                //flashing colors!
                if (count % 20 < 10) {
                    bground.setColor(Color.yellow);
                    bground.fillRect(0, 0, 200, 200);
                } else {
                    bground.setColor(Color.orange);
                    bground.fillRect(0, 0, 200, 200);
                }
                break;
            case 1:
                bground.setColor(Color.WHITE);
                bground.fillRect(0, 0, getWidth(), getHeight());
                bground.setColor(Color.RED);
                int y = (getHeight() / 2) - 4;
                bground.fillOval(x, y, 8, 8);
                break;
        }
        //paint over the background then draw it to screen
        paint(bground);
        g.drawImage(bgImage, 0, 0, this);
    }

}
person MadProgrammer    schedule 24.01.2013

Я думаю, вы должны начать, но добавить больше фигурных скобок. Я новичок в кодировании, но из того, что я читал, кодирование длинных операторов без фигурных скобок в определенных операторах в вашем коде приведет к некоторым ошибкам.

Здесь происходит много процессов, и я чувствую, что брекеты помогают

 //defines new tunnel space
        if(topTunnel[199]<=0 || !tunUp)
            topTunnel[199]++;
        if(botTunnel[199]>=200 || tunUp)
            topTunnel[199]--;
        botTunnel[199] = topTunnel[199]+tunnelSize;
        //randomly chooses direction to move tunnel
        double randomNum = Math.random();
        if(randomNum>.5)
            tunUp = true;
        else
            tunUp = false;

        //narrows tunnel
        if(count%20 == 0)
            tunnelSize--;

        //calls update
        this.repaint();

Поправьте меня, если я ошибаюсь, я тоже хочу научиться!

person DonJunior    schedule 24.01.2013
comment
эх, возможно, вы правы, но все это прекрасно работало до того, как были введены операторы switch, поэтому я не думаю, что это проблема на данный момент. - person spastic_walrus; 24.01.2013