Как я могу прокрутить более одного объекта одновременно?

Новый вопрос был задан после этого, найденного здесь.

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

Прямо сейчас моя программа создает случайный канал и прокручивает его, но мне не нужно продолжать прокручивать его, когда x1-3 = -83 (это когда труба полностью исчезнет с экрана и больше не нужна).

Вопросы

Как я могу сделать мой Game.class прокрутить более одного экземпляра Pipes.class при добавлении заданного расстояния между ними? Я мог бы определить расстояние между ними, но что касается отображения более одного, я не уверен, как это сделать. Максимум, 3 трубы должны отображаться одновременно.

Как я могу отобразить панель для главного меню, а затем переключиться на панель труб после нажатия кнопки запуска?

Классы

Game.java

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.Timer;

public class Game {

    Pipes panel = new Pipes();

    public Game() {
        JFrame f = new JFrame();

        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        f.add(panel);
        f.setTitle("Pipe Game");
        f.setResizable(false);
        f.pack();
        f.setLocationRelativeTo(null);
        f.setVisible(true);

        Timer timer = new Timer(10, new ActionListener() {  //pipe speed
            @Override
            public void actionPerformed(ActionEvent e) {
                panel.move();
            }
        });
        timer.start();

        Timer refresh = new Timer(30, new ActionListener() {    //refresh rate
            @Override
            public void actionPerformed(ActionEvent e) {
                panel.repaint();
            }
        });
        refresh.start();


    }

    public static void main(String args[]) {
        SwingUtilities.invokeLater(new Runnable() {

            @Override
            public void run() {
                new Game();
            }
        });
    }
}

Pipes.java

import java.awt.Dimension;
import java.awt.Graphics;
import javax.swing.JPanel;

public class Pipes extends JPanel {
    //Declare and initialiaze variables
    int x1 = 754;               //xVal start
    int x2 = 75;                //pipe width
                                //total width is 83
    int y1 = -1;                //yVal start
    int y2 = setHeightVal();    //pipe height
    int gap = 130;              //gap height

    @Override
    public void paintComponent(Graphics g) {
        super.paintComponent(g);

        g.clearRect(0,0,750,500);                       //Clear screen
        g.drawRect(x1,y1,x2,y2);                        //Draw part 1
        g.drawRect(x1-3,y2-1,x2+6,25);                  //Draw part 2
        g.drawRect(x1-3,y2+25+gap,x2+6,25);             //Draw part 3
        g.drawRect(x1,y2+25+gap+25,x2,500-y2-49-gap);   //Draw part 4
    }

    public void move() {
        x1--;
    }

    public int getMyX() {   //To determine where the pipe is horizontally
        return x1-3;
    }

    public int getMyY() {   //To determine where the pipe is vertically
        return y2+25;
    }

    public int setHeightVal() {     //Get a random number and select a preset height
        int num = (int)(9*Math.random() + 1);
        int val = 0;
        if (num == 9)
        {
            val = 295;
        }
        else if (num == 8)
        {
            val = 246;
        }
        else if (num == 7)
        {
            val = 216;
        }
        else if (num == 6)
        {
            val = 185;
        }
        else if (num == 5)
        {
            val = 156;
        }
        else if (num == 4)
        {
            val = 125;
        }
        else if (num == 3)
        {
            val = 96;
        }
        else if (num == 2)
        {
            val = 66;
        }
        else
        {
            val = 25;
        }
        return val;
    }

    @Override
    public Dimension getPreferredSize() {
        return new Dimension(751, 501);
    }
}

1 ответ

Решение

"Как я могу сделать так, чтобы мой Game.class прокручивал более одного экземпляра Pipes.class, добавляя предварительно установленное расстояние между ними? "

Вот немного простой логики. Вы хотите использовать структуру данных для хранения ваших каналов. Эта структура данных будет содержать любые данные, необходимые для рисования, такие как x, y, координаты. Для этой задачи я предпочитаю просто создать новый класс с собственным draw метод, который я передаю paintComponentГрафический контекст для. Например

public class Pipe {
    int x;
    int y;
    public class Pipe(int x, int y) {
        this.x = x;
        this.y = y;
    }

    public void drawPipe(Graphics g) {
        g.fillRect(x, y, 50, 100);
    }
}

Теперь это просто пример класса. Выше только рисует прямоугольник, но это просто, чтобы показать вам, что вы должны делать.

