Я создал игру, которая рисует изображения в JPanel. Это работает с JTimer, который выполняет каждые 14 миллисекунд для перемещения фона, перемещает препятствия и перемещает игрока (вертолет). Иногда я получаю мерцание фона и препятствий, и это не особенно гладко.
Есть ли способ, которым я могу обойти это? Нужно ли использовать потоки и анимировать в другом классе?
Я также использовал двойную буферизацию, но потом я обнаружил, что JPanels в любом случае имеет двойную буферизацию, поэтому я удалил ее.
Вот код из класса Panel.
class ImagePanel extends JPanel implements KeyListener, MouseListener,
MouseMotionListener {
/**
*
*/
private static final long serialVersionUID = -6096603231469523786L;
Plane o1 = new Plane();
Tank o2 = new Tank();
ArrayList<Plane> planeArray;
ArrayList<Tank> tankArray;
ArrayList<Missile> missileArray;
int bgx;
int bgxTwo;
int time;
int y;
int score;
int obsNum;
int obsNum2;
int planeSpeed;
int missileSpeed;
int count;
boolean holding;
boolean gameOver;
boolean startscreen;
boolean shooting;
boolean obsOne = false;
boolean obsTwo = false;
Color colorone = Color.WHITE;
Color colortwo = Color.WHITE;
Color restartColor = Color.white;
Color menuColor = Color.white;
Color bulletColor = Color.white;
Font f1;
Font f2;
Font f3;
String version = "Get To The Chopper Beta 1.2";
int level = 1;
java.util.Timer movementtimer;
TimerTask task;
java.util.Timer obstacletimer;
TimerTask taskTwo;
private Image image;
private Image imageTwo;
private Image chopper;
private Image chopper2;
private Image tank;
private Image plane;
private Image missile;
private Image explosion;
BufferedImage bufferedImage;
Graphics buffer;
java.net.URL bgurl;
java.net.URL curl;
java.net.URL c2url;
java.net.URL turl;
java.net.URL purl;
java.net.URL murl;
java.net.URL eurl;
// ///////// CONSTRUCTOR SETS NON-CHANGABLE VARIABLES ////////////////
public ImagePanel() {
setFocusable(true);
addKeyListener(this);
addMouseListener(this);
addMouseMotionListener(this);
f1 = new Font("Helvetica", Font.BOLD, 10);
f2 = new Font("Helvetica", Font.PLAIN, 30);
f3 = new Font("Helvetica", Font.PLAIN, 25);
startscreen = true;
getImages();
planeArray = new ArrayList<Plane>();
tankArray = new ArrayList<Tank>();
missileArray = new ArrayList<Missile>();
repaint();
}
public void getImages() {
bgurl = getClass().getResource("images/background.png");
switch (level) {
case (1):
bgurl = getClass().getResource("images/grassbackground.png");
bulletColor = Color.black;
break;
case (2):
bgurl = getClass().getResource("images/snowbackground.png");
bulletColor = Color.red;
break;
}
curl = getClass().getResource("images/heli.png");
c2url = getClass().getResource("images/heli2.png");
turl = getClass().getResource("images/tank.png");
purl = getClass().getResource("images/plane.png");
murl = getClass().getResource("images/missile.png");
eurl = getClass().getResource("images/explosion.png");
try {
image = Toolkit.getDefaultToolkit().getImage(bgurl);
imageTwo = Toolkit.getDefaultToolkit().getImage(bgurl);
chopper = Toolkit.getDefaultToolkit().getImage(curl);
chopper2 = Toolkit.getDefaultToolkit().getImage(c2url);
tank = Toolkit.getDefaultToolkit().getImage(turl);
plane = Toolkit.getDefaultToolkit().getImage(purl);
missile = Toolkit.getDefaultToolkit().getImage(murl);
explosion = Toolkit.getDefaultToolkit().getImage(eurl);
} catch (Exception ex) {
System.out.println("File Not Found");
}
}
// //////// SETS VARIABLES WHEN GAME IS STARTED OR RESTARTED
// //////////////////
public void startGame() {
bgx = 0;
bgxTwo = 800;
y = 50;
score = 0;
holding = false;
gameOver = false;
time = (int) (Math.random() * 500 + 500);
obsNum2 = 0;
shooting = false;
count = 1;
planeSpeed = -6;
missileSpeed = -7;
planeArray.clear();
tankArray.clear();
missileArray.clear();
colorone = Color.WHITE;
colortwo = Color.WHITE;
restartColor = Color.white;
menuColor = Color.white;
movementtimer = new java.util.Timer();
task = new TimerTask() {
public void run() {
moveImage();repaint();
}
};
movementtimer.schedule(task, 0, 13);
obstacletimer = new java.util.Timer();
taskTwo = new TimerTask() {
public void run() {
generateObstacle();
}
};
obstacletimer.schedule(taskTwo, 2000, time);
}
// ////////// COLLISION DETECTION //////////////////
public void moveImage() {
moveBackground();
addToScore();
if (holding) {
y += -3;
} else {
y += 3;
}
for (int i = 0; i < planeArray.size(); i++) {
Plane plane = planeArray.get(i);
if (y + 30 >= plane.yPos && y + 30 <= plane.yPos + 30
&& plane.xPos >= 200 && plane.xPos <= 250
|| y >= plane.yPos && y <= plane.yPos + 30
&& plane.xPos >= 200 && plane.xPos + 50 <= 250) {
gameOver = true;
System.out.println("Crash with plane!");
}
}
for (int i = 0; i < tankArray.size(); i++) {
Tank tank = tankArray.get(i);
if (y + 30 >= tank.yPos && y + 30 <= tank.yPos + 30
&& tank.xPos >= 200 && tank.xPos <= 250
|| y >= tank.yPos && y <= tank.yPos + 30
&& tank.xPos >= 200 && tank.xPos + 50 <= 250) {
gameOver = true;
System.out.println("Crash with a tank");
}
if (shooting) {
if (y + 30 >= tank.bulletYPos && y <= tank.bulletYPos
&& tank.bulletXPos >= 200 && tank.bulletXPos <= 250) {
gameOver = true;
System.out.println("Shot down");
}
}
}
for (int i = 0; i < missileArray.size(); i++) {
Missile missile = missileArray.get(i);
if (y + 30 >= missile.yPos && y + 30 <= missile.yPos + 30
&& missile.xPos >= 200 && missile.xPos <= 250
|| y >= missile.yPos && y <= missile.yPos + 30
&& missile.xPos >= 200 && missile.xPos + 50 <= 250) {
gameOver = true;
System.out.println("Crash with a missile");
}
}
if (y >= 300) {
gameOver = true;
} else if (y <= -15) {
gameOver = true;
}
}
// //////// MOVES BACKGROUND //////////////
public void moveBackground() {
bgx += -5;
if (bgx == -800) {
bgx = 800;
}
bgxTwo += -5;
if (bgxTwo == -800) {
bgxTwo = 800;
}
for (int i = 0; i < planeArray.size(); i++) {
Plane obs = planeArray.get(i);
obs.xPos = obs.xPos - 6;
}
for (int i = 0; i < tankArray.size(); i++) {
Tank obs = tankArray.get(i);
obs.xPos = obs.xPos - 5;
if (shooting) {
obs.bulletYPos = obs.bulletYPos - 2;
obs.bulletXPos = obs.bulletXPos - obs.angle;
}
}
for (int i = 0; i < missileArray.size(); i++) {
Missile obs = missileArray.get(i);
obs.xPos = obs.xPos - 7;
}
}
public void addToScore() {
score += 5;
increaseDiff();
}
public void increaseDiff() {
if (score == 10000) {
shooting = true;
for (int i = 0; i < tankArray.size(); i++) {
Tank tank = tankArray.get(i);
tank.bulletXPos = tank.xPos;
}
}
if (score > 5000 && score < 9999) {
time = (int) (Math.random() * 400 + 250);
planeSpeed = -7;
missileSpeed = -8;
} else if (score > 10000 && score < 14999) {
time = (int) (Math.random() * 400 + 150);
planeSpeed = -8;
missileSpeed = -10;
} else if (score > 15000 && score < 19999) {
time = (int) (Math.random() * 400 + 150);
planeSpeed = -9;
missileSpeed = -11;
obsNum2 = (int) (Math.random() * 2 + 1);
} else if (score > 20000 && score < 29999) {
time = (int) (Math.random() * 300 + 100);
planeSpeed = -10;
missileSpeed = -13;
obsNum2 = (int) (Math.random() * 2 + 1);
} else if (score > 30000) {
time = (int) (Math.random() * 300 + 100);
planeSpeed = -12;
missileSpeed = -15;
obsNum2 = (int) (Math.random() * 2 + 1);
}
}
public void generateObstacle() {
obsNum = (int) (Math.random() * 5 + 1);
if (obsNum == 1 || obsNum == 4 || obsNum2 == 1) {
planeArray.add(new Plane());
}
if (obsNum == 2) {
tankArray.add(new Tank());
}
if (obsNum == 3 || obsNum == 5 || obsNum2 == 2) {
missileArray.add(new Missile());
}
}
public void update(Graphics g) {
paint(g);
}
// /////////////// MAIN PAINT METHOD //////////////////////
@Override
public void paint(Graphics g) {
g.clearRect(0,0,800,400);
if (!startscreen) {
g.drawImage(image, bgx, 0, null);
g.drawImage(imageTwo, bgxTwo, 0, null);
for (int i = 0; i < planeArray.size(); i++) {
Plane obs = planeArray.get(i);
if (obs.xPos <= -50) {
planeArray.remove(i);
} else {
g.drawImage(plane, obs.xPos, obs.yPos, null);
}
}
for (int i = 0; i < tankArray.size(); i++) {
Tank obs = tankArray.get(i);
if (obs.xPos <= -50) {
tankArray.remove(i);
} else {
g.drawImage(tank, obs.xPos, obs.yPos, null);
if (shooting) {
g.setColor(bulletColor);
g.fillOval(obs.bulletXPos, obs.bulletYPos, 5,
5);
}
}
}
for (int i = 0; i < missileArray.size(); i++) {
Missile obs = missileArray.get(i);
if (obs.xPos <= -50) {
missileArray.remove(i);
} else {
g.drawImage(missile, obs.xPos, obs.yPos, null);
}
}
if (gameOver) {
movementtimer.cancel();
obstacletimer.cancel();
g.setColor(Color.WHITE);
g.setFont(f2);
g.drawString("GAME OVER", 250, 150);
g.setFont(f3);
g.drawString("Your score: " + score, 250, 200);
g.setColor(restartColor);
g.drawString("Click to restart!", 250, 250);
g.setColor(menuColor);
g.drawString("Back to menu", 250, 300);
g.drawImage(explosion, 200, y, this);
}
} else if (startscreen) {
g.drawImage(image, 0, 0, this);
g.drawImage(imageTwo, 0, 0, this);
g.drawImage(chopper, 200, 50, this);
g.setColor(Color.WHITE);
g.setFont(f2);
g.drawString("Choose a level:", 200, 150);
g.setFont(f3);
g.setColor(colorone);
g.drawString("Grass Level!", 250, 200);
g.setColor(colortwo);
g.drawString("Snow Level!", 250, 250);
}
if (count <= 9 && !gameOver && !startscreen) {
g.drawImage(chopper, 200, y, this);
count++;
} else if (count >= 10 && count < 20 && !gameOver && !startscreen) {
g.drawImage(chopper2, 200, y, this);
count++;
} else if (count == 20 && !gameOver && !startscreen) {
count = 1;
g.drawImage(chopper, 200, y, this);
}
g.setFont(f1);
g.setColor(Color.WHITE);
g.drawString(version, 10, 10);
g.drawString("Score: " + score + "", 700, 10);
}
// ///////////////////OVERRIDE KEYPRESSED EVENTS//////////////////////
@Override
public void keyPressed(KeyEvent e) {
// TODO Auto-generated method stub
if (e.getKeyCode() == 32) {
holding = true;
repaint();
}
}
@Override
public void keyReleased(KeyEvent e) {
// TODO Auto-generated method stub
if (e.getKeyCode() == 32) {
holding = false;
repaint();
}
}
@Override
public void keyTyped(KeyEvent e) {
// TODO Auto-generated method stub
}
public void mousePressed(MouseEvent e) {
if (e.getX() >= 250 && e.getX() <= 400 && e.getY() >= 180
&& e.getY() <= 200 && startscreen) {
startscreen = false;
level = 1;
getImages();
startGame();
}
if (e.getX() >= 250 && e.getX() <= 400 && e.getY() >= 230
&& e.getY() <= 250 && startscreen) {
startscreen = false;
level = 2;
getImages();
startGame();
}
if (e.getX() >= 250 && e.getX() <= 420 && e.getY() >= 230
&& e.getY() <= 250 && gameOver) {
startGame();
}
if (e.getX() >= 250 && e.getX() <= 420 && e.getY() >= 280
&& e.getY() <= 320 && gameOver) {
gameOver = false;
startscreen = true;
repaint();
}
}
@Override
public void mouseClicked(MouseEvent arg0) {
// TODO Auto-generated method stub
}
@Override
public void mouseEntered(MouseEvent e) {
// TODO Auto-generated method stub
}
public void mouseMoved(MouseEvent e) {
if (e.getX() >= 250 && e.getX() <= 400 && e.getY() >= 180
&& e.getY() <= 200 && startscreen) {
colorone = Color.RED;
repaint();
} else if (e.getX() >= 250 && e.getX() <= 400 && e.getY() >= 230
&& e.getY() <= 250 && startscreen) {
colortwo = Color.RED;
repaint();
} else if (startscreen) {
colorone = Color.white;
colortwo = Color.white;
repaint();
}
if (e.getX() >= 250 && e.getX() <= 420 && e.getY() >= 230
&& e.getY() <= 250 && gameOver) {
restartColor = Color.red;
repaint();
} else if (e.getX() >= 250 && e.getX() <= 420 && e.getY() >= 280
&& e.getY() <= 320 && gameOver) {
menuColor = Color.red;
repaint();
} else if (gameOver) {
restartColor = Color.white;
menuColor = Color.white;
repaint();
}
}
@Override
public void mouseExited(MouseEvent arg0) {
// TODO Auto-generated method stub
}
@Override
public void mouseReleased(MouseEvent arg0) {
// TODO Auto-generated method stub
}
@Override
public void mouseDragged(MouseEvent arg0) {
// TODO Auto-generated method stub
}
}
Извините за весь код, как вы можете сказать, я новичок в Java и программировании в целом (начал в прошлом году в колледже), но я хочу развиваться и делать карьеру.
Спасибо
Том