groupsCommunity
Project Structure Recommendations
Project Structure Recommendations
Community guide for organizing s&box projects based on Facepunch examples and successful community projects.
Recommended Folder Structure
CODE
my_game/
├── code/
│ ├── GameManager.cs # Main game logic
│ ├── Player/
│ │ ├── PlayerController.cs
│ │ ├── PlayerState.cs # Health, inventory, etc.
│ │ └── PlayerInput.cs # Input handling
│ ├── Weapons/
│ │ ├── Weapon.cs # Base weapon class
│ │ ├── WeaponRifle.cs
│ │ └── WeaponShotgun.cs
│ ├── UI/
│ │ ├── Hud.razor
│ │ ├── MainMenu.razor
│ │ └── Scoreboard.razor
│ └── Utils/
│ ├── Extensions.cs
│ └── Constants.cs
├── assets/
│ ├── weapons/
│ │ ├── rifle.vmdl
│ │ └── rifle.fire.sound
│ ├── ui/
│ │ └── hud.scss
│ └── materials/
│ └── bullet_hole.vmat
├── scenes/
│ ├── main_menu.scene
│ └── level_01.scene
└── my_game.sbprojNamespace Organization
CSHARP
// Keep namespaces consistent with folder structure
namespace MyGame.Player;
namespace MyGame.Weapons;
namespace MyGame.UI;
// Avoid generic namespaces
// ❌ namespace MyGame; (too broad)
// ✅ namespace MyGame.Weapons; (specific)Component Naming
CSHARP
// ✅ Good: Clear, specific names
public class PlayerHealth : Component
public class WeaponManager : Component
public class GameTimer : Component
// ❌ Bad: Vague or generic
public class Manager : Component // Which manager?
public class Script : Component // Too generic
public class MyComponent : Component // MeaninglessAsset Naming Conventions
| Type | Convention | Example |
|---|---|---|
| Scenes | PascalCase | MainMenu.scene |
| Materials | snake_case | metal_rusty.vmat |
| Sounds | snake_case | weapon_rifle.fire.sound |
| Models | PascalCase | PlayerRig.vmdl |
| Prefabs | PascalCase | EnemyZombie.prefab |
Scene Organization
Use empty GameObjects as "folders" in scenes:
CODE
Level_01 (scene root)
├── [Environment] (empty, groups terrain/props)
│ ├── Terrain
│ └── Buildings
├── [Gameplay] (empty, groups game logic)
│ ├── Spawners
│ └── Triggers
├── [Lighting] (empty, groups lights)
└── [Players] (empty, spawn points)Tags Strategy
Establish a consistent tagging system:
CSHARP
// Core gameplay tags
public static class Tags
{
public const string Player = "player";
public const string Enemy = "enemy";
public const string Weapon = "weapon";
public const string Solid = "solid";
public const string Trigger = "trigger";
public const string Interactable = "interactable";
// Team tags for multiplayer
public const string TeamRed = "team_red";
public const string TeamBlue = "team_blue";
}Resource Loading Strategy
CSHARP
public class AssetManager : Component
{
// Cache loaded resources
private static Dictionary<string, Material> _materials = new();
private static Dictionary<string, SoundEvent> _sounds = new();
public static Material GetMaterial(string path)
{
if (!_materials.TryGetValue(path, out var mat))
{
mat = Material.Load(path);
_materials[path] = mat;
}
return mat;
}
}Settings Organization
CSHARP
// Game settings in one place
public static class GameSettings
{
// Player
public const float PlayerWalkSpeed = 200f;
public const float PlayerRunSpeed = 400f;
public const float PlayerJumpForce = 400f;
// Weapons
public const float WeaponFireRate = 0.1f;
public const int WeaponMaxAmmo = 30;
// Game
public const float MatchDuration = 300f;
public const int MaxPlayers = 16;
}Version Control Best Practices
GITIGNORE
# Add to .gitignore
*.los # Compiled assets
*.vpk # Packaged files
bin/
obj/
.vs/
*.userSource
- Facepunch example projects
- Official asset pipeline docs: https://sbox.game/dev/doc/assets
- Community best practices from s&box Discord
Was this helpful?