Skip to content

Unity Integration

Yaroslav Sarchuk edited this page Aug 29, 2025 · 1 revision

Unity Integration Guide

This guide covers Unity-specific features and best practices for using the Atomic Plugin with Unity projects.

🎮 Unity Setup

Prerequisites

  • Unity Version: 2020.3 LTS or newer
  • Atomic Framework: Installed via Package Manager
  • Rider Integration: Unity configured to use Rider as external editor

Installing Atomic Framework in Unity

Method 1: Package Manager (Recommended)

  1. Open Unity Package Manager (Window → Package Manager)
  2. Click + → Add package from git URL
  3. Enter: https://github.com/StarKRE22/Atomic.git
  4. Click Add

Method 2: Manual Installation

  1. Download Atomic Framework from GitHub
  2. Extract to Assets/Plugins/Atomic/
  3. Unity will automatically import the framework

Configuring Unity for Rider

  1. Go to Edit → Preferences → External Tools
  2. Set External Script Editor to JetBrains Rider
  3. Enable Generate .csproj files for:
    • Embedded packages
    • Local packages
    • Built-in packages

📁 Project Structure

Recommended Folder Organization

Assets/
├── Atomic/                 # Atomic Framework (if manual install)
├── Scripts/
│   ├── AtomicDefinitions/  # Your .atomic files
│   │   ├── Entities/
│   │   ├── Components/
│   │   └── Systems/
│   ├── Generated/          # Generated extension methods
│   │   ├── Entities/
│   │   ├── Components/
│   │   └── Systems/
│   └── Game/              # Your game logic
├── Prefabs/
│   └── Entities/          # Entity prefabs
└── Resources/
    └── AtomicConfigs/     # Runtime configurations

Assembly Definitions

Create assembly definitions for better compilation:

Scripts/AtomicDefinitions/AtomicDefinitions.asmdef:

{
    "name": "AtomicDefinitions",
    "rootNamespace": "Game.Atomic",
    "references": [
        "Atomic.Framework"
    ],
    "includePlatforms": [],
    "excludePlatforms": [],
    "allowUnsafeCode": true,
    "overrideReferences": false,
    "precompiledReferences": [],
    "autoReferenced": true,
    "defineConstraints": [],
    "versionDefines": [],
    "noEngineReferences": false
}

🔧 Unity-Specific Configuration

Unity Types in Atomic Files

The plugin recognizes Unity types automatically:

entityType: "IEntity"
namespace: "Game.Components"
className: "UnityComponentExtensions"

imports:
    UnityEngine
    UnityEngine.UI
    TMPro

values:
    # Unity Components
    Transform: Transform
    Rigidbody: Rigidbody
    Collider: Collider
    Animator: Animator
    
    # UI Components
    Canvas: Canvas
    Button: Button
    TextMeshProUGUI: TextMeshProUGUI
    
    # Unity Types
    Position: Vector3
    Rotation: Quaternion
    Velocity: Vector3
    Color: Color
    Sprite: Sprite
    Material: Material
    
    # Collections
    Waypoints: List<Vector3>
    Targets: Transform[]

MonoBehaviour Integration

Entity Component Pattern

using UnityEngine;
using Atomic.Entities;
using Game.Components;

public class EntityBehaviour : MonoBehaviour
{
    private IEntity entity;
    
    public IEntity Entity => entity;
    
    void Awake()
    {
        // Create or get entity
        entity = new Entity();
        
        // Bind Unity components
        entity.SetTransform(transform);
        entity.SetRigidbody(GetComponent<Rigidbody>());
        entity.SetAnimator(GetComponent<Animator>());
    }
    
    void Start()
    {
        // Initialize entity values
        entity.SetPosition(transform.position);
        entity.SetRotation(transform.rotation);
    }
    
    void Update()
    {
        // Sync Unity transform with entity
        if (entity.TryGetPosition(out var pos))
        {
            transform.position = pos;
        }
    }
}

System Component Pattern

using UnityEngine;
using System.Collections.Generic;
using Atomic.Entities;

public class MovementSystem : MonoBehaviour
{
    private List<IEntity> movableEntities = new List<IEntity>();
    
    public void RegisterEntity(IEntity entity)
    {
        if (entity.HasPosition() && entity.HasVelocity())
        {
            movableEntities.Add(entity);
        }
    }
    
    void FixedUpdate()
    {
        float deltaTime = Time.fixedDeltaTime;
        
        foreach (var entity in movableEntities)
        {
            if (entity.TryGetVelocity(out var velocity) &&
                entity.TryGetPosition(out var position))
            {
                // Update position based on velocity
                position += velocity * deltaTime;
                entity.SetPosition(position);
                
                // Update Unity transform
                if (entity.TryGetTransform(out var transform))
                {
                    transform.position = position;
                }
            }
        }
    }
}

