senior-game-dev
Senior game developer: Unity, Unreal Engine, game architecture, multiplayer, performance optimization
Senior Game Developer
Engine Selection Guide
| Criteria | Unity | Unreal Engine 5 | |----------|-------|-----------------| | 2D | Excellent (Tilemap, SpriteShape) | Limited (Paper2D deprecated) | | 3D | Good (URP/HDRP) | Excellent (Nanite, Lumen) | | Mobile | Best-in-class (IL2CPP, small runtime) | Heavy (1GB+ install) | | VR/AR | Excellent (XR Plugin, AR Foundation) | Good (OpenXR, no native AR) | | Programming | C# | C++, Blueprint | | Rendering | URP (perf), HDRP (quality) | Nanite + Lumen GI | | Team size | Small to medium | Medium to large | | Learning curve | Moderate | Steep | | Source control | Perforce, Git (YAML) | Perforce, Git LFS |
Blueprint vs C++ (Unreal)
| Task | Pick | Reason | |------|------|--------| | Gameplay logic | Blueprint | Rapid iteration, designers own it | | Performance-critical | C++ | No VM overhead, direct memory | | Data assets | Blueprint | Easy to author and edit | | AI behavior trees | Blueprint | Visual flow clearer | | Network replication | C++ | Precise RPC/state control | | Math-heavy systems | C++ | 10-100x faster | | UI widgets | Blueprint | UMG designer integration |
Project Structure
Unity
Assets/Scripts/ C# source
Assets/Scenes/ Scene files
Assets/Prefabs/ Reusable game objects
Assets/AddressableAssets/Remote asset groups
Assets/Art/ Models, textures, materials
Assets/Audio/ SFX, music, mixers
Assets/UI/ UXML, USS, sprites
Assets/Plugins/ Native platform plugins
Assets/Settings/ URP/HDRP assets, input
Assets/StreamingAssets/ Raw build-shipped files
Unreal
Project/Source/ C++ modules
Project/Content/Core/ Blueprints, data assets
Project/Content/Characters/ Skeletons, animations
Project/Content/Environments/ Maps, landscapes
Project/Content/FX/ Niagara, VFX
Project/Content/UI/ UMG widgets, fonts
Project/Content/Audio/ Sound cues, mixers
Project/Content/GAS/ Ability system assets
Project/Config/ .ini config files
Project/Plugins/ Project plugins
Game Architecture Patterns
State Machine
public abstract class BaseState
{
public abstract void Enter();
public abstract void Update(float dt);
public abstract void Exit();
}
public class StateMachine
{
private BaseState current;
public void Change(BaseState next)
{
current?.Exit();
current = next;
current.Enter();
}
public void Tick(float dt) => current?.Update(dt);
}
Observer (C# Events)
public class HealthSystem : MonoBehaviour
{
public event Action<float, float> OnChanged;
public event Action OnDeath;
[SerializeField] float maxHealth = 100f;
float currentHealth;
public void TakeDamage(float amount)
{
currentHealth = Mathf.Max(0f, currentHealth - amount);
OnChanged?.Invoke(currentHealth, maxHealth);
if (currentHealth <= 0f) OnDeath?.Invoke();
}
}
ECS (Unity DOTS)
public struct Velocity : IComponentData { public float3 Value; }
public partial struct MoveSystem : ISystem
{
public void OnUpdate(ref SystemState state)
{
foreach (var (vel, xform) in
SystemAPI.Query<RefRO<Velocity>, RefRW<LocalTransform>>())
{
xform.ValueRW.Position +=
vel.ValueRO.Value * SystemAPI.Time.DeltaTime;
}
}
}
GAS (Unreal)
| Concept | Purpose | |---------|---------| | UGameplayAbility | Executable actions (cast, attack) | | UGameplayEffect | Temp/permanent stat modifiers | | UAttributeSet | Attribute collection (health, mana) | | FGameplayTag | Hierarchical state matching | | UAbilityTask | Async ability actions |
Performance Optimization
| Technique | Unity | Unreal | |-----------|-------|--------| | Static batching | Static flag | Auto with StaticMeshes | | GPU instancing | MaterialPropertyBlock | Instanced Static Meshes | | Texture atlas | SpriteAtlas | Texture Atlas Group | | LOD groups | LODGroup component | LOD screen sizes | | Occlusion culling | Occlusion window | Auto HZB occlusion |
Checklist
- Object pooling over Instantiate/Destroy
- Cache GetComponent refs or use RequireComponent
- Enable GPU instancing on shared materials
- LOD groups with 3+ levels
- Bake occlusion culling for static scenes
- Light probes over real-time lights
- Pool particle systems (stop vs destroy)
- Profile with Unity Profiler / Unreal Insights
Asset Pipeline
Unity Addressables
public async Task<GameObject> LoadAssetAsync(string key)
{
var handle = Addressables.LoadAssetAsync<GameObject>(key);
return await handle.Task;
}
public void ReleaseAsset(GameObject asset) => Addressables.Release(asset);
Unreal Async Load
void LoadWeaponAsync(FSoftObjectPath Path)
{
TSoftObjectPtr<UDataAsset> Ptr(Path);
if (Ptr.IsPending())
{
StreamableManager.RequestAsyncLoad(Ptr.ToSoftObjectPath(),
FStreamableDelegate::CreateLambda([]()
{ UE_LOG(LogTemp, Log, TEXT("Loaded")); }));
}
}
Networking
| Solution | Platform | Architecture | Best For | |----------|----------|--------------|----------| | Mirror | Unity | Auth server | 16-64 players | | Photon Fusion | Unity | State sync | Action, 8-32 players | | Unity Netcode | Unity | Client-server | 2-8 players | | UE Replication | Unreal | Client-server | Large-scale, built-in | | Steamworks | Both | P2P + relay | PC lobbies |
UE Replication
UCLASS(Replicated)
class AMyProjectile : public AActor
{
GENERATED_BODY()
public:
UPROPERTY(ReplicatedUsing = OnRep_HitLocation)
FVector HitLocation;
UFUNCTION() void OnRep_HitLocation();
UFUNCTION(Server, Reliable, WithValidation)
void Server_DealDamage(AActor* Target, float Damage);
bool Server_DealDamage_Validate(AActor* Target, float Damage);
void Server_DealDamage_Implementation(AActor* Target, float Damage);
};
Build and Deployment
Unity
IL2CPP, Low stripping, Dedicated Server
Addressables: remote catalog build
Output: Windows .exe | Android .apk | iOS .xcodeproj
Unreal
UBT compile -> UAT package -> cook per platform
Output: WindowsNoEditor | Android .apk/.aab | Console
CI/CD
Cache build artifacts, split cook/compile, version asset bundles, symbol servers, automated smoke tests.