物体不能正确移动
Objects don't move correctly
我目前正在编写一款游戏,您必须躲避障碍物才能到达目标。根据玩家选择的难度,有许多障碍物以随机角度沿直线移动。如果它们到达屏幕边界,它们会在随机生成点重生(有三个,也是随机创建的)。当你玩一轮时出生点应该保持静止,并在你开始下一轮时在不同的地方重新创建。
如果我现在开始游戏,生成点会随着障碍物一起移动,这些障碍物在同一生成点生成时会分组并使用组合移动矢量。
现在我将列出对确定我的问题很重要的 类:
游戏面板(大部分游戏发生在这里):
public class GamePanel extends JPanel
{
private JFrame fenster; //Frame for the game
private final Dimension prefSize=new Dimension(1180, 780); //preferred dimension
private boolean gameOver=false,roundWin=false; //booleans for round win and game over
private Timer t; //Timer
private int c=0,p=0; //counter and points
private int[][] max; //highscore Array
private Player player=null; //playable game object
private Goal goal=null; //the goal to end the round and earn points
private int schwer=2; //difficulty
private Obstacle[] obstacles; //obstacles to avoid
private Spawn spawn0,spawn1,spawn2; //spawn points 1,2 and 3
private Coordinate cSpawn0,cSpawn1,cSpawn2; //coordinates for the spawn points
public GamePanel()
{
fenster = new JFrame();
fenster.setTitle("Faster Course");
fenster.setLocation(50,50);
fenster.setResizable(false);
fenster.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
fenster.setVisible(true);
fenster.setPreferredSize(prefSize);
fenster.setSize(prefSize.width,prefSize.height);
//fenster is specified
JMenuBar Menü = new JMenuBar();
JMenu file = new JMenu("File");
JMenu game = new JMenu("Game");
JMenu pref = new JMenu("Preferences");
fenster.setJMenuBar(Menü);
Menü.add(file);
Menü.add(game);
Menü.add(pref);
//Menu for fenster is 'made'
JMenuItem quit = new JMenuItem("Close");
file.add(quit);
quit.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
System.exit(0); //if this button is clicked, the game exits
}
});
JMenuItem diff = new JMenuItem("Difficulty");
pref.add(diff);
diff.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
JFrame Schwierigkeit = new JFrame();
Schwierigkeit.setLayout(null);
Schwierigkeit.setTitle("Difficulty");
Schwierigkeit.setLocation(200,200);
Schwierigkeit.setVisible(true);
Schwierigkeit.setSize(30,275);
Schwierigkeit.setResizable(false);
JButton kLeicht=new JButton("Easy");
kLeicht.setBounds(20,10,90,25);
JButton kNormal=new JButton("Normal");
kNormal.setBounds(20,50,90,25);
JButton kSchwer=new JButton("Hard");
kSchwer.setBounds(20,90,90,25);
JButton kProfi=new JButton("Pro");
kProfi.setBounds(20,130,90,25);
JButton kAlbtraum=new JButton("Nightmare");
kAlbtraum.setBounds(20,170,90,25);
JButton kQual=new JButton("Torture");
kQual.setBounds(20,210,90,25);
Schwierigkeit.add(kLeicht);
kLeicht.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
Schwierigkeit.dispose();
changeDiff(1);
}
});
Schwierigkeit.add(kNormal);
kNormal.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
Schwierigkeit.dispose();
changeDiff(2);
}
});
Schwierigkeit.add(kSchwer);
kSchwer.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
Schwierigkeit.dispose();
changeDiff(3);
}
});
Schwierigkeit.add(kProfi);
kProfi.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
Schwierigkeit.dispose();
changeDiff(4);
}
});
Schwierigkeit.add(kAlbtraum);
kAlbtraum.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
Schwierigkeit.dispose();
changeDiff(5);
}
});
Schwierigkeit.add(kQual);
kQual.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
Schwierigkeit.dispose();
changeDiff(6);
}
});
}
}); //if difficulty is clicked, a window to choose the difficulty is opened
//if a difficulty is chosen, the difficulty may be changed
JMenuItem pause=new JMenuItem("Pause");
game.add(pause);
JMenuItem resume=new JMenuItem("Resume");
game.add(resume);
pause.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
pause.setEnabled(false);
resume.setEnabled(true); //if pause is clicked, the game is paused and pause
pauseGame(); //cannot be clicked anymore but resume now can be
}
});
resume.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
pause.setEnabled(true);
resume.setEnabled(false); //if resume is clicked, the game continues and resume
resumeGame(); //cannot be clicked anymore but pause now can be
}
});
max=new int[5][3];
//highscores: 5 scores with each points[x][0], rounds[x][1] and difficulty[x][2]
fenster.add(this);
fenster.setVisible(true); //now all is placed onto the JFrame
initGame(); //all objects are initialized
startGame(); //the game starts
}
public boolean isGameOver()
{
return gameOver;
}
public void setGameOver(boolean gameOver)
{
this.gameOver=gameOver;
}
public boolean isRoundWin()
{
return roundWin;
}
public void setRoundWin(boolean roundWin)
{
this.roundWin=roundWin;
}
public String schwerMax(int i) //to return the words for the difficulty numbers
{
if(i==1)
{
return "Easy";
}
else if(i==2)
{
return "Normal";
}
else if(i==3)
{
return "Hard";
}
else if(i==4)
{
return "Pro";
}
else if(i==5)
{
return "Nightmare";
}
else if(i==6)
{
return "Torture";
}
return "-";
}
private void initGame ()
{
createGameObjects();
fenster.addKeyListener(new KeyAdapter() //controls and hotkeys
{
@Override
public void keyReleased(KeyEvent e)
{
switch(e.getKeyCode())
{
case KeyEvent.VK_A:
case KeyEvent.VK_LEFT:
player.setAngleLeft(false);
break;
case KeyEvent.VK_D:
case KeyEvent.VK_RIGHT:
player.setAngleRight(false);
case KeyEvent.VK_W:
case KeyEvent.VK_UP:
player.setAcc(false);
break;
case KeyEvent.VK_S:
case KeyEvent.VK_DOWN:
player.setDec(false);
break;
}
}
@Override
public void keyPressed(KeyEvent e)
{
switch(e.getKeyCode())
{
case KeyEvent.VK_A:
case KeyEvent.VK_LEFT:
player.setAngleLeft(true);
break;
case KeyEvent.VK_D:
case KeyEvent.VK_RIGHT:
player.setAngleRight(true);
break;
case KeyEvent.VK_W:
case KeyEvent.VK_UP:
player.setAcc(true);
break;
case KeyEvent.VK_S:
case KeyEvent.VK_DOWN:
if(player.getMovingDistance()>0)
{
player.setDec(true);
}
else
{
player.setDec(false);
player.setMovingDistance(-1);
}
break;
case KeyEvent.VK_ESCAPE:
if(isGameOver()||isRoundWin())
{
fenster.dispose();
}
if(t.isRunning())
{
pauseGame();
}
else if(!isGameOver())
{
resumeGame();
}
break;
case KeyEvent.VK_E:
endGame();
break;
case KeyEvent.VK_ENTER:
if(isGameOver())
{
restartGame();
}
else if(isRoundWin())
{
continueGame();
}
break;
case KeyEvent.VK_1:
changeDiff(1);
break;
case KeyEvent.VK_2:
changeDiff(2);
break;
case KeyEvent.VK_3:
changeDiff(3);
break;
case KeyEvent.VK_4:
changeDiff(4);
break;
case KeyEvent.VK_5:
changeDiff(5);
break;
case KeyEvent.VK_6:
changeDiff(6);
break;
}
}
});
t=new Timer(20, new ActionListener() //timer to control the ticks
{
@Override
public void actionPerformed(ActionEvent e)
{
doOnTick();
}
});
}
public void changeDiff(int schwer)
{
Object[] restart={"OK","No"}; //game has to be restarted to change the difficulty
int chosenRestart=JOptionPane.showOptionDialog(fenster,"In order to change the difficulty, the game has to be restarted.\nDo you really want to change the difficulty?","Warning!",JOptionPane.YES_NO_OPTION,JOptionPane.QUESTION_MESSAGE,null,restart,restart[0]);
if(chosenRestart==0) //if yes is chosen, the difficulty will change and the game restarts
{
this.schwer=schwer;
restartGame();
}
}
private void createGameObjects()
{
if(player==null) //if there is no player, there will be a new one
{
player=new Player(new Coordinate(900,150),20,Math.toRadians(180),5);
}
if(goal==null) //if there is no goal, there will be a new one
{
goal=new Goal(new Coordinate(prefSize.width-200,100),80,80);
}
initPlayer(); //player is initialized
initSpawns(); //spawns are initialized
obstacles=new Obstacle[schwer];
initObstacles(); //objects are initialized
}
private void initPlayer() //player is initialized
{
player.setObjectPosition(new Coordinate(40,700));
player.setMovingAngle(Math.toRadians(-90));
}
public void initObstacles() //objects are initialized
{
for(int i=0;i<obstacles.length;i++)
{
obstacles[i]=new Obstacle(new Coordinate(90,150),70,70,5);
obstacles[i].setMovingDistance(schwer*2+c);
obstacleSpawn(i);
}
}
public void obstacleSpawn(int i) //objects spawn at a random spawn
{
double zufall=Math.random();
if(zufall<=0.33)
{
obstacles[i].spawn(cSpawn0);
}
else if(zufall<=0.67)
{
obstacles[i].spawn(cSpawn1);
}
else
{
obstacles[i].spawn(cSpawn2);
}
}
public void initSpawns() //spawns are initialized
{
cSpawn0=new Coordinate((Math.random()*prefSize.width-200)+100,(Math.random()*prefSize.height-200)+100);
cSpawn1=new Coordinate((Math.random()*prefSize.width-200)+100,(Math.random()*prefSize.height-200)+100);
cSpawn2=new Coordinate((Math.random()*prefSize.width-200)+100,(Math.random()*prefSize.height-200)+100);
spawn0=new Spawn();
spawn1=new Spawn();
spawn2=new Spawn();
}
private void startGame() //timer starts
{
t.start();
}
public void pauseGame() //timer stops
{
t.stop();
}
public void resumeGame() //if game is not over, timer starts again
{
if(!isGameOver())
{
t.start();
}
}
public void continueGame() //if the current round is won, a new one will start
{
if(isRoundWin())
{
setRoundWin(false);
player.setMovingDistance(5);
createGameObjects();
startGame();
}
}
public void restartGame() //if a round is lost, a new game will start
{
setGameOver(false);
setRoundWin(false);
c=0;
p=0;
player.setMovingDistance(5);
createGameObjects();
startGame();
}
private void endGame() //game is set to be over
{
setGameOver(true);
pauseGame();
}
private void doOnTick() //every tick (controlled by the timer), this will happen:
{
if(player.getObjectPosition().getX() <=0||player.getObjectPosition().getX()>=prefSize.width||player.getObjectPosition().getY()<=0||player.getObjectPosition().getY()>=prefSize.height)
{
endGame();
}
//if a player leaves the window, the game is over
for(int i=0;i<schwer;i++)
{
if(obstacles[i].getObjectPosition().getX() <=0||obstacles[i].getObjectPosition().getX()>=prefSize.width||obstacles[i].getObjectPosition().getY()<=0||obstacles[i].getObjectPosition().getY()>=prefSize.height)
{
obstacleSpawn(i);
}
//if an obstacle leaves the window, it will respawn
if(player.touches(obstacles[i])||obstacles[i].touches(player))
{
endGame();
}
//if the player touches an obstacle, the game is over
}
if(player.touches(goal)||goal.touches(player))
{
setRoundWin(true);
pauseGame();
c=c+1;
p=(int)(p+(player.getMovingDistance()*schwer));
}
//if the player touches the goal, the round is won and the new scores for round and points are
//calculated
player.makeMove(); //the player is moved
for(int i=0;i<schwer;i++)
{
obstacles[i].makeMove();
}
//all obstacles are moved
repaint(); //the game is repainted
}
@Override
public void paintComponent(Graphics g)
{
super.paintComponent(g); //everything of the original paintComponent is done
Graphics2D g2d = (Graphics2D) g; //g2d is g
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
//antialiasing is turned on -> Kantenglättung
setBackground(Color.GRAY); //background is gray
player.paintMe(g); //player is painted
for(int i=0;i<schwer;i++)
{
obstacles[i].paintMe(g);
}
//all obstacles are painted
spawn0.paintMe(g,cSpawn0);
spawn1.paintMe(g,cSpawn1);
spawn2.paintMe(g,cSpawn2);
//all spawns are painted
goal.paintMe(g); //goal is painted
g.setFont(new Font(Font.SANS_SERIF,Font.BOLD,30));
g.setColor(Color.BLUE);
g.drawString("Rounds: "+c,prefSize.width-200,30);
g.setColor(Color.RED);
g.drawString("Points: "+p,30,30);
//rounds and points GUI are painted
if(isGameOver())
{
for(int i=0;i<max.length;i++)
{
if(p>=max[i][0])
{
for(int j=max.length-1;j>i+1;j--)
{
max[j][0]=max[j-1][0];
max[j][1]=max[j-1][1];
max[j][2]=max[j-1][2];
}
max[i][0]=p;
max[i][1]=c;
max[i][2]=schwer;
break;
}
}
//if the game is lost, all highscores are sized
g.setFont(new Font(Font.SANS_SERIF,Font.BOLD,50));
g.setColor(Color.RED);
g.drawString("GAME OVER!",prefSize.width/2-170,prefSize.height/5);
//the "GAME OVER!" is painted on the screen ...
g.setFont(new Font(Font.SANS_SERIF,Font.BOLD,20));
g.setColor(Color.ORANGE);
g.drawString("Highscores",prefSize.width/2-100,prefSize.height/4);
for(int i=0;i<max.length;i++)
{
g.drawString(max[i][0]+" Points",200,300+30*i);
g.drawString(max[i][1]+" Rounds",500,300+30*i);
g.drawString(schwerMax(max[i][2]),700,300+30*i);
}
//... and all the highscores
}
if(isRoundWin())
{
g.setFont(new Font(Font.SANS_SERIF,Font.BOLD,50));
g.setColor(Color.BLUE);
g.drawString("ROUND WON!",prefSize.width/2-130,prefSize.height/5);
} //if the round is won, this is painted on the screen
}
}
抽象 Class 游戏对象(玩家、障碍物和球门是游戏对象;我已经为生成物尝试了一些不同的东西):
public abstract class GameObject
{
private Coordinate objectPosition;
private double width;
private double height;
private double movingAngle;
private double movingDistance;
public GameObject(Coordinate objectPosition,double width,double height)
{
this.objectPosition=objectPosition;
this.width=width;
this.height=height;
movingAngle=0;
movingDistance=0;
}
public Coordinate getObjectPosition()
{
return objectPosition;
}
public void setObjectPosition(Coordinate objectPosition)
{
this.objectPosition=objectPosition;
}
public double getWidth()
{
return width;
}
public void setWidth(double width)
{
this.width=width;
}
public double getHeight()
{
return height;
}
public void setHeight(double height)
{
this.height=height;
}
public double getMovingAngle()
{
return movingAngle;
}
public void setMovingAngle(double movingAngle)
{
this.movingAngle=movingAngle;
}
public double getMovingDistance()
{
return movingDistance;
}
public void setMovingDistance(double movingDistance)
{
this.movingDistance=movingDistance;
}
public boolean isLeftOf(GameObject that)
{
return this.getObjectPosition().getX()+this.getWidth()<that.getObjectPosition().getX();
}
public boolean isAbove(GameObject that)
{
return this.getObjectPosition().getY()+this.getHeight()<that.getObjectPosition().getY();
}
public boolean touches(GameObject that)
{
if(this.isLeftOf(that)) return false;
if(that.isLeftOf(this)) return false;
if(this.isAbove(that)) return false;
if(that.isAbove(this)) return false;
return true;
}
public static Coordinate polarToCartesianCoordinates(double angle)
{
double x=Math.cos(angle);
double y=Math.sin(angle);
return new Coordinate(x,y);
}
public void moveGameObject()
{
Coordinate direction=polarToCartesianCoordinates(movingAngle);
objectPosition.setX(objectPosition.getX()+direction.getX()*movingDistance);
objectPosition.setY(objectPosition.getY()+direction.getY()*movingDistance);
}
public void makeMove()
{
moveGameObject();
}
protected abstract void paintMe(Graphics g);
}
障碍:
public class Obstacle extends GameObject
{
private Shape transformedObstacle=new RoundRectangle2D.Double();
public Obstacle(Coordinate position,double size,double MovingAngle,double MovingDistance)
{
super(position,size,size/3);
this.setMovingAngle(MovingAngle);
this.setMovingDistance(MovingDistance);
}
public Shape getTransformedObstacle()
{
return transformedObstacle;
}
public void setTransformedObstacle(Shape transformedObstacle)
{
this.transformedObstacle=transformedObstacle;
}
public void spawn(Coordinate spawn)
{
this.setObjectPosition(spawn);
this.setMovingAngle(Math.toRadians(Math.random()*360));
}
public void paintMe(java.awt.Graphics g)
{
Graphics2D g2d=(Graphics2D) g;
this.paintComponent(g2d);
}
public void paintComponent(Graphics2D g2d)
{
RoundRectangle2D quader=new RoundRectangle2D.Double(this.getObjectPosition().getX(),this.getObjectPosition().getY(),this.getWidth(),this.getHeight(),5,5);
g2d.setColor(Color.GREEN);
AffineTransform transform=new AffineTransform();
transform.rotate(this.getMovingAngle(),quader.getCenterX(),quader.getCenterY());
Shape transformed=transform.createTransformedShape(quader);
g2d.fill(transformed);
setTransformedObstacle(transformed);
}
}
重生:
public class Spawn
{
public void paintMe(java.awt.Graphics g,Coordinate position)
{
Graphics2D g2d=(Graphics2D) g;
paintSpawn(g2d,position);
}
public void paintSpawn(Graphics2D g2d,Coordinate position)
{
RoundRectangle2D spawn=new RoundRectangle2D.Double(position.getX(),position.getY(),50,50,100,100);
g2d.setColor(Color.DARK_GRAY);
g2d.fill(spawn);
}
}
这是一个关于组合障碍物和移动重生点的视频:https://youtu.be/N8Rq3yKblXk
我知道,这是很多代码,但我希望有人能帮我找到问题所在。
.
干杯
林德亚龙
您将 spawn0
(Coordinate
) 的引用传递给 Obstacle
,然后在 Obstacle
移动时更新,所以现在 Obstacle
和 spawn0
位置相同,所以一起移动
Spawn
应该用它自己的位置构建(这不应该然后共享),Spawn
然后应该负责 Obstacle
的生命周期并产生新的 Obstacle
根据需要(并删除旧的)
我目前正在编写一款游戏,您必须躲避障碍物才能到达目标。根据玩家选择的难度,有许多障碍物以随机角度沿直线移动。如果它们到达屏幕边界,它们会在随机生成点重生(有三个,也是随机创建的)。当你玩一轮时出生点应该保持静止,并在你开始下一轮时在不同的地方重新创建。
如果我现在开始游戏,生成点会随着障碍物一起移动,这些障碍物在同一生成点生成时会分组并使用组合移动矢量。
现在我将列出对确定我的问题很重要的 类:
游戏面板(大部分游戏发生在这里):
public class GamePanel extends JPanel { private JFrame fenster; //Frame for the game private final Dimension prefSize=new Dimension(1180, 780); //preferred dimension private boolean gameOver=false,roundWin=false; //booleans for round win and game over private Timer t; //Timer private int c=0,p=0; //counter and points private int[][] max; //highscore Array private Player player=null; //playable game object private Goal goal=null; //the goal to end the round and earn points private int schwer=2; //difficulty private Obstacle[] obstacles; //obstacles to avoid private Spawn spawn0,spawn1,spawn2; //spawn points 1,2 and 3 private Coordinate cSpawn0,cSpawn1,cSpawn2; //coordinates for the spawn points public GamePanel() { fenster = new JFrame(); fenster.setTitle("Faster Course"); fenster.setLocation(50,50); fenster.setResizable(false); fenster.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); fenster.setVisible(true); fenster.setPreferredSize(prefSize); fenster.setSize(prefSize.width,prefSize.height); //fenster is specified JMenuBar Menü = new JMenuBar(); JMenu file = new JMenu("File"); JMenu game = new JMenu("Game"); JMenu pref = new JMenu("Preferences"); fenster.setJMenuBar(Menü); Menü.add(file); Menü.add(game); Menü.add(pref); //Menu for fenster is 'made' JMenuItem quit = new JMenuItem("Close"); file.add(quit); quit.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { System.exit(0); //if this button is clicked, the game exits } }); JMenuItem diff = new JMenuItem("Difficulty"); pref.add(diff); diff.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { JFrame Schwierigkeit = new JFrame(); Schwierigkeit.setLayout(null); Schwierigkeit.setTitle("Difficulty"); Schwierigkeit.setLocation(200,200); Schwierigkeit.setVisible(true); Schwierigkeit.setSize(30,275); Schwierigkeit.setResizable(false); JButton kLeicht=new JButton("Easy"); kLeicht.setBounds(20,10,90,25); JButton kNormal=new JButton("Normal"); kNormal.setBounds(20,50,90,25); JButton kSchwer=new JButton("Hard"); kSchwer.setBounds(20,90,90,25); JButton kProfi=new JButton("Pro"); kProfi.setBounds(20,130,90,25); JButton kAlbtraum=new JButton("Nightmare"); kAlbtraum.setBounds(20,170,90,25); JButton kQual=new JButton("Torture"); kQual.setBounds(20,210,90,25); Schwierigkeit.add(kLeicht); kLeicht.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { Schwierigkeit.dispose(); changeDiff(1); } }); Schwierigkeit.add(kNormal); kNormal.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { Schwierigkeit.dispose(); changeDiff(2); } }); Schwierigkeit.add(kSchwer); kSchwer.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { Schwierigkeit.dispose(); changeDiff(3); } }); Schwierigkeit.add(kProfi); kProfi.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { Schwierigkeit.dispose(); changeDiff(4); } }); Schwierigkeit.add(kAlbtraum); kAlbtraum.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { Schwierigkeit.dispose(); changeDiff(5); } }); Schwierigkeit.add(kQual); kQual.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { Schwierigkeit.dispose(); changeDiff(6); } }); } }); //if difficulty is clicked, a window to choose the difficulty is opened //if a difficulty is chosen, the difficulty may be changed JMenuItem pause=new JMenuItem("Pause"); game.add(pause); JMenuItem resume=new JMenuItem("Resume"); game.add(resume); pause.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { pause.setEnabled(false); resume.setEnabled(true); //if pause is clicked, the game is paused and pause pauseGame(); //cannot be clicked anymore but resume now can be } }); resume.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { pause.setEnabled(true); resume.setEnabled(false); //if resume is clicked, the game continues and resume resumeGame(); //cannot be clicked anymore but pause now can be } }); max=new int[5][3]; //highscores: 5 scores with each points[x][0], rounds[x][1] and difficulty[x][2] fenster.add(this); fenster.setVisible(true); //now all is placed onto the JFrame initGame(); //all objects are initialized startGame(); //the game starts } public boolean isGameOver() { return gameOver; } public void setGameOver(boolean gameOver) { this.gameOver=gameOver; } public boolean isRoundWin() { return roundWin; } public void setRoundWin(boolean roundWin) { this.roundWin=roundWin; } public String schwerMax(int i) //to return the words for the difficulty numbers { if(i==1) { return "Easy"; } else if(i==2) { return "Normal"; } else if(i==3) { return "Hard"; } else if(i==4) { return "Pro"; } else if(i==5) { return "Nightmare"; } else if(i==6) { return "Torture"; } return "-"; } private void initGame () { createGameObjects(); fenster.addKeyListener(new KeyAdapter() //controls and hotkeys { @Override public void keyReleased(KeyEvent e) { switch(e.getKeyCode()) { case KeyEvent.VK_A: case KeyEvent.VK_LEFT: player.setAngleLeft(false); break; case KeyEvent.VK_D: case KeyEvent.VK_RIGHT: player.setAngleRight(false); case KeyEvent.VK_W: case KeyEvent.VK_UP: player.setAcc(false); break; case KeyEvent.VK_S: case KeyEvent.VK_DOWN: player.setDec(false); break; } } @Override public void keyPressed(KeyEvent e) { switch(e.getKeyCode()) { case KeyEvent.VK_A: case KeyEvent.VK_LEFT: player.setAngleLeft(true); break; case KeyEvent.VK_D: case KeyEvent.VK_RIGHT: player.setAngleRight(true); break; case KeyEvent.VK_W: case KeyEvent.VK_UP: player.setAcc(true); break; case KeyEvent.VK_S: case KeyEvent.VK_DOWN: if(player.getMovingDistance()>0) { player.setDec(true); } else { player.setDec(false); player.setMovingDistance(-1); } break; case KeyEvent.VK_ESCAPE: if(isGameOver()||isRoundWin()) { fenster.dispose(); } if(t.isRunning()) { pauseGame(); } else if(!isGameOver()) { resumeGame(); } break; case KeyEvent.VK_E: endGame(); break; case KeyEvent.VK_ENTER: if(isGameOver()) { restartGame(); } else if(isRoundWin()) { continueGame(); } break; case KeyEvent.VK_1: changeDiff(1); break; case KeyEvent.VK_2: changeDiff(2); break; case KeyEvent.VK_3: changeDiff(3); break; case KeyEvent.VK_4: changeDiff(4); break; case KeyEvent.VK_5: changeDiff(5); break; case KeyEvent.VK_6: changeDiff(6); break; } } }); t=new Timer(20, new ActionListener() //timer to control the ticks { @Override public void actionPerformed(ActionEvent e) { doOnTick(); } }); } public void changeDiff(int schwer) { Object[] restart={"OK","No"}; //game has to be restarted to change the difficulty int chosenRestart=JOptionPane.showOptionDialog(fenster,"In order to change the difficulty, the game has to be restarted.\nDo you really want to change the difficulty?","Warning!",JOptionPane.YES_NO_OPTION,JOptionPane.QUESTION_MESSAGE,null,restart,restart[0]); if(chosenRestart==0) //if yes is chosen, the difficulty will change and the game restarts { this.schwer=schwer; restartGame(); } } private void createGameObjects() { if(player==null) //if there is no player, there will be a new one { player=new Player(new Coordinate(900,150),20,Math.toRadians(180),5); } if(goal==null) //if there is no goal, there will be a new one { goal=new Goal(new Coordinate(prefSize.width-200,100),80,80); } initPlayer(); //player is initialized initSpawns(); //spawns are initialized obstacles=new Obstacle[schwer]; initObstacles(); //objects are initialized } private void initPlayer() //player is initialized { player.setObjectPosition(new Coordinate(40,700)); player.setMovingAngle(Math.toRadians(-90)); } public void initObstacles() //objects are initialized { for(int i=0;i<obstacles.length;i++) { obstacles[i]=new Obstacle(new Coordinate(90,150),70,70,5); obstacles[i].setMovingDistance(schwer*2+c); obstacleSpawn(i); } } public void obstacleSpawn(int i) //objects spawn at a random spawn { double zufall=Math.random(); if(zufall<=0.33) { obstacles[i].spawn(cSpawn0); } else if(zufall<=0.67) { obstacles[i].spawn(cSpawn1); } else { obstacles[i].spawn(cSpawn2); } } public void initSpawns() //spawns are initialized { cSpawn0=new Coordinate((Math.random()*prefSize.width-200)+100,(Math.random()*prefSize.height-200)+100); cSpawn1=new Coordinate((Math.random()*prefSize.width-200)+100,(Math.random()*prefSize.height-200)+100); cSpawn2=new Coordinate((Math.random()*prefSize.width-200)+100,(Math.random()*prefSize.height-200)+100); spawn0=new Spawn(); spawn1=new Spawn(); spawn2=new Spawn(); } private void startGame() //timer starts { t.start(); } public void pauseGame() //timer stops { t.stop(); } public void resumeGame() //if game is not over, timer starts again { if(!isGameOver()) { t.start(); } } public void continueGame() //if the current round is won, a new one will start { if(isRoundWin()) { setRoundWin(false); player.setMovingDistance(5); createGameObjects(); startGame(); } } public void restartGame() //if a round is lost, a new game will start { setGameOver(false); setRoundWin(false); c=0; p=0; player.setMovingDistance(5); createGameObjects(); startGame(); } private void endGame() //game is set to be over { setGameOver(true); pauseGame(); } private void doOnTick() //every tick (controlled by the timer), this will happen: { if(player.getObjectPosition().getX() <=0||player.getObjectPosition().getX()>=prefSize.width||player.getObjectPosition().getY()<=0||player.getObjectPosition().getY()>=prefSize.height) { endGame(); } //if a player leaves the window, the game is over for(int i=0;i<schwer;i++) { if(obstacles[i].getObjectPosition().getX() <=0||obstacles[i].getObjectPosition().getX()>=prefSize.width||obstacles[i].getObjectPosition().getY()<=0||obstacles[i].getObjectPosition().getY()>=prefSize.height) { obstacleSpawn(i); } //if an obstacle leaves the window, it will respawn if(player.touches(obstacles[i])||obstacles[i].touches(player)) { endGame(); } //if the player touches an obstacle, the game is over } if(player.touches(goal)||goal.touches(player)) { setRoundWin(true); pauseGame(); c=c+1; p=(int)(p+(player.getMovingDistance()*schwer)); } //if the player touches the goal, the round is won and the new scores for round and points are //calculated player.makeMove(); //the player is moved for(int i=0;i<schwer;i++) { obstacles[i].makeMove(); } //all obstacles are moved repaint(); //the game is repainted } @Override public void paintComponent(Graphics g) { super.paintComponent(g); //everything of the original paintComponent is done Graphics2D g2d = (Graphics2D) g; //g2d is g g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); //antialiasing is turned on -> Kantenglättung setBackground(Color.GRAY); //background is gray player.paintMe(g); //player is painted for(int i=0;i<schwer;i++) { obstacles[i].paintMe(g); } //all obstacles are painted spawn0.paintMe(g,cSpawn0); spawn1.paintMe(g,cSpawn1); spawn2.paintMe(g,cSpawn2); //all spawns are painted goal.paintMe(g); //goal is painted g.setFont(new Font(Font.SANS_SERIF,Font.BOLD,30)); g.setColor(Color.BLUE); g.drawString("Rounds: "+c,prefSize.width-200,30); g.setColor(Color.RED); g.drawString("Points: "+p,30,30); //rounds and points GUI are painted if(isGameOver()) { for(int i=0;i<max.length;i++) { if(p>=max[i][0]) { for(int j=max.length-1;j>i+1;j--) { max[j][0]=max[j-1][0]; max[j][1]=max[j-1][1]; max[j][2]=max[j-1][2]; } max[i][0]=p; max[i][1]=c; max[i][2]=schwer; break; } } //if the game is lost, all highscores are sized g.setFont(new Font(Font.SANS_SERIF,Font.BOLD,50)); g.setColor(Color.RED); g.drawString("GAME OVER!",prefSize.width/2-170,prefSize.height/5); //the "GAME OVER!" is painted on the screen ... g.setFont(new Font(Font.SANS_SERIF,Font.BOLD,20)); g.setColor(Color.ORANGE); g.drawString("Highscores",prefSize.width/2-100,prefSize.height/4); for(int i=0;i<max.length;i++) { g.drawString(max[i][0]+" Points",200,300+30*i); g.drawString(max[i][1]+" Rounds",500,300+30*i); g.drawString(schwerMax(max[i][2]),700,300+30*i); } //... and all the highscores } if(isRoundWin()) { g.setFont(new Font(Font.SANS_SERIF,Font.BOLD,50)); g.setColor(Color.BLUE); g.drawString("ROUND WON!",prefSize.width/2-130,prefSize.height/5); } //if the round is won, this is painted on the screen } }
抽象 Class 游戏对象(玩家、障碍物和球门是游戏对象;我已经为生成物尝试了一些不同的东西):
public abstract class GameObject { private Coordinate objectPosition; private double width; private double height; private double movingAngle; private double movingDistance; public GameObject(Coordinate objectPosition,double width,double height) { this.objectPosition=objectPosition; this.width=width; this.height=height; movingAngle=0; movingDistance=0; } public Coordinate getObjectPosition() { return objectPosition; } public void setObjectPosition(Coordinate objectPosition) { this.objectPosition=objectPosition; } public double getWidth() { return width; } public void setWidth(double width) { this.width=width; } public double getHeight() { return height; } public void setHeight(double height) { this.height=height; } public double getMovingAngle() { return movingAngle; } public void setMovingAngle(double movingAngle) { this.movingAngle=movingAngle; } public double getMovingDistance() { return movingDistance; } public void setMovingDistance(double movingDistance) { this.movingDistance=movingDistance; } public boolean isLeftOf(GameObject that) { return this.getObjectPosition().getX()+this.getWidth()<that.getObjectPosition().getX(); } public boolean isAbove(GameObject that) { return this.getObjectPosition().getY()+this.getHeight()<that.getObjectPosition().getY(); } public boolean touches(GameObject that) { if(this.isLeftOf(that)) return false; if(that.isLeftOf(this)) return false; if(this.isAbove(that)) return false; if(that.isAbove(this)) return false; return true; } public static Coordinate polarToCartesianCoordinates(double angle) { double x=Math.cos(angle); double y=Math.sin(angle); return new Coordinate(x,y); } public void moveGameObject() { Coordinate direction=polarToCartesianCoordinates(movingAngle); objectPosition.setX(objectPosition.getX()+direction.getX()*movingDistance); objectPosition.setY(objectPosition.getY()+direction.getY()*movingDistance); } public void makeMove() { moveGameObject(); } protected abstract void paintMe(Graphics g); }
障碍:
public class Obstacle extends GameObject { private Shape transformedObstacle=new RoundRectangle2D.Double(); public Obstacle(Coordinate position,double size,double MovingAngle,double MovingDistance) { super(position,size,size/3); this.setMovingAngle(MovingAngle); this.setMovingDistance(MovingDistance); } public Shape getTransformedObstacle() { return transformedObstacle; } public void setTransformedObstacle(Shape transformedObstacle) { this.transformedObstacle=transformedObstacle; } public void spawn(Coordinate spawn) { this.setObjectPosition(spawn); this.setMovingAngle(Math.toRadians(Math.random()*360)); } public void paintMe(java.awt.Graphics g) { Graphics2D g2d=(Graphics2D) g; this.paintComponent(g2d); } public void paintComponent(Graphics2D g2d) { RoundRectangle2D quader=new RoundRectangle2D.Double(this.getObjectPosition().getX(),this.getObjectPosition().getY(),this.getWidth(),this.getHeight(),5,5); g2d.setColor(Color.GREEN); AffineTransform transform=new AffineTransform(); transform.rotate(this.getMovingAngle(),quader.getCenterX(),quader.getCenterY()); Shape transformed=transform.createTransformedShape(quader); g2d.fill(transformed); setTransformedObstacle(transformed); } }
重生:
public class Spawn { public void paintMe(java.awt.Graphics g,Coordinate position) { Graphics2D g2d=(Graphics2D) g; paintSpawn(g2d,position); } public void paintSpawn(Graphics2D g2d,Coordinate position) { RoundRectangle2D spawn=new RoundRectangle2D.Double(position.getX(),position.getY(),50,50,100,100); g2d.setColor(Color.DARK_GRAY); g2d.fill(spawn); } }
这是一个关于组合障碍物和移动重生点的视频:https://youtu.be/N8Rq3yKblXk
我知道,这是很多代码,但我希望有人能帮我找到问题所在。
.
干杯
林德亚龙
您将 spawn0
(Coordinate
) 的引用传递给 Obstacle
,然后在 Obstacle
移动时更新,所以现在 Obstacle
和 spawn0
位置相同,所以一起移动
Spawn
应该用它自己的位置构建(这不应该然后共享),Spawn
然后应该负责 Obstacle
的生命周期并产生新的 Obstacle
根据需要(并删除旧的)