PixelChipCode

Solar System Simulation

Oct 16th, 2024 (edited)
75
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
JavaScript 10.62 KB | Source Code | 0 0
  1. /// Solar System Simulation by oliver @pixelchipcode
  2. /// This simulation creates a pseudo-3D solar system with planets orbiting around a sun.
  3. /// The user can rotate, tilt, and zoom the camera to explore the system, while planets
  4. /// are rendered with proper depth sorting for occlusion effects, meaning planets in
  5. /// front of the sun are drawn on top, and those behind are occluded.
  6. ///
  7. /// Key Features:
  8. /// - **Pseudo-3D Camera**: Camera movement allows for dynamic rotation, tilt, and zoom.
  9. /// - **Planet Occlusion**: Planets are depth sorted to render behind or in front of the sun.
  10. /// - **Interactive System**: Planets and the sun are clickable, displaying relevant data like
  11. ///   orbit radius, size, and orbital period.
  12. /// - **Dynamic Orbits**: Orbits can be toggled on or off via spacebar, adjusting planet speeds.
  13. /// - **Text Display**: When clicking on a planet or the sun, text information is displayed
  14. ///   dynamically, fading out after a few seconds.
  15. /// - **Ease-based Motion**: Smooth transitions in camera angles, zoom, and planet orbits.
  16. ///
  17. /// Key Constants:
  18. /// - **NUM_PLANETS**: Total number of planets in the simulation.
  19. /// - **SUN_SIZE**: Size of the central star (sun).
  20. /// - **SUN_COLOR**: Color of the sun.
  21. /// - **ORBIT_COLOR**: Color for drawing the orbital paths.
  22. ///
  23. /// This system demonstrates occlusion rendering, interactive celestial bodies, and smooth
  24. /// pseudo-3D camera controls, making it an excellent example of dynamic 3D-like simulations
  25. /// in a 2D environment.
  26.  
  27. /// Create Event
  28. // Constants and configuration
  29. #macro NUM_PLANETS 10
  30. #macro SUN_SIZE 30
  31. #macro SUN_COLOR make_color_rgb(255, 208, 21)
  32. #macro BACKGROUND_COLOR make_color_rgb(37, 38, 42)
  33. #macro FONT_COLOR make_color_rgb(192, 191, 193)
  34. #macro ORBIT_COLOR make_color_rgb(96, 99, 101)
  35.  
  36. // Arrays for names and colors
  37. star_names = ["Proxima Centauri", "Sirius", "Vega", "Altair", "Deneb"];
  38. planet_names = ["Kepler-22b", "Proxima Centauri b", "TRAPPIST-1d", "Gliese 581c", "HD 209458b"];
  39. planet_colors = [
  40.     make_color_rgb(239, 52, 36),   // Red
  41.     make_color_rgb(254, 254, 194), // Light Yellow
  42.     make_color_rgb(109, 72, 205),  // Purple
  43.     make_color_rgb(252, 145, 65)   // Orange
  44. ];
  45.  
  46. // Camera and simulation control
  47. view_angle = 0;
  48. target_view_angle = 0;
  49. tilt_angle = 0;
  50. target_tilt_angle = 0;
  51. zoom = 1;
  52. target_zoom = 1;
  53. orbits_active = false;
  54.  
  55. // Text display variables
  56. text_to_display = "";
  57. text_index = 0;
  58. is_displaying_text = false;
  59. text_display_timer = 0;
  60.  
  61. // Sun properties
  62. sun_name = star_names[irandom(array_length(star_names) - 1)];
  63.  
  64. // Initialize planets array
  65. planets = array_create(NUM_PLANETS);
  66.  
  67. // Function to initialize planets
  68. function initialize_planets() {
  69.     var previous_orbit_radius = 0;
  70.    
  71.     for (var i = 0; i < NUM_PLANETS; i++) {
  72.         var planet_name = planet_names[irandom(array_length(planet_names) - 1)];
  73.         var orbital_period = irandom_range(200, 1000);
  74.         var planet_size = random_range(5, 10);
  75.        
  76.         var planet_orbit_radius = (i == 0)
  77.             ? random_range(50, 100)
  78.             : previous_orbit_radius + planets[i - 1].size + planet_size + random_range(20, 40);
  79.  
  80.         previous_orbit_radius = planet_orbit_radius;
  81.  
  82.         planets[i] = {
  83.             name: planet_name,
  84.             orbit_radius: planet_orbit_radius,
  85.             orbit_speed: random_range(0.5, 1.5),
  86.             angle: random(360),
  87.             color: planet_colors[i % array_length(planet_colors)],
  88.             size: planet_size,
  89.             current_speed: 0,
  90.             target_speed: 0,
  91.             orbital_period: orbital_period
  92.         };
  93.     }
  94. }
  95.  
  96. // Function to determine if a point is in front of the sun
  97. function is_point_in_front(dist, angle, _tilt_angle) {
  98.     var cy = room_height / 2;
  99.     return (cy + lengthdir_y(dist, angle) * dcos(_tilt_angle) > cy);
  100. }
  101.  
  102. // Function to sort planets by depth
  103. function sort_planets_by_depth() {
  104.     array_sort(planets, function(a, b) {
  105.         var cy = room_height / 2;
  106.         var y1 = cy + lengthdir_y(a.orbit_radius * zoom, a.angle + view_angle) * dcos(tilt_angle);
  107.         var y2 = cy + lengthdir_y(b.orbit_radius * zoom, b.angle + view_angle) * dcos(tilt_angle);
  108.         return sign(y1 - y2);
  109.     });
  110. }
  111.  
  112. // Function to get clicked object
  113. function get_clicked_object(mx, my) {
  114.     var cx = room_width / 2;
  115.     var cy = room_height / 2;
  116.    
  117.     // Sort planets by depth before checking clicks
  118.     sort_planets_by_depth();
  119.    
  120.     // Check planets from front to back
  121.     for (var i = NUM_PLANETS - 1; i >= 0; i--) {
  122.         var planet = planets[i];
  123.         var dist = planet.orbit_radius * zoom;
  124.         var angle = planet.angle + view_angle;
  125.         var x_rot = cx + lengthdir_x(dist, angle);
  126.         var y_rot = cy + lengthdir_y(dist, angle);
  127.         var ny = cy + (y_rot - cy) * dcos(tilt_angle);
  128.        
  129.         if (point_distance(mx, my, x_rot, ny) <= planet.size * zoom) {
  130.             return {
  131.                 type: "planet",
  132.                 name: planet.name,
  133.                 orbit_radius: planet.orbit_radius,
  134.                 orbital_period: planet.orbital_period,
  135.                 size: planet.size
  136.             };
  137.         }
  138.     }
  139.    
  140.     // Check if sun was clicked (only if no planet was clicked)
  141.     if (point_distance(mx, my, cx, cy) <= SUN_SIZE * zoom) {
  142.         return {
  143.             type: "sun",
  144.             name: sun_name,
  145.             size: SUN_SIZE
  146.         };
  147.     }
  148.     return noone;
  149. }
  150.  
  151. // Function to display object info
  152. function display_object_info(obj) {
  153.     if (obj == noone) return;
  154.    
  155.     if (obj.type == "sun") {
  156.         text_to_display = obj.name + "\nSun Size: " + string(obj.size);
  157.     } else if (obj.type == "planet") {
  158.         text_to_display = obj.name + "\n" +
  159.                           "Orbit Radius: " + string(obj.orbit_radius) + "\n" +
  160.                           "Orbital Period: " + string(obj.orbital_period) + " days\n" +
  161.                           "Size: " + string(obj.size);
  162.     }
  163.     text_index = 1;
  164.     is_displaying_text = true;
  165.     text_display_timer = room_speed * 3;
  166. }
  167.  
  168. // Initialize planets
  169. initialize_planets();
  170.  
  171. /// Step Event
  172. var ease_factor = 0.05;
  173.  
  174. // Toggle orbits
  175. if (keyboard_check_pressed(vk_space)) {
  176.     orbits_active = !orbits_active;
  177.     for (var i = 0; i < NUM_PLANETS; i++) {
  178.         planets[i].target_speed = orbits_active ? planets[i].orbit_speed : 0;
  179.     }
  180. }
  181.  
  182. // Update planet speeds and positions
  183. for (var i = 0; i < NUM_PLANETS; i++) {
  184.     var planet = planets[i];
  185.     planet.current_speed = lerp(planet.current_speed, planet.target_speed, ease_factor);
  186.     planet.angle += planet.current_speed;
  187. }
  188.  
  189. // Camera controls
  190. var rotate_speed = 1;
  191. var tilt_speed = 1;
  192. var zoom_speed = 0.05;
  193.  
  194. if (keyboard_check(vk_left)) target_view_angle -= rotate_speed;
  195. if (keyboard_check(vk_right)) target_view_angle += rotate_speed;
  196. if (keyboard_check(vk_up)) target_tilt_angle = min(target_tilt_angle + tilt_speed, 89);
  197. if (keyboard_check(vk_down)) target_tilt_angle = max(target_tilt_angle - tilt_speed, -89);
  198. if (keyboard_check(vk_pageup)) target_zoom = min(target_zoom + zoom_speed, 2);
  199. if (keyboard_check(vk_pagedown)) target_zoom = max(target_zoom - zoom_speed, 0.2);
  200.  
  201. view_angle = lerp(view_angle, target_view_angle, ease_factor);
  202. tilt_angle = lerp(tilt_angle, target_tilt_angle, ease_factor);
  203. zoom = lerp(zoom, target_zoom, ease_factor);
  204.  
  205. // Text display logic
  206. if (is_displaying_text) {
  207.     if (text_index < string_length(text_to_display)) {
  208.         text_index++;
  209.     } else if (text_display_timer > 0) {
  210.         text_display_timer--;
  211.     } else {
  212.         is_displaying_text = false;
  213.     }
  214. }
  215.  
  216. /// Draw Event
  217. draw_clear(BACKGROUND_COLOR);
  218.  
  219. var cx = room_width / 2;
  220. var cy = room_height / 2;
  221.  
  222. // Draw text
  223. if (is_displaying_text) {
  224.     draw_set_color(FONT_COLOR);
  225.     draw_text(20, 20, string_copy(text_to_display, 1, text_index));
  226. }
  227.  
  228. // Draw orbits behind the sun
  229. draw_set_color(ORBIT_COLOR);
  230. for (var i = 0; i < NUM_PLANETS; i++) {
  231.     var planet = planets[i];
  232.     var dist = planet.orbit_radius * zoom;
  233.    
  234.     for (var angle = 0; angle < 360; angle += 5) {
  235.         var angle_current = angle + view_angle;
  236.         var angle_next = angle_current + 5;
  237.        
  238.         if (!is_point_in_front(dist, angle_current, tilt_angle)) {
  239.             var x1 = cx + lengthdir_x(dist, angle_current);
  240.             var y1 = cy + lengthdir_y(dist, angle_current) * dcos(tilt_angle);
  241.             var x2 = cx + lengthdir_x(dist, angle_next);
  242.             var y2 = cy + lengthdir_y(dist, angle_next) * dcos(tilt_angle);
  243.             draw_line(x1, y1, x2, y2);
  244.         }
  245.     }
  246. }
  247.  
  248. // Draw planets behind the sun
  249. sort_planets_by_depth();
  250. for (var i = 0; i < NUM_PLANETS; i++) {
  251.     var planet = planets[i];
  252.     var dist = planet.orbit_radius * zoom;
  253.     var angle = planet.angle + view_angle;
  254.     var x_rot = cx + lengthdir_x(dist, angle);
  255.     var y_rot = cy + lengthdir_y(dist, angle);
  256.     var ny = cy + (y_rot - cy) * dcos(tilt_angle);
  257.  
  258.     if (!is_point_in_front(dist, angle, tilt_angle)) {
  259.         draw_set_color(planet.color);
  260.         draw_circle(x_rot, ny, planet.size * zoom, false);
  261.     }
  262. }
  263.  
  264. // Draw the sun
  265. draw_set_color(SUN_COLOR);
  266. draw_circle(cx, cy, SUN_SIZE * zoom, false);
  267.  
  268. // Draw orbits in front of the sun
  269. draw_set_color(ORBIT_COLOR);
  270. for (var i = 0; i < NUM_PLANETS; i++) {
  271.     var planet = planets[i];
  272.     var dist = planet.orbit_radius * zoom;
  273.    
  274.     for (var angle = 0; angle < 360; angle += 5) {
  275.         var angle_current = angle + view_angle;
  276.         var angle_next = angle_current + 5;
  277.        
  278.         if (is_point_in_front(dist, angle_current, tilt_angle)) {
  279.             var x1 = cx + lengthdir_x(dist, angle_current);
  280.             var y1 = cy + lengthdir_y(dist, angle_current) * dcos(tilt_angle);
  281.             var x2 = cx + lengthdir_x(dist, angle_next);
  282.             var y2 = cy + lengthdir_y(dist, angle_next) * dcos(tilt_angle);
  283.             draw_line(x1, y1, x2, y2);
  284.         }
  285.     }
  286. }
  287.  
  288. // Draw planets in front of the sun
  289. for (var i = 0; i < NUM_PLANETS; i++) {
  290.     var planet = planets[i];
  291.     var dist = planet.orbit_radius * zoom;
  292.     var angle = planet.angle + view_angle;
  293.     var x_rot = cx + lengthdir_x(dist, angle);
  294.     var y_rot = cy + lengthdir_y(dist, angle);
  295.     var ny = cy + (y_rot - cy) * dcos(tilt_angle);
  296.  
  297.     if (is_point_in_front(dist, angle, tilt_angle)) {
  298.         draw_set_color(planet.color);
  299.         draw_circle(x_rot, ny, planet.size * zoom, false);
  300.     }
  301. }
  302.  
  303. // Handle clicks
  304. if (mouse_check_button_pressed(mb_left)) {
  305.     var clicked_object = get_clicked_object(mouse_x, mouse_y);
  306.     if (clicked_object != noone) {
  307.         display_object_info(clicked_object);
  308.     }
  309. }
Tags: gml gameMaker
Add Comment
Please, Sign In to add comment