Skip to content
IRC-Coding IRC-Coding
Game development fundamentals Unity Unreal Engine 3D graphics physics Animation Game programming

Game Development Fundamentals: Unity, Unreal Engine & 3D

Learn game development basics: Unity, Unreal Engine, 3D graphics, physics engines, animation, game loops, rendering, and collision detection.

S

schutzgeist

2 min read
Game Development Fundamentals: Unity, Unreal Engine & 3D

Game Development Fundamentals: Unity, Unreal Engine, 3D Graphics, Physics & Animation

This article is a comprehensive introduction to game development fundamentals – including Unity, Unreal Engine, 3D graphics, physics engines and animation with practical examples.

In a Nutshell

Game development combines programming, 3D graphics, physics and animation. Unity and Unreal Engine are the leading engines, C# and C++ are the main programming languages, OpenGL/Vulkan are the graphics APIs.

Compact Technical Description

Game development is the creation of interactive entertainment software through the combination of programming, graphics, sound and gameplay mechanics.

Core components:

Game Engines

  • Unity: C# engine for 2D/3D games, cross-platform
  • Unreal Engine: C++ engine for AAA games, high-end graphics
  • Godot: Open-source engine with GDScript/C#
  • CryEngine: C++ engine for realistic graphics

3D Graphics

  • Rendering Pipeline: Vertex → Fragment → Display
  • Shaders: GLSL/HLSL for visual effects
  • Lighting: Lighting models (Phong, PBR)
  • Texturing: 2D/3D materials and mapping

Physics Engines

  • Collision Detection: AABB, OBB, Sphere, Mesh
  • Physics Simulation: Rigid Bodies, Forces, Constraints
  • Integration: Verlet, Euler, RK4
  • Optimization: Spatial Hashing, Broad Phase

Animation Systems

  • Skeletal Animation: Bones, Weights, Skinning
  • Keyframe Animation: Timeline-based animation
  • Procedural Animation: Algorithmically generated
  • Morph Targets: Shape interpolation

Exam-Relevant Key Points

  • Game development: Creation of interactive games
  • Unity: C# engine for cross-platform games
  • Unreal Engine: C++ engine for AAA games
  • 3D Graphics: Rendering pipeline, shaders, lighting
  • Physics: Collision detection, physics simulation
  • Animation: Skeletal, keyframe, procedural animation
  • Game Loop: Update-render cycle, fixed time step
  • IHK-relevant: Modern game development and technologies

Core Components

  1. Game Engine: Foundation for game development
  2. Rendering Pipeline: Graphics processing and display
  3. Physics Engine: Physics simulation and collision detection
  4. Animation System: Movement and character animation
  5. Input System: User interaction and control
  6. Audio System: Sound effects and music
  7. UI System: User interface and HUD
  8. Networking: Multiplayer and online features

Practical Examples

1. Unity Game with C# - 2D Platformer

using UnityEngine;
using System.Collections;

// Player Controller für 2D Platformer
public class PlayerController : MonoBehaviour
{
    [Header("Movement Settings")]
    [SerializeField] private float moveSpeed = 5f;
    [SerializeField] private float jumpForce = 10f;
    [SerializeField] private LayerMask groundLayer;
    
    [Header("Animation Settings")]
    [SerializeField] private Animator animator;
    [SerializeField] private Transform groundCheck;
    [SerializeField] private float groundCheckRadius = 0.2f;
    
    private Rigidbody2D rb;
    private bool isGrounded = false;
    private bool facingRight = true;
    private float horizontalInput;
    private Vector2 velocity = Vector2.zero;
    
    // Physics Constants
    private const float GROUND_CHECK_DISTANCE = 0.1f;
    private const float COYOTE_TIME = 0.2f;
    private const float MAX_FALL_SPEED = 20f;
    
    private void Awake()
    {
        rb = GetComponent<Rigidbody2D>();
        
        if (animator == null)
            animator = GetComponent<Animator>();
            
        if (groundCheck == null)
            groundCheck = transform;
    }
    
    private void Update()
    {
        HandleInput();
        UpdateAnimations();
    }
    
    private void FixedUpdate()
    {
        HandleMovement();
        HandlePhysics();
    }
    
    private void HandleInput()
    {
        // Horizontal movement
        horizontalInput = Input.GetAxisRaw("Horizontal");
        
        // Jump input
        if (Input.GetButtonDown("Jump") && isGrounded)
        {
            Jump();
        }
        
        // Dash input
        if (Input.GetButtonDown("Dash"))
        {
            Dash();
        }
        
        // Attack input
        if (Input.GetButtonDown("Attack"))
        {
            Attack();
        }
    }
    
    private void HandleMovement()
    {
        // Horizontal movement with smooth acceleration
        float targetVelocityX = horizontalInput * moveSpeed;
        velocity.x = Mathf.SmoothDamp(velocity.x, targetVelocityX, 0.1f);
        
        // Apply movement
        rb.velocity = new Vector2(velocity.x, rb.velocity.y);
        
        // Flip character based on direction
        if (horizontalInput != 0 && horizontalInput != transform.localScale.x)
        {
            Flip();
        }
    }
    
    private void HandlePhysics()
    {
        // Ground check
        isGrounded = Physics2D.OverlapCircle(groundCheck.position, groundCheckRadius, groundLayer);
        
        // Limit fall speed
        if (rb.velocity.y < -MAX_FALL_SPEED)
        {
            rb.velocity = new Vector2(rb.velocity.x, -MAX_FALL_SPEED);
        }
        
        // Apply gravity
        if (!isGrounded)
        {
            rb.velocity += Vector2.up * Physics2D.gravity * Time.fixedDeltaTime * 2f;
        }
    }
    
    private void Jump()
    {
        // Reset vertical velocity
        rb.velocity = new Vector2(rb.velocity.x, 0f);
        
        // Apply jump force
        rb.AddForce(Vector2.up * jumpForce, ForceMode2D.Impulse);
        
        // Trigger jump animation
        if (animator != null)
        {
            animator.SetTrigger("Jump");
        }
        
        // Play jump sound
        PlaySound("Jump");
    }
    
    private void Dash()
    {
        // Apply dash force
        float dashForce = 15f;
        float dashDirection = facingRight ? 1f : -1f;
        
        rb.velocity = new Vector2(dashForce * dashDirection, rb.velocity.y);
        
        // Trigger dash animation
        if (animator != null)
        {
            animator.SetTrigger("Dash");
        }
        
        // Play dash sound
        PlaySound("Dash");
        
        // Start dash cooldown
        StartCoroutine(DashCooldown());
    }
    
    private void Attack()
    {
        // Trigger attack animation
        if (animator != null)
        {
            animator.SetTrigger("Attack");
        }
        
        // Play attack sound
        PlaySound("Attack");
        
        // Detect enemies in range
        DetectAndDamageEnemies();
    }
    
    private void Flip()
    {
        facingRight = !facingRight;
        Vector3 theScale = transform.localScale;
        theScale.x *= -1;
        transform.localScale = theScale;
    }
    
    private void UpdateAnimations()
    {
        if (animator == null) return;
        
        // Set movement parameters
        animator.SetFloat("Speed", Mathf.Abs(rb.velocity.x));
        animator.SetBool("IsGrounded", isGrounded);
        animator.SetFloat("VerticalSpeed", rb.velocity.y);
        
        // Set animation states
        if (Mathf.Abs(rb.velocity.x) > 0.1f)
        {
            animator.SetBool("IsMoving", true);
        }
        else
        {
            animator.SetBool("IsMoving", false);
        }
    }
    
    private void DetectAndDamageEnemies()
    {
        // Detect enemies in attack range
        Collider2D[] enemies = Physics2D.OverlapCircleAll(
            transform.position, 
            1.5f, 
            LayerMask.GetMask("Enemy")
        );
        
        foreach (Collider2D enemy in enemies)
        {
            EnemyController enemyController = enemy.GetComponent<EnemyController>();
            if (enemyController != null)
            {
                enemyController.TakeDamage(10);
            }
        }
    }
    
    private void PlaySound(string soundName)
    {
        // Play sound through AudioManager
        AudioManager.Instance.PlaySound(soundName);
    }
    
    private IEnumerator DashCooldown()
    {
        // Disable dash for cooldown period
        float cooldownTime = 1f;
        
        // Visual feedback
        SpriteRenderer spriteRenderer = GetComponent<SpriteRenderer>();
        if (spriteRenderer != null)
        {
            Color originalColor = spriteRenderer.color;
            spriteRenderer.color = new Color(1f, 1f, 1f, 0.5f);
            
            yield return new WaitForSeconds(cooldownTime);
            
            spriteRenderer.color = originalColor;
        }
    }
    
    // Collision handling
    private void OnCollisionEnter2D(Collision2D collision)
    {
        if (collision.gameObject.CompareTag("Enemy"))
        {
            TakeDamage(10);
        }
        else if (collision.gameObject.CompareTag("Collectible"))
        {
            CollectItem(collision.gameObject);
        }
        else if (collision.gameObject.CompareTag("Platform"))
        {
            // Platform specific logic
            HandlePlatformCollision(collision);
        }
    }
    
    private void TakeDamage(int damage)
    {
        // Apply damage to player
        // This would be handled by a separate health system
        
        // Trigger hurt animation
        if (animator != null)
        {
            animator.SetTrigger("Hurt");
        }
        
        // Play hurt sound
        PlaySound("Hurt");
        
        // Knockback
        Vector2 knockbackDirection = (transform.position - collision.transform.position).normalized;
        rb.AddForce(knockbackDirection * 5f, ForceMode2D.Impulse);
        
        // Start invincibility frames
        StartCoroutine(InvincibilityFrames());
    }
    
