Java 如何停止在使用瓷砖的侧卷轴中闪烁?
因此,我试图阻止我的程序闪烁,但由于其他人的问题,我找不到适用于我的代码的解决方案。它只是闪烁,我看到另一个人的帖子建议改为paintComponent,但与paint相比,我看不出它是如何工作的。任何帮助都将不胜感激Java 如何停止在使用瓷砖的侧卷轴中闪烁?,java,swing,Java,Swing,因此,我试图阻止我的程序闪烁,但由于其他人的问题,我找不到适用于我的代码的解决方案。它只是闪烁,我看到另一个人的帖子建议改为paintComponent,但与paint相比,我看不出它是如何工作的。任何帮助都将不胜感激 package runalreadypls; import java.awt.Color; import java.awt.Font; import java.awt.Graphics; import java.awt.event.ActionEvent; import jav
package runalreadypls;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.image.BufferedImage;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Random;
import javax.imageio.ImageIO;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.Timer;
public class GameGen extends JFrame implements KeyListener{
private static final long serialVersionUID = -7177541209377865450L;
Random rand = new Random();//Random generator for map
double move = 0;//Moves graphics generation
int timed = 750;//Moving delay
int speed = 2;//Moves Faster
int [][] world=new int[10][100];//Map generation
int WIDTH = 720;//Width of frame/window
int HEIGHT = 480;//Height of frame/window
String exitMSG;//Exit message
String user;//username
int charX = 0;//Starting coordinates for character
int charY= 4;
BufferedImage img1;//Graphics generation
static double score = 0;//Score of player
GameGen(){//Start game
super("Runner");//Set frame specifications
this.setSize(WIDTH,HEIGHT);
this.setLocationRelativeTo(null);
this.setUndecorated(true);
this.setDefaultCloseOperation(DO_NOTHING_ON_CLOSE);
this.setResizable(false);
this.setFocusable(true);
this.setVisible(true);
//Adds spacebar listener
addKeyListener(this);
//Starts world generation
worldGen();
//Paints world
repaint();
//Swing Timer for moving of character and background
Timer timer = new Timer(timed ,null);
timer.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent evt) {
//Increasing speed
if (speed < 400){
speed = speed + 5;
}
timer.setDelay(timed - speed);
//Increasing score
score = score + 3;
//Moving character
charX= charX + 1;
//Checks if game is over
if(gameOverCollision()){
timer.stop();//Ends "delayed loop"
}
//Gravity
//If charY is not below the screen to prevent array out of bounds
if (charY < 9){
if (world[charY+1][charX] == 0){//Moves character down/Gravity
charY = charY+1;
deleter();//Deletes character previous coords
mover();//Moves character coords on array
}
}
deleter();//Deletes character previous coords
mover();//Moves character coords on array
}
});
timer.start();//Starts "delayed loop" / swing timer
}
public void deleter(){//Deletes character previous coords so there is only one character on the screen
for(int x = 0;x <9;x++){
for(int y = 0; y < 100; y++){
if (world[x][y] == 2){
world[x][y] = 0;
}
}
}
}
public void mover(){//Moves character on the array
world[charY][charX] = 2;
repaint();
}
/*
*
* 0 = Background
* 1 = Surface
* 2 = Player
* 3 = Below Surface
*
* */
public void worldGen(){
int xAt = 5;
world[4][0] = 2;//Character placement
world[5][0] = 1;//First tile placement
for (int x = 1; x < 100; x++){ //Starting place
int X =3;
X = rand.nextInt(X)+1;//Random Number Generator
if (xAt <= 6 && xAt>=3){//If where the ground is at is between 7 and 2 (exclusive)then it will generate normally
if (X == 1){
xAt =xAt+ 1;
world[xAt][x] = 1;
}else if (X == 3){
xAt =xAt - 1;
world[xAt][x] = 1;
}else if (X==2){
world[xAt][x]=1;
}
/*
* If where the ground is at is too low between 7 and 9 (which is the bottom 3 tiles)
* then it will generate with more chances of going up instead of staying the same
*
*/
}else if(xAt >6 && xAt <9){
if (X==1 || X==3){
xAt =xAt- 1;
world[xAt][x] = 1;
}else if (X==2){
world[xAt][x]=1;
}
/*
* If where the ground is at is too low between 1 and 4((exclusive) which is the top 3 tiles)
* then it will generate with more chances of going down instead of staying the same
*
*/
}else if(xAt >1 && xAt <3){
if (X==1 || X==3){
xAt =xAt+ 1;
world[xAt][x] = 1;
}else if (X==2){
world[xAt][x] = 1;
}
}
}
//Generates ground below the surface
for(int x = 0;x <9;x++){
for(int y = 0; y < 100; y++){
if (world[x][y] == 1){
world[x+1][y] = 3;
}
if (world[x][y] == 3){
world[x+1][y] = 3;
}
}
}
}
@Override
public void paint(Graphics g){
super.paint(g);
g.setColor(Color.WHITE);
g.setFont(new Font("TimesRoman", Font.PLAIN, 100));
g.drawString(Integer.toString((int) score), 220, 100);
//Checks through 2d array to generate images
for(int x = 0;x <9;x++){
for(int y = 0; y < 100; y++){
if(world[x][y] == 0){
try {//If background then accesses background image
img1 = ImageIO.read(new File("src/runalreadypls/Background.png"));
} catch (IOException e) {
e.printStackTrace();
}
} else if(world[x][y] == 1){
try {//If surface then accesses surface image
img1 = ImageIO.read(new File("src/runalreadypls/Ground.png"));
} catch (IOException e) {
e.printStackTrace();
}
}else if (world[x][y] == 2){
try {//If surface then accesses character image
img1 = ImageIO.read(new File("src/runalreadypls/Character2.png"));
} catch (IOException e) {
e.printStackTrace();
}
}else if (world[x][y] == 3){
try {//If below surface then accesses below surface image
img1 = ImageIO.read(new File("src/runalreadypls/Foreground.png"));
} catch (IOException e) {
e.printStackTrace();
}
}
g.drawImage(img1,(int) (45*(y-move)),60*x,null);//Draws images in procedural order
}
}
move = move + .65;//Moves screen
}
/*
*
* WALL collision
* If player misses jump
* Game is over
*
*
* */
public boolean gameOverCollision(){
//Checks if the player has missed a tile or if they have finished the map
if(world[charY][charX] == 1||charX == 99){
/*
*
* Adds current players score to the high score file
*
* */
try {
fileAppend();
} catch (IOException e) {
e.printStackTrace();
}
/*
*
* Sorts high scores in order of greatest to least
*
* */
try {
fileSort();
} catch (IOException e) {
e.printStackTrace();
}
//Deletes window
dispose();
//Exit Msg
exitMSG = "Thank you for playing " +Game.name() +" your score is: " + score;
JOptionPane.showMessageDialog(null, exitMSG, "Thank you for Playing!", JOptionPane.ERROR_MESSAGE);
//Recreates main menu
new Game();
//Reseting Score and speed
score = 0;
speed = 2;
return true;
//Checks if player has finished the map
}else{
return false;
}
}
public void fileSort()throws IOException,FileNotFoundException{
List<Integer> list = new ArrayList<Integer>();//Array list to store integers
File file = new File("highscores.txt");//File
BufferedReader br = null;//br
br = new BufferedReader(new FileReader(file));//br
String text = null;//text
while ((text = br.readLine()) != null) {//Putting integer into list
list.add((int) Double.parseDouble(text));//Converting line text to int and putting into list
}
if (br != null) {//closing
br.close();
}
Collections.sort(list);//sort list
Collections.reverse(list);//reverse list for descending order
FileWriter fw = new FileWriter("highscores.txt");//Write to file
BufferedWriter bw = new BufferedWriter(fw);
for(Integer lists: list) {
bw.write(lists);//WRiting to file
bw.newLine();//New line
}
bw.close();//Closing
fw.close();
}
public void fileAppend()throws IOException{
//Declaring writers
FileWriter fw = null;
BufferedWriter bw = null;
PrintWriter pw = null;
fw = new FileWriter("highscores.txt", true);
bw = new BufferedWriter(fw); pw = new PrintWriter(bw);
pw.println(score); //Adding to file
//Closing
pw.close();
bw.close();
fw.close();
}
/*
*
* Listens to spacebar input to move character up a tile
*
* */
@Override
public void keyPressed(KeyEvent e) {
if(charY<9 && charY >0){
if (e.getKeyCode()==KeyEvent.VK_SPACE){
if(world[charY][charX+1] == 1){
charY-=1;//Moving character Y coords up a tile
deleter();//Deletes character previous coords
mover();//Changing player's tile in array
}
if(world[charY][charX+1] != 1){
score = score -3; //Substracts score if player jumps early
}
}
}
}
@Override
public void keyReleased(KeyEvent e) {
}
@Override
public void keyTyped(KeyEvent e) {
}
}
包runalreadypls;
导入java.awt.Color;
导入java.awt.Font;
导入java.awt.Graphics;
导入java.awt.event.ActionEvent;
导入java.awt.event.ActionListener;
导入java.awt.event.KeyEvent;
导入java.awt.event.KeyListener;
导入java.awt.image.buffereImage;
导入java.io.BufferedReader;
导入java.io.BufferedWriter;
导入java.io.File;
导入java.io.FileNotFoundException;
导入java.io.FileReader;
导入java.io.FileWriter;
导入java.io.IOException;
导入java.io.PrintWriter;
导入java.util.ArrayList;
导入java.util.Collections;
导入java.util.List;
导入java.util.Random;
导入javax.imageio.imageio;
导入javax.swing.JFrame;
导入javax.swing.JOptionPane;
导入javax.swing.Timer;
公共类GameGen扩展JFrame实现KeyListener{
私有静态最终长serialVersionUID=-7177541209377865450L;
Random rand=new Random();//映射的随机生成器
双移动=0;//移动图形生成
int timed=750;//移动延迟
int speed=2;//移动速度更快
int[][]世界=新int[10][100];//地图生成
int WIDTH=720;//框架/窗口的宽度
int HEIGHT=480;//框架/窗口的高度
字符串exitsg;//退出消息
字符串user;//用户名
int charX=0;//字符的起始坐标
int-charY=4;
BuffereImage img1;//图形生成
静态双倍得分=0;//玩家得分
GameGen(){//开始游戏
super(“Runner”);//设置帧规格
此.setSize(宽度、高度);
此.setLocationRelativeTo(空);
此项。未装饰的设置(正确);
此.setDefaultCloseOperation(在关闭时不执行任何操作);
此参数为.setresizeable(false);
此参数为.setFocusable(true);
此.setVisible(true);
//添加空格键侦听器
addKeyListener(此);
//开始世界新一代
worldGen();
//绘画世界
重新油漆();
//用于移动角色和背景的摆动计时器
计时器=新计时器(已计时,空);
timer.addActionListener(新ActionListener(){
已执行的公共无效操作(操作事件evt){
//增长速度
如果(速度<400){
速度=速度+5;
}
定时器。设置延迟(定时-速度);
//增加分数
分数=分数+3;
//移动字符
charX=charX+1;
//检查游戏是否结束
if(gameOverCollision()){
timer.stop();//结束“延迟循环”
}
//重力
//如果charY不在屏幕下方,以防止数组越界
if(charY<9){
如果(world[charY+1][charX]==0){//向下移动字符/重力
charY=charY+1;
deleter();//删除前面的字符坐标
mover();//移动数组上的字符坐标
}
}
deleter();//删除前面的字符坐标
mover();//移动数组上的字符坐标
}
});
timer.start();//启动“延迟循环”/swing timer
}
public void deleter(){//删除以前的字符坐标,因此屏幕上只有一个字符
对于(int x=0;x 6&&xAt 1&&xAt许多类似问题的类似建议:
- 在JPanel的
受保护的void paintComponent
方法中绘制,而不是在JFrame的绘制方法中绘制。默认情况下,这将提供双缓冲
- 切勿在绘图方法中读取文件或资源。此方法的速度是感知程序响应的最重要因素,您不应采取任何措施来降低速度。它应仅用于绘图和绘图
- 相反,将图像读入变量一次,然后从
paintComponent
中的变量中绘制图像
- 将背景图像绘制到BuffereImage,然后在paintComponent方法中绘制
双缓冲区图纸
在run()方法中,应该有如下内容--
好的,为了减少fliker--“jump”--你应该应用双缓冲技术。一种方法是让gameRender()绘制到它自己的图形对象中,它将代表与屏幕大小相同的图像
我的例子是:
// Global variables for off-screen rendering
private Graphics dbg;
private Image dbImage = null;
private void gameRender() {
/* Draw the current frame to an image buffer*/
if(dbImage == null) { // create the buffer
dbImage = createImage(PWIDTH, PHEIGHT);
if(dbImage == null ) {
System.out.println("dbImage is null");
return;
}
else
dbg = dbImage.getGraphics();
}
//clear the background
dbg.setColor(Color.white);
dbg.fillRect(0, 0, PWIDTH, PHEIGHT);
// Draws game elements
// ...
if(gameOver)
gameOverMessage(dbg);
} // end gameRender()
作为run()循环中repaint()请求的结果,dbImage被paintComponent()放置在屏幕上--(运行时)…gameUpdate()、Render()、repaint()。。
以下是将dbImage置于屏幕上的调用。此调用是在渲染步骤完成后进行的(上面的代码):
如果直接在屏幕上进行大范围绘图,则该过程可能需要足够长的时间才能被用户注意到。在paintComponent()中调用drawImage()的速度足够快,因此从一帧到下一帧的变化是即时的
油漆组件应保持简单
此外,我还将转换为活动渲染,因为对repaint()的调用只是一个请求,很难知道repaint()何时完成…这意味着动画线程中的睡眠时间(运行时)基本上是一个猜测..当我说睡眠时间时,我的意思是:
running = true;
while (running) {
gameUpdate(); // Game state is updated
gameRender(); // Render to a buffer
paintScreen(); // Note: Change from repaint() to paintScreen(),
// will explain later.
try {
Thread.sleep(20); // sleep a bit.. 20 ms to be exact.
} catch(InterruptedException ex){}
} // end of run()
应该有一个指定的睡眠时间,主要原因有三:1.它停止动画线程,从而释放CPU用于其他任务,如垃圾
public void paintComponent(Graphic g) {
super.paintComponent(g);
if (dbImage != null)
g.drawImage(dbImage, 0,0,null);
}
running = true;
while (running) {
gameUpdate(); // Game state is updated
gameRender(); // Render to a buffer
paintScreen(); // Note: Change from repaint() to paintScreen(),
// will explain later.
try {
Thread.sleep(20); // sleep a bit.. 20 ms to be exact.
} catch(InterruptedException ex){}
} // end of run()
running = true;
while (running) {
gameUpdate(); // Game state is updated
gameRender(); // Render to a buffer
paintScreen(); // Note: Change from repaint() to paintScreen(),
// will explain later.
try {
Thread.sleep(20); // sleep a bit.. 20 ms to be exact.
} catch(InterruptedException ex){}
System.exit(0);
/**
* Actively render the buffer image to screen
*/
private void paintScreen() {
Graphics g;
try {
g = this.getGraphics(); // get the panel's graphic context
if ((g != null) && (dbImage != null))
g.drawImage(dbImage, 0, 0, null);
Toolkit.getDefaultToolkit().sync(); // sync the display on some
// systems
g.dispose();
}
catch (Exception e) {
System.out.println("Graphics context error: " + e);
} // end catch
} // end paintScreen()
} // end of run()
private static final int MAX_FRAME_SKIPS = 5;
// number of frames that can be skipped in any one animation loop
// i.e the game state is updated but not rendered
private static final int NO_DELAYS_PER_YIELD = 16;
// number of frames with a delay of 0 ms before the animation
// thread yields to other running threads.
@Override
public void run() {
/* Repeatedly update, render, sleep so loop takes close
* to period nsecs. Sleep inaccuracies are handled.
* The timing calculation use the Java 3D timer.
*
* Overrruns in update/renders will cause extra updates
* to be carried out so UPS ~== requested FPS
*/
long beforeTime, afterTime, timeDiff, sleepTime;
long overSleepTime = 0L; // Number zero of type long (0L)
int noDelays = 0;
long excess = 0L;
beforeTime = J3DTimer.getValue();
running = true;
while (running) {
gameUpdate(); // Game state is updated
gameRender(); // Render to a buffer
paintScreen(); // Draw buffer to screen
afterTime = J3DTimer.getValue();
timeDiff = afterTime - beforeTime;
sleepTime = (period - timeDiff) - overSleepTime; // Time left in this
// loop
if (sleepTime > 0) { // Some time left in this cycle
try {
Thread.sleep(sleepTime/1000000L); // nano -> ms
} catch (InterruptedException ex) {}
overSleepTime =
(J3DTimer.getValue()-afterTime) - sleepTime;
}
else { // sleepTime <= 0; frame took longer than the period
excess -= sleepTime; // store excess time value
overSleepTime = 0L;
if (++noDelays >= NO_DELAYS_PER_YIELD) {
Thread.yield(); // Give another thread a chance to run
noDelays = 0; // New thread, no delays.
} // end inner if
} // end outer if
beforeTime = J3DTimer.getValue();
/* If frame animation is taking too long, update the game state
* without rendering it, to get the updates/sec bearer to required
* FPS
* */
int skips = 0;
while((excess > period) &&(skips < MAX_FRAME_SKIPS)) {
excess -= period;
gameUpdate(); // Update state, but don't render
skips++;
}
} // end while
System.exit(0); // So enclosing JApplet/JFrame exits
} // end of run()
/**
* Actively render the buffer image to screen
*/
private void paintScreen() {
Graphics g;
try {
g = this.getGraphics(); // get the panel's graphic context
if ((g != null) && (dbImage != null))
g.drawImage(dbImage, 0, 0, null);
Toolkit.getDefaultToolkit().sync(); // sync the display on some
// systems
g.dispose();
}
catch (Exception e) {
System.out.println("Graphics context error: " + e);
} // end catch
} // end paintScreen()