On this page
Build your game

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:

C#
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

C#
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:

C#
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

(c) 2014 - 2026 BoneCracker Games - City Car Driving Simulator 1.6Back to top ↑
Document details

Generated from: 02_Build_Your_Game/04_Customization_And_Garage.md
Date: 2026-09-15 07:52
(c) 2014 - 2026 BoneCracker Games - City Car Driving Simulator 1.6