作者热门文章
- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我利用互联网和一些书籍的帮助制作了一个俄罗斯方 block 游戏,它似乎几乎按照我想要的方式工作。唯一的问题是,当我运行它时,当方 block 掉落时,屏幕会严重闪烁。
我是 AWT 和 swing 的新手,因此我经常倾向于使用反复试验(我知道这很糟糕)来获得我想要的东西。这次我非常不确定程序的哪一部分导致了它。
这是我的代码。抱歉,我的代码有点长,我真的不知道问题出在哪里。 (但大多数情况下是在 Paint() 方法或计时器中。至少我是这么认为的。)
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import java.applet.*;
import java.io.*;
import sun.audio.*;
public class MatrixBoard extends Frame implements ActionListener{
int boardHeight = 20;
int boardWidth = 10;
int score = 0;
int curX = 0, curY = 0;
int squareWidth;
int squareHeight;
Timer timer;
int sleepTime = 300;
Shape curPiece;
Shape.Tetromino[][] board;
boolean isFallingFinished = false;
boolean isStarted = false;
boolean isPaused = false;
public static void main(String [] args){
playAudio("C:\\doak.wav");
MatrixBoard b = new MatrixBoard();
}
public static void playAudio(String filename)
{
InputStream in = null;
AudioStream as = null;
try{
in = new FileInputStream(filename);
as = new AudioStream(in);
}
catch(Exception e){
System.out.println("Error!!!");
}
AudioPlayer.player.start(as);
}
MatrixBoard(){
setTitle("TETRIS: NEW GAME");
setFocusable(true);
setSize(200, 400);
setVisible(true);
setBackground(Color.BLACK);
timer = new Timer(400, this);
timer.setInitialDelay(10);
squareWidth = (getWidth())/ boardWidth;
squareHeight = (getHeight()) / boardHeight;
curPiece = new Shape();
board = new Shape.Tetromino[boardWidth][boardHeight];
addKeyListener(new KeyHandler());
clearBoard();
timer.start();
JOptionPane.showMessageDialog(null, "Press Enter to Start!!!");
start();
System.out.println("MatrixBoard() Success!");
}
public void clearBoard(){
for(int i = 0; i < boardWidth; ++i)
for(int j = 0; j < boardHeight; ++j)
board[i][j] = Shape.Tetromino.NoShape;
}
public void start()
{
if (isPaused)
return;
clearBoard();
timer.start();
timer = new Timer(400, this);
timer.setInitialDelay(100);
isStarted = true;
isFallingFinished = false;
score = 0;
repaint();
newPiece();
System.out.println("START SUCCESS!");
}
private void newPiece(){
if(!isStarted) return;
curPiece.generateShape();
curX = boardWidth / 2;
curY = 1;
if(!tryMove(curPiece, curX, curY)){
curPiece.selectPiece(Shape.Tetromino.NoShape);
isStarted = false;
JOptionPane.showMessageDialog(null, "Game Over! Score : " + score);
isStarted = false;
int opt = JOptionPane.showConfirmDialog(null, "Try Again?", "Again?", JOptionPane.YES_NO_OPTION);
if(opt == JOptionPane.YES_NO_OPTION){
start();
}
dispose();
System.exit(0);
//new Tetris();
return;
}
dropDown();
System.out.println("NEW PIECE SUCCESS!");
}
private boolean tryMove(Shape newPiece, int newX, int newY){
for(int i = 0; i < 4; i++){
int x = newX + newPiece.coords[i][0];
int y = newY + newPiece.coords[i][1];
if(x < 0 || x >= boardWidth || y < 0 || y >= boardHeight){
System.out.println("FALSE1");
return false;
}
if(board[x][y] != Shape.Tetromino.NoShape){
System.out.println("FALSE2");
return false;
}
}
curPiece = newPiece;
curX = newX;
curY = newY;
System.out.println("curX = " + curX + " curY = " + curY);
System.out.println("TRY MOVE SUCCESS!");
return true;
}
private void dropDown(){
int newY = curY;
sleepTime = 300;
System.out.println("newY = " + newY);
while(newY < boardHeight){
if(!tryMove(curPiece, curX, newY+1)){ break;}
++newY;
repaint();
try {
Thread.sleep(sleepTime);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
pieceDropped();
System.out.println("DROPDOWN SUCCESS!");
}
private void pieceDropped(){
for(int i = 0; i < 4; i++){
int x = curX + curPiece.coords[i][0];
int y = curY + curPiece.coords[i][1];
board[x][y] = curPiece.retShape();
System.out.println("PIECE: at X = " + x + " Y = " + y + "is " + curPiece.retShape().ordinal());
}
removeFullLines();
if(!isFallingFinished) newPiece();
System.out.println("PIECE DROPPED SUCCESS!");
}
public void paint(Graphics g){
Dimension size = getSize();
int boardTop = (int) size.getHeight() - boardHeight * squareHeight;
for (int i = 0; i < boardWidth; ++i) {
for (int j = 0; j < boardHeight; ++j) {
Shape.Tetromino shape = board[i][j];
if (shape != Shape.Tetromino.NoShape)
drawSquare(g, i * squareWidth,
boardTop + j * squareHeight, shape);
}
}
if (curPiece.retShape() != Shape.Tetromino.NoShape) {
for (int i = 0; i < 4; ++i) {
int x = curX + curPiece.coords[i][0];
int y = curY + curPiece.coords[i][1];
drawSquare(g, x * squareWidth,
boardTop + (y - 1) * squareHeight,
curPiece.retShape());
}
}
}
private void drawSquare(Graphics g, int x, int y, Shape.Tetromino shape)
{
Color colors[] = { new Color(0, 0, 0), new Color(204, 102, 102),
new Color(102, 204, 102), new Color(102, 102, 204),
new Color(204, 204, 102), new Color(204, 102, 204),
new Color(102, 204, 204), new Color(218, 170, 0)
};
Color color = colors[shape.ordinal()];
g.setColor(color);
g.fillRect(x + 1, y + 1, squareWidth - 2, squareHeight - 2);
g.setColor(color.brighter());
g.drawLine(x, y + squareHeight - 1, x, y);
g.drawLine(x, y, x + squareWidth - 1, y);
g.setColor(color.darker());
g.drawLine(x + 1, y + squareHeight - 1,
x + squareWidth - 1, y + squareHeight - 1);
g.drawLine(x + squareWidth - 1, y + squareHeight - 1,
x + squareWidth - 1, y + 1);
}
private void removeFullLines(){
int numLines = 0;
for(int i = 0; i < boardHeight; i++){
boolean isLineFull = true;
for(int j = 0; j < boardWidth; j++){
System.out.println("i = " + i + " j = " + j);
if(board[j][i] == Shape.Tetromino.NoShape){
System.out.println("Found No Shape here!");
isLineFull = false;
break;
}
}
System.out.println("IIIIIIIIS LINE : " + isLineFull);
if(isLineFull){
numLines++;
for(int k = i; k > 0; k--){
for(int j = 0; j < boardWidth; ++j){
board[j][k] = board[j][k-1];
}
}
}
}
if(numLines > 0){
score += numLines;
repaint();
newPiece();
}
}
class KeyHandler extends KeyAdapter{
public void keyPressed(KeyEvent e){
if(!isStarted || curPiece.retShape() == Shape.Tetromino.NoShape){
return;
}
int keyCode = e.getKeyCode();
switch(keyCode){
case KeyEvent.VK_LEFT:
tryMove(curPiece, curX - 1, curY);
break;
case KeyEvent.VK_RIGHT:
tryMove(curPiece, curX + 1, curY);
break;
case KeyEvent.VK_DOWN:
sleepTime = 10;
break;
case KeyEvent.VK_E:
int opt = JOptionPane.showConfirmDialog(null,"Are you sure?", "Exit", JOptionPane.YES_NO_OPTION);
if(opt == JOptionPane.YES_OPTION){
System.exit(0);
}
break;
case KeyEvent.VK_SPACE:
tryMove(curPiece.rotateLeft(), curX, curY);
break;
default:
break;
}
}
}
@Override
public void actionPerformed(ActionEvent e) {
if (isFallingFinished) {
isFallingFinished = false;
newPiece();
}
}
}
(我知道我的问题可能不符合要求的格式。但我是这个地方的新手,需要一些帮助。因此,对于这个问题中的任何错误,我深表歉意。)
编辑:
问题已解决。按照已接受答案的评论部分中给出的链接,我继续添加了一个类似于链接中给出的示例的函数:http://old.koalateam.com/jml/java/tricks/double-buffering.html
另外,按照其他建议,我将继承更改为 Panel 而不是 Frame,使我能够实现双缓冲。
非常感谢大家。
最佳答案
通常,屏幕闪烁是由于绘图函数花费的时间比屏幕重新绘制的时间长。基本的解决方案是进行离屏缓冲,在离屏图像上绘制,然后在 Paint() 方法中,只需将该图像绘制到屏幕上即可。
有很多帖子都讨论过这个问题。这是一个:https://today.java.net/pub/a/today/2006/02/23/smooth-moves-solutions.html
关于java - 消除自制俄罗斯方 block 游戏中的闪烁,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21795434/
我是一名优秀的程序员,十分优秀!