    private void CollectItem(GameObject item)
    {
        // Collect item logic
        CollectibleItem collectible = item.GetComponent<CollectibleItem>();
        if (collectible != null)
        {
            collectible.Collect();
        }
        
        // Play collect sound
        PlaySound("Collect");
        
        // Trigger collect animation
        if (animator != null)
        {
            animator.SetTrigger("Collect");
        }
    }
    
    private void HandlePlatformCollision(Collision2D collision)
    {
        // Make player child of moving platform
        if (collision.gameObject.CompareTag("MovingPlatform"))
        {
            transform.SetParent(collision.transform);
        }
    }
    
    private void OnCollisionExit2D(Collision2D collision)
    {
        // Unparent from moving platforms
        if (collision.gameObject.CompareTag("MovingPlatform"))
        {
            transform.SetParent(null);
        }
    }
    
    private IEnumerator InvincibilityFrames()
    {
        // Enable invincibility
        Physics2D.IgnoreLayerCollision(gameObject, LayerMask.GetMask("Enemy"));
        
        // Visual feedback
        SpriteRenderer spriteRenderer = GetComponent<SpriteRenderer>();
        if (spriteRenderer != null)
        {
            Color originalColor = spriteRenderer.color;
            spriteRenderer.color = new Color(1f, 1f, 1f, 0.3f);
            
            yield return new WaitForSeconds(1f);
            
            spriteRenderer.color = originalColor;
        }
        
        // Disable invincibility
        Physics2D.IgnoreLayerCollision(gameObject, LayerMask.GetMask("Enemy"));
    }
    
    // Public methods
    public void SetVelocity(Vector2 newVelocity)
    {
        velocity = newVelocity;
    }
    
    public Vector2 GetVelocity()
    {
        return velocity;
    }
    
    public bool IsFacingRight()
    {
        return facingRight;
    }
    
    public bool IsGrounded()
    {
        return isGrounded;
    }
}

// Enemy Controller
public class EnemyController : MonoBehaviour
{
    [Header("Enemy Settings")]
    [SerializeField] private int maxHealth = 100;
    [SerializeField] private int damage = 10;
    [SerializeField] private float moveSpeed = 2f;
    [SerializeField] private float detectionRange = 5f;
    [SerializeField] private float attackRange = 1f;
    [SerializeField] private LayerMask playerLayer;
    
    [Header("Animation")]
    [SerializeField] private Animator animator;
    [SerializeField] private GameObject deathEffect;
    
    private int currentHealth;
    private Transform player;
    private bool isDead = false;
    private bool canAttack = true;
    
    private void Awake()
    {
        currentHealth = maxHealth;
        
        if (animator == null)
            animator = GetComponent<Animator>();
    }
    
    private void Start()
    {
        // Find player
        GameObject playerObj = GameObject.FindGameObjectWithTag("Player");
        if (playerObj != null)
        {
            player = playerObj.transform;
        }
    }
    
    private void Update()
    {
        if (isDead) return;
        
        // Check if player is in range
        if (player != null)
        {
            float distanceToPlayer = Vector2.Distance(transform.position, player.position);
            
            if (distanceToPlayer <= detectionRange)
            {
                if (distanceToPlayer <= attackRange && canAttack)
                {
                    Attack();
                }
                else
                {
                    MoveTowardsPlayer();
                }
            }
            else
            {
                Patrol();
            }
        }
        
        UpdateAnimations();
    }
    
    private void MoveTowardsPlayer()
    {
        if (player == null) return;
        
        Vector2 direction = (player.position - transform.position).normalized;
        transform.position = Vector2.MoveTowards(
            transform.position, 
            player.position, 
            moveSpeed * Time.deltaTime
        );
        
        // Flip enemy based on direction
        if (direction.x > 0 && transform.localScale.x < 0)
        {
            Flip();
        }
        else if (direction.x < 0 && transform.localScale.x > 0)
        {
            Flip();
        }
    }
    
    private void Patrol()
    {
        // Simple patrol behavior
        // This would be expanded with waypoints or random movement
        transform.position += Vector2.right * moveSpeed * Time.deltaTime * Mathf.Sign(Mathf.Sin(Time.time));
    }
    
    private void Attack()
    {
        // Trigger attack animation
        if (animator != null)
        {
            animator.SetTrigger("Attack");
        }
        
        // Start attack cooldown
        StartCoroutine(AttackCooldown());
        
        // Deal damage to player if in range
        float distanceToPlayer = Vector2.Distance(transform.position, player.position);
        if (distanceToPlayer <= attackRange)
        {
            PlayerController playerController = player.GetComponent<PlayerController>();
            if (playerController != null)
            {
                playerController.TakeDamage(damage);
            }
        }
    }
    
    private IEnumerator AttackCooldown()
    {
        canAttack = false;
        yield return new WaitForSeconds(1.5f);
        canAttack = true;
    }
    
    private void UpdateAnimations()
    {
        if (animator == null) return;
        
        animator.SetBool("IsDead", isDead);
        animator.SetBool("IsMoving", player != null && Vector2.Distance(transform.position, player.position) > attackRange);
    }
    
    private void Flip()
    {
        Vector3 theScale = transform.localScale;
        theScale.x *= -1;
        transform.localScale = theScale;
    }
    
    public void TakeDamage(int damageAmount)
    {
        if (isDead) return;
        
        currentHealth -= damageAmount;
        
        // Trigger hurt animation
        if (animator != null)
        {
            animator.SetTrigger("Hurt");
        }
        
        // Visual feedback
        SpriteRenderer spriteRenderer = GetComponent<SpriteRenderer>();
        if (spriteRenderer != null)
        {
            StartCoroutine(FlashRed());
        }
        
        // Check if dead
        if (currentHealth <= 0)
        {
            Die();
        }
    }
    
    private IEnumerator FlashRed()
    {
        SpriteRenderer spriteRenderer = GetComponent<SpriteRenderer>();
        if (spriteRenderer != null)
        {
            Color originalColor = spriteRenderer.color;
            spriteRenderer.color = Color.red;
            
            yield return new WaitForSeconds(0.1f);
            
            spriteRenderer.color = originalColor;
        }
    }
    
    private void Die()
    {
        isDead = true;
        
        // Trigger death animation
        if (animator != null)
        {
            animator.SetTrigger("Die");
        }
        
        // Disable collision
        GetComponent<Collider2D>().enabled = false;
        
        // Disable movement
        enabled = false;
        
        // Spawn death effect
        if (deathEffect != null)
        {
            Instantiate(deathEffect, transform.position, Quaternion.identity);
        }
        
        // Remove enemy after delay
        StartCoroutine(DestroyAfterDelay());
    }
    
    private IEnumerator DestroyAfterDelay()
    {
        yield return new WaitForSeconds(2f);
        Destroy(gameObject);
    }
}

// Collectible Item
public class CollectibleItem : MonoBehaviour
{
    [Header("Item Settings")]
    [SerializeField] private string itemName = "Coin";
    [SerializeField] private int value = 1;
    [SerializeField] private GameObject collectEffect;
    [SerializeField] private AudioClip collectSound;
    
    private bool isCollected = false;
    
    private void OnTriggerEnter2D(Collider2D other)
    {
        if (isCollected) return;
        
        if (other.CompareTag("Player"))
        {
            Collect();
        }
    }
    
    public void Collect()
    {
        if (isCollected) return;
        
        isCollected = true;
        
        // Add to player inventory
        PlayerController player = FindObjectOfType<PlayerController>();
        if (player != null)
        {
            // This would interface with an inventory system
            Debug.Log($"Collected {itemName} worth {value} points");
        }
        
        // Spawn collect effect
        if (collectEffect != null)
        {
            Instantiate(collectEffect, transform.position, Quaternion.identity);
        }
        
        // Play collect sound
        if (collectSound != null)
        {
            AudioSource.PlayClipAtPoint(collectSound, transform.position);
        }
        
        // Destroy item
        Destroy(gameObject);
    }
    
    public string GetItemName()
    {
        return itemName;
    }
    
    public int GetValue()
    {
        return value;
    }
}

// AudioManager Singleton
public class AudioManager : MonoBehaviour
{
    public static AudioManager Instance { get; private set; }
    
    [Header("Audio Settings")]
    [SerializeField] private AudioSource musicSource;
    [SerializeField] private AudioSource sfxSource;
    [SerializeField] private AudioClip[] musicTracks;
    [SerializeField] private AudioClip[] soundEffects;
    
    private Dictionary<string, AudioClip> soundDictionary;
    
    private void Awake()
    {
        if (Instance == null)
        {
            Instance = this;
            DontDestroyOnLoad(gameObject);
        }
        else
        {
            Destroy(gameObject);
        }
    }
    
    private void Start()
    {
        // Initialize sound dictionary
        soundDictionary = new Dictionary<string, AudioClip>();
        
        foreach (AudioClip clip in soundEffects)
        {
            soundDictionary[clip.name] = clip;
        }
        
        // Play background music
        PlayMusic("BackgroundMusic");
    }
    
    public void PlayMusic(string musicName)
    {
        AudioClip musicClip = Array.Find(musicTracks, clip => clip.name == musicName);
        
        if (musicClip != null && musicSource != null)
        {
            musicSource.clip = musicClip;
            musicSource.loop = true;
            musicSource.Play();
        }
    }
    
    public void PlaySound(string soundName)
    {
        if (soundDictionary.ContainsKey(soundName) && sfxSource != null)
        {
            sfxSource.PlayOneShot(soundDictionary[soundName]);
        }
    }
    
