Skip to content

Setting up your vehicle GameObject (in Unity)

Michael Neises edited this page May 20, 2024 · 10 revisions

Setting Up Vehicle GameObject in Unity for Vehicle Framework

Introduction

This guide will help you take a (visually game-ready) vehicle model that you have in Unity and set it up so that Vehicle Framework is ready to work with it.

Prerequisites

What I Assume You Already Have:

  • Unity installed and basic knowledge of its interface
  • Basic understanding of GameObjects in Unity
  • Basic understanding of the transform hierarchy
  • Your model imported into Unity and looking good

Getting Started

Vehicle Framework requires that certain parts of the vehicle are named in a certain way, and it also requires the presence of a few "administrative" game objects. This guide will help you configure your vehicle game object the right way. We'll start with the quickest parts and end on the most time-consuming part: collision modelling.

A few necessary naming conventions

  • It is critical that "lights_parent" be named exactly that, and be at the top-level of the hierarchy. This is for compatibility with Tweaks and Fixes.

  • The lights of your vehicle must have "light" in their name. This is so no shader is applied to the lights. In the lights_parent breakout image above, the example objects here are those such as the "headlights3" and "floodlights4" objects. Those objects will be appropriately skipped by Vehicle Framework.

  • The windows of your vehicle must have "Canopy" in their name. This is so their transparency can be handled specially by Vehicle Framework.

ModulesRoot

This is where your installed upgrade modules will live within your vehicle's transform hierarchy. The position and rotation don't matter. It has no special components.

StorageRoot

This is where your stored good will live within your vehicle's transform hierarchy. The position and rotation don't matter. It has no special components.

lights_parent

This GameObject must be at the top of the hierarchy and it must be named "lights_parent" for compatibility reasons (Tweaks and Fixes). lights_parent should have two children: "headlights" and "floodlights"

  • headlights: these are the lights that will trigger when you right click while piloting. They light up what's visible through your viewport.
  • floodlights: these are lights you can toggle on the control panel. They can light any direction.

Within each of those, there are individual lights, so the hierarchy might look like: model>lights_parent>headlights>light1>VolumetricLight

The "VolumetricLight" object is necessary to create the visible light cone that you can see when you're outside the vehicle.

The lights_parent, headlights, and headlight1 etc are all simple transforms (empty gameobjects). They have no special components (no lights either). The only important transforms are those of individual lights like headlight1 or floodlight1. These lights must be rotated so that Z-Positive points towards where the beam of light should point. The VolumetricLight child of each light should have position and rotation identical to its parent (so that the volumetric beam matches that actual beam).

Control-Panel-Location

This is the position and rotation of the control panel that VehicleFramework will install into your vehicle model. You can include a control panel in your vehicle AssetBundle. If you don't, VehicleFramework will provide you with one. However, you must provide this "-Location" object that is a placeholder for the control panel.

Fabricator-Location

This is the position and rotation and localScale of the fabricator that VehicleFramework will install into your vehicle model. It's a placeholder for the actual model.

TetherSources

This is an empty game object whose position and rotation don't matter. However, each of its children is considered to be a tether source, so their positions are important (but their rotations don't matter). You should space these throughout the inside of your ship. If your vehicle is a good scale and is a good scale in-game, then these tether sources should be about 1m apart and cover the whole interior. For example, the Atrama and Odyssey have 2 and 3 each, so not that many are required.

The purpose of the tether sources is to keep the player "in the ship" or "out of the ship" as necessary. These help control the state of the vehicle and let the player teleport into and out of the vehicle without weird gravity issues happening.

In the above image, I've added some cubes to the tether sources so that you can see how they are positioned within the Abyss. The scale of the cubes is unimportant- only their positions matter.

WaterClipProxies

This is an empty game object whose position and rotation don't matter. However, all of its descendants are considered to be a water clip proxy, so their positions, rotations, and scale are important. These important objects must also have a "Mesh Filter - Cube." In this way, we'll cover the vehicle in cubes. The purpose of these cubes is to prevent the Subnautica "ocean surface" from clipping into the vehicle. This is important to maintain the illusion of the vehicle as an immersive experience.

