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