    public void StopMusic()
    {
        if (musicSource != null)
        {
            musicSource.Stop();
        }
    }
    
    public void SetMusicVolume(float volume)
    {
        if (musicSource != null)
        {
            musicSource.volume = volume;
        }
    }
    
    public void SetSFXVolume(float volume)
    {
        if (sfxSource != null)
        {
            sfxSource.volume = volume;
        }
    }
}

2. Unreal Engine Game with C++ - 3D Shooter

// PlayerCharacter.h
#pragma once

#include "CoreMinimal.h"
#include "GameFramework/Character.h"
#include "GameFramework/SpringArmComponent.h"
#include "GameFramework/CameraComponent.h"
#include "Components/HealthComponent.h"
#include "Components/StaminaComponent.h"
#include "Components/WeaponComponent.h"

#include "PlayerCharacter.generated.h"

UCLASS()
class APlayerCharacter : public ACharacter
{
    GENERATED_BODY()

public:
    APlayerCharacter();

    virtual void SetupPlayerInput(UInputComponent* PlayerInputComponent) override;
    virtual void BeginPlay() override;

    // Movement
    UFUNCTION(BlueprintCallable, Category = "Player")
    void MoveForward(float Value);
    
    UFUNCTION(BlueprintCallable, Category = "Player")
    void MoveRight(float Value);
    
    UFUNCTION(BlueprintCallable, Category = "Player")
    void Turn(float Value);
    
    UFUNCTION(BlueprintCallable, Category = "Player")
    void StartJump();
    
    UFUNCTION(BlueprintCallable, Category = "Player")
    void StopJumping();
    
    // Combat
    UFUNCTION(BlueprintCallable, Category = "Player")
    void StartFire();
    
    UFUNCTION(BlueprintCallable, Category = "Player")
    void StopFire();
    
    UFUNCTION(BlueprintCallable, Category = "Player")
    void Reload();
    
    UFUNCTION(BlueprintCallable, Category = "Player")
    void Aim();
    
    UFUNCTION(BlueprintCallable, Category = "Player")
    void StopAiming();
    
    // Camera
    UFUNCTION(BlueprintCallable, Category = "Player")
    void ToggleCameraMode();
    
    // Health and Stamina
    UFUNCTION(BlueprintCallable, Category = "Player")
    float GetHealth() const;
    
    UFUNCTION(BlueprintCallable, Category = "Player")
    float GetMaxHealth() const;
    
    UFUNCTION(BlueprintCallable, Category = "Player")
    float GetStamina() const;
    
    UFUNCTION(BlueprintCallable, Category = "Player")
    float GetMaxStamina() const;
    
    // Weapon
    UFUNCTION(BlueprintCallable, Category = "Player")
    AWeaponComponent* GetCurrentWeapon() const;
    
    UFUNCTION(BlueprintCallable, Category = "Player")
    void EquipWeapon(class AWeapon* Weapon);
    
    // Movement
    UFUNCTION(BlueprintCallable, Category = "Player")
    bool IsMoving() const;
    
    UFUNCTION(BlueprintCallable, Category = "Player")
    bool IsJumping() const;
    
    UFUNCTION(BlueprintCallable, Category = "Player")
    bool IsAiming() const;
    
    UFUNCTION(BlueprintCallable, Category = "Player")
    bool IsSprinting() const;

protected:
    virtual void Tick(float DeltaTime) override;
    virtual void SetupPlayerInputComponent(UInputComponent* PlayerInputComponent) override;
    
private:
    // Movement
    void MoveForward(float Value);
    void MoveRight(float Value);
    void Turn(float Value);
    void StartJump();
    void StopJumping();
    
    // Combat
    void StartFire();
    void StopFire();
    void Reload();
    void Aim();
    void StopAiming();
    
    // Camera
    void ToggleCameraMode();
    
    // Movement states
    UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Player")
    bool bIsMoving;
    
    UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Player")
    bool bIsJumping;
    
    UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Player")
    bool bIsAiming;
    
    UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Player")
    bool bIsSprinting;
    
    // Components
    UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Components")
    USpringArmComponent* SpringArmComponent;
    
    UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Components")
    UCameraComponent* CameraComponent;
    
    UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Components")
    UHealthComponent* HealthComponent;
    
    UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Components")
    UStaminaComponent* StaminaComponent;
    
    UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Components")
    UWeaponComponent* WeaponComponent;
    
    // Movement variables
    UPROPERTY(EditDefaults, Category = "Player|Movement")
    float BaseTurnRate;
    
    UPROPERTY(EditDefaults, Category = "Player|Movement")
    float LookUpRate;
    
    UPROPERTY(EditDefaults, Category = "Player|Movement")
    float JumpHeight;
    
    UPROPERTY(EditDefaults, Category = "Player|Movement")
    float AirControl;
    
    // Combat variables
    UPROPERTY(EditDefaults, Category = "Player|Combat")
    float BaseTurnRate;
    
    UPROPERTY(EditDefaults, Category = "Player|Combat")
    float AimSensitivity;
    
    // Camera variables
    UPROPERTY(EditDefaults, Category = "Player|Camera")
    bool bFirstPerson;
    
    UPROPERTY(EditDefaults, Category = "Player|Camera")
    float BaseFOV;
    
    UPROPERTY(EditDefaults, Category = "Player|Camera")
    float AimFOV;
    
    // Movement
    UPROPERTY(EditDefaults, Category = "Player|Movement")
    float MaxWalkSpeed;
    
    UPROPERTY(EditDefaults, Category = "Player|Movement")
    float MaxRunSpeed;
    
    UPROPERTY(EditDefaults, Category = "Player|Movement")
    float MaxSprintSpeed;
    
    UPROPERTY(EditDefaults, Category = "Player|Movement")
    float SprintStaminaCost;
    
    // Combat
    UPROPERTY(EditDefaults, Category = "Player|Combat")
    float BaseTurnRate;
    
    UPROPERTY(EditDefaults, Category = "Player|Combat")
    float AimSensitivity;
    
    // Camera
    UPROPERTY(EditDefaults, Category = "Player|Camera")
    bool bFirstPerson;
    
    UPROPERTY(EditDefaults, Category = "Player|Camera")
    float BaseFOV;
    
    UPROPERTY(EditDefaults, Category = "Player|Camera")
    float AimFOV;
};

// PlayerCharacter.cpp
#include "PlayerCharacter.h"
#include "Engine/World.h"
#include "EnhancedInputComponent.h"
#include "Components/EnhancedInputComponent.h"
#include "GameFramework/CharacterMovementComponent.h"
#include "Camera/CameraComponent.h"
#include "Kismet/GameplayStatics.h"

APlayerCharacter::APlayerCharacter()
{
    // Set this character to call Tick() every frame.  You can turn this off to improve performance if you don't need it.
    PrimaryActorTick.bCanEverTick = true;
    
    // Create components
    SpringArmComponent = CreateDefaultSubobject<USpringArmComponent>(TEXT("SpringArmComponent"));
    CameraComponent = CreateDefaultSubobject<UCameraComponent>(TEXT("CameraComponent"));
    HealthComponent = CreateDefaultSubobject<UHealthComponent>(TEXT("HealthComponent"));
    StaminaComponent = CreateDefaultSubobject<UStaminaComponent>(TEXT("StaminaComponent"));
    WeaponComponent = CreateDefaultSubobject<UWeaponComponent>(TEXT("WeaponComponent"));
    
    // Set default values
    BaseTurnRate = 45.0f;
    LookUpRate = 45.0f;
    JumpHeight = 300.0f;
    AirControl = 0.05f;
    
    AimSensitivity = 1.0f;
    
    bFirstPerson = true;
    BaseFOV = 90.0f;
    AimFOV = 60.0f;
    
    MaxWalkSpeed = 600.0f;
    MaxRunSpeed = 900.0f;
    MaxSprintSpeed = 1200.0f;
    SprintStaminaCost = 10.0f;
    
    bIsMoving = false;
    bIsJumping = false;
    bIsAiming = false;
    bIsSprinting = false;
}

void APlayerCharacter::BeginPlay()
{
    Super::BeginPlay();
    
    // Setup input
    if (APlayerController* PC = Cast<APlayerController>(Controller))
    {
        PC->SetupPlayerInput(this);
    }
    
    // Initialize components
    if (HealthComponent)
    {
        HealthComponent->OnDeath.AddDynamic(this, &APlayerCharacter::OnDeath);
    }
    
    // Equip default weapon
    if (WeaponComponent)
    {
        // This would be set up based on game rules
        // WeaponComponent->SpawnWeapon(DefaultWeaponClass);
    }
}

void APlayerCharacter::Tick(float DeltaTime)
{
    Super::Tick(DeltaTime);
    
    // Update movement states
    UpdateMovementStates();
    
    // Update camera
    UpdateCamera(DeltaTime);
    
    // Handle stamina regeneration
    if (StaminaComponent && !bIsSprinting)
    {
        StaminaComponent->RegenerateStamina(DeltaTime);
    }
}

