| name | unity3d |
| description | USE FOR: Building 2D and 3D games, simulations, AR/VR experiences, and interactive applications using the Unity game engine with C# scripting. Use when you need a visual editor, asset store, and cross-platform deployment to PC, consoles, mobile, and web.
DO NOT USE FOR: Business applications, web APIs, or CRUD apps (use ASP.NET Core or Blazor), command-line tools, or projects that require fully open-source tooling (Unity is proprietary).
|
| license | MIT |
| metadata | {"displayName":"Unity3D","author":"Tyler-R-Kendrick","version":"1.0.0"} |
| compatibility | ["claude","copilot","cursor"] |
| references | [{"title":"Unity Documentation","url":"https://docs.unity3d.com/Manual/index.html"},{"title":"Unity Official Site","url":"https://unity.com/"},{"title":"Unity Scripting API Reference","url":"https://docs.unity3d.com/ScriptReference/index.html"}] |
Unity3D
Overview
Unity is a cross-platform game engine and development environment that uses C# as its primary scripting language. It supports 2D and 3D game development, AR/VR, simulation, and interactive media. Unity provides a visual editor, scene hierarchy, inspector, animation system, physics engine, and an asset store. Games and applications built with Unity can be deployed to Windows, macOS, Linux, iOS, Android, WebGL, PlayStation, Xbox, Nintendo Switch, and more. Unity scripts are C# classes that inherit from MonoBehaviour and use lifecycle methods (Awake, Start, Update, FixedUpdate, OnDestroy) to define behavior.
MonoBehaviour Lifecycle and Player Controller
The MonoBehaviour class provides lifecycle hooks. Use Update for frame-dependent logic and FixedUpdate for physics.
using UnityEngine;
namespace MyGame
{
[RequireComponent(typeof(Rigidbody))]
[RequireComponent(typeof(CapsuleCollider))]
public class PlayerController : MonoBehaviour
{
[Header("Movement")]
[SerializeField] private float moveSpeed = 6f;
[SerializeField] private float jumpForce = 8f;
[SerializeField] private float groundCheckDistance = 0.3f;
[Header("Camera")]
[SerializeField] private Transform cameraTransform;
[SerializeField] private float mouseSensitivity = 2f;
private Rigidbody _rb;
private bool _isGrounded;
private float _verticalRotation;
private void Awake()
{
_rb = GetComponent<Rigidbody>();
_rb.freezeRotation = true;
Cursor.lockState = CursorLockMode.Locked;
}
private void Update()
{
HandleMouseLook();
CheckGrounded();
if (_isGrounded && Input.GetButtonDown("Jump"))
{
_rb.AddForce(Vector3.up * jumpForce, ForceMode.Impulse);
}
}
{
horizontal = Input.GetAxisRaw();
vertical = Input.GetAxisRaw();
Vector3 direction = transform.forward * vertical + transform.right * horizontal;
direction = direction.normalized * moveSpeed;
direction.y = _rb.linearVelocity.y;
_rb.linearVelocity = direction;
}
{
mouseX = Input.GetAxis() * mouseSensitivity;
mouseY = Input.GetAxis() * mouseSensitivity;
_verticalRotation -= mouseY;
_verticalRotation = Mathf.Clamp(_verticalRotation, , );
cameraTransform.localRotation = Quaternion.Euler(_verticalRotation, , );
transform.Rotate(Vector3.up * mouseX);
}
{
_isGrounded = Physics.Raycast(
transform.position, Vector3.down, groundCheckDistance);
}
}
}
Scriptable Objects for Data
Use ScriptableObject to define data assets that can be edited in the Unity Inspector and shared across objects.
using UnityEngine;
namespace MyGame.Data
{
[CreateAssetMenu(fileName = "NewWeapon", menuName = "Game/Weapon Data")]
public class WeaponData : ScriptableObject
{
[Header("Weapon Info")]
public string weaponName;
public Sprite icon;
public GameObject prefab;
[Header("Stats")]
[Range(1, 100)] public int damage = 10;
[Range(0.1f, 5f)] public float fireRate = 0.5f;
[Range(1, 100)] public int maxAmmo = 30;
[Range(5f, 200f)] public float range = 50f;
[Header("Effects")]
public AudioClip fireSound;
public ParticleSystem muzzleFlash;
}
public class WeaponSystem : MonoBehaviour
{
[SerializeField] private WeaponData currentWeapon;
private int _currentAmmo;
private float _nextFireTime;
private ()
{
_currentAmmo = currentWeapon.maxAmmo;
}
{
(Time.time < _nextFireTime || _currentAmmo <= ) ;
_nextFireTime = Time.time + currentWeapon.fireRate;
_currentAmmo--;
(Physics.Raycast(transform.position, transform.forward,
RaycastHit hit, currentWeapon.range))
{
(hit.collider.TryGetComponent<IDamageable>( target))
{
target.TakeDamage(currentWeapon.damage);
}
}
(currentWeapon.fireSound != )
AudioSource.PlayClipAtPoint(currentWeapon.fireSound, transform.position);
}
{
_currentAmmo = currentWeapon.maxAmmo;
}
}
{
;
}
}
Object Pooling
Avoid runtime Instantiate/Destroy overhead with an object pool for frequently spawned objects.
using System.Collections.Generic;
using UnityEngine;
namespace MyGame.Systems
{
public class ObjectPool : MonoBehaviour
{
[SerializeField] private GameObject prefab;
[SerializeField] private int initialSize = 20;
[SerializeField] private Transform poolParent;
private readonly Queue<GameObject> _available = new();
private void Awake()
{
for (int i = 0; i < initialSize; i++)
{
var obj = Instantiate(prefab, poolParent);
obj.SetActive(false);
_available.Enqueue(obj);
}
}
public GameObject Get(Vector3 position, Quaternion rotation)
{
GameObject obj;
if (_available.Count > 0)
{
obj = _available.Dequeue();
}
else
{
obj = Instantiate(prefab, poolParent);
}
obj.transform.SetPositionAndRotation(position, rotation);
obj.SetActive(true);
return obj;
}
public void Return(GameObject obj)
{
obj.SetActive(false);
_available.Enqueue(obj);
}
}
}
Coroutines and Async Patterns
Unity supports both coroutines (via IEnumerator) and modern async/await patterns for asynchronous operations.
using System.Collections;
using System.Threading;
using System.Threading.Tasks;
using UnityEngine;
using UnityEngine.Networking;
namespace MyGame.Networking
{
public class DataLoader : MonoBehaviour
{
private CancellationTokenSource _cts;
private void OnEnable()
{
_cts = new CancellationTokenSource();
}
private void OnDisable()
{
_cts?.Cancel();
_cts?.Dispose();
}
public IEnumerator LoadTextureCoroutine(string url, System.Action<Texture2D> callback)
{
using var request = UnityWebRequestTexture.GetTexture(url);
yield return request.SendWebRequest();
if (request.result == UnityWebRequest.Result.Success)
{
var texture = DownloadHandlerTexture.GetContent(request);
callback?.Invoke(texture);
}
else
{
Debug.LogError($"Failed to load texture: {request.error}");
}
}
public async Task<string> LoadJsonAsync( url)
{
request = UnityWebRequest.Get(url);
operation = request.SendWebRequest();
(!operation.isDone)
{
_cts.Token.ThrowIfCancellationRequested();
Task.Yield();
}
(request.result != UnityWebRequest.Result.Success)
System.Exception();
request.downloadHandler.text;
}
}
}
Unity vs Other Game Engines
| Feature | Unity | Unreal Engine | Godot | MonoGame |
|---|
| Language | C# | C++ / Blueprints | GDScript / C# | C# |
| Editor | Full visual editor | Full visual editor | Full visual editor | None (code-only) |
| 2D support | Good | Limited | Excellent | Excellent |
| 3D support | Good | Excellent (AAA) | Good | Manual |
| Asset store | Largest ecosystem | Marketplace | Asset Library | None |
| Platform reach | 20+ platforms | 15+ platforms | 10+ platforms | 8+ platforms |
| Pricing | Free (revenue caps) | Free (5% royalty > $1M) | Free (MIT) | Free (MIT) |
Best Practices
-
Use [SerializeField] private instead of public fields for Inspector-exposed values so that other scripts cannot directly modify the field, maintaining encapsulation; public fields bypass property setters, making it impossible to validate or react to changes at assignment time.
-
Cache GetComponent<T>() results in Awake() and store them in private fields rather than calling GetComponent every frame in Update(); each GetComponent call performs a runtime type lookup on the GameObject's component list, and calling it 60+ times per second across hundreds of objects creates measurable CPU overhead.
-
Use FixedUpdate() for all physics-related code (Rigidbody forces, raycasts for physics queries, collision checks) because FixedUpdate runs at a deterministic timestep synchronized with the physics engine; physics code in Update() produces frame-rate-dependent behavior that varies across devices.
-
Implement object pooling for frequently instantiated/destroyed objects (bullets, particles, UI popups) using a Queue<GameObject> pattern, because Instantiate() and Destroy() allocate and deallocate managed and native memory, triggering GC spikes that cause visible frame stutters on mobile.
-
Use ScriptableObject assets for shared game data (weapon stats, enemy configurations, dialog trees) instead of hardcoding values in MonoBehaviour fields or static variables, because ScriptableObjects are editable in the Inspector, shareable across prefabs, and do not require scene references.
-
Cancel CancellationTokenSource in OnDisable() or OnDestroy() for all async operations to prevent MissingReferenceException when a coroutine or Task completes after the GameObject has been destroyed; this is especially critical for scene transitions where objects are destroyed mid-operation.
-
Use [RequireComponent(typeof(T))] attribute on MonoBehaviours that depend on specific components (e.g., Rigidbody, Collider, AudioSource) so Unity automatically adds the required component when the script is attached and prevents accidental removal in the Inspector.