物体不能正确移动

Objects don't move correctly

我目前正在编写一款游戏,您必须躲避障碍物才能到达目标。根据玩家选择的难度,有许多障碍物以随机角度沿直线移动。如果它们到达屏幕边界,它们会在随机生成点重生(有三个,也是随机创建的)。当你玩一轮时出生点应该保持静止,并在你开始下一轮时在不同的地方重新创建。

如果我现在开始游戏,生成点会随着障碍物一起移动,这些障碍物在同一生成点生成时会分组并使用组合移动矢量。

现在我将列出对确定我的问题很重要的 类:

  1. 游戏面板(大部分游戏发生在这里):

    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
    }
    }
    
  2. 抽象 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);
    }
    
  3. 障碍:

    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);
    }
    }
    
  4. 重生:

    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 移动时更新,所以现在 Obstaclespawn0位置相同,所以一起移动

Spawn 应该用它自己的位置构建(这不应该然后共享),Spawn 然后应该负责 Obstacle 的生命周期并产生新的 Obstacle 根据需要(并删除旧的)