void APlayerCharacter::SetupPlayerInput(UInputComponent* PlayerInputComponent)
{
    // Bind movement actions
    PlayerInputComponent->BindAction(EEnhancedInputAction::IA_MoveForward, this, &APlayerCharacter::MoveForward);
    PlayerInputComponent->BindAction(EEnhancedInputAction::IA_MoveRight, this, &APlayerCharacter::MoveRight);
    PlayerInputComponent->BindAction(EEnhancedInputAction::IA_Turn, this, &APlayerCharacter::Turn);
    PlayerInputComponent->BindAction(EEnhancedInputAction::IA_Jump, this, &APlayerCharacter::StartJump);
    PlayerInputComponent->BindAction(EEnhancedInputAction::IA_StopJump, this, &APlayerCharacter::StopJumping);
    
    // Bind combat actions
    PlayerInputComponent->BindAction(EEnhancedInputAction::IA_Fire, this, &APlayerCharacter::StartFire);
    PlayerInputComponent->BindAction(EEnhancedInputAction::IA_StopFire, this, &APlayerCharacter::StopFire);
    PlayerInputComponent->BindAction(EEnhancedInputAction::IA_Reload, this, &APlayerCharacter::Reload);
    PlayerInputComponent->BindAction(EEnhancedInputAction::IA_Aim, this, &APlayerCharacter::Aim);
    PlayerInputComponent->BindAction(EEnhancedInputAction::IA_StopAim, this, &APlayerCharacter::StopAiming);
    
    // Bind utility actions
    PlayerInputComponent->BindAction(EEnhancedInputAction::IA_ToggleCamera, this, &APlayerCharacter::ToggleCameraMode);
    
    // Bind sprint action
    PlayerInputComponent->BindAction(EEnhancedInputAction::IA_Sprint, this, &APlayerCharacter::StartSprint);
    PlayerInputComponent->BindAction(EEnhancedInputAction::IA_StopSprint, this, &APlayerCharacter::StopSprinting);
}

void APlayerCharacter::MoveForward(float Value)
{
    if (Controller != nullptr)
    {
        const FRotator = GetControlRotation();
        const FRotation = FRotator.Pitch;
        
        // Calculate movement direction
        const FVector Direction = FRotation.Vector();
        const FVector MovementVector = Direction * Value;
        
        // Apply movement
        AddMovementInput(MovementVector);
        
        // Set moving state
        bIsMoving = FMath::Abs(Value) > 0.1f;
    }
}

void APlayerCharacter::MoveRight(float Value)
{
    if (Controller != nullptr)
    {
        const FRotator = GetControlRotation();
        const FRotation = FRotator.Yaw;
        
        // Calculate movement direction
        const FVector Direction = FRotation.RightVector();
        const FVector MovementVector = Direction * Value;
        
        // Apply movement
        AddMovementInput(MovementVector);
        
        // Set moving state
        bIsMoving = FMath::Abs(Value) > 0.1f;
    }
}

void APlayerCharacter::Turn(float Value)
{
    if (Controller != nullptr)
    {
        // Apply turn
        AddControllerYawInput(Value * BaseTurnRate * GetWorld()->GetDeltaSeconds());
    }
}

void APlayerCharacter::StartJump()
{
    if (bIsJumping) return;
    
    // Check if can jump
    if (CanJump())
    {
        // Jump
        bIsJumping = true;
        
        // Play jump montage
        if (UAnimInstance* JumpMontage = GetMesh()->GetAnimInstance())
        {
            JumpMontage->Montage_Play("Jump");
        }
        
        // Apply jump force
        LaunchCharacter(FVector(0.0f, 0.0f, JumpHeight));
        
        // Play jump sound
        if (USoundBase* JumpSound = GEngine->SoundBase)
        {
            JumpSound->PlaySound2D(GetActorLocation());
        }
    }
}

void APlayerCharacter::StopJumping()
{
    // Stop jumping
    bIsJumping = false;
    
    // Stop jump montage
    if (UAnimInstance* JumpMontage = GetMesh()->GetAnimInstance())
    {
        JumpMontage->Montage_Stop("Jump");
    }
}

void APlayerCharacter::StartFire()
{
    if (WeaponComponent)
    {
        WeaponComponent->StartFire();
        
        // Set aiming state
        bIsAiming = true;
        
        // Update camera for aiming
        if (CameraComponent && bFirstPerson)
        {
            CameraComponent->SetFieldOfView(AimFOV);
        }
    }
}

void APlayerCharacter::StopFire()
{
    if (WeaponComponent)
    {
        WeaponComponent->StopFire();
    }
    
    // Clear aiming state
    bIsAiming = false;
    
    // Reset camera
    if (CameraComponent && bFirstPerson)
    {
        CameraComponent->SetFieldOfView(BaseFOV);
    }
}

void APlayerCharacter::Reload()
{
    if (WeaponComponent)
    {
        WeaponComponent->Reload();
    }
}

void APlayerCharacter::Aim()
{
    // Start aiming
    bIsAiming = true;
    
    // Update camera for aiming
    if (CameraComponent && bFirstPerson)
    {
        CameraComponent->SetFieldOfView(AimFOV);
        
        // Reduce mouse sensitivity for precision aiming
        if (APlayerController* PC = Cast<APlayerController>(Controller))
        {
            PC->SetAimSensitivity(AimSensitivity * 0.5f);
        }
    }
    
    // Play aim montage
    if (UAnimInstance* AimMontage = GetMesh()->GetAnimInstance())
    {
        AimMontage->Montage_Play("Aim");
    }
}

void APlayerCharacter::StopAiming()
{
    // Stop aiming
    bIsAiming = false;
    
    // Reset camera
    if (CameraComponent && bFirstPerson)
    {
        CameraComponent->SetFieldOfView(BaseFOV);
    }
    
    // Reset mouse sensitivity
    if (APlayerController* PC = Cast<APlayerController>(Controller))
    {
        PC->SetAimSensitivity(AimSensitivity);
    }
    
    // Stop aim montage
    if (UAnimInstance* AimMontage = GetMesh()->GetAnimInstance())
    {
        AimMontage->Montage_Stop("Aim");
    }
}

void APlayerCharacter::ToggleCameraMode()
{
    // Toggle between first and third person
    bFirstPerson = !bFirstPerson;
    
    // Update camera
    if (CameraComponent)
    {
        if (bFirstPerson)
        {
            CameraComponent->AttachToComponent(SpringArmComponent, USpringArmComponent::SocketName);
            CameraComponent->SetFieldOfView(bIsAiming ? AimFOV : BaseFOV);
        }
        else
        {
            CameraComponent->DetachFromController();
            CameraComponent->SetFieldOfView(BaseFOV);
        }
    }
}

void APlayerCharacter::StartSprint()
{
    if (bIsSprinting || !CanSprint()) return;
    
    // Start sprinting
    bIsSprinting = true;
    
    // Update movement speed
    if (UCharacterMovementComponent* MovementComponent = GetCharacterMovement())
    {
        MovementComponent->MaxWalkSpeed = MaxSprintSpeed;
    }
    
    // Play sprint montage
    if (UAnimInstance* SprintMontage = GetMesh()->GetAnimInstance())
    {
        SprintMontage->Montage_Play("Sprint");
    }
    
    // Play sprint sound
    if (USoundBase* SprintSound = GEngine->SoundBase)
    {
        SprintSound->PlaySound2D(GetActorLocation());
    }
}

void APlayerCharacter::StopSprinting()
{
    if (!bIsSprinting) return;
    
    // Stop sprinting
    bIsSprinting = false;
    
    // Reset movement speed
    if (UCharacterMovementComponent* MovementComponent = GetCharacterMovement())
    {
        MovementComponent->MaxWalkSpeed = MaxRunSpeed;
    }
    
    // Stop sprint montage
    if (UAnimInstance* SprintMontage = GetMesh()->GetAnimInstance())
    {
        SprintMontage->Montage_Stop("Sprint");
    }
}

void APlayerCharacter::UpdateMovementStates()
{
    // Update jumping state
    if (GetCharacterMovement())
    {
        bIsJumping = !GetCharacterMovement()->IsMovingOnGround();
    }
    
    // Update moving state
    bIsMoving = GetVelocity().Size2D() > 0.1f;
    
    // Handle sprint stamina
    if (bIsSprinting && StaminaComponent)
    {
        StaminaComponent->ConsumeStamina(SprintStaminaCost * GetWorld()->GetDeltaSeconds());
        
        // Stop sprinting if out of stamina
        if (StaminaComponent->GetStamina() <= 0.0f)
        {
            StopSprinting();
        }
    }
}

void APlayerCharacter::UpdateCamera(float DeltaTime)
{
    if (CameraComponent)
    {
        // Handle camera shake when firing
        if (WeaponComponent && WeaponComponent->IsFiring())
        {
            float CameraShakeIntensity = WeaponComponent->GetCameraShakeIntensity();
            if (CameraShakeIntensity > 0.0f)
            {
                // Apply camera shake
                FVector CameraLocation = CameraComponent->GetComponentLocation();
                FRotator CameraRotation = CameraComponent->GetComponentRotation();
                
                // Add random offset
                float RandomX = FMath::RandRange(-CameraShakeIntensity, CameraShakeIntensity);
                float RandomY = FMath::RandRange(-CameraShakeIntensity, CameraShakeIntensity);
                float RandomZ = FMath::RandRange(-CameraShakeIntensity, CameraShakeIntensity);
                
                FVector CameraOffset = FVector(RandomX, RandomY, RandomZ);
                FRotator CameraOffsetRotation = FRotator(RandomX, RandomY, RandomZ);
                
                CameraComponent->SetWorldLocationAndRotation(CameraLocation + CameraOffset, CameraRotation + CameraOffsetRotation);
            }
        }
    }
}

float APlayerCharacter::GetHealth() const
{
    return HealthComponent ? HealthComponent->GetHealth() : 0.0f;
}

float APlayerCharacter::GetMaxHealth() const
{
    return HealthComponent ? HealthComponent->GetMaxHealth() : 0.0f;
}

