Customization and the Garage
Sell paint, wheels, spoilers, decals, neons and performance upgrades to the player, and persist what they bought.
How the pieces fit
| Piece | Owner | Role |
|---|---|---|
| Applying the change to the car | RCCP RCCP_Customizer |
Paint, wheels, spoilers, decals, neons, sirens, upgrades |
| Charging the player | CCDS_UI_PurchaseItem / CCDS_UI_PurchaseUpgrade |
Price display, affordability, purchase |
| Remembering it | CCDS_SaveGameManager |
Save keys in the JSON save file |
| Getting the player there | CCDS_Marker_Garage |
Drives the player back to the main menu |
CCDS does not re-implement customization. It wraps RCCP's customizer with a purchase and persistence layer.
The vehicle must be customizer-ready
The customization UI does nothing on a vehicle without RCCP_Customizer. When CCDS adds player components it configures the customizer for you:
| Property | Set to | Why |
|---|---|---|
autoInitialize |
true |
The customizer sets itself up on spawn |
autoSave |
false |
CCDS owns persistence |
autoLoadLoadout |
false |
CCDS decides when a loadout is applied |
If you add RCCP_Customizer by hand, match these. Leaving autoSave on gives you two systems writing the same state, and RCCP's copy will win at the wrong moment.
Items and upgrades
Everything purchasable is a CCDS_CartItem:
| Field | Type | Purpose |
|---|---|---|
itemType |
CartItemType |
Routes the purchase to the right RCCP subsystem |
saveKey |
string |
Unique key persisting ownership |
itemName |
string |
Shown in the UI |
price |
int (≥ 0) |
Cost in in-game currency |
CartItemType has eight values:
Paint · Wheel · Spoiler · Decal · Neon · UpgradeEngine · UpgradeHandling · UpgradeSpeed
Save keys are the identity of an item. Two items sharing a key share ownership. Changing a key on a shipped game makes previously bought items look unowned. Prefix them — paint_red, wheel_sport_01, upg_engine — and never reuse.
One-off items
CCDS_UI_PurchaseItem handles anything bought once.
| Field | Purpose |
|---|---|
item |
The CCDS_CartItem |
pricePanel |
Hidden automatically once owned |
priceText |
Formatted price label |
isPurchased |
Runtime flag — refreshed on enable, do not set by hand |
It implements IPointerClickHandler, so the purchase fires from a UI click.
Levelled upgrades
CCDS_UI_PurchaseUpgrade handles engine, handling and speed, which are bought repeatedly.
| Field | Default | Purpose |
|---|---|---|
item |
— | The CCDS_CartItem, typed UpgradeEngine / UpgradeHandling / UpgradeSpeed |
maximumLevel |
5 |
Level at which the upgrade is complete and the price panel hides |
pricePanel |
— | Auto-hidden at max level |
priceText |
— | Price of the next level |
The price is not fixed. It scales with the current level:
UpgradePrice = (int)(Mathf.InverseLerp(0, 6, UpgradeLevel + 1) * (defaultPrice * 1.5f));
So the displayed price rises each level, and the price on the cart item is a base figure, not what the player pays. Set price and check the resulting curve in play mode rather than expecting the literal number.
What an upgrade actually changes
Upgrades act on the RCCP upgrade components, whose efficiency ceilings come from the vehicle roster:
| Upgrade | Component | Ceiling from |
|---|---|---|
| Engine | RCCP_VehicleUpgrade_Engine |
upgradedEngineEfficiency |
| Handling | RCCP_VehicleUpgrade_Handling |
upgradedHandlingEfficiency |
| Speed | RCCP_VehicleUpgrade_Speed |
upgradedSpeedEfficiency |
All three default to 1.2 — a fully upgraded car is 20% better than base. Raise them per vehicle in CCDS_PlayerVehicles.asset; see Add Your Own Vehicle.
A vehicle missing one of these components accepts the purchase and applies nothing. Check the prefab has all three before shipping a car.
Wheels
Selectable wheels live in CCDS_ChangableWheels.asset in Assets/CCDS/Resources/:
| Field | Purpose |
|---|---|
wheels[] |
Ordered list of wheel sets |
wheels[i].wheel |
Wheel prefab — complete mesh and collider |
As with vehicles, the array index is the persistent ID written to the save file's ownedWheels. Append; do not insert or reorder.
Scripting purchases
using BoneCrackerGames.CCDS;
// One-off items
if (!CCDS.IsItemPurchased("paint_red")) {
if (CCDS.GetMoney() >= 500) {
CCDS.ChangeMoney(-500);
CCDS.PurchaseItem("paint_red"); // marks owned and saves
}
}
// Levelled upgrades
CCDS.PurchaseUpgrade("upg_engine");
bool owned = CCDS.IsUpgradePurchased("upg_engine");
PurchaseItem and PurchaseUpgrade both call Save() themselves — no separate save is needed.
Neither one charges the player. Deduct with ChangeMoney yourself, and check affordability first; there is no built-in guard against negative balances.
Vehicle ownership
Separate from items:
CCDS.IsOwnedVehicle(3); // owned?
CCDS.UnlockVehicle(3); // grant
CCDS.LockVehicle(3); // revoke
CCDS.UnlockAllVehicles(); // useful while testing
CCDS.SetVehicle(3); // make it the active selection
The index is the position in CCDS_PlayerVehicles.playerVehicles. A vehicle priced 0 is owned from the start.
The garage marker
CCDS_Marker_Garage is a trigger volume that returns the player to the main menu, which is where customization happens.
Enter it and remain inside for 3 seconds. Leaving early cancels. There is no key to press.
Place one where the player would expect a garage. Its collider must be a trigger and large enough that a car at speed cannot pass through in under three seconds.
Persistence
Customization state lands in the JSON save file in Application.persistentDataPath:
| Save data | Holds |
|---|---|
ownedVehicles |
Owned vehicle indices |
ownedWheels |
Owned wheel indices |
| purchased items | Keyed by saveKey |
| purchased upgrades | Keyed by saveKey, with level |
vehicleCustomization |
Per-vehicle RCCP loadout as a JSON string |
Clear it while testing with Tools → BoneCracker Games → CCDS → Delete Save Data, or CCDS.ResetGame() at runtime.
Common problems
| Symptom | Cause |
|---|---|
| Customization UI does nothing | No RCCP_Customizer on the vehicle |
| Purchases forgotten between sessions | Duplicate or changed saveKey |
| Upgrade bought, car unchanged | Missing RCCP_VehicleUpgrade_* component |
| Price differs from the cart item | Expected for upgrades — the price scales with level |
| Player goes negative | Nothing deducts automatically; check GetMoney() before ChangeMoney |
| Wheels resolve to the wrong set | CCDS_ChangableWheels.wheels was reordered |
| Garage marker never fires | Collider is not a trigger, or the player leaves before 3 seconds |
Next
- Add Your Own Vehicle — where the upgrade ceilings are set.
- Scripting API — the full money and ownership surface.