Skip to content
IRC-Coding IRC-Coding
Game Entwicklung Grundlagen Unity Unreal Engine 3D Graphics Physics Animation Spieleprogrammierung

Game-Entwicklung Grundlagen: Unity, Unreal Engine, 3D-Graphics, Physics & Animation

Game-Entwicklung Grundlagen mit Unity, Unreal Engine, 3D-Graphics, Physics-Engines und Animation. Spieleprogrammierung, Game Loop, Rendering, Collision Detection mit praktischen Beispielen.

S

schutzgeist

2 min read

Game-Entwicklung Grundlagen: Unity, Unreal Engine, 3D-Graphics, Physics & Animation

Dieser Beitrag ist eine umfassende Einführung in die Game-Entwicklung Grundlagen – inklusive Unity, Unreal Engine, 3D-Graphics, Physics-Engines und Animation mit praktischen Beispielen.

In a Nutshell

Game-Entwicklung kombiniert Programmierung, 3D-Graphics, Physics und Animation. Unity und Unreal Engine sind die führenden Engines, C# und C++ die Hauptprogrammiersprachen, OpenGL/Vulkan die Grafik-APIs.

Kompakte Fachbeschreibung

Game-Entwicklung ist die Erstellung von interaktiven Unterhaltungssoftware durch Kombination von Programmierung, Grafik, Sound und Gameplay-Mechaniken.

Kernkomponenten:

Game Engines

  • Unity: C#-Engine für 2D/3D-Spiele, Cross-Platform
  • Unreal Engine: C++-Engine für AAA-Spiele, High-End-Grafik
  • Godot: Open-Source-Engine mit GDScript/C#
  • CryEngine: C++-Engine für Realistische Grafik

3D-Graphics

  • Rendering Pipeline: Vertex → Fragment → Display
  • Shaders: GLSL/HLSL für visuelle Effekte
  • Lighting: Beleuchtungsmodelle (Phong, PBR)
  • Texturing: 2D/3D-Materialien und 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-basierte Animation
  • Procedural Animation: Algorithmisch generiert
  • Morph Targets: Shape-Interpolation

Prüfungsrelevante Stichpunkte

  • Game-Entwicklung: Erstellung von interaktiven Spielen
  • Unity: C#-Engine für Cross-Platform-Spiele
  • Unreal Engine: C++-Engine für AAA-Spiele
  • 3D-Graphics: Rendering Pipeline, Shaders, Lighting
  • Physics: Kollisionserkennung, Physik-Simulation
  • Animation: Skeletal, Keyframe, Procedural Animation
  • Game Loop: Update-Render-Zyklus, Fixed Time Step
  • IHK-relevant: Moderne Spieleentwicklung und -technologien

Kernkomponenten

  1. Game Engine: Grundlage für Spielentwicklung
  2. Rendering Pipeline: Grafik-Verarbeitung und Darstellung
  3. Physics Engine: Physik-Simulation und Kollisionserkennung
  4. Animation System: Bewegung und Charakter-Animation
  5. Input System: Benutzerinteraktion und Steuerung
  6. Audio System: Soundeffekte und Musik
  7. UI System: Benutzeroberfläche und HUD
  8. Networking: Multiplayer und Online-Funktionen

Praxisbeispiele

1. Unity Game mit 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 mit 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.X <= End.X && Start.Y <= End.Y;
}

Game Engine Vergleich

EngineSprachenPlattformenStärkenLizenzTyp
UnityC#Cross-PlatformMittelKostenlosAll
UnrealC++Cross-PlatformHochLizenzgebührAAA
GodotGDScript/C#Cross-PlatformMittelKostenlosIndie
CryEngineC++Cross-PlatformHochLizenzgebührAAA
Amazon LumberyardLuaCross-PlatformMittelKostenlosCloud

3D-Graphics Pipeline

Rendering Pipeline Stages

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

TypZweckSpracheKomplexität
Vertex ShaderVertex-TransformationGLSL/HLSLMittel
Fragment ShaderPixel-FarbeGLSL/HLSLHoch
Geometry ShaderPrimitive-ErzeugungGLSL/HLSLSehr Hoch
Compute ShaderGeneral-PurposeGLSL/HLSLHoch

Physics Engine Konzepte

Collision Detection Algorithmen

AlgorithmTypKomplexitätGenauigkeitAnwendung
AABBBroad PhaseO(1)NiedrigSchnelle Filterung
OBBNarrow PhaseO(n)MittelGenau
SATNarrow PhaseO(log n)HochPräzise
GJKNarrow PhaseO(log n)Sehr HochKomplexe

Integration Methods

| Methode | Stabilität | Energie-Effizienz | Anwendung | |--------|-----------|-----------------|-------------|---------| | Euler | Bedingt | Gering | Einfach | General Purpose | | Verlet | Bedingt | Gering | Stabil | Präzise | | RK4 | Bedingt | Gering | Stabil | Präzise |

Animation Systeme

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 Implementierung

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 Optimierung

Performance Techniques

  • Level of Detail (LOD): Dynamische Qualitätsanpassung
  • Occlusion Culling: Unsichtbare Objekte ausblenden
  • Frustum Culling: Sichtbaren Bereich begrenzen
  • Object Pooling: Objekte wiederverwenden
  • Texture Compression: Grafik-Kompression

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;
};

Vorteile und Nachteile

Vorteile von Game Engines

  • Rapid Development: Visuelle Editoren, Drag-and-Drop
  • Cross-Platform: Einmal für alle Plattformen entwickeln
  • Built-in Systems: Physik, Audio, Animation, Networking
  • Asset Pipeline: Asset-Management und -Import
  • Community Support: Große Entwickler-Communities

Nachteile

  • Performance: Nicht immer optimal für AAA-Spiele
  • Flexibilität: Engine-spezifische Einschränkungen
  • Lizenzkosten: Kommerzielle Lizenzmodelle
  • Dateigröße: Große Build-Größen
  • Debugging: Engine-spezifische Debugging-Werkzeuge

Häufige Prüfungsfragen

  1. Was ist der Unterschied zwischen Unity und Unreal Engine? Unity verwendet C# und ist für Indie- und Mobile-Spiele optimiert, Unreal Engine verwendet C++ und für AAA-Spiele mit High-End-Grafik.

  2. Erklären Sie die Game Loop! Die Game Loop ist der zentrale Zyklus aus Input-Handling, Logic-Update, Physics-Update und Rendering mit festem oder variablem Zeitintervall.

  3. Wann verwendet man welche Kollisionserkennung? AABB für schnelle Filterung, OBB für präzise Kollisionen, SAT für komplexe Geometrien, GJK für komplexe Szenarien.

  4. Was ist der Zweck von Shadern? Shaders sind kleine Programme, die auf der GPU laufen und die visuelle Darstellung von 3D-Objekten steuern.

Wichtigste Quellen

  1. https://unity.com/
  2. https://unrealengine.com/
  3. https://docs.unity3d.com/
  4. https://docs.unrealengine.com/
Zurück zum Blog
Share: