如何在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(弧度)+…
(ball.getY()+10)*Math.sin(弧度)+……
(ball.getY()+10)*时间*Math.sin(弧度)+…
我引用位移作为弧度的函数来回答您的问题。您为x和y位移创建的公式在第一个术语中都缺少时间系数。下面,我将您的代码放在上面,并将正确的代码放在下面,以便进行比较,这样您就可以准确地看到您遗漏了什么 用于X位移
(ball.getX()+10)*Math.cos(弧度)+…
(ball.getX()+10)*时间*Math.cos(弧度)+…
(ball.getY()+10)*Math.sin(弧度)+……
(ball.getY()+10)*时间*Math.sin(弧度)+…
我引用位移作为弧度的函数来回答您的问题。需要注意的是:在Java中(与许多其他语言一样)图像中的位置(0,0)是左上角。因此,要模拟对象“坠落”,实际上需要增加其Y坐标(并检查它是否已经“触地”->
if(position.Y==ground)stop();
)。此外,起始位置不是(0,0),而是(0,开始)
除此之外,我的建议是:
move
方法,该方法将根据速度改变当前位置速度.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,开始)
除此之外,我的建议是:
move
方法,该方法将根据速度改变当前位置速度.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);
}
}
}
正如评论中所指出的(和我