Как я могу прокрутить более одного объекта одновременно?
Новый вопрос был задан после этого, найденного здесь.
Я новичок в 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);
}
});
}
}