float APlayerCharacter::GetStamina() const
{
    return StaminaComponent ? StaminaComponent->GetStamina() : 0.0f;
}

float APlayerCharacter::GetMaxStamina() const
{
    return StaminaComponent ? StaminaComponent->MaxStamina : 0.0f;
}

AWeaponComponent* APlayerCharacter::GetCurrentWeapon() const
{
    return WeaponComponent;
}

void APlayerCharacter::EquipWeapon(AWeapon* Weapon)
{
    if (WeaponComponent)
    {
        WeaponComponent->EquipWeapon(Weapon);
    }
}

bool APlayerCharacter::IsMoving() const
{
    return bIsMoving;
}

bool APlayerCharacter::IsJumping() const
{
    return bIsJumping;
}

bool APlayerCharacter::IsAiming() const
{
    return bIsAiming;
}

bool APlayerCharacter::IsSprinting() const
{
    return bIsSprinting;
}

bool APlayerCharacter::CanSprint() const
{
    return !bIsJumping && StaminaComponent && StaminaComponent->GetStamina() > SprintStaminaCost;
}

void APlayerCharacter::OnDeath()
{
    // Handle death
    DisableInput();
    
    // Play death montage
    if (UAnimInstance* DeathMontage = GetMesh()->GetAnimInstance())
    {
        DeathMontage->Montage_Play("Death");
    }
    
    // Disable collision
    SetActorEnableCollision(false);
    
    // Hide weapon
    if (WeaponComponent)
    {
        WeaponComponent->SetVisibility(false);
    }
    
    // Ragdoll physics
    if (GetCapsuleComponent())
    {
        GetCapsuleComponent->SetSimulatePhysics(true);
    }
    
    // Game over handling
    if (APlayerController* PC = Cast<APlayerController>(Controller))
    {
        PC->OnPlayerDeath();
    }
}

// Enhanced Input Component
UCLASS()
class AEnhancedInputComponent : public UInputComponent
{
    GENERATED_BODY()

public:
    AEnhancedInputComponent();
    
    virtual void SetupInputBinding(UInputComponent* PlayerInputComponent) override;
    
protected:
    virtual void BeginPlay() override;
    
private:
    UEnhancedInputAction CurrentAction;
    float ActionValue;
    
    void HandleMovement(float Value);
    void HandleCombat(float Value);
    void HandleUtility(float Value);
};

// Enhanced Input Component Implementation
AEnhancedInputComponent::AEnhancedInputComponent()
{
    CurrentAction = EEnhancedInputAction::IA_None;
    ActionValue = 0.0f;
}

void AEnhancedInputComponent::BeginPlay()
{
    Super::BeginPlay();
    
    // Setup input binding
    SetupInputBinding(this);
}

void AEnhancedInputComponent::SetupInputBinding(UInputComponent* PlayerInputComponent)
{
    // Movement bindings
    PlayerInputComponent->BindAxis("MoveForward", this, &AEnhancedInputComponent::HandleMovement);
    PlayerInputComponent->BindAxis("MoveRight", this, &AEnhancedInputComponent::HandleMovement);
    PlayerInputComponent->BindAxis("Turn", this, &AEnhancedInputComponent::HandleMovement);
    PlayerInputComponent->BindAxis("LookUp", this, &AEnhancedInputComponent::HandleMovement);
    
    // Combat bindings
    PlayerInputComponent->BindAction("Fire", this, &AEnhancedInputComponent::HandleCombat);
    PlayerInputComponent->BindAction("Reload", this, &AEnhancedInputComponent::HandleCombat);
    PlayerInputComponent->BindAction("Aim", this, &AEnhancedInputComponent::HandleCombat);
    
    // Utility bindings
    PlayerInputComponent->BindAction("Jump", this, &AEnhancedInputComponent::HandleUtility);
    PlayerInputComponent->BindAction("Sprint", this, &AEnhancedInputComponent::HandleUtility);
    PlayerInputComponent->BindAction("ToggleCamera", this, &AEnhancedInputComponent::HandleUtility);
}

void AEnhancedInputComponent::HandleMovement(float Value)
{
    CurrentAction = EEnhancedInputAction::IA_MoveForward;
    ActionValue = Value;
    
    if (APlayerCharacter* Player = Cast<APlayerCharacter>(GetOwner()))
    {
        switch (CurrentAction)
        {
            case EEnhancedInputAction::IA_MoveForward:
                Player->MoveForward(Value);
                break;
            case EEnhancedInputAction::IA_MoveRight:
                Player->MoveRight(Value);
                break;
            case EEnhancedInputAction::IA_Turn:
                Player->Turn(Value);
                break;
            case EEnhancedInputAction::IA_LookUp:
                // Handle look up/down
                break;
        }
    }
}

void AEnhancedInputComponent::HandleCombat(float Value)
{
    CurrentAction = EEnhancedInputAction::IA_Fire;
    ActionValue = Value;
    
    if (APlayerCharacter* Player = Cast<APlayerCharacter>(GetOwner()))
    {
        switch (CurrentAction)
        {
            case EEnhancedInputAction::IA_Fire:
                if (Value > 0.5f)
                {
                    Player->StartFire();
                }
                else
                {
                    Player->StopFire();
                }
                break;
            case EEnhancedInputAction::IA_Reload:
                if (Value > 0.5f)
                {
                    Player->Reload();
                }
                break;
            case EEnhancedInputAction::IA_Aim:
                if (Value > 0.5f)
                {
                    Player->Aim();
                }
                else
                {
                    Player->StopAiming();
                }
                break;
        }
    }
}

void AEnhancedInputComponent::HandleUtility(float Value)
{
    CurrentAction = EEnhancedInputAction::IA_Jump;
    ActionValue = Value;
    
    if (APlayerCharacter* Player = Cast<APlayerCharacter>(GetOwner()))
    {
        switch (CurrentAction)
        {
            case EEnhancedInputAction::IA_Jump:
                if (Value > 0.5f)
                {
                    Player->StartJump();
                }
                else
                {
                    Player->StopJumping();
                }
                break;
            case EEnhancedInputAction::IA_Sprint:
                if (Value > 0.5f)
                {
                    Player->StartSprint();
                }
                else
                {
                    Player->StopSprinting();
                }
                break;
            case EEnhancedInputAction::IA_ToggleCamera:
                if (Value > 0.5f)
                {
                    Player->ToggleCameraMode();
                }
                break;
        }
    }
}

3. Custom Physics Engine mit C++

// PhysicsEngine.h
#pragma once

#include "CoreMinimal.h"
#include "Math/Vector2D.h"
#include "Math/Vector3D.h"
#include "Containers/Array.h"
#include "Containers/Map.h"

class PhysicsBody;
class Collider;
class Rigidbody;

// Physics Engine class
class PHYSICS_API PhysicsEngine
{
public:
    PhysicsEngine();
    ~PhysicsEngine();
    
    // World management
    void SetGravity(const FVector2D& Gravity);
    void SetTimeStep(float TimeStep);
    
    // Body management
    PhysicsBody* CreateBody(const FVector2D& Position, float Mass);
    void DestroyBody(PhysicsBody* Body);
    
    // Collider management
    void AddCollider(PhysicsBody* Body, TSharedPtr<Collider> Collider);
    void RemoveCollider(PhysicsBody* Body, Collider* Collider);
    
    // Simulation
    void Step(float DeltaTime);
    
    // Query methods
    TArray<PhysicsBody*> GetBodiesInArea(const FVector2D& Min, const FVector2D& Max);
    bool IsOverlapping(const Collider* ColliderA, const Collider* ColliderB) const;
    
    // Debug rendering
    void DebugRender();
    
private:
    void UpdateBodies(float DeltaTime);
    void UpdateCollisions();
    void ResolveCollisions();
    
    void BroadPhaseCollisionDetection();
    void NarrowPhaseCollisionDetection();
    void CollisionResolution();
    
    void IntegrateForces(float DeltaTime);
    void ApplyGravity(float DeltaTime);
    
    TArray<PhysicsBody*> Bodies;
    TArray<TSharedPtr<Collider>> Colliders;
    
    TArray<CollisionPair> CollisionPairs;
    
    FVector2D Gravity;
    float TimeStep;
    
    bool bIsDebugRendering;
};

// Collision Pair structure
struct CollisionPair
{
    PhysicsBody* BodyA;
    PhysicsBody* BodyB;
    FVector2D ContactNormal;
    float PenetrationDepth;
    
    CollisionPair(PhysicsBody* InBodyA, PhysicsBody* InBodyB, const FVector2D& InNormal, float InPenetration)
        : BodyA(InBodyA), BodyB(InBodyB), ContactNormal(InNormal), PenetrationDepth(InPenetration) {}
};

// Physics Body class
class PHYSICS_API PhysicsBody
{
public:
    PhysicsBody(const FVector2D& Position, float Mass);
    ~PhysicsBody();
    
    // Position and movement
    void SetPosition(const FVector2D& Position);
    FVector2D GetPosition() const { return Position; }
    
    void SetVelocity(const FVector2D& Velocity);
    FVector2D GetVelocity() const { return Velocity; }
    
    void AddForce(const FVector2D& Force);
    void AddImpulse(const FVector2D& Impulse);
    
    // Properties
    void SetMass(float Mass);
    float GetMass() const { return Mass; }
    
    void SetStatic(bool bStatic);
    bool IsStatic() const { return bStatic; }
    
    void SetGravityScale(float Scale);
    float GetGravityScale() const { return GravityScale; }
    
    // Collision
    void SetCollisionEnabled(bool bEnabled);
    bool IsCollisionEnabled() const { return bCollisionEnabled; }
    
