如何在Java Swing中对不同力和角度的球的抛射进行编码?

如何在Java Swing中对不同力和角度的球的抛射进行编码?,java,swing,applet,physics,japplet,Java,Swing,Applet,Physics,Japplet,我已经为不同力和角度的抛射运动编写了以下函数,但它不能正常工作。我哪里出错了?我想要像《愤怒的小鸟》这样的游戏 代码: public void shootBall(int timeCounter){ int gravity = 4; double time = timeCounter/40.0; int velocity = force_value; double radians = currentangle*Math.PI/180; ball.setX

我已经为不同力和角度的抛射运动编写了以下函数,但它不能正常工作。我哪里出错了?我想要像《愤怒的小鸟》这样的游戏

代码:

public void shootBall(int timeCounter){
    int gravity = 4;

    double time = timeCounter/40.0;
    int velocity = force_value;
    double radians = currentangle*Math.PI/180;
    ball.setX((int)((ball.getX()+10)*Math.cos(radians) + velocity*Math.cos(radians)*time));
    ball.setY((int)((ball.getY()+10)*Math.sin(radians) + velocity*Math.sin(radians)*time - 0.5*gravity*time*time));
    updateGame();
}
我想把球从左下角扔出去


您为x和y位移创建的公式在第一个术语中都缺少时间系数。下面,我将您的代码放在上面,并将正确的代码放在下面,以便进行比较,这样您就可以准确地看到您遗漏了什么

用于X位移

  • (ball.getX()+10)*Math.cos(弧度)+…
  • (ball.getX()+10)*时间*Math.cos(弧度)+…
用于Y位移

  • (ball.getY()+10)*Math.sin(弧度)+……
  • (ball.getY()+10)*时间*Math.sin(弧度)+…

我引用位移作为弧度的函数来回答您的问题。

您为x和y位移创建的公式在第一个术语中都缺少时间系数。下面,我将您的代码放在上面,并将正确的代码放在下面,以便进行比较,这样您就可以准确地看到您遗漏了什么

用于X位移

  • (ball.getX()+10)*Math.cos(弧度)+…
  • (ball.getX()+10)*时间*Math.cos(弧度)+…
用于Y位移

  • (ball.getY()+10)*Math.sin(弧度)+……
  • (ball.getY()+10)*时间*Math.sin(弧度)+…

我引用位移作为弧度的函数来回答您的问题。

需要注意的是:在Java中(与许多其他语言一样)图像中的位置(0,0)是左上角。因此,要模拟对象“坠落”,实际上需要增加其Y坐标(并检查它是否已经“触地”->
if(position.Y==ground)stop();
)。此外,起始位置不是(0,0),而是(0,开始)

除此之外,我的建议是:

  • 将球的当前位置存储在一个单独的结构中(可以是两个变量,x和y。)
  • 让你的速度由两个元素组成:X方向的速度和Y方向的速度
  • 创建一个
    move
    方法,该方法将根据速度改变当前位置
  • 请注意,您的x坐标在一个恒定的maner中变化,因此您的
    速度.x
    将是恒定的,并且可以在开始时进行计算。然后,你的
    velocity.Y
    应该随时间变化:你计算它的初始值,然后在每次迭代中从中减去重力相关的量(也是常数)。
    move
    方法可能如下所示:

    public void move(Position position, Velocity velocity) {
        position.X += velocity.X;
        position.Y += velocity.Y;
        velocity.Y -= ACCELERATION*TIME;    //TIME is time between calls of move(), approximate.
    }
    
    position.X = startingX;    //the leftmost pixel of the screen is 0, of course.
    position.Y = startingY;    //the "ground level" of your simulation is probably NOT 0.
    velocity.X = speed*Math.cos(throwAngle);
    velocity.Y = speed*Math.sin(throwAngle);
    
    当然,这是一个非常简单的例子,但我想它给出了一个想法。请注意,时间和加速度在模拟中都是恒定的,因为时间不是从开始经过的时间,而是从上一次
    move
    调用经过的时间。记住这个答案顶部的通知。另外:正确初始化
    速度
    位置
    ,如下所示:

    public void move(Position position, Velocity velocity) {
        position.X += velocity.X;
        position.Y += velocity.Y;
        velocity.Y -= ACCELERATION*TIME;    //TIME is time between calls of move(), approximate.
    }
    
    position.X = startingX;    //the leftmost pixel of the screen is 0, of course.
    position.Y = startingY;    //the "ground level" of your simulation is probably NOT 0.
    velocity.X = speed*Math.cos(throwAngle);
    velocity.Y = speed*Math.sin(throwAngle);
    

    其中,
    speed
    只是一个int(开始时速度向量的长度)。

    需要注意的是:在Java中(与许多其他语言一样)图像中的位置(0,0)是左上角。因此,要模拟对象“坠落”,实际上需要增加其Y坐标(并检查它是否已经“触地”->
    if(position.Y==ground)stop();
    )。此外,起始位置不是(0,0),而是(0,开始)

    除此之外,我的建议是:

  • 将球的当前位置存储在一个单独的结构中(可以是两个变量,x和y。)
  • 让你的速度由两个元素组成:X方向的速度和Y方向的速度
  • 创建一个
    move
    方法,该方法将根据速度改变当前位置
  • 请注意,您的x坐标在一个恒定的maner中变化,因此您的
    速度.x
    将是恒定的,并且可以在开始时进行计算。然后,你的
    velocity.Y
    应该随时间变化:你计算它的初始值,然后在每次迭代中从中减去重力相关的量(也是常数)。
    move
    方法可能如下所示:

    public void move(Position position, Velocity velocity) {
        position.X += velocity.X;
        position.Y += velocity.Y;
        velocity.Y -= ACCELERATION*TIME;    //TIME is time between calls of move(), approximate.
    }
    
    position.X = startingX;    //the leftmost pixel of the screen is 0, of course.
    position.Y = startingY;    //the "ground level" of your simulation is probably NOT 0.
    velocity.X = speed*Math.cos(throwAngle);
    velocity.Y = speed*Math.sin(throwAngle);
    
    当然,这是一个非常简单的例子,但我想它给出了一个想法。请注意,时间和加速度在模拟中都是恒定的,因为时间不是从开始经过的时间,而是从上一次
    move
    调用经过的时间。记住这个答案顶部的通知。另外:正确初始化
    速度
    位置
    ,如下所示:

    public void move(Position position, Velocity velocity) {
        position.X += velocity.X;
        position.Y += velocity.Y;
        velocity.Y -= ACCELERATION*TIME;    //TIME is time between calls of move(), approximate.
    }
    
    position.X = startingX;    //the leftmost pixel of the screen is 0, of course.
    position.Y = startingY;    //the "ground level" of your simulation is probably NOT 0.
    velocity.X = speed*Math.cos(throwAngle);
    velocity.Y = speed*Math.sin(throwAngle);
    

    其中,
    速度
    只是一个int(开始时速度向量的长度)。

    如评论(以及回答)中所述:为了实现弹丸的“真实”弹道,必须考虑速度以及给定加速度的速度变化(基于重力).诚然,我并不完全理解您在当前职位更新中希望通过正/反方向计算实现什么。但我这里已经有一些SSCE,接近您想要实现的目标,所以我对其进行了一些修改。其中大部分是q&d样板代码,但您可能想看看
    射弹
    a类以及如何在其
    performTimeStep
    方法中更新速度和位置

    顺便说一句:这种方法有一个很好的优点,它可以很容易地扩展到类似风的模型:只需使用不同的加速度。例如,不是(0,-9.81),而是(1,-9.81)来模拟从左侧吹来的微风

    import java.awt.BorderLayout;
    import java.awt.Color;
    import java.awt.Graphics;
    import java.awt.Graphics2D;
    import java.awt.GridLayout;
    import java.awt.event.ActionEvent;
    import java.awt.event.ActionListener;
    import java.awt.geom.AffineTransform;
    import java.awt.geom.Point2D;
    
    import javax.swing.JButton;
    import javax.swing.JComponent;
    import javax.swing.JFrame;
    import javax.swing.JLabel;
    import javax.swing.JPanel;
    import javax.swing.JSlider;
    import javax.swing.SwingUtilities;
    
    public class ProjectileShooterTest
    {
        public static void main(String[] args)
        {
            SwingUtilities.invokeLater(new Runnable()
            {
                @Override
                public void run()
                {
                    createAndShowGUI();
                }
            });
        }
    
        private static void createAndShowGUI()
        {
            JFrame f = new JFrame();
            f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            f.setSize(600,600);
    
            final ProjectileShooter projectileShooter = 
                new ProjectileShooter();
            ProjectileShooterPanel projectileShooterPanel = 
                new ProjectileShooterPanel(projectileShooter);
            projectileShooter.setPaintingComponent(projectileShooterPanel);
    
            JPanel controlPanel = new JPanel(new GridLayout(1,0));
    
            controlPanel.add(new JLabel("Angle"));
            final JSlider angleSlider = new JSlider(0, 90, 45);
            controlPanel.add(angleSlider);
    
            controlPanel.add(new JLabel("Power"));
            final JSlider powerSlider = new JSlider(0, 100, 50);
            controlPanel.add(powerSlider);
    
            JButton shootButton = new JButton("Shoot");
            shootButton.addActionListener(new ActionListener()
            {
                @Override
                public void actionPerformed(ActionEvent e)
                {
                    int angleDeg = angleSlider.getValue();
                    int power = powerSlider.getValue();
                    projectileShooter.setAngle(Math.toRadians(angleDeg));
                    projectileShooter.setPower(power);
                    projectileShooter.shoot();
                }
            });
            controlPanel.add(shootButton);
    
            f.getContentPane().setLayout(new BorderLayout());
            f.getContentPane().add(controlPanel, BorderLayout.NORTH);
            f.getContentPane().add(projectileShooterPanel, BorderLayout.CENTER);
            f.setVisible(true);
        }
    }
    
    class ProjectileShooter
    {
        private double angleRad = Math.toRadians(45);
        private double power = 50;
        private Projectile projectile;
        private JComponent paintingComponent;
    
        void setPaintingComponent(JComponent paintingComponent)
        {
            this.paintingComponent = paintingComponent;
        }
    
        void setAngle(double angleRad)
        {
            this.angleRad = angleRad;
        }
    
        void setPower(double power)
        {
            this.power = power;
        }
    
        void shoot()
        {
            Thread t = new Thread(new Runnable()
            {
                @Override
                public void run()
                {
                    executeShot();
                }
            });
            t.setDaemon(true);
            t.start();
        }
    
        private void executeShot()
        {
            if (projectile != null)
            {
                return;
            }
            projectile = new Projectile();
    
            Point2D velocity = 
                AffineTransform.getRotateInstance(angleRad).
                    transform(new Point2D.Double(1,0), null);
            velocity.setLocation(
                velocity.getX() * power * 0.5, 
                velocity.getY() * power * 0.5);
            projectile.setVelocity(velocity);
    
            //System.out.println("Initial "+velocity);
    
            long prevTime = System.nanoTime();
            while (projectile.getPosition().getY() >= 0)
            {
                long currentTime = System.nanoTime();
                double dt = 3 * (currentTime - prevTime) / 1e8;
                projectile.performTimeStep(dt);
    
                prevTime = currentTime;
                paintingComponent.repaint();
                try
                {
                    Thread.sleep(10);
                }
                catch (InterruptedException e)
                {
                    Thread.currentThread().interrupt();
                    return;
                }
            }
    
            projectile = null;
            paintingComponent.repaint();
        }
    
        Projectile getProjectile()
        {
            return projectile;
        }
    }
    
    class Projectile
    {
        private final Point2D ACCELERATION = new Point2D.Double(0, -9.81 * 0.1);
    
        private final Point2D position = new Point2D.Double();
        private final Point2D velocity = new Point2D.Double();
    
        public Point2D getPosition()
        {
            return new Point2D.Double(position.getX(), position.getY());
        }
        public void setPosition(Point2D point)
        {
            position.setLocation(point);
        }
    
        public void setVelocity(Point2D point)
        {
            velocity.setLocation(point);
        }
    
        void performTimeStep(double dt)
        {
            scaleAddAssign(velocity, dt, ACCELERATION);
            scaleAddAssign(position, dt, velocity);
    
            //System.out.println("Now at "+position+" with "+velocity);
        }
    
        private static void scaleAddAssign(
            Point2D result, double factor, Point2D addend)
        {
            double x = result.getX() + factor * addend.getX();
            double y = result.getY() + factor * addend.getY();
            result.setLocation(x, y);
        }
    
    }
    
    class ProjectileShooterPanel extends JPanel
    {
        private final ProjectileShooter projectileShooter;
    
        public ProjectileShooterPanel(ProjectileShooter projectileShooter)
        {
            this.projectileShooter = projectileShooter;
        }
    
        @Override
        protected void paintComponent(Graphics gr)
        {
            super.paintComponent(gr);
            Graphics2D g = (Graphics2D)gr;
    
            Projectile projectile = projectileShooter.getProjectile();
            if (projectile != null)
            {
                g.setColor(Color.RED);
                Point2D position = projectile.getPosition();
                int x = (int)position.getX();
                int y = getHeight() - (int)position.getY();
                g.fillOval(x-01, y-10, 20, 20);
            }
        }
    }
    

    正如评论中所指出的(和我