Имитировать гравитационное притяжение звезды?
Я делаю игру, в которой игрок (при отпускании мышки) будет стрелять "звездой" в определенном направлении с начальной скоростью, определяемой тем, как далеко он потянул мышь до отпускания. У меня есть "планета" (неподвижный круг) на холсте, который я хочу оказать гравитационное воздействие на движущуюся планету. Я полагаю, что я использую правильные формулы для гравитационной силы и тому подобное, и у меня она частично работает - планета воздействует на траекторию планеты вплоть до определенной точки, когда звезда, кажется, бесконечно ускоряется и перестает менять направление на основе своего угла к звезде Любой совет? (Я знаю, что звезды не должны вращаться вокруг планет, все наоборот. Я закодировал все это, поменяв имена, так что простите).
основной класс:
import acm.graphics.GCompound;
import acm.graphics.GImage;
import acm.graphics.GLabel;
import acm.graphics.GLine;
import acm.graphics.GMath;
import acm.graphics.GObject;
import acm.graphics.GPen;
import acm.graphics.GPoint;
import acm.graphics.GRect;
import acm.graphics.GOval;
import acm.graphics.GRectangle;
import acm.program.GraphicsProgram;
import acm.util.RandomGenerator;
import java.awt.Color;
import java.awt.event.MouseEvent;
import java.util.*;
public class Space extends GraphicsProgram {
public static int APPLICATION_WIDTH = 1000;
public static int APPLICATION_HEIGHT = 1000;
private int size = 15;
public static double pMass = 1000;
public static int sMass = 20;
public static double G = 200;
private RandomGenerator rand = new RandomGenerator();
GOval planet, tempstar;
shootingStar star;
GLine line;
double accel, xAccel, yAccel, xspeed, yspeed, angle;
public void init(){
planet = new GOval(APPLICATION_WIDTH/2, APPLICATION_HEIGHT/2, 30, 30);
planet.setFilled(true);
planet.setFillColor(rand.nextColor());
add(planet);
}
public void mousePressed(GPoint point) {
// draw a line
tempstar = new GOval(point.getX() - size/2, point.getY() - size/2, size, size);
tempstar.setFilled(true);
tempstar.setColor(rand.nextColor());
add(tempstar);
line = new GLine(tempstar.getX() + size/2, tempstar.getY() + size/2,
point.getX(), point.getY());
add(line);
line.setVisible(true);
}
public void mouseDragged(GPoint point) {
line.setEndPoint(point.getX(), point.getY());
}
public void mouseReleased(GPoint point){
xspeed =
-.05*GMath.cosDegrees(getAngle(line))*GMath.distance(line.getStartPoint().getX(),
line.getStartPoint().getY(), line.getEndPoint().getX(), line.getEndPoint().getY());
yspeed =
.05*GMath.sinDegrees(getAngle(line))*GMath.distance(line.getStartPoint().getX(),
line.getStartPoint().getY(), line.getEndPoint().getX(), line.getEndPoint().getY());
System.out.println(xspeed + " " + yspeed);
star = new shootingStar(xspeed, yspeed, this);
if(xspeed != 0)
add(star, tempstar.getX(), tempstar.getY());
new Thread(star).start();
remove(tempstar);
remove(line);
}
private double getAngle(GLine line) {
return GMath.angle(line.getStartPoint().getX(), line.getStartPoint().getY(),
line.getEndPoint().getX(), line.getEndPoint().getY());
}
public void checkPlanet(){
accel = .06*GMath.distance(star.getX(), star.getY(), planet.getX(),
planet.getY());
angle = correctedAngle(GMath.angle(planet.getX(), planet.getY(), star.getX(),
star.getY()));
xAccel = accel*GMath.cosDegrees(GMath.angle(planet.getX(), planet.getY(),
star.getX(), star.getY()));
yAccel = accel*GMath.sinDegrees(GMath.angle(planet.getX(), planet.getY(),
star.getX(), star.getY()));
double newX = xspeed - xAccel*.01;
double newY = yspeed + yAccel*.01;
xspeed = newX + xAccel*Math.pow(.01, 2)/2;
yspeed = newY + yAccel*Math.pow(.01, 2)/2;
star.setSpeed(xspeed, yspeed);
}
public double correctedAngle(double x) {
return (x%360.0+360.0+180.0)%360.0-180.0;
}
}
Уместные части стрельбы Стар-класса:
public void run() {
// move the ball by a small interval
while (alive) {
oneTimeStep();
}
}
// a helper method, move the ball in each time step
private void oneTimeStep() {
game1.checkPlanet();
shootingStar.move(xSpeed, ySpeed);
pause(20);
}
public void setSpeed (double xspeed, double yspeed){
xSpeed = xspeed;;
ySpeed = yspeed;
}
}
РЕДАКТИРОВАТЬ:
Текущий метод основного класса:
public void checkPlanet(){
double xDistance = star.getX() - planet.getX();
double yDistance = star.getY() - planet.getY();
double distance = Math.sqrt(Math.pow(xDistance, 2) + Math.pow(yDistance, 2));
accel = G*pMass/Math.pow(distance, 2);
xAccel = accel * xDistance/distance;
yAccel = accel * yDistance/distance;
xspeed += xAccel;
yspeed += yAccel;
star.setSpeed(xspeed, yspeed);
}
Текущий метод класса Star:
public void run() {
while (alive) {
oneTimeStep();
}
}
private void oneTimeStep() {
game1.checkPlanet();
shootingStar.move(xSpeed, ySpeed);
pause(20);
}
public void setSpeed (double xspeed, double yspeed){
xSpeed = xspeed;;
ySpeed = yspeed;
}
}
2 ответа
Вау, это намного больше усилий, чем то, что ты "ДОЛЖЕН" делать.
Если вещь находится на доске, рассчитайте ее расстояние от объекта. Если это дальше, чем D, ничего не делай. Если это D, то это внутри гравитационного притяжения объектов. Просто добавьте небольшое количество скорости, указывающей на объект. Скажем, это было 1000 X и 500 Z. Просто сделайте что-нибудь простое, например, разделите на 100, и прибавьте это к скорости объекта, чтобы она двигалась в 10 раз и 5 лет по направлению к объекту. Каждый раз, когда вы обновляете, добавляйте скорость снова.
Возможно, вам также понадобится максимальная скорость. Это ОЧЕНЬ легче вычислить, работает хорошо, и даст вам эффекты, как в игре STAR CONTROL, где есть планета, или корабли немного притягиваются друг к другу гравитационно. Я сделал это с 10 планетами и звездой, и пользователь мог в основном делать лунную посадку на каждой планете. Это был взрыв, но я никогда не превращал его в настоящую игру. Это имеет преимущество в том, что он невероятно быстр для расчета. Существуют некоторые граничные условия, например, если вы делаете карту тором, чтобы они деформировались по сторонам карты, но в основном это всего лишь простое сложение и вычитание.
Это достаточно хорошо для игры. Вы не делаете симулятор. Вы делаете игру.
Я не уверен, но попробуйте изменить часть, в которой вы рассчитываете значения xAccel и yAccel, примерно так.
xDistance = XComponentObject1 - XComponentObject2;
yDistance = YComponentObject1 - YComponentObject2;
(xDistance and yDistance can have negative values)
Distance = sqrt( xDistance^2 + yDistance^2 );
gConstant = constant Value for gravitational strenght in your world;
MassObject1 = some Mass;
MassObject2 = some other Mass;
Accel = gConstant*MassObject1*MassObject2 / (Distance^2 );
''NOW COMES THE IMPORTANT PART''
xAccel = Accel * xDistance/Distance;
yAccel = Accel * yDistance/Distance;
Я думаю, что вся ваша йадада с синусом и косинусом создает целую кучу ошибок, которые трудно отследить.