    // Components
    void AddCollider(TSharedPtr<Collider> Collider);
    void RemoveCollider(Collider* Collider);
    TArray<TSharedPtr<Collider>> GetColliders() const { return Colliders; }
    
    // Material properties
    void SetRestitution(float Restitution);
    float GetRestitution() const { return Restitution; }
    
    void SetFriction(float Friction);
    float GetFriction() const { return Friction; }
    
private:
    FVector2D Position;
    FVector2D Velocity;
    FVector2D Force;
    
    float Mass;
    float InverseMass;
    
    bool bStatic;
    float GravityScale;
    
    bool bCollisionEnabled;
    
    TArray<TSharedPtr<Collider>> Colliders;
    
    float Restitution;
    float Friction;
    
    friend class PhysicsEngine;
};

// Collider base class
class PHYSICS_API Collider
{
public:
    Collider();
    virtual ~Collider();
    
    // Type identification
    enum class EType
    {
        Circle,
        Rectangle,
        Polygon,
        Edge,
        Point
    };
    
    virtual EType GetType() const = 0;
    
    // Collision detection
    virtual bool Overlaps(const Collider* Other) const = 0;
    virtual bool ContainsPoint(const FVector2D& Point) const = 0;
    virtual bool IntersectsLine(const FVector2D& Start, const FVector2D& End) const = 0;
    
    // Collision response
    virtual void ComputeCollisionData(const Collider* Other, FVector2D& OutNormal, float& OutPenetration) const = 0;
    
    // Bounds
    virtual FVector2D GetCenter() const = 0;
    virtual FVector2D GetExtents() const = 0;
    
    // Material properties
    void SetRestitution(float Restitution);
    float GetRestitution() const { return Restitution; }
    
    void SetFriction(float Friction);
    float GetFriction() const { return Friction; }
    
protected:
    float Restitution;
    float Friction;
    
    friend class PhysicsEngine;
};

// Circle collider
class PHYSICS_API CircleCollider : public Collider
{
public:
    CircleCollider(float Radius);
    
    virtual EType GetType() const override { return Circle; }
    
    virtual bool Overlaps(const Collider* Other) const override;
    virtual bool ContainsPoint(const FVector2D& Point) const override;
    virtual bool IntersectsLine(const FVector2D& Start, const FVector2D& End) const override;
    virtual void ComputeCollisionData(const Collider* Other, FVector2D& OutNormal, float& OutPenetration) const override;
    
    virtual FVector2D GetCenter() const override;
    virtual FVector2D GetExtents() const override;
    
    void SetRadius(float NewRadius);
    float GetRadius() const { return Radius; }
    
private:
    float Radius;
};

// Rectangle collider
class PHYSICS_API RectangleCollider : public Collider
{
public:
    RectangleCollider(const FVector2D& Size);
    
    virtual EType GetType() const override { return Rectangle; }
    
    virtual bool Overlaps(const Collider* Other) const override;
    virtual bool ContainsPoint(const FVector2D& Point) const override;
    virtual bool IntersectsLine(const FVector2D& Start, const FVector2D& End) const override;
    virtual void ComputeCollisionData(const Collider* Other, FVector2D& OutNormal, float& OutPenetration) const override;
    
    virtual FVector2D GetCenter() const override;
    virtual FVector2D GetExtents() const override;
    
    void SetSize(const FVector2D& NewSize);
    FVector2D GetSize() const { return Size; }
    
private:
    FVector2D Size;
};

// Physics Engine Implementation
PhysicsEngine::PhysicsEngine()
{
    Gravity = FVector2D(0.0f, 9.81f);
    TimeStep = 1.0f / 60.0f;
    bIsDebugRendering = false;
}

PhysicsEngine::~PhysicsEngine()
{
    // Clean up bodies
    for (PhysicsBody* Body : Bodies)
    {
        delete Body;
    }
    Bodies.Empty();
    
    // Clean up colliders
    Colliders.Empty();
}

void PhysicsEngine::SetGravity(const FVector2D& InGravity)
{
    Gravity = InGravity;
}

void PhysicsEngine::SetTimeStep(float InTimeStep)
{
    TimeStep = InTimeStep;
}

PhysicsBody* PhysicsEngine::CreateBody(const FVector2D& Position, float Mass)
{
    PhysicsBody* Body = new PhysicsBody(Position, Mass);
    Bodies.Add(Body);
    return Body;
}

void PhysicsEngine::DestroyBody(PhysicsBody* Body)
{
    if (Bodies.Contains(Body))
    {
        Bodies.Remove(Body);
        delete Body;
    }
}

void PhysicsEngine::AddCollider(PhysicsBody* Body, TSharedPtr<Collider> Collider)
{
    if (Body && Collider)
    {
        Body->AddCollider(Collider);
        Colliders.Add(Collider);
    }
}

void PhysicsEngine::RemoveCollider(PhysicsBody* Body, Collider* Collider)
{
    if (Body && Body->GetColliders().Contains(Collider))
    {
        Body->RemoveCollider(Collider);
    }
    
    // Remove from global list
    for (int32 i = 0; i < Colliders.Num(); ++i)
    {
        if (Colliders[i].Get() == Collider)
        {
            Colliders.RemoveAt(i);
            break;
        }
    }
}

void PhysicsEngine::Step(float DeltaTime)
{
    // Update physics simulation
    UpdateBodies(DeltaTime);
    
    // Update collisions
    UpdateCollisions();
    
    // Resolve collisions
    ResolveCollisions();
}

void PhysicsEngine::UpdateBodies(float DeltaTime)
{
    for (PhysicsBody* Body : Bodies)
    {
        if (!Body->IsStatic())
        {
            // Apply gravity
            ApplyGravity(DeltaTime);
            
            // Integrate forces
            IntegrateForces(DeltaTime);
            
            // Update position
            FVector2D NewPosition = Body->GetPosition() + Body->GetVelocity() * DeltaTime;
            Body->SetPosition(NewPosition);
        }
    }
}

void PhysicsEngine::UpdateCollisions()
{
    CollisionPairs.Empty();
    
    // Broad phase collision detection
    BroadPhaseCollisionDetection();
    
    // Narrow phase collision detection
    NarrowPhaseCollisionDetection();
}

void PhysicsEngine::BroadPhaseCollisionDetection()
{
    // Simple spatial hashing for broad phase
    const int32 GridSize = 100;
    TMap<FVector2D, TArray<PhysicsBody*>> SpatialGrid;
    
    // Add bodies to spatial grid
    for (PhysicsBody* Body : Bodies)
    {
        if (!Body->IsCollisionEnabled()) continue;
        
        FVector2D GridPos = FVector2D(
            FMath::Floor(Body->GetPosition().X / GridSize),
            FMath::Floor(Body->GetPosition().Y / GridSize)
        );
        
        SpatialGrid.FindOrAdd(GridPos).Add(Body);
    }
    
    // Check potential collisions
    for (auto& GridCell : SpatialGrid)
    {
        TArray<PhysicsBody*>& CellBodies = GridCell.Value;
        
        for (int32 i = 0; i < CellBodies.Num(); ++i)
        {
            for (int32 j = i + 1; j < CellBodies.Num(); ++j)
            {
                PhysicsBody* BodyA = CellBodies[i];
                PhysicsBody* BodyB = CellBodies[j];
                
                // Quick AABB check
                if (CheckAABBOverlap(BodyA, BodyB))
                {
                    CollisionPairs.Add(CollisionPair(BodyA, BodyB));
                }
            }
        }
    }
}

void PhysicsEngine::NarrowPhaseCollisionDetection()
{
    for (CollisionPair& Pair : CollisionPairs)
    {
        PhysicsBody* BodyA = Pair.BodyA;
        PhysicsBody* BodyB = Pair.BodyB;
        
        // Get colliders for each body
        TArray<TSharedPtr<Collider>> CollidersA = BodyA->GetColliders();
        TArray<TSharedPtr<Collider>> CollidersB = BodyB->GetColliders();
        
        // Check each collider pair
        for (const TSharedPtr<Collider>& ColliderA : CollidersA)
        {
            for (const TSharedPtr<Collider>& ColliderB : CollidersB)
            {
                if (ColliderA->Overlaps(ColliderB.Get()))
                {
                    // Compute collision data
                    FVector2D Normal;
                    float Penetration;
                    ColliderA->ComputeCollisionData(ColliderB.Get(), Normal, Penetration);
                    
                    // Add collision pair with computed data
                    Pair.ContactNormal = Normal;
                    Pair.PenetrationDepth = Penetration;
                    
                    break; // Only one collision per pair
                }
            }
        }
    }
}

