Comunidad Game Maker

Ayuda => Preguntas y respuestas => Mensaje iniciado por: pixel rojo gamer en Septiembre 14, 2018, 08:32:23 PM

Título: Simulador de mecánica orbital (órbitas elípticas) al estilo Kerbal Space Program
Publicado por: pixel rojo gamer en Septiembre 14, 2018, 08:32:23 PM
Estoy intentando hacer un simulador de mecánica orbital en 2D. Tomen como referencia a los siguientes juegos:


Así como Angry Birds tiene una forma de predecir sus trayectorias parabólicas, los juegos dichos también predicen las trayectorias elípticas:
(https://i.pinimg.com/originals/b2/24/76/b224767c7aaf07cac2f24ff958946f61.jpg)
(http://kspmods.net/wp-content/uploads/2015/10/screenshot288.jpg)

¿Cómo podría hacer esto último en Game maker? (A partir de mi código)

Mi juego, por el momento consiste en un objeto Sol (oSol) al centro y un objeto player (oPlayer) que está orbitando a su alrededor.

Evento Create de oPlayer

x=oSol.x;
y=oSol.y-350;

hspeed=0.3;


Evento Step de oPlayer

//Codigo de gravedad hacia el Sol
var g, DirG;
with (oSol){
   g = masa/sqr(point_distance(x, y, oPlayer.x, oPlayer.y)); //Ley de gravitacion F=GM/r^2
   DirG = point_direction(oPlayer.x, oPlayer.y, x, y); //Direccion de la gravedad
   with (oPlayer) {motion_add(DirG, g);} //Aceleracion de la gravedad
}


Evento Create de oSol
masa=25;

Evento Keyboards de oPlayer
hspeed -= 0.001; //<Left>
vspeed -= 0.001; //<Up>
hspeed += 0.001; //<Right>
vspeed += 0.001; //<Down>



Lo que necesito saber es qué poner en el evento Draw para lograr hacer algo como lo que dije... Desde ya, muchas gracias!!
(https://upload.wikimedia.org/wikipedia/commons/thumb/7/73/Newton_Cannon.svg/240px-Newton_Cannon.svg.png)
Título: Re:Simulador de mecánica orbital (órbitas elípticas) al estilo Kerbal Space Program
Publicado por: Clamud en Septiembre 16, 2018, 07:05:12 PM
Se puede hacer de esta forma, pero no es la más eficiente.
Puedes ver como funciona aquí: Ejemplo en GMLive (https://yal.cc/r/gml/?mode=GL&tabs_lz=NobwRAdghgtgpmAXGA8gJwEYEsAuYA0YAxgPYAmCyA9DQAQDCacUOctAogG5wQ4A6aPhDoAFADZQIcfoIgAPWgF5aaSWRIwA+qogBzOAAoATAAYT+WgGYzASgDcAoQE8lKtRu2T9xsxesn7Rwg0VwBWEztaGlUyLABXAGcg3VcARjNIml1VTlwXFlpYhJxJIjZUoKC6ACE4sTFpIIwFZR11LR1vdPNaABZbB1kMF1b3Dq9Dbot+gMGhDBDlXsyqGLisJNlc1zaPTsMTADpUiyOADnsoqiwIXCwoMVpuMRIiPKDYnbGDSwA2WauNzuD0KWCYRBwWBIEEqsgAxBQAGY3NhkVQAdyuVFoABEMRxuLxYUI6HioJiAA4SKQyIRo8maBLSTSkF5oAxETQYMRxOCBWT09HaOAQrwNHzmUw9fz4GW0HBoXn8ukYllgojiuQWJwWNAWREPJnKmGyUn4jB1Bq0iCCxnM1kkdmcphkY228ElPTiqZTPq+GYWBVKuY21VvNAawzNCzDGN62gGsRGkNVbFkzGO7DW21MnAskhsjmadEAC1wfJDtszuAMWp1uhjWtjuXwsWNH1VrDkOAM5h6fDAADERABlRC0AcAamKaBuugMiIpCRs7dkQQRcGRUloFJINzzRTzCQAjiE6AkiLOKdbUzu97xQcVSmwT3EoC6gkwcHE0BBaCf2XfXQ4ngXgTFoABaWggJAngcCMGxaEnf9TwMGDQJwVJIOgtBgIwyxVyEdckRRQpVWrHArn-S8sGvYlhGxABBXDYN4TYhE4d8dxaHC8LgiIripSRpFoOQgk4kIKRGXjWMwlYhJpWgnHEriKRSZR0Lgox5OpETsigXIcGUtcti45pXE03hLBWC16hEsTTJCYYLJYjDliuWyrSUlSnM4Fy+N4UIViBSEQQSCk4DgMgfNoDAyH82TfmC25QseWIPShE0iMc2LOB4ho9BwEt0s0OQDAwTgY1dEMJNy6SCt0IqSqccrKti6qYowBtYt0MgVn0wz8htWgBryUEMuhBNHViy1GhMlUGQpWcYDubguTgXQbgMJbNDEFEZ1o40mAilgDHCAJaBAIJaBusiGW4NAu3KpsnEuGhPJE3cEjuaFrtu8zJ2UCq5BWGASG4Ga7OtW7YpcQG6pDGGutcNSojvfdNEPRlUIpLUpMbfBhjeqg4gpMgWDYUajL+m6uvi5Rdwx9KRUhaFnsJnVuPwKTidJ8nWBGnIxuZiFMpp3KFHhhqmrBUryu6unebJin-wiqLxYquHlGl4rZZarqY1640AF8O0W5bVrgTQeDIAx7DAY2AF0gA)
[gml]
// Arguments
var px = argument0; //planet x
var py = argument1; //planet y
var pg = argument2; //planet gravity

var bx = argument3; //bullet x
var by = argument4; //bullet y
var bv = argument5; //initial speed
var bd = argument6; //initial direction

var bvx = lengthdir_x(bv, bd);
var bvy = lengthdir_y(bv, bd);
var bg, bgd; //gravity and gravity direction for bullet

draw_primitive_begin(pr_linestrip);
repeat(500) {
    draw_vertex(bx,by); //bullet position
    bx += bvx; //move bullet
    by += bvy;
    bg = pg / point_dist_sqr(px,py, bx,by); //update gravity
    bgd = point_direction(bx,by, px,py); //update gravity direction
    bvx += lengthdir_x(bg, bgd); //update speed
    bvy += lengthdir_y(bg, bgd);
}
draw_primitive_end();
[/gml]
Dentro de ese script se usa otro script: point_dist_sqr
[gml]
// point distance squared
return sqr(argument0 - argument2) + sqr(argument1 - argument3);
[/gml]
Es mejor que usar point_distance y después elevar al cuadrado, nos ahorramos 2 operaciones.

Sería más eficiente si la trayectoria no se re-dibujara en cada evento Draw. Se podría dibujar en una surface.
También podría calcularse más rápido si se obtiene una ecuación paramétrica a partir de las condiciones inicales, no lo he investigado, pero debe se posible.
Algo que me parece complicado es hacer líneas punteadas con segmentos de longitud igual.