Build Consumable Food Pickups in VRChat
A consumable pickup combines three separate systems: the object can be held, the use input changes its state, and multiplayer rules decide whether that change is personal or shared. This guide builds those parts separately so a food prop remains predictable on desktop, in VR, and for late joiners.
Make the pickup reliable first, then add bites, feedback, synchronization, and respawning.
- Create a VRC Pickup with a Rigidbody, Collider, comfortable grip, and Auto Hold.
- Handle OnPickupUseDown and verify one use produces one local bite.
- Store remaining bites in one variable and derive the visible food state from it.
- Add ownership and synchronization only when all players must share the same food item.
- Test pickup, use, drop, late join, depletion, and respawn behaviour in VRChat.
VRC Pickup requires a Rigidbody and Collider. On desktop, OnPickupUseDown and OnPickupUseUp require Auto Hold, so configure the pickup before debugging the Udon event.
Video Companion
Fionna's CyanTrigger tutorial demonstrates the original eatable-food interaction. Use it for the visual construction sequence, then apply the current pickup, state, ownership, and late-join rules below.
Video creator: Fionna
Choose the Interaction Model
Decide whether the food is personal or shared before adding networking.
| Model | State | Player experience |
|---|---|---|
| Local prop | Local variable | Each player sees their own bite count and depletion state. |
| Shared consumable | Synced variable | Everyone sees the same remaining bites and depleted state. |
| Temporary feedback | Local action or network event | Sound, particles, or animation plays without becoming the source of persistent state. |
| Respawning shared prop | Synced state plus VRC Object Sync when transform synchronization is required | The shared item returns to its original location and becomes usable again. |
A local prop is simpler and avoids network traffic. Use shared state only when players are meant to consume the same physical item.
Build the Pickup Object
Create one root GameObject for the pickup and keep its required components together.
Required components
VRC PickupRigidbody- a Collider that covers the grabbable object
- an UdonBehaviour, UdonSharpBehaviour, or CyanTrigger behaviour for the use logic
Add VRC Object Sync when the pickup's position and rotation must be synchronized between players.
Pickup settings
Review these VRC Pickup properties:
| Property | Purpose |
|---|---|
| Pickupable | Allows players to grab the item. |
| Proximity | Sets the maximum pickup reach used by VR and desktop interaction rules. |
| Auto Hold | Keeps the item held after the grab input and enables pickup-use events on desktop. |
| Use Text | Shows the equipped-use prompt when Auto Hold is enabled. |
| Exact Grip | Defines the held position for grip-oriented items. |
| Disallow Theft | Prevents another player from taking the item from the current holder when enabled. |
Use Text should describe the action directly, such as Take Bite or Drink.
Align the Held Pose
Place the Exact Grip transform so the food sits naturally in the hand:
- Position the grip near the part a player should hold.
- Rotate the grip so the edible end faces away from the palm.
- Test left and right hands in VR.
- Confirm the object does not cover the player's view in desktop mode.
- Keep the Collider large enough to grab without extending far beyond the visible prop.
The pickup's Proximity affects how far away it can be selected. Test it at the intended table, shelf, or counter height rather than choosing a value by inspection alone.
Handle Pickup Events
Use VRChat's pickup events for the interaction lifecycle:
| Event | Use |
|---|---|
OnPickup |
Optional held-state feedback or setup. |
OnDrop |
Optional cleanup when the player releases the item. |
OnPickupUseDown |
Consume one bite when the held-use input is pressed. |
OnPickupUseUp |
End a held-use effect when release timing matters. |
For a bite-based food prop, OnPickupUseDown is normally the main input. Keep the bite change on the press event so one press has one defined result.
Store the Bite State
Use one integer such as bitesRemaining as the source of truth.
The use flow should follow this order:
OnPickupUseDown
→ confirm bites remain
→ obtain ownership if this is shared
→ reduce bitesRemaining once
→ serialize shared state when required
→ apply the new visual state
→ play feedback
Clamp the value so repeated input cannot push it below zero. Ignore further consume requests while the item is depleted.
Apply Visual Bite Stages
Represent the food's state with a small list of prepared stages:
| Remaining state | Visual result |
|---|---|
| Full | Show the complete food mesh. |
| Partly consumed | Show the matching bite-stage mesh or material state. |
| Final bite | Show the smallest remaining stage. |
| Depleted | Hide the edible mesh and disable further consumption. |
Only one stage should be active at a time. Drive every stage from bitesRemaining, including after synchronization and respawn. Do not rely on the original use event to be the only place that changes visuals.
For a simple object, separate child meshes for each stage are easier to inspect than a complicated animation. If an Animator is used, make its state a direct result of the bite value.
Add Feedback
Feedback should confirm that a bite was accepted:
- a short local sound
- a small particle effect
- a brief animation
- a visible bite-stage change
Keep personal feedback local unless other players need to observe it. Network events are suitable for temporary shared effects, but VRChat does not replay them for late joiners. The remaining bite count belongs in a synced variable when it must persist in the instance.
Build a Local Consumable
For food that each player consumes independently:
- Keep
bitesRemainingunsynchronized. - Process OnPickupUseDown locally.
- Change only local visual and audio state.
- Reset the local value when the item should become available again.
This model works well for personal roleplay props or food where one player's bites should not remove the item for everyone else.
Build a Shared Consumable
For one shared item:
- Mark
bitesRemainingas synchronized. - Use manual synchronization for the infrequent bite changes.
- Before changing the value, check or transfer ownership to the player using the pickup.
- Reduce the value as the owner.
- Call
RequestSerialization(). - Apply the bite stage locally.
- Apply the received value again in
OnDeserialization.
Only the owner of a networked GameObject can modify its synchronized Udon variables. VRChat sends the latest synced values to late joiners, but does not replay the bite events that produced them.
Synchronize Movement Separately
VRC Object Sync synchronizes a GameObject's position, rotation, kinematic state, and gravity state. It does not replace the bite-state variable.
Use:
- VRC Object Sync for the shared physical transform
- a synced integer for remaining bites
- ownership handling for both movement and state changes
Keep these responsibilities explicit when debugging. A prop can move correctly while its bite count is wrong, or show the correct bite count while its transform is not synchronized.
Add Respawn Behaviour
Choose a clear respawn rule:
| Rule | Trigger |
|---|---|
| Manual reset | A reset button or world-system event. |
| Depletion reset | The item respawns after its final bite and the chosen reset condition. |
| Drop-zone reset | The item returns when it enters a defined reset area. |
| Out-of-bounds reset | The item returns when it leaves the playable space. |
For a shared VRC Object Sync pickup, its Respawn() method moves the object back to its original spawn position.
A shared reset should:
- run through the current owner
- restore
bitesRemainingto its initial value - serialize the restored value
- reapply the full visual state
- re-enable consumption
- respawn the synchronized transform when required
Do not leave the bite variable depleted while only moving the object back to its spawn point.
Handle Competing Use Inputs
Two players may attempt to grab or use a shared item close together.
Design for:
- ownership changing when the pickup changes hands
- a second request arriving after the last bite was taken
- the owner leaving while the object is depleted
- rapid repeated input
- a player joining after some bites are already gone
Check the current state again after ownership is established. The accepted bite should reduce the synchronized value exactly once.
Cross-Platform Pickup Checklist
- The Collider is easy to target with a VR hand ray and desktop camera ray.
- Proximity works at the intended placement height.
- Auto Hold allows desktop users to press the use input.
- Use Text names the action clearly.
- Exact Grip positions the item comfortably in either hand.
- Bite stages remain readable at normal social distance.
- The prop does not depend on a precise mouth collision or VR-only gesture.
- Mobile players have an input path that does not require unavailable controller movement.
- Shared feedback is not sent more often than required.
Test the Consumable
| Test | Expected result |
|---|---|
| Grab and drop | The pickup can be acquired, held, and released normally. |
| Desktop use | Auto Hold permits OnPickupUseDown and one press consumes one bite. |
| VR use | The held pose and use input work in both hands. |
| Repeated use | Bite count stops at zero and cannot underflow. |
| Depletion | Visuals, Collider behaviour, and feedback match the depleted state. |
| Reset | Full bite state and transform are restored together. |
| Second player | Shared or local scope matches the intended design. |
| Ownership change | A new holder can update a shared bite state correctly. |
| Late join | A new player sees the current shared bite stage. |
| Owner leaves | The remaining players can continue or reset the interaction. |
Use ClientSim for quick pickup and event tests, then use multiple VRChat clients or a private instance for ownership, synchronization, and late-join validation.
Release Checklist
- [ ] VRC Pickup, Rigidbody, Collider, and Udon logic are present.
- [ ] Auto Hold supports desktop pickup-use input.
- [ ] Use Text describes the consume action.
- [ ] Exact Grip and Proximity pass desktop and VR tests.
- [ ] One OnPickupUseDown call consumes exactly one bite.
- [ ] Bite state cannot fall below zero.
- [ ] Visual stages are derived from the current bite value.
- [ ] Local food does not send unnecessary networking.
- [ ] Shared food checks ownership and serializes bite changes.
- [ ] Late joiners receive the current shared bite state.
- [ ] Respawn restores both transform and bite state.
- [ ] Desktop, VR, mobile, multiplayer, and owner-leave tests pass.
Troubleshooting
The food cannot be picked up.
Confirm VRC Pickup, a Rigidbody, and a Collider are on the pickup object. Check Pickupable, Proximity, the Collider size, and whether another object blocks the selection ray.
OnPickupUseDown works in VR but not on desktop.
Enable Auto Hold on the VRC Pickup. VRChat documents Auto Hold as required for OnPickupUseDown and OnPickupUseUp on desktop.
One press consumes multiple bites.
Change the bite count only on OnPickupUseDown, not in a per-frame update or both press and release events. Confirm only one active behaviour handles the consume request.
Players see different bite stages.
If the item is shared, store bitesRemaining in a synced variable, change it as the owner, call RequestSerialization for manual sync, and reapply visuals in OnDeserialization.
The pickup moves for everyone, but bite state does not sync.
VRC Object Sync handles the physical transform, not your custom bite variable. Synchronize the bite value separately and include ownership and serialization handling.
The object respawns but stays empty.
Reset and serialize the bite variable as part of the same owner-controlled reset flow, then reapply the full visual stage before or after moving the object to its spawn position.
Late joiners see a full item after other players consumed it.
Do not rely on bite events for persistent state. Store the remaining bite count in a synced variable and apply the received value in OnDeserialization.
Official References
- VRC Pickup
- Udon Event Nodes
- VRC Object Sync
- Udon Networking
- Network Variables
- Object Ownership
- Late Joiners and Sync Issues
- Network Events
- Networking Performance