void PhysicsEngine::ResolveCollisions()
{
    for (CollisionPair& Pair : CollisionPairs)
    {
        PhysicsBody* BodyA = Pair.BodyA;
        PhysicsBody* BodyB = Pair.BodyB;
        
        // Skip if either body is static
        if (BodyA->IsStatic() && BodyB->IsStatic())
        {
            continue;
        }
        
        // Calculate relative masses
        float MassA = BodyA->GetMass();
        float MassB = BodyB->GetMass();
        float TotalMass = MassA + MassB;
        
        float InverseMassA = MassA > 0.0f ? 1.0f / MassA : 0.0f;
        float InverseMassB = MassB > 0.0f ? 1.0f / MassB : 0.0f;
        
        // Calculate impulse
        float Restitution = FMath::Min(BodyA->GetRestitution(), BodyB->GetRestitution());
        float Impulse = (1 + Restitution) * FVector2D::Dot(Pair.ContactNormal, BodyB->GetVelocity() - BodyA->GetVelocity()) / TotalMass;
        
        // Apply impulse
        if (!BodyA->IsStatic())
        {
            FVector2D VelocityA = BodyA->GetVelocity();
            VelocityA += Impulse * InverseMassA;
            BodyA->SetVelocity(VelocityA);
        }
        
        if (!BodyB->IsStatic())
        {
            FVector2D VelocityB = BodyB->GetVelocity();
            VelocityB -= Impulse * InverseMassB;
            BodyB->SetVelocity(VelocityB);
        }
        
        // Position correction
        const float Percent = 0.8f; // Position correction percentage
        const float Slop = 0.2f; // Position correction slop
        
        FVector2D CorrectionMagnitude = Pair.PenetrationDepth * Percent;
        FVector2D Correction = Pair.ContactNormal * CorrectionMagnitude;
        
        if (!BodyA->IsStatic())
        {
            FVector2D PositionA = BodyA->GetPosition();
            PositionA -= Correction * (InverseMassA * Slop);
            BodyA->SetPosition(PositionA);
        }
        
        if (!BodyB->IsStatic())
        {
            FVector2D PositionB = BodyB->GetPosition();
            PositionB += Correction * (InverseMassB * Slop);
            BodyB->SetPosition(PositionB);
        }
    }
}

void PhysicsEngine::IntegrateForces(float DeltaTime)
{
    for (PhysicsBody* Body : Bodies)
    {
        if (!Body->IsStatic())
        {
            // Semi-implicit Euler integration
            FVector2D Acceleration = Body->GetForce() * Body->GetInverseMass();
            
            FVector2D Velocity = Body->GetVelocity() + Acceleration * DeltaTime;
            Body->SetVelocity(Velocity);
            
            Body->SetForce(FVector2D::ZeroVector); // Reset force accumulator
        }
    }
}

void PhysicsEngine::ApplyGravity(float DeltaTime)
{
    for (PhysicsBody* Body : Bodies)
    {
        if (!Body->IsStatic())
        {
            FVector2D GravityForce = Gravity * Body->GetGravityScale() * Body->GetMass();
            Body->AddForce(GravityForce);
        }
    }
}

bool PhysicsEngine::CheckAABBOverlap(const PhysicsBody* BodyA, const PhysicsBody* BodyB)
{
    if (!BodyA || !BodyB) return false;
    
    // Get AABB bounds for both bodies
    FVector2D MinA, MaxA;
    FVector2D MinB, MaxB;
    
    GetBodyBounds(BodyA, MinA, MaxA);
    GetBodyBounds(BodyB, MinB, MaxB);
    
    // Check AABB overlap
    return (MinA.X <= MaxB.X && MaxA.X >= MinB.X &&
            MinA.Y <= MaxB.Y && MaxA.Y >= MinB.Y);
}

void PhysicsEngine::GetBodyBounds(const PhysicsBody* Body, FVector2D& Min, FVector2D& Max)
{
    if (!Body) return;
    
    Min = FVector2D(FLT_MAX, FLT_MAX);
    Max = FVector2D(-FLT_MAX, -FLT_MAX);
    
    for (const TSharedPtr<Collider>& Collider : Body->GetColliders())
    {
        FVector2D Center = Collider->GetCenter();
        FVector2D Extents = Collider->GetExtents();
        
        FVector2D ColliderMin = Center - Extents;
        FVector2D ColliderMax = Center + Extents;
        
        Min.X = FMath::Min(Min.X, ColliderMin.X);
        Min.Y = FMath::Min(Min.Y, ColliderMin.Y);
        Max.X = FMath::Max(Max.X, ColliderMax.X);
        Max.Y = FMath::Max(Max.Y, ColliderMax.Y);
    }
}

TArray<PhysicsBody*> PhysicsEngine::GetBodiesInArea(const FVector2D& Min, const FVector2D& Max)
{
    TArray<PhysicsBody*> BodiesInArea;
    
    for (PhysicsBody* Body : Bodies)
    {
        FVector2D BodyMin, BodyMax;
        GetBodyBounds(Body, BodyMin, BodyMax);
        
        if (BodyMin.X <= Max.X && BodyMax.X >= Min.X &&
            BodyMin.Y <= Max.Y && BodyMax.Y >= Min.Y)
        {
            BodiesInArea.Add(Body);
        }
    }
    
    return BodiesInArea;
}

bool PhysicsEngine::IsOverlapping(const Collider* ColliderA, const Collider* ColliderB) const
{
    if (!ColliderA || !ColliderB) return false;
    
    return ColliderA->Overlaps(ColliderB);
}

void PhysicsEngine::DebugRender()
{
    if (!bIsDebugRendering) return;
    
    // Render bodies
    for (const PhysicsBody* Body : Bodies)
    {
        FVector2D Position = Body->GetPosition();
        FVector2D Min, Max;
        GetBodyBounds(Body, Min, Max);
        
        // Draw body outline
        DrawDebugBox(Min, Max, FColor::Green);
        
        // Draw velocity vector
        FVector2D VelocityEnd = Position + Body->GetVelocity();
        DrawDebugLine(Position, VelocityEnd, FColor::Blue);
    }
    
    // Render colliders
    for (const TSharedPtr<Collider>& Collider : Colliders)
    {
        FVector2D Center = Collider->GetCenter();
        FVector2D Extents = Collider->GetExtents();
        
        DrawDebugBox(Center - Extents, Center + Extents, FColor::Red);
    }
    
    // Render spatial grid
    if (bIsDebugRendering)
    {
        const int32 GridSize = 100;
        const FColor GridColor = FColor(0, 0, 1, 0.1f);
        
        for (int32 X = 0; X < 10; X++)
        {
            for (int32 Y = 0; Y < 10; Y++)
            {
                FVector2D GridMin(X * GridSize, Y * GridSize);
                FVector2D GridMax((X + 1) * GridSize, (Y + 1) * GridSize);
                DrawDebugBox(GridMin, GridMax, GridColor);
            }
        }
    }
}

// Circle Collider Implementation
CircleCollider::CircleCollider(float InRadius)
    : Radius(InRadius)
{
}

bool CircleCollider::Overlaps(const Collider* Other) const
{
    if (!Other) return false;
    
    switch (Other->GetType())
    {
        case Circle:
        {
            const CircleCollider* OtherCircle = static_cast<const CircleCollider*>(Other);
            float Distance = FVector2D::Dist(GetCenter(), OtherCircle->GetCenter());
            return Distance < (Radius + OtherCircle->GetRadius());
        }
        
        case Rectangle:
        {
            const RectangleCollider* OtherRect = static_cast<const RectangleCollider*>(Other);
            return OverlapsRectangle(OtherRect);
        }
        
        default:
            return false;
    }
}

bool CircleCollider::ContainsPoint(const FVector2D& Point) const
{
    return FVector2D::Dist(GetCenter(), Point) <= Radius;
}

bool CircleCollider::IntersectsLine(const FVector2D& Start, const FVector2D& End) const
{
    // Line-circle intersection test
    FVector2D D = End - Start;
    float A = D.Dot(D);
    float B = 2.0f * D.Dot(Start);
    float C = Start.SizeSquared() - Radius * Radius;
    
    float Discriminant = B * B - 4.0f * A * C;
    
    if (Discriminant < 0.0f)
    {
        return false; // No intersection
    }
    
    float T1 = (-B - FMath::Sqrt(Discriminant)) / (2.0f * A);
    float T2 = (-B + FMath::Sqrt(Discriminant)) / (2.0f * A);
    
    if (T1 >= 0.0f && T1 <= 1.0f)
    {
        return ContainsPoint(Start + D * T1);
    }
    
    if (T2 >= 0.0f && T2 <= 1.0f)
    {
        return ContainsPoint(Start + D * T2);
    }
    
    return false;
}

void CircleCollider::ComputeCollisionData(const Collider* Other, FVector2D& OutNormal, float& OutPenetration) const
{
    if (!Other || Other->GetType() != Circle)
    {
        OutNormal = FVector2D::ZeroVector;
        OutPenetration = 0.0f;
        return;
    }
    
    const CircleCollider* OtherCircle = static_cast<const CircleCollider*>(Other);
    
    // Calculate collision normal
    FVector2D Direction = OtherCircle->GetCenter() - GetCenter();
    float Distance = Direction.Size();
    
    if (Distance > 0.0f)
    {
        OutNormal = Direction / Distance;
    }
    else
    {
        OutNormal = FVector2D::ZeroVector;
    }
    
    // Calculate penetration depth
    OutPenetration = (Radius + OtherCircle->GetRadius()) - Distance;
}

FVector2D CircleCollider::GetCenter() const
{
    return Position;
}

FVector2D CircleCollider::GetExtents() const
{
    return FVector2D(Radius, Radius);
}

void CircleCollider::SetRadius(float NewRadius)
{
    Radius = NewRadius;
}

// Rectangle Collider Implementation
RectangleCollider::RectangleCollider(const FVector2D& InSize)
    : Size(InSize)
{
}

bool RectangleCollider::Overlaps(const Collider* Other) const
{
    if (!Other) return false;
    
    switch (Other->GetType())
    {
        case Rectangle:
        {
            const RectangleCollider* OtherRect = static_cast<const RectangleCollider*>(Other);
            return OverlapsRectangle(OtherRect);
        }
        
        case Circle:
            {
            const CircleCollider* OtherCircle = static_cast<const CircleCollider*>(Other);
            return OtherCircle->Overlaps(this);
        }
        
        default:
            return false;
    }
}

