text field java
Cómo codificar el proyectil de una bola de diferente fuerza y ángulo en Java Swing? (3)
Es muy importante tener en cuenta: en Java (como en muchos otros idiomas) la posición (0, 0) en su imagen es la esquina superior izquierda . Entonces, para simular que su objeto "se caiga", realmente necesita aumentar su coordenada Y (y verificar si ya "tocó el suelo" -> if (position.Y == GROUND) stop();
). Además, la posición de inicio no es (0, 0) sino (0, comenzando Y).
Aparte de esto, mi recomendación es:
- almacena la posición actual de una bola en una estructura separada (podría ser simplemente 2 variables, xey).
- deja que tu velocidad consista en dos elementos: velocidad en dirección de X y velocidad en dirección de Y.
- crea un método de
move
, que cambiaría la posición actual de acuerdo con la velocidad.
Tenga en cuenta que su coordenada x cambia en un generador constante, por lo que su velocity.X
sería constante y podría calcularse al inicio. Luego, su velocity.Y
debería cambiar con el tiempo: calcula su valor inicial y luego resta una cantidad relacionada con la gravedad (también constante) en cada iteración. El método de move
podría verse así:
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.
}
Por supuesto, este es un ejemplo muy simple, pero supongo que da la idea. Tenga en cuenta que tanto el TIEMPO como la ACELERACIÓN son constantes dentro de la simulación, ya que TIEMPO no es el tiempo transcurrido desde el inicio, sino el tiempo transcurrido desde la llamada al move
anterior. Recuerde el aviso de la parte superior de esta respuesta. Además: inicializa tu velocity
y position
correctamente, así:
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);
Donde la speed
es solo un int (la longitud de su vector de velocidad al inicio).
He escrito la siguiente función para el movimiento del proyectil de diferentes fuerzas y ángulos, pero no funciona correctamente. ¿Dónde me he equivocado? Quiero algo como el juego Angry Birds.
Código:
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();
}
Quiero que la pelota sea lanzada desde la esquina inferior izquierda.
Las fórmulas que creó para el desplazamiento xey están faltando un factor de time
en el primer término. A continuación, coloqué tu código arriba y el código correcto a continuación, para comparar, para que puedas ver exactamente lo que dejaste fuera.
Para desplazamiento de X
-
(ball.getX()+10)*Math.cos(radians)+ ...
-
(ball.getX()+10)*time*Math.cos(radians)+ ...
Para el desplazamiento en Y
-
(ball.getY()+10)*Math.sin(radians)+ ...
-
(ball.getY()+10)*time*Math.sin(radians)+ ...
Hice referencia a la ecuación de Wikipedia para el desplazamiento como una función de radianes para responder a su pregunta.
Como se señala en el comentario (y en la respuesta https://.com/a/21785385 ): para lograr una trayectoria balística "realista" para el proyectil, es importante tener en cuenta la velocidad, así como también como el cambio de velocidad para la aceleración dada (basada en la fuerza de la gravedad). Es cierto que no entendí completamente lo que quería lograr con el cálculo de sin / cos en su actualización de posición actual. Pero ya tenía algo de SSCE que estaba cerca de lo que quieres lograr, así que lo adapté un poco. La mayoría de esto es un código repetitivo de Q & D, pero es posible que desee echarle un vistazo a la clase Projectile
y cómo se actualizan la velocidad y la posición en su método performTimeStep
.
Por cierto: este enfoque tiene la agradable ventaja de que puede extenderse fácilmente para modelar algo como el viento : simplemente usa una aceleración diferente. Por ejemplo, no (0, -9.81) pero (1, -9.81) para simular un viento ligero desde la izquierda.
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);
}
}
}