我目前正在嘗試制作一個產生圓圈的游戲,玩家必須點擊它才能獲得分數。那里有很多細節,但我想問這個問題。
由于原始代碼來自youtube上的“Bro Code”制作的蛇游戲,因此一些變數在那里未使用或不合適。我正在嘗試使用他的代碼作為基礎。
如何在二維網格中無限制地生成多個圓圈?(我在始終觸發的偵聽器中測驗了 spawnTarget() 方法,它只允許存在一個圓圈。)
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import java.util.Random;
public class GamePanel extends JPanel implements ActionListener {
static final int SCREEN_WIDTH = 1600;
static final int SCREEN_HEIGHT = 1000;
static final int UNIT_SIZE = 25;
static final int GAME_UNITS = (SCREEN_WIDTH*SCREEN_HEIGHT)/UNIT_SIZE;
static final int DELAY = 75;
final int x[] = new int[GAME_UNITS];
final int y[] = new int[GAME_UNITS];
int bodyParts = 6;
int applesEaten = 0;
int appleX;
int appleY;
boolean running = false;
Timer timer;
Random random;
//
JPanel clockPanel;
JLabel clock;
long startTime;
long endTime;
//
long elapsedSeconds;
long elapsedTenthSeconds;
//
//
GamePanel() {
random = new Random();
this.setPreferredSize(new Dimension(SCREEN_WIDTH,SCREEN_HEIGHT));
this.setBackground(Color.black);
this.setFocusable(true);
this.addKeyListener(new MyKeyAdapter());
startGame();
}
public void startGame() {
running = true;
timer = new Timer(DELAY,this);
timer.start();
clockMethod();
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
draw(g);
}
public void draw(Graphics g) {
if (running) {
// optional grid
for(int i=0; i<SCREEN_WIDTH/UNIT_SIZE; i ) {
g.drawLine(0, i*UNIT_SIZE, SCREEN_WIDTH, i*UNIT_SIZE);
g.drawLine(i*UNIT_SIZE, 0, i*UNIT_SIZE, SCREEN_HEIGHT);
}
// apple
g.setColor(Color.red);
g.fillOval(appleX, appleY, UNIT_SIZE, UNIT_SIZE);
// score
g.setColor(Color.white);
g.setFont(new Font("Courier New", Font.BOLD, 40));
FontMetrics metrics = getFontMetrics(g.getFont());
g.drawString(String.valueOf(applesEaten),(SCREEN_WIDTH - metrics.stringWidth(String.valueOf(applesEaten)))/2,2*g.getFont().getSize());
}
else {
gameOver(g);
}
}
public void newTargetCoords() {
appleX = random.nextInt((int)(SCREEN_WIDTH/UNIT_SIZE))*UNIT_SIZE;
appleY = random.nextInt((int)(SCREEN_HEIGHT/UNIT_SIZE))*UNIT_SIZE;
}
public void move() {
}
public void spawnTarget() {
newTargetCoords();
}
public void checkApple() {
if ((x[0] == appleX)&&(y[0] == appleY)) {
bodyParts ;
applesEaten ;
}
}
public void checkCollisions() {
if (!running) {
timer.stop();
}
}
public void gameOver(Graphics g) {
// score
g.setColor(Color.white);
g.setFont(new Font("Courier New", Font.BOLD, 20));
FontMetrics metrics1 = getFontMetrics(g.getFont());
g.drawString("score: " applesEaten,(SCREEN_WIDTH - metrics1.stringWidth("score: " applesEaten))/2,g.getFont().getSize());
// Game Over text
g.setColor(Color.green);
g.setFont(new Font("Courier New", Font.PLAIN, 40));
FontMetrics metrics2 = getFontMetrics(g.getFont());
g.drawString("game over",(SCREEN_WIDTH - metrics2.stringWidth("game over"))/2,SCREEN_HEIGHT/2);
}
public void restartGame() {
setVisible(false);
new GameFrame();
}
public void clockMethod() {
clockPanel = new JPanel();
clock = new JLabel("00:00");
clockPanel.add(clock);
startTime = System.currentTimeMillis();
add(clockPanel);
}
@Override
public void actionPerformed(ActionEvent e) {
if (running) {
move();
checkApple();
checkCollisions();
}
repaint();
if(timer.isRunning())
{
endTime = System.currentTimeMillis();
// elapsed quarter seconds for spawns
elapsedTenthSeconds = (endTime-startTime)/100;
// put elapsed seconds into variable
elapsedSeconds = (endTime-startTime)/1000;
// declare formatting
int min = (int)elapsedSeconds/60;
int sec = (int)elapsedSeconds%60;
String minStr = (min<10 ? "0" : "") min;
String secStr = (sec<10 ? "0" : "") sec;
// display elapsed time (minutes:seconds)
clock.setText(minStr ":" secStr);
// spawn circle
spawnTarget();
}
}
public class MyKeyAdapter extends KeyAdapter {
@Override
public void keyPressed(KeyEvent e) {
if (e.getKeyCode() == KeyEvent.VK_R) {
restartGame();
}
}
}
}
uj5u.com熱心網友回復:
因為原始代碼來自youtube上“Bro Code”制作的蛇游戲
作為“一般”建議,我會避免使用 YouTube 來學習代碼,除了過時非常快之外,SO 似乎花費了大量時間來糾正來自 YouTube 的代碼示例。
首先,我建議您花時間閱讀AWT 中的繪畫和 Swing和執行自定義繪畫,以確保您對 Swing 中的繪畫程序有基本的了解。
至于您的問題,是否需要跟蹤可見的內容。根據您希望它的作業流程,我可能有一個“物體”池,您可以隨機選擇這些“物體”并將它們移動到“可見物體”池中。當新的繪制周期運行時,您只需繪制“可見物體”。
您需要考慮一個物體應該顯示多長時間,并且每次“游戲回圈”運行時,您都需要檢查是否有任何可見物體“死亡”,此時您將從中洗掉“可見物體”池并將它們放回“物體池”。
例如...
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.time.Duration;
import java.time.Instant;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Random;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.Timer;
public class Main {
public static void main(String[] args) {
new Main();
}
public Main() {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
JFrame frame = new JFrame();
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class StopWatch {
private Instant startedAt;
private Duration duration;
public void setDuration(Duration duration) {
this.duration = duration;
}
public Duration getDuration() {
return duration;
}
public void start() {
startedAt = Instant.now();
}
public Instant getStartedAt() {
return startedAt;
}
public Duration getTimeRemaining() {
Instant startedAt = getStartedAt();
Duration duration = getDuration();
if (startedAt == null || duration == null) {
return Duration.ZERO;
}
Duration runtime = Duration.between(startedAt, Instant.now());
return duration.minus(runtime);
}
public boolean hasTimeRemaining() {
Duration timeRemaining = getTimeRemaining();
return timeRemaining.toMillis() > 0;
}
}
public class Target {
private int row;
private int col;
private StopWatch stopWatch = new StopWatch();
public Target(int row, int col) {
this.row = row;
this.col = col;
}
public int getColumn() {
return col;
}
public int getRow() {
return row;
}
public void spawn(Duration lifeSpan) {
stopWatch = new StopWatch();
stopWatch.setDuration(lifeSpan);
stopWatch.start();
}
public void die() {
stopWatch = null;
}
public Instant getBirthDate() {
if (stopWatch == null) {
return null;
}
return stopWatch.getStartedAt();
}
public Duration getLifeSpan() {
if (stopWatch == null) {
return null;
}
return stopWatch.getDuration();
}
public Duration getTimeRemaining() {
if (stopWatch == null) {
return Duration.ZERO;
}
return stopWatch.getTimeRemaining();
}
public boolean isAlive() {
if (stopWatch == null) {
return false;
}
return stopWatch.hasTimeRemaining();
}
}
public class TestPane extends JPanel {
private List<Target> targets;
private List<Target> visibleTargets;
private int rows = 4;
private int cols = 4;
private Target clickedTarget;
public TestPane() {
targets = new ArrayList<>(getRows() * getColumns());
visibleTargets = new ArrayList<>(getRows() * getColumns());
for (int row = 0; row < rows; row ) {
for (int col = 0; col < cols; col ) {
targets.add(new Target(row, col));
}
}
Timer timer = new Timer(5, new ActionListener() {
private Random rnd = new Random();
private List<Target> deadTargets = new ArrayList<>(getRows() * getColumns());
private StopWatch respawnStopWatch;
protected void restartRespawnClock() {
// Spawn a new target every second
respawnStopWatch.setDuration(Duration.ofSeconds(rnd.nextInt(1) 1));
respawnStopWatch.start();
}
@Override
public void actionPerformed(ActionEvent e) {
if (respawnStopWatch == null) {
respawnStopWatch = new StopWatch();
restartRespawnClock();
}
if (!respawnStopWatch.hasTimeRemaining()) {
restartRespawnClock();
if (!targets.isEmpty()) {
Collections.shuffle(targets);
Target target = targets.remove(0);
Duration lifeSpan = Duration.ofSeconds(rnd.nextInt(5) 3);
target.spawn(lifeSpan);
visibleTargets.add(target);
}
}
deadTargets.clear();
for (Target target : visibleTargets) {
if (!target.isAlive()) {
deadTargets.add(target);
}
}
visibleTargets.removeAll(deadTargets);
targets.addAll(deadTargets);
repaint();
}
});
timer.start();
addMouseListener(new MouseAdapter() {
@Override
public void mouseClicked(MouseEvent e) {
for (Target target : visibleTargets) {
Rectangle bounds = getBoundsFor(target);
if (bounds.contains(e.getPoint())) {
clickedTarget = target;
return;
}
}
}
});
}
@Override
public Dimension getPreferredSize() {
return new Dimension(400, 400);
}
public int getRows() {
return rows;
}
public int getColumns() {
return cols;
}
protected Rectangle getBoundsFor(Target target) {
int width = getWidth() / getColumns();
int height = getHeight() / getRows();
int x = target.getColumn() * width;
int y = target.getRow() * height;
return new Rectangle(x, y, width, height);
}
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
for (Target target : visibleTargets) {
Rectangle bounds = getBoundsFor(target);
if (target == clickedTarget) {
g2d.fillOval(bounds.x, bounds.y, bounds.width, bounds.height);
} else {
g2d.drawOval(bounds.x, bounds.y, bounds.width, bounds.height);
}
}
g2d.dispose();
}
}
}
有幾點需要注意...
- 我沒有快取
Target邊界,因為它們是根據組件的當前大小動態計算的。實際上,您可以使用ComponentListener當componentResized被呼叫時,使快取無效,但這是您可以自行調查的附加增強功能。 - 生成新目標之間的時間隨機介于 1-2 秒之間,可以將其調整為使用毫秒而不是秒,但我相信大多數用戶不會看到差異
- 目標的隨機生命周期在 2-7 秒之間,請隨意修改。
該示例還演示了一種檢測目標何時被單擊的簡單方法,在上面的示例中,它將簡單地導致目標被填充。
我還會考慮為游戲和游戲螢屏使用單獨的組件,可能使用CardLayout. 這降低了類的復雜性。
轉載請註明出處,本文鏈接:https://www.uj5u.com/shujuku/483448.html