Итак, затем вы хотите иметь структуру данных для хранения трех Pipe объекты, такие как массив. Я предпочитаю использовать List, Ты захочешь List в вашем Pipes класс и добавить три Pipe возражать против этого. Вы можете указать x быть чем угодно, держать их на одинаковом расстоянии друг от друга

public class Pipes extends JPanel {
    List<Pipe> pipes = new ArrayList<Pipe>();

    public Pipes() {
        pipes.add(new Pipe(50, 100));
        pipes.add(new Pipe(150, 100));
        pipes.add(new Pipe(250, 100));
    }
}

Сейчас в paintComponent метод, все, что вам нужно сделать, это перебрать их и использовать его drawPipe метод

protected void paintComponent(Graphics g) {
    super.paintComponent(g);

    for ( Pipe pipe : pipes ){
        pipe.drawPipe(g);
    }
}

Теперь вы перемещаете их все, что вам нужно сделать, это двигаться туда x позиции в таймере и вызове repaint, Вы также можете проверить на x, чтобы убедиться, что он не смещается с экрана, или, если вы перемещаете их вправо, вы можете поместить их в крайнее левое положение, а затем убрать с экрана, как конвейерную ленту. Так что вы могли бы сделать что-то вроде этого

private static final int X_INC = 5;
...
Timer timer = new Timer(40, new ActionListener(){
    public void actionPerformed(ActionEvent e) {
        for (Pipe pipe : pipes ){
            if (pipe.x >= screenWidth) {
                pipe.x = 0;
            } else {
                pipe.x += X_INC;
            }
        }
        repaint();
    }
});

Как вы можете видеть, я делаю цикл List и просто поменяй все свои x координаты, то repaint(), Таким образом, вы можете создать свой собственный Pipe Класс с любыми значениями, которые вам нужно нарисовать, и просто переместить их в цикле.


Для изменения скорости, вместо использования жестко закодированных как 10 для таймера используйте переменную delay, что вы можете изменить, как с нажатием кнопки

int delay = 100;
JButton speedUp = new JButton("Speed UP");
JButton slowDown = new JButton("Slow Down");
Timer timer = null;
public Pipes() {
    timer = new Timer(delay, new ActionListener(){
        ...
    });
    timer.start();

    speedUp.addActionListener(new ActionListener(){
        public void actionPerformed(ActionEvent e) {
            if (!((delay - 20) < 0)) {
                delay -=20;
                timer.setDelay(delay);
            }
        }
    });
    // do the same for slowDown, but decrease the delay
}

Проверьте это

import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.imageio.ImageIO;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.Timer;


public class Mario extends JPanel {

    private static final int D_W = 800;
    private static final int D_H = 300;
    private static final int X_INC = 5;

    BufferedImage bg;
    BufferedImage pipeImg;

    List<Pipe> pipes = new ArrayList<>();

    int delay = 50;

    Timer timer = null;

    public Mario() {

        try {
            bg = ImageIO.read(new URL("http://farm8.staticflickr.com/7341/12338164043_0f68c73fe4_o.png"));
            pipeImg = ImageIO.read(new URL("http://farm3.staticflickr.com/2882/12338452484_7c72da0929_o.png"));
        } catch (IOException ex) {
            Logger.getLogger(Mario.class.getName()).log(Level.SEVERE, null, ex);
        }

        pipes.add(new Pipe(100, 150, pipeImg));
        pipes.add(new Pipe(400, 150, pipeImg));
        pipes.add(new Pipe(700, 150, pipeImg));

        timer = new Timer(delay, new ActionListener(){
            public void actionPerformed(ActionEvent e) {
                for (Pipe pipe : pipes) {
                    if (pipe.x > D_W) {
                        pipe.x = 0;
                    } else {
                        pipe.x += X_INC;
                    }
                }
                repaint();
            }
        });
        timer.start();
    }

    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        g.drawImage(bg, 0, 0, getWidth(), getHeight(), this);
        for (Pipe pipe : pipes) {
            pipe.drawPipe(g);
        }
    }

    @Override
    public Dimension getPreferredSize() {
        return new Dimension(D_W, D_H);
    }

    public class Pipe {

        int x;
        int y;
        Image pipe;

        public Pipe(int x, int y, Image pipe) {
            this.x = x;
            this.y = y;
            this.pipe = pipe;
        }

        public void drawPipe(Graphics g) {
            g.drawImage(pipe, x, y, 75, 150, Mario.this);
        }
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                JFrame frame = new JFrame("Mario Pipes");
                frame.add(new Mario());
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }
}

Другие вопросы по тегам