bool RectangleCollider::OverlapsRectangle(const RectangleCollider* Other) const
{
    if (!Other) return false;
    
    FVector2A = GetCenter() - GetExtents();
    FVector2B = GetCenter() + GetExtents();
    FVector2C = Other->GetCenter() - Other->GetExtents();
    FVector2D = Other->GetCenter() + Other->GetExtents();
    
    return (A.X <= C.X && B.X >= C.X &&
            A.Y <= C.Y && B.Y >= C.Y);
}

bool RectangleCollider::ContainsPoint(const FVector2D& Point) const
{
    FVector2A = GetCenter() - GetExtents();
    FVector2B = GetCenter() + GetExtents();
    
    return Point.X >= A.X && Point.X <= B.X &&
           Point.Y >= A.Y && Point.Y <= B.Y;
}

bool RectangleCollider::IntersectsLine(const FVector2D& Start, const FVector2D& End) const
{
    // Line-rectangle intersection test
    FVector2A = GetCenter() - GetExtents();
    FVector2B = GetCenter() + GetExtents();
    
    // Check if line intersects rectangle
    return LineIntersectsRect(Start, End, A, B);
}

void RectangleCollider::ComputeCollisionData(const Collider* Other, FVector2D& OutNormal, float& OutPenetration) const
{
    if (!Other || Other->GetType() != Rectangle)
    {
        OutNormal = FVector2D::ZeroVector;
        OutPenetration = 0.0f;
        return;
    }
    
    const RectangleCollider* OtherRect = static_cast<const RectangleCollider*>(Other);
    
    // Calculate overlap
    FVector2A = GetCenter() - GetExtents();
    FVector2B = GetCenter() + GetExtents();
    FVector2C = OtherRect->GetCenter() - OtherRect->GetExtents();
    FVector2D = OtherRect->GetCenter() + OtherRect->GetExtents();
    
    // Calculate overlap
    float OverlapX = FMath::Min(B.X, C.X + OtherRect->GetExtents().X) - FMath::Max(A.X, C.X - OtherRect->GetExtents().X);
    float OverlapY = FMath::Min(B.Y, C.Y + OtherRect->GetExtents().Y) - FMath::Max(A.Y, C.Y - OtherRect->GetExtents().Y);
    
    // Calculate collision normal and penetration
    if (OverlapX < OverlapY)
    {
        OutNormal = FVector2D(1.0f, 0.0f);
        OutPenetration = OverlapX;
    }
    else
    {
        OutNormal = FVector2D(0.0f, 1.0f);
        OutPenetration = OverlapY;
    }
    
    // Flip normal if needed
    if (FVector2D::Dot((GetCenter() - OtherRect->GetCenter()), OutNormal) < 0.0f)
    {
        OutNormal = -OutNormal;
    }
}

FVector2D RectangleCollider::GetCenter() const
{
    return Position;
}

FVector2D RectangleCollider::GetExtents() const
{
    return Size * 0.5f;
}

void RectangleCollider::SetSize(const FVector2D& NewSize)
{
    Size = NewSize;
}

// Line-Rectangle intersection helper
bool LineIntersectsRect(const FVector2D& Start, const FVector2D& End, const FVector2D& RectMin, const FVector2D& RectMax)
{
    // Check if line segment intersects rectangle
    // This is a simplified implementation
    return Start.X <= RectMax.X && End.X >= RectMin.X &&
           Start.Y <= RectMax.Y && End.Y >= RectMin.Y &&
           Start.
## Game Engine Comparison

| Engine | Languages | Platforms | Strengths | License | Type |
|--------|---------|------------|---------|-------|------|
| **Unity** | C# | Cross-Platform | Medium | Free | All |
| **Unreal** | C++ | Cross-Platform | High | License Fee | AAA |
| **Godot** | GDScript/C# | Cross-Platform | Medium | Free | Indie |
| **CryEngine** | C++ | Cross-Platform | High | License Fee | AAA |
| **Amazon Lumberyard** | Lua | Cross-Platform | Medium | Free | Cloud |

## 3D Graphics Pipeline

### Rendering Pipeline Stages
```mermaid
graph TD
    A[Application] --> B[Vertex Processing]
    B --> C[Primitive Assembly]
    C --> D[Vertex Shader]
    D --> E[Fragment Shader]
    E --> F[Per-Fragment Operations]
    F --> G[Blending]
    G --> H[Frame Buffer]
    H --> I[Display]

Shader Types

TypePurposeLanguageComplexity
Vertex ShaderVertex TransformationGLSL/HLSLMedium
Fragment ShaderPixel ColorGLSL/HLSLHigh
Geometry ShaderPrimitive GenerationGLSL/HLSLVery High
Compute ShaderGeneral-PurposeGLSL/HLSLHigh

Physics Engine Concepts

Collision Detection Algorithms

AlgorithmTypeComplexityAccuracyApplication
AABBBroad PhaseO(1)LowFast Filtering
OBBNarrow PhaseO(n)MediumPrecise
SATNarrow PhaseO(log n)HighPrecise
GJKNarrow PhaseO(log n)Very HighComplex

Integration Methods

MethodStabilityEnergy EfficiencyApplication
EulerConditionalLowGeneral Purpose
VerletConditionalLowStable
RK4ConditionalLowPrecise

Animation Systems

Skeletal Animation

// Bone structure
struct Bone
{
    FString Name;
    int32 ParentIndex;
    FVector3D Position;
    FQuat4 Rotation;
    TArray<Bone> Children;
    
    // Transform matrix
    FMatrix44 Transform;
    
    // Animation data
    TArray<FTransform> Keyframes;
    int32 CurrentKeyframe;
    float AnimationSpeed;
    bool bLooping;
};

// Animation system
class AnimationSystem
{
public:
    void UpdateAnimation(float DeltaTime);
    void PlayAnimation(const FString& AnimationName);
    void StopAnimation();
    
    void SetAnimationSpeed(float Speed);
    void SetLooping(bool bLoop);
    
private:
    TArray<SkeletalAnimation*> Animations;
    SkeletalAnimation* CurrentAnimation;
    float CurrentTime;
};

Animation Blending

// Animation blending states
enum class EAnimationBlendState
{
    Idle,
    Moving,
    Jumping,
    Attacking,
    Dead
};

// Blend tree structure
struct FAnimationBlendState
{
    EAnimationState State;
    float BlendTime;
    float BlendDuration;
    UAnimationAsset* Animation;
};

Game Loop Implementation

Fixed Time Step Game Loop

void Game::Tick(float DeltaTime)
{
    // Accumulate time
    AccumulatedTime += DeltaTime;
    
    // Fixed timestep update
    while (AccumulatedTime >= FixedTimeStep)
    {
        // Update game logic
        UpdateGameLogic(FixedTimeStep);
        
        // Handle input
        HandleInput(FixedTimeStep);
        
        // Update physics
        UpdatePhysics(FixedTimeStep);
        
        // Accumulate time
        AccumulatedTime -= FixedTimeStep;
    }
    
    // Render
    Render();
}

Variable Time Step Game Loop

void Game::Tick(float DeltaTime)
{
    // Update game logic
    UpdateGameLogic(DeltaTime);
    
    // Handle input
    HandleInput(DeltaTime);
    
    // Update physics
    UpdatePhysics(DeltaTime);
    
    // Render
    Render();
}

Mobile Game Optimization

Performance Techniques

  • Level of Detail (LOD): Dynamic quality adjustment
  • Occlusion Culling: Hide invisible objects
  • Frustum Culling: Limit visible area
  • Object Pooling: Reuse objects
  • Texture Compression: Graphics compression

Memory Management

// Object pooling for game objects
template<typename T>
class ObjectPool
{
public:
    ObjectPool(int32 PoolSize = 100)
    {
        for (int32 i = 0; i < PoolSize; ++i)
        {
            AvailableObjects.Add(new T());
        }
    }
    
    T* GetObject()
    {
        if (AvailableObjects.Num() > 0)
        {
            T* Object = AvailableObjects.Pop();
            ActiveObjects.Add(Object);
            return Object;
        }
        return new T();
    }
    
    void ReturnObject(T* Object)
    {
        if (ActiveObjects.Contains(Object))
        {
            ActiveObjects.Remove(Object);
            AvailableObjects.Add(Object);
        }
    }
    
private:
    TArray<T*> AvailableObjects;
    TArray<T*> ActiveObjects;
};

Advantages and Disadvantages

Advantages of Game Engines

  • Rapid Development: Visual editors, drag-and-drop
  • Cross-Platform: Develop once for all platforms
  • Built-in Systems: Physics, audio, animation, networking
  • Asset Pipeline: Asset management and import
  • Community Support: Large developer communities

Disadvantages

  • Performance: Not always optimal for AAA games
  • Flexibility: Engine-specific limitations
  • License Costs: Commercial licensing models
  • File Size: Large build sizes
  • Debugging: Engine-specific debugging tools

Common Exam Questions

  1. What is the difference between Unity and Unreal Engine? Unity uses C# and is optimized for indie and mobile games, Unreal Engine uses C++ and is designed for AAA games with high-end graphics.

  2. Explain the Game Loop! The game loop is the central cycle of input handling, logic update, physics update, and rendering with fixed or variable time intervals.

  3. When do you use which collision detection? AABB for fast filtering, OBB for precise collisions, SAT for complex geometries, GJK for complex scenarios.

  4. What is the purpose of shaders? Shaders are small programs that run on the GPU and control the visual representation of 3D objects.

Most Important Sources

  1. https://unity.com/
  2. https://unrealengine.com/
  3. https://docs.unity3d.com/
  4. https://docs.unrealengine.com/
Back to Blog
Share: