Development rules for a custom 2D game engine with networking support. Handles entity management, networking, sprite rendering, RPCs, and SyncVars without Unity APIs.
You are developing a game in a custom 2D engine that DOES NOT HAVE ALL UNITY APIs.
```csharp
// Create an entity
var entity = Entity.Create();
// Make it visible to other clients (server only)
Network.Spawn(entity);
```
```csharp
// Get all components of a type in the scene
foreach (var player in Scene.Components<MyPlayer>())
{
// Process each player
}
// Get a specific entity by name
var entity = Entity.FindByName("EntityName");
// Check if entity exists
if (entity.Alive())
{
// Entity is valid
}
```
```csharp
// Seed the RNG
RNG.Seed(1337);
// Generate random numbers
int randomInt = RNG.RangeInt(min, max);
float randomFloat = RNG.RangeFloat(min, max);
// Do not try any other RNG methods
```
```csharp
// Do NOT prefix with /res
var texture = Assets.GetAsset<Texture>("path/to/asset");
var audio = Assets.GetAsset<AudioAsset>("path/to/audio");
var skeleton = Assets.GetAsset<SpineSkeletonAsset>("path/to/skeleton");
```
Common asset types:
```csharp
var spriteRenderer = entity.GetComponent<Sprite_Renderer>();
spriteRenderer.Tint = new Vector4(1, 0, 0, 1); // Red tint
```
```csharp
if (Network.IsServer)
{
// Server-side code
}
if (Network.IsClient)
{
// Client-side code
}
```
SyncVars wrap primitives and automatically keep them synchronized between all clients and the server.
**Supported Types:**
**Declaration:**
```csharp
public partial class BattlePlayer : Player
{
// Always call the constructor when declaring
public SyncVar<int> Health = new(100);
}
```
**Usage:**
```csharp
// Access the value
if (Health.Value <= 0)
{
// Handle death
}
// Change the value (server only)
Health.Set(50);
// Respond to changes
Health.OnSync((oldValue, newValue) =>
{
Debug.Log($"Health changed from {oldValue} to {newValue}");
});
```
**Important:**
ClientRPCs are used when the server needs to call a function on all clients.
**Declaration:**
```csharp
public partial class MyPlayer : Player
{
// ClientRpc functions MUST be public
[ClientRpc]
public void PlaySuccessSound()
{
// This runs on clients
}
}
```
**Calling:**
```csharp
// Call with CallClient_ prefix
CallClient_PlaySuccessSound();
```
**Important Rules:**
```csharp
using AO;
public partial class GamePlayer : Player
{
// SyncVar for health
public SyncVar<int> Health = new(100);
public override void Start()
{
if (IsLocal)
{
// Setup camera for local player
var camera = Entity.Create();
camera.AddComponent<CameraControl>();
}
// Listen for health changes
Health.OnSync((old, current) =>
{
if (current <= 0)
{
CallClient_OnDeath();
}
});
}
public void TakeDamage(int amount)
{
if (Network.IsServer)
{
Health.Set(Health.Value - amount);
}
}
[ClientRpc]
public void OnDeath()
{
// Play death sound on all clients
var audio = Assets.GetAsset<AudioAsset>("sounds/death");
// Play audio...
}
}
```
1. Always check `Network.IsServer` before spawning networked entities
2. Keep UI and visual updates on the client side
3. Use SyncVars for state that needs to be synchronized
4. Use ClientRPCs for one-time events that all clients should respond to
5. Remember to use `.Alive()` to check entity validity
6. Always initialize SyncVars with a constructor call
7. Mark classes with RPCs as `partial`
Leave a review
No reviews yet. Be the first to review this skill!
# Download SKILL.md from killerskills.ai/api/skills/custom-2d-game-engine-rules/raw