仿射变换与多边形点的关系
Relationship Between AffineTransformation and Polygon's Point
作为一个项目,我正在尝试创建 Asteroids 游戏的模拟。目前,我正在努力做到这一点,如果玩家将自己送出界外,宇宙飞船就会出现在 GUI 的另一侧。
但是,我对 AffineTransformation 的旋转和 createTransformedShape 函数如何与多边形的 x 点和 y 点交互感到很困惑。
目前,我的飞船正在运行;它以用户指定的角度飞行,所有涉及的运动都正常。但是,当我试图获取宇宙飞船的最低 X 坐标以比较它是否大于常量 WIDTH
时,它 returns 780。无论我是否在地图的一侧到另一侧,它总是 returns 780。我觉得这很奇怪,因为它不应该 return 当前所在位置的最小 X 坐标吗?
Here is a screenshot of the console displaying that the "smallest x coordinate" of the polygon is 780, despite not being at 780
谁能给我解释一下为什么多边形的 X 坐标没有变化?我有 2 classes。一个是 driver classes,另一个是扩展 Polygon.class 的船 class。
public class AsteroidGame implements ActionListener, KeyListener{
public static AsteroidGame game;
public Renderer renderer;
public boolean keyDown = false;
public int playerAngle = 0;
public boolean left = false;
public boolean right = false;
public boolean go = false;
public boolean back = false;
public boolean still = true;
public double angle = 0;
public int turnRight = 5;
public int turnLeft = -5;
public Shape transformed;
public Shape transformedLine;
public Point p1;
public Point p2;
public Point center;
public Point p4;
public final int WIDTH = 1600;
public final int HEIGHT = 800;
public Ship ship;
public AffineTransform transform = new AffineTransform();
public AsteroidGame(){
JFrame jframe = new JFrame();
Timer timer = new Timer(20, this);
renderer = new Renderer();
jframe.add(renderer);
jframe.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
jframe.setSize(WIDTH, HEIGHT);
jframe.setVisible(true);
jframe.addKeyListener(this);
jframe.setResizable(false);
int xPoints[] = {800, 780, 800, 820};
int yPoints[] = {400, 460, 440, 460};
p1 = new Point(400,400);
p2 = new Point(380, 460);
center = new Point(400,440);//center
p4 = new Point(420, 460);
ship = new Ship(xPoints, yPoints, 4, 0);
transformed = transform.createTransformedShape(ship);
timer.start();
}
public void repaint(Graphics g){
g.setColor(Color.BLACK);
g.fillRect(0, 0, WIDTH, HEIGHT);
Graphics2D g2d = (Graphics2D)g;
g2d.setColor(Color.WHITE);
g2d.draw(transformed);
/*
g2d.draw(r2);
Path2D.Double path = new Path2D.Double();
path.append(r, false);
AffineTransform t = new AffineTransform();
t.rotate(Math.toRadians(45));
path.transform(t);
g2d.draw(path);
Rectangle test = new Rectangle(WIDTH/2, HEIGHT/2, 200, 100);
Rectangle test2 = new Rectangle(WIDTH/2, HEIGHT/2, 200, 100);
g2d.draw(test2);
AffineTransform at = AffineTransform.getTranslateInstance(100, 100);
g2d.rotate(Math.toRadians(45));
g2d.draw(test);
*/
}
public void actionPerformed(ActionEvent arg0) {
// TODO Auto-generated method stub
if (right){
ship.right();
transform.rotate(Math.toRadians(turnRight), ship.getCenterX(), ship.getCenterY());
System.out.println(ship.getCenterY());
}
else if (left){
ship.left();
transform.rotate(Math.toRadians(turnLeft), ship.getCenterX(), ship.getCenterY());
}
if (go){
ship.go();
//ship.x += Math.sin(Math.toRadians(angle)) * 5;
//ship.y
/*
ship.x += (int) Math.sin(Math.toRadians(angle));
ship.y += (int) Math.cos(Math.toRadians(angle));
*/
//System.out.println(Math.sin(Math.toRadians(ship.angle)) * 5 + "y" + Math.cos(Math.toRadians(ship.angle)) * 5);
}
else if (back){
ship.reverse();
}
ship.move();
//ship.decrement();
transformed = transform.createTransformedShape(ship);
if (ship.smallestX() >= WIDTH){
System.out.println("out");
}
renderer.repaint();
System.out.println("Smallest x coordinate: " + ship.smallestX());
}
public static void main(String[] args){
game = new AsteroidGame();
}
@Override
public void keyPressed(KeyEvent e) {
// TODO Auto-generated method stub
if (e.getKeyCode() == KeyEvent.VK_RIGHT){
System.out.println("I am down");
right = true;
keyDown = true;
}else if (e.getKeyCode() == KeyEvent.VK_LEFT){
left = true;
System.out.println("I am down");
keyDown = true;
}
if (e.getKeyCode() == KeyEvent.VK_UP){
go = true;
}
else if (e.getKeyCode() == KeyEvent.VK_DOWN){
back = true;
}
}
@Override
public void keyReleased(KeyEvent e) {
// TODO Auto-generated method stub
if (e.getKeyCode() == KeyEvent.VK_RIGHT){
right = false;
}
if (e.getKeyCode() == KeyEvent.VK_LEFT){
left = false;
}
if (e.getKeyCode() == KeyEvent.VK_UP){
go = false;
}
if (e.getKeyCode() == KeyEvent.VK_DOWN){
back = false;
}
still = true;
keyDown = false;
System.out.println("up");
}
@Override
public void keyTyped(KeyEvent e) {
// TODO Auto-generated method stub
}
船Class:
public class Ship extends Polygon{
/**
*
*/
private double currSpeed = 0;
private static final long serialVersionUID = 1L;
public double angle;
public Ship(int[] x, int[] y, int points, double angle){
super(x, y, points);
this.angle= angle;
}
public void right(){
angle += 5;
}
public void left(){
angle -= 5;
}
public void move(){
for (int i = 0; i < super.ypoints.length; i++){
super.ypoints[i] -= currSpeed;
//System.out.println(super.ypoints[i]);
//System.out.println(super.xpoints[i]);
}
}
public void reverse(){
if (currSpeed > -15) currSpeed -= 0.2;
}
public void go(){
if (currSpeed < 25) currSpeed += 0.5;
}
public int smallestX(){
int min = super.xpoints[0];
for (int i = 0; i < super.xpoints.length; i++){
if (min > super.xpoints[i]){
min = super.xpoints[i];
}
}
return min;
}
public int smallestY(){
int min = super.ypoints[0];
for (int i = 0; i < super.ypoints.length; i++){
if (min < super.ypoints[i]){
min = super.ypoints[i];
}
}
return min;
}
public int getCenterX(){
return super.xpoints[2];
}
public int getCenterY(){
return super.ypoints[2];
}
public double getAng(){
return angle;
}
为什么它不起作用
仿射变换实际上并没有影响飞船实例,而是创建了一个全新的实例,这就是为什么您的方法似乎不起作用的原因。为了证明这一点,我有以下代码:
int[] xPoints = {800, 780, 800, 820};
int[] yPoints = {400, 460, 440, 460};
Ship ship = new Ship(xPoints, yPoints, 4, 0);
System.out.println("old points:");
System.out.println(Arrays.toString(ship.xpoints));
System.out.println(Arrays.toString(ship.ypoints));
AffineTransform transform = new AffineTransform();
transform.translate(20, 20);
Shape transformed = transform.createTransformedShape(ship);
System.out.println("new points (unchanged):");
System.out.println(Arrays.toString(ship.xpoints));
System.out.println(Arrays.toString(ship.ypoints));
两次,点数相同
解决方案
我建议您不要将点视为屏幕上的实际点,而应将它们视为模型,这也会使物理部分更容易。我们将以 (0,0) 为中心点。当我们需要渲染它时,将它转换到正确的位置和旋转。
这些点将是这样的:
int[] xPoints = {0, -20, 0, 20};
int[] yPoints = {-40, 20, 0, 20};
所以现在,您在移动飞船时不需要编辑所有的点,只需编辑旋转和中心。注意要先平移,再旋转。
这些点在 (0,0) 附近这一事实很重要,因为这是旋转的中心。这可能就是为什么你现在似乎可以移动,你的旋转不是以船的中心为中心的。并且当你旋转向上移动时,你也向右移动了一点。
这解决了我们的问题,因为现在你不需要再看所有的点了,你可以只看船的中心。如果中心超出范围,则将其移至另一侧。
导致下面的简单代码(我在这里使用 300 因为这是我示例中的宽度和高度,请在实际代码中将其更改为您的宽度和高度)
if(center_x > 300)
center_x = 0;
if(center_x < 0)
center_x = 300;
if(center_y > 300)
center_y = 0;
if(center_y < 0)
center_y = 300;
这会在需要时将飞船带到屏幕的另一边。但是,我们仍然需要显示一部分船,而另一部分在另一侧。出于这个原因,我们可以渲染这艘船两次。我希望下面的代码不言自明。
Rectangle2D box = transformed.getBounds2D();
//wrap in x direction
if(box.getX() + box.getWidth() > 300){
AffineTransform transform2 = new AffineTransform();
transform2.translate(ship.center_x - 300, ship.center_y);
transform2.rotate(Math.toRadians(ship.angle));
Shape transformed2 = transform2.createTransformedShape(ship);
g2.draw(transformed2);
}else if(box.getX() < 0){
AffineTransform transform2 = new AffineTransform();
transform2.translate(ship.center_x + 300, ship.center_y);
transform2.rotate(Math.toRadians(ship.angle));
Shape transformed2 = transform2.createTransformedShape(ship);
g2.draw(transformed2);
}
//wrap in y direction
if(box.getY() + box.getHeight() > 300){
AffineTransform transform2 = new AffineTransform();
transform2.translate(ship.center_x, ship.center_y - 300);
transform2.rotate(Math.toRadians(ship.angle));
Shape transformed2 = transform2.createTransformedShape(ship);
g2.draw(transformed2);
}else if(box.getY() < 0){
AffineTransform transform2 = new AffineTransform();
transform2.translate(ship.center_x, ship.center_y + 300);
transform2.rotate(Math.toRadians(ship.angle));
Shape transformed2 = transform2.createTransformedShape(ship);
g2.draw(transformed2);
}
物理学
您还要求提供有关实际物理学的更多信息,我只会给您公式(如果您需要更多帮助,请告诉我)。这里,theta 是以弧度为单位的船的角度,如果 theta 为 0,则船指向上。 x轴指向右侧,y轴指向上方
a_x = Math.sin(theta)*a;
a_y = -Math.cos(theta)*a;
v_x_new = v_x_old + a_x*timeDiff;
v_y_new = v_y_old + a_y*timeDiff;
x_new = x_old + v_x_old*timeDiff + a_x*timeDiff*timeDiff/2;
y_new = y_old + v_y_old*timeDiff + a_y*timeDiff*timeDiff/2;
x_old = x_new;
y_old = y_new;
v_x_old = v_x_new;
v_y_old = v_y_new;
最终结果
我已经实现了飞船 class 的外观,还测试了渲染方法是否有效。
public class AsteroidsTest {
public static void main(String[] args){
int[] xPoints = {0, -20, 0, 20};
int[] yPoints = {-40, 20, 0, 20};
Ship ship = new Ship(xPoints, yPoints, 4, 0);
ship.center_x = 100;
ship.center_y = 100;
ship.angle = 45;
ship.speed_x = 30;
ship.speed_y = -30;
System.out.println("running...");
JFrame window = new JFrame();
window.setBounds(30, 30, 300, 300);
window.getContentPane().add(new MyCanvas(ship));
window.setVisible(true);
window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
long time1 = System.currentTimeMillis();
while(true){
long time2 = System.currentTimeMillis();
double timeDiff = (time2-time1)/1000f;
time1 = time2;
ship.move(timeDiff);
window.getContentPane().repaint();
}
}
}
class MyCanvas extends JComponent {
private Ship ship;
public MyCanvas(Ship ship){
this.ship = ship;
}
public void paint(Graphics g) {
Graphics2D g2 = (Graphics2D)g;
AffineTransform transform = new AffineTransform();
transform.translate(ship.center_x, ship.center_y);
transform.rotate(Math.toRadians(ship.angle));
Shape transformed = transform.createTransformedShape(ship);
g2.draw(transformed);
Rectangle2D box = transformed.getBounds2D();
//wrap in x direction
if(box.getX() + box.getWidth() > 300){
AffineTransform transform2 = new AffineTransform();
transform2.translate(ship.center_x - 300, ship.center_y);
transform2.rotate(Math.toRadians(ship.angle));
Shape transformed2 = transform2.createTransformedShape(ship);
g2.draw(transformed2);
}else if(box.getX() < 0){
AffineTransform transform2 = new AffineTransform();
transform2.translate(ship.center_x + 300, ship.center_y);
transform2.rotate(Math.toRadians(ship.angle));
Shape transformed2 = transform2.createTransformedShape(ship);
g2.draw(transformed2);
}
//wrap in y direction
if(box.getY() + box.getHeight() > 300){
AffineTransform transform2 = new AffineTransform();
transform2.translate(ship.center_x, ship.center_y - 300);
transform2.rotate(Math.toRadians(ship.angle));
Shape transformed2 = transform2.createTransformedShape(ship);
g2.draw(transformed2);
}else if(box.getY() < 0){
AffineTransform transform2 = new AffineTransform();
transform2.translate(ship.center_x, ship.center_y + 300);
transform2.rotate(Math.toRadians(ship.angle));
Shape transformed2 = transform2.createTransformedShape(ship);
g2.draw(transformed2);
}
}
}
飞船class:
import java.awt.Polygon;
public class Ship extends Polygon{
private static final long serialVersionUID = 1L;
public double center_x = 0;
public double center_y = 0;
public double speed_x = 0;
public double speed_y = 0;
//the angle of the ship
public double angle = 0;
//the acceleration of the ship in the direction defined by angle
public double acceleration = 0;
public Ship(int[] x, int[] y, int points, double angle){
super(x, y, points);
this.angle= angle;
}
public void right(){
angle += 5;
}
public void left(){
angle -= 5;
}
public void move(double timeDiff){
double a_x = Math.sin(Math.toRadians(angle))*acceleration;
double a_y = -Math.cos(Math.toRadians(angle))*acceleration;
center_x = center_x + speed_x*timeDiff + a_x*timeDiff*timeDiff/2;
center_y = center_y + speed_y*timeDiff + a_y*timeDiff*timeDiff/2;
speed_x = speed_x + a_x*timeDiff;
speed_y = speed_y + a_y*timeDiff;
if(center_x > 300)
center_x = 0;
if(center_x < 0)
center_x = 300;
if(center_y > 300)
center_y = 0;
if(center_y < 0)
center_y = 300;
}
public void reverse(){
acceleration = -1;
}
public void go(){
acceleration = 1;
}
public void stop(){
acceleration = 0;
}
public int getCenterX(){
return (int) Math.round(center_x);
}
public int getCenterY(){
return (int) Math.round(center_y);
}
public double getAng(){
return angle;
}
}
作为一个项目,我正在尝试创建 Asteroids 游戏的模拟。目前,我正在努力做到这一点,如果玩家将自己送出界外,宇宙飞船就会出现在 GUI 的另一侧。
但是,我对 AffineTransformation 的旋转和 createTransformedShape 函数如何与多边形的 x 点和 y 点交互感到很困惑。
目前,我的飞船正在运行;它以用户指定的角度飞行,所有涉及的运动都正常。但是,当我试图获取宇宙飞船的最低 X 坐标以比较它是否大于常量 WIDTH
时,它 returns 780。无论我是否在地图的一侧到另一侧,它总是 returns 780。我觉得这很奇怪,因为它不应该 return 当前所在位置的最小 X 坐标吗?
Here is a screenshot of the console displaying that the "smallest x coordinate" of the polygon is 780, despite not being at 780
谁能给我解释一下为什么多边形的 X 坐标没有变化?我有 2 classes。一个是 driver classes,另一个是扩展 Polygon.class 的船 class。
public class AsteroidGame implements ActionListener, KeyListener{
public static AsteroidGame game;
public Renderer renderer;
public boolean keyDown = false;
public int playerAngle = 0;
public boolean left = false;
public boolean right = false;
public boolean go = false;
public boolean back = false;
public boolean still = true;
public double angle = 0;
public int turnRight = 5;
public int turnLeft = -5;
public Shape transformed;
public Shape transformedLine;
public Point p1;
public Point p2;
public Point center;
public Point p4;
public final int WIDTH = 1600;
public final int HEIGHT = 800;
public Ship ship;
public AffineTransform transform = new AffineTransform();
public AsteroidGame(){
JFrame jframe = new JFrame();
Timer timer = new Timer(20, this);
renderer = new Renderer();
jframe.add(renderer);
jframe.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
jframe.setSize(WIDTH, HEIGHT);
jframe.setVisible(true);
jframe.addKeyListener(this);
jframe.setResizable(false);
int xPoints[] = {800, 780, 800, 820};
int yPoints[] = {400, 460, 440, 460};
p1 = new Point(400,400);
p2 = new Point(380, 460);
center = new Point(400,440);//center
p4 = new Point(420, 460);
ship = new Ship(xPoints, yPoints, 4, 0);
transformed = transform.createTransformedShape(ship);
timer.start();
}
public void repaint(Graphics g){
g.setColor(Color.BLACK);
g.fillRect(0, 0, WIDTH, HEIGHT);
Graphics2D g2d = (Graphics2D)g;
g2d.setColor(Color.WHITE);
g2d.draw(transformed);
/*
g2d.draw(r2);
Path2D.Double path = new Path2D.Double();
path.append(r, false);
AffineTransform t = new AffineTransform();
t.rotate(Math.toRadians(45));
path.transform(t);
g2d.draw(path);
Rectangle test = new Rectangle(WIDTH/2, HEIGHT/2, 200, 100);
Rectangle test2 = new Rectangle(WIDTH/2, HEIGHT/2, 200, 100);
g2d.draw(test2);
AffineTransform at = AffineTransform.getTranslateInstance(100, 100);
g2d.rotate(Math.toRadians(45));
g2d.draw(test);
*/
}
public void actionPerformed(ActionEvent arg0) {
// TODO Auto-generated method stub
if (right){
ship.right();
transform.rotate(Math.toRadians(turnRight), ship.getCenterX(), ship.getCenterY());
System.out.println(ship.getCenterY());
}
else if (left){
ship.left();
transform.rotate(Math.toRadians(turnLeft), ship.getCenterX(), ship.getCenterY());
}
if (go){
ship.go();
//ship.x += Math.sin(Math.toRadians(angle)) * 5;
//ship.y
/*
ship.x += (int) Math.sin(Math.toRadians(angle));
ship.y += (int) Math.cos(Math.toRadians(angle));
*/
//System.out.println(Math.sin(Math.toRadians(ship.angle)) * 5 + "y" + Math.cos(Math.toRadians(ship.angle)) * 5);
}
else if (back){
ship.reverse();
}
ship.move();
//ship.decrement();
transformed = transform.createTransformedShape(ship);
if (ship.smallestX() >= WIDTH){
System.out.println("out");
}
renderer.repaint();
System.out.println("Smallest x coordinate: " + ship.smallestX());
}
public static void main(String[] args){
game = new AsteroidGame();
}
@Override
public void keyPressed(KeyEvent e) {
// TODO Auto-generated method stub
if (e.getKeyCode() == KeyEvent.VK_RIGHT){
System.out.println("I am down");
right = true;
keyDown = true;
}else if (e.getKeyCode() == KeyEvent.VK_LEFT){
left = true;
System.out.println("I am down");
keyDown = true;
}
if (e.getKeyCode() == KeyEvent.VK_UP){
go = true;
}
else if (e.getKeyCode() == KeyEvent.VK_DOWN){
back = true;
}
}
@Override
public void keyReleased(KeyEvent e) {
// TODO Auto-generated method stub
if (e.getKeyCode() == KeyEvent.VK_RIGHT){
right = false;
}
if (e.getKeyCode() == KeyEvent.VK_LEFT){
left = false;
}
if (e.getKeyCode() == KeyEvent.VK_UP){
go = false;
}
if (e.getKeyCode() == KeyEvent.VK_DOWN){
back = false;
}
still = true;
keyDown = false;
System.out.println("up");
}
@Override
public void keyTyped(KeyEvent e) {
// TODO Auto-generated method stub
}
船Class:
public class Ship extends Polygon{
/**
*
*/
private double currSpeed = 0;
private static final long serialVersionUID = 1L;
public double angle;
public Ship(int[] x, int[] y, int points, double angle){
super(x, y, points);
this.angle= angle;
}
public void right(){
angle += 5;
}
public void left(){
angle -= 5;
}
public void move(){
for (int i = 0; i < super.ypoints.length; i++){
super.ypoints[i] -= currSpeed;
//System.out.println(super.ypoints[i]);
//System.out.println(super.xpoints[i]);
}
}
public void reverse(){
if (currSpeed > -15) currSpeed -= 0.2;
}
public void go(){
if (currSpeed < 25) currSpeed += 0.5;
}
public int smallestX(){
int min = super.xpoints[0];
for (int i = 0; i < super.xpoints.length; i++){
if (min > super.xpoints[i]){
min = super.xpoints[i];
}
}
return min;
}
public int smallestY(){
int min = super.ypoints[0];
for (int i = 0; i < super.ypoints.length; i++){
if (min < super.ypoints[i]){
min = super.ypoints[i];
}
}
return min;
}
public int getCenterX(){
return super.xpoints[2];
}
public int getCenterY(){
return super.ypoints[2];
}
public double getAng(){
return angle;
}
为什么它不起作用
仿射变换实际上并没有影响飞船实例,而是创建了一个全新的实例,这就是为什么您的方法似乎不起作用的原因。为了证明这一点,我有以下代码:
int[] xPoints = {800, 780, 800, 820};
int[] yPoints = {400, 460, 440, 460};
Ship ship = new Ship(xPoints, yPoints, 4, 0);
System.out.println("old points:");
System.out.println(Arrays.toString(ship.xpoints));
System.out.println(Arrays.toString(ship.ypoints));
AffineTransform transform = new AffineTransform();
transform.translate(20, 20);
Shape transformed = transform.createTransformedShape(ship);
System.out.println("new points (unchanged):");
System.out.println(Arrays.toString(ship.xpoints));
System.out.println(Arrays.toString(ship.ypoints));
两次,点数相同
解决方案
我建议您不要将点视为屏幕上的实际点,而应将它们视为模型,这也会使物理部分更容易。我们将以 (0,0) 为中心点。当我们需要渲染它时,将它转换到正确的位置和旋转。 这些点将是这样的:
int[] xPoints = {0, -20, 0, 20};
int[] yPoints = {-40, 20, 0, 20};
所以现在,您在移动飞船时不需要编辑所有的点,只需编辑旋转和中心。注意要先平移,再旋转。
这些点在 (0,0) 附近这一事实很重要,因为这是旋转的中心。这可能就是为什么你现在似乎可以移动,你的旋转不是以船的中心为中心的。并且当你旋转向上移动时,你也向右移动了一点。
这解决了我们的问题,因为现在你不需要再看所有的点了,你可以只看船的中心。如果中心超出范围,则将其移至另一侧。
导致下面的简单代码(我在这里使用 300 因为这是我示例中的宽度和高度,请在实际代码中将其更改为您的宽度和高度)
if(center_x > 300)
center_x = 0;
if(center_x < 0)
center_x = 300;
if(center_y > 300)
center_y = 0;
if(center_y < 0)
center_y = 300;
这会在需要时将飞船带到屏幕的另一边。但是,我们仍然需要显示一部分船,而另一部分在另一侧。出于这个原因,我们可以渲染这艘船两次。我希望下面的代码不言自明。
Rectangle2D box = transformed.getBounds2D();
//wrap in x direction
if(box.getX() + box.getWidth() > 300){
AffineTransform transform2 = new AffineTransform();
transform2.translate(ship.center_x - 300, ship.center_y);
transform2.rotate(Math.toRadians(ship.angle));
Shape transformed2 = transform2.createTransformedShape(ship);
g2.draw(transformed2);
}else if(box.getX() < 0){
AffineTransform transform2 = new AffineTransform();
transform2.translate(ship.center_x + 300, ship.center_y);
transform2.rotate(Math.toRadians(ship.angle));
Shape transformed2 = transform2.createTransformedShape(ship);
g2.draw(transformed2);
}
//wrap in y direction
if(box.getY() + box.getHeight() > 300){
AffineTransform transform2 = new AffineTransform();
transform2.translate(ship.center_x, ship.center_y - 300);
transform2.rotate(Math.toRadians(ship.angle));
Shape transformed2 = transform2.createTransformedShape(ship);
g2.draw(transformed2);
}else if(box.getY() < 0){
AffineTransform transform2 = new AffineTransform();
transform2.translate(ship.center_x, ship.center_y + 300);
transform2.rotate(Math.toRadians(ship.angle));
Shape transformed2 = transform2.createTransformedShape(ship);
g2.draw(transformed2);
}
物理学
您还要求提供有关实际物理学的更多信息,我只会给您公式(如果您需要更多帮助,请告诉我)。这里,theta 是以弧度为单位的船的角度,如果 theta 为 0,则船指向上。 x轴指向右侧,y轴指向上方
a_x = Math.sin(theta)*a;
a_y = -Math.cos(theta)*a;
v_x_new = v_x_old + a_x*timeDiff;
v_y_new = v_y_old + a_y*timeDiff;
x_new = x_old + v_x_old*timeDiff + a_x*timeDiff*timeDiff/2;
y_new = y_old + v_y_old*timeDiff + a_y*timeDiff*timeDiff/2;
x_old = x_new;
y_old = y_new;
v_x_old = v_x_new;
v_y_old = v_y_new;
最终结果
我已经实现了飞船 class 的外观,还测试了渲染方法是否有效。
public class AsteroidsTest {
public static void main(String[] args){
int[] xPoints = {0, -20, 0, 20};
int[] yPoints = {-40, 20, 0, 20};
Ship ship = new Ship(xPoints, yPoints, 4, 0);
ship.center_x = 100;
ship.center_y = 100;
ship.angle = 45;
ship.speed_x = 30;
ship.speed_y = -30;
System.out.println("running...");
JFrame window = new JFrame();
window.setBounds(30, 30, 300, 300);
window.getContentPane().add(new MyCanvas(ship));
window.setVisible(true);
window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
long time1 = System.currentTimeMillis();
while(true){
long time2 = System.currentTimeMillis();
double timeDiff = (time2-time1)/1000f;
time1 = time2;
ship.move(timeDiff);
window.getContentPane().repaint();
}
}
}
class MyCanvas extends JComponent {
private Ship ship;
public MyCanvas(Ship ship){
this.ship = ship;
}
public void paint(Graphics g) {
Graphics2D g2 = (Graphics2D)g;
AffineTransform transform = new AffineTransform();
transform.translate(ship.center_x, ship.center_y);
transform.rotate(Math.toRadians(ship.angle));
Shape transformed = transform.createTransformedShape(ship);
g2.draw(transformed);
Rectangle2D box = transformed.getBounds2D();
//wrap in x direction
if(box.getX() + box.getWidth() > 300){
AffineTransform transform2 = new AffineTransform();
transform2.translate(ship.center_x - 300, ship.center_y);
transform2.rotate(Math.toRadians(ship.angle));
Shape transformed2 = transform2.createTransformedShape(ship);
g2.draw(transformed2);
}else if(box.getX() < 0){
AffineTransform transform2 = new AffineTransform();
transform2.translate(ship.center_x + 300, ship.center_y);
transform2.rotate(Math.toRadians(ship.angle));
Shape transformed2 = transform2.createTransformedShape(ship);
g2.draw(transformed2);
}
//wrap in y direction
if(box.getY() + box.getHeight() > 300){
AffineTransform transform2 = new AffineTransform();
transform2.translate(ship.center_x, ship.center_y - 300);
transform2.rotate(Math.toRadians(ship.angle));
Shape transformed2 = transform2.createTransformedShape(ship);
g2.draw(transformed2);
}else if(box.getY() < 0){
AffineTransform transform2 = new AffineTransform();
transform2.translate(ship.center_x, ship.center_y + 300);
transform2.rotate(Math.toRadians(ship.angle));
Shape transformed2 = transform2.createTransformedShape(ship);
g2.draw(transformed2);
}
}
}
飞船class:
import java.awt.Polygon;
public class Ship extends Polygon{
private static final long serialVersionUID = 1L;
public double center_x = 0;
public double center_y = 0;
public double speed_x = 0;
public double speed_y = 0;
//the angle of the ship
public double angle = 0;
//the acceleration of the ship in the direction defined by angle
public double acceleration = 0;
public Ship(int[] x, int[] y, int points, double angle){
super(x, y, points);
this.angle= angle;
}
public void right(){
angle += 5;
}
public void left(){
angle -= 5;
}
public void move(double timeDiff){
double a_x = Math.sin(Math.toRadians(angle))*acceleration;
double a_y = -Math.cos(Math.toRadians(angle))*acceleration;
center_x = center_x + speed_x*timeDiff + a_x*timeDiff*timeDiff/2;
center_y = center_y + speed_y*timeDiff + a_y*timeDiff*timeDiff/2;
speed_x = speed_x + a_x*timeDiff;
speed_y = speed_y + a_y*timeDiff;
if(center_x > 300)
center_x = 0;
if(center_x < 0)
center_x = 300;
if(center_y > 300)
center_y = 0;
if(center_y < 0)
center_y = 300;
}
public void reverse(){
acceleration = -1;
}
public void go(){
acceleration = 1;
}
public void stop(){
acceleration = 0;
}
public int getCenterX(){
return (int) Math.round(center_x);
}
public int getCenterY(){
return (int) Math.round(center_y);
}
public double getAng(){
return angle;
}
}