[英]Flicker on movement (Not using JPanel or Swing)
如果您的确是错的话,请原谅我,但我有点不高兴。 -我的计算机科学课上让我们从头开始制作了自己的游戏/程序,但是我们的老师特别忽略了挥杆的存在,并说这是他的境界来教球,所以从我的阅读中看来,好像一个游戏几乎就要用完了问题,到目前为止,我写的主要内容和调试信息在按键输入上剧烈闪烁。 有没有解决的办法?
我知道JPanel / JFrame / Swing可以解决此问题,但是我们还没有教过它,到目前为止,如果有人能够帮助我转换代码以使用它,那我将无所适从令人惊讶,因为我从解剖中学到的东西变得更容易。。这似乎有些不可靠,但这确实是最简单的学习方法。 到目前为止,我的代码是;
public class GameThing extends Applet implements KeyListener {
Image rightsprite, picture;
Image leftsprite, picture2;
Image spritedead, picture3;
Image background, picture4;
boolean left;
boolean dead;
boolean wall;
boolean menu;
int widthX, heightY;
int bgx, bgy;
String sr = " ";
char ch = '*';
Graphics bufferGraphics;
Image offscreen;
Dimension dim;
@Override
public void init() {
rightsprite = getImage(getDocumentBase(), "SpriteRight.png");
leftsprite = getImage(getDocumentBase(), "SpriteLeft.png");
spritedead = getImage(getDocumentBase(), "Sprite.png");
background = getImage(getDocumentBase(), "Background.png");
requestFocus();
addKeyListener(this);
left = false;
menu = true;
setSize(600, 380);
dim = getSize();
offscreen = createImage(dim.width, dim.height);
bufferGraphics = offscreen.getGraphics();
bgx = 0;
bgy = 0;
}
public void pause(final int delay) { // PAUSE COMMAND LIFTED FROM RAY
// waits a while
try {
Thread.sleep(delay);
} catch (InterruptedException e) {
return;
}
}
public GameThing() { // SPRITE INITIAL SPAWN LOCATION
widthX = 100;
heightY = 300;
}
@Override
public void paint(final Graphics g) { // DRAW MAIN CHARACTER SPRITE AND BACKGROUND
bufferGraphics.setColor(Color.black); // DRAW GROUND (REPLACE WITH BLOCKS SOON)
bufferGraphics.drawRect(0, 334, 500, 50);
bufferGraphics.setColor(Color.green);
bufferGraphics.fillRect(0, 335, 500, 50);
g.drawImage(offscreen, 0, 0, this);
if (menu == true) {
pause(500);
g.drawString("Side Scroller Test.", 180, 250);
pause(1500);
menu = false;
}
if (left == false) { // LEFT KEY MOVEMENT COMMANDS
g.drawImage(rightsprite, widthX, heightY, this);
g.drawString("Sprites Current X Location is: " + widthX, 20, 30);
g.drawString("Sprites Current Y Location is: " + heightY, 20, 50);
g.drawString("Background X location is: " + bgx, 20, 90);
g.drawString("Currently: " + sr, 20, 70);
}
if (left == true) { // RIGHT KEY MOVEMENT COMMANDS
g.drawImage(leftsprite, widthX, heightY, this);
g.drawString("Sprites Current X Location is: " + widthX, 20, 30);
g.drawString("Sprites Current Y Location is: " + heightY, 20, 50);
g.drawString("Background X location is: " + bgx, 20, 90);
g.drawString("Currently: " + sr, 20, 70);
}
if (dead == true) { // COMMANDS TO EXECUTE WHEN MAIN CHARACTER DIES
widthX = 506;
heightY = 314;
g.drawImage(spritedead, widthX, heightY, this);
pause(500);
g.setColor(Color.white);
g.drawRect(widthX, heightY, widthX, heightY);
g.fillRect(widthX, heightY, widthX, heightY);
pause(500);
widthX = 100;
heightY = 300;
bgx = 0;
left = true;
dead = false;
}
}
@Override
public void update(final Graphics g) { // KEEPS BACKGROUND STATIC
paint(g);
}
public void keyPressed(final KeyEvent e) {
sr = "blank!";
ch = '1';
if (e.getKeyCode() == 39) {
sr = "Moving Right!";
widthX = widthX + 7;
if (widthX <= 121) {
bgx = bgx;
} else {
bgx = bgx - 7;
}
left = false;
if ((widthX > 490) && (heightY > 300)) { // FALL DEATH
sr = "You Died!";
widthX = 900;
heightY = 900;
dead = true;
}
if (widthX == 499) {
heightY = heightY + 7;
}
}
if (widthX == 2) {
wall = true;
}
if (e.getKeyCode() == 37) {
if (wall == true) {
sr = "Wall!";
if (widthX > 2) {
wall = false;
}
}
if (wall == false) {
sr = "Moving Left!";
widthX = widthX - 7;
if (bgx >= 0) {
bgx = bgx;
} else {
bgx = bgx + 7;
}
left = true;
}
}
if (e.getKeyCode() == 38) {
sr = "Jumping!";
}
repaint();
}
public void keyTyped(final KeyEvent e) {
ch = e.getKeyChar();
repaint();
}
public void keyReleased(final KeyEvent e) {
} // key released
}
ps:使用向上键跳也是一个问题,我不能简单地添加到Y变量,然后减去它,因为它是如此之快,就好像它从未移动过。我没想到
我编辑了您的代码:
public class GameThing extends Applet {
// External resources
BufferedImage rightSprite, leftSprite, spriteDead, backgroundImg;
// Game data
int state = 1; //0 = left, 1 = right, 2 = dead
// Geometry
int locX = 100, locY = 300;
int bgX = 0, bgY = 0;
int groundX = 0, groundY = 334, groundW = 500, groundH = 50;
int appletW = 600, appletH = 480;
int wallW = 20, wallH = 40, wallX = 20, wallY = groundY - wallH;
final int STEP_SIZE = 7;
// Information
final String X_LOC_STR = "Sprites Current X Location is: ";
final String Y_LOC_STR = "Sprites Current Y Location is: ";
final String STATE_STR = "Currently: ";
final String X_BG_STR = "Background X location is: ";
String stateString = "";
// Double buffering
Image offscreen;
Graphics bufferGraphics;
Dimension dim;
// GUI components
Panel gamePanel;
Panel statusPanel = new Panel();
Label xLocLabel = new Label();
Label yLocLabel = new Label();
Label stateLabel = new Label();
Label xBGLocLabel = new Label();
@Override
public void init() {
// Load images
try {
rightSprite = ImageIO.read(new File(getClass().getResource("SpriteRIght.png").getPath()));
leftSprite = ImageIO.read(new File(getClass().getResource("SpriteLeft.png").getPath()));
spriteDead = ImageIO.read(new File(getClass().getResource("SpriteDead.png").getPath()));
backgroundImg = ImageIO.read(new File(getClass().getResource("Background.png").getPath()));
} catch (IOException e) {
e.printStackTrace();
}
// Set the panel that displays data
statusPanel.setLayout(new BoxLayout(statusPanel, BoxLayout.Y_AXIS));
statusPanel.add(xLocLabel);
statusPanel.add(yLocLabel);
statusPanel.add(stateLabel);
statusPanel.add(xBGLocLabel);
// Create the panel that draws the game and specify its behavior
gamePanel = new Panel() {
// Reduces flickering
@Override
public void update(Graphics g) {
paint(g);
}
// DRAW MAIN CHARACTER SPRITE AND BACKGROUND
@Override
public void paint(Graphics g) {
bufferGraphics.clearRect(0, 0, dim.width, dim.width);
bufferGraphics.drawImage(backgroundImg, bgX, bgY, this);
bufferGraphics.setColor(Color.BLACK); // DRAW GROUND (REPLACE WITH BLOCKS SOON)
bufferGraphics.drawRect(groundX, groundY, groundW, groundH);
bufferGraphics.setColor(Color.GREEN);
bufferGraphics.fillRect(groundX, groundY + 1, groundW, groundH);
bufferGraphics.setColor(Color.RED);
bufferGraphics.fillRect(wallX, wallY, wallW, wallH);
switch (state) {
case 0: bufferGraphics.drawImage(leftSprite, locX, locY, this);
break;
case 1: bufferGraphics.drawImage(rightSprite, locX, locY, this);
break;
case 2: bufferGraphics.drawImage(spriteDead, locX, locY, this);
// After death wait a bit and reset the game
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
pause(2000);
reset();
}
});
break;
}
g.drawImage(offscreen, 0, 0, this);
}
};
// Set the applet window
setLayout(new BorderLayout());
add(statusPanel, BorderLayout.PAGE_START);
add(gamePanel);
// Set double buffering
setSize(appletW, appletH);
dim = getSize();
offscreen = createImage(dim.width, dim.height);
bufferGraphics = offscreen.getGraphics();
// Set the panel that draws the game
gamePanel.addKeyListener(new Controls());
gamePanel.requestFocusInWindow();
updateLabels();
}
// PAUSE COMMAND LIFTED FROM RAY (who is Ray?)
// waits a while
public void pause(int delay) {
try {
Thread.sleep(delay);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
// Set to start parameters
public void reset() {
locX = 100; locY = 300;
bgX = 0;
state = 1;
gamePanel.repaint(); // These 2 lines automatically restart the game
updateLabels(); // Remove if you want to stay on the death screen until next press
}
public void updateLabels() {
xLocLabel.setText(X_LOC_STR + locX);
yLocLabel.setText(Y_LOC_STR + locY);
stateLabel.setText(STATE_STR + stateString);
xBGLocLabel.setText(X_BG_STR + bgX);
}
private class Controls extends KeyAdapter {
public void keyPressed(KeyEvent e) {
switch (e.getKeyCode()) {
case KeyEvent.VK_RIGHT:
stateString = "Moving Right!";
locX += STEP_SIZE;
state = 1;
if (locX > 121)
bgX -= STEP_SIZE;
// FALL DEATH
if ((locX > 490) && (locY > 300)) {
stateString = "You Died!";
state = 2;
}
// Start fall
if (locX == 499)
locY += STEP_SIZE;
// Check wall collision
if (locX >= wallX && locX <= wallX + wallW) {
locX -= STEP_SIZE;
stateString = "Wall!";
}
break;
case KeyEvent.VK_LEFT:
stateString = "Moving Left!";
locX -= STEP_SIZE;
state = 0;
if (bgX < 0)
bgX += STEP_SIZE;
// Check wall collision
if (locX >= wallX && locX <= wallX + wallW) {
locX += STEP_SIZE;
stateString = "Wall!";
}
break;
case KeyEvent.VK_UP:
// Implement jumping
stateString = "Jumping!";
break;
}
// Repaint the game panel and update the data panel
gamePanel.repaint();
updateLabels();
}
}
}
首先测试并了解更改 :
if else
替换switch
, VK_UP
37和这样的代替)。 final
。 Color.RED
而不是Color.red
)。 @Override
,即使编译器理解了它也是如此。 sleep
或昂贵的计算来阻塞事件分发线程(EDT)。 诸如paint
键事件之类的方法旨在快速执行。 我仅在EDT处理完所有排队事件后才使用invokeLater
暂停。 (我知道这个线程主题无处不在,只要忍受我吧)。 期待代码的当前状态(无新功能):
state
应该是一个enum
或接近它的东西,而不是随机数。 Shape
而不是指定其参数。 双缓冲实现说明:
您将在屏幕offscreen
创建一个屏幕offscreen
Image
对象,并在其上绘制一个Graphics
对象bufferGraphics
。 在paint
内部,您仅对 bufferGraphics
使用bufferGraphics
。 实际上,即使paint
属于gamePanel
(或任何其他对象及其paint
),您实际上还是在offscreen
paint
,这有些令人困惑。 当您在屏幕外完成绘制所有内容时,您可以使用g.drawImage(offscreen...)
将其全部放入屏幕,后者使用gamePanel
的Graphics
对象g
。
这个想法就像将所有东西都画在纸上然后放到相机的前面,而不是一点一点地在相机上画,或者类似的东西...
当前,屏幕外图像是整个applet的大小,而不仅仅是游戏面板的大小,但差别不大。
与Swing方法相关的差异:
JLabel
替换Label
,用JPanel
替换Panel
等。 JComponent
的setDoubleBuffered
和isDoubleBuffered
)。 删除所有这些屏幕外的恶作剧,并直接使用Graphics g
绘制。 也无需覆盖update
。 paint
是在paintComponent
完成的,而不是在paint
。 @ user1803551好的,一切都又回到了原来的样子。 -滚动的背景在其中(仅需要从您的帖子中进行一些调整),我知道最后一行“ gamePanel.repaint();”会刷新屏幕上的所有内容,因为背景需要更新每个按键输入,它不应该局限于代码中的微小方块,对吗?现在可以刷新整个屏幕,但是我认为这不是所需要的,因为它只会导致闪烁,底部的绿色矩形不会闪烁,所以我的假设是转换
g.drawImage(backgroundImg, bgx, bgy,this);
进入缓冲图形?
-编辑-将主Sprite和背景图像移到bufferGraphics中。 现在,闪烁几乎消失了,但是按住箭头键几秒钟后,屏幕将闪烁片刻,然后恢复正常。
public class GameTest extends Applet {
/**
*
*/
private static final long serialVersionUID = -1533028791433336859L;
Image rightsprite, leftsprite, spritedead, backgroundImg, offscreen;
boolean left = false, dead = false, wall = false, menu = true;
int locX = 100, locY = 300, width, height, bgx = 0, bgy = 0;
final int STEP_SIZE = 7;
final String X_LOC_STR= "Sprites Current X Location is: ";
final String Y_LOC_STR= "Sprites Current Y Location is: ";
final String STATE_STR= "Currently: ";
final String X_BG_STR= "Background X location is: ";
String sr = " ";
Graphics bufferGraphics;
Dimension dim;
Panel gamePanel;
Panel statusPanel = new Panel();
Label xLoc = new Label(X_LOC_STR);
Label yLoc = new Label(Y_LOC_STR);
Label state = new Label(STATE_STR);
Label xBGLoc = new Label(X_BG_STR);
public void init() {
try {
rightsprite = ImageIO.read(new File(getClass().getResource("SpriteRight.png").getPath()));
leftsprite = ImageIO.read(new File(getClass().getResource("SpriteLeft.png").getPath()));
spritedead = ImageIO.read(new File(getClass().getResource("SpriteDead.png").getPath()));
backgroundImg = ImageIO.read(new File(getClass().getResource("Background.png").getPath()));
} catch (IOException e) {
e.printStackTrace();
}
height = rightsprite.getHeight(this);
width = rightsprite.getWidth(this);
statusPanel.setLayout(new BoxLayout(statusPanel, BoxLayout.Y_AXIS));
statusPanel.add(xLoc);
statusPanel.add(yLoc);
statusPanel.add(state);
statusPanel.add(xBGLoc);
gamePanel = new Panel() {
/**
*
*/
private static final long serialVersionUID = 1L;
// DRAW MAIN CHARACTER SPRITE AND BACKGROUND
@Override
public void paint(Graphics g) {
bufferGraphics.drawImage(backgroundImg,bgx, bgy, this);
bufferGraphics.setColor(Color.black); // DRAW GROUND (REPLACE WITH BLOCKS SOON)
bufferGraphics.drawRect(0, 334, 500, 50);
bufferGraphics.setColor(Color.green);
bufferGraphics.fillRect(0, 335, 500, 50);
if (menu == true) {
pause(500);
g.drawString("Side Scroller Test.", 180, 250);
pause(1500);
menu = false;
}
// LEFT KEY MOVEMENT COMMANDS
if (left == false)
bufferGraphics.drawImage(rightsprite, locX, locY, this);
// RIGHT KEY MOVEMENT COMMANDS
else
bufferGraphics.drawImage(leftsprite, locX, locY, this);
// COMMANDS TO EXECUTE WHEN MAIN CHARACTER DIES
if (dead == true) {
locX = 506;
locY = 314;
bufferGraphics.drawImage(spritedead, locX, locY, this);
pause(500);
bufferGraphics.setColor(Color.white);
bufferGraphics.drawRect(locX, locY, width, height);
bufferGraphics.fillRect(locX, locY, width, height);
pause(500);
locX = 100;
locY = 300;
bgx = 0;
bgy = 0;
bufferGraphics.clearRect(locX, locY, width, height);
left = true;
dead = false;
}
g.drawImage(offscreen, 0, 0, this);
super.paint(g);
}
};
setLayout(new BorderLayout());
add(statusPanel, BorderLayout.PAGE_START);
add(gamePanel);
setSize(600, 480);
dim = getSize();
offscreen = createImage(dim.width, dim.height);
bufferGraphics = offscreen.getGraphics();
gamePanel.addKeyListener(new Controls());
gamePanel.requestFocusInWindow();
}
// waits a while
public void pause(int delay) {
try {
Thread.sleep(delay);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
private class Controls extends KeyAdapter {
public void keyPressed(KeyEvent e) {
sr = "blank!";
if (e.getKeyCode() == KeyEvent.VK_RIGHT) {
sr = "Moving Right!";
locX += STEP_SIZE;
if (locX > 121)
bgx = bgx - STEP_SIZE;
left = false;
// FALL DEATH
if ((locX > 490) && (locY > 300)) {
sr = "You Died!";
locX = 900;
locY = 900;
dead = true;
gamePanel.repaint();
}
if (locX == 499) {
locY += STEP_SIZE;
}
}
if (locX == 2) {
wall = true;
}
else if (e.getKeyCode() == KeyEvent.VK_LEFT) {
if (wall == true) {
sr = "Wall!";
if (locX > 2) {
wall = false;
}
}
else {
sr = "Moving Left!";
locX -= STEP_SIZE;
if (bgx < 0)
bgx += STEP_SIZE;
left = true;
}
}
if (e.getKeyCode() == KeyEvent.VK_UP) {
sr = "Jumping!";
}
xLoc.setText(X_LOC_STR + locX);
yLoc.setText(Y_LOC_STR + locY);
state.setText(STATE_STR + sr);
xBGLoc.setText(X_BG_STR + bgx);
gamePanel.repaint();
}
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.