!ux2_branch1_dev0
This description is now used for the SkyModExamples guide.
This post documents how some changes to the SimplePlanes sky can be achieved through modding. This guide assumes basic knowledge of Unity and C#.
Example GitHub repository with SPMOD. View the full scripts and download the SPMOD from there. Feel free to use the scripts shown here, Examples2.cs
is usable "out of the box". While the following sections show some code snippets, you will need the full scripts to see how they are used in a larger program. The SPMOD contains:
ChangeSkyBrightness
command that can be run in the main menu or sandbox.- "Skybox Replace Test" sandbox map. This map uses the "Cold Sunset" skybox in AllSky Free.
[ Open SPMODing ] This guide and my mod source code repositories are intended to help those that may have an interest in programming. Promote community learning!
Contents
- Basics
- Sky References
- Sky Modification
- Sky Replacement
1. Basics
This section provides some basic technical information.
The SimplePlanes sky is controlled by the Time of Day (TOD) asset, of which documentation exists online.
Since TOD contains its own classes that aren't part of C# or Unity, it's not possible to access them without bundling them with the mod. Of course, this is not practical due to its price.
Luckily, C# has a feature called reflection, which allows us to use TOD types and classes without having to physically include them in the mod. The online documentation can be consulted to find out which parameters are available for editing.
While we are using reflection here, we do not need to use the SP Reflection Tools package.
2. Sky References
This section demonstrates how to get the main TOD objects for processing in Sections 3 and 4.
The first step is to get a reference to the TOD_Sky
component, which is the master component and responsible for controlling others. At the same time, get the reference to its host GameObject. This will facilitate getting the other components.
Here are the first three fields we need to populate. Notice how we store the Type of TOD_Sky
in addition to the reference to the actual instance of TOD_Sky
.
// [Examples.cs ~ Lines 7 to 14]
// Sky Dome GameObject.
private GameObject SkyDome;
// Sky Dome "TOD_Sky" component type
private Type SkyComponentType;
// A reference to the actual component of type "TOD_Sky"
private object SkyComponent;
Notice how we can compare the Type name to any string, in this case the known TOD_Sky
Component Type. This module finds one component of any Type, but should only be used if only one component of that Type exists in the scene.
Note: Even though we know the names of the Sky Dome GameObjects in the main menu and sandbox, we should rely on GameObject names as little as possible. This is because they are more likely to be changed in updates than Type names.
// [Examples.cs ~ Lines 34 to 45]
// Get all components, and looks through them to find a TOD_Sky component
Component[] AllComponents = FindObjectsOfType<Component>();
foreach (Component c in AllComponents)
{
if (c.GetType().Name == "TOD_Sky")
{
// Saves Sky Dome information
SkyDome = c.gameObject;
SkyComponentType = c.GetType();
SkyComponent = c;
}
}
If a different TOD component is required, it can be obtained by changing the compared Type. To get more than one component from this foreach
block, add else if
block(s). If you like switch
statements, it works too.
3. Sky Modification
This section demonstrates getting Fields in TOD components.
Before starting, make a note of the location of each Field you want to modify in your mod. In this example, we will choose the Brightness
parameter, found in the Type TOD_AtmosphereParameters
. Like before, we store both the instance of the object, and its Type.
Note that "Attributes" as listed in the documentation are actually called Fields in C#, and Attributes are something different.
// [Examples.cs ~ Lines 16 to 23]
// "TOD_AtmosphereParameters" type found in "TOD_Sky"
private Type AtmosphereType;
// A reference to the object of type "TOD_AtmosphereParameters" in SkyComponent
private object Atmosphere;
// The brightness field defined in the "TOD_AtmosphereParameters" type
private FieldInfo BrightnessField;
Get the TOD_AtmosphereParameters Atmosphere
Field in the TOD_Sky
component, and hence get the Brightness
Field.
// [Examples.cs ~ Lines 54 to 73]
// Get all fields in the TOD_Sky type,
// and looks through them to find the Atmosphere field
FieldInfo[] fields = SkyComponentType.GetFields();
foreach (FieldInfo field in fields)
{
// also try (field.FieldType.Name == "TOD_AtmosphereParameters")
if (field.Name == "Atmosphere")
{
AtmosphereType = field.FieldType;
Atmosphere = field.GetValue(SkyComponent);
// Get all fields in the TOD_AtmosphereParameters type,
// and looks through them to find the Brightness field
FieldInfo[] atmoFields = AtmosphereType.GetFields();
foreach (FieldInfo atmoField in atmoFields)
{
if (atmoField.Name == "Brightness")
BrightnessField = atmoField;
}
}
}
Once we have the Brightness
Field and the object with that Field we want to modify, we can use SetValue()
to write a value to it.
private void ChangeSkyBrightness(float brightness)
{
BrightnessField.SetValue(Atmosphere, brightness);
}
Download the example SPMOD in the GitHub repository, and run the command ChangeSkyBrightness
. Watch the sky's brightness change according to your entry, keeping in mind that 1.5
is the default value.
4. Sky Replacement
This section demonstrates how to remove the TOD system and add a custom skybox.
We have previously learnt that TOD_Sky
is the main Component used in the TOD sky asset. However, to replace the sky, we must get the TOD_Components
Component instead. This Component holds references to all GameObjects used by TOD to generate the sky at runtime.
Try to convert the Component-finding example code in Section 2! It should look like this.
// [Examples2.cs ~ Lines 19 to 29]
// Similar Component finder to the first example
Component[] AllComponents = FindObjectsOfType<Component>();
foreach (Component c in AllComponents)
{
if (c.GetType().Name == "TOD_Components")
{
SkyDome = c.gameObject;
SkyComponentHolderType = c.GetType();
SkyComponentHolder = c;
}
}
To remove the default TOD sky, all its GameObjects must be destroyed. Find all GameObject fields in the TOD_Components
Component and destroy them. After that, destroy the Sky Dome itself to remove the TOD scripts. (While not strictly necessary, it will prevent NullReferenceException
s from appearing in the dev console.)
// [Examples2.cs ~ Lines 36 to 51]
// Similar Field finder to the first example
FieldInfo[] fields = SkyComponentHolderType.GetFields();
foreach (FieldInfo field in fields)
{
// Get all GameObjects referenced by TOD and destroy them
if (field.FieldType.Name == "GameObject")
{
GameObject RefGameObject = (GameObject)field.GetValue(SkyComponentHolder);
Debug.Log("Destroyed GameObject " + RefGameObject.name);
Destroy(RefGameObject);
}
}
// Finally destroy the Sky Dome itself to prevent errors from appearing in the dev console
Debug.Log("Destroyed GameObject " + SkyDome.name);
Destroy(SkyDome);
Change the skybox with your own, and set up the cameras to use it. From running tests in the dev console, Camera (MainCamera)
has the lowest depth
value, and so it is the one to be modified. However, due to the existence of multiple cameras tagged MainCamera
in the sandbox, we cannot use Camera.main
to get the proper camera.
In this example, the lowest Camera is selected by name, but it is also possible to use the depth
value to find the Camera.
// [Examples2.cs ~ Lines 53 to 64 (modified)]
// Replace the skybox
RenderSettings.skybox = SkyboxMaterial;
// Set up the Main Camera to use the skybox
MainCamera = GameObject.Find("MainCamera").GetComponent<Camera>();
MainCamera.clearFlags = CameraClearFlags.Skybox;
Debug.Log("Applied settings on Camera " + MainCamera.name);
When making your map, keep in mind that the Directional Light controlled by TOD is also destroyed by the skybox replacement script. You must add your own Directional Light.
Specifications
General Characteristics
- Created On Android
- Wingspan 16.4ft (5.0m)
- Length 15.0ft (4.6m)
- Height 23.3ft (7.1m)
- Empty Weight 7,523lbs (3,412kg)
- Loaded Weight 7,523lbs (3,412kg)
Performance
- Power/Weight Ratio 17.922
- Wing Loading 439,839.3lbs/ft2 (2,147,483.6kg/m2)
- Wing Area 0.0ft2 (0.0m2)
- Drag Points 15233
Parts
- Number of Parts 198
- Control Surfaces 0
- Performance Cost 619