A Game About Managing Satellites
14 Feb 2024 Update: After a long time without touching this project, I've made the decision to restart it in Godot. The reason for the break in development was the complexity of implementing a save system. I made some progress in Unity, but retrofitting it to existing code was a huge pain. Now knowing what needs to be done, I can structure code a lot better. I can alos port over a lot of the code and algorithms.
I'm starting this write up after a good chunk of development, so the early posts are not dated.
I'm making a game about launching and managing your own constellation to complete various missions. Here's a short list of features:
- 3D view of the all satellites in orbit
- Select-able satellites to see details and command them
- Missions include data relay, imagery, science experiments, and grappling
- Simplified physics: fuel is measured in delta V, the Earth is perfectly spherical, there is no moon, etc.
In Unity, the basic building block is the "game object". Game objects can contain other game objects (child-parent relationship) and "components". Components are the real workers, being things like scripts, 3D meshes, lights, 3D meshes (but for physics), etc. A useful principle of Unity is using "prefabs". For those familiar with object oriented programming, this is equivalent to a class.
All game objects have a component called the "transform". This defines the location, rotation, and scale of the object. Even game objects that aren't shown to the player (e.g. one that controls sound effects) have a transform.
Understanding the systems Unity provides you and designing your architecture around that can make building games a lot easier.
The primary game loop will be launching and managing satellites to accomplish certain missions. Completing these will reward money, which is used to launch more satellites. Satellites have finite fuel and must use some to maintain their orbit, so they have a certain lifespan. Is this fun? I'm not sure yet. If it's not fun to build a constellation slowly like a tycoon game, then I could switch to a level system where each level has specific missions and money to complete those missions. If it's not fun, then fuck it, this is the first game I've made and this is a hobby.
The game will use realistic-ish physics. Since this is a game and I'm not an astrophysicist, I'm not accounting for fancy things like the Moon. Maneuvering a satellite uses fuel, so we need a way to measure it. I'm using delta V instead of an actual volume of fuel. This avoids complicated calculations like how firing a thruster with a full gas tank will have less effect than with an empty one; required for actual satellites, but probably not interesting for someone playing this in their free time.
Since I'm making the Earth a sphere, I can just make a couple spheres in Unity. One is the Earth and the other is the Sun. I don't think Unity will actually let you place the Sun a realistic distance away, so I'm making it smaller so it looks sort of right.
The Earth is set to rotate at the proper speed, and the Sun set to orbit the Earth (This isn't a real simulator, we can cheat). Checking the Sun's rotation is a little difficult since it moves so slowly, even at x50 speed, but letting it run for a while shows that it does move.
Each satellite is a single game object with a few components: a main script, 3D mesh, a trail renderer, a line renderer, and a maneuver preview script.
The main script contains all the normal functions like the force of gravity being applied, moving through the scene, rotating to point at the Earth, etc. Pretty much all code for the satellite is here.
The mesh is simply the 3D model used for the satellite. Satellites are tiny compared to the Earth, so I may change this to be a large sphere or something.
The trail renderer is used to convey where the satellite is.
The line renderer is used to display the current orbit of the satellite.
The maneuver preview is used when a speed and direction are typed in for a maneuver, but the player hasn't confirmed it. It shows what the satellite's orbit will look like after the maneuver, assuming it occurs right now.
The main script has a lot of variables.
I won't go through every one, but rather the categories they each fall under.
Physics Parameters: The main important ones are position and current velocity.
Classical Orbital Elements: Each COE is calculated and stored by the satellite. These are only used for the UI and a couple for calculating the ellipse to show the orbit path.
Payload: The type of payload, fuel remaining, etc. Come to think of it, the payloads may have been better off handled by a different script.
Misc Useful parameters: Things like angular velocity and the vector pointing straight back to Earth aren't inputs or outputs, but are useful middle steps to calculating other variables. There are some for if the orbit is circular or not and a few references to other game objects for getting their information.
I have also assigned several other public variables so I can watch them in the Unity editor to help with debugging. Hopefully I remember to remove these in the final build.
I wanted to have the camera focused on the Earth, and have it so the player can right-click drag to have the camera orbit. The scroll wheel also will zoom in and out. After a little Googling, I found this Stack Overflow question about this exact thing. The basic idea is to create an invisible sphere that the camera attaches to. A small script rotates the sphere, thus moving the camera. The scroll-wheel also controls the local y-position of the camera. Since the local y-axis will rotate with the sphere, this is functionally the distance between the camera and center of the Earth.
If you want to be able to adjust the focus of the camera, you can simply set the position of the invisible sphere to match the target object.
I'm no UI artist. I'm okay with a pencil or camera, but this is very unfamiliar territory for me. There is some information that the player needs, some that is nice to have, and then an infinite number of ways to present it. I'll start with the default UI artwork from Unity and work on the actual aesthetics of it later. First, the info the player needs to have:
- A list of satellites
- The ability to select a satellite to command
- The ability to view the orbits & positions of satellites
- Orbital Elements and payload information of the selected satellite
- A list of missions and their details upon selection
The first item I tackled was the list of satellites since this is sort of required for everything else to work.
The list of satellites is made using Unity's "Scroll View" object. This has a gameObject that acts as a container for things that will show up in the window.
In this content bucket, I added a "Vertical Layout Group" component and a "Toggle Group". The layout group will make sure all sub-items will arrange themselves neatly according to it's adjustable parameters. The toggle group will be used to make sure that only only 1 satellite can be focused on at a time. This focus is used to determining which satellite's information should be shown in the details panel and be the target of the maneuver panel.
Each entry in this list is a modified version of the "Toggle" UI object. The checkbox has been moved and stretched so it acts like a highlighter, showing which satellite is selected. This toggle is added to the toggle group for the list, making it so only 1 toggle can be active at a time. I also added another toggle as a child object to this one. This sub-toggle is used to select which orbits are visible. This screenshot shows 2/3 satellites displaying their orbits as well as the 3 UI panels for satellite interaction:
Since no satellite is selected, the details panel shows nothing. When a list entry is clicked, a function is called on the entry which links back to the actual satellite game object. It gets the details from the satellite and changes the text values of the details panel.
I've made a lot of progress on creating a mission system to give the player something to do. Borrowing a lot of code from the satellite list, ecah mission gets added to a list. Selecting them shows details about it. There are imaging, comm, and grapple missions.
Image missions are a point on the surface of the Earth. If an imaging satellite passes over it, it marks itself complete. Comm missions are 2 points on the surface; if a comm sat covers both, it's marked complete. Grapple missions are more complicated. They spawn a satellite of the "target" type. A grapple satellite can match the orbit of a target, get close, and grab it. This is done by disabling the Update() function of the target, and setting it's position to match the satellite grabbing it.
I've also made the 3d model for satellites just a sphere. This shows where the satellite is better than a trail, and will match the 80s interface look I'm going for.
The mission system is a GameObject which is a child of the Earth. It contains 3 "bucket" game objects that hold each mission type. This setup means that for the image missions, the transform is just set to somewhere 1 earth-radius away from the origin and it will automatically match the Earth's rotation. Comm missions contain 2 points that follow this same setup.
When I made the grapple missions spawn a target satellite, they used the same script as regular satellites, but their physics were not behaving correctly. They seemed to have far too much velocity. It turns out, the same "stick-to-the-Earth" feature was adding the rotation of the Earth to their velocity. Making their "bucket" game object its own (not a child of the Earth object) fixed this.
Back to Top