我正在编写一个游戏,你必须避开障碍并达到目标。基于玩家选择的难度,存在许多障碍,这些障碍以随机角度沿直线移动。如果它们到达屏幕的边界,它们会在随机生成点重生(有三个,也是随机创建的)。当你进行一轮比赛时,产卵点应保持静止,并在你开始下一轮时在不同的地方重建。
如果我现在开始游戏,则生成点会随着障碍物一起移动,这些障碍物会在同一产卵点产生时使用组合的移动矢量进行分组。
我现在列出对于识别我的问题很重要的类:
GamePanel(大部分游戏都在这里发生):
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
}
}
抽象类游戏对象(玩家,障碍物和目标是游戏对象;我已经尝试了不同的产品):
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);
}
}
The Spawn:
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
我知道,这是很多代码,但我希望,有人可以帮我找到问题。
干杯
Lindwurm的
答案 0 :(得分:1)
您将spawn0
(Coordinate
)的引用传递给Obstacle
,然后在Obstacle
移动时更新,现在Obstacle
和{{1具有相同的位置,因此,彼此一起移动。
spawn0
应该使用它自己的位置构建(这不应该随后共享),Spawn
应该负责Spawn
的生命周期和生成根据需要添加新Obstacle
(并删除旧版本)