🎯 Unity-Specific Features

Prefab Workflow

Creating Entity Prefabs

  1. Create GameObject with EntityBehaviour
  2. Configure components
  3. Save as prefab
  4. Use for spawning:
public class EntitySpawner : MonoBehaviour
{
    public GameObject entityPrefab;
    
    public IEntity SpawnEntity(Vector3 position)
    {
        var go = Instantiate(entityPrefab, position, Quaternion.identity);
        var entityBehaviour = go.GetComponent<EntityBehaviour>();
        
        // Configure spawned entity
        var entity = entityBehaviour.Entity;
        entity.SetHealth(100);
        entity.AddEnemyTag();
        
        return entity;
    }
}

ScriptableObject Integration

Entity Configuration

[CreateAssetMenu(fileName = "EntityConfig", menuName = "Atomic/Entity Config")]
public class EntityConfig : ScriptableObject
{
    public int maxHealth = 100;
    public float moveSpeed = 5f;
    public float attackDamage = 10f;
    
    public void ApplyToEntity(IEntity entity)
    {
        entity.SetMaxHealth(maxHealth);
        entity.SetMoveSpeed(moveSpeed);
        entity.SetDamage(attackDamage);
    }
}

Unity Events Integration

using UnityEngine;
using UnityEngine.Events;
using Atomic.Entities;

public class HealthComponent : MonoBehaviour
{
    private IEntity entity;
    
    [System.Serializable]
    public class HealthEvent : UnityEvent<int, int> { }
    
    public HealthEvent OnHealthChanged;
    public UnityEvent OnDeath;
    
    void Start()
    {
        entity = GetComponent<EntityBehaviour>().Entity;
        entity.SetHealth(100);
    }
    
    public void TakeDamage(int damage)
    {
        int currentHealth = entity.GetHealth();
        int newHealth = Mathf.Max(0, currentHealth - damage);
        
        entity.SetHealth(newHealth);
        OnHealthChanged?.Invoke(newHealth, entity.GetMaxHealth());
        
        if (newHealth <= 0)
        {
            entity.AddDeadTag();
            OnDeath?.Invoke();
        }
    }
}

⚡ Performance Optimization

Unity-Specific Optimizations

Object Pooling with Entities

public class EntityPool : MonoBehaviour
{
    private Queue<IEntity> pool = new Queue<IEntity>();
    private Queue<GameObject> gameObjectPool = new Queue<GameObject>();
    
    public GameObject entityPrefab;
    public int poolSize = 50;
    
    void Start()
    {
        for (int i = 0; i < poolSize; i++)
        {
            var go = Instantiate(entityPrefab);
            go.SetActive(false);
            
            var entity = go.GetComponent<EntityBehaviour>().Entity;
            pool.Enqueue(entity);
            gameObjectPool.Enqueue(go);
        }
    }
    
    public IEntity GetEntity()
    {
        if (pool.Count > 0)
        {
            var entity = pool.Dequeue();
            var go = gameObjectPool.Dequeue();
            
            go.SetActive(true);
            ResetEntity(entity);
            
            return entity;
        }
        
        // Create new if pool is empty
        return CreateNewEntity();
    }
    
    public void ReturnEntity(IEntity entity)
    {
        if (entity.TryGetTransform(out var transform))
        {
            transform.gameObject.SetActive(false);
            pool.Enqueue(entity);
            gameObjectPool.Enqueue(transform.gameObject);
        }
    }
}

Burst Compilation Support

When using Unity's Job System:

using Unity.Burst;
using Unity.Jobs;
using Unity.Collections;
using Unity.Mathematics;

[BurstCompile]
public struct MoveEntitiesJob : IJobParallelFor
{
    public NativeArray<float3> positions;
    public NativeArray<float3> velocities;
    public float deltaTime;
    
    public void Execute(int index)
    {
        positions[index] += velocities[index] * deltaTime;
    }
}

Profiling Integration

using UnityEngine.Profiling;

public class EntitySystemProfiler : MonoBehaviour
{
    void Update()
    {
        Profiler.BeginSample("Entity Update");
        UpdateEntities();
        Profiler.EndSample();
        
        Profiler.BeginSample("Entity Physics");
        UpdatePhysics();
        Profiler.EndSample();
    }
}

🛠️ Debugging

Unity Inspector Integration

#if UNITY_EDITOR
using UnityEditor;