The best way I've found to do this is to create a child within WaterClipProxies and add a Cube 3D object to it. Then transform the scale of the gameobject that owns the cube rather than changing the cube itself. The cube will stretch and shrink and you can use it to paint a box over your whole vehicle.

You should cover at least the whole inside, so that "no water gets in." However, if you draw too big a cube, there will inexplicably be no ocean surface around your vehicle.

The image shows the 3D cubes to help visualize the water clip proxies. Be sure to disable or delete the cubes before exporting your AssetBundle.

BoundingBox

The BoundingBox should be a GameObject whose parent is the top-level vehicle. The BoundingBox should have a transform with localPosition and localScale as Vector3.zero and Vector3.one, respectively. The BoundingBox should have a BoxCollider. Only the BoxCollider should be modified to circumscribe the vehicle (don't adjust the transform).   The purpose of this box is twofold. First it, gives the little Build Bots a meaningful path to trace while they construct your vehicle. Second, it allows VF to determine whether your vehicle will fit (and how to place it) in a Moonpool or Cyclops dock.

The image shows the 3D cube to help visualize the bounding box.

PilotSeat

PilotSeat has a Collider and two children. The collider should encompass the chair that you'll use to pilot the ship. This will let you click on the chair and not pass through it. The two children are SitLocation and ExitLocation:

  • SitLocation: this is where the player will be teleported to sit at when you begin piloting
  • ExitLocation: this is where the player will be teleported to when they stand up from piloting

In the following image, you can see the seat and its collider

In the following image, you can see the placement of the SitLocation

In the following image, you can see the placement of the ExitLocation

Hatches

Hatches have children that are important. Each child corresponds to a hatch going into and out of your vehicle. Each hatch has several important descendants.

  • InsideHatch corresponds to that hatch when accessed from the inside of the ship. It has a collider so that the player can touch it.

  • OutsideHatch corresponds to that hatch when accessed from the inside of the ship. It has a collider so that the player can touch it.

  • Entry is an empty gameobject that designates to where the player will teleport when they use this hatch to enter the ship.

  • Exit is an empty gameobject that designates to where the player will teleport when they use this hatch to exit the ship underwater.

  • SurfaceExit is an empty gameobject that designates to where the player will teleport when they use this hatch to exit the ship at the ocean surface.

In the above image, you can see how many cube objects were added to the hatch to create a walkable and nicely clickable interior hatch.

For the Submersible case, the entry location is not used. Instead, the Submersible gets this value from its sole PilotSeat.

UpgradesInterface

It has a collider that corresponds to the touch interface of your upgrade slots. When the player clicks on this, they'll be shown the screen where they can insert and remove upgrade modules. Right now, this should be a cover for that part on your vehicle. When clicked, the cover will rotate away and reveal the inside.

Batteries

The position and rotation of this object don't matter, but those of its children are important. Every child of this object will be considered a battery interface and should thus have a collider. When the player clicks on it, they'll be given the option to insert or remove a battery.

InnateStorages

This is exactly like the Batteries. However, when the player clicks on it, they'll be given the option to store or retrieve things from storage.

CollisionModel

The purpose of the CollisionModel (besides colliding with the world) is to ensure Leviathans interact appropriately with the vehicle. For example, the Reaper Leviathan will disable the CollisionModel during when it grabs the vehicle. Problematically, it will grab the vehicle at the vehicle's center, which sometimes may not be a natural place to grab. This can cause bizarre physics-sickening behavior when the reaper grabs a vehicle in a way where some of the vehicle goes into the reaper's body. For this reason, you should ensure at this step that the center of your vehicle is relatively near the front:

This is a collection of colliders. The colliders can exist anywhere within the transform hierarchy of CollisionModel. You must place colliders in a way that keeps the player inside the vehicle without inhibiting their movement, and the seams should be tight such that no fish can wiggle in. In the simplest format, this requires 6 "faces" of a "cube" that represents your vehicle. Each "face" in such an example would be long and tall but thin, because they form the walls, floor, and ceiling of the vehicle.

I try to use cube colliders for everything because they're "fast." Unfortunately you can't just use a mesh collider for your model. Even if it behaves correctly in the game, the log will be spamming about how non-convex mesh colliders can't be kinematic rigidbodies and stuff like that. So you have to painstakingly approximate the colliders of your vehicle with cubes for the best results.