[CustomEditor(typeof(EntityBehaviour))]
public class EntityBehaviourEditor : Editor
{
    public override void OnInspectorGUI()
    {
        base.OnInspectorGUI();
        
        var behaviour = (EntityBehaviour)target;
        if (behaviour.Entity == null) return;
        
        EditorGUILayout.Space();
        EditorGUILayout.LabelField("Entity Values", EditorStyles.boldLabel);
        
        if (behaviour.Entity.TryGetHealth(out int health))
        {
            EditorGUILayout.IntField("Health", health);
        }
        
        if (behaviour.Entity.TryGetPosition(out var pos))
        {
            EditorGUILayout.Vector3Field("Position", pos);
        }
        
        EditorGUILayout.Space();
        EditorGUILayout.LabelField("Entity Tags", EditorStyles.boldLabel);
        
        EditorGUILayout.Toggle("Player", behaviour.Entity.HasPlayerTag());
        EditorGUILayout.Toggle("Enemy", behaviour.Entity.HasEnemyTag());
        EditorGUILayout.Toggle("Dead", behaviour.Entity.HasDeadTag());
    }
}
#endif

Debug Visualization

public class EntityDebugger : MonoBehaviour
{
    public bool showEntityInfo = true;
    public Color healthBarColor = Color.green;
    
    void OnDrawGizmos()
    {
        if (!showEntityInfo) return;
        
        var entity = GetComponent<EntityBehaviour>()?.Entity;
        if (entity == null) return;
        
        // Draw health bar
        if (entity.TryGetHealth(out int health) && 
            entity.TryGetMaxHealth(out int maxHealth))
        {
            var healthPercent = (float)health / maxHealth;
            Gizmos.color = healthBarColor;
            Gizmos.DrawLine(
                transform.position + Vector3.up * 2,
                transform.position + Vector3.up * 2 + Vector3.right * healthPercent
            );
        }
        
        // Draw velocity vector
        if (entity.TryGetVelocity(out var velocity))
        {
            Gizmos.color = Color.blue;
            Gizmos.DrawRay(transform.position, velocity);
        }
    }
}

🚀 Build Considerations

Platform-Specific Settings

# Mobile-optimized configuration
entityType: "IEntity"
namespace: "Game.Mobile"
aggressiveInlining: true  # Important for mobile performance
unsafe: false  # Some mobile platforms don't support unsafe

imports:
    UnityEngine
    #if UNITY_IOS
    UnityEngine.iOS
    #endif

Stripping Prevention

Add to link.xml:

<linker>
    <assembly fullname="Game.Generated" preserve="all"/>
    <assembly fullname="Atomic.Framework" preserve="all"/>
</linker>

📚 Unity-Specific Examples

Input System Integration

using UnityEngine;
using UnityEngine.InputSystem;

public class PlayerInputHandler : MonoBehaviour
{
    private IEntity playerEntity;
    private PlayerInput playerInput;
    
    void Awake()
    {
        playerEntity = GetComponent<EntityBehaviour>().Entity;
        playerInput = GetComponent<PlayerInput>();
    }
    
    public void OnMove(InputValue value)
    {
        Vector2 input = value.Get<Vector2>();
        Vector3 movement = new Vector3(input.x, 0, input.y);
        playerEntity.SetVelocity(movement * playerEntity.GetMoveSpeed());
    }
    
    public void OnFire()
    {
        if (!playerEntity.HasAttackingTag())
        {
            playerEntity.AddAttackingTag();
            StartCoroutine(PerformAttack());
        }
    }
}

Animation Integration

public class EntityAnimationController : MonoBehaviour
{
    private IEntity entity;
    private Animator animator;
    
    void Start()
    {
        entity = GetComponent<EntityBehaviour>().Entity;
        animator = GetComponent<Animator>();
        entity.SetAnimator(animator);
    }
    
    void Update()
    {
        // Sync animation parameters with entity state
        if (entity.TryGetVelocity(out var velocity))
        {
            animator.SetFloat("Speed", velocity.magnitude);
        }
        
        animator.SetBool("IsAttacking", entity.HasAttackingTag());
        animator.SetBool("IsDead", entity.HasDeadTag());
    }
}

🆘 Troubleshooting Unity Issues

Common Problems

Generated code not found in Unity

  • Ensure generation directory exists
  • Check assembly definition references
  • Refresh Unity asset database (Ctrl+R)

Type not recognized in .atomic file

  • Add proper Unity namespace to imports
  • Use fully qualified type names
  • Check assembly references

Performance issues in Play Mode

  • Enable aggressive inlining
  • Use object pooling
  • Profile with Unity Profiler

📖 Additional Resources


Need Help? Check Troubleshooting or report Unity-specific issues on GitHub.

Navigation

📚 Documentation

📖 Reference

❓ Help

🔗 Links

Clone this wiki locally