diff --git a/CHANGELOG.md b/CHANGELOG.md index ab689a1e..a4535374 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,13 @@ # Changelog +## v0.7.1 - 2026-01-10 +### 🐞 Fixes +- [Patch] Added a profiler to the engine (6be0955…) +- [Patch] added multi-platform support build system (d6642d1…) +- [Patch]fixed the space in the Build system path (31497f0…) +- [Patch]Added apply transform to parents in deserializer (907cde3…) +- [Patch]Fixed async loading not setting skeleton component (ea52f24…) +### πŸ“š Docs +- [Docs]Added docs explaining how to start a project (2496315…) ## v0.7.0 - 2026-01-06 ### 🐞 Fixes - [Patch] re-enabled renderer tests in pre-commit (fd67537…) diff --git a/docs/03-Game Development/02-Tutorials/000_HelloEditor.md b/docs/03-Game Development/02-Tutorials/000_HelloEditor.md index 47bc9a98..02c65870 100644 --- a/docs/03-Game Development/02-Tutorials/000_HelloEditor.md +++ b/docs/03-Game Development/02-Tutorials/000_HelloEditor.md @@ -44,6 +44,26 @@ You will then be prompted to open the project in Xcode. I recommend doing so. After opening the project in Xcode, take a moment to explore the file structure. This will help you navigate the project later. +### Project Structure + +``` +MyGame/ # Your working directory +└── MyGame/ # Generated project + β”œβ”€β”€ MyGame.xcodeproj # Open this in Xcode + β”œβ”€β”€ project.yml # XcodeGen configuration + └── Sources/ + └── MyGame/ + β”œβ”€β”€ GameData/ # ← Put your assets here + β”‚ β”œβ”€β”€ Models/ # 3D models + β”‚ β”œβ”€β”€ Scenes/ # Scene files + β”‚ β”œβ”€β”€ Scripts/ # USC scripts + β”‚ β”œβ”€β”€ Textures/ # Images + β”‚ └── ... + β”œβ”€β”€ GameScene.swift # Your game logic + β”œβ”€β”€ GameViewController.swift # View controller + └── AppDelegate.swift # App entry point +``` + The most important file to look for is: ```GameScene.swift``` diff --git a/website/versioned_docs/version-0.7.1/01-Intro.md b/website/versioned_docs/version-0.7.1/01-Intro.md new file mode 100644 index 00000000..81b5d670 --- /dev/null +++ b/website/versioned_docs/version-0.7.1/01-Intro.md @@ -0,0 +1,118 @@ +--- +slug: /intro +--- + +# Untold Engine Documentation + +Welcome to the **Untold Engine documentation**. + +These docs are the primary reference for working with the Untold Engine ecosystem β€” whether you are building a game, extending the engine, or contributing to the editor. + +--- + +## What Is Untold Engine? + +![untoldengine](images/Editor/EditorMainShot.png) + +The Untold Engine strives to be a stable, performant, and developer-friendly 3D engine that empowers creativity, removes friction, and makes game development feel effortless for Apple developers + +The Untold Engine is an open-source 3D game engine under active development, designed for macOS, iOS, xrOS platforms. Written in Swift and powered by Metal, its goal is to simplify game creation with a clean, intuitive API. + +While the engine already supports many core systems like rendering, physics, and animation, there’s still much to build and improve. + +--- + +## The Untold Engine Ecosystem + +Untold Engine is delivered through three closely related products: + +### Untold Engine Studio +A downloadable application that includes: +- The Untold Engine runtime +- The Untold Editor +- Built-in tools for scripting, assets, and scene editing + +This is the recommended starting point for most users. + +--- + +### Untold Engine +The core engine runtime. + +This is intended for: +- Engine developers +- Contributors +- Advanced users who want to modify or extend engine systems + +Installation is performed via the command line. + +--- + +### Untold Editor +The editor application built on top of the engine runtime. + +This is intended for: +- Contributors working on editor features +- Developers extending tools and workflows + +The editor uses the same runtime as games, ensuring consistent behavior. + +--- + +## Choose Your Path + +These docs are organized around **how you intend to use the engine**. + +### Game Development +For developers building games using Untold Engine. + +You will learn: +- How to create scenes visually +- How to write game logic (Swift or USC scripts) +- How to work with assets and entities +- How to build and run your game + +Untold Engine supports two approaches for writing gameplay code: +- **Swift in Xcode** (recommended) - Full engine API access +- **USC Scripts** (experimental) - Component-based scripting + +Start here if your goal is to build a game. + +--- + +### Engine Development +For developers who want to understand or extend the engine itself. + +You will learn: +- The engine architecture +- ECS and system execution +- Rendering and simulation internals +- How to contribute new engine features + +Start here if you want to work on the engine runtime. + +--- + +### Editor Development +For contributors working on the Untold Editor. + +You will learn: +- Editor architecture +- Views, tools, and interaction models +- How the editor coordinates with the engine +- How to extend or add editor functionality + +Start here if you want to improve the editor. + +--- + +## Getting Started + +If you are unsure where to begin: + +- New users: **Game Development β†’ Overview** +- Scripting users: **USC β†’ Introduction** +- Contributors: **Engine Development β†’ Architecture** + +Each section is designed to stand on its own. + diff --git a/website/versioned_docs/version-0.7.1/02-Getting Started/02-Installation.md b/website/versioned_docs/version-0.7.1/02-Getting Started/02-Installation.md new file mode 100644 index 00000000..89e99a7e --- /dev/null +++ b/website/versioned_docs/version-0.7.1/02-Getting Started/02-Installation.md @@ -0,0 +1,221 @@ +--- +id: intro +title: Installation +sidebar_position: 1 +--- + +# Installation + +This page explains how to install **Untold Engine Studio**, the recommended way to get started with Untold Engine. + +Untold Engine Studio is a downloadable app that includes: +- The **Untold Engine** runtime +- The **Untold Editor** for building and editing games + +![editorbottomshot](../images/Editor/EditorBottomShot.png) + +If your goal is to **make games**, this is the only installation you need. + +--- + +## Recommended Installation (Untold Engine Studio) + +### 1. Download + +Download the latest version of **Untold Engine Studio** from the official website: + +[Download Releases](https://github.com/untoldengine/UntoldEditor/releases) + +The download is provided as a `.dmg` file for macOS. + +--- + +### 2. Install + +1. Open the downloaded `.dmg` file +2. Drag **Untold Engine Studio** into your `Applications` folder +3. Launch the app from `Applications` + +No additional setup is required. + +--- + +### 3. First Launch + +On first launch, Untold Engine Studio will: +- Initialize the engine runtime +- Set up the editor environment +- Prompt you to create or open a project + +From here, you can immediately: +- Create scenes visually +- Import 3D models and assets +- Write game logic (Swift in Xcode or USC scripts) +- Build and test your game + +--- + +## System Requirements + +- macOS (Apple Silicon recommended) +- Metal-capable GPU +- Keyboard and mouse + +--- + +## What You Get + +By installing Untold Engine Studio, you get: + +- A complete **game development environment** +- Visual editor for scenes, assets, and scripts +- Full **Untold Engine Swift API** for game logic in Xcode +- **USC scripting system** (experimental component-based scripting) +- Build and run support for macOS, iOS, and visionOS + +You do **not** need to install the engine or editor separately. + +### Two Ways to Write Game Logic + +Untold Engine Studio supports two approaches for writing gameplay code: + +**1. Swift in Xcode (Recommended)** +- Write game logic in `GameScene.swift` using the full Untold Engine API +- Complete control over game systems and performance +- Best for complex games and experienced developers +- Works seamlessly with Xcode debugging and profiling + +**2. USC Scripts (Experimental)** +- Component-based scripting attached to entities +- Write gameplay behaviors in the integrated script editor +- Good for prototyping and simple game mechanics +- API is experimental and subject to change + +You can **use both approaches** in the same project. + +--- + +## Alternative Installation: CLI Workflow + +For **advanced users** or those who prefer a **command-line workflow** without the visual editor, you can install the CLI tools. + +### When to Use CLI + +- You prefer working entirely in Xcode without a visual editor +- You want to script project creation and automation +- You're building tools or integrations on top of UntoldEngine + +### CLI Installation + +**1. Clone the repository:** + +```bash +git clone https://github.com/untoldengine/UntoldEngine.git +cd UntoldEngine +``` + +**2. Install the CLI globally:** + +```bash +./scripts/install-create.sh +``` + +**3. Verify installation:** + +```bash +untoldengine-create --version +untoldengine-create --help +``` + +### CLI Quick Start + +After installing the CLI, create a project from anywhere: + +```bash +# 1. Create project directory +cd ~/anywhere +mkdir MyGame && cd MyGame + +# 2. Create the project +untoldengine-create create MyGame + +# 3. Open in Xcode +open MyGame/MyGame.xcodeproj +``` + +For complete CLI documentation, see `Tools/UntoldEngineCLI/README.md` in the repository. + +--- + +### What You Get + +The CLI creates a complete, ready-to-run project: + +- **Xcode project** - Configured and ready to build +- **GameScene.swift** - Your game logic goes here +- **GameViewController.swift** - Renderer and view setup +- **GameData/** directory - All game assets location +- **Platform-specific** files (AppDelegate, Info.plist, etc.) + +### Project Structure + +``` +MyGame/ # Your working directory +└── MyGame/ # Generated project + β”œβ”€β”€ MyGame.xcodeproj # Open this in Xcode + β”œβ”€β”€ project.yml # XcodeGen configuration + └── Sources/ + └── MyGame/ + β”œβ”€β”€ GameData/ # ← Put your assets here + β”‚ β”œβ”€β”€ Models/ # 3D models + β”‚ β”œβ”€β”€ Scenes/ # Scene files + β”‚ β”œβ”€β”€ Scripts/ # USC scripts + β”‚ β”œβ”€β”€ Textures/ # Images + β”‚ └── ... + β”œβ”€β”€ GameScene.swift # Your game logic + β”œβ”€β”€ GameViewController.swift # View controller + └── AppDelegate.swift # App entry point +``` + +### Platform Support + +The CLI supports multiple platforms: + +```bash +# macOS (default) +untoldengine-create create MyGame --platform macos + +# iOS +untoldengine-create create MyGame --platform ios + +# iOS with ARKit +untoldengine-create create MyGame --platform iosar + +# visionOS (Apple Vision Pro) +untoldengine-create create MyGame --platform visionos +``` + +### Development Workflow + +1. **Write code** in GameScene.swift (game logic) +2. **Add assets** to the GameData/ directory +3. **Build & run** in Xcode (Cmd+R) +4. **Iterate** - make changes and rebuild + +For complete CLI documentation, see `Tools/UntoldEngineCLI/README.md` in the repository. + +--- + +## Preloaded Assets + +To kickstart development, download prebuilt demo assets: + +- **Models**: Soccer stadium, player, ball, and more +- **Animations**: Running, idle, and other character motions +- **Textures**: Sample materials + +[Download Demo Assets v1.0](https://haroldserrano.gumroad.com/l/iqjlac) + +Extract and copy into your project's `GameData/` directory. + +--- diff --git a/website/versioned_docs/version-0.7.1/02-Getting Started/03-ChoosingYourPath.md b/website/versioned_docs/version-0.7.1/02-Getting Started/03-ChoosingYourPath.md new file mode 100644 index 00000000..4d003ace --- /dev/null +++ b/website/versioned_docs/version-0.7.1/02-Getting Started/03-ChoosingYourPath.md @@ -0,0 +1,79 @@ +# Choosing Your Path + +Untold Engine supports different types of developers. + +This page helps you choose the path that best matches what you want to do. + +--- + +## I Want to Make a Game + +Choose this path if your goal is to: +- Build gameplay +- Create scenes +- Write scripts +- Ship a game + +### What You’ll Use + +- **Untold Engine Studio** +- **USC scripting API** + +### Where to Start + +> **Game Development β†’ Overview** + +You do not need to understand engine internals to make a game. + +--- + +## I Want to Improve the Engine + +Choose this path if you want to: +- Work on core engine systems +- Improve rendering, physics, or ECS +- Extend platform support + +### What You’ll Use + +- **Untold Engine (core)** +- Command-line tools +- Source builds + +### Where to Start + +> **Engine Development β†’ Overview** + +This path assumes familiarity with engine concepts and systems programming. + +--- + +## I Want to Improve the Editor + +Choose this path if you want to: +- Improve the editor UI +- Add new tools or views +- Improve workflows and usability + +### What You’ll Use + +- **Untold Editor** +- Editor-specific APIs +- Engine integration points + +### Where to Start + +> **Editor Development β†’ Overview** + +Editor development focuses on tooling rather than gameplay. + +--- + +## Not Sure Yet? + +If you’re not sure where to begin, start here: + +> **Game Development β†’ Overview** + +You can always explore the other paths later. + diff --git a/website/versioned_docs/version-0.7.1/02-Getting Started/_category.json b/website/versioned_docs/version-0.7.1/02-Getting Started/_category.json new file mode 100644 index 00000000..ac4e7d57 --- /dev/null +++ b/website/versioned_docs/version-0.7.1/02-Getting Started/_category.json @@ -0,0 +1,2 @@ +{ "label": "01-Getting Starter", "position": 1, "collapsed": false } + diff --git a/website/versioned_docs/version-0.7.1/03-Game Development/01-Overview.md b/website/versioned_docs/version-0.7.1/03-Game Development/01-Overview.md new file mode 100644 index 00000000..a41e30ce --- /dev/null +++ b/website/versioned_docs/version-0.7.1/03-Game Development/01-Overview.md @@ -0,0 +1,116 @@ +# Overview + +This section covers **game development** with the Untold Engine. + +You'll learn how to create games using **Untold Engine Studio**, with two approaches for writing game logic: + +1. **Swift in Xcode** - Full engine API access (recommended) +2. **USC Scripts** - Component-based scripting (experimental) + +![editorsideshotalt](../images/Editor/EditorSideShotWide-alt.png) + +--- + +## Two Approaches to Game Logic + +Untold Engine gives you flexibility in how you write gameplay code: + +### Option 1: Swift in Xcode (Recommended) + +Write game logic in `GameScene.swift` using the full Untold Engine Swift API: +- Complete control over game systems and performance +- Access to all engine features and APIs +- Seamless integration with Xcode debugging and profiling +- Best for complex games and experienced developers + +### Option 2: USC Scripts (Experimental) + +Write component-based scripts that attach to entities: +- Simpler, component-oriented approach +- Good for prototyping and simple game mechanics +- Edit scripts in the integrated editor or Xcode +- API is experimental and subject to change + +**You can use both approaches in the same project.** + +--- + +## The Development Workflow + +A typical development workflow with Untold Engine Studio: + +1. **Create a project** using the "New" button in Untold Engine Studio +2. **Compose scenes visually** using the editor +3. **Write game logic** (Swift in `GameScene.swift` or USC scripts) +4. **Add assets** to the GameData/ directory +5. **Build & run** in Xcode (Cmd+R) +6. **Iterate** quickly with visual feedback + +--- + +## Entry Point 1: GameScene.swift (Swift) + +When you create a project, you get a clean `GameScene.swift` file for writing game logic in Swift: + +```swift +class GameScene { + + init() { + // Configure asset paths + setupAssetPaths() + + // Load game content + loadBundledScripts() + loadAndPlayFirstScene() + + // Start game systems + startGameSystems() + } + + func update(deltaTime: Float) { + // Your game logic goes here + } + + func handleInput() { + // Handle user input here + } +} +``` + +**This is where your game comes to life.** Write Swift code, access the full engine API, and build your game. + +--- + +## Entry Point 2: USC Scripts (Experimental) + +Alternatively, write game logic as USC scripts that attach to entities: + +Create USC scripts from the **Script** menu in Untold Engine Studio, then attach them to entities in the Inspector. + +--- + + +## Project Structure + +Your generated project has everything you need: + +``` +MyGame/ +└── MyGame/ + β”œβ”€β”€ MyGame.xcodeproj # Open in Xcode + └── Sources/ + └── MyGame/ + β”œβ”€β”€ GameData/ # Assets location + β”‚ β”œβ”€β”€ Models/ + β”‚ β”œβ”€β”€ Scenes/ + β”‚ β”œβ”€β”€ Scripts/ + β”‚ └── Textures/ + β”œβ”€β”€ GameScene.swift # Your game logic ⭐ + β”œβ”€β”€ GameViewController.swift # Renderer setup + └── AppDelegate.swift # App entry +``` + +**Focus on GameScene.swift** - that's where your game lives. + +--- + diff --git a/website/versioned_docs/version-0.7.1/03-Game Development/02-Tutorials/000_HelloEditor.md b/website/versioned_docs/version-0.7.1/03-Game Development/02-Tutorials/000_HelloEditor.md new file mode 100644 index 00000000..02c65870 --- /dev/null +++ b/website/versioned_docs/version-0.7.1/03-Game Development/02-Tutorials/000_HelloEditor.md @@ -0,0 +1,170 @@ +# Getting Started with Untold Engine Studio + +This guide will walk you through the basics of getting up and running with **Untold Engine Studio**, from installation to loading your first model. + +--- + +## Downloading Untold Engine Studio + +To start developing with the Untold Engine, download the latest version of **Untold Engine Studio** from the official GitHub releases page: + +πŸ‘‰ https://github.com/untoldengine/UntoldEditor/releases + +Once downloaded: + +1. Drag **Untold Engine Studio** into your **Applications** folder +2. Double-click the app to launch it + +--- + +## Creating a New Project + +When the editor launches, you will be presented with the main startup screen. + +![editor_empty_view](../../images/Editor/Editor_scene_empty.png) + +At this point, create a new project: + +1. Click **New** +2. A new window will appear asking for: + - **Project name** + - **Target platform** + - **Project location** +3. Fill in the details and click **Create** + +Once completed, the engine will generate a fully configured **Xcode game project** for you. + +You will then be prompted to open the project in Xcode. I recommend doing so. + +![editor_scene_xcode](../../images/Editor/Editor_scene_xcode.png) + +--- + +## Exploring the Generated Project + +After opening the project in Xcode, take a moment to explore the file structure. This will help you navigate the project later. + +### Project Structure + +``` +MyGame/ # Your working directory +└── MyGame/ # Generated project + β”œβ”€β”€ MyGame.xcodeproj # Open this in Xcode + β”œβ”€β”€ project.yml # XcodeGen configuration + └── Sources/ + └── MyGame/ + β”œβ”€β”€ GameData/ # ← Put your assets here + β”‚ β”œβ”€β”€ Models/ # 3D models + β”‚ β”œβ”€β”€ Scenes/ # Scene files + β”‚ β”œβ”€β”€ Scripts/ # USC scripts + β”‚ β”œβ”€β”€ Textures/ # Images + β”‚ └── ... + β”œβ”€β”€ GameScene.swift # Your game logic + β”œβ”€β”€ GameViewController.swift # View controller + └── AppDelegate.swift # App entry point +``` + +The most important file to look for is: + +```GameScene.swift``` + +This is where you will do most of your coding. +It contains the core lifecycle functions, including: + +- `init()` – scene setup +- `update()` – per-frame logic + +You’ll be spending most of your time here when writing game logic. + +--- + +## Back to the Editor + +Return to **Untold Engine Studio**. + +If you look at the editor toolbar, you’ll notice the name of your newly created project displayed on the right side of the window. + +At this point, you can already start adding content to your scene. + +--- + +## Adding Entities to the Scene + +You can quickly add a primitive by clicking the **β€œ+”** button in the **Scenegraph View** and selecting a cube or other built-in shapes. + +However, it’s more fun to load real models. + +--- + +## Downloading Sample Models + +I’ve provided a small set of [sample models](https://haroldserrano.gumroad.com/l/iqjlac) you can use to get started: + +- A soccer player +- A soccer ball +- A stadium +- Idle and running animations + +All assets are provided as **`.usdz`** files. + +> **Note** +> Untold Engine currently accepts **USDZ** files only. + +Download the sample assets from the provided link. + +--- + +## Importing Models into Your Project + +Once the models are downloaded, it’s time to import them into your project. + +1. Open the **Asset Browser** +2. Select the **Model** category +3. Click **Import** +4. Navigate to the folder containing your downloaded `.usdz` file +5. Select a model and confirm + +After importing, the engine will display a feedback message confirming the import. +You will also see the `.usdz` file listed under the **Model** category. + +--- + +## Loading a Model into the Scene + +Now for the fun part. + +- **Double-click** the imported `.usdz` file in the Asset Browser + +The model will immediately appear in the editor viewport. + +![Editor_scene_model_viewport](../../images/Editor/Editor_scene_model_viewport.png) + +Behind the scenes, two things just happened: + +1. An **entity** was created +2. The `.usdz` asset was linked to that entity + +--- + +## Importing and Linking Animations + +The same workflow applies to animations. + +1. Select the **Animation** category in the Asset Browser +2. Click **Import** +3. Locate and import an animation `.usdz` file +4. Double-click the animation asset + +The animation will automatically be linked to the currently selected entity. + +If you open the **Inspector** tab, you’ll see the animation listed as part of the entity’s components. + +--- + +## What’s Next? + +Now that you have a basic understanding of the editor, asset workflow, and project structure, you’re ready to start coding with the Untold Engine. + +πŸ‘‰ Continue with the **Hello World** tutorial to write your first gameplay logic. + + diff --git a/website/versioned_docs/version-0.7.1/03-Game Development/02-Tutorials/00_HelloWorld.md b/website/versioned_docs/version-0.7.1/03-Game Development/02-Tutorials/00_HelloWorld.md new file mode 100644 index 00000000..6c5007b7 --- /dev/null +++ b/website/versioned_docs/version-0.7.1/03-Game Development/02-Tutorials/00_HelloWorld.md @@ -0,0 +1,152 @@ +# Hello World + +Your first UntoldEngine program - logging a message every frame. + +--- + +## Overview + +This tutorial shows you how to add custom code to your game's update loop and log output to the console. + +--- + +## Prerequisites + +This tutorial assumes you have: +- Created a project using the 'Untold Engine Studio` or `untoldengine-create` +- Opened the project in Xcode +- Located `GameScene.swift` in your project + +--- + +## Step 1: Open GameScene.swift + +In Xcode, navigate to: + +``` +Sources/YourProjectName/GameScene.swift +``` + +--- + +## Step 2: Add Your First Game Logic + +Find the `update(deltaTime:)` method in `GameScene.swift`: + +```swift path=null start=null +func update(deltaTime: Float) { + // Skip logic if not in game mode + if gameMode == false { return } + + // Add your custom update logic here +} +``` + +Replace the comment with: + +```swift path=null start=null +func update(deltaTime: Float) { + // Skip logic if not in game mode + if gameMode == false { return } + + // Your first game code! πŸŽ‰ + Logger.log(message: "Hello World! Delta: \(deltaTime)") +} +``` + +--- + +## Step 3: Build and Run + +Press **Cmd+R** in Xcode. + +Open the **Debug Console** (Cmd+Shift+Y) to see: + +``` +Hello World! Delta: 0.016 +Hello World! Delta: 0.017 +Hello World! Delta: 0.016 +... +``` + +The message appears every frame! πŸš€ + +--- + +## What Just Happened? + +### The Update Loop + +`update(deltaTime:)` is called every frame by the engine: + +- **60 FPS** = called 60 times per second +- **deltaTime** = time since last frame (in seconds) + +All game logic goes here: movement, input handling, collision detection, etc. + +### Logging + +```swift path=null start=null +Logger.log(message: "Hello World!") +``` + +Use `Logger.log()` to print debug messages. It's better than `print()` because: +- Engine-aware logging +- Can be filtered/disabled in production +- Consistent formatting + +### Other Logging Methods + +```swift path=null start=null +Logger.logWarning(message: "Something might be wrong") +Logger.logError(message: "Something went wrong!") +``` + +--- + +## Limiting Output (Recommended) + +Logging every frame creates spam. Let's log once per second instead: + +```swift path=null start=null +class GameScene { + var elapsedTime: Float = 0.0 // Add this property + + func update(deltaTime: Float) { + if gameMode == false { return } + + // Accumulate time + elapsedTime += deltaTime + + // Log once per second + if elapsedTime >= 1.0 { + Logger.log(message: "Hello World! One second passed.") + elapsedTime = 0.0 // Reset + } + } +} +``` + +Now you'll see: + +``` +Hello World! One second passed. +Hello World! One second passed. +... +``` + +Much cleaner! + +--- + +## Summary + +You've learned: + +βœ… The `update(deltaTime:)` method runs every frame +βœ… `deltaTime` is the time between frames +βœ… `Logger.log()` prints messages to the console +βœ… How to accumulate time for periodic actions + +This is the foundation of game development: **write code that runs every frame**. + diff --git a/website/versioned_docs/version-0.7.1/03-Game Development/02-Tutorials/01_Transform/01_MoveAnEntityy.md b/website/versioned_docs/version-0.7.1/03-Game Development/02-Tutorials/01_Transform/01_MoveAnEntityy.md new file mode 100644 index 00000000..94cf91c3 --- /dev/null +++ b/website/versioned_docs/version-0.7.1/03-Game Development/02-Tutorials/01_Transform/01_MoveAnEntityy.md @@ -0,0 +1,214 @@ +# Move an Entity + +Learn how to move entities using the Transform System. + +--- + +## Overview + +This tutorial shows you how to: +- Find an entity from a loaded scene +- Move an entity to an absolute position +- Move an entity relative to its current position + +--- + +## Prerequisites + +This tutorial assumes you have: +- A project with `GameScene.swift` open +- **A scene loaded** with at least one entity (created in Untold Engine Studio or loaded via `loadScene()`) +- The entity has a name set in the editor (e.g., "Player") + +For complete API documentation: + +➑️ **[Transform System API](../../../04-Engine%20Development/03-Engine%20Systems/UsingTransformSystem.md)** + +--- + +## Step 1: Find the Entity from Your Scene + +In `GameScene.swift`, add a property to store the entity reference: + +```swift path=null start=null +class GameScene { + var player: EntityID! + + init() { + // ... setup code (setupAssetPaths, loadScene, etc.) ... + startGameSystems() + + // Find the entity by name (set in the editor) + player = findEntity(name: "Player") + + if player == nil { + Logger.logWarning(message: "Player entity not found in scene") + } + } +} +``` + +**Important**: "Player" must match the entity name you set in Untold Engine Studio. + +--- + +## Step 2: Move to an Absolute Position + +Use `translateTo()` to set an entity to a specific world position: + +```swift path=null start=null +class GameScene { + var player: EntityID! + + init() { + // ... setup code ... + + player = findEntity(name: "Player") + + // Move player to position (5, 0, -10) + translateTo(entityId: player, position: SIMD3(5.0, 0.0, -10.0)) + } +} +``` + +**Result**: The entity immediately moves to position (5, 0, -10) in world space. + +--- + +## Step 3: Move Relative to Current Position + +Use `translateBy()` to move an entity by an offset: + +```swift path=null start=null +class GameScene { + var player: EntityID! + + init() { + // ... setup code ... + + player = findEntity(name: "Player") + + // Move player 3 units to the right (X-axis) + translateBy(entityId: player, delta: SIMD3(3.0, 0.0, 0.0)) + } +} +``` + +**Result**: The entity moves 3 units along the X-axis from its current position. + +--- + +## Step 4: Continuous Movement in Update Loop + +For smooth movement every frame, use `translateBy()` in `update(deltaTime:)`: + +```swift path=null start=null +class GameScene { + var player: EntityID! + let moveSpeed: Float = 5.0 // Units per second + + init() { + // ... setup code ... + player = findEntity(name: "Player") + } + + func update(deltaTime: Float) { + if gameMode == false { return } + + // Move forward continuously + let movement = SIMD3(0, 0, -moveSpeed * deltaTime) + translateBy(entityId: player, delta: movement) + } +} +``` + +**Result**: The player moves forward smoothly at 5 units per second. + +--- + +## Understanding Delta Time + +**Why multiply by `deltaTime`?** + +`deltaTime` is the time (in seconds) since the last frame: +- At 60 FPS: `deltaTime β‰ˆ 0.016` seconds +- At 30 FPS: `deltaTime β‰ˆ 0.033` seconds + +By multiplying speed by `deltaTime`, movement becomes **frame-rate independent**: + +```swift path=null start=null +// Without deltaTime (BAD) +translateBy(entityId: player, delta: SIMD3(0, 0, -0.1)) +// Result: Speed varies with frame rate ❌ + +// With deltaTime (GOOD) +let movement = SIMD3(0, 0, -moveSpeed * deltaTime) +translateBy(entityId: player, delta: movement) +// Result: Consistent speed regardless of frame rate βœ… +``` + +--- + +## Movement Examples + +### Move Forward + +```swift path=null start=null +let movement = SIMD3(0, 0, -moveSpeed * deltaTime) +translateBy(entityId: player, delta: movement) +``` + +### Move Right + +```swift path=null start=null +let movement = SIMD3(moveSpeed * deltaTime, 0, 0) +translateBy(entityId: player, delta: movement) +``` + +### Move Up + +```swift path=null start=null +let movement = SIMD3(0, moveSpeed * deltaTime, 0) +translateBy(entityId: player, delta: movement) +``` + +### Move Along Entity's Forward Direction + +```swift path=null start=null +let forward = getForwardAxisVector(entityId: player) +let movement = forward * moveSpeed * deltaTime +translateBy(entityId: player, delta: movement) +``` + +--- + +## Checking Entity Position + +To read an entity's current position: + +```swift path=null start=null +// World position (absolute) +let worldPos = getPosition(entityId: player) +Logger.log(message: "Player world position: \(worldPos)") + +// Local position (relative to parent, if parented) +let localPos = getLocalPosition(entityId: player) +Logger.log(message: "Player local position: \(localPos)") +``` + +--- + +## Summary + +You've learned: + +βœ… `findEntity(name:)` - Find entities from loaded scenes +βœ… `translateTo()` - Set absolute world position +βœ… `translateBy()` - Move relative to current position +βœ… `deltaTime` - Make movement frame-rate independent +βœ… `getPosition()` - Read current position + +--- + + + diff --git a/website/versioned_docs/version-0.7.1/03-Game Development/02-Tutorials/01_Transform/02_RotateAnEntity.md b/website/versioned_docs/version-0.7.1/03-Game Development/02-Tutorials/01_Transform/02_RotateAnEntity.md new file mode 100644 index 00000000..1fc40aaa --- /dev/null +++ b/website/versioned_docs/version-0.7.1/03-Game Development/02-Tutorials/01_Transform/02_RotateAnEntity.md @@ -0,0 +1,246 @@ +# Rotate an Entity + +Learn how to rotate entities using the Transform System. + +--- + +## Overview + +This tutorial shows you how to: +- Rotate an entity to an absolute angle +- Rotate an entity incrementally +- Create smooth rotation using `deltaTime` + +--- + +## Prerequisites + +This tutorial assumes you have: +- A project with `GameScene.swift` open +- **A scene loaded** with at least one entity +- The entity has a name set in the editor (e.g., "Propeller") + +For complete API documentation: + +➑️ **[Transform System API](../../../04-Engine%20Development/03-Engine%20Systems/UsingTransformSystem.md)** + +--- + +## Step 1: Find the Entity from Your Scene + +In `GameScene.swift`, add a property to store the entity reference: + +```swift path=null start=null +class GameScene { + var propeller: EntityID! + + init() { + // ... setup code (setupAssetPaths, loadScene, etc.) ... + startGameSystems() + + // Find the entity by name (set in the editor) + propeller = findEntity(name: "Propeller") + + if propeller == nil { + Logger.logWarning(message: "Propeller entity not found in scene") + } + } +} +``` + +--- + +## Step 2: Rotate to an Absolute Angle + +Use `rotateTo()` to set an entity to a specific rotation: + +```swift path=null start=null +class GameScene { + var propeller: EntityID! + + init() { + // ... setup code ... + + propeller = findEntity(name: "Propeller") + + // Rotate 45 degrees around the Y-axis (up) + rotateTo(entityId: propeller, angle: 45.0, axis: SIMD3(0, 1, 0)) + } +} +``` + +**Result**: The entity immediately rotates to 45 degrees around the Y-axis. + +--- + +## Step 3: Rotate Incrementally + +Use `rotateBy()` to add rotation to the current orientation: + +```swift path=null start=null +class GameScene { + var propeller: EntityID! + + init() { + // ... setup code ... + + propeller = findEntity(name: "Propeller") + + // Rotate 15 degrees from current rotation + rotateBy(entityId: propeller, angle: 15.0, axis: SIMD3(0, 1, 0)) + } +} +``` + +**Result**: The entity rotates an additional 15 degrees around the Y-axis. + +--- + +## Step 4: Continuous Rotation in Update Loop + +For smooth spinning, use `rotateBy()` in `update(deltaTime:)`: + +```swift path=null start=null +class GameScene { + var propeller: EntityID! + let rotationSpeed: Float = 90.0 // Degrees per second + + init() { + // ... setup code ... + propeller = findEntity(name: "Propeller") + } + + func update(deltaTime: Float) { + if gameMode == false { return } + + // Rotate continuously around Y-axis + let angleThisFrame = rotationSpeed * deltaTime + rotateBy(entityId: propeller, angle: angleThisFrame, axis: SIMD3(0, 1, 0)) + } +} +``` + +**Result**: The propeller spins smoothly at 90 degrees per second. + +--- + +## Understanding Rotation Axes + +### Common Rotation Axes + +```swift path=null start=null +// Rotate around Y-axis (up) - typical yaw rotation +rotateBy(entityId: entity, angle: 45.0, axis: SIMD3(0, 1, 0)) + +// Rotate around X-axis (right) - pitch rotation +rotateBy(entityId: entity, angle: 45.0, axis: SIMD3(1, 0, 0)) + +// Rotate around Z-axis (forward) - roll rotation +rotateBy(entityId: entity, angle: 45.0, axis: SIMD3(0, 0, 1)) +``` + +### Using Entity's Local Axes + +You can also rotate around an entity's own forward/right/up vectors: + +```swift path=null start=null +// Rotate around entity's own up direction +let up = getUpAxisVector(entityId: entity) +rotateBy(entityId: entity, angle: 45.0, axis: up) + +// Rotate around entity's own right direction +let right = getRightAxisVector(entityId: entity) +rotateBy(entityId: entity, angle: 45.0, axis: right) +``` + +--- + +## Rotation Examples + +### Spin Clockwise (Y-axis) + +```swift path=null start=null +let angle = rotationSpeed * deltaTime +rotateBy(entityId: entity, angle: angle, axis: SIMD3(0, 1, 0)) +``` + +### Spin Counter-Clockwise (Y-axis) + +```swift path=null start=null +let angle = -rotationSpeed * deltaTime // Negative for opposite direction +rotateBy(entityId: entity, angle: angle, axis: SIMD3(0, 1, 0)) +``` + +### Tumble (X-axis) + +```swift path=null start=null +let angle = rotationSpeed * deltaTime +rotateBy(entityId: entity, angle: angle, axis: SIMD3(1, 0, 0)) +``` + +### Face a Direction + +To face a target, you typically calculate the direction and convert to rotation. This is more advanced, but here's a simple Y-axis example: + +```swift path=null start=null +let targetPos = SIMD3(10, 0, 5) +let currentPos = getPosition(entityId: entity) +let direction = normalize(targetPos - currentPos) + +// Calculate angle to target (simplified for Y-axis only) +let angle = atan2(direction.x, direction.z) * (180.0 / .pi) +rotateTo(entityId: entity, angle: angle, axis: SIMD3(0, 1, 0)) +``` + +--- + +## Checking Current Rotation + +To read an entity's current orientation: + +```swift path=null start=null +// World orientation matrix +let worldOrientation = getOrientation(entityId: entity) +Logger.log(message: "World orientation: \(worldOrientation)") + +// Local orientation matrix (relative to parent) +let localOrientation = getLocalOrientation(entityId: entity) +Logger.log(message: "Local orientation: \(localOrientation)") +``` + +--- + +## Combining Translation and Rotation + +You can move and rotate in the same frame: + +```swift path=null start=null +func update(deltaTime: Float) { + if gameMode == false { return } + + // Move forward + let forward = getForwardAxisVector(entityId: player) + let movement = forward * moveSpeed * deltaTime + translateBy(entityId: player, delta: movement) + + // Rotate based on input + let turnAngle = turnSpeed * deltaTime + rotateBy(entityId: player, angle: turnAngle, axis: SIMD3(0, 1, 0)) +} +``` + +--- + +## Summary + +You've learned: + +βœ… `rotateTo()` - Set absolute rotation angle +βœ… `rotateBy()` - Rotate incrementally from current orientation +βœ… `deltaTime` - Make rotation frame-rate independent +βœ… Rotation axes - Control rotation direction +βœ… `getOrientation()` - Read current rotation + +--- + + diff --git a/website/versioned_docs/version-0.7.1/03-Game Development/02-Tutorials/02_Input/01_KeyboardMovement.md b/website/versioned_docs/version-0.7.1/03-Game Development/02-Tutorials/02_Input/01_KeyboardMovement.md new file mode 100644 index 00000000..988a4970 --- /dev/null +++ b/website/versioned_docs/version-0.7.1/03-Game Development/02-Tutorials/02_Input/01_KeyboardMovement.md @@ -0,0 +1,261 @@ +# Keyboard Movement + +Learn how to move entities using keyboard input. + +--- + +## Overview + +This tutorial shows you how to: +- Detect keyboard input using the Input System +- Move an entity based on WASD keys +- Combine input with Transform System + +--- + +## Prerequisites + +This tutorial assumes you have: +- A project with `GameScene.swift` open +- **A scene loaded** with at least one entity +- The entity has a name set in the editor (e.g., "Player") + +For complete API documentation: + +➑️ **[Input System API](../../../04-Engine%20Development/03-Engine%20Systems/UsingInputSystem.md)** + +--- + +## Step 1: Enable Input System + +Before detecting input, you need to register keyboard events. Add this to your `startGameSystems()` helper or in `init()`: + +```swift path=null start=null +class GameScene { + var player: EntityID! + + init() { + // ... setup code ... + startGameSystems() + + // Register input keyboard events + InputSystem.shared.registerKeyboardEvents() + + // Find the entity by name (set in the editor) + player = findEntity(name: "Player") + } +} +``` + +**Important**: Call `InputSystem.shared.registerKeyboardEvents()` once during initialization to enable keyboard input detection. + +--- + +## Step 2: Detect Keyboard Input + +The Input System provides a `keyState` object to check if keys are pressed: + +```swift path=null start=null +func update(deltaTime: Float) { + if gameMode == false { return } + + // Check if W key is pressed + if inputSystem.keyState.wPressed == true { + Logger.log(message: "W key pressed!") + } +} +``` + +**Available Keys**: +- `inputSystem.keyState.wPressed` - W key +- `inputSystem.keyState.aPressed` - A key +- `inputSystem.keyState.sPressed` - S key +- `inputSystem.keyState.dPressed` - D key + +--- + +## Step 3: Move Entity with WASD + +Combine input detection with movement: + +```swift path=null start=null +class GameScene { + var player: EntityID! + let moveSpeed: Float = 5.0 + + init() { + // ... setup code ... + player = findEntity(name: "Player") + } + + func update(deltaTime: Float) { + if gameMode == false { return } + + var movement = SIMD3(0, 0, 0) + + // Forward (W) + if inputSystem.keyState.wPressed == true { + movement.z += moveSpeed * deltaTime + } + + // Backward (S) + if inputSystem.keyState.sPressed == true { + movement.z -= moveSpeed * deltaTime + } + + // Left (A) + if inputSystem.keyState.aPressed == true { + movement.x -= moveSpeed * deltaTime + } + + // Right (D) + if inputSystem.keyState.dPressed == true { + movement.x += moveSpeed * deltaTime + } + + // Apply movement + if movement != SIMD3(0, 0, 0) { + translateBy(entityId: player, delta: movement) + } + } +} +``` + +**Result**: The player moves based on WASD input at 5 units per second. + +--- + +## Understanding the Code + +### Input Detection + +```swift path=null start=null +if inputSystem.keyState.wPressed == true { + // Key is currently pressed +} +``` + +The Input System automatically tracks key states. You don't need to register listeners or handle events. + +### Accumulating Movement + +```swift path=null start=null +var movement = SIMD3(0, 0, 0) + +if inputSystem.keyState.wPressed == true { + movement.z += moveSpeed * deltaTime +} + +if inputSystem.keyState.dPressed == true { + movement.x += moveSpeed * deltaTime +} +``` + +By accumulating input into a `movement` vector, diagonal movement (W+D) works correctly. + +### Delta Time + +Multiplying by `deltaTime` ensures consistent speed regardless of frame rate: + +```swift path=null start=null +movement.z += moveSpeed * deltaTime // βœ… Frame-rate independent +movement.z += 0.1 // ❌ Varies with frame rate +``` + +--- + +## Advanced: Normalized Diagonal Movement + +Diagonal movement (W+D) is currently faster than single-direction movement. To fix this, normalize the movement vector: + +```swift path=null start=null +func update(deltaTime: Float) { + if gameMode == false { return } + + var movement = SIMD3(0, 0, 0) + + // Accumulate input + if inputSystem.keyState.wPressed == true { + movement.z += 1.0 + } + if inputSystem.keyState.sPressed == true { + movement.z -= 1.0 + } + if inputSystem.keyState.aPressed == true { + movement.x -= 1.0 + } + if inputSystem.keyState.dPressed == true { + movement.x += 1.0 + } + + // Normalize and apply speed + if movement != SIMD3(0, 0, 0) { + movement = normalize(movement) * moveSpeed * deltaTime + translateBy(entityId: player, delta: movement) + } +} +``` + +**Result**: Diagonal movement is now the same speed as cardinal movement. + +--- + +## Example: Tank Controls (Forward + Rotation) + +For tank-style controls where forward moves along the entity's facing direction: + +```swift path=null start=null +class GameScene { + var player: EntityID! + let moveSpeed: Float = 5.0 + let turnSpeed: Float = 90.0 // Degrees per second + + func update(deltaTime: Float) { + if gameMode == false { return } + + // Forward/backward movement + var forwardMovement: Float = 0.0 + if inputSystem.keyState.wPressed == true { + forwardMovement = moveSpeed * deltaTime + } + if inputSystem.keyState.sPressed == true { + forwardMovement = -moveSpeed * deltaTime + } + + // Apply forward movement along entity's forward direction + if forwardMovement != 0.0 { + let forward = getForwardAxisVector(entityId: player) + translateBy(entityId: player, delta: forward * forwardMovement) + } + + // Left/right rotation + var turnAngle: Float = 0.0 + if inputSystem.keyState.aPressed == true { + turnAngle = -turnSpeed * deltaTime + } + if inputSystem.keyState.dPressed == true { + turnAngle = turnSpeed * deltaTime + } + + // Apply rotation + if turnAngle != 0.0 { + rotateBy(entityId: player, angle: turnAngle, axis: SIMD3(0, 1, 0)) + } + } +} +``` + +--- + +## Summary + +You've learned: + +βœ… `inputSystem.keyState` - Check keyboard input +βœ… Detect W, A, S, D keys +βœ… Combine input with `translateBy()` +βœ… Normalize diagonal movement +βœ… Tank-style controls with rotation + +--- + diff --git a/website/versioned_docs/version-0.7.1/03-Game Development/02-Tutorials/03_Animation/01_PlayAnimation.md b/website/versioned_docs/version-0.7.1/03-Game Development/02-Tutorials/03_Animation/01_PlayAnimation.md new file mode 100644 index 00000000..8c903a35 --- /dev/null +++ b/website/versioned_docs/version-0.7.1/03-Game Development/02-Tutorials/03_Animation/01_PlayAnimation.md @@ -0,0 +1,252 @@ +# Play Animation + +Learn how to load and play animations on entities. + +--- + +## Overview + +This tutorial shows you how to: +- Load animation data from a `.usdc` file +- Play an animation on an entity +- Pause animations + +--- + +## Prerequisites + +This tutorial assumes you have: +- A project with `GameScene.swift` open +- **A scene loaded** with at least one entity that has an animation skeleton +- An animation file (e.g., `running.usdc`) in `GameData/Models/` or `GameData/Animations/` +- The entity has a name set in the editor (e.g., "Player") +- The entity has animations linked in the editor + +For complete API documentation: + +➑️ **[Animation System API](../../../04-Engine%20Development/03-Engine%20Systems/UsingAnimationSystem.md)** + +--- + +## Step 1: Find the Entity + +In `GameScene.swift`, add a property to store the entity reference: + +```swift path=null start=null +class GameScene { + var player: EntityID! + + init() { + // ... setup code ... + startGameSystems() + + // Find the entity by name (set in the editor) + player = findEntity(name: "Player") + } +} +``` + +--- + +## Step 2: Load the Animation + +>>> Skip this section if you linked an animation to the entity through the editor. + +Use `setEntityAnimations()` to load animation data: + +```swift path=null start=null +class GameScene { + var player: EntityID! + + init() { + // ... setup code ... + player = findEntity(name: "Player") + + // Load the running animation + setEntityAnimations( + entityId: player, + filename: "running", + withExtension: "usdc", + name: "running" + ) + } +} +``` + +**Parameters**: +- `filename`: The animation file name (without extension) +- `withExtension`: File extension (usually `"usdc"`) +- `name`: A label to reference this animation later + +--- + +## Step 3: Play the Animation + +Use `changeAnimation()` to start playing the animation: + +```swift path=null start=null +class GameScene { + var player: EntityID! + + init() { + // ... setup code ... + player = findEntity(name: "Player") + + // Load animation -- Ignore if you linked an animation through the editor + setEntityAnimations( + entityId: player, + filename: "running", + withExtension: "usdc", + name: "running" + ) + + // Play the animation - we assume that the animation linked is called running + changeAnimation(entityId: player, name: "running") + } +} +``` + +**Result**: The entity plays the "running" animation in a loop. + +--- + +## Step 4: Pause the Animation (Optional) + +To pause or resume an animation: + +```swift path=null start=null +// Pause the animation +pauseAnimationComponent(entityId: player, isPaused: true) + +// Resume the animation +pauseAnimationComponent(entityId: player, isPaused: false) +``` + +--- + +## Loading Multiple Animations + +You can load multiple animations for the same entity: + +```swift path=null start=null +class GameScene { + var player: EntityID! + + init() { + // ... setup code ... + player = findEntity(name: "Player") + + // Load multiple animations -- Ignore if you linked all three animations through the editor + setEntityAnimations( + entityId: player, + filename: "idle", + withExtension: "usdc", + name: "idle" + ) + + setEntityAnimations( + entityId: player, + filename: "running", + withExtension: "usdc", + name: "running" + ) + + setEntityAnimations( + entityId: player, + filename: "jumping", + withExtension: "usdc", + name: "jumping" + ) + + // Start with idle animation + changeAnimation(entityId: player, name: "idle") + } +} +``` + +--- + +## Switching Animations at Runtime + +Switch between animations based on game state: + +```swift path=null start=null +class GameScene { + var player: EntityID! + var isRunning: Bool = false + + init() { + // ... setup code ... + startGameSystems() + + // Register input keyboard events + InputSystem.shared.registerKeyboardEvents() + + } + + func update(deltaTime: Float) { + if gameMode == false { return } + + // Check if player is moving + let wasRunning = isRunning + isRunning = inputSystem.keyState.wPressed || + inputSystem.keyState.aPressed || + inputSystem.keyState.sPressed || + inputSystem.keyState.dPressed + + // Switch animation when state changes + if isRunning && !wasRunning { + changeAnimation(entityId: player, name: "running") + } else if !isRunning && wasRunning { + changeAnimation(entityId: player, name: "idle") + } + } +} +``` + +--- + +## File Organization + +Animation files should be placed in your project's `GameData` directory: + + +``` +Sources/YourProject/GameData/ +β”œβ”€β”€ Models/ +β”‚ └── player.usdz +β”œβ”€β”€ Animations/ +β”‚ β”œβ”€β”€ idle.usdc +β”‚ β”œβ”€β”€ running.usdc +β”‚ └── jumping.usdc +``` + +--- + +## Troubleshooting + +### Animation doesn't play + +1. **Check the entity has a skeleton**: Not all models support animation. The model must have a skeletal rig. +2. **Verify file path**: Make sure the animation file exists in `GameData/Models/` or `GameData/Animations/`. +3. **Check animation name**: The `name` parameter must match when loading and playing. + +### Animation plays too fast/slow + +Animation playback speed is controlled by the animation file itself. To adjust speed, you'll need to modify the animation in your 3D software (e.g., Blender, Maya) or use animation blending (advanced topic). + +--- + +## Summary + +You've learned: + +βœ… `setEntityAnimations()` - Load animation data +βœ… `changeAnimation()` - Play a specific animation +βœ… `pauseAnimationComponent()` - Pause/resume animations +βœ… Load multiple animations per entity +βœ… Switch animations based on game state + +--- + + diff --git a/website/versioned_docs/version-0.7.1/03-Game Development/02-Tutorials/03_Animation/02_AnimationStateSwitch.md b/website/versioned_docs/version-0.7.1/03-Game Development/02-Tutorials/03_Animation/02_AnimationStateSwitch.md new file mode 100644 index 00000000..3bbd8abc --- /dev/null +++ b/website/versioned_docs/version-0.7.1/03-Game Development/02-Tutorials/03_Animation/02_AnimationStateSwitch.md @@ -0,0 +1,319 @@ +# Animation State Switching + +Learn how to switch between different animations based on player input and game state. + +--- + +## Overview + +This tutorial shows you how to: +- Create a state-based animation system +- Switch between idle, running, and jumping animations +- Trigger animations based on input + +--- + +## Prerequisites + +This tutorial assumes you have: +- Completed the [Play Animation tutorial](./01_PlayAnimation.md) +- A project with multiple animations loaded (idle, running, jumping) +- An entity with a skeleton that supports animation + +For complete API documentation: + +➑️ **[Animation System API](../../../04-Engine%20Development/03-Engine%20Systems/UsingAnimationSystem.md)** + +--- + +## Step 1: Set Up Animation States + +Define an enum to represent your animation states: + +```swift path=null start=null +enum PlayerState { + case idle + case running + case jumping +} + +class GameScene { + var player: EntityID! + var playerState: PlayerState = .idle + + init() { + // ... setup code ... + startGameSystems() + + // Register input + InputSystem.shared.registerKeyboardEvents() + + player = findEntity(name: "Player") + + // Load all animations -- ignore if you linked all three animations through the editor. + loadPlayerAnimations() + + // Start with idle + changeAnimation(entityId: player, name: "idle") + } + + func loadPlayerAnimations() { + setEntityAnimations( + entityId: player, + filename: "idle", + withExtension: "usdc", + name: "idle" + ) + + setEntityAnimations( + entityId: player, + filename: "running", + withExtension: "usdc", + name: "running" + ) + + setEntityAnimations( + entityId: player, + filename: "jumping", + withExtension: "usdc", + name: "jumping" + ) + } +} +``` + +--- + +## Step 2: Implement State Switching Logic + +Create a function to handle state transitions: + +```swift path=null start=null +class GameScene { + var player: EntityID! + var playerState: PlayerState = .idle + var isGrounded: Bool = true // Track if player is on ground + + func update(deltaTime: Float) { + if gameMode == false { return } + + updatePlayerState() + } + + func updatePlayerState() { + let oldState = playerState + + // Determine new state based on input and game conditions + if !isGrounded { + playerState = .jumping + } else if isMovementKeyPressed() { + playerState = .running + } else { + playerState = .idle + } + + // Only change animation if state actually changed + if playerState != oldState { + switchToAnimation(for: playerState) + } + } + + func isMovementKeyPressed() -> Bool { + return inputSystem.keyState.wPressed || + inputSystem.keyState.aPressed || + inputSystem.keyState.sPressed || + inputSystem.keyState.dPressed + } + + func switchToAnimation(for state: PlayerState) { + switch state { + case .idle: + changeAnimation(entityId: player, name: "idle") + Logger.log(message: "Switched to idle animation") + + case .running: + changeAnimation(entityId: player, name: "running") + Logger.log(message: "Switched to running animation") + + case .jumping: + changeAnimation(entityId: player, name: "jumping") + Logger.log(message: "Switched to jumping animation") + } + } +} +``` + +--- + +## Step 3: Add Jump Trigger + +Add space bar input to trigger jumping: + +```swift path=null start=null +class GameScene { + var player: EntityID! + var playerState: PlayerState = .idle + var isGrounded: Bool = true + var jumpTimer: Float = 0.0 + let jumpDuration: Float = 0.5 // Jump animation duration in seconds + + func update(deltaTime: Float) { + if gameMode == false { return } + + handleJumpInput() + updateJumpTimer(deltaTime: deltaTime) + updatePlayerState() + } + + func handleJumpInput() { + // Trigger jump on space press (only if grounded) + if inputSystem.keyState.spacePressed && isGrounded { + isGrounded = false + jumpTimer = jumpDuration + } + } + + func updateJumpTimer(deltaTime: Float) { + // Count down jump timer + if !isGrounded { + jumpTimer -= deltaTime + + // Land when timer expires + if jumpTimer <= 0.0 { + isGrounded = true + jumpTimer = 0.0 + } + } + } + + func updatePlayerState() { + let oldState = playerState + + // Priority: jumping > running > idle + if !isGrounded { + playerState = .jumping + } else if isMovementKeyPressed() { + playerState = .running + } else { + playerState = .idle + } + + if playerState != oldState { + switchToAnimation(for: playerState) + } + } +} +``` + +--- + +## Step 4: Combine Animation with Movement + +Integrate animation state switching with actual movement: + +```swift path=null start=null +class GameScene { + var player: EntityID! + var playerState: PlayerState = .idle + var isGrounded: Bool = true + var jumpTimer: Float = 0.0 + let moveSpeed: Float = 5.0 + let jumpDuration: Float = 0.5 + + func update(deltaTime: Float) { + if gameMode == false { return } + + handleJumpInput() + updateJumpTimer(deltaTime: deltaTime) + updatePlayerState() + updatePlayerMovement(deltaTime: deltaTime) + } + + func updatePlayerMovement(deltaTime: Float) { + var movement = SIMD3(0, 0, 0) + + // Only move if grounded + if isGrounded { + if inputSystem.keyState.wPressed { + movement.z += moveSpeed * deltaTime + } + if inputSystem.keyState.sPressed { + movement.z -= moveSpeed * deltaTime + } + if inputSystem.keyState.aPressed { + movement.x -= moveSpeed * deltaTime + } + if inputSystem.keyState.dPressed { + movement.x += moveSpeed * deltaTime + } + + if movement != SIMD3(0, 0, 0) { + translateBy(entityId: player, delta: movement) + } + } + } +} +``` + +--- + +## Advanced: State Machine Pattern + +For more complex state management, consider using a proper state machine: + +```swift path=null start=null +class AnimationStateMachine { + var currentState: PlayerState = .idle + var entityId: EntityID + + init(entityId: EntityID) { + self.entityId = entityId + } + + func canTransition(to newState: PlayerState) -> Bool { + switch (currentState, newState) { + case (.jumping, .idle), (.jumping, .running): + // Can only exit jumping state when landing + return false + default: + return true + } + } + + func transition(to newState: PlayerState) { + guard canTransition(to: newState) else { return } + + if currentState != newState { + currentState = newState + playAnimation(for: newState) + } + } + + func playAnimation(for state: PlayerState) { + let animationName: String + switch state { + case .idle: animationName = "idle" + case .running: animationName = "running" + case .jumping: animationName = "jumping" + } + + changeAnimation(entityId: entityId, name: animationName) + } +} +``` + +--- + +## Summary + +You've learned: + +βœ… Create animation states using enums +βœ… Switch animations based on game state +βœ… Trigger animations from input +βœ… Prevent animation flickering with state checks +βœ… Combine animations with movement logic + +--- + + diff --git a/website/versioned_docs/version-0.7.1/03-Game Development/02-Tutorials/04_Physics/01_ApplyForce.md b/website/versioned_docs/version-0.7.1/03-Game Development/02-Tutorials/04_Physics/01_ApplyForce.md new file mode 100644 index 00000000..ef685064 --- /dev/null +++ b/website/versioned_docs/version-0.7.1/03-Game Development/02-Tutorials/04_Physics/01_ApplyForce.md @@ -0,0 +1,331 @@ +# Apply Force + +Learn how to use the Physics System to apply forces and create realistic movement. + +--- + +## Overview + +This tutorial shows you how to: +- Enable physics on an entity +- Configure mass and gravity +- Apply forces for dynamic movement +- Use the Steering System for advanced behaviors + +--- + +## Prerequisites + +This tutorial assumes you have: +- A project with `GameScene.swift` open +- **A scene loaded** with at least one entity +- The entity has a name set in the editor (e.g., "Ball") +- The entity has a kinetic component applied through the editor + +For complete API documentation: + +➑️ **[Physics System API](../../../04-Engine%20Development/03-Engine%20Systems/UsingPhysicsSystem.md)** +➑️ **[Steering System API](../../../04-Engine%20Development/03-Engine%20Systems/UsingSteeringSystem.md)** + +--- + +## Step 1: Find the Entity + +In `GameScene.swift`, add a property to store the entity reference: + +```swift path=null start=null +class GameScene { + var ball: EntityID! + + init() { + // ... setup code ... + startGameSystems() + + ball = findEntity(name: "Ball") + } +} +``` + +--- + +## Step 2: Enable Physics (Kinetics) + +Before applying forces, enable physics on the entity: + +```swift path=null start=null +class GameScene { + var ball: EntityID! + + init() { + // ... setup code ... + ball = findEntity(name: "Ball") + + // Enable physics components + setEntityKinetics(entityId: ball) // Ignore this if you linked kinetic component through the editor + } +} +``` + +**What this does**: `setEntityKinetics()` adds `PhysicsComponents` and `KineticComponent` to the entity, enabling it to respond to forces. + +--- + +## Step 3: Configure Mass and Gravity + +Set the entity's mass and gravity scale: + +```swift path=null start=null +class GameScene { + var ball: EntityID! + + init() { + // ... setup code ... + ball = findEntity(name: "Ball") + + // Enable physics + setEntityKinetics(entityId: ball) // Ignore this if you linked kinetic component through the editor + + // Configure physics properties + setMass(entityId: ball, mass: 0.5) // Lighter = easier to move + setGravityScale(entityId: ball, gravityScale: 1.0) // Normal gravity + } +} +``` + +**Parameters**: +- `mass`: How heavy the entity is. Lower = easier to push. Default is `1.0`. +- `gravityScale`: How much gravity affects it. `0.0` = no gravity, `1.0` = normal gravity. + +--- + +## Step 4: Apply a Force + +Use `applyForce()` to push the entity: + +```swift path=null start=null +class GameScene { + var ball: EntityID! + + init() { + // ... setup code ... + ball = findEntity(name: "Ball") + + setEntityKinetics(entityId: ball) // Ignore this if you linked kinetic component through the editor + setMass(entityId: ball, mass: 0.5) + setGravityScale(entityId: ball, gravityScale: 1.0) + + InputSystem.shared.registerKeyboardEvents() + } + + func update(deltaTime: Float) { + if gameMode == false { return } + + // Apply forward force when W is pressed + if inputSystem.keyState.wPressed { + applyForce(entityId: ball, force: SIMD3(0.0, 0.0, 5.0)) + } + } +} +``` + +**Result**: When you press W, the ball accelerates forward. + +**Important**: Forces are applied every frame while the key is pressed. The physics system automatically integrates forces into velocity and position. + +--- + +## Understanding Forces vs. Direct Movement + +### Direct Movement (Transform System) + +```swift path=null start=null +// Immediate, precise movement +translateBy(entityId: entity, delta: SIMD3(0, 0, speed * deltaTime)) +``` + +βœ… Precise control +βœ… No physics overhead +❌ No inertia or momentum +❌ Doesn't interact with physics + +### Force-Based Movement (Physics System) + +```swift path=null start=null +// Gradual acceleration with momentum +applyForce(entityId: entity, force: SIMD3(0, 0, 5.0)) +``` + +βœ… Realistic inertia +βœ… Physics interactions +βœ… Momentum and deceleration +❌ Less precise +❌ Requires tuning + +--- + +## Step 5: Use the Steering System + +For easier physics-based movement, use the Steering System: + +### Steer to a Target Position + +```swift path=null start=null +class GameScene { + var player: EntityID! + let maxSpeed: Float = 5.0 + + init() { + // ... setup code ... + player = findEntity(name: "Player") + + setEntityKinetics(entityId: player) // Ignore this if you linked kinetic component through the editor + setMass(entityId: player, mass: 1.0) + setGravityScale(entityId: player, gravityScale: 0.0) // No gravity for top-down + } + + func update(deltaTime: Float) { + if gameMode == false { return } + + let targetPosition = SIMD3(10.0, 0.0, 5.0) + steerSeek(entityId: player, targetPosition: targetPosition, maxSpeed: maxSpeed, deltaTime: deltaTime) + } +} +``` + +**Result**: The entity smoothly accelerates toward the target position. + +--- + +## Steering System Examples + +### Steer with WASD Keys + +The easiest way to add physics-based movement: + +```swift path=null start=null +class GameScene { + var player: EntityID! + let maxSpeed: Float = 5.0 + + init() { + // ... setup code ... + InputSystem.shared.registerKeyboardEvents() + + player = findEntity(name: "Player") + setEntityKinetics(entityId: player) // Ignore this if you linked kinetic component through the editor + setMass(entityId: player, mass: 1.0) + setGravityScale(entityId: player, gravityScale: 0.0) + } + + func update(deltaTime: Float) { + if gameMode == false { return } + + // Automatic WASD steering + steerWithWASD(entityId: player, maxSpeed: maxSpeed, deltaTime: deltaTime) + } +} +``` + +**Result**: WASD keys apply forces in the corresponding directions with smooth acceleration/deceleration. + +### Flee from a Threat + +```swift path=null start=null +let threatPosition = SIMD3(0.0, 0.0, 0.0) +steerFlee(entityId: player, threatPosition: threatPosition, maxSpeed: maxSpeed, deltaTime: deltaTime) +``` + +### Follow a Path + +```swift path=null start=null +let waypoints = [ + SIMD3(0, 0, 0), + SIMD3(5, 0, 0), + SIMD3(5, 0, 5), + SIMD3(0, 0, 5) +] +steerFollowPath(entityId: player, path: waypoints, maxSpeed: maxSpeed, deltaTime: deltaTime) +``` + +### Pursue a Moving Target + +```swift path=null start=null +let enemy = findEntity(name: "Enemy") +steerPursuit(entityId: player, targetEntity: enemy!, maxSpeed: maxSpeed, deltaTime: deltaTime) +``` + +### Avoid Obstacles + +```swift path=null start=null +let obstacles = [ + findEntity(name: "Rock1")!, + findEntity(name: "Rock2")!, + findEntity(name: "Tree1")! +] +steerAvoidObstacles(entityId: player, obstacles: obstacles, avoidanceRadius: 2.0, maxSpeed: maxSpeed, deltaTime: deltaTime) +``` + +### Arrive at Target (Slowing Down) + +```swift path=null start=null +let targetPosition = SIMD3(10.0, 0.0, 5.0) +steerArrive(entityId: player, targetPosition: targetPosition, maxSpeed: maxSpeed, deltaTime: deltaTime) +``` + +**Difference from `steerSeek()`**: `steerArrive()` slows down as it approaches the target, preventing overshoot. + +--- + +## Combining Steering Behaviors + +You can use multiple steering behaviors together: + +```swift path=null start=null +func update(deltaTime: Float) { + if gameMode == false { return } + + // Steer toward target while avoiding obstacles + let targetPosition = SIMD3(10.0, 0.0, 5.0) + + steerSeek(entityId: player, targetPosition: targetPosition, maxSpeed: maxSpeed, deltaTime: deltaTime) + + let obstacles = [findEntity(name: "Rock1")!, findEntity(name: "Rock2")!] + steerAvoidObstacles(entityId: player, obstacles: obstacles, avoidanceRadius: 2.0, maxSpeed: maxSpeed, deltaTime: deltaTime) +} +``` + +--- + +## When to Use What? + +### Use Transform System (`translateBy`, `translateTo`) +- Precise, scripted movement +- UI elements or camera +- Platformer-style movement +- When you don't need physics interactions + +### Use Physics System (`applyForce`) +- Projectiles (bullets, grenades) +- Vehicles with custom physics +- When you need low-level control + +### Use Steering System (`steerSeek`, `steerWithWASD`, etc.) +- Character movement in top-down or 3D games +- AI pathfinding and behaviors +- When you want smooth, realistic movement with minimal code + +--- + +## Summary + +You've learned: + +βœ… `setEntityKinetics()` - Enable physics on entities +βœ… `setMass()` and `setGravityScale()` - Configure physics properties +βœ… `applyForce()` - Apply custom forces +βœ… `steerWithWASD()` - Easy WASD physics movement +βœ… Steering behaviors - Seek, flee, pursue, avoid, arrive +βœ… When to use Transform vs. Physics vs. Steering + +--- + diff --git a/website/versioned_docs/version-0.7.1/03-Game Development/03-EditorOverview.md b/website/versioned_docs/version-0.7.1/03-Game Development/03-EditorOverview.md new file mode 100644 index 00000000..191fd6b5 --- /dev/null +++ b/website/versioned_docs/version-0.7.1/03-Game Development/03-EditorOverview.md @@ -0,0 +1,92 @@ +# Editor Overview + +The editor is the primary environment for building games with the Untold Engine. + +It is designed to be **explicit, predictable, and tightly integrated** with the engine runtime. +What you see in the editor reflects what runs in the game. + +This page provides a **user-facing overview** of the editor for game developers. + +![editorbottomshot](../images/Editor/EditorBottomShot.png) + +--- + +## Purpose of the Editor + +The editor allows you to: + +- Create and manage scenes +- Inspect and modify entities +- Write and iterate on gameplay scripts +- Manage assets +- Preview runtime behavior in real time + +The editor is not a separate simulation layer β€” it runs directly on top of the engine runtime. + +--- + +## Core Editor Views + +The editor is composed of several focused views, each with a clear responsibility. + +--- + +### Scene View + +The Scene View is where you visually interact with the world. + +You can: +- Navigate the scene camera +- Select entities +- Translate, rotate, and scale entities +- Preview lighting and scene composition + +This view reflects the engine’s real transform and rendering state. + +![editormainshot](../images/Editor/EditorMainShot.png) + +--- + +### Scene Hierarchy View + +The Scene Hierarchy shows all entities in the current scene. + +It allows you to: +- View parent–child relationships +- Select entities +- Organize scene structure + +The hierarchy mirrors the engine’s internal scene graph. + +![editorscenegraphview](../images/Editor/EditorScenegraphView.png) + +--- + +### Inspector View + +The Inspector displays detailed information about the selected entity. + +From the Inspector, you can: +- View and modify components +- Adjust transforms and properties +- Attach scripts and assets + +Changes made in the Inspector apply directly to the runtime state. + +![editorinspectorview](../images/Editor/EditorInspectorView.png) + +--- + +### Asset Browser View + +The Asset Browser provides access to project assets such as: + +- Models +- Textures +- Scripts +- Scenes + +Assets imported through the editor are organized and made available to the engine automatically. + +![editorassetbrowserview](../images/Editor/EditorAssetBrowserView-alt.png) + diff --git a/website/versioned_docs/version-0.7.1/03-Game Development/04-Scripting-Experimental/01-Overview.md b/website/versioned_docs/version-0.7.1/03-Game Development/04-Scripting-Experimental/01-Overview.md new file mode 100644 index 00000000..e2ab1628 --- /dev/null +++ b/website/versioned_docs/version-0.7.1/03-Game Development/04-Scripting-Experimental/01-Overview.md @@ -0,0 +1,100 @@ +# Overview + +⚠️ **EXPERIMENTAL FEATURE** + +This section documents the **UntoldEngine Scripting (USC)** language - an experimental scripting system that is **currently in development**. + +--- + +## Current Status + +USC scripting is in **early experimental phases** and is **not recommended for production use**. + +For game development, we strongly recommend using **Swift** and **Xcode** (see parent section: [Game Development Overview](../01-Overview.md)). + +--- + +## What is USC? + +USC (Untold Scripting Language) is a custom scripting language designed for the UntoldEngine. It aims to provide: + +- Simple C-like syntax +- Entity-component scripting +- Scene-based game logic + +However, the language is still evolving, and **its future direction is under evaluation**. + +--- + +## Why USC? + +Originally, USC was designed to provide: + +1. **Lower barrier to entry** - Simpler syntax than Swift +2. **Scene-embedded scripts** - Scripts attached to entities in the editor +3. **Hot-reload** - Faster iteration for non-compiled changes + +However, **Swift + Xcode** has proven to be more practical for most use cases: + +- Mature tooling (debugging, profiling, autocomplete) +- Type safety and compile-time errors +- Familiar to Apple platform developers +- Better performance + +--- + +## Should You Use USC? + +**No, not yet.** Here's why: + +❌ **Incomplete** - Many features are missing or unstable +❌ **Underdocumented** - Documentation is sparse and may be outdated +❌ **Limited tooling** - No debugger, no IDE support +❌ **Breaking changes** - Syntax and behavior may change without notice +❌ **Unoptimized** - Performance is not production-ready + +Use **Swift** for all game development until USC reaches a stable release. + +--- + +## When Will USC Be Ready? + +USC is in **exploratory development**. We are evaluating: + +- Whether USC provides enough value over Swift +- What the ideal syntax and feature set should be +- How to integrate it seamlessly with Xcode workflows + +There is **no timeline** for USC becoming production-ready. + +--- + +## Exploring USC Anyway? + +If you want to experiment with USC despite the warnings: + +1. Read the **[USC Language Reference](./02-USC/01_Introduction.md)** +2. Try the **[USC Tutorials](./03-Tutorials/00_HelloWorld.md)** +3. Understand that **nothing is guaranteed to work** + +Do NOT use USC for: +- Production games +- Serious projects +- Teaching materials +- Anything you want to maintain long-term + +--- + +## Feedback + +If you experiment with USC, we welcome feedback: + +- What do you like about it? +- What frustrates you? +- Does it solve problems Swift doesn't? +- Would you use it if it were stable? + +Your feedback helps us decide USC's future direction. + +--- + diff --git a/website/versioned_docs/version-0.7.1/03-Game Development/04-Scripting-Experimental/02-USC/01_Introduction.md b/website/versioned_docs/version-0.7.1/03-Game Development/04-Scripting-Experimental/02-USC/01_Introduction.md new file mode 100644 index 00000000..06d6abd3 --- /dev/null +++ b/website/versioned_docs/version-0.7.1/03-Game Development/04-Scripting-Experimental/02-USC/01_Introduction.md @@ -0,0 +1,136 @@ +--- +id: usc-scripting-introducction +title: Introduction +sidebar_label: Introduction +sidebar_position: 1 +--- + +# Introduction to USC + +USC (Untold Script Core) is the scripting system used to define **gameplay behavior** in Untold Engine. + +USC is designed to be: +- Explicit +- Predictable +- Easy to read and reason about + +It focuses on *what your game does*, not how the engine is implemented. + +--- + +## What USC Is + +USC is a **script-based API** that allows you to attach behavior to entities. + +You use USC to: +- Respond to input +- Move entities +- Control cameras +- Apply forces +- Drive simple gameplay logic + +USC scripts describe *behavior over time*. + +--- + +## What USC Is Not + +USC is **not**: +- A general-purpose programming language +- A replacement for engine code +- A system for complex algorithms or heavy math + +If you need low-level control or complex systems, those belong in the engine itself. + +USC intentionally keeps the surface area small. + +--- + +## Why USC Exists + +Traditional game engines often expose: +- Large, complex APIs +- Implicit behavior +- Hidden update order + +USC takes a different approach. + +It is designed so that: +- Scripts read top-to-bottom +- Behavior is explicit +- There is no hidden execution magic + +This makes gameplay logic easier to understand, debug, and maintain. + +--- + +## How USC Fits into Untold Engine + +USC sits **above the engine** and **below the editor**. + +- The engine provides systems and data +- USC expresses gameplay intent +- The editor helps you attach and manage scripts + +USC does not replace the engine β€” it builds on top of it. + +--- + +## The Script Lifecycle + +A USC script runs as part of the engine update loop. + +At a high level: +1. The engine updates input +2. USC scripts are evaluated +3. The engine applies the results + +Scripts are evaluated every frame while the game is running. + +You do not manually manage update loops. + +--- + +## Working with Entities + +USC scripts operate on **entities**. + +A script is attached to an entity and can: +- Read entity state +- Modify transforms +- Interact with components +- Respond to input + +Scripts do not create entities or systems β€” they control behavior. + +--- + +## Example Use Cases + +USC is ideal for: +- Player movement +- Camera follow logic +- Simple physics interaction +- Trigger-based events +- Prototyping gameplay ideas + +If something feels *game-specific*, it likely belongs in USC. + +--- + +## Design Philosophy + +USC follows a few guiding principles: + +- **Explicit over implicit** + No hidden behavior. + +- **Readable over clever** + Scripts should be easy to understand at a glance. + +- **Stable over flexible** + Fewer features, fewer surprises. + +These principles are intentional. + + diff --git a/website/versioned_docs/version-0.7.1/03-Game Development/04-Scripting-Experimental/02-USC/02_QuickStart.md b/website/versioned_docs/version-0.7.1/03-Game Development/04-Scripting-Experimental/02-USC/02_QuickStart.md new file mode 100644 index 00000000..bb021ce3 --- /dev/null +++ b/website/versioned_docs/version-0.7.1/03-Game Development/04-Scripting-Experimental/02-USC/02_QuickStart.md @@ -0,0 +1,197 @@ +# USC Scripting – Quick Start + +This tutorial will walk you through creating your first script in the Untold Engine, from setup to testing in Play mode. + +**What you'll build:** A cube that moves upward by changing its position every frame. + +**Time:** ~10 minutes + +--- + +## Step 1: Create Your First Script + +### 1.1 Configure Asset Path + +1. Open Untold Engine. +2. Go to **Asset Library β†’ Set Asset Folder** +3. Create/Select your projects's asset directory. + +This is where your assets will be saved. Including your Scripts. + +![assetlibraryloupe](../../../images/Editor/EditorAssetLibraryLoupe.png) + +### 1.2 Create Your First Script + +1. In the editor toolbar, click **Scripts: Open in Xcode** (blue button). +2. Click the `+` button to create a new script. +3. Enter the script name: `MovingCube` +4. Xcode opens the Scripts package so you can edit the new file. + +When the script is created: +- The source file is added to your project +- Xcode shows a template like this: + +```swift +import Foundation +import UntoldEngine + +extension GenerateScripts { + static func generateMovingCube(to dir: URL) { + // Write your script here + } +} +``` + +You will edit everything in Xcode. + +--- + +## Step 2: Wire Up the Script + +⚠️ IMPORTANT MANUAL STEP + +The editor created your script file, but you need to tell the build system to generate it. + +1. Click Scripts: Open in Xcode (blue button in toolbar) +2. In Xcode, open GenerateScripts.swift +3. Add your script to the main() function: + +```swift +@main +struct GenerateScripts { + static func main() { + print("πŸ”¨ Generating USC scripts...") + + let outputDir = URL(fileURLWithPath: "Generated/") + try? FileManager.default.createDirectory(at: outputDir, withIntermediateDirectories: true) + + // Add this line: + generateMovingCube(to: outputDir) + + print("βœ… All scripts generated in Generated/") + } +} +``` + +Now run the GenerateScripts target (`Cmd+R`) to generate the `.uscript` files. + + +MPORTANT NOTES: +The function name (e.g. generateMovingCube) MUST match the tutorial’s script +Only adjust that single line per tutorial +The structure, wording, and warning must remain consistent across all documents + +--- + +## Step 3: Write USC Logic + +Replace the function with this complete script: + +```swift +extension GenerateScripts { + static func generateMovingCube(to dir: URL) { + let script = buildScript(name: "MovingCube") { s in + // Run every frame + s.onUpdate() + .getProperty(.position, as: "pos") + .setVariable("offset", to: simd_float3(x: 0.0, y: 0.1, z: 0.0)) + .addVec3("pos", "offset", as: "newPos") + .setProperty(.position, toVariable: "newPos") + } + + let outputPath = dir.appendingPathComponent("MovingCube.uscript") + try? saveUSCScript(script, to: outputPath) + print(" βœ… MovingCube.uscript") + } +} +``` + +--- + +## Step 4: Build Scripts + +After editing scripts, build and run in Xcode so the engine can use the generated output. + +- In Xcode, press `Cmd+R` to run the GenerateScripts target and produce the `.uscript` files. (Optional: `Cmd+B` to check the build first.) +- Build and run output appears inside Xcode. + +> A successful build makes the script available in the Asset Library to attach to entities. + +**First build?** It may take 30-60 seconds to download dependencies. Subsequent builds are much faster. + +--- + +## Step 5: Add an Entity to the scene + +1. In the editor, click on "+" in the scenegraph +2. Click on "Cube" +3. A cube will show up in the scene. Make sure to select it. + +## Step 6: Link script to entity + +4. Open the **Asset Library** +5. Under the Script category, look for your script `MovingCube` and double click on the `.uscript`. This will automatically link the script to the entity. +6. To verify, the Inspector View will show the newly added script linked to the entity. + +![editorassetbrowserscript](../../../images/Editor/EditorAssetBrowserScripts.png) + +The script is now active and will run according to the engine update loop. + +--- + +## Step 7: Test in Play Mode + +### 7.1 Run the Scene + +1. Click **Play** in the editor +2. Watch your entity move upward continuously! + +### 7.2 Stop Play Mode + +Click **Stop** when done testing. + +--- + +## Step 8: Test Hot Reload - Move Sideways + +Let's modify the script to move the cube sideways instead of upward, and test the hot reload feature. + +### 8.1 Modify the Offset + +Modify your script to change the offset direction: + +```swift +extension GenerateScripts { + static func generateMovingCube(to dir: URL) { + let script = buildScript(name: "MovingCube") { s in + s.onUpdate() + .getProperty(.position, as: "pos") + .setVariable("offset", to: simd_float3(x: 0.1, y: 0.0, z: 0.0)) // Changed to move sideways + .addVec3("pos", "offset", as: "newPos") + .setProperty(.position, toVariable: "newPos") + } + + let outputPath = dir.appendingPathComponent("MovingCube.uscript") + try? saveUSCScript(script, to: outputPath) + print(" βœ… MovingCube.uscript") + } +} +``` + +**What changed:** The offset is now `(0.1, 0.0, 0.0)` instead of `(0.0, 0.1, 0.0)`, so the cube will move along the X-axis (sideways) instead of the Y-axis (upward). + +### 8.2 Rebuild + +1. In Xcode, press `Cmd+R` to run the GenerateScripts target. +2. Wait for "βœ… MovingCube.uscript" in the Xcode run output + +### 8.3 Hot Reload + +Back in the editor: +1. With your entity selected +2. Click **"Reload"** (orange button) in the Script Component Inspector +3. Click **Play** to test the changes +4. The cube should now move sideways instead of upward! + +![scriptreload](../../../images/Editor/ScriptReload.png) + diff --git a/website/versioned_docs/version-0.7.1/03-Game Development/04-Scripting-Experimental/02-USC/03_Workflow.md b/website/versioned_docs/version-0.7.1/03-Game Development/04-Scripting-Experimental/02-USC/03_Workflow.md new file mode 100644 index 00000000..87ff7779 --- /dev/null +++ b/website/versioned_docs/version-0.7.1/03-Game Development/04-Scripting-Experimental/02-USC/03_Workflow.md @@ -0,0 +1,108 @@ +# USC Scripting Workflow + +This document describes the **end-to-end workflow** for developing USC scripts in the Untold Engine. + +USC scripts are authored in Xcode. The Untold Editor coordinates assets and playback but does not include a built-in script editor. + +--- + +## Overview + +The USC workflow follows a clear sequence: + +1. Author scripts +2. Register scripts for generation +3. Build scripts +4. Attach scripts to entities +5. Iterate using hot reload + +The editor is the central coordination point for this process, while Xcode is where you author scripts. + +--- + +## Primary Editing Surface + +USC scripts are written in Xcode. Use **Scripts: Open in Xcode** to open the Scripts package; the Untold Editor does not provide an in-editor script editor. + +Xcode provides: +- Direct access to script source files +- Editing of generation entry points +- Build/run feedback and diagnostics + +--- + +## Script Authoring + +Scripts are written as Swift source files using the USC DSL. + +Responsibilities: +- Express gameplay behavior +- React to input and engine state +- Remain independent of engine internals + +Scripts do not: +- Manage entities directly +- Access low-level engine systems +- Perform rendering or physics logic + +--- + +## Script Registration + +All USC scripts are registered through `GenerateScripts.swift`. + +This file: +- Defines which scripts are generated +- Acts as a single source of truth for scripting output +- Is edited directly in Xcode + +Unregistered scripts are ignored by the engine. + +--- + +## Script Generation and Build + +Building and running the GenerateScripts target: +- Runs the USC generation pipeline +- Produces engine-consumable output +- Reports errors and warnings in Xcode + +Builds are explicit and controlled. + +--- + +## Runtime Attachment + +After a successful build: +- Scripts appear as selectable components +- Scripts can be attached to entities via the Inspector +- Multiple entities may share the same script + +The engine controls execution timing. + +--- + +## Hot Reload and Iteration + +USC supports rapid iteration: + +- Edit script +- Build scripts +- Observe changes immediately + +This workflow encourages experimentation and fast feedback. + +--- + +## Design Intent + +The USC workflow is intentionally: + +- Xcode-first for authoring +- Editor-coordinated for playback +- Explicit +- Predictable +- Easy to debug + +It avoids hidden build steps and implicit execution. + diff --git a/website/versioned_docs/version-0.7.1/03-Game Development/04-Scripting-Experimental/02-USC/04_Scritps.md b/website/versioned_docs/version-0.7.1/03-Game Development/04-Scripting-Experimental/02-USC/04_Scritps.md new file mode 100644 index 00000000..e1744538 --- /dev/null +++ b/website/versioned_docs/version-0.7.1/03-Game Development/04-Scripting-Experimental/02-USC/04_Scritps.md @@ -0,0 +1,167 @@ +# USC Scripts + +This document explains **what a USC script is**, how it fits into the Untold Engine, and the rules that govern its behavior. + +It is intended to give you a **clear mental model** before diving into APIs, examples, or workflows. + +This page does **not** describe how to write scripts step by step. +It explains what scripts *represent* and *why they are designed the way they are*. + +--- + +## What Is a USC Script? + +A **USC script** is a declarative description of gameplay behavior. + +You write scripts in Swift using a constrained, fluent DSL, and the engine executes those scripts at runtime as part of its update loop. + +A script expresses **intent**, not implementation details. + +Examples of intent: +- Move an entity when input is received +- Apply forces in response to events +- Adjust camera behavior over time + +The engine owns *how* those intentions are executed. + +--- + +## Scripts and Entities + +USC scripts are **attached to entities**. + +- A script always operates in the context of the entity it is attached to +- Scripts do not own entities +- Scripts do not create or destroy entities + +Multiple entities may share the same script definition, each with its own execution context and script-local state. + +--- + +## Execution Model + +Scripts participate in the engine’s execution model. + +Key characteristics: + +- Scripts run when their declared events are triggered +- The engine controls execution order and timing +- Scripts do not manage threads or scheduling +- Execution is deterministic and engine-driven + +A script never decides *when* it runs β€” it only declares *what should happen* when it does. + +--- + +## Script Lifecycle + +At a high level, a USC script goes through the following lifecycle: + +1. Script is authored +2. Script is registered and generated +3. Script is attached to an entity +4. Script becomes active +5. Script executes in response to events +6. Script stops executing when detached or when the entity is destroyed + +Lifecycle transitions are managed by the engine. + +--- + +## Events and Entry Points + +Scripts are organized around **events**, also called entry points. + +Examples include: +- Startup events +- Per-frame updates +- Custom or engine-driven events + +Each event defines **when a block of instructions executes**. + +Scripts may contain multiple event handlers, each expressing a different behavior. + +--- + +## Script Context + +Every script executes with a **context** provided by the engine. + +The context gives controlled access to: +- The attached entity’s properties +- Script-defined variables +- Engine-provided values (such as delta time or input state) + +Scripts never access engine state directly β€” all access flows through this context. + +--- + +## State and Variables + +Scripts may store local state using variables. + +- Variables are scoped to the script instance +- Each entity gets its own variable set +- Variables persist across executions unless reset + +Script variables are designed for **lightweight gameplay state**, not long-term data storage. + +--- + +## What Scripts Can Do + +USC scripts are designed to express common gameplay behaviors, such as: + +- Reading input +- Modifying transforms +- Applying forces or impulses +- Steering entities +- Controlling cameras +- Triggering animations +- Reacting to events + +Scripts focus on *what should happen*, not *how systems work internally*. + +--- + +## What Scripts Cannot Do + +USC scripts intentionally **cannot**: + +- Create or destroy entities +- Access rendering pipelines or GPU resources +- Manage memory +- Spawn threads +- Call arbitrary engine internals +- Control execution order or threading + +These constraints are deliberate and central to USC’s design. + +--- + +## Design Intent + +USC exists to provide: + +- Predictable gameplay behavior +- Clear ownership of state +- Safe boundaries between game logic and engine internals +- Fast iteration and easy debugging + +By limiting what scripts can do, the engine remains stable and behavior remains easy to reason about. + +--- + +## Relationship to the API Reference + +This document explains **what a script is**. + +For detailed information about: +- Available events +- Instructions and commands +- Math operations +- Input handling +- Physics and camera helpers + +See **USC β†’ API Reference**. + diff --git a/website/versioned_docs/version-0.7.1/03-Game Development/04-Scripting-Experimental/02-USC/05_APIReference.md b/website/versioned_docs/version-0.7.1/03-Game Development/04-Scripting-Experimental/02-USC/05_APIReference.md new file mode 100644 index 00000000..ac00431a --- /dev/null +++ b/website/versioned_docs/version-0.7.1/03-Game Development/04-Scripting-Experimental/02-USC/05_APIReference.md @@ -0,0 +1,624 @@ +--- +id: usc-scripting-api +title: USC Scripting API Reference +sidebar_label: API Reference +sidebar_position: 10 +--- + +# Untold Engine – USC Scripting API Reference + +USC (Untold Script Core) is the scripting system inside the Untold Engine. +You write scripts in Swift using a fluent DSL, and the engine executes them at runtime. + +This reference provides the complete API surface for building gameplay scripts. + +--- + +## 1. Script Lifecycle + +### Building and Exporting Scripts + +USC provides two ways to create scripts: + +**buildScript()** - Creates a script in memory: +```swift +let script = buildScript(name: "MyScript") { s in + s.onUpdate() + .log("Running every frame") +} +``` + +**saveUSCScript()** - Saves a script to a `.uscript` file: +```swift +let outputPath = dir.appendingPathComponent("MyScript.uscript") +try? saveUSCScript(script, to: outputPath) +``` + +**Typical Pattern** - Build then save: +```swift +extension GenerateScripts { + static func generateMyScript(to dir: URL) { + let script = buildScript(name: "MyScript") { s in + s.onUpdate() + .log("Running every frame") + } + + let outputPath = dir.appendingPathComponent("MyScript.uscript") + try? saveUSCScript(script, to: outputPath) + print(" βœ… MyScript.uscript") + } +} +``` + +### TriggerType (Optional) + +**Default:** `.perFrame` (runs every frame) + +You only need to specify `triggerType` if you want something other than the default: + +**When to override:** + +- **`.event`** - For event-driven scripts (collision handlers, triggers) + ```swift + let script = buildScript(name: "DoorTrigger", triggerType: .event) { s in + s.onCollision(tag: "Player") // Coming soon - collision system not yet implemented + .log("Door opened!") + } + ``` + +- **`.manual`** - For manually controlled scripts (cutscenes, special sequences) + ```swift + let script = buildScript(name: "Cutscene", triggerType: .manual) { s in + s.onEvent("StartCutscene") + .log("Cutscene playing...") + } + ``` + +**Most scripts don't need to specify this** - the default `.perFrame` works for continuous behaviors like movement and AI. + +### ExecutionMode (Optional) + +**Default:** `.auto` (engine manages execution) + +You rarely need to override this. Only specify `executionMode` for advanced scenarios: + +- **`.interpreted`** - Force interpreter-based execution (debugging, special cases) + ```swift + let script = buildScript(name: "DebugScript", executionMode: .interpreted) { s in + s.onUpdate() + .log("Debug mode") + } + ``` + +**Most scripts should use the default** `.auto` mode. + +--- + +## 2. Events (Entry Points) + +Events define when code blocks execute. Chain commands after each event: + +**onStart()** - Runs once when the entity starts (like Awake/Start in Unity): +```swift +s.onStart() + .setVariable("health", to: 100.0) + .setVariable("speed", to: 5.0) + .log("Entity initialized") +``` + +**onUpdate()** - Runs every frame (like Update in Unity): +```swift +s.onUpdate() + .getProperty(.position, as: "pos") + .log("Current position") +``` + +**onCollision(tag:)** - Runs when colliding with tagged entities: +> ⚠️ **Coming Soon** - The collision system is not yet implemented. This API is planned for a future release. + +```swift +s.onCollision(tag: "Enemy") + .log("Hit an enemy!") + .setVariable("health", to: 0.0) +``` + +**onEvent(_:)** - Runs when a custom event is fired: +```swift +s.onEvent("PowerUpCollected") + .setVariable("speed", to: 10.0) + .log("Speed boost activated") +``` + +### Multiple Event Handlers + +You can define multiple event handlers in one script: +```swift +let script = buildScript(name: "Player") { s in + s.onStart() + .setVariable("score", to: 0.0) + + s.onUpdate() + .getProperty(.position, as: "pos") + + // Coming soon - collision system not yet implemented + s.onCollision(tag: "Coin") + .addFloat("score", 1.0, as: "score") +} + +let outputPath = dir.appendingPathComponent("Player.uscript") +try? saveUSCScript(script, to: outputPath) +``` + +### Interpreter Execution (Advanced) + +For `.interpreted` execution mode: +```swift +interpreter.execute(script: script, context: context, forEvent: "OnStart") +interpreter.execute(script: script, context: context, forEvent: nil) // onUpdate +``` + +--- + +## 3. Script Context + +Every script runs with a **context** that provides access to: +- **Entity properties** (position, scale, velocity, acceleration, lights) +- **Script variables** (custom data you store) +- **Engine state** (delta time, input, etc.) + +You access the entity's properties using `.getProperty()` and `.setProperty()`. + +**Available at Runtime:** +- Current entity's transform (position, scale) +- Physics properties (velocity, acceleration, mass) +- Rendering properties (color, intensity for lights) +- All script variables you've defined + +**Example:** +```swift +s.onUpdate() + .getProperty(.position, as: "currentPos") // Read from entity + .getProperty(.velocity, as: "currentVel") // Read physics + .setVariable("myCustomData", to: 42.0) // Store in script + .setProperty(.position, toVariable: "newPos") // Write to entity +``` + +--- + +## 4. Flow Control + +**Conditionals** - Execute code based on comparisons: +```swift +s.ifCondition( + lhs: .variableRef("speed"), + .greater, + rhs: .float(10.0) +) { nested in + nested.log("Too fast!") + nested.setVariable("speed", to: 10.0) +} +``` + +**Available operators:** +- `.greater`, `.less` +- `.equal`, `.notEqual` +- `.lessOrEqual`, `.greaterOrEqual` + +**Convenience conditionals:** +```swift +s.ifGreater("speed", than: 10.0) { nested in + nested.log("Too fast!") +} + +s.ifLess("health", than: 20.0) { nested in + nested.log("Low health!") +} + +s.ifEqual("state", to: 1.0) { nested in + nested.log("State is 1") +} +``` + +**Organizing math-heavy code with `.math { ... }`:** +```swift +s.onUpdate() + .math { m in + m.getProperty(.velocity, as: "vel") + m.lengthVec3("vel", as: "speed") + m.ifGreater("speed", than: 10) { n in + n.normalizeVec3("vel", as: "dir") + n.scaleVec3("dir", literal: 10, as: "clampedVel") + n.setProperty(.velocity, toVariable: "clampedVel") + } + } + .log("Velocity clamped if above 10") +``` + +--- + +## 5. Values & Variables + +**Value Types** - USC supports these data types: +```swift +enum Value { + case float(Float) // Single number + case vec3(x: Float, y: Float, z: Float) // 3D vector + case string(String) // Text + case bool(Bool) // True/false + case variableRef(String) // Reference to a variable +} +``` + +**Setting Variables:** +```swift +s.setVariable("speed", to: 5.0) +s.setVariable("direction", to: simd_float3(x: 1, y: 0, z: 0)) +s.setVariable("isActive", to: true) +s.setVariable("playerName", to: "Hero") +``` + +**Using Variable References:** +```swift +s.setVariable("maxSpeed", to: 10.0) +s.setVariable("currentSpeed", to: .variableRef("maxSpeed")) // Copy value +``` + +--- + +## 6. Engine Properties + +**Available Properties** - Read/write entity properties: +```swift +enum ScriptProperty: String { + // Transform + case position, scale + + // Physics + case velocity, acceleration, mass, angularVelocity + + // Rendering (lights) + case intensity, color + + // Engine time + case deltaTime +} +``` + +**Reading Properties:** +```swift +s.getProperty(.position, as: "pos") // Store position in "pos" variable +s.getProperty(.velocity, as: "vel") // Store velocity in "vel" variable +s.getProperty(.deltaTime, as: "dt") // Store frame delta time +``` + +**Writing Properties:** +```swift +s.setProperty(.position, toVariable: "newPos") // Set from variable +s.setProperty(.velocity, to: simd_float3(x: 0, y: 5, z: 0)) // Set from literal +s.setProperty(.angularVelocity, to: simd_float3(x: 0, y: 1, z: 0)) // Set spin (write-only today) +``` + +> Note: Rotation is controlled through `rotateTo` / `rotateBy` instructions. Reading rotation via `getProperty(.rotation, ...)` is not yet supported. + +**Complete Example:** +```swift +s.onUpdate() + .getProperty(.position, as: "currentPos") + .setVariable("offset", to: simd_float3(x: 0, y: 0.1, z: 0)) + .addVec3("currentPos", "offset", as: "newPos") + .setProperty(.position, toVariable: "newPos") // Move entity up +``` + +--- + +## 7. Math Operations + +**Float Math:** +```swift +s.addFloat("a", "b", as: "sum") // sum = a + b (two variables) +s.addFloat("a", literal: 5.0, as: "sum") // sum = a + 5 (variable + literal) +s.mulFloat("a", "b", as: "product") // product = a * b (two variables) +s.mulFloat("a", literal: 2.0, as: "product") // product = a * 2 (variable * literal) +``` + +**Vector Math:** +```swift +s.addVec3("v1", "v2", as: "sum") // sum = v1 + v2 +s.scaleVec3("dir", literal: 2.0, as: "scaled") // scaled = dir * 2.0 +s.scaleVec3("dir", by: "scale", as: "scaled") // scaled = dir * scale +s.lengthVec3("vec", as: "length") // length = magnitude of vec +s.normalizeVec3("vec", as: "unitVec") // normalized vec (zero-safe) +s.dotVec3("a", "b", as: "dot") // dot product -> float +s.crossVec3("a", "b", as: "cross") // cross product -> vec3 +s.lerpVec3(from: "a", to: "b", t: "t", as: "lerped") // linear interpolation +s.lerpFloat(from: "a", to: "b", t: "t", as: "out") // scalar lerp +s.reflectVec3("v", normal: "n", as: "reflected") // reflect v about normal +s.projectVec3("v", onto: "axis", as: "proj") // project v onto axis +s.angleBetweenVec3("a", "b", as: "angleDeg") // angle in degrees +s.clampFloat("speed", min: "minSpeed", max: "maxSpeed", as: "clampedSpeed") // bounds via vars +s.clampVec3("velocity", min: "minVel", max: "maxVel", as: "clampedVel") // component-wise +``` + +**Example - Calculate velocity:** +```swift +s.onUpdate() + .setVariable("direction", to: simd_float3(x: 1, y: 0, z: 0)) + .setVariable("speed", to: 5.0) + .scaleVec3("direction", by: "speed", as: "velocity") + .setProperty(.velocity, toVariable: "velocity") +``` + +--- + +## 8. Built-in Behaviors (Steering, Camera, Physics) + +All behaviors are instruction helpersβ€”no `callAction` or `ScriptArgKey`. + +**Steering** +```swift +// Seek toward a target and store the steering force +s.seek(targetPosition: .vec3(x: 10, y: 0, z: 0), + maxSpeed: .float(5.0), + result: "seekForce") + +s.steerSeek(targetPosition: .variableRef("targetPos"), + maxSpeed: .variableRef("maxSpeed"), + deltaTime: .variableRef("dt"), + turnSpeed: .variableRef("turnSpeed")) + +// Arrive with slowing radius +s.steerArrive(targetPosition: .variableRef("targetPos"), + maxSpeed: .variableRef("maxSpeed"), + slowingRadius: .variableRef("slowingRadius"), + deltaTime: .variableRef("dt"), + turnSpeed: .variableRef("turnSpeed")) + +// Evade a threat: compute force into result or apply directly +s.steerEvade(threatEntity: .string("Enemy"), + maxSpeed: .float(6.0), + result: "evadeForce") // omit result to apply immediately + +// Pursuit +s.steerPursuit(targetEntity: .variableRef("targetName"), + maxSpeed: .variableRef("maxSpeed"), + deltaTime: .variableRef("dt"), + turnSpeed: .variableRef("turnSpeed")) + +// Align orientation to current velocity (smooth) +s.alignOrientation(deltaTime: .float(0.016), + turnSpeed: .float(1.0)) +``` + +**Camera** +```swift +// Snap camera to a position +s.cameraMoveTo(.vec3(x: 0, y: 3, z: -10)) + +// Look at a target +s.cameraLookAt(eye: .vec3(x: 0, y: 3, z: -8), + target: .variableRef("lookTarget"), + up: .vec3(x: 0, y: 1, z: 0)) + +// Follow a target with smoothing +s.cameraFollow(target: .string("Player"), + offset: .vec3(x: 0, y: 3, z: -6), + smoothFactor: .float(5.0), + deltaTime: .float(0.016)) + +// WASDQE fly camera +s.cameraMoveWithInput(speedVar: "moveSpeed", + deltaTimeVar: "dt", + wVar: "wPressed", + aVar: "aPressed", + sVar: "sPressed", + dVar: "dPressed", + qVar: "qPressed", + eVar: "ePressed") + +// Orbit a target entity (auto look-at) +s.cameraOrbitTarget(target: .string("Boss"), + radius: .float(12.0), + speed: .float(1.5), + deltaTime: .float(0.016), + offsetY: .float(1.5)) +``` + +**Physics** +```swift +// Impulse +s.applyLinearImpulse(direction: .vec3(x: 1, y: 0, z: 0), + magnitude: .float(5.0)) + +// Continuous world force +s.applyWorldForce(direction: .vec3(x: 0, y: 1, z: 0), + magnitude: .float(3.0)) + +// Velocity control +s.setLinearVelocity(.vec3(x: 0, y: 0, z: 5)) +s.addLinearVelocity(.variableRef("deltaVel")) +s.clampLinearSpeed(min: .float(2.0), max: .float(8.0)) + +// Angular control +s.applyAngularImpulse(axis: .vec3(x: 0, y: 1, z: 0), magnitude: .float(2.0)) +s.clampAngularSpeed(max: .float(5.0)) +s.applyAngularDamping(damping: .float(0.6), deltaTime: .float(0.016)) +``` + +--- + +## 9. Transform & Physics Helpers + +**Transform:** +```swift +s.translateTo(x: 1, y: 2, z: 3) // Set absolute position +s.translateTo(simd_float3(x: 1, y: 2, z: 3)) // Alternative syntax +s.translateBy(x: 0.1, y: 0, z: 0) // Move relative +s.translateBy(simd_float3(x: 0.1, y: 0, z: 0)) // Alternative syntax +s.rotateTo(degrees: 45, axis: simd_float3(x: 0, y: 1, z: 0)) // Set absolute rotation +s.rotateBy(degrees: 45, axis: simd_float3(x: 0, y: 1, z: 0)) // Rotate relative +s.lookAt("targetEntityName") // Face another entity +``` + +**Physics - Force & Torque:** +```swift +s.applyForce(force: simd_float3(x: 0, y: 10, z: 0)) // Apply linear force +s.applyMoment(force: simd_float3(x: 5, y: 0, z: 0), at: simd_float3(x: 1, y: 0, z: 0)) // Apply torque at point +``` + +**Physics - Velocity Control:** +```swift +s.clearVelocity() // Stop linear movement instantly +s.clearAngularVelocity() // Stop rotation instantly +s.clearForces() // Clear accumulated forces +``` + +**Physics - Gravity & Pause:** +```swift +s.setGravityScale(0.5) // Half gravity (0 = no gravity, 1 = normal, 2 = double) +s.pausePhysicsComponent(isPaused: true) // Pause/unpause physics simulation +``` + +**Example - Jump mechanic:** +```swift +s.onEvent("Jump") + .getProperty(.velocity, as: "currentVel") + .setVariable("jumpForce", to: simd_float3(x: 0, y: 15, z: 0)) + .addVec3("currentVel", "jumpForce", as: "newVel") + .setProperty(.velocity, toVariable: "newVel") +``` + +**Example - Reset physics:** +```swift +s.onEvent("Respawn") + .clearVelocity() // Stop all movement + .clearAngularVelocity() // Stop all rotation + .clearForces() // Clear force accumulation + .translateTo(simd_float3(x: 0, y: 5, z: 0)) // Move to spawn point +``` + +**Example - Apply torque to spin:** +```swift +s.onUpdate() + .ifKeyPressed("R") { n in + // Apply torque at the right edge to spin left + n.applyMoment(force: simd_float3(x: 0, y: 10, z: 0), at: simd_float3(x: 1, y: 0, z: 0)) + } +``` + +**Animation:** +```swift +s.playAnimation("Walk", loop: true) // Play looping animation +s.playAnimation("Jump", loop: false) // Play once +s.stopAnimation() // Stop current animation +``` + +--- + +## 10. Input Conditions + +**Keyboard Input:** +```swift +s.ifKeyPressed("W") { nested in + nested.log("Forward") + nested.applyForce(force: simd_float3(x: 0, y: 0, z: -1)) +} + +s.ifKeyPressed("Space") { nested in + nested.log("Jump!") + nested.applyForce(force: simd_float3(x: 0, y: 10, z: 0)) +} +``` + +**Example - WASD movement:** +```swift +s.onUpdate() + .setVariable("moveSpeed", to: 5.0) + .ifKeyPressed("W") { n in + n.applyForce(force: simd_float3(x: 0, y: 0, z: -5)) + } + .ifKeyPressed("S") { n in + n.applyForce(force: simd_float3(x: 0, y: 0, z: 5)) + } + .ifKeyPressed("A") { n in + n.applyForce(force: simd_float3(x: -5, y: 0, z: 0)) + } + .ifKeyPressed("D") { n in + n.applyForce(force: simd_float3(x: 5, y: 0, z: 0)) + } +``` + +--- + +## 11. Logging & Debugging + +**Log Messages:** +```swift +s.log("Debug message") // Simple message +s.log("Player health: 100") // Can include values +s.logValue("velocity", value: .variableRef("vel")) // Log a labeled variable +s.logValue("spawnPoint", value: .vec3(x: 0, y: 1, z: 2)) // Log a literal with a label +``` + +**Debug Variables:** +```swift +s.onUpdate() + .getProperty(.position, as: "pos") + .log("Position updated") // Track when events occur +``` + +--- + +## 12. Best Practices + +### Use enums instead of raw strings +βœ… **Good:** +```swift +s.getProperty(.position, as: "pos") +s.setProperty(.velocity, toVariable: "vel") +``` + +❌ **Avoid:** +```swift +s.getProperty("position", as: "pos") // String-based, no autocomplete +``` + +### Variable Naming +- Use descriptive names: `"playerHealth"` not `"h"` +- Consistent naming: `"currentPos"`, `"targetPos"`, `"newPos"` +- Avoid conflicts with property names + +### Performance +- Use `.perFrame` for continuous behaviors (movement, AI) +- Use `.event` for one-time triggers (collision, pickups) +- Minimize operations in `onUpdate()` when possible + +### Script Organization +```swift +let script = buildScript(name: "Enemy") { s in + // Initialization + s.onStart() + .setVariable("health", to: 100.0) + .setVariable("speed", to: 3.0) + + // Main loop + s.onUpdate() + .setVariable("maxSpeed", to: 5.0) + .seek(targetPosition: .string("Player"), + maxSpeed: .variableRef("maxSpeed"), + result: "steer") + .applyForce(force: .variableRef("steer")) + + // Event handlers (collision system coming soon) + s.onCollision(tag: "Bullet") + .subtractFloat("health", 10.0, as: "health") +} + +let outputPath = dir.appendingPathComponent("Enemy.uscript") +try? saveUSCScript(script, to: outputPath) +``` + +### Debugging Tips +- Add `.log()` statements to trace execution +- Use meaningful variable names for debugging +- Test scripts incrementally +- Check console output in Play mode diff --git a/website/versioned_docs/version-0.7.1/03-Game Development/04-Scripting-Experimental/03-Tutorials/00_HelloWorld.md b/website/versioned_docs/version-0.7.1/03-Game Development/04-Scripting-Experimental/03-Tutorials/00_HelloWorld.md new file mode 100644 index 00000000..d2300510 --- /dev/null +++ b/website/versioned_docs/version-0.7.1/03-Game Development/04-Scripting-Experimental/03-Tutorials/00_HelloWorld.md @@ -0,0 +1,228 @@ +# "Hello World" - Your First Script + +**What you'll learn:** +- Creating a script in Untold Engine Studio +- Using `onStart()` and `onUpdate()` lifecycle events +- Logging messages for debugging +- Attaching scripts to entities + +**Time:** ~5 minutes + +--- + +## What We're Building + +A simple script that: +1. Logs "Hello, Untold Engine!" when the entity starts +2. Logs "Script running..." every frame during Play mode + +--- + +## Step 1: Create the Script + +1. Open **Untold Engine Studio** +2. In the toolbar, click **Scripts: Open in Xcode** (blue button) +3. Click the `+` button and enter the script name: `HelloWorld` +4. Click OK, then Xcode opens the Scripts package + +When the script is created: +- The source file is added to your project +- You edit the script in Xcode + +You'll see a template like this: + +```swift +import Foundation +import UntoldEngine +import simd + +extension GenerateScripts { + static func generateHelloWorld(to dir: URL) { + // Write your script here + } +} +``` +> This script is added to GenerateScripts, which is the entry point the engine uses to discover and generate USC scripts. + +--- + + +## Step 2: Wire Up the Script + +⚠️ IMPORTANT MANUAL STEP + +The editor created your script file, but you need to tell the build system to generate it. + +1. Click Scripts: Open in Xcode (blue button in toolbar) +2. In Xcode, open GenerateScripts.swift +3. Add your script to the main() function: + +```swift +@main +struct GenerateScripts { + static func main() { + print("πŸ”¨ Generating USC scripts...") + + let outputDir = URL(fileURLWithPath: "Generated/") + try? FileManager.default.createDirectory(at: outputDir, withIntermediateDirectories: true) + + // Add this line: + generateHelloWorld(to: outputDir) + + print("βœ… All scripts generated in Generated/") + } +} +``` + +Now run the GenerateScripts target (`Cmd+R`) to generate the `.uscript` files. + + +MPORTANT NOTES: +The function name (e.g. generateHelloWorld) MUST match the tutorial’s script +Only adjust that single line per tutorial +The structure, wording, and warning must remain consistent across all documents + +--- + + +## Step 3: Write the Script + +Replace the function with this complete script: + +```swift +import Foundation +import UntoldEngine +import simd + +extension GenerateScripts { + static func generateHelloWorld(to dir: URL) { + let script = buildScript(name: "HelloWorld") { s in + // Runs once when entity starts + s.onStart() + .log("Hello, Untold Engine!") + .log("Script initialized successfully") + + // Runs every frame + s.onUpdate() + .log("Script running...") + } + + let outputPath = dir.appendingPathComponent("HelloWorld.uscript") + try? saveUSCScript(script, to: outputPath) + print(" βœ… HelloWorld.uscript") + } +} +``` + +### Understanding the Code + +**`buildScript(name:)`** - Creates a new script +- The name identifies the script in the editor + +**`onStart()`** - Lifecycle event that runs once +- Perfect for initialization +- Logs appear in the console when Play mode starts + +**`onUpdate()`** - Lifecycle event that runs every frame +- Use for continuous behaviors +- Be mindful of performance (runs 60+ times per second!) + +**`.log()`** - Outputs debug messages +- Messages appear in the editor's Console view +- Great for debugging and tracking execution + +--- + +## Step 4: Build the Script + +1. In Xcode, press `Cmd+R` to run the GenerateScripts target and generate the `.uscript` (optional: `Cmd+B` first to verify the build). +2. Watch for the Xcode run output: + +``` +πŸ”¨ Generating USC scripts... + βœ… HelloWorld.uscript +βœ… All scripts generated in Generated/ +``` + +**First build?** May take 30-60 seconds to download engine dependencies. Subsequent builds are much faster. + +--- + +## Step 5: Attach to an Entity + +1. Return to **Untold Engine Studio** +2. Select any entity in your scene (create a cube if needed) +3. In the Inspector panel, click **Add Component** β†’ **Script Component** +4. In the Asset Browser, find `HelloWorld.uscript` under Scripts/Generated +5. Double click on the `.uscript`. The script will be linked to the entity +--- + +## Step 6: Test It! + +1. Click **Play** in the toolbar +2. Open the **Console** view (bottom panel) +3. You should see: + ``` + Hello, Untold Engine! + Script initialized successfully + Script running... + Script running... + Script running... + ... + ``` + +4. Click **Stop** to exit Play mode + +--- + +## Understanding the Output + +- **"Hello, Untold Engine!"** appears once (from `onStart()`) +- **"Script running..."** appears continuously (from `onUpdate()`) + +⚠️ **Performance Note:** `onUpdate()` runs every frame! In a real game, avoid heavy logging in `onUpdate()`. This example is just for demonstration. + +--- + +## Modify and Experiment + +Try these changes to learn more: + +### Change the Messages +```swift +s.onStart() + .log("Game initialized") + .log("Player ready!") +``` + +### Remove the Update Log +```swift +s.onUpdate() + // Remove .log() to avoid console spam +``` + +### Add Initialization Variables +```swift +s.onStart() + .setVariable("playerName", to: "Hero") + .setVariable("health", to: 100.0) + .log("Player initialized with 100 health") +``` + +After making changes: +1. In Xcode, press `Cmd+R` to rerun the GenerateScripts target and regenerate the scripts (`Cmd+B` optional first). +2. Click **Reload** in the Script Component Inspector +3. Test in Play mode + +--- + +## What You Learned + +βœ… How to create a script in Untold Engine Studio +βœ… Using `onStart()` for initialization +βœ… Using `onUpdate()` for per-frame logic +βœ… Logging debug messages +βœ… Building and attaching scripts to entities +βœ… Testing scripts in Play mode + +--- diff --git a/website/versioned_docs/version-0.7.1/03-Game Development/04-Scripting-Experimental/03-Tutorials/01_Transform/01_MoveAnEntity.md b/website/versioned_docs/version-0.7.1/03-Game Development/04-Scripting-Experimental/03-Tutorials/01_Transform/01_MoveAnEntity.md new file mode 100644 index 00000000..57cf2d07 --- /dev/null +++ b/website/versioned_docs/version-0.7.1/03-Game Development/04-Scripting-Experimental/03-Tutorials/01_Transform/01_MoveAnEntity.md @@ -0,0 +1,235 @@ +# Move an Entity - Basic Translation + +**What you'll learn:** +- Moving an entity with `setProperty(.position)` +- Using `simd_float3` direction vectors +- Controlling speed with script variables +- Updating position every frame with `onUpdate()` + +**Time:** ~7 minutes + +**Prerequisites:** +- Untold Engine Studio installed and a scene with any entity (a cube works great) +- Access to Xcode via **Scripts: Open in Xcode** (toolbar button) + +--- + +## What We're Building + +A simple movement script that: +1. Moves an entity steadily along a chosen axis +2. Uses variables to control speed and direction +3. Logs a message when movement begins + +--- + +## Step 1: Create the Script + +1. Open **Untold Engine Studio** +2. In the toolbar, click **Scripts: Open in Xcode** (blue button) +3. Click the `+` button and enter the script name: `MoveAnEntity` +4. Click OK, then Xcode opens the Scripts package + +When the script is created: +- The source file is added to your project +- You edit the script in Xcode + +You'll see a template like this: + +```swift +import Foundation +import UntoldEngine +import simd + +extension GenerateScripts { + static func generateMoveAnEntity(to dir: URL) { + // Write your script here + } +} +``` +> This script is added to GenerateScripts, which is the entry point the engine uses to discover and generate USC scripts. + +--- + + +## Step 2: Wire Up the Script + +⚠️ IMPORTANT MANUAL STEP + +The editor created your script file, but you need to tell the build system to generate it. + +1. Click Scripts: Open in Xcode (blue button in toolbar) +2. In Xcode, open GenerateScripts.swift +3. Add your script to the main() function: + +```swift +@main +struct GenerateScripts { + static func main() { + print("πŸ”¨ Generating USC scripts...") + + let outputDir = URL(fileURLWithPath: "Generated/") + try? FileManager.default.createDirectory(at: outputDir, withIntermediateDirectories: true) + + // Add this line: + generateMoveAnEntity(to: outputDir) + + print("βœ… All scripts generated in Generated/") + } +} +``` + +Now run the GenerateScripts target (`Cmd+R`) to generate the `.uscript` files. + + +MPORTANT NOTES: +The function name (e.g. generateMoveAnEntity) MUST match the tutorial’s script +Only adjust that single line per tutorial +The structure, wording, and warning must remain consistent across all documents + +--- + + +## Step 3: Write the Script + +Replace the function with this complete script: + +```swift +import Foundation +import UntoldEngine +import simd + +extension GenerateScripts { + static func generateMoveAnEntity(to dir: URL) { + let script = buildScript(name: "MoveAnEntity") { s in + // Runs once when the entity starts + s.onStart() + .setVariable("moveSpeed", to: 0.05) // units per frame + .setVariable("direction", to: simd_float3(x: 0, y: 0, z: 1)) + .log("MoveAnEntity ready") + + // Runs every frame + s.onUpdate() + .getProperty(.position, as: "currentPos") + .scaleVec3("direction", by: "moveSpeed", as: "step") + .addVec3("currentPos", "step", as: "nextPos") + .setProperty(.position, toVariable: "nextPos") + } + + let outputPath = dir.appendingPathComponent("MoveAnEntity.uscript") + try? saveUSCScript(script, to: outputPath) + print(" βœ… MoveAnEntity.uscript") + } +} +``` + +### Understanding the Code + +**`moveSpeed` + `direction`** - Control how fast and where to move +- Speed is a scalar; direction is a vector (x, y, z) +- Change either without touching the rest of the script + +**`getProperty(.position, as:)`** - Reads the current position +- Positions are `simd_float3` values + +**`scaleVec3()` + `addVec3()`** - Build the new position +- Scales the direction by speed +- Adds it to the current position for smooth motion + +**`setProperty(.position, toVariable:)`** - Applies the updated position +- Runs every frame inside `onUpdate()` +- Keeps the movement continuous while Play mode runs + +--- + +## Step 4: Build the Script + +1. In Xcode, press `Cmd+R` to run the GenerateScripts target and generate the `.uscript` (optional: `Cmd+B` first to verify the build). +2. Watch for the Xcode run output: + +``` +πŸ”¨ Generating USC scripts... + βœ… MoveAnEntity.uscript +βœ… All scripts generated in Generated/ +``` + +**First build?** May take 30-60 seconds to download engine dependencies. Subsequent builds are much faster. + +--- + +## Step 4: Attach to an Entity + +1. Return to **Untold Engine Studio** +2. Select any entity in your scene (a cube or platform) +3. In the Inspector panel, click **Add Component** β†’ **Script Component** +4. In the Asset Browser, find `MoveAnEntity.uscript` under Scripts/Generated +5. Double click on the `.uscript`. The script will be linked to the entity +--- + +## Step 5: Test It! + +1. Click **Play** in the toolbar +2. Watch the entity move steadily along the +Z axis +3. Check the **Console** view to confirm: + ``` + MoveAnEntity ready + ``` +4. Click **Stop** to exit Play mode + +--- + +## Understanding the Output + +- The entity moves every frame toward +Z +- Speed comes from `moveSpeed`; direction comes from `direction` +- To stop movement, disable the Script Component or set speed to 0 + +⚠️ **Placement Note:** If the entity is already near a boundary, lower the speed or adjust the start position to avoid moving out of view. + +--- + +## Modify and Experiment + +Try these changes to learn more: + +### Move Upward Instead +```swift +.setVariable("direction", to: simd_float3(x: 0, y: 1, z: 0)) +``` + +### Slow or Fast Motion +```swift +.setVariable("moveSpeed", to: 0.01) // slower +// or +.setVariable("moveSpeed", to: 0.15) // faster +``` + +### Pause After a Distance +```swift +s.onUpdate() + .getProperty(.position, as: "currentPos") + .ifGreater("currentPos.z", than: 10.0) { n in + n.setVariable("moveSpeed", to: 0.0) // stop after z > 10 + } + .scaleVec3("direction", by: "moveSpeed", as: "step") + .addVec3("currentPos", "step", as: "nextPos") + .setProperty(.position, toVariable: "nextPos") +``` + +After making changes: +1. In Xcode, press `Cmd+R` to rerun the GenerateScripts target and regenerate the scripts (`Cmd+B` optional first). +2. Click **Reload** in the Script Component Inspector +3. Test in Play mode + +--- + +## What You Learned + +βœ… Creating a movement script in Untold Engine Studio +βœ… Using variables for speed and direction +βœ… Updating position every frame with `onUpdate()` +βœ… Building and attaching scripts to entities +βœ… Testing motion in Play mode + +--- + diff --git a/website/versioned_docs/version-0.7.1/03-Game Development/04-Scripting-Experimental/03-Tutorials/01_Transform/02_RotateAnEntity.md b/website/versioned_docs/version-0.7.1/03-Game Development/04-Scripting-Experimental/03-Tutorials/01_Transform/02_RotateAnEntity.md new file mode 100644 index 00000000..7e92ccbb --- /dev/null +++ b/website/versioned_docs/version-0.7.1/03-Game Development/04-Scripting-Experimental/03-Tutorials/01_Transform/02_RotateAnEntity.md @@ -0,0 +1,239 @@ +# Rotate an Entity - Continuous Spin + +**What you'll learn:** +- Rotating entities with `rotateTo()` inside `onUpdate()` +- Tracking angles with script variables +- Choosing rotation axes with `simd_float3` +- Building USC scripts entirely in Xcode + +**Time:** ~7 minutes + +**Prerequisites:** +- Untold Engine Studio open with any entity selected (a cube makes rotation easy to see) +- Access to Xcode via **Scripts: Open in Xcode** (toolbar button) + +--- + +## What We're Building + +A rotation script that: +1. Spins an entity around a chosen axis +2. Uses a variable to track the current angle +3. Lets you adjust spin speed without rewriting the script + +--- + +## Step 1: Create the Script + +1. Open **Untold Engine Studio** +2. In the toolbar, click **Scripts: Open in Xcode** (blue button) +3. Click the `+` button and enter the script name: `RotateAnEntity` +4. Click OK, then Xcode opens the Scripts package + +When the script is created: +- The source file is added to your project +- You edit the script in Xcode + +You'll see a template like this: + +```swift +import Foundation +import UntoldEngine +import simd + +extension GenerateScripts { + static func generateRotateAnEntity(to dir: URL) { + // Write your script here + } +} +``` +> This script is added to GenerateScripts, which is the entry point the engine uses to discover and generate USC scripts. + +--- + + +## Step 2: Wire Up the Script + +⚠️ IMPORTANT MANUAL STEP + +The editor created your script file, but you need to tell the build system to generate it. + +1. Click Scripts: Open in Xcode (blue button in toolbar) +2. In Xcode, open GenerateScripts.swift +3. Add your script to the main() function: + +```swift +@main +struct GenerateScripts { + static func main() { + print("πŸ”¨ Generating USC scripts...") + + let outputDir = URL(fileURLWithPath: "Generated/") + try? FileManager.default.createDirectory(at: outputDir, withIntermediateDirectories: true) + + // Add this line: + generateRotateAnEntity(to: outputDir) + + print("βœ… All scripts generated in Generated/") + } +} +``` + +Now run the GenerateScripts target (`Cmd+R`) to generate the `.uscript` files. + + +MPORTANT NOTES: +The function name (e.g. generateRotateAnEntity) MUST match the tutorial’s script +Only adjust that single line per tutorial +The structure, wording, and warning must remain consistent across all documents + +--- + + +## Step 3: Write the Script + +Replace the function with this complete script: + +```swift +import Foundation +import UntoldEngine +import simd + +extension GenerateScripts { + static func generateRotateAnEntity(to dir: URL) { + let script = buildScript(name: "RotateAnEntity") { s in + // Runs once when the entity starts + s.onStart() + .setVariable("rotationSpeed", to: 2.0) // degrees per frame + .setVariable("currentAngle", to: 0.0) + .setVariable("axis", to: simd_float3(x: 0, y: 1, z: 0)) + .log("RotateAnEntity ready") + + // Runs every frame + s.onUpdate() + .addFloat("currentAngle", "rotationSpeed", as: "nextAngle") + .setVariable("currentAngle", to: .variableRef("nextAngle")) + .rotateTo( + degrees: .variableRef("currentAngle"), + axis: simd_float3(x:0,y:1,z:0) + ) + } + + let outputPath = dir.appendingPathComponent("RotateAnEntity.uscript") + try? saveUSCScript(script, to: outputPath) + print(" βœ… RotateAnEntity.uscript") + } +} +``` + +### Understanding the Code + +**`rotationSpeed`** - Controls how much to rotate each frame +- Higher values spin faster +- Change this without touching the rest of the script + +**`currentAngle`** - Tracks total rotation +- Prevents drift and keeps rotation smooth + +**`axis`** - A `simd_float3` defining which way to spin +- `(0, 1, 0)` spins around Y (like a turntable) +- `(1, 0, 0)` spins forward/backward +- `(0, 0, 1)` spins left/right + +**`rotateTo()`** - Sets an absolute rotation +- Uses the stored angle each frame +- Cleanly resets if you set `currentAngle` back to `0` + +--- + +## Step 4: Build the Script + +1. In Xcode, press `Cmd+R` to run the GenerateScripts target and generate the `.uscript` (optional: `Cmd+B` first to verify the build). +2. Watch for the Xcode run output: + +``` +πŸ”¨ Generating USC scripts... + βœ… RotateAnEntity.uscript +βœ… All scripts generated in Generated/ +``` + +**First build?** May take 30-60 seconds to download engine dependencies. Subsequent builds are much faster. + +--- + +## Step 5: Attach to an Entity + +1. Return to **Untold Engine Studio** +2. Select the entity you want to rotate +3. In the Inspector panel, click **Add Component** β†’ **Script Component** +4. In the Asset Browser, find `RotateAnEntity.uscript` under Scripts/Generated +5. Double click on the `.uscript`. The script will be linked to the entity +--- + +## Step 6: Test It! + +1. Click **Play** in the toolbar +2. Watch the entity spin around the Y-axis +3. Open the **Console** view to confirm: + ``` + RotateAnEntity ready + ``` +4. Click **Stop** to exit Play mode + +--- + +## Understanding the Output + +- The entity rotates smoothly using `rotationSpeed` degrees per frame +- Changing `axis` changes the spin direction without new code +- Resetting `currentAngle` to `0` realigns the entity instantly + +⚠️ **Consistency Note:** Large `rotationSpeed` values can cause visible jumps. Increase gradually for smoother motion. + +--- + +## Modify and Experiment + +Try these changes to learn more: + +### Rotate with `rotateBy()` +```swift +s.onUpdate() + .rotateBy( + degrees: 1.0, + axis: simd_float3(x: 0, y: 1, z: 0) + ) +``` + +### Spin on Multiple Axes +```swift +.setVariable("axis", to: simd_float3(x: 1, y: 1, z: 0)) // diagonal spin +``` + +### Start Facing a Specific Direction +```swift +s.onStart() + .rotateTo( + degrees: 45.0, + axis: simd_float3(x: 0, y: 1, z: 0) + ) + .setVariable("currentAngle", to: 45.0) +``` + +After making changes: +1. In Xcode, press `Cmd+R` to rerun the GenerateScripts target and regenerate the scripts (`Cmd+B` optional first). +2. Click **Reload** in the Script Component Inspector +3. Test in Play mode + +--- + +## What You Learned + +βœ… Creating a rotation script in Untold Engine Studio +βœ… Tracking angles with script variables +βœ… Rotating entities around any axis +βœ… Building and attaching scripts to entities +βœ… Testing rotations in Play mode + +--- + diff --git a/website/versioned_docs/version-0.7.1/03-Game Development/04-Scripting-Experimental/03-Tutorials/02_Input/01_KeyboardMovement.md b/website/versioned_docs/version-0.7.1/03-Game Development/04-Scripting-Experimental/03-Tutorials/02_Input/01_KeyboardMovement.md new file mode 100644 index 00000000..20a9f580 --- /dev/null +++ b/website/versioned_docs/version-0.7.1/03-Game Development/04-Scripting-Experimental/03-Tutorials/02_Input/01_KeyboardMovement.md @@ -0,0 +1,268 @@ +# Keyboard Movement - WASD Motion + +**What you'll learn:** +- Reading keyboard input with `getKeyState()` +- Building movement vectors from multiple keys +- Combining input with `setProperty(.position)` +- Iterating quickly with Xcode builds + +**Time:** ~10 minutes + +**Prerequisites:** +- Untold Engine Studio open with an entity you want to move +- Access to Xcode via **Scripts: Open in Xcode** (toolbar button) + +--- + +## What We're Building + +A simple controller that: +1. Moves with **WASD** +2. Supports diagonal movement by combining keys +3. Uses a configurable speed variable + +--- + +## Step 1: Create the Script + +1. Open **Untold Engine Studio** +2. In the toolbar, click **Scripts: Open in Xcode** (blue button) +3. Click the `+` button and enter the script name: `KeyboardMovement` +4. Click OK, then Xcode opens the Scripts package + +When the script is created: +- The source file is added to your project +- You edit the script in Xcode + +You'll see a template like this: + +```swift +import Foundation +import UntoldEngine +import simd + +extension GenerateScripts { + static func generateKeyboardMovement(to dir: URL) { + // Write your script here + } +} +``` +> This script is added to GenerateScripts, which is the entry point the engine uses to discover and generate USC scripts. + +--- + + +## Step 2: Wire Up the Script + +⚠️ IMPORTANT MANUAL STEP + +The editor created your script file, but you need to tell the build system to generate it. + +1. Click Scripts: Open in Xcode (blue button in toolbar) +2. In Xcode, open GenerateScripts.swift +3. Add your script to the main() function: + +```swift +@main +struct GenerateScripts { + static func main() { + print("πŸ”¨ Generating USC scripts...") + + let outputDir = URL(fileURLWithPath: "Generated/") + try? FileManager.default.createDirectory(at: outputDir, withIntermediateDirectories: true) + + // Add this line: + generateKeyboardMovement(to: outputDir) + + print("βœ… All scripts generated in Generated/") + } +} +``` + +Now run the GenerateScripts target (`Cmd+R`) to generate the `.uscript` files. + + +MPORTANT NOTES: +The function name (e.g. generateKeyboardMovement) MUST match the tutorial’s script +Only adjust that single line per tutorial +The structure, wording, and warning must remain consistent across all documents + +--- + + +## Step 3: Write the Script + +Replace the function with this complete script: + +```swift +import Foundation +import UntoldEngine +import simd + +extension GenerateScripts { + static func generateKeyboardMovement(to dir: URL) { + let script = buildScript(name: "KeyboardMovement") { s in + // Runs once when the entity starts + s.onStart() + .setVariable("moveSpeed", to: 0.2) // units per frame + .setVariable("forward", to: simd_float3(x: 0, y: 0, z: 1)) + .setVariable("right", to: simd_float3(x: 1, y: 0, z: 0)) + .log("KeyboardMovement ready") + + // Runs every frame + s.onUpdate() + .getProperty(.position, as: "currentPos") + .setVariable("offset", to: simd_float3(x: 0, y: 0, z: 0)) + + // Read keys + .getKeyState("w", as: "wPressed") + .getKeyState("s", as: "sPressed") + .getKeyState("a", as: "aPressed") + .getKeyState("d", as: "dPressed") + + // Forward (W) + .ifEqual("wPressed", to: true) { n in + n.scaleVec3("forward", by: "moveSpeed", as: "step") + n.addVec3("offset", "step", as: "offset") + } + // Backward (S) + .ifEqual("sPressed", to: true) { n in + n.scaleVec3("forward", by: "moveSpeed", as: "stepForward") + n.scaleVec3("stepForward", literal: -1.0, as: "stepBack") + n.addVec3("offset", "stepBack", as: "offset") + } + // Left (A) + .ifEqual("aPressed", to: true) { n in + n.scaleVec3("right", by: "moveSpeed", as: "stepRight") + n.scaleVec3("stepRight", literal: -1.0, as: "stepLeft") + n.addVec3("offset", "stepLeft", as: "offset") + } + // Right (D) + .ifEqual("dPressed", to: true) { n in + n.scaleVec3("right", by: "moveSpeed", as: "stepRight") + n.addVec3("offset", "stepRight", as: "offset") + } + + // Apply movement + .addVec3("currentPos", "offset", as: "nextPos") + .setProperty(.position, toVariable: "nextPos") + } + + let outputPath = dir.appendingPathComponent("KeyboardMovement.uscript") + try? saveUSCScript(script, to: outputPath) + print(" βœ… KeyboardMovement.uscript") + } +} +``` + +### Understanding the Code + +**`getKeyState()`** - Reads whether a key is pressed this frame +- Lowercase strings like `"w"` match keyboard keys + +**Offset pattern** - Build movement from multiple keys +- Start with `offset = (0,0,0)` +- Add forward/back and left/right contributions +- Apply once per frame + +**`moveSpeed` variable** - Single place to tune speed +- Scale any direction by this value (or its negative) + +**Position-based control** - Directly updates `.position` +- No physics required for this example +- Works consistently every frame + +--- + +## Step 4: Build the Script + +1. In Xcode, press `Cmd+R` to run the GenerateScripts target and generate the `.uscript` (optional: `Cmd+B` first to verify the build). +2. Watch for the Xcode run output: + +``` +πŸ”¨ Generating USC scripts... + βœ… KeyboardMovement.uscript +βœ… All scripts generated in Generated/ +``` + +**First build?** May take 30-60 seconds to download engine dependencies. Subsequent builds are much faster. + +--- + +## Step 5: Attach to an Entity + +1. Return to **Untold Engine Studio** +2. Select the entity you want to move +3. In the Inspector panel, click **Add Component** β†’ **Script Component** +4. In the Asset Browser, find `KeyboardMovement.uscript` under Scripts/Generated +5. Double click on the `.uscript`. The script will be linked to the entity +--- + +## Step 5: Test It! + +1. Click **Play** in the toolbar +2. Press `W`, `A`, `S`, `D` to move the entity +3. Hold multiple keys (e.g., `W` + `D`) to move diagonally +4. Click **Stop** to exit Play mode + +--- + +## Understanding the Output + +- Movement updates every frame based on current key states +- Diagonal movement combines offset vectors naturally +- Changing `moveSpeed` updates all directions at once + +⚠️ **Scene Scale Note:** If motion is too fast for your scene scale, drop `moveSpeed` to `0.05` and retest. + +--- + +## Modify and Experiment + +Try these changes to learn more: + +### Adjustable Sprint +```swift +.getKeyState("lshift", as: "shiftPressed") +.setVariable("currentSpeed", to: 0.15) +.ifEqual("shiftPressed", to: true) { n in + n.setVariable("currentSpeed", to: 0.4) +} +// Use currentSpeed instead of moveSpeed when scaling direction +``` + +### Vertical Movement +```swift +.getKeyState("space", as: "upPressed") +.getKeyState("c", as: "downPressed") +.ifEqual("upPressed", to: true) { n in + n.addVec3("offset", simd_float3(x: 0, y: 0.2, z: 0), as: "offset") +} +.ifEqual("downPressed", to: true) { n in + n.addVec3("offset", simd_float3(x: 0, y: -0.2, z: 0), as: "offset") +} +``` + +### Normalize Diagonals +```swift +.normalizeVec3("offset", as: "offset") +.scaleVec3("offset", by: "moveSpeed", as: "offset") +``` + +After making changes: +1. In Xcode, press `Cmd+R` to rerun the GenerateScripts target and regenerate the scripts (`Cmd+B` optional first). +2. Click **Reload** in the Script Component Inspector +3. Test in Play mode + +--- + +## What You Learned + +βœ… Reading keyboard input with `getKeyState()` +βœ… Building movement vectors from multiple keys +βœ… Updating position every frame with `onUpdate()` +βœ… Building and attaching scripts to entities +βœ… Testing interactive input in Play mode + +--- + diff --git a/website/versioned_docs/version-0.7.1/03-Game Development/04-Scripting-Experimental/03-Tutorials/03_Animation/01_PlayAnimation.md b/website/versioned_docs/version-0.7.1/03-Game Development/04-Scripting-Experimental/03-Tutorials/03_Animation/01_PlayAnimation.md new file mode 100644 index 00000000..6542e635 --- /dev/null +++ b/website/versioned_docs/version-0.7.1/03-Game Development/04-Scripting-Experimental/03-Tutorials/03_Animation/01_PlayAnimation.md @@ -0,0 +1,241 @@ +# Play an Animation - Single Clip + +**What you'll learn:** +- Playing an animation clip with `playAnimation()` +- Looping vs. one-shot playback +- Using variables to track the current clip +- Building and testing animations from Xcode + +**Time:** ~8 minutes + +**Prerequisites:** +- Untold Engine Studio open with an entity that has an **Animation Component** and at least one loaded clip (e.g., `idle`) +- Access to Xcode via **Scripts: Open in Xcode** (toolbar button) + +--- + +## What We're Building + +A simple animation script that: +1. Plays a single clip on start +2. Loops it continuously +3. Shows how to trigger a one-shot clip on demand + +--- + +## Step 1: Create the Script + +1. Open **Untold Engine Studio** +2. In the toolbar, click **Scripts: Open in Xcode** (blue button) +3. Click the `+` button and enter the script name: `PlayAnimation` +4. Click OK, then Xcode opens the Scripts package + +When the script is created: +- The source file is added to your project +- You edit the script in Xcode + +You'll see a template like this: + +```swift +import Foundation +import UntoldEngine +import simd + +extension GenerateScripts { + static func generatePlayAnimation(to dir: URL) { + // Write your script here + } +} +``` +> This script is added to GenerateScripts, which is the entry point the engine uses to discover and generate USC scripts. + +--- + + +## Step 2: Wire Up the Script + +⚠️ IMPORTANT MANUAL STEP + +The editor created your script file, but you need to tell the build system to generate it. + +1. Click Scripts: Open in Xcode (blue button in toolbar) +2. In Xcode, open GenerateScripts.swift +3. Add your script to the main() function: + +```swift +@main +struct GenerateScripts { + static func main() { + print("πŸ”¨ Generating USC scripts...") + + let outputDir = URL(fileURLWithPath: "Generated/") + try? FileManager.default.createDirectory(at: outputDir, withIntermediateDirectories: true) + + // Add this line: + generatePlayAnimation(to: outputDir) + + print("βœ… All scripts generated in Generated/") + } +} +``` + +Now run the GenerateScripts target (`Cmd+R`) to generate the `.uscript` files. + + +MPORTANT NOTES: +The function name (e.g. generatePlayAnimation) MUST match the tutorial’s script +Only adjust that single line per tutorial +The structure, wording, and warning must remain consistent across all documents + +--- + + +## Step 3: Write the Script + +Replace the function with this complete script: + +```swift +import Foundation +import UntoldEngine +import simd + +extension GenerateScripts { + static func generatePlayAnimation(to dir: URL) { + let script = buildScript(name: "PlayAnimation") { s in + // Runs once when the entity starts + s.onStart() + .setVariable("idleClip", to: "idle") // Must match the clip name in the Animation Component + .setVariable("currentClip", to: "idle") + .playAnimation("idle", loop: true) + .log("Playing idle animation (looping)") + + // Optional: trigger a one-shot animation with Space + s.onUpdate() + .getKeyState("space", as: "spacePressed") + .ifEqual("spacePressed", to: true) { n in + n.playAnimation("jump", loop: false) // Replace with your one-shot clip name + n.setVariable("currentClip", to: "jump") + n.log("Playing jump animation (one-shot)") + } + } + + let outputPath = dir.appendingPathComponent("PlayAnimation.uscript") + try? saveUSCScript(script, to: outputPath) + print(" βœ… PlayAnimation.uscript") + } +} +``` + +### Understanding the Code + +**`playAnimation(name, loop:)`** - Starts an animation by name +- `loop: true` repeats continuously (great for idle or walk) +- `loop: false` plays once (great for jump or attacks) + +**Clip names** - Must match exactly what you see in the Animation Component +- Case-sensitive +- If you rename a clip in the editor, update the script too + +**`currentClip` variable** - Tracks what is playing +- Useful when adding more conditions later + +--- + +## Step 4: Build the Script + +1. In Xcode, press `Cmd+R` to run the GenerateScripts target and generate the `.uscript` (optional: `Cmd+B` first to verify the build). +2. Watch for the Xcode run output: + +``` +πŸ”¨ Generating USC scripts... + βœ… PlayAnimation.uscript +βœ… All scripts generated in Generated/ +``` + +**First build?** May take 30-60 seconds to download engine dependencies. Subsequent builds are much faster. + +--- + +## Step 5: Attach to an Entity + +1. Return to **Untold Engine Studio** +2. Select an entity that has an **Animation Component** +3. In the Asset Library, double click on the animations you want to add to the entity, i.e. `idle` and `jump` +4. In the Inspector panel, click **Add Component** β†’ **Script Component** +5. In the Asset Browser, find `PlayAnimation.uscript` under Scripts/Generated +6. Double click on the `.uscript`. The script will be linked to the entity +--- + +## Step 6: Test It! + +1. Click **Play** in the toolbar +2. The entity should immediately play the `idle` clip on loop +3. Tap **Space** to trigger the one-shot clip (e.g., `jump`) +4. Click **Stop** to exit Play mode + +--- + +## Understanding the Output + +- Looping clip runs continuously until another clip interrupts it +- One-shot clip plays once; if you need to return to idle automatically, add a timer or state check +- If nothing plays, verify the clip names match the Animation Component exactly + +⚠️ **Asset Note:** The script only calls animations that already exist on the entity’s Animation Component. Ensure clips are loaded and named correctly. + +--- + +## Modify and Experiment + +Try these changes to learn more: + +### Start with a Different Clip +```swift +.setVariable("idleClip", to: "breathing_idle") +.playAnimation("breathing_idle", loop: true) +``` + +### Return to Idle After One-Shot +```swift +s.onUpdate() + .getKeyState("space", as: "spacePressed") + .ifEqual("spacePressed", to: true) { n in + n.playAnimation("jump", loop: false) + n.setVariable("currentClip", to: "jump") + } + // Simple timer to return to idle after ~1 second + .setVariable("returnTimer", to: 60.0) // frames at ~60 FPS + .ifGreater("returnTimer", than: 0.0) { n in + n.addFloat("returnTimer", literal: -1.0, as: "returnTimer") + } + .ifEqual("returnTimer", to: 0.0) { n in + n.playAnimation("idle", loop: true) + n.setVariable("currentClip", to: "idle") + } +``` + +### Add a Stop Button +```swift +.getKeyState("p", as: "pPressed") +.ifEqual("pPressed", to: true) { n in + n.stopAnimation() + n.log("Animation stopped") +} +``` + +After making changes: +1. In Xcode, press `Cmd+R` to rerun the GenerateScripts target and regenerate the scripts (`Cmd+B` optional first). +2. Click **Reload** in the Script Component Inspector +3. Test in Play mode + +--- + +## What You Learned + +βœ… Playing animation clips with `playAnimation()` +βœ… Looping vs. one-shot playback +βœ… Tracking the current clip with script variables +βœ… Building, attaching, and testing animation scripts + +--- + diff --git a/website/versioned_docs/version-0.7.1/03-Game Development/04-Scripting-Experimental/03-Tutorials/03_Animation/02_AnimationStateSwitch.md b/website/versioned_docs/version-0.7.1/03-Game Development/04-Scripting-Experimental/03-Tutorials/03_Animation/02_AnimationStateSwitch.md new file mode 100644 index 00000000..a43e42f1 --- /dev/null +++ b/website/versioned_docs/version-0.7.1/03-Game Development/04-Scripting-Experimental/03-Tutorials/03_Animation/02_AnimationStateSwitch.md @@ -0,0 +1,265 @@ +# Animation State Switch - Idle to Walk + +**What you'll learn:** +- Switching animations based on input +- Tracking current state to avoid restart flicker +- Using `playAnimation()` for looped clips +- Building and testing animations from Xcode + +**Time:** ~10 minutes + +**Prerequisites:** +- Untold Engine Studio open with an entity that has an **Animation Component** and two clips loaded (e.g., `idle`, `walk`) +- Access to Xcode via **Scripts: Open in Xcode** (toolbar button) + +--- + +## What We're Building + +An animation controller that: +1. Plays `idle` when no movement keys are pressed +2. Switches to `walk` when any WASD key is pressed +3. Only changes clips when the state actually changes + +--- + +## Step 1: Create the Script + +1. Open **Untold Engine Studio** +2. In the toolbar, click **Scripts: Open in Xcode** (blue button) +3. Click the `+` button and enter the script name: `AnimationStateSwitch` +4. Click OK, then Xcode opens the Scripts package + +When the script is created: +- The source file is added to your project +- You edit the script in Xcode + +You'll see a template like this: + +```swift +import Foundation +import UntoldEngine +import simd + +extension GenerateScripts { + static func generateAnimationStateSwitch(to dir: URL) { + // Write your script here + } +} +``` +> This script is added to GenerateScripts, which is the entry point the engine uses to discover and generate USC scripts. + +--- + + +## Step 2: Wire Up the Script + +⚠️ IMPORTANT MANUAL STEP + +The editor created your script file, but you need to tell the build system to generate it. + +1. Click Scripts: Open in Xcode (blue button in toolbar) +2. In Xcode, open GenerateScripts.swift +3. Add your script to the main() function: + +```swift +@main +struct GenerateScripts { + static func main() { + print("πŸ”¨ Generating USC scripts...") + + let outputDir = URL(fileURLWithPath: "Generated/") + try? FileManager.default.createDirectory(at: outputDir, withIntermediateDirectories: true) + + // Add this line: + generateAnimationStateSwitch(to: outputDir) + + print("βœ… All scripts generated in Generated/") + } +} +``` + +Now run the GenerateScripts target (`Cmd+R`) to generate the `.uscript` files. + + +MPORTANT NOTES: +The function name (e.g. generateAnimationStateSwitch) MUST match the tutorial’s script +Only adjust that single line per tutorial +The structure, wording, and warning must remain consistent across all documents + +--- + + +## Step 3: Write the Script + +Replace the function with this complete script: + +```swift +import Foundation +import UntoldEngine +import simd + +extension GenerateScripts { + static func generateAnimationStateSwitch(to dir: URL) { + let script = buildScript(name: "AnimationStateSwitch") { s in + // Runs once when the entity starts + s.onStart() + .setVariable("currentAnim", to: "idle") + .playAnimation("idle", loop: true) + .log("AnimationStateSwitch ready - idle playing") + + // Runs every frame + s.onUpdate() + // Read movement keys + .getKeyState("w", as: "wPressed") + .getKeyState("a", as: "aPressed") + .getKeyState("s", as: "sPressed") + .getKeyState("d", as: "dPressed") + + // Determine if moving + .setVariable("isMoving", to: false) + .ifEqual("wPressed", to: true) { n in n.setVariable("isMoving", to: true) } + .ifEqual("aPressed", to: true) { n in n.setVariable("isMoving", to: true) } + .ifEqual("sPressed", to: true) { n in n.setVariable("isMoving", to: true) } + .ifEqual("dPressed", to: true) { n in n.setVariable("isMoving", to: true) } + + // Switch to walk when moving + .ifEqual("isMoving", to: true) { n in + n.ifCondition(lhs: .variableRef("currentAnim"), .notEqual, rhs: .string("walk")) { change in + change.playAnimation("walk", loop: true) + change.setVariable("currentAnim", to: "walk") + change.log("Switched to walk") + } + } + + // Switch back to idle when not moving + .ifEqual("isMoving", to: false) { n in + n.ifCondition(lhs: .variableRef("currentAnim"), .notEqual, rhs: .string("idle")) { change in + change.playAnimation("idle", loop: true) + change.setVariable("currentAnim", to: "idle") + change.log("Switched to idle") + } + } + } + + let outputPath = dir.appendingPathComponent("AnimationStateSwitch.uscript") + try? saveUSCScript(script, to: outputPath) + print(" βœ… AnimationStateSwitch.uscript") + } +} +``` + +### Understanding the Code + +**State tracking** - `currentAnim` stores what is playing +- Prevents restarting the same clip every frame +- Eliminates flicker when staying in the same state + +**Input gating** - `isMoving` becomes true if any WASD key is pressed +- One boolean drives all animation switching + +**`playAnimation()` only on change** - Uses a condition to switch +- Keeps transitions smooth +- Avoids repeating the same clip call + +--- + +## Step 4: Build the Script + +1. In Xcode, press `Cmd+R` to run the GenerateScripts target and generate the `.uscript` (optional: `Cmd+B` first to verify the build). +2. Watch for the Xcode run output: + +``` +πŸ”¨ Generating USC scripts... + βœ… AnimationStateSwitch.uscript +βœ… All scripts generated in Generated/ +``` + +**First build?** May take 30-60 seconds to download engine dependencies. Subsequent builds are much faster. + +--- + +## Step 5: Attach to an Entity + +1. Return to **Untold Engine Studio** +2. Add an entity to the scene. +3. In the Asset Library, double click on the animations you want to add to the entity, such as `idle` and `walk` +3. In the Inspector panel, click **Add Component** β†’ **Script Component** +4. In the Asset Browser, find `AnimationStateSwitch.uscript` under Scripts/Generated +5. Double click on the `.uscript`. The script will be linked to the entity +--- + +## Step 5: Test It! + +1. Click **Play** in the toolbar +2. With no input, the entity plays `idle` +3. Press any of `W`, `A`, `S`, `D` to switch to `walk` +4. Release the keys to return to `idle` +5. Click **Stop** to exit Play mode + +--- + +## Understanding the Output + +- Idle is the default and fallback state +- Walk plays only while movement keys are down +- No flicker because the script checks before switching + +⚠️ **Name Matching:** Clip names are case-sensitive. If your clips are named differently (e.g., `Idle`, `Walking`), update the script strings. + +--- + +## Modify and Experiment + +Try these changes to learn more: + +### Add a Run State with Shift +```swift +.getKeyState("lshift", as: "shiftPressed") +.ifEqual("shiftPressed", to: true) { n in + n.ifEqual("isMoving", to: true) { run in + run.ifCondition(lhs: .variableRef("currentAnim"), .notEqual, rhs: .string("run")) { change in + change.playAnimation("run", loop: true) + change.setVariable("currentAnim", to: "run") + } + } +} +``` + +### Add a Jump One-Shot +```swift +.getKeyState("space", as: "jumpPressed") +.ifEqual("jumpPressed", to: true) { n in + n.playAnimation("jump", loop: false) + n.setVariable("currentAnim", to: "jump") +} +``` + +### Reset to Idle After a Delay +```swift +.setVariable("idleTimer", to: 30.0) // half-second at ~60 FPS +.ifEqual("isMoving", to: false) { n in + n.addFloat("idleTimer", literal: -1.0, as: "idleTimer") + n.ifEqual("idleTimer", to: 0.0) { back in + back.playAnimation("idle", loop: true) + back.setVariable("currentAnim", to: "idle") + } +} +``` + +After making changes: +1. In Xcode, press `Cmd+R` to rerun the GenerateScripts target and regenerate the scripts (`Cmd+B` optional first). +2. Click **Reload** in the Script Component Inspector +3. Test in Play mode + +--- + +## What You Learned + +βœ… Switching animations based on player input +βœ… Tracking the current clip to avoid restart flicker +βœ… Using looped clips for idle/walk states +βœ… Building, attaching, and testing animation controllers + +--- + diff --git a/website/versioned_docs/version-0.7.1/03-Game Development/04-Scripting-Experimental/03-Tutorials/04_Physics/01_ApplyForce.md b/website/versioned_docs/version-0.7.1/03-Game Development/04-Scripting-Experimental/03-Tutorials/04_Physics/01_ApplyForce.md new file mode 100644 index 00000000..ca5ba9cc --- /dev/null +++ b/website/versioned_docs/version-0.7.1/03-Game Development/04-Scripting-Experimental/03-Tutorials/04_Physics/01_ApplyForce.md @@ -0,0 +1,232 @@ +# Apply Force - Physics Push + +**What you'll learn:** +- Applying world-space forces with `applyWorldForce()` +- Controlling force direction and magnitude with variables +- Testing physics-driven motion from Xcode builds +- Building scripts in Xcode before playtesting + +**Time:** ~8 minutes + +**Prerequisites:** +- Untold Engine Studio open with an entity that has a Physics/Kinetic component +- Access to Xcode via **Scripts: Open in Xcode** (toolbar button) + +--- + +## What We're Building + +A physics push that: +1. Applies a continuous upward force +2. Uses variables for direction and magnitude +3. Shows how to tweak force strength between builds + +--- + +## Step 1: Create the Script + +1. Open **Untold Engine Studio** +2. In the toolbar, click **Scripts: Open in Xcode** (blue button) +3. Click the `+` button and enter the script name: `ApplyForce` +4. Click OK, then Xcode opens the Scripts package + +When the script is created: +- The source file is added to your project +- You edit the script in Xcode + +You'll see a template like this: + +```swift +import Foundation +import UntoldEngine +import simd + +extension GenerateScripts { + static func generateApplyForce(to dir: URL) { + // Write your script here + } +} +``` +> This script is added to GenerateScripts, which is the entry point the engine uses to discover and generate USC scripts. + +--- + + +## Step 2: Wire Up the Script + +⚠️ IMPORTANT MANUAL STEP + +The editor created your script file, but you need to tell the build system to generate it. + +1. Click Scripts: Open in Xcode (blue button in toolbar) +2. In Xcode, open GenerateScripts.swift +3. Add your script to the main() function: + +```swift +@main +struct GenerateScripts { + static func main() { + print("πŸ”¨ Generating USC scripts...") + + let outputDir = URL(fileURLWithPath: "Generated/") + try? FileManager.default.createDirectory(at: outputDir, withIntermediateDirectories: true) + + // Add this line: + generateApplyForce(to: outputDir) + + print("βœ… All scripts generated in Generated/") + } +} +``` + +Now run the GenerateScripts target (`Cmd+R`) to generate the `.uscript` files. + + +MPORTANT NOTES: +The function name (e.g. generateApplyForce) MUST match the tutorial’s script +Only adjust that single line per tutorial +The structure, wording, and warning must remain consistent across all documents + +--- + + +## Step 3: Write the Script + +Replace the function with this complete script: + +```swift +import Foundation +import UntoldEngine +import simd + +extension GenerateScripts { + static func generateApplyForce(to dir: URL) { + let script = buildScript(name: "ApplyForce") { s in + // Runs once when the entity starts + s.onStart() + .setVariable("forceDir", to: simd_float3(x: 0, y: 1, z: 0)) + .setVariable("forceMagnitude", to: 0.2) + .log("ApplyForce ready") + + // Runs every frame + s.onUpdate() + .applyWorldForce( + direction: .variableRef("forceDir"), + magnitude: .variableRef("forceMagnitude") + ) + } + + let outputPath = dir.appendingPathComponent("ApplyForce.uscript") + try? saveUSCScript(script, to: outputPath) + print(" βœ… ApplyForce.uscript") + } +} +``` + +### Understanding the Code + +**`forceDir` + `forceMagnitude`** - Set the push direction and strength +- `(0, 1, 0)` pushes upward +- Reduce magnitude for gentle movement; increase for stronger lifts + +**`applyWorldForce()`** - Applies a force in world space +- Requires a Physics/Kinetic component on the entity +- Accumulates over time, so the object accelerates while the force runs + +**`onUpdate()`** - Applies force every frame +- Stop the push by setting magnitude to 0 or disabling the Script Component + +--- + +## Step 4: Build the Script + +1. In Xcode, press `Cmd+R` to run the GenerateScripts target and generate the `.uscript` (optional: `Cmd+B` first to verify the build). +2. Watch for the Xcode run output: + +``` +πŸ”¨ Generating USC scripts... + βœ… ApplyForce.uscript +βœ… All scripts generated in Generated/ +``` + +**First build?** May take 30-60 seconds to download engine dependencies. Subsequent builds are much faster. + +--- + +## Step 5: Attach to an Entity + +1. Return to **Untold Engine Studio** +2. Add an entity to the scene. +3. In the Inspector panel, click **Add Component** β†’ **Kinetic Component** +4. In the Inspector panel, click **Add Component** β†’ **Script Component** +5. In the Asset Browser, find `ApplyForce.uscript` under Scripts/Generated +6. Double click on the `.uscript`. The script will be linked to the entity +--- + +## Step 6: Test It! + +1. Click **Play** in the toolbar +2. Watch the entity accelerate upward as the force is applied each frame +3. Open the **Console** view to confirm: + ``` + ApplyForce ready + ``` +4. Click **Stop** to exit Play mode + +--- + +## Understanding the Output + +- The entity accelerates while the force is active +- Direction is world-based; change `forceDir` to push sideways +- Lower gravity or heavier masses will change how fast it moves + +⚠️ **Physics Note:** Forces accumulate; if the object moves too fast, lower `forceMagnitude` or apply the force only on certain frames. + +--- + +## Modify and Experiment + +Try these changes to learn more: + +### Short Burst Instead of Continuous Force +```swift +s.onStart() + .setVariable("framesLeft", to: 60) // apply for 1 second at ~60 FPS + +s.onUpdate() + .ifGreater("framesLeft", than: 0) { n in + n.applyWorldForce(direction: .variableRef("forceDir"), + magnitude: .variableRef("forceMagnitude")) + n.addFloat("framesLeft", literal: -1, as: "framesLeft") + } +``` + +### Sideways Push +```swift +.setVariable("forceDir", to: simd_float3(x: 1, y: 0, z: 0)) // push along +X +``` + +### Switch to Impulse +```swift +s.onUpdate() + .applyLinearImpulse(direction: .variableRef("forceDir"), + magnitude: .variableRef("forceMagnitude")) +``` + +After making changes: +1. In Xcode, press `Cmd+R` to rerun the GenerateScripts target and regenerate the scripts (`Cmd+B` optional first). +2. Click **Reload** in the Script Component Inspector +3. Test in Play mode + +--- + +## What You Learned + +βœ… Applying forces to physics-enabled entities +βœ… Controlling direction and magnitude with variables +βœ… Building and attaching physics scripts in the editor +βœ… Testing physics responses in Play mode + +--- + diff --git a/website/versioned_docs/version-0.7.1/04-Engine Development/01-Overview.md b/website/versioned_docs/version-0.7.1/04-Engine Development/01-Overview.md new file mode 100644 index 00000000..670971d7 --- /dev/null +++ b/website/versioned_docs/version-0.7.1/04-Engine Development/01-Overview.md @@ -0,0 +1,94 @@ +--- +id: engine-overview +title: Overview +sidebar_position: 1 +--- + +# Overview + +This section is for **engine developers and contributors** who want to work on the core of Untold Engine. + +It assumes familiarity with engine concepts and systems programming. + +--- + +## What You’ll Work On + +In this section, you’ll learn about: +- The engine architecture +- The ECS design +- Rendering systems +- Simulation and update flow +- Platform-specific layers + +This is where the **core behavior** of Untold Engine lives. + +--- + +## Installing the Engine for Development + +Engine development requires installing Untold Engine via the command line and working from source. + +Detailed installation steps are provided here: + + +1. Clone the Repository + +```bash +git clone https://github.com/untoldengine/UntoldEngine +cd UntoldEngine +open Package.swift +``` + +**How to Run** +1. Select the **DemoGame** scheme. +2. Download the [Demo Game Assets v1.0](https://github.com/untoldengine/UntoldEngine-Assets/releases/tag/v1) and place them in your Desktop folder. +3. Set the Scheme to **Demo Game**. Then set **My Mac** as the target device and hit **Run**. +4. Use **WASD** keys to move the player around. + + +![DemoGame](../images/demogame-noeditor.png) + + +You do not need Untold Engine Studio to work on the engine itself. + +--- + +## Engine Architecture + +Untold Engine is built around: +- A clear ECS model +- Explicit system update order +- Minimal hidden state +- Platform-specific rendering backends + +The architecture favors **clarity over abstraction**. + +A high-level breakdown is provided in: + +> **Engine Development β†’ Architecture** + +--- + +## Rendering and Systems + +Rendering, physics, and other systems are implemented as: +- Independent modules +- Explicit update stages +- Predictable data flow + +Rendering is designed to expose low-level control while remaining approachable. + +--- + +## Who This Section Is Not For + +This section is **not** intended for: +- Game developers writing gameplay scripts +- Users who only want to use the editor +- Beginners to engine development + +If you want to make a game, see: + +> **Game Development β†’ Overview** + diff --git a/website/versioned_docs/version-0.7.1/04-Engine Development/02-Architecture/Internals.md b/website/versioned_docs/version-0.7.1/04-Engine Development/02-Architecture/Internals.md new file mode 100644 index 00000000..0d5c089d --- /dev/null +++ b/website/versioned_docs/version-0.7.1/04-Engine Development/02-Architecture/Internals.md @@ -0,0 +1,57 @@ +--- +id: engine-architecture +title: Engine Architecture Internals +sidebar_position: 2 +--- + +# Untold Engine Architecture Internals + +You’re looking under the hood of Untold Engine. This is how the pieces fit together, why we picked them, and where contributors can plug in. + +## The Big Idea: ECS at the Core +Untold Engine is deliberately **ECS-first**: +- **Entities** are just 64-bit IDs (index + version) managed in `Scenes.swift` with pooling, masks, and tombstones. +- **Components** are plain data (no logic) in `ECS/Components.swift`: transforms, render payloads, physics state, animation sets, lights, scripts, etc. Components live in type-specific pools keyed by component ID. +- **Systems** are the behavior layer in `Sources/UntoldEngine/Systems/`. Each system queries entities by component mask and runs every frame (or in fixed steps for physics). Examples: Transform, Scenegraph, Rendering, Physics, Animation, Input, Culling, Loading, Lighting, Shadow, Steering, USC scripting. + +Why this matters: contributors can add data (components) and behavior (systems) without rewriting the core. Keep components dumb, keep systems focused, and everything stays modular and testable. + +## Frame Flow +`UntoldRenderer.runFrame` orchestrates each tick: +1) **Simulation prep**: delta time, scene graph traversal, input handling. +2) **Gameplay & scripting**: AnimationSystem, USCSystem, custom game update callbacks. +3) **Physics**: fixed-timestep accumulator, gravity/drag/forces, Runge–Kutta integration (collision/contact still open for contribution). +4) **Culling & rendering**: frustum cull, Gaussian depth/sort, build render graph, execute passes, present. + +## Rendering Stack +- **Entry point**: `UntoldRenderer` (MTKView delegate) sets up device/queue, loads metallib, initializes buffers, and drives the frame loop. Platform variants exist for macOS/iOS, visionOS (XR), and AR. +- **Render graph**: `RenderingSystem.swift` builds a dependency graph (environment/grid/AR base β†’ shadow β†’ GBuffer/model β†’ gaussian β†’ post β†’ precomp) and executes via `RenderPasses` + `PipelineManager`. +- **Pipelines**: Render and compute pipelines live in `Renderer/Pipelines/`. Gaussian splats run dedicated compute passes (depth + bitonic sort) before their render pass. + +## Physics & Motion +- **Data**: `PhysicsComponents` and `KineticComponent` store mass, velocity/angular velocity, drag, inertia tensors, forces, moments, and pause flags. +- **Runtime**: `updatePhysicsSystem` accumulates forces/moments, applies gravity/drag, and integrates with Runge–Kutta. Collision/contact resolution is intentionally minimal todayβ€”prime territory for contributions. +- **Steering & Animation**: SteeringSystem and AnimationSystem run alongside physics to drive motion and skeletal playback. + +## Scripting (USC) +- **Data**: `ScriptComponent` holds one or more scripts plus file paths (backward compatible with single-script scenes). +- **Runtime**: `USCSystem` ticks the `USCInterpreter` each frame. Actions are registered in `USCScripting.swift` (math helpers, etc.). Extend the DSL by adding actions to `USCActionRegistry`. + +## Scenes, Assets, Resources +- **Scene authoring**: Swift DSL in `Scenes/Builder/` (`Node`/`SceneBuilder`) plus `SceneSerializer` for persistence. +- **Meshes/animations**: abstractions in `Mesh/` and `Skeleton`; resources created through MTK allocators/loaders. +- **Bundled bits**: Prebuilt metallibs per platform and demo resources under `Resources/`. + +## Platform Layers +- **XR (visionOS)**: `UntoldEngineXR` ties CompositorServices/ARKit to the core renderer entry. +- **AR (iOS)**: `UntoldEngineAR` wraps MTKView + ARKit for AR mode. +- **Sample**: `Sources/DemoGame` shows system registration and simple gameplay loops. + +## Where Contributors Can Make Impact +- **Collision/contact & determinism**: Build the missing collision stack, material/friction models, and deterministic stepping for netcode/replays. +- **Render passes/pipelines**: Add or refine passes in the render graph (effects, optimizations, new pipelines). +- **USC actions & API surface**: Expose new engine capabilities to scripts; add higher-level gameplay helpers. +- **Debug/observability**: Better logging sinks, on-screen overlays, profiling, and error surfacing. +- **New systems/components**: AI utilities, networking hooks, gameplay-specific dataβ€”keep components data-only and register them for serialization where relevant. + +When proposing big changes, consider ECS storage impact, system ordering, and cross-platform Metal constraints. Align early with maintainers for collision/determinism/netcode-sized work so we keep the architecture cohesive. diff --git a/website/versioned_docs/version-0.7.1/04-Engine Development/02-Architecture/Overview.md b/website/versioned_docs/version-0.7.1/04-Engine Development/02-Architecture/Overview.md new file mode 100644 index 00000000..ae33b9cd --- /dev/null +++ b/website/versioned_docs/version-0.7.1/04-Engine Development/02-Architecture/Overview.md @@ -0,0 +1,191 @@ +--- +id: engine-architecture overview +title: Architecture Overview +sidebar_position: 1 +--- + +# Engine Architecture + +This document describes the **high-level architecture** of Untold Engine. + +It is intended for developers who want to understand how the engine is structured *before* working on individual subsystems such as rendering, physics, or scripting. + +This page focuses on **concepts and responsibilities**, not file layouts or implementation details. + +--- + +## Architectural Philosophy + +Untold Engine is designed with a small set of guiding principles: + +- **Clarity over abstraction** + Systems should be understandable without deep indirection. + +- **Explicit execution order** + Engine behavior is deterministic and visible. + +- **Data-oriented design** + Data and behavior are separated cleanly. + +- **Composable systems** + New systems can be added without destabilizing existing ones. + +The architecture favors *learnability and debuggability* over convenience shortcuts. + +--- + +## High-Level Structure + +At a conceptual level, Untold Engine is organized into the following layers: + +Gameplay (USC Scripts) +↓ +Engine Systems +↓ +Core Runtime +↓ +Platform & Rendering Backends + +Each layer has a single responsibility and communicates downward through well-defined interfaces. + +--- + +## Core Runtime + +The **core runtime** is responsible for: + +- Entity and component storage +- System registration and ordering +- Scene lifecycle management +- Global engine state +- Frame orchestration + +The runtime does **not** contain gameplay logic, editor logic, or platform-specific behavior. + +Its role is to provide a **stable execution environment** for all systems. + +--- + +## Entity–Component–System (ECS) + +Untold Engine uses an **Entity–Component–System (ECS)** architecture. + +### Entities +- Lightweight identifiers +- Contain no data or behavior +- Used to associate components + +### Components +- Plain data containers +- Represent state (transform, physics, rendering, scripting, etc.) +- Do not contain logic + +### Systems +- Contain all behavior +- Operate on entities matching specific component sets +- Are executed in an explicit order + +This separation keeps systems focused and minimizes hidden dependencies. + +--- + +## System Execution Model + +Systems are executed as part of a well-defined update flow. + +A simplified frame looks like this: + +1. Input collection +2. Simulation and gameplay systems +3. USC script evaluation +4. Physics integration +5. Culling and render preparation +6. Rendering and presentation + +There is no implicit or callback-driven execution. + +Each system declares: +- When it runs +- What data it reads +- What data it writes + +--- + +## Rendering Architecture + +Rendering in Untold Engine is **explicit and staged**. + +Key characteristics: +- Clear separation between simulation and rendering +- Explicit render passes +- Minimal global render state +- Platform-specific backends hidden behind a thin abstraction + +Rendering is treated as a system, not a special case. + +--- + +## Platform Abstraction + +Untold Engine supports multiple platforms through **thin platform layers**. + +These layers handle: +- Window and surface management +- Input sources +- Graphics API integration +- Platform lifecycle events + +The core engine remains platform-agnostic. + +--- + +## USC Integration + +USC (Untold Script Core) is layered on top of the engine. + +- The engine owns the update loop +- USC expresses gameplay intent +- Scripts interact with engine state through a constrained API + +USC does not bypass engine systems. + +This ensures predictable behavior and keeps ownership of state clear. + +--- + +## Editor Relationship + +The Untold Editor is built **on top of the same engine runtime** used by games. + +- Editor features are implemented as engine clients +- Editor-only systems are isolated +- Play mode uses the same execution path as runtime builds + +This minimizes editor-only behavior and keeps debugging consistent. + +--- + +## Design Tradeoffs + +Untold Engine intentionally avoids: + +- Hidden execution order +- Large global managers +- Overly generic abstractions +- Implicit engine magic + +These tradeoffs prioritize: +- Predictability +- Debuggability +- Long-term maintainability + +--- + +## Architecture in Practice + +This document provides the conceptual overview. + +For implementation-level details, see: + +Engine Development β†’ Architecture β†’ Engine internals + diff --git a/website/versioned_docs/version-0.7.1/04-Engine Development/02-Architecture/_category.json b/website/versioned_docs/version-0.7.1/04-Engine Development/02-Architecture/_category.json new file mode 100644 index 00000000..b32af10f --- /dev/null +++ b/website/versioned_docs/version-0.7.1/04-Engine Development/02-Architecture/_category.json @@ -0,0 +1 @@ +{ "label": "Architecture", "position": 2, "collapsed": false } diff --git a/website/versioned_docs/version-0.7.1/04-Engine Development/03-Engine Systems/UsingAnimationSystem.md b/website/versioned_docs/version-0.7.1/04-Engine Development/03-Engine Systems/UsingAnimationSystem.md new file mode 100644 index 00000000..e0530058 --- /dev/null +++ b/website/versioned_docs/version-0.7.1/04-Engine Development/03-Engine Systems/UsingAnimationSystem.md @@ -0,0 +1,78 @@ +--- +id: animationsystem +title: Animation System +sidebar_position: 4 +--- + +# Enabling Animation in Untold Engine + +The Untold Engine simplifies adding animations to your rigged models, allowing for lifelike movement and dynamic interactions. This guide will show you how to set up and play animations for a rigged model. + + +## How to Enable Animation + +### Step 1: Create an Entity + +Start by creating an entity to represent your animated model. + +```swift +let redPlayer = createEntity() +``` + +--- + +### Step 2: Link the Mesh to the Entity + +Load your rigged model’s .usdc file and link it to the entity. This step ensures the entity is visually represented in the scene. + +```swift +setEntityMesh(entityId: redPlayer, filename: "redplayer", withExtension: "usdc", flip: false) +``` +>>> Note: If your model renders with the wrong orientation, set the flip parameter to false. + +--- + +### Step 3: Load the Animation +Load the animation data for your model by providing the animation .usdc file and a name to reference the animation later. + +```swift +setEntityAnimations(entityId: redPlayer, filename: "running", withExtension: "usdc", name: "running") +``` + +--- + +### Step 4: Set the Animation to play + +Trigger the animation by referencing its name. This will set the animation to play on the entity. + +```swift +changeAnimation(entityId: redPlayer, name: "running") +``` + +--- + +### Step 5. Pause the animation (Optional) + +To pause the current animation, simply call the following function. The animation component will be paused for the current entity. + +```swift +pauseAnimationComponent(entityId: redPlayer, isPaused: true) +``` + +--- + +### Running the Animation + +Once the animation is set up: + +1. Run the project: Your model will appear in the game window. +2. Click on "Play" to enter Game Mode: +- The model will play the assigned animation in real time. + +--- + +## Tips and Best Practices + +- Name Animations Clearly: Use descriptive names like "running" or "jumping" to make it easier to manage multiple animations. +- Debug Orientation Issues: If the model’s animation appears misaligned, revisit the flip parameter or check the model’s export settings. +- Combine Animations: For complex behaviors, load multiple animations (e.g., walking, idle, jumping) and switch between them dynamically. diff --git a/website/versioned_docs/version-0.7.1/04-Engine Development/03-Engine Systems/UsingAsyncLoading.md b/website/versioned_docs/version-0.7.1/04-Engine Development/03-Engine Systems/UsingAsyncLoading.md new file mode 100644 index 00000000..a9831058 --- /dev/null +++ b/website/versioned_docs/version-0.7.1/04-Engine Development/03-Engine Systems/UsingAsyncLoading.md @@ -0,0 +1,319 @@ +# Async USDZ Loading System - Usage Guide + +## Overview + +The async loading system allows you to load USDZ files with many models without blocking the main thread. The engine remains responsive during loading, and you can track progress for UI feedback. + +## Features + +βœ… **Non-blocking loading** - Engine continues running while assets load +βœ… **Progress tracking** - Monitor loading progress per entity or globally +βœ… **Fallback meshes** - Automatically loads a cube if loading fails +βœ… **Backward compatible** - Old synchronous APIs still work + +--- + +## Basic Usage + +### Load Entity Mesh Asynchronously + +```swift +// Create entity +let entityId = createEntity() + +// Load mesh asynchronously (fire and forget) +setEntityMeshAsync( + entityId: entityId, + filename: "large_model", + withExtension: "usdz" +) + +// Engine continues running - mesh appears when loaded +``` + +### With Completion Callback + +```swift +let entityId = createEntity() + +setEntityMeshAsync( + entityId: entityId, + filename: "large_model", + withExtension: "usdz" +) { success in + if success { + print("βœ… Model loaded successfully!") + } else { + print("❌ Failed to load - fallback cube used") + } +} +``` + +### Load Entire Scene Asynchronously + +```swift +loadSceneAsync( + filename: "complex_scene", + withExtension: "usdz" +) { success in + if success { + print("Scene loaded with all entities") + } +} +``` + +--- + +## Progress Tracking + +### Check if Assets are Loading + +```swift +Task { + let isLoading = await AssetLoadingState.shared.isLoadingAny() + if isLoading { + print("Assets are currently loading...") + } +} +``` + +### Get Loading Count + +```swift +Task { + let count = await AssetLoadingState.shared.loadingCount() + print("Loading \(count) entities") +} +``` + +### Get Detailed Progress + +```swift +Task { + let (current, total) = await AssetLoadingState.shared.totalProgress() + let percentage = Float(current) / Float(total) * 100 + print("Progress: \(percentage)% (\(current)/\(total) meshes)") +} +``` + +### Get Progress Summary String + +```swift +Task { + let summary = await AssetLoadingState.shared.loadingSummary() + print(summary) // "Loading large_model.usdz: 5/20 meshes" +} +``` + +### Track Specific Entity + +```swift +Task { + if let progress = await AssetLoadingState.shared.getProgress(for: entityId) { + print("\(progress.filename): \(progress.currentMesh)/\(progress.totalMeshes)") + print("Percentage: \(progress.percentage * 100)%") + } +} +``` + +--- + +## Untold Editor Integration + +### Display Loading UI + +```swift +// In your editor's update loop or UI +Task { + if await AssetLoadingState.shared.isLoadingAny() { + let summary = await AssetLoadingState.shared.loadingSummary() + // Show loading indicator with summary text + showLoadingIndicator(text: summary) + } else { + // Hide loading indicator + hideLoadingIndicator() + } +} +``` + +### Progress Bar Example + +```swift +Task { + let allProgress = await AssetLoadingState.shared.getAllProgress() + + for progress in allProgress { + let percentage = progress.percentage * 100 + print("πŸ“¦ \(progress.filename): \(Int(percentage))%") + + // Update UI progress bar + updateProgressBar( + id: progress.entityId, + filename: progress.filename, + percentage: percentage + ) + } +} +``` + +--- + +## Error Handling + +### Automatic Fallback + +When async loading fails, a fallback cube mesh is automatically loaded: + +```swift +setEntityMeshAsync( + entityId: entityId, + filename: "missing_file", + withExtension: "usdz" +) { success in + if !success { + // Entity now has a cube mesh as fallback + print("Loaded fallback cube") + } +} +``` + +### Manual Error Handling + +```swift +setEntityMeshAsync( + entityId: entityId, + filename: "model", + withExtension: "usdz" +) { success in + if !success { + // Handle error - entity has fallback cube + showErrorDialog("Failed to load model.usdz") + + // Optionally destroy entity or retry + // destroyEntity(entityId: entityId) + } +} +``` + +--- + +## Backward Compatibility + +The old synchronous APIs still work unchanged: + +```swift +// Old way (blocks main thread) +setEntityMesh( + entityId: entityId, + filename: "model", + withExtension: "usdz" +) + +// New way (non-blocking) +setEntityMeshAsync( + entityId: entityId, + filename: "model", + withExtension: "usdz" +) +``` + +--- + +## Advanced Usage + +### Loading Multiple Models + +```swift +let entity1 = createEntity() +let entity2 = createEntity() +let entity3 = createEntity() + +// All three load in parallel without blocking +setEntityMeshAsync(entityId: entity1, filename: "model1", withExtension: "usdz") +setEntityMeshAsync(entityId: entity2, filename: "model2", withExtension: "usdz") +setEntityMeshAsync(entityId: entity3, filename: "model3", withExtension: "usdz") + +// Track total progress +Task { + while await AssetLoadingState.shared.isLoadingAny() { + let summary = await AssetLoadingState.shared.loadingSummary() + print(summary) + try? await Task.sleep(nanoseconds: 100_000_000) // 0.1 seconds + } + print("All models loaded!") +} +``` + +### Coordinate System Conversion + +```swift +setEntityMeshAsync( + entityId: entityId, + filename: "blender_model", + withExtension: "usdz", + coordinateConversion: .forceZUpToYUp +) +``` + +--- + +## Implementation Details + +### What Runs on Background Thread + +- Reading USDZ file from disk +- Parsing MDL data structures +- Loading texture data +- Applying coordinate transformations + +### What Runs on Main Thread + +- Creating Metal resources (MTKMesh, MTLTexture) +- Registering ECS components +- Updating entity transforms +- Creating fallback meshes on error + +### Thread Safety + +All `AssetLoadingState` operations are thread-safe via Swift's actor model. You can safely query loading state from any thread. + +--- + +## Performance Tips + +1. **Prefer async for large files** (>20 models or >50MB) +2. **Use sync for small files** (1-5 models, <10MB) - less overhead +3. **Batch loads together** - loading multiple files in parallel is efficient +4. **Monitor progress** - use for UI feedback during long loads + +--- + +## Migration Guide + +### Before (Blocking) + +```swift +func loadGameAssets() { + let entity = createEntity() + setEntityMesh(entityId: entity, filename: "huge_scene", withExtension: "usdz") + // Engine was frozen here ❌ +} +``` + +### After (Non-blocking) + +```swift +func loadGameAssets() { + let entity = createEntity() + setEntityMeshAsync(entityId: entity, filename: "huge_scene", withExtension: "usdz") { + success in + if success { + print("Scene ready!") + } + } + // Engine continues running βœ… +} +``` + +--- + diff --git a/website/versioned_docs/version-0.7.1/04-Engine Development/03-Engine Systems/UsingGaussianSystem.md b/website/versioned_docs/version-0.7.1/04-Engine Development/03-Engine Systems/UsingGaussianSystem.md new file mode 100644 index 00000000..63d87e5a --- /dev/null +++ b/website/versioned_docs/version-0.7.1/04-Engine Development/03-Engine Systems/UsingGaussianSystem.md @@ -0,0 +1,47 @@ +--- +id: gaussiansystem +title: Gaussian System +sidebar_position: 3 +--- + +# Enabling Gaussian System in Untold Engine + +The Gaussian System in the Untold Engine is responsible for rendering Gaussian Splatting models. It enables you to visualize high-quality 3D reconstructions created from photogrammetry or neural rendering techniques, providing a modern approach to displaying complex 3D scenes. + +## How to Enable the Gaussian System + +### Step 1: Create an Entity + +Start by creating an entity that represents your Gaussian Splat object. + +```swift +let myEntity = createEntity() +``` +--- + +### Step 2: Link a Gaussian Splat to the Entity + +To display a Gaussian Splat model, load its .ply file and link it to the entity using setEntityGaussian. + +```swift +setEntityGaussian(entityId: myEntity, filename: "splat", withExtension: "ply") +``` + +Parameters: + +- entityId: The ID of the entity created earlier. +- filename: The name of the .ply file (without the extension). +- withExtension: The file extension, typically "ply". + +> Note: The Gaussian System renders point cloud data stored in the .ply format. Ensure your Gaussian Splat file is properly formatted and contains the necessary attributes (position, color, opacity, scale, rotation). + +--- + +### Running the Gaussian System + +Once everything is set up: + +1. Run the project. +2. Your Gaussian Splat model will appear in the game window. +3. If the model is not visible or appears incorrect, revisit the file path and format to ensure everything is loaded correctly. + diff --git a/website/versioned_docs/version-0.7.1/04-Engine Development/03-Engine Systems/UsingInputSystem.md b/website/versioned_docs/version-0.7.1/04-Engine Development/03-Engine Systems/UsingInputSystem.md new file mode 100644 index 00000000..4c994f85 --- /dev/null +++ b/website/versioned_docs/version-0.7.1/04-Engine Development/03-Engine Systems/UsingInputSystem.md @@ -0,0 +1,84 @@ +--- +id: inputsystem +title: Input System +sidebar_position: 6 +--- + +# Using the Input System in Untold Engine + +The Input System in the Untold Engine allows you to detect user inputs, such as keystrokes and mouse movements, to control entities and interact with the game. This guide will explain how to use the Input System effectively. + + +## How to Use the Input System + +### Step 1: Detect Keystrokes +To detect if a specific key is pressed, use the keyState object from the Input System. + +Example: Detecting the 'W' Key + +```swift +if inputSystem.keyState.wPressed == true { + // Your code here +} +``` +You can use the same logic for other keys like A, S, and D: + +```swift +if inputSystem.keyState.aPressed == true { + // Move left +} + +if inputSystem.keyState.sPressed == true { + // Move backward +} + +if inputSystem.keyState.dPressed == true { + // Move right +} +``` + +###Step 2: Using Input to Control Entities + +Here’s an example function that moves a car entity based on keyboard inputs: + +```swift +func moveCar(entityId: EntityID, dt: Float) { + // Ensure we are in game mode + if gameMode == false { + return + } + + var position = simd_float3(0.0, 0.0, 0.0) + + // Move forward + if inputSystem.keyState.wPressed == true { + position.z += 1.0 * dt + } + + // Move backward + if inputSystem.keyState.sPressed == true { + position.z -= 1.0 * dt + } + + // Move left + if inputSystem.keyState.aPressed == true { + position.x -= 1.0 * dt + } + + // Move right + if inputSystem.keyState.dPressed == true { + position.x += 1.0 * dt + } + + // Apply the translation to the entity + translateTo(entityId: entityId, position: position) +} +``` + +--- + +## Tips and Best Practices +- Debouncing: If you want to execute an action only once per key press, track the key's previous state to avoid repeated triggers. +- Game Mode Check: Always ensure the game is in the appropriate mode (e.g., Game Mode) before processing inputs. +- Smooth Movement: Use dt (delta time) to ensure frame-rate-independent movement. + diff --git a/website/versioned_docs/version-0.7.1/04-Engine Development/03-Engine Systems/UsingLightingSystem.md b/website/versioned_docs/version-0.7.1/04-Engine Development/03-Engine Systems/UsingLightingSystem.md new file mode 100644 index 00000000..51ad9176 --- /dev/null +++ b/website/versioned_docs/version-0.7.1/04-Engine Development/03-Engine Systems/UsingLightingSystem.md @@ -0,0 +1,48 @@ +--- +id: lightinsystem +title: Lighting System +sidebar_position: 3 +--- + +# Enabling the Lighting System in Untold Engine + +The Lighting System lets you add illumination to your scenes using common real-time light types. Under the hood it wires up the required ECS components, provides an editor-friendly visual handle, and tags the light so the renderer can pick it up. + +--- + +## Creating Each Light Type +### Directional Light + +Use for sunlight or distant key lights. Orientation (rotation) defines its direction. + +```swift +let sun = createEntity() +createDirLight(entityId: sun) +``` +### Point Light + +Omni light that radiates equally in all directions from a position. + +```swift +let bulb = createEntity() +createPointLight(entityId: bulb) +``` + +### Spot Light + +Cone-shaped light with a position and direction. + +```swift +let spot = createEntity() +createSpotLight(entityId: spot) +``` + +### Area Light + +Rect/area emitter used to mimic panels/windows; position and orientation matter. + +```swift +let panel = createEntity() +createAreaLight(entityId: panel) +``` + diff --git a/website/versioned_docs/version-0.7.1/04-Engine Development/03-Engine Systems/UsingPhysicsSystem.md b/website/versioned_docs/version-0.7.1/04-Engine Development/03-Engine Systems/UsingPhysicsSystem.md new file mode 100644 index 00000000..fd8e53d9 --- /dev/null +++ b/website/versioned_docs/version-0.7.1/04-Engine Development/03-Engine Systems/UsingPhysicsSystem.md @@ -0,0 +1,100 @@ +--- +id: physicssystem +title: Physics System +sidebar_position: 5 +--- + +# Enabling Physics System in Untold Engine + +The physics system in the Untold Engine enables realistic simulations such as gravity, forces, and dynamic interactions. While collision support is still under development, this guide will walk you through adding physics to your entities. + +## How to Enable Physics + +### Step 1: Create an Entity + +Start by creating an entity that represents the object you want to add physics to. + +```swift +let redPlayer = createEntity() +``` +--- + +### Step 2: Link a Mesh to the Entity +Next, load your model’s mesh file and link it to the entity. This step visually represents your entity in the scene. + +```swift +setEntityMesh(entityId: redPlayer, filename: "redplayer", withExtension: "usdc") +``` +--- + +### Step 3: Enable Physics on the Entity +Activate the physics simulation for your entity using the setEntityKinetics function. This function prepares the entity for movement and dynamic interaction. + +```swift +setEntityKinetics(entityId: redPlayer) +``` +--- + +#### Step 4: Configure Physics Properties +You can customize the entity’s physics behavior by defining its mass and gravity scale: + +- Mass: Determines the force needed to move the object. Heavier objects require more force. +- Gravity Scale: Controls how strongly gravity affects the entity (default is 0.0). + +```swift +setMass(entityId: redPlayer, mass: 0.5) +setGravityScale(entityId: redPlayer, gravityScale: 1.0) +``` +--- + +#### Step 5: Apply Forces (Optional) +You can apply a custom force to the entity for dynamic movement. This is useful for simulating actions like jumps or pushes. + +```swift +applyForce(entityId: redPlayer, force: simd_float3(0.0, 0.0, 5.0)) +``` + +> Note: Forces are applied per frame. To avoid unintended behavior, only apply forces when necessary. + +--- + +#### Step 6: Use the Steering System +For advanced movement behaviors, leverage the Steering System to steer entities toward or away from targets. This system automatically calculates the required forces. + +Example: Steering Toward a Position + +```swift +steerTo(entityId: redPlayer, targetPosition: simd_float3(0.0, 0.0, 5.0), maxSpeed: 2.0, deltaTime: deltaTime) +``` + +--- + +#### Additional Steering Functions + +The Steering System includes other useful behaviors, such as: + +- steerAway() +- steerPursuit() +- followPath() + +These functions simplify complex movement patterns, making them easy to implement. + +--- + +### What Happens Behind the Scenes? + +1. Physics Simulation: +- Entities with physics enabled are updated each frame to account for forces, gravity, and other dynamic factors. +- Transformations are recalculated based on velocity, acceleration, and forces applied. +2. Realistic Motion: +- The system ensures consistent, physics-based movement without manual updates to the transform. + +--- + +### Running the Simulation +Once you've set up physics, run the project to see it in action: + +1. Launch the project: Your model will appear in the game window. +2. Press "P" to enter Game Mode: +- Gravity and forces will affect the entity. +- If forces are applied, you’ll see dynamic motion in real time. diff --git a/website/versioned_docs/version-0.7.1/04-Engine Development/03-Engine Systems/UsingRegistrationSystem.md b/website/versioned_docs/version-0.7.1/04-Engine Development/03-Engine Systems/UsingRegistrationSystem.md new file mode 100644 index 00000000..0e9925a5 --- /dev/null +++ b/website/versioned_docs/version-0.7.1/04-Engine Development/03-Engine Systems/UsingRegistrationSystem.md @@ -0,0 +1,60 @@ +--- +id: registrationsystem +title: Registration System +sidebar_position: 2 +--- + +# Using the Registration System in Untold Engine + +The Registration System in the Untold Engine is an integral part of its Entity-Component-System (ECS) architecture. It provides core functionalities to manage entities and components, such as: + +- Creating and destroying entities. +- Registering components to entities. +- Setting up helper functions for other systems by configuring necessary components. + + +## How to Use the Registration System + +### Step 1: Create an Entity + +Entities represent objects in the scene. Use the createEntity() function to create a new entity. + +```swift +let entity = createEntity() +``` + +--- + +### Step 2: Register Components + +Components define the behavior or attributes of an entity. Use registerComponent to add a component to an entity. + +```swift +registerComponent(entityId: entity, componentType: RenderComponent.self) +``` +Example: + +When you load a mesh for rendering, the system automatically registers the required components: + +```swift +setEntityMesh(entityId: entity, filename: "model", withExtension: "usdz") +``` + +This function: + +- Loads the mesh from the specified .usdc file. +- Associates the mesh with the entity. +- Registers default components like RenderComponent and TransformComponent. + +--- + +### Step 3: Destroy an Entity + +To remove an entity and its components from the scene, use destroyEntity. + +```swift +destroyEntity(entityId: entity) +``` + +This ensures the entity is properly removed from all systems. + diff --git a/website/versioned_docs/version-0.7.1/04-Engine Development/03-Engine Systems/UsingRenderingSystem.md b/website/versioned_docs/version-0.7.1/04-Engine Development/03-Engine Systems/UsingRenderingSystem.md new file mode 100644 index 00000000..c42d5ae1 --- /dev/null +++ b/website/versioned_docs/version-0.7.1/04-Engine Development/03-Engine Systems/UsingRenderingSystem.md @@ -0,0 +1,77 @@ +--- +id: renderingsystem +title: Rendering System +sidebar_position: 2 +--- + +# Enabling Rendering System in Untold Engine + +The Rendering System in the Untold Engine is responsible for displaying your models on the screen. It supports advanced features such as Physically Based Rendering (PBR) for realistic visuals and multiple types of lights to illuminate your scenes. + +## How to Enable the Rendering System + +### Step 1: Create an Entity + +Start by creating an entity that represents your 3D object. + +```swift +let entity = createEntity() +``` +--- + +### Step 2: Link a Mesh to the Entity + +To display a model, load its .usdc file and link it to the entity using setEntityMesh. + +```swift +setEntityMesh(entityId: entity, filename: "entity", withExtension: "usdz") +``` + +Parameters: + +- entityId: The ID of the entity created earlier. +- filename: The name of the .usdc file (without the extension). +- withExtension: The file extension, typically "usdz". + +> Note: If PBR textures (e.g., albedo, normal, roughness, metallic maps) are included, the rendering system will automatically use the appropriate PBR shader to render the model with realistic lighting and material properties. + +--- + +### Running the Rendering System + +Once everything is set up: + +1. Run the project. +2. Your model will appear in the game window, illuminated by the configured lights. +3. If the model is not visible or appears flat, revisit the lighting and texture setup to ensure everything is loaded correctly. + +--- + +## Common Issues and Fixes + +#### Issue: My Model Isn’t Visible! + +- Cause: The scene lacks a light source. +- Solution: Add a directional or point light as shown above. Lighting is required to render objects visibly. + +#### Issue: Model Appears Flat or Dull + +- Cause: PBR textures are missing or not linked properly. +- Solution: Ensure the .usdc file includes the correct PBR textures, and verify their paths during the loading process. + +#### Debugging Tip: + +- Log the addition of lights and entities to verify the scene setup. +- Ensure the position of the point light is within the visible range of the camera and the objects it is meant to illuminate. + +--- + +### Tips and Best Practices + +- Combine Light Types: Use directional lights for overall scene lighting and point lights for localized effects. +- Use PBR Materials: Provide high-quality PBR textures for realistic rendering. +- Position Lights Intelligently: Place point lights strategically to highlight key areas without excessive overlap. + +--- + + diff --git a/website/versioned_docs/version-0.7.1/04-Engine Development/03-Engine Systems/UsingScenegraph.md b/website/versioned_docs/version-0.7.1/04-Engine Development/03-Engine Systems/UsingScenegraph.md new file mode 100644 index 00000000..6dbdcb6a --- /dev/null +++ b/website/versioned_docs/version-0.7.1/04-Engine Development/03-Engine Systems/UsingScenegraph.md @@ -0,0 +1,40 @@ +--- +id: scenegraphsystem +title: Scenegraph System +sidebar_position: 8 +--- + +# Adding Parent-Child Relationships in Untold Engine + +The Untold Engine includes a Scene Graph data structure, designed to manage hierarchical transformations efficiently. This enables parent-child relationships between entities, where a child's transformation (position, rotation, scale) is relative to its parent. For example, a car's wheels (children) move and rotate relative to the car body (parent). + +## Why Use Parent-Child Relationships? + +Parent-child relationships are useful when you want multiple entities to move or transform together. When a parent entity changes its position, rotation, or scale, its child entities inherit those changes automatically. This is ideal for scenarios like: + +- A car (parent) and its wheels (children) +- A robot (parent) with movable arms and legs (children) +- A group of objects that should remain in a fixed configuration relative to each other + +## Assigning Parent-Child Relationships + +To assign a parent to an entity, use the setParent function. This function establishes a hierarchical relationship between the specified entities. + +```swift +// Create child and parent entities +let childEntity = createEntity() +let parentEntity = createEntity() + +// Set parent-child relationship +setParent(childId: childEntity, parentId: parentEntity) +``` + +## What Happens Behind the Scenes? + +1. Transformation Inheritance: +- Once the relationship is established, any transformation applied to the parent entity (e.g., movement, rotation) will automatically affect the child entity. +- The child’s transformation is expressed relative to the parent. + +2. Independent Local Transformations: +- While the child inherits the parent's transformations, it can also have its own independent local transformations, such as offset positions or rotations relative to the parent. + diff --git a/website/versioned_docs/version-0.7.1/04-Engine Development/03-Engine Systems/UsingSteeringSystem.md b/website/versioned_docs/version-0.7.1/04-Engine Development/03-Engine Systems/UsingSteeringSystem.md new file mode 100644 index 00000000..05c8465b --- /dev/null +++ b/website/versioned_docs/version-0.7.1/04-Engine Development/03-Engine Systems/UsingSteeringSystem.md @@ -0,0 +1,107 @@ +--- +id: steeringsystem +title: Steering System +sidebar_position: 7 +--- + +# Using the Steering System in Untold Engine + +The Steering System in the Untold Engine enables entities to move dynamically and intelligently within the scene. It provides both low-level steering behaviors (e.g., seek, flee, arrive) for granular control and high-level behaviors (e.g., steerTo, steerAway, followPath) that integrate seamlessly with the Physics System. + +## Why Use the Steering System? + +The Steering System is essential for creating dynamic and realistic movement for entities, such as: + +- A character chasing a target. +- An enemy avoiding obstacles. +- A vehicle following a predefined path. + +The high-level behaviors are recommended because they are designed to work closely with the Physics System, simplifying implementation while maintaining smooth motion. + +--- + +## How to Use the Steering System + +Examples: + +1. Steer Toward a Target Position: + +```swift +steerSeek(entityId: entity, targetPosition: targetPosition, maxSpeed: 5.0, deltaTime: 0.016) +``` +2. Steer Away from a Threat: + +```swift +steerFlee(entityId: entity, threatPosition: threatPosition, maxSpeed: 5.0, deltaTime: 0.016) +``` + +3. Follow a Path: Guide an entity along a series of waypoints. + +```swift +steerFollowPath(entityId: entity, path: waypoints, maxSpeed: 5.0, deltaTime: 0.016) +``` +4. Pursue a Moving Target: + +```swift +steerPursuit(entityId: chaserEntity, targetEntity: targetEntity, maxSpeed: 5.0, deltaTime: 0.016) +``` + +5. Avoid Obstacles: + +```swift +steerAvoidObstacles(entityId: entity, obstacles: obstacleEntities, avoidanceRadius: 2.0, maxSpeed: 5.0, deltaTime: 0.016) +``` + +6. Steer Toward a Target Position (with Arrive): + +```swift +steerArrive(entityId: entity, targetPosition: targetPosition, maxSpeed: 5.0, deltaTime: 0.016) +``` + +7. Steer using WASD keys + +```swift +steerWithWASD(entityId: entity, maxSpeed: 5.0, deltaTime: 0.016) +``` + +--- + +## What Happens Behind the Scenes? + +1. Low-Level Behaviors: +- Calculate desired velocity based on the target or threat position. +- Generate steering forces by comparing desired velocity with current velocity. +2. High-Level Behaviors: +- Use low-level behaviors to calculate steering adjustments. +- Apply these forces to the entity’s physics system for smooth, realistic motion. +- Align the entity’s orientation to face its movement direction. +3. Physics Integration: +- Forces are applied through the Physics System, ensuring that movement respects mass, velocity, and acceleration. + +--- + +## Tips and Best Practices +- Prefer High-Level Behaviors: They simplify complex movement patterns and automatically handle integration with the Physics System. +- Use Low-Level Behaviors for Custom Logic: When precise control is required, combine low-level behaviors for unique movement styles. +- Smooth Orientation: Use alignOrientation or integrate orientation alignment directly into high-level functions. +- Tune Parameters: Adjust maxSpeed, turnSpeed, and slowingRadius for different entity types (e.g., fast-moving cars vs. slow-moving enemies). + +--- + +## Common Issues and Fixes + +### Issue: Entity Doesn’t Move + +- Cause: The Physics Component is missing or paused. +- Solution: Ensure the entity has a PhysicsComponents and it’s not paused. + +### Issue: Jittery Movement + +- Cause: Conflicting forces or large delta times. +- Solution: Tune maxSpeed and ensure deltaTime is passed correctly. + +### Issue: Entity Ignores Obstacles + +- Cause: Avoidance radius is too small or obstacles are not registered. +- Solution: Increase the avoidanceRadius and verify obstacle entities. + diff --git a/website/versioned_docs/version-0.7.1/04-Engine Development/03-Engine Systems/UsingTransformSystem.md b/website/versioned_docs/version-0.7.1/04-Engine Development/03-Engine Systems/UsingTransformSystem.md new file mode 100644 index 00000000..fb91bfdd --- /dev/null +++ b/website/versioned_docs/version-0.7.1/04-Engine Development/03-Engine Systems/UsingTransformSystem.md @@ -0,0 +1,118 @@ +--- +id: transformsystem +title: Transform System +sidebar_position: 3 +--- + +# Using the Transform System in Untold Engine + +The Transform System is a core part of the Untold Engine, responsible for managing the position, rotation, and scale of entities. It provides both local transformations (relative to a parent entity) and world transformations (absolute in the scene). + +## How to Use the Transform System + +### Step 1: Retrieve Transform Data +You can retrieve an entity’s position, orientation, or axis vectors using the provided functions. + +#### Get Local Position + +Retrieves the entity’s position relative to its parent. + +```swift +let localPosition = getLocalPosition(entityId: entity) +``` + +#### Get World Position + +Retrieves the entity’s absolute position in the scene. + +```swift +let worldPosition = getPosition(entityId: entity) +``` + +#### Get Local Orientation + +Retrieves the entity’s orientation matrix relative to its parent. + +```swift +let localOrientation = getLocalOrientation(entityId: entity) +``` + +#### Get World Orientation + +Retrieves the entity’s absolute orientation matrix. + +```swift +let worldOrientation = getOrientation(entityId: entity) +``` + +#### Get Axis Vectors + +Retrieve the entity’s forward, right, or up axis: + +```swift +let forward = getForwardAxisVector(entityId: entity) +let right = getRightAxisVector(entityId: entity) +let up = getUpAxisVector(entityId: entity) +``` + +--- + +### Step 2: Update Transform Data + +Modify an entity’s transform by translating or rotating it. + +#### Translate the Entity + +Move the entity to a new position: + +```swift +translateTo(entityId: entity, position: simd_float3(5.0, 0.0, 3.0)) +``` + +Move the entity by an offset relative to its current position: + +```swift +translateBy(entityId: entity, position: simd_float3(1.0, 0.0, 0.0)) +``` + +#### Rotate the Entity + +Rotate the entity to a specific angle around an axis: + +```swift +rotateTo(entityId: entity, angle: 45.0, axis: simd_float3(0.0, 1.0, 0.0)) +``` + +Apply an incremental rotation to the entity: + +```swift +rotateBy(entityId: entity, angle: 15.0, axis: simd_float3(0.0, 1.0, 0.0)) +``` + +Directly set the entity’s rotation matrix: + +```swift +rotateTo(entityId: entity, rotation: simd_float4x4( /* matrix values */ )) +``` + +--- + +## What Happens Behind the Scenes? + +1. Local and World Transform Components: +- Each entity has a LocalTransformComponent for transformations relative to its parent. +- The WorldTransformComponent calculates the absolute transform by combining the local transform with the parent’s world transform. +2. Transform Matrices: +- Transformations are stored in 4x4 matrices that include position, rotation, and scale. +- These matrices are updated whenever you translate or rotate an entity. +3. Scene Graph Integration: +- Changes to a parent entity automatically propagate to its children through the scene graph. + +--- + +## Tips and Best Practices +- Use Local Transformations for Hierarchies: + - For example, a car’s wheels (children) should use local transforms relative to the car body (parent). +- Combine Translations and Rotations: + - Use translateTo or rotateTo to set an entity’s absolute position or rotation. + - Use translateBy or rotateBy for incremental adjustments. diff --git a/website/versioned_docs/version-0.7.1/04-Engine Development/03-Engine Systems/_category.json b/website/versioned_docs/version-0.7.1/04-Engine Development/03-Engine Systems/_category.json new file mode 100644 index 00000000..a1c32169 --- /dev/null +++ b/website/versioned_docs/version-0.7.1/04-Engine Development/03-Engine Systems/_category.json @@ -0,0 +1 @@ +{ "label": "Engine Systems", "position": 4, "collapsed": false } diff --git a/website/versioned_docs/version-0.7.1/04-Engine Development/04-Custom Components/_category.json b/website/versioned_docs/version-0.7.1/04-Engine Development/04-Custom Components/_category.json new file mode 100644 index 00000000..71b20166 --- /dev/null +++ b/website/versioned_docs/version-0.7.1/04-Engine Development/04-Custom Components/_category.json @@ -0,0 +1 @@ +{ "label": "Custom Components", "position": 5, "collapsed": false } diff --git a/website/versioned_docs/version-0.7.1/04-Engine Development/04-Custom Components/customComponent.md b/website/versioned_docs/version-0.7.1/04-Engine Development/04-Custom Components/customComponent.md new file mode 100644 index 00000000..d327a357 --- /dev/null +++ b/website/versioned_docs/version-0.7.1/04-Engine Development/04-Custom Components/customComponent.md @@ -0,0 +1,60 @@ +--- +id: ecs-create-custom-component +title: Create a Custom Component +sidebar_position: 1 +--- + +# Create a Custom Component + +In your game, you may want to **extend functionality to an entity**. +You can do this by creating a **custom component**. + +Components in the Untold Engine are **data-only objects** that you attach to entities. +They should hold **state, not behavior**. All game logic is handled in systems. + +Every custom component must conform to the `Component` protocol. + +By following this design, your game stays modular: +- **Components** define what an entity *is capable of*. +- **Systems** define *how that capability behaves*. + +--- + +## Minimal Template + +Here’s an example of a simple custom component for a soccer player’s dribbling behavior: + +```swift +public class DribblinComponent: Component { + public required init() {} + var maxSpeed: Float = 5.0 + var kickSpeed: Float = 15.0 + var direction: simd_float3 = .zero +} +``` + +> ⚠️ Note: Components should not include functions or game logic. Keep them as pure data containers. + +## Attaching a Component to an Entity + +Once you’ve defined a component, you attach it to an entity in your scene: + +```swift +let player = createEntity(name: "player") + +// Attach DribblinComponent to the entity +registerComponent(entityId: player, componentType: DribblinComponent.self) + +// Access and modify component data +if let c = scene.get(component: DribblinComponent.self, for: player) { + c.maxSpeed = 6.5 + c.kickSpeed = 18.0 +} + +``` + +This example creates a new entity called player, attaches a DribblinComponent, and updates its values. + + +On its own, the component just stores numbers β€” it doesn’t do anything yet. +To make the player actually dribble, you’ll need to implement a system that processes this component each frame. diff --git a/website/versioned_docs/version-0.7.1/04-Engine Development/04-Custom Components/customSystem.md b/website/versioned_docs/version-0.7.1/04-Engine Development/04-Custom Components/customSystem.md new file mode 100644 index 00000000..0b6ed75b --- /dev/null +++ b/website/versioned_docs/version-0.7.1/04-Engine Development/04-Custom Components/customSystem.md @@ -0,0 +1,57 @@ +--- +id: ecs-create-custom-system +title: Create a Custom System +sidebar_position: 2 +--- + +# Create a Custom System + +If you’ve created a **custom component**, you’ll usually also want to create a **custom system** to make it do something. +Components store the data, but systems are where the behavior lives. + +The engine automatically calls systems every frame. A system typically: + +1. Resolves the component IDs it cares about +2. Queries entities that have those components +3. Reads and updates their state (transforms, physics, animation, etc.) + +This separation ensures components remain pure data containers, while systems drive the simulation. + +--- + +## Minimal Template + +Here’s a simple system that works with the `DribblinComponent` we defined earlier: + +```swift +public func dribblingSystemUpdate(deltaTime: Float) { + // 1. Get the ID of the DribblinComponent + let customId = getComponentId(for: DribblinComponent.self) + + // 2. Query all entities that have this component + let entities = queryEntitiesWithComponentIds([customId], in: scene) + + // 3. Loop through each entity and update its data + for entity in entities { + guard let dribblingComponent = scene.get(component: DribblinComponent.self, for: entity) else { + continue + } + + // Example logic: move player in the dribbling direction + dribblingComponent.direction = simd_normalize(dribblingComponent.direction) + let displacement = dribblingComponent.direction * dribblingComponent.maxSpeed * deltaTime + + if let transform = scene.get(component: LocalTransformComponent.self, for: entity) { + transform.position += displacement + } + } +} +``` + +## Registering the System +All custom systems must be registered during initialization so the engine knows to run them every frame: + +```swift +registerCustomSystem(dribblingSystemUpdate) +``` + diff --git a/website/versioned_docs/version-0.7.1/04-Engine Development/_category.json b/website/versioned_docs/version-0.7.1/04-Engine Development/_category.json new file mode 100644 index 00000000..e71fa89a --- /dev/null +++ b/website/versioned_docs/version-0.7.1/04-Engine Development/_category.json @@ -0,0 +1,2 @@ +{ "label": "Engine Development", "position": 3, "collapsed": false } + diff --git a/website/versioned_docs/version-0.7.1/05-Editor Development/01-Overview.md b/website/versioned_docs/version-0.7.1/05-Editor Development/01-Overview.md new file mode 100644 index 00000000..9abb3020 --- /dev/null +++ b/website/versioned_docs/version-0.7.1/05-Editor Development/01-Overview.md @@ -0,0 +1,135 @@ +--- +id: editoroverview +title: Overview +sidebar_position: 1 +--- + +# Editor Development Overview + +This section is for developers who want to **improve or extend the Untold Editor**. + +The editor is a separate application built on top of Untold Engine. + +--- + +## What You’ll Work On + +In this section, you’ll learn how to: +- Understand the editor architecture +- Add or modify editor views +- Improve workflows and tooling +- Integrate editor features with the engine + +Editor development focuses on **usability and tooling**, not gameplay. + +--- + +## Installing the Editor for Development + +Working on the editor requires installing Untold Editor via the command line and running it from source. + +For editor development, clone this repository: + +```bash +git clone https://github.com/untoldengine/UntoldEditor.git +cd UntoldEditor +``` +The Editor is a Swift Package with an executable target named UntoldEditor. +It declares a dependency on the Untold Engine package; Xcode/SwiftPM will resolve it automatically. + +### Open in Xcode + +1. Open Xcode β†’ File β–Έ Open β†’ select the Package.swift in this repo +2. Xcode will create a workspace view for the package +3. Choose the UntoldEditor scheme β†’ Run + +### Build & run via CLI +If you prefer working with the terminal, you can build and run the Editor as follows: + +```bash +swift build +swift run UntoldEditor +``` + +### Pinning the Engine Dependency + +By default, this repo pins Untold Engine to a released version. +If you want the latest engine changes: + +#### Option A β€” Xcode UI +- In the project navigator: Package Dependencies β†’ UntoldEngine +- Set Dependency Rule to Branch and type develop + +#### Option B β€” Edit Package.swift + +```swift +.dependencies = [ + .package(url: "https://github.com/untoldengine/UntoldEngine.git", branch: "develop") +] +``` + +Then reload packages: + +```bash +xcodebuild -resolvePackageDependencies +# or in Xcode: File β–Έ Packages β–Έ Resolve Package Versions +``` + + +The editor can be developed independently of game projects. + +--- + +## πŸ•Ή Using the Editor + +1. **Create / Open a Project** – Use the start screen or File menu +2. **Set Asset Folder** – Choose an **external** directory for your project’s assets +3. **Import Assets** – Drag files in or use the Asset Browser β€œ+” +4. **Build Your Scene** – Create entities, add components, use gizmos to position +5. **Play Mode** – Toggle to simulate and validate behavior +6. **Save / Load** – Save project and scene files; reopen later to continue + +> πŸ’‘ Why an *external* asset folder? +> It enables **runtime importing** and iteration without copying everything into the app bundle. + + +## Editor Architecture + +The Untold Editor is structured around: +- Independent views +- Shared engine state +- Explicit data flow between UI and engine +- Minimal magic + +Understanding the editor architecture is key before adding features. + +You can start with: + +> **Editor Development β†’ Architecture** + +--- + +## Editor Views and Interaction + +The editor is composed of views such as: +- Scene View +- Inspector +- Asset Browser +- Scene Hierarchy +- Code Editor (note: USC scripts are authored in Xcode; the editor does not include a built-in USC script editor) + +Each view is designed to be modular and replaceable. + +--- + +## Who This Section Is Not For + +This section is **not** intended for: +- Game developers building gameplay +- Engine developers working on core systems +- Users looking to learn the editor UI + +If you want to *use* the editor, see: + +> **Game Development β†’ Using the Editor** + diff --git a/website/versioned_docs/version-0.7.1/05-Editor Development/02-Architecture/EditorArchitecture.md b/website/versioned_docs/version-0.7.1/05-Editor Development/02-Architecture/EditorArchitecture.md new file mode 100644 index 00000000..c2d19857 --- /dev/null +++ b/website/versioned_docs/version-0.7.1/05-Editor Development/02-Architecture/EditorArchitecture.md @@ -0,0 +1,187 @@ +# Editor Architecture + +This document provides a high-level overview of the **Untold Editor architecture**. + +It is intended for contributors who want to understand how the editor is structured before working on specific views, tools, or workflows. + +This page focuses on **concepts, responsibilities, and data flow**, not implementation details. + +--- + +## Architectural Goals + +The Untold Editor is designed with the following goals: + +- **Editor as a client of the engine** + The editor uses the same runtime as the game. + +- **Explicit data flow** + Editor actions translate directly into engine state changes. + +- **Minimal editor-only behavior** + Play mode mirrors runtime behavior as closely as possible. + +- **Composable tools and views** + Editor features should be modular and replaceable. + +The editor is a tool β€” not a separate simulation environment. + +--- + +## High-Level Structure + +At a conceptual level, the editor is organized into these layers: + +Editor UI (Views & Tools) +↓ +Editor Coordination Layer +↓ +Engine Runtime +↓ +Platform & Rendering Backends + +The editor does not own the engine β€” it **drives** it. + +--- + +## Editor as an Engine Client + +The Untold Editor runs on top of the same engine runtime used by games. + +Key implications: +- Scene data is real engine data +- Systems execute through the same update loop +- Rendering paths are shared +- Bugs reproduced in the editor are runtime-relevant + +There is no β€œfake” editor simulation. + +--- + +## Editor Coordination Layer + +Between the UI and the engine sits a thin coordination layer. + +This layer is responsible for: +- Translating UI actions into engine operations +- Managing selection state +- Coordinating editor-only modes (Edit vs Play) +- Routing commands between views + +It does **not** contain simulation logic. + +--- + +## Views + +The editor is composed of **independent views**, each with a focused responsibility. + +Typical views include: +- Scene View +- Inspector +- Scene Hierarchy +- Asset Browser +- Code Editor (USC scripts are authored in Xcode; the editor does not include a built-in USC script editor) + +Views: +- Observe engine state +- Emit commands +- Do not own core data + +This keeps views simple and interchangeable. + +--- + +## Tools and Interaction + +Editor tools (selection, transform, manipulation, etc.) are built as: +- Stateless or minimally stateful controllers +- Operating on selected engine entities +- Emitting explicit transform or component changes + +Input handling is centralized and routed to active tools. + +--- + +## Scene Editing Model + +Scene editing operates directly on engine data: + +- Entities and components are real +- Transforms update immediately +- Changes are visible to all views + +Editor-only metadata (selection, highlighting, gizmos) is stored separately. + +--- + +## Edit Mode vs Play Mode + +The editor supports two primary modes: + +### Edit Mode +- Systems that mutate simulation state are paused +- Editor tools manipulate entity state directly +- Scene changes are persistent + +### Play Mode +- Full engine update loop runs +- USC scripts execute +- Physics and animation systems are active +- Scene state may be restored on exit + +The transition between modes is explicit and controlled. + +--- + +## Asset and Resource Handling + +The editor manages assets as references to engine resources. + +Responsibilities include: +- Importing external files +- Tracking asset paths +- Updating resource bindings +- Refreshing views when assets change + +The engine remains the owner of resource lifetimes. + +--- + +## Relationship to USC + +USC scripts are authored in Xcode and managed through the editor but executed by the engine. The editor itself does not host a built-in USC script editor. + +The editor: +- Creates script source files +- Triggers script builds +- Attaches generated scripts to entities + +The editor does not interpret or execute USC logic. + +--- + +## Design Tradeoffs + +The Untold Editor intentionally avoids: + +- Duplicating engine logic +- Editor-only simulation paths +- Heavy UI-driven state mutation +- Hidden side effects from tools + +These tradeoffs prioritize: +- Consistency with runtime behavior +- Debuggability +- Contributor approachability + +--- + +## Architecture in Practice + +This document describes the conceptual structure of the editor. + +For implementation details, see: + +Editor Development β†’ Architecture β†’ Internals + diff --git a/website/versioned_docs/version-0.7.1/05-Editor Development/03-Views/AssetBrowserView.md b/website/versioned_docs/version-0.7.1/05-Editor Development/03-Views/AssetBrowserView.md new file mode 100644 index 00000000..5f4a73fa --- /dev/null +++ b/website/versioned_docs/version-0.7.1/05-Editor Development/03-Views/AssetBrowserView.md @@ -0,0 +1,128 @@ +# Asset Browser View + +The **Asset Browser View** is the discovery and selection surface for project assets within the Untold Editor. + +It presents filtered asset metadata, supports browsing and search, and emits asset selection or assignment intents through the coordination layer. + +This document describes the **architectural role** of the Asset Browser View, not how to use it as an end user. + +--- + +## Purpose + +The Asset Browser View exists to: + +- Surface the project’s asset library for discovery +- Enable filtering, searching, and grouping of assets +- Provide a control point for selecting assets +- Initiate asset assignment intents (e.g., β€œassign mesh,” β€œassign script”) without owning import or load logic + +It is the bridge between asset metadata and editor interactions that consume assets. + +--- + +## Responsibilities + +The Asset Browser View is responsible for: + +- Displaying asset entries with relevant metadata and previews +- Providing search, filter, and organization affordances +- Reflecting shared selection state for assets +- Emitting asset selection changes +- Emitting asset assignment intents to other systems (e.g., drag-and-drop targets) via commands +- Respecting editor mode (Edit vs Play) where assignment is allowed + +The Asset Browser View does **not** own asset data or selection state. + +--- + +## What This View Does NOT Do + +The Asset Browser View intentionally does **not**: + +- Own or manage asset import, processing, or versioning +- Load GPU resources or instantiate runtime objects +- Apply asset assignments directly; it emits intents through the coordination layer +- Manage project file I/O beyond reading metadata exposed by asset services +- Execute scripts or run simulation logic +- Decide selection globally; it only requests changes through shared state + +If asset browser behavior appears to require import, loading, or state ownership, that logic belongs elsewhere. + +--- + +## Data Flow + +The Asset Browser View participates in the editor data flow as follows: + +### Reads +- Asset catalog metadata (names, types, tags, thumbnails, availability) +- Asset selection state +- Editor mode state +- Search/filter parameters provided by shared state or local UI + +### Emits +- Asset selection change requests +- Asset assignment intents (e.g., assign to component field, instantiate into scene) +- Folder or collection navigation commands (if supported by asset services) +- Mode-aware warnings when an assignment is not allowed + +All emitted actions flow through the editor coordination layer. + +--- + +## Interaction With Other Views + +The Asset Browser View interacts indirectly with other views via shared editor state: + +- **Scene View / Scene Hierarchy** + Receives asset drops or assignment intents to create or replace scene content + +- **Inspector** + Accepts asset assignments into component fields + +- **Code Editor** + May reference scripts as assets; USC authoring itself happens in Xcode, not inside the editor + +The Asset Browser View does not directly communicate with other views. + +--- + +## Edit Mode vs Play Mode Behavior + +### Edit Mode +- Full asset browsing, selection, and assignment intents are available +- Assignments update authoring data through commands + +### Play Mode +- Asset browsing remains available; assignments that mutate authoring data may be blocked or limited +- Runtime-safe assignments (if supported) are routed through the same command pathways + +Mode transitions are handled externally and reflected in the view. + +--- + +## Extension Points + +Contributors may extend the Asset Browser View by: + +- Adding advanced filters (tags, dependencies, usage frequency) +- Introducing custom previews or inspectors for specific asset types +- Extending drag-and-drop behaviors for assignment targets +- Adding collection/saved search features backed by shared state + +Extensions should integrate through existing asset metadata sources and command pathways. + +--- + +## Design Constraints + +The Asset Browser View is intentionally constrained to: + +- Visualization of asset metadata and selection +- Command emission for selection and assignment intents +- Stateless or minimal local UI state driven by shared data +- No direct import, loading, or mutation of asset storage + +Keeping these boundaries strict ensures predictable asset workflows and debuggability. + diff --git a/website/versioned_docs/version-0.7.1/05-Editor Development/03-Views/CodeEditorView.md b/website/versioned_docs/version-0.7.1/05-Editor Development/03-Views/CodeEditorView.md new file mode 100644 index 00000000..89753d95 --- /dev/null +++ b/website/versioned_docs/version-0.7.1/05-Editor Development/03-Views/CodeEditorView.md @@ -0,0 +1,129 @@ +# Code Editor View + +The **Code Editor View** is the text editing surface for scripts and other source assets in the Untold Editor. USC scripts themselves are authored in Xcode; the editor does not provide a built-in USC script editor. + +It presents source files, supports editing workflows, and emits save/build/run intents through the coordination layer without owning compilation or runtime. + +This document describes the **architectural role** of the Code Editor View, not how to use it as an end user. + +--- + +## Purpose + +The Code Editor View exists to: + +- Surface project scripts and source files for editing +- Provide an authoring surface for text assets; USC authoring lives in Xcode and is only surfaced here for viewing/coordination +- Bridge editing to build and run workflows via explicit commands +- Reflect scripting workflow state (open project, build output) in the editor context + +It is the link between source assets and scripting workflows, not the runtime itself. + +--- + +## Responsibilities + +The Code Editor View is responsible for: + +- Displaying and editing text buffers for selected source assets +- Reflecting file metadata (path, dirty state, read-only status) +- Emitting save commands for edited buffers +- Emitting build/run/test commands tied to scripting workflows +- Surfacing diagnostics and build output provided by external services +- Respecting editor mode (Edit vs Play) when enabling edits or execution commands + +The Code Editor View does **not** own source storage, compilation, or runtime execution. + +--- + +## What This View Does NOT Do + +The Code Editor View intentionally does **not**: + +- Interpret or execute USC or other scripts +- Own compilation, packaging, or deployment workflows; it triggers them +- Manage source control operations beyond reflecting status indicators +- Own project discovery or dependency resolution +- Apply engine changes directly; all actions flow through commands +- Decide selection globally; it observes selection/open-file state from shared editor context + +If code editor behavior appears to require compilation or runtime ownership, that logic belongs elsewhere. + +--- + +## Data Flow + +The Code Editor View participates in the editor data flow as follows: + +### Reads +- Source file contents and metadata (path, permissions, timestamps) +- Open-file/session state from the editor +- Build/run status and diagnostics from scripting services +- Editor mode state + +### Emits +- Save commands for current buffers +- Build/run/test commands for the active scripting project +- File open/close requests within the editor session +- Selection change requests for symbols or files if shared selection is used + +All emitted actions flow through the editor coordination layer. + +--- + +## Interaction With Other Views + +The Code Editor View interacts indirectly with other views via shared editor state: + +- **Asset Browser** + Opens scripts selected in the asset list + +- **Scene View / Scene Hierarchy** + May reflect selection-driven context (e.g., open script referenced by a component) but does not call views directly + +- **Inspector** + Consumes scripts as assignable assets; script edits propagate via save and build commands + +The Code Editor View does not directly communicate with other views. + +--- + +## Edit Mode vs Play Mode Behavior + +### Edit Mode +- Full text editing, save, and build/run commands are enabled +- Diagnostics and build output are surfaced for authoring + +### Play Mode +- Editing may be limited or read-only depending on project policy +- Build/run commands that mutate authoring state may be blocked or deferred +- Runtime logs may be surfaced without enabling authoring changes + +Mode transitions are handled externally and reflected in the view. + +--- + +## Extension Points + +Contributors may extend the Code Editor View by: + +- Adding language services (syntax highlighting, completion, diagnostics) via existing plugin hooks +- Integrating advanced navigation (symbol search, references) through shared project metadata +- Surfacing build/test pipelines with richer progress and error reporting +- Enhancing run configurations to emit explicit launch commands + +Extensions should integrate through existing command pathways and shared scripting state. + +--- + +## Design Constraints + +The Code Editor View is intentionally constrained to: + +- Text editing and presentation of scripting-related feedback +- Command emission for save/build/run +- Stateless or minimal local UI state driven by shared data +- No direct compilation, execution, or mutation of engine state + +Keeping these boundaries strict ensures predictable scripting workflows and debuggability. + diff --git a/website/versioned_docs/version-0.7.1/05-Editor Development/03-Views/InspectorView.md b/website/versioned_docs/version-0.7.1/05-Editor Development/03-Views/InspectorView.md new file mode 100644 index 00000000..6745678a --- /dev/null +++ b/website/versioned_docs/version-0.7.1/05-Editor Development/03-Views/InspectorView.md @@ -0,0 +1,135 @@ +# Inspector View + +The **Inspector View** is the focused property panel for examining and editing the selected entities and components in the Untold Editor. + +It presents authoritative component data for the current selection and emits structured changes back through the editor coordination layer. + +This document describes the **architectural role** of the Inspector View, not how to use it as an end user. + +--- + +## Purpose + +The Inspector View exists to: + +- Surface component data for the current selection +- Provide structured editors for component properties +- Validate edits against component rules and modes +- Emit explicit change requests to the coordination layer + +It is the bridge between selection state and component-level editing. + +--- + +## Responsibilities + +The Inspector View is responsible for: + +- Displaying the current selection (single or multi-entity) +- Rendering component sections and property editors +- Showing validation and state (read-only, overridden, default) +- Emitting add/remove component requests +- Emitting property change commands with full context (target entity, component, field, value) +- Reflecting editor mode (Edit vs Play) in allowed operations + +The Inspector View does **not** own component data or selection state. + +--- + +## What This View Does NOT Do + +The Inspector View intentionally does **not**: + +- Manage or decide selection; it only observes it +- Apply engine changes directly; all edits flow through commands +- Run simulation, scripting, or component lifecycle logic +- Own component storage or serialization; it only issues edits +- Own schemas or define component types (it consumes published definitions) +- Manage undo/redo stacks (it emits commands compatible with them) +- Provide asset authoring workflows beyond property-level references + +If Inspector behavior appears to require simulation or data ownership, that logic belongs elsewhere. + +--- + +## Data Flow + +The Inspector View participates in the editor data flow as follows: + +### Reads +- Selection state +- Component definitions and metadata (including editability rules) +- Component instances for selected entities +- Editor mode state +- Validation results and command feedback + +### Emits +- Property change commands +- Component add/remove requests +- Component reorder or enable/disable requests (if supported by schema) +- Mode-aware warnings (e.g., attempted edit in Play mode) + +All emitted actions flow through the editor coordination layer. + +--- + +## Interaction With Other Views + +The Inspector View interacts indirectly with other views via shared editor state: + +- **Scene Hierarchy** + Mirrors selection changes driven by hierarchy navigation + +- **Scene View** + Reflects selection changes initiated in world space + +- **Asset Browser** + Accepts drag-and-drop asset references into component fields + +- **Code Editor** + Consumes component schemas defined in code; USC authoring occurs in Xcode, not inside the editor; does not depend on editor code directly + +The Inspector View does not directly communicate with other views. + +--- + +## Edit Mode vs Play Mode Behavior + +### Edit Mode +- Full component editing is enabled +- Changes persist to the authoring state +- Validation prevents invalid component configurations + +### Play Mode +- Inspector prioritizes observation; many edits are read-only or limited +- Runtime values may be displayed distinctly from authoring values +- Commands that would mutate persistent data may be blocked or deferred + +Mode transitions are handled externally and reflected in the view. + +--- + +## Extension Points + +Contributors may extend the Inspector View by: + +- Adding custom property drawers for specific field types +- Providing component-specific inspectors with bespoke UI/validation +- Introducing contextual warnings or hints based on selection +- Enhancing multi-edit behavior across heterogeneous selections + +Extensions should integrate through existing data binding and command pathways. + +--- + +## Design Constraints + +The Inspector View is intentionally constrained to: + +- Observation of selection and component state +- Stateless or minimal local UI state +- Deterministic rendering based on shared data +- Command-only mutations; no direct state writes + +Keeping these boundaries strict ensures predictable editing and debuggability. + diff --git a/website/versioned_docs/version-0.7.1/05-Editor Development/03-Views/Overview.md b/website/versioned_docs/version-0.7.1/05-Editor Development/03-Views/Overview.md new file mode 100644 index 00000000..109c7029 --- /dev/null +++ b/website/versioned_docs/version-0.7.1/05-Editor Development/03-Views/Overview.md @@ -0,0 +1,172 @@ +# Editor Views Overview + +This section documents the **views that make up the Untold Editor**. + +It is intended for contributors who want to understand how editor views are structured, how they interact with the engine, and how they coordinate with each other. + +This is **not** user documentation. +It does not explain how to *use* the editor β€” only how it is built. + +--- + +## What Is a View? + +A **View** is a UI surface that: +- Observes engine and editor state +- Presents that state visually +- Emits explicit commands in response to user input + +Views do **not** own core data. + +They are clients of the editor and engine systems. + +--- + +## Responsibilities of a View + +Every editor view follows the same core responsibilities: + +- Render information derived from engine or editor state +- React to user input (mouse, keyboard, gestures) +- Emit commands to the editor coordination layer +- Stay stateless or minimally stateful + +A view should be easy to reason about in isolation. + +--- + +## What Views Do NOT Do + +Views intentionally do **not**: + +- Own or mutate engine state directly +- Contain simulation logic +- Manage entity lifetimes +- Execute USC scripts +- Perform rendering or physics work themselves + +If a view feels like it needs to β€œdo logic,” that logic likely belongs elsewhere. + +--- + +## Data Flow Model + +All views participate in a shared data flow model: + +Engine Runtime +↓ +Editor Coordination Layer +↓ +Editor Views +↓ +User Input +↓ +Editor Commands +↓ +Engine Runtime + +Key characteristics: +- Data flows downward +- Commands flow upward +- Views never bypass the coordination layer + +This keeps behavior predictable and debuggable. + +--- + +## Selection as Shared State + +Selection is a cross-view concern. + +- Views may observe the current selection +- Views may request selection changes +- No single view owns selection state + +This allows multiple views to remain decoupled while staying synchronized. + +--- + +## View Independence + +Views are designed to be independent and replaceable. + +This means: +- Views do not directly call each other +- Communication happens through shared editor state +- Views can be added, removed, or replaced without breaking others + +This is a deliberate architectural decision. + +--- + +## Editor Modes and Views + +Views must respect the editor’s active mode. + +### Edit Mode +- Views manipulate persistent scene data +- Simulation systems are paused +- Tools operate directly on entity state + +### Play Mode +- Views observe runtime state +- Simulation systems are active +- Editing is limited or disabled + +Views should not decide mode behavior β€” they respond to it. + +--- + +## Common View Patterns + +While views are independent, many follow similar patterns: + +- Scene-oriented views +- Inspection views +- Asset-oriented views +- Code-oriented views + +Each category emphasizes different interactions but follows the same architectural rules. + +--- + +## Extending or Adding a View + +When adding a new view: + +1. Define the view’s purpose +2. Identify the data it observes +3. Identify the commands it emits +4. Ensure it does not own core state +5. Integrate it through the coordination layer + +If a new view requires engine changes, document those explicitly. + +--- + +## View Documentation Structure + +Each individual view document follows this structure: + +- Purpose +- Responsibilities +- What This View Does NOT Do +- Data Flow +- Interaction With Other Views +- Extension Points + +This keeps documentation consistent and easy to scan. + +--- + +## Available Views + +The following views are documented in this section: + +- Scene View +- Inspector +- Scene Hierarchy +- Asset Browser +- Code Editor (USC scripts are authored in Xcode; the editor does not include a built-in USC script editor) + +--- diff --git a/website/versioned_docs/version-0.7.1/05-Editor Development/03-Views/SceneHierarchyView.md b/website/versioned_docs/version-0.7.1/05-Editor Development/03-Views/SceneHierarchyView.md new file mode 100644 index 00000000..aad738a1 --- /dev/null +++ b/website/versioned_docs/version-0.7.1/05-Editor Development/03-Views/SceneHierarchyView.md @@ -0,0 +1,127 @@ +# Scene Hierarchy View + +The **Scene Hierarchy View** presents the scene graph as an ordered list/tree of entities and is the primary control surface for selection and hierarchy manipulation. + +It exposes parent/child relationships conceptually and emits structured commands for selection, reparenting, ordering, and basic entity lifecycle actions. + +This document describes the **architectural role** of the Scene Hierarchy View, not how to use it as an end user. + +--- + +## Purpose + +The Scene Hierarchy View exists to: + +- Visualize the scene graph and entity ordering +- Provide a clear control point for selecting entities +- Enable conceptual hierarchy edits (parenting, unparenting, reordering) +- Initiate entity lifecycle actions (create, duplicate, delete) through commands + +It is the bridge between the scene graph model and selection-centric editing. + +--- + +## Responsibilities + +The Scene Hierarchy View is responsible for: + +- Displaying the scene graph structure and entity ordering +- Reflecting shared selection state and allowing selection changes +- Emitting hierarchy edit commands (reparent, reorder, toggle visibility/activation) +- Emitting entity lifecycle requests (create, duplicate, delete) via commands +- Respecting editor mode (Edit vs Play) when enabling hierarchy edits + +The Scene Hierarchy View does **not** own scene data or selection state. + +--- + +## What This View Does NOT Do + +The Scene Hierarchy View intentionally does **not**: + +- Compute transforms or resolve world/local matrices +- Maintain or persist the scene graph; it only visualizes and issues commands +- Perform simulation, physics, or animation updates +- Decide selection globally; it requests changes through shared state +- Apply engine changes directly; all edits flow through the coordination layer +- Execute scripting or component logic + +If hierarchy behavior appears to require graph ownership or simulation, that logic belongs elsewhere. + +--- + +## Data Flow + +The Scene Hierarchy View participates in the editor data flow as follows: + +### Reads +- Scene graph structure (entities, parent/child links, ordering) +- Entity metadata needed for display (names, icons, state flags) +- Selection state +- Editor mode state + +### Emits +- Selection change requests +- Reparent and reorder commands +- Visibility/activation toggle commands (if exposed) +- Entity lifecycle requests (create, duplicate, delete) + +All emitted actions flow through the editor coordination layer. + +--- + +## Interaction With Other Views + +The Scene Hierarchy View interacts indirectly with other views via shared editor state: + +- **Scene View** + Synchronizes selection changes between hierarchy and world-space interaction + +- **Inspector** + Displays and edits data for entities selected in the hierarchy + +- **Asset Browser** + May support drag-and-drop of assets to instantiate entities or assign references + +The Scene Hierarchy View does not directly communicate with other views. + +--- + +## Edit Mode vs Play Mode Behavior + +### Edit Mode +- Full hierarchy editing (reparent, reorder, lifecycle actions) is available +- Selection changes drive authoring-state inspection + +### Play Mode +- Hierarchy is primarily observational; destructive edits may be blocked or limited +- Selection may reflect runtime entities without persisting authoring changes + +Mode transitions are handled externally and reflected in the view. + +--- + +## Extension Points + +Contributors may extend the Scene Hierarchy View by: + +- Adding filters, search, or grouping affordances +- Introducing custom badges or state indicators derived from metadata +- Extending drag-and-drop behaviors for entity or asset interactions +- Providing bulk operations that emit explicit hierarchy commands + +Extensions should integrate through existing command pathways and shared state. + +--- + +## Design Constraints + +The Scene Hierarchy View is intentionally constrained to: + +- Visualization of the scene graph and selection state +- Command emission for hierarchy and lifecycle edits +- Stateless or minimal local UI state driven by shared data +- No direct mutation of engine or editor core data + +Keeping these boundaries strict ensures predictable editing and debuggability. + diff --git a/website/versioned_docs/version-0.7.1/05-Editor Development/03-Views/SceneView.md b/website/versioned_docs/version-0.7.1/05-Editor Development/03-Views/SceneView.md new file mode 100644 index 00000000..984b7fd7 --- /dev/null +++ b/website/versioned_docs/version-0.7.1/05-Editor Development/03-Views/SceneView.md @@ -0,0 +1,158 @@ +# Scene View + +The **Scene View** is the primary spatial view in the Untold Editor. + +It provides a visual representation of the current scene and allows contributors and tools to interact with entities in world space. + +This document describes the **architectural role** of the Scene View, not how to use it as an end user. + +--- + +## Purpose + +The Scene View exists to: + +- Visualize the current scene state +- Display entities and their transforms +- Provide spatial context for selection and manipulation +- Act as the main interaction surface for world-space tools + +It is the bridge between engine data and spatial editor interaction. + +--- + +## Responsibilities + +The Scene View is responsible for: + +- Rendering a visual representation of the scene +- Displaying editor overlays (selection outlines, gizmos, helpers) +- Receiving world-space input (mouse, keyboard, gestures) +- Emitting commands related to selection and transformation +- Respecting the current editor mode (Edit vs Play) + +The Scene View does **not** own scene data. + +--- + +## What This View Does NOT Do + +The Scene View intentionally does **not**: + +- Own or modify engine state directly +- Perform simulation, physics, or animation updates +- Decide how entities are selected globally +- Execute USC scripts +- Implement rendering pipelines or render passes + +If the Scene View appears to require simulation logic, that logic belongs elsewhere. + +--- + +## Data Flow + +The Scene View participates in the editor data flow as follows: + +### Reads +- Scene graph data +- Entity transforms +- Camera state +- Selection state +- Editor mode state + +### Emits +- Selection change requests +- Transform manipulation commands +- Camera navigation commands +- Tool activation signals + +All emitted actions flow through the editor coordination layer. + +--- + +## Interaction With Other Views + +The Scene View interacts indirectly with other views via shared editor state: + +- **Scene Hierarchy** + Synchronizes selection changes + +- **Inspector** + Displays and edits data for selected entities + +- **Asset Browser** + May initiate drag-and-drop actions into the scene + +The Scene View does not directly communicate with other views. + +--- + +## Tools and Manipulation + +World-space tools (translate, rotate, scale, etc.) are driven through the Scene View. + +Key characteristics: +- Tools operate on selected entities +- Input is routed to the active tool +- Tools emit explicit transform commands +- Visual gizmos are editor-only overlays + +The Scene View hosts tool interaction but does not implement tool logic. + +--- + +## Camera Control + +The Scene View owns the **editor camera**, which is distinct from game cameras. + +Responsibilities include: +- Camera navigation (orbit, pan, zoom) +- Framing selected entities +- Switching camera perspectives + +Editor camera state is isolated from runtime camera components. + +--- + +## Edit Mode vs Play Mode Behavior + +### Edit Mode +- Scene View allows full manipulation +- Entity transforms are persistent +- Editor overlays and gizmos are visible + +### Play Mode +- Scene View observes runtime state +- Manipulation may be limited or disabled +- Runtime cameras may be previewed + +Mode transitions are handled externally and reflected in the view. + +--- + +## Extension Points + +Contributors may extend the Scene View by: + +- Adding new world-space tools +- Introducing new editor overlays +- Customizing camera behavior +- Adding debug visualization layers + +Extensions should integrate through existing tool and command pathways. + +--- + +## Design Constraints + +The Scene View is intentionally constrained to: + +- Visualization +- Input capture +- Command emission + +Keeping these boundaries strict ensures: +- Predictable behavior +- Easier debugging +- Cleaner separation of concerns + diff --git a/website/versioned_docs/version-0.7.1/05-Editor Development/EditorOverview.md b/website/versioned_docs/version-0.7.1/05-Editor Development/EditorOverview.md new file mode 100644 index 00000000..27704bf8 --- /dev/null +++ b/website/versioned_docs/version-0.7.1/05-Editor Development/EditorOverview.md @@ -0,0 +1,99 @@ +--- +id: editorfeatures +title: Editor Features +sidebar_position: 2 +--- + +# Untold Engine Editor Features + +The Untold Engine Editor makes it easier than ever to set up your scenes and entities without touching code. With the Editor, you can visually create, configure, and organize your game world, while keeping Swift code focused on game logic and behaviors. + +Here’s a quick tour of the Editor’s main features: + +--- + +## Scene Graph + +![Scene Graph](../images/engine-scenegraph.png) + +The **Scene Graph** shows all the entities in your scene in a hierarchical view. You can add, rename, and organize entities, as well as set up parent–child relationships. This is where you’ll find your cameras, lights, and models at a glance. + +--- + +## Inspector + +![Inspector](../images/engine-inspector.png) + +The **Inspector** lets you configure properties of the selected entity. Adjust position, rotation, and scale, or fine-tune camera settings and add components. Think of it as the control panel for whatever you’re working on. + +--- + +## Gizmo Manipulation + +![Gizmo](../images/engine-gizmo.png) + +Use the **3D gizmo** to interactively move, rotate, and scale entities directly in the scene. This makes it quick to place objects exactly where you want them. + +--- + +## Materials + +![Materials](../images/engine-materials.png) + +Assign meshes and materials through the **Inspector**. You can drop in textures for base color, roughness, metallic, and emissive maps, then tweak material properties to get the right look. + +--- + +## Lighting & Environment + +![Lighting](../images/engine-lights.png) + +The **Lighting panel** give you control over your scene’s mood. Add directional, point, spotlight and area lights, adjust intensities. + +## Environment + +The **Environment panel** enable **Image-Based Lighting (IBL)** for realistic reflections and ambient light. + +![HDR](../images/engine-hdr.png) + +--- + +## Post-Processing Effects + +![Post Processing](../images/engine-post-processing.png) + +The **Effects tab** lets you add and tweak post-processing features such as: +- Depth of Field +- Chromatic Aberration +- Bloom +- Color Grading +- SSAO, Vignette, White Balance, and more + +These effects bring your scenes closer to a polished, production-ready look. + +--- + +## Asset Browser + +![Asset Browser](../images/engine-assetbrowser.png) + +The **Asset Browser** keeps your models, textures, and materials organized. Import new assets, set paths for your project, and quickly assign resources to entities in your scene. + +--- + +## Console Log + +![Console](../images/engine-consolelog.png) + +The **Console Log** provides real-time feedback from the engine. Use it to debug entity creation, monitor system messages, and track issues while working on your scene. + +--- + +## Putting It All Together + +With the Editor, you now have a clear separation of responsibilities: +- **Use the Editor** for entity initialization, scene setup, materials, and visual configuration. +- **Use Swift code** for gameplay logic, physics tweaks, and systems that bring your game to life. + +This workflow makes iteration faster and keeps your codebase focused on what matters most: gameplay. + diff --git a/website/versioned_docs/version-0.7.1/06-Reference/01-USCAPI.md b/website/versioned_docs/version-0.7.1/06-Reference/01-USCAPI.md new file mode 100644 index 00000000..0c961d1c --- /dev/null +++ b/website/versioned_docs/version-0.7.1/06-Reference/01-USCAPI.md @@ -0,0 +1,133 @@ +# Untold Script Core API + +Use this page as a compact checklist of the most-used USC (Untold Script Core) DSL calls. All snippets assume you’re inside a `buildScript` closure on the current entity (`self`). + +--- + +## Lifecycle +- `onStart()` – one-time init per play. +- `onUpdate()` – every frame. +- `onEvent("Name")` – custom triggers. +- `onCollision(tag:)` – **planned** (not yet available). + +## Properties (get/set) +Supported keys: `.position`, `.scale`, `.velocity`, `.acceleration`, `.mass`, `.angularVelocity` (write-only today), `.intensity`, `.color`, `.deltaTime`. +```swift +.getProperty(.position, as: "pos") +.setProperty(.position, toVariable: "nextPos") +.setProperty(.velocity, to: simd_float3(0, 2, 0)) +``` + +## Input +```swift +.ifKeyPressed("W") { n in n.log("forward") } +.ifKeyReleased("Space") { n.log("jump released") } +.getKeyState("w", as: "wPressed") +``` + +## Transform +```swift +.translateTo(simd_float3(0, 1, 0)) +.translateBy(simd_float3(0, 0, 1)) +.rotateTo(degrees: 45, axis: simd_float3(0, 1, 0)) +.rotateBy(degrees: .float(5), axis: simd_float3(0, 1, 0)) +.lookAt("TargetEntity") +``` + +## Animation +```swift +.playAnimation("Walk", loop: true) +.stopAnimation() +``` + +## Physics (forces/velocity) +```swift +.applyForce(force: simd_float3(0, 10, 0)) +.applyLinearImpulse(direction: .vec3(x: 0, y: 1, z: 0), magnitude: .float(5)) +.setLinearVelocity(.vec3(x: 0, y: 0, z: 5)) +.addLinearVelocity(.vec3(x: 0, y: 0, z: -1)) +.clampLinearSpeed(min: .float(0), max: .float(8)) +.clearVelocity() +.clearAngularVelocity() +.clearForces() +.setGravityScale(0.5) +.pausePhysicsComponent(isPaused: true) +``` + +## Steering (vectors or side effects) +```swift +.seek(targetPosition: .vec3(x: 10, y: 0, z: 0), maxSpeed: .float(5), result: "steer") +.flee(threatPosition: .vec3(x: 0, y: 0, z: 0), maxSpeed: .float(6), result: "steer") +.arrive(targetPosition: .vec3(x: 0, y: 0, z: 0), maxSpeed: .float(6), slowingRadius: .float(2), result: "steer") +.pursuit(targetEntity: .string("Player"), maxSpeed: .float(6), result: "steer") +.evade(threatEntity: .string("Enemy"), maxSpeed: .float(6), result: "steer") +.steerSeek(targetPosition: .variableRef("targetPos"), maxSpeed: .variableRef("maxSpeed"), deltaTime: .variableRef("dt")) +.steerArrive(targetPosition: .variableRef("targetPos"), maxSpeed: .variableRef("maxSpeed"), slowingRadius: .variableRef("slow"), deltaTime: .variableRef("dt")) +.steerFlee(threatPosition: .variableRef("threatPos"), maxSpeed: .variableRef("maxSpeed"), deltaTime: .variableRef("dt")) +.steerPursuit(targetEntity: .string("Target"), maxSpeed: .float(6), deltaTime: .float(0.016)) +.orbit(centerPosition: .vec3(x: 0, y: 0, z: 0), radius: .float(5), maxSpeed: .float(4), deltaTime: .float(0.016)) +.alignOrientation(deltaTime: .float(0.016), turnSpeed: .float(1.0)) +``` + +## Camera +```swift +.cameraMoveTo(.vec3(x: 0, y: 3, z: -10)) +.cameraMoveBy(.vec3(x: 1, y: 0, z: 0)) +.cameraRotate(pitch: .float(0.02), yaw: .float(-0.08)) +.cameraFollow(target: .string("Player"), + offset: .vec3(x: 0, y: 3, z: -6), + smoothFactor: .float(5), + deltaTime: .float(0.016)) +.cameraFollowLocal(target: .string("Player"), + localOffset: .vec3(x: 0, y: 2, z: -4), + smoothFactor: .float(5), + deltaTime: .float(0.016)) +.cameraOrbitTarget(target: .string("Boss"), + radius: .float(12), + speed: .float(1.5), + deltaTime: .float(0.016), + offsetY: .float(1.5)) +.cameraMoveWithInput(speedVar: "moveSpeed", + deltaTimeVar: "dt", + wVar: "wPressed", aVar: "aPressed", + sVar: "sPressed", dVar: "dPressed", + qVar: "qPressed", eVar: "ePressed") +``` + +## Math (variables only) +```swift +.addFloat("a", "b", as: "sum") +.addFloat("a", literal: 1, as: "sum") +.subFloat("a", "b", as: "diff") +.mulFloat("a", "b", as: "prod") +.divFloat("a", "b", as: "quot") +.addVec3("v1", "v2", as: "sum") +.scaleVec3("v", by: "s", as: "out") +.scaleVec3("v", literal: 2, as: "out") +.lengthVec3("v", as: "len") +.normalizeVec3("v", as: "unit") +.dotVec3("a", "b", as: "dot") +.crossVec3("a", "b", as: "cross") +.lerpVec3(from: "a", to: "b", t: "t", as: "out") +.lerpFloat(from: "a", to: "b", t: "t", as: "out") +.reflectVec3("v", normal: "n", as: "reflected") +.projectVec3("v", onto: "axis", as: "proj") +.angleBetweenVec3("a", "b", as: "angleDeg") +.clampFloat("speed", min: "minSpeed", max: "maxSpeed", as: "clamped") +.clampVec3("vel", min: "minVel", max: "maxVel", as: "clampedVel") +``` + +## Flow / Variables / Debug +```swift +.ifCondition(lhs: .variableRef("speed"), .greater, rhs: .float(10)) { n in n.log("Too fast") } +.ifGreater("health", than: 0) { n in n.log("Alive") }.else { n in n.log("Dead") } +.ifEqual("flag", to: true) { n in n.log("Flag set") } +.setVariable("speed", to: 5.0) +.setVariable("dir", to: simd_float3(0, 0, 1)) +.setVariable("copy", fromVariable: "speed") +.log("Hello") +.logValue("velocity", value: .variableRef("vel")) +``` + +> Tip: If you need an entity other than `self`, use names in your instructions (e.g., `.lookAt("TargetName")`) or stash them in variables, then call `findEntity`-driven instructions like `pursuit`/`evade`. + diff --git a/website/versioned_docs/version-0.7.1/06-Reference/02-EngineAPI.md b/website/versioned_docs/version-0.7.1/06-Reference/02-EngineAPI.md new file mode 100644 index 00000000..4baa6bf8 --- /dev/null +++ b/website/versioned_docs/version-0.7.1/06-Reference/02-EngineAPI.md @@ -0,0 +1,387 @@ +# Untold Engine Core API + +## Quick Reference + + +| Category | Common APIs | +|--------------|-------------| +| **Entities** | [createEntity](#create-an-entity), [destroyEntity](#destroy-an-entity), [setParent](#parent-child-relationships), [findEntity](#find-entity) | +| **Transforms** | [getLocalPosition](#get-local-position), [getPosition](#get-world-position), [getLocalOrientation](#get-local-orientation), [getOrientation](#get-world-orientation), [getForwardAxisVector](#get-axis-vectors), [translateTo](#translate-the-entity), [translateBy](#translate-the-entity), [rotateTo](#rotate-the-entity), [rotateBy](#rotate-the-entity) | +| **Assets** | [assetBasePath](#base-path-to-assets) | +| **Rendering** | [setEntityMesh](#link-a-mesh-to-the-entity), [setEntityGaussian](#link-a-gaussian-splat-to-the-entity), [createDirLight](#directional-light), [createPointLight](#point-light), [createSpotLight](#spot-light), [createAreaLight](#area-light) | +| **Animation** | [setEntityAnimations](#load-an-animation), [changeAnimation](#set-the-animation-to-play), [pauseAnimationComponent](#pause-the-animation-optional) | +| **Physics** | [setEntityKinetics](#enable-physics-on-the-entity), [setMass](#configure-physics-properties), [setGravityScale](#configure-physics-properties), [applyForce](#apply-forces-optional), [steerTo](#use-the-steering-system), [steerAway](#additional-steering-functions), [steerPursuit](#additional-steering-functions), [followPath](#additional-steering-functions) | +| **Components** | [registerComponent](#register-components), [create-custom-component](#create-custom-component), [attach-component](#attaching-a-component-to-an-entity) | +| **Systems** | [create-custom-system](#create-custom-system), [registerCustomSystem](#registering-the-custom-system) | + + +# Entities + +### Create an Entity + +Entities represent objects in the scene. Use the createEntity() function to create a new entity. + +```swift +let entity = createEntity() +``` + +### Destroy an Entity + +To remove an entity and its components from the scene, use destroyEntity. + +```swift +destroyEntity(entityId: entity) +``` + +This ensures the entity is properly removed from all systems. + +--- + +### Parent-Child Relationships + +To assign a parent to an entity, use the setParent function. This function establishes a hierarchical relationship between the specified entities. + +```swift +// Create child and parent entities +let childEntity = createEntity() +let parentEntity = createEntity() + +// Set parent-child relationship +setParent(childId: childEntity, parentId: parentEntity) +``` + +### Find Entity + +You can find an entity by name using the following function: + +```swift +let ball = findEntity(name: "ball") +``` +--- + +# Transforms + +### Get Local Position + +Retrieves the entity’s position relative to its parent. + +```swift +let localPosition = getLocalPosition(entityId: entity) +``` + +### Get World Position + +Retrieves the entity’s absolute position in the scene. + +```swift +let worldPosition = getPosition(entityId: entity) +``` + +### Get Local Orientation + +Retrieves the entity’s orientation matrix relative to its parent. + +```swift +let localOrientation = getLocalOrientation(entityId: entity) +``` + +### Get World Orientation + +Retrieves the entity’s absolute orientation matrix. + +```swift +let worldOrientation = getOrientation(entityId: entity) +``` + +### Get Axis Vectors + +Retrieve the entity’s forward, right, or up axis: + +```swift +let forward = getForwardAxisVector(entityId: entity) +let right = getRightAxisVector(entityId: entity) +let up = getUpAxisVector(entityId: entity) +``` + +--- + +### Translate the Entity + +Move the entity to a new position: + +```swift +translateTo(entityId: entity, position: simd_float3(5.0, 0.0, 3.0)) +``` + +Move the entity by an offset relative to its current position: + +```swift +translateBy(entityId: entity, position: simd_float3(1.0, 0.0, 0.0)) +``` + +### Rotate the Entity + +Rotate the entity to a specific angle around an axis: + +```swift +rotateTo(entityId: entity, angle: 45.0, axis: simd_float3(0.0, 1.0, 0.0)) +``` + +Apply an incremental rotation to the entity: + +```swift +rotateBy(entityId: entity, angle: 15.0, axis: simd_float3(0.0, 1.0, 0.0)) +``` + +Directly set the entity’s rotation matrix: + +```swift +rotateTo(entityId: entity, rotation: simd_float4x4( /* matrix values */ )) +``` + + +--- + +### Base path to assets + +Define the asset directory the engine will use to load content (Assuming you are using an external folder during development). Please see Import-Export section for more details. + +```swift +// Here we point it to a folder named "DemoGameAssets/Assets" on the Desktop. +// You can change this to any folder where you keep your own assets. +if let desktopURL = FileManager.default.urls(for: .desktopDirectory, in: .userDomainMask).first { + assetBasePath = desktopURL.appendingPathComponent("DemoGameAssets/Assets") +} +``` + +# Rendering + +### Link a Mesh to the Entity + +To display a model, load its .usdc file and link it to the entity using setEntityMesh. + +```swift +setEntityMesh(entityId: entity, filename: "entity", withExtension: "usdc") +``` + +Parameters: + +- entityId: The ID of the entity created earlier. +- filename: The name of the .usdc file (without the extension). +- withExtension: The file extension, typically "usdc". + +> Note: If PBR textures (e.g., albedo, normal, roughness, metallic maps) are included, the rendering system will automatically use the appropriate PBR shader to render the model with realistic lighting and material properties. + +### Link a Gaussian Splat to the Entity + +To display a Gaussian Splat model, load its .ply file and link it to the entity using setEntityGaussian. + +```swift +setEntityGaussian(entityId: entity, filename: "splat", withExtension: "ply") +``` + +Parameters: + +- entityId: The ID of the entity created earlier. +- filename: The name of the .ply file (without the extension). +- withExtension: The file extension, typically "ply". + +> Note: The Gaussian System renders point cloud data stored in the .ply format. Ensure your Gaussian Splat file is properly formatted and contains the necessary attributes (position, color, opacity, scale, rotation). + +### Directional Light + +Use for sunlight or distant key lights. Orientation (rotation) defines its direction. + +```swift +let sun = createEntity() +createDirLight(entityId: sun) +``` +### Point Light + +Omni light that radiates equally in all directions from a position. + +```swift +let bulb = createEntity() +createPointLight(entityId: bulb) +``` + +### Spot Light + +Cone-shaped light with a position and direction. + +```swift +let spot = createEntity() +createSpotLight(entityId: spot) +``` + +### Area Light + +Rect/area emitter used to mimic panels/windows; position and orientation matter. + +```swift +let panel = createEntity() +createAreaLight(entityId: panel) +``` + +--- + +# Animation + +### Load an Animation +Load the animation data for your model by providing the animation .usdc file and a name to reference the animation later. + +```swift +setEntityAnimations(entityId: redPlayer, filename: "running", withExtension: "usdc", name: "running") +``` + +### Set the Animation to play + +Trigger the animation by referencing its name. This will set the animation to play on the entity. + +```swift +changeAnimation(entityId: redPlayer, name: "running") +``` + +### Pause the animation (Optional) + +To pause the current animation, simply call the following function. The animation component will be paused for the current entity. + +```swift +pauseAnimationComponent(entityId: redPlayer, isPaused: true) +``` + +--- + +# Physics + +### Enable Physics on the Entity + +Activate the physics simulation for your entity using the setEntityKinetics function. This function prepares the entity for movement and dynamic interaction. + +```swift +setEntityKinetics(entityId: redPlayer) +``` +--- + +### Configure Physics Properties +You can customize the entity’s physics behavior by defining its mass and gravity scale: + +- Mass: Determines the force needed to move the object. Heavier objects require more force. +- Gravity Scale: Controls how strongly gravity affects the entity (default is 0.0). + +```swift +setMass(entityId: redPlayer, mass: 0.5) +setGravityScale(entityId: redPlayer, gravityScale: 1.0) +``` + +### Apply Forces (Optional) +You can apply a custom force to the entity for dynamic movement. This is useful for simulating actions like jumps or pushes. + +```swift +applyForce(entityId: redPlayer, force: simd_float3(0.0, 0.0, 5.0)) +``` + +> Note: Forces are applied per frame. To avoid unintended behavior, only apply forces when necessary. + +### Use the Steering System +For advanced movement behaviors, leverage the Steering System to steer entities toward or away from targets. This system automatically calculates the required forces. + +Example: Steering Toward a Position + +```swift +steerTo(entityId: redPlayer, targetPosition: simd_float3(0.0, 0.0, 5.0), maxSpeed: 2.0, deltaTime: deltaTime) +``` + +### Additional Steering Functions + +The Steering System includes other useful behaviors, such as: + +- steerAway() +- steerPursuit() +- followPath() + +These functions simplify complex movement patterns, making them easy to implement. + +--- + +# Components + +### Register Components + +Components define the behavior or attributes of an entity. Use registerComponent to add a component to an entity. + +```swift +let entity = createEntity() + +registerComponent(entityId: entity, componentType: RenderComponent.self) +``` + +### Create Custom Component + +Here’s an example of a simple custom component for a soccer player’s dribbling behavior: + +```swift +public class DribblinComponent: Component { + public required init() {} + var maxSpeed: Float = 5.0 + var kickSpeed: Float = 15.0 + var direction: simd_float3 = .zero +} +``` + +> ⚠️ Note: Components should not include functions or game logic. Keep them as pure data containers. + +### Attaching a Component to an Entity + +Once you’ve defined a component, you attach it to an entity in your scene: + +```swift +let player = createEntity(name: "player") + +// Attach DribblinComponent to the entity +registerComponent(entityId: player, componentType: DribblinComponent.self) +``` + +# Systems + +### Create Custom System + +If you’ve created a **custom component**, you’ll usually also want to create a **custom system** to make it do something. +Components store the data, but systems are where the behavior lives. + +The engine automatically calls systems every frame. + +Here’s a simple system that works with the `DribblinComponent` we defined earlier: + +```swift +public func dribblingSystemUpdate(deltaTime: Float) { + // 1. Get the ID of the DribblinComponent + let customId = getComponentId(for: DribblinComponent.self) + + // 2. Query all entities that have this component + let entities = queryEntitiesWithComponentIds([customId], in: scene) + + // 3. Loop through each entity and update its data + for entity in entities { + guard let dribblingComponent = scene.get(component: DribblinComponent.self, for: entity) else { + continue + } + + // Example logic: move player in the dribbling direction + dribblingComponent.direction = simd_normalize(dribblingComponent.direction) + let displacement = dribblingComponent.direction * dribblingComponent.maxSpeed * deltaTime + + if let transform = scene.get(component: LocalTransformComponent.self, for: entity) { + transform.position += displacement + } + } +} +``` + +### Registering the Custom System +All custom systems must be registered during initialization so the engine knows to run them every frame: + +```swift +registerCustomSystem(dribblingSystemUpdate) +``` + diff --git a/website/versioned_docs/version-0.7.1/07-Contributor/ContributionGuidelines.md b/website/versioned_docs/version-0.7.1/07-Contributor/ContributionGuidelines.md new file mode 100644 index 00000000..5f52ebeb --- /dev/null +++ b/website/versioned_docs/version-0.7.1/07-Contributor/ContributionGuidelines.md @@ -0,0 +1,131 @@ +--- +id: contributorguidelines +title: Contributor Guidelines +sidebar_position: 1 +--- + +# Contributing Guidelines + +Thank you for your interest in contributing! + +The vision for Untold Engine is to continually shape a 3D engine that is **stable, performant and developer-friendly**. +As maintainer, my focus is on **performance, testing, quality control, and API design**. +Contributors are encouraged to expand features, fix bugs, improve documentation, and enhance usability β€” always keeping the vision in mind. + +--- + +## Maintainer Responsibilities + +The Untold Engine is guided by a clear vision: To be a stable, performant, and developer-friendly 3D engine that empowers creativity, removes friction, and makes game development feel effortless. + +## Guiding Principles + +To achieve this vision, we follow these principles: + +- The engine strives to remain stable and crash-free. +- The codebase is backed by unit tests. +- We profile continuously to prevent regressions (visual and performance). +- The API must remain clear and user-friendly. +- We always think about the developer firstβ€”removing friction so they can focus on their games. + +As the maintainer, my primary focus is to ensure the project stays true to this vision. + +### What I Focus On +- **Performance** β†’ keeping the renderer and systems lean, efficient, and optimized for Apple hardware. +- **Testing & Stability** β†’ maintaining a reliable codebase with proper testing practices. +- **Quality Control** β†’ reviewing PRs for clarity, readability, and adherence to coding standards. +- **API Design** β†’ ensuring that the engine’s API remains logical, intuitive, and consistent. + +### What Contributors Are Encouraged to Focus On +- **Features** β†’ adding or improving systems, tools, and workflows. +- **Bug Fixes** β†’ addressing open issues and fixing edge cases. +- **Documentation** β†’ clarifying how things work and providing examples. +- **Editor & Usability** β†’ enhancing the UI, workflows, and overall developer experience. + +### Decision Making +All contributions are welcome, but acceptance will be guided by the project’s vision and the priorities above. +PRs that align with clarity, performance, or creativity β€” while keeping the engine stable and simple β€” are more likely to be accepted. + +These guidelines aren’t here to block you, but to make sure every contribution keeps the engine stable, clear, and useful for everyone. + +## Pull Request Guidelines + +- **One feature or bug fix per PR** + Each Pull Request should focus on a single feature, bug fix, or documentation improvement. + This keeps the history clean and makes it easier to track down issues later. + +- **Commit hygiene** + - Keep commits meaningful (avoid "misc changes" or "fix stuff"). + - Squash commits if needed, but do not mix unrelated features in the same commit. + - If your PR touches multiple files, make sure they all relate to the same feature or fix. + +βœ… Example: +- Good: *β€œAdd PhysicsSystem with gravity integration”* +- Bad: *β€œAdded PhysicsSystem + fixed rendering bug + updated docs”* + +--- + +## Required Contributions for New System Support + +For **new systems or major features**, your PR must include: + +- **Unit Tests** β†’ Validate functionality and cover edge cases. +- **How-To Guide** β†’ A step-by-step markdown guide explaining how to use the system. + +This ensures new features are stable, documented, and accessible to all users. + +πŸ‘‰ Note: For small fixes or incremental features, a How-To is not required. + +--- + +### How-To Guide Format + +Your guide must follow this structure: + +1. Introduction + +- Briefly explain the feature and its purpose. +- Describe what problem it solves or what value it adds. + +2. Why Use It + +- Provide real-world examples or scenarios where the feature is useful. +- Explain the benefits of using the feature in these contexts. + +3. Step-by-Step Implementation + +- Break down the setup process into clear, actionable steps. +- Include well-commented code snippets for each step. + +4. What Happens Behind the Scenes + +- Provide technical insights into how the system works internally (if relevant). +- Explain any significant impacts on performance or functionality. + +5. Tips and Best Practices + +- Share advice for effective usage. +- Highlight common pitfalls and how to avoid them. + +6. Running the Feature + +- Explain how to test or interact with the feature after setup. + +--- + +### Additional Notes + +--- + +## Questions & Discussions + +To keep communication clear and accessible for everyone: + +- πŸ’‘ Use **[GitHub Discussions](https://github.com/untoldengine/UntoldEngine/discussions)** for feature proposals, ideas, or general questions. +- 🐞 Use **[GitHub Issues](https://github.com/untoldengine/UntoldEngine/issues)** for bugs or concrete tasks that need tracking. + +This way, conversations stay organized, visible to the community, and future contributors can benefit from past discussions. + +--- + +Thank you for contributing to the Untold Engine! Following these guidelines will ensure that your work aligns with the project's goals and provides value to users. diff --git a/website/versioned_docs/version-0.7.1/07-Contributor/Formatting.md b/website/versioned_docs/version-0.7.1/07-Contributor/Formatting.md new file mode 100644 index 00000000..6d45d621 --- /dev/null +++ b/website/versioned_docs/version-0.7.1/07-Contributor/Formatting.md @@ -0,0 +1,105 @@ +--- +id: formatting +title: Formatting +sidebar_position: 2 +--- + +# Formatting and Linting + +To maintain a consistent code style across the Untold Engine repo, we use [SwiftFormat](https://github.com/nicklockwood/SwiftFormat). SwiftFormat is a code formatter for Swift that helps enforce Swift style conventions and keep the codebase clean. If you don't have SwiftFormat installed, see the **Installing SwiftFormat** section below. + +## Quick Formatting & Linting + +Navigate to the root directory of Untold Engine and then run the commands below: + +### πŸ” Lint files + +To lint (check) all Swift files without making changes: + +```bash +swiftformat --lint . --swiftversion 5.8 --reporter github-actions-log +``` + +Or, using the Makefile: + +```bash +make lint +``` + +This command runs the same lint configuration as our GitHub Actions workflow and pre-commit hook, ensuring consistent results locally and in CI. + +### βœ… Formatting Files + +To format files: + +```bash +swiftformat --swiftversion 5.8 . +``` + +Alternatively, you can use the Makefile shortcut: + +```bash +make format +``` + +πŸ’‘ Tip +If the pre-commit hook blocks your commit due to formatting issues, simply run: + +```bash +make format +``` + +then re-stage your changes and try committing again. + +You can bypass the hook temporarily (not recommended) with: + +```bash +git commit --no-verify +``` + +## Installing SwiftFormat + +The simplest way to install SwiftFormat is through the command line. + +1. Install SwiftFormat Using Homebrew: Open the terminal and run the following command: + +```bash +brew install swiftformat +``` +2. Verify Installation: After installation, verify that SwiftFormat is installed correctly by running: + +```bash +swiftformat --version +``` +This should print the installed version of SwiftFormat. + +### Using SwiftFormat + +Format a Single File + +To format a specific Swift file: + +1. Open the terminal and navigate to your project directory. + +2. Run the following command: + +```bash +swiftformat path/to/YourFile.swift +``` +This will format YourFile.swift according to the default rules. + +### Format Multiple Files + +To format all Swift files in your project: + +1. Navigate to your project directory in the terminal. + +2. Run the following command: + +```bash +swiftformat . +``` + +This will recursively format all Swift files in the current directory and its subdirectories. + + diff --git a/website/versioned_docs/version-0.7.1/07-Contributor/_category.json b/website/versioned_docs/version-0.7.1/07-Contributor/_category.json new file mode 100644 index 00000000..4308c167 --- /dev/null +++ b/website/versioned_docs/version-0.7.1/07-Contributor/_category.json @@ -0,0 +1,2 @@ +{ "label": "10-Contributor", "position": 99, "collapsed": false } + diff --git a/website/versioned_docs/version-0.7.1/07-Contributor/versioning.md b/website/versioned_docs/version-0.7.1/07-Contributor/versioning.md new file mode 100644 index 00000000..ddb6c7a9 --- /dev/null +++ b/website/versioned_docs/version-0.7.1/07-Contributor/versioning.md @@ -0,0 +1,16 @@ +--- +id: versioning +title: Versioning +sidebar_position: 3 +--- + +# Versioning + +To help us identity the purpose of your commits, make sure to use the following tags in your commit messages. The tags will also automatically increment the the current version when pushed to github. + +- [Patch] - Bug fixes (eg. v1.0.0 -> v1.0.1) +- [Feature] - For new feature that don't break compatibility (eg. v1.0.0 -> v1.1.0) +- [API Change] - For major changes that are not API backward compatible (eg. v1.0.0 -> v2.0.0) + + + diff --git a/website/versioned_docs/version-0.7.1/08-CLI/CLI.md b/website/versioned_docs/version-0.7.1/08-CLI/CLI.md new file mode 100644 index 00000000..0ff5498a --- /dev/null +++ b/website/versioned_docs/version-0.7.1/08-CLI/CLI.md @@ -0,0 +1,505 @@ +# UntoldEngine CLI Tool + +> **Note:** The CLI tool source code is located in the `Tools/UntoldEngineCLI/` directory of the repository. +> +> For the most up-to-date documentation, see `Tools/UntoldEngineCLI/README.md` in the repository. + +The `untoldengine-create` command-line tool allows you to create and manage UntoldEngine game projects without launching the UntoldEditor. + +## Quick Start + +```bash +# Clone the repository +git clone https://github.com/untoldengine/UntoldEngine.git +cd UntoldEngine + +# Install the CLI globally +./scripts/install-create.sh + +# Create a project from anywhere +cd ~/anywhere +mkdir MyGame && cd MyGame +untoldengine-create create MyGame +``` + +## Complete Documentation + +For complete CLI documentation including: + +- Installation instructions +- Command reference +- Platform options +- Usage examples +- Troubleshooting + +Please refer to `Tools/UntoldEngineCLI/README.md` in the repository. + +## Quick Start + +Create a new game project in three simple steps: + +```bash +# 1. Create and enter your project directory +mkdir MyGame && cd MyGame + +# 2. Create the project (default: macOS) +untoldengine-create create MyGame + +# 3. Open in Xcode +open MyGame/MyGame.xcodeproj +``` + +All project files and assets will be created in the current directory. + +## Commands + +### create + +Creates a new UntoldEngine game project with the specified platform configuration. + +**Usage:** +```bash +untoldengine-create create [--platform ] +``` + +**Arguments:** +- ``: Name of your game project (required) + +**Options:** +- `--platform `: Target platform (default: `macos`) + - `macos` - macOS desktop application + - `ios` - iOS application + - `iosar` - iOS with ARKit support + - `visionos` - visionOS (Apple Vision Pro) + +**Examples:** + +Create a macOS game: +```bash +mkdir SpaceShooter && cd SpaceShooter +untoldengine-create create SpaceShooter +``` + +Create an iOS game: +```bash +mkdir MobileRPG && cd MobileRPG +untoldengine-create create MobileRPG --platform ios +``` + +Create an AR game for iOS: +```bash +mkdir ARAdventure && cd ARAdventure +untoldengine-create create ARAdventure --platform iosar +``` + +Create a visionOS game: +```bash +mkdir VisionGame && cd VisionGame +untoldengine-create create VisionGame --platform visionos +``` + +**What it does:** + +1. Creates the complete project structure in the current directory +2. Generates an Xcode project using XcodeGen +3. Sets up the game asset directories at `/Sources//GameData/` +4. Configures the UntoldEngine to load assets from the GameData directory +5. Creates platform-specific configuration files + +### update + +Updates the game data directory structure for an existing project. + +**Usage:** +```bash +untoldengine-create update +``` + +**Arguments:** +- ``: Name of the existing project (required) + +**What it does:** + +Re-creates the GameData folder structure at `/Sources//GameData/` with all standard asset directories: +- Models/ +- Scenes/ +- Scripts/ +- Animations/ +- Gaussians/ +- Shaders/ +- Textures/ + +**Example:** + +```bash +cd MyGame +untoldengine-create update MyGame +``` + +**When to use:** +- After accidentally deleting asset folders +- When you need to reset the folder structure +- To ensure all standard directories exist + +## Platform Options + +### macOS +**Command:** `--platform macos` (default) + +**Features:** +- Full desktop application +- Window management +- Keyboard and mouse input +- High performance rendering + +**Use for:** +- Desktop games +- Development and testing +- Maximum performance applications + +### iOS +**Command:** `--platform ios` + +**Features:** +- iPhone and iPad support +- Touch input +- Accelerometer support +- App Store distribution + +**Use for:** +- Mobile games +- Touch-based experiences +- Wide distribution via App Store + +### iOS AR (ARKit) +**Command:** `--platform iosar` + +**Features:** +- All iOS features +- ARKit integration +- World tracking +- Plane detection +- Face tracking + +**Use for:** +- Augmented reality games +- AR experiences +- Real-world interactive applications + +### visionOS +**Command:** `--platform visionos` + +**Features:** +- Apple Vision Pro support +- Spatial computing +- 3D UI elements +- Hand tracking +- Eye tracking + +**Use for:** +- Immersive 3D experiences +- Spatial applications +- Next-generation mixed reality + +## Project Structure + +After running `untoldengine-create create MyGame`, your project structure will look like: + +``` +MyGame/ # Your working directory +└── MyGame/ # Generated project + β”œβ”€β”€ MyGame.xcodeproj # Xcode project (generated) + β”œβ”€β”€ project.yml # XcodeGen configuration + β”œβ”€β”€ README.md # Project documentation + └── Sources/ + └── MyGame/ + β”œβ”€β”€ GameData/ # Game assets location + β”‚ β”œβ”€β”€ Models/ # 3D models (.usdz, etc.) + β”‚ β”œβ”€β”€ Scenes/ # Scene files + β”‚ β”œβ”€β”€ Scripts/ # Game logic scripts + β”‚ β”œβ”€β”€ Animations/ # Animation data + β”‚ β”œβ”€β”€ Gaussians/ # Gaussian splatting data + β”‚ β”œβ”€β”€ Shaders/ # Custom shaders + β”‚ └── Textures/ # Image files + β”œβ”€β”€ AppDelegate.swift # Application entry point + β”œβ”€β”€ GameViewController.swift # Main game controller + └── Info.plist # App configuration +``` + +### Important Directories + +**GameData/**: The single location for all game assets +- Path: `MyGame/Sources/MyGame/GameData/` +- The UntoldEngine is configured to load all assets from this location +- Copy your game assets (models, textures, etc.) here +- Subdirectories are organized by asset type + +**Sources/**: Swift source code +- Contains your game's Swift files +- Platform-specific delegates and controllers +- Can add additional Swift files here + +### Adding Assets + +To add assets to your game, copy them into the appropriate GameData subdirectory: + +```bash +# Add a 3D model +cp ~/Downloads/spaceship.usdz MyGame/Sources/MyGame/GameData/Models/ + +# Add textures +cp ~/Downloads/texture_*.png MyGame/Sources/MyGame/GameData/Textures/ + +# Add a scene +cp ~/Downloads/level1.json MyGame/Sources/MyGame/GameData/Scenes/ +``` + +The engine will automatically find assets in these locations. + +## Workflow Examples + +### Typical Development Workflow + +```bash +# 1. Create project directory +mkdir MyAwesomeGame +cd MyAwesomeGame + +# 2. Create the game project +untoldengine-create create MyAwesomeGame --platform ios + +# 3. Add your game assets +cp -r ~/GameAssets/Models/* MyAwesomeGame/Sources/MyAwesomeGame/GameData/Models/ +cp -r ~/GameAssets/Textures/* MyAwesomeGame/Sources/MyAwesomeGame/GameData/Textures/ + +# 4. Open in Xcode and start developing +open MyAwesomeGame/MyAwesomeGame.xcodeproj +``` + +### Starting from Scratch + +```bash +# Create a new game from scratch +mkdir PuzzleGame && cd PuzzleGame +untoldengine-create create PuzzleGame --platform macos + +# The GameData directory is ready for your assets +ls -la PuzzleGame/Sources/PuzzleGame/GameData/ +# Models/ Scenes/ Scripts/ Animations/ Gaussians/ Shaders/ Textures/ +``` + +### Multi-Platform Development + +You might want to test the same game on different platforms: + +```bash +# Create macOS version for development +mkdir MyGame-macOS && cd MyGame-macOS +untoldengine-create create MyGame --platform macos + +# Create iOS version in a separate directory +cd .. +mkdir MyGame-iOS && cd MyGame-iOS +untoldengine-create create MyGame --platform ios + +# Copy assets between projects +cp -r ../MyGame-macOS/MyGame/Sources/MyGame/GameData/* \ + MyGame/Sources/MyGame/GameData/ +``` + +### Resetting Asset Structure + +If you accidentally delete asset folders or need to reset: + +```bash +cd MyGame +untoldengine-create update MyGame +# GameData structure is recreated +``` + +## Troubleshooting + +### Command Not Found + +**Problem:** `untoldengine-create: command not found` + +**Solution:** +1. Ensure you ran the installation script: + ```bash + cd /path/to/UntoldEngine + ./Scripts/install-create.sh + ``` + +2. Check if the tool exists: + ```bash + ls -l /usr/local/bin/untoldengine-create + ``` + +3. If it exists but still not found, add `/usr/local/bin` to your PATH: + ```bash + echo 'export PATH="/usr/local/bin:$PATH"' >> ~/.zshrc + source ~/.zshrc + ``` + +### XcodeGen Failed + +**Problem:** Error message about XcodeGen failing + +**Solution:** +1. Ensure XcodeGen is installed: + ```bash + brew install xcodegen + ``` + +2. Verify XcodeGen works: + ```bash + xcodegen --version + ``` + +3. Check the project.yml file for syntax errors: + ```bash + cat path/to/project/project.yml + ``` + +### Build System Errors + +**Problem:** Error message about BuildSystem failure + +**Solution:** +1. Verify the UntoldEngine framework is properly built +2. Check that you're running the command from the correct directory +3. Ensure sufficient disk space for the project + +### Permission Denied + +**Problem:** Permission errors during installation + +**Solution:** +Use sudo for installation: +```bash +sudo ./Scripts/install-create.sh +``` + +Or install to a user directory (advanced): +```bash +# Edit install-create.sh to use a different install location +# Change INSTALL_PATH to ~/bin/untoldengine-create +``` + +### Xcode Project Won't Open + +**Problem:** Generated .xcodeproj file won't open + +**Solution:** +1. Regenerate the project: + ```bash + cd path/to/project + xcodegen generate + ``` + +2. Check Xcode version compatibility: + ```bash + xcodebuild -version + ``` + (Requires Xcode 15.0+) + +3. Verify project.yml is valid: + ```bash + cat project.yml + ``` + +### Assets Not Loading + +**Problem:** Game can't find assets at runtime + +**Solution:** +1. Verify assets are in the correct location: + ```bash + ls -la MyGame/Sources/MyGame/GameData/ + ``` + +2. Ensure assets are in the right subdirectories: + - Models go in `GameData/Models/` + - Textures go in `GameData/Textures/` + - etc. + +3. Check asset file names and extensions are correct + +4. Verify the GameData directory structure by running update: + ```bash + untoldengine-create update MyGame + ``` + +## Advanced Usage + +### Scripting and Automation + +The CLI tool is designed to work well in scripts: + +```bash +#!/bin/bash +# create-all-platforms.sh + +PROJECT_NAME="MyGame" + +for PLATFORM in macos ios iosar visionos; do + DIR="${PROJECT_NAME}-${PLATFORM}" + mkdir -p "$DIR" && cd "$DIR" + untoldengine-create create "$PROJECT_NAME" --platform "$PLATFORM" + cd .. +done +``` + +### CI/CD Integration + +Example GitHub Actions workflow: + +```yaml +name: Create Game Projects +on: [push] + +jobs: + create-projects: + runs-on: macos-latest + steps: + - uses: actions/checkout@v2 + + - name: Install CLI tool + run: | + cd UntoldEngine + ./Scripts/install-create.sh + + - name: Create projects + run: | + mkdir -p builds/MyGame-iOS && cd builds/MyGame-iOS + untoldengine-create create MyGame --platform ios +``` + +### Environment Variables + +While the CLI doesn't currently use environment variables, you can use them in your workflow: + +```bash +export GAME_NAME="MyGame" +export PLATFORM="ios" + +mkdir "$GAME_NAME" && cd "$GAME_NAME" +untoldengine-create create "$GAME_NAME" --platform "$PLATFORM" +``` + +## Getting Help + +For additional help: + +```bash +# General help +untoldengine-create --help + +# Command-specific help +untoldengine-create create --help +untoldengine-create update --help +``` + +## Feedback and Issues + +Found a bug or have a feature request? Please report it on the [UntoldEngine GitHub repository](https://github.com/untoldengine/UntoldEngine/issues). diff --git a/website/versioned_docs/version-0.7.1/images/Editor/EditorAssetBrowserScripts.png b/website/versioned_docs/version-0.7.1/images/Editor/EditorAssetBrowserScripts.png new file mode 100644 index 00000000..0b523ad7 Binary files /dev/null and b/website/versioned_docs/version-0.7.1/images/Editor/EditorAssetBrowserScripts.png differ diff --git a/website/versioned_docs/version-0.7.1/images/Editor/EditorAssetBrowserView-alt.png b/website/versioned_docs/version-0.7.1/images/Editor/EditorAssetBrowserView-alt.png new file mode 100644 index 00000000..b925157b Binary files /dev/null and b/website/versioned_docs/version-0.7.1/images/Editor/EditorAssetBrowserView-alt.png differ diff --git a/website/versioned_docs/version-0.7.1/images/Editor/EditorAssetBrowserView.png b/website/versioned_docs/version-0.7.1/images/Editor/EditorAssetBrowserView.png new file mode 100644 index 00000000..c5cbe12f Binary files /dev/null and b/website/versioned_docs/version-0.7.1/images/Editor/EditorAssetBrowserView.png differ diff --git a/website/versioned_docs/version-0.7.1/images/Editor/EditorAssetLibraryLoupe.png b/website/versioned_docs/version-0.7.1/images/Editor/EditorAssetLibraryLoupe.png new file mode 100644 index 00000000..9a4a0c8e Binary files /dev/null and b/website/versioned_docs/version-0.7.1/images/Editor/EditorAssetLibraryLoupe.png differ diff --git a/website/versioned_docs/version-0.7.1/images/Editor/EditorBottomShot.png b/website/versioned_docs/version-0.7.1/images/Editor/EditorBottomShot.png new file mode 100644 index 00000000..ed3f3c73 Binary files /dev/null and b/website/versioned_docs/version-0.7.1/images/Editor/EditorBottomShot.png differ diff --git a/website/versioned_docs/version-0.7.1/images/Editor/EditorCodeScriptView-alt.png b/website/versioned_docs/version-0.7.1/images/Editor/EditorCodeScriptView-alt.png new file mode 100644 index 00000000..84d7461b Binary files /dev/null and b/website/versioned_docs/version-0.7.1/images/Editor/EditorCodeScriptView-alt.png differ diff --git a/website/versioned_docs/version-0.7.1/images/Editor/EditorCodeScriptView.png b/website/versioned_docs/version-0.7.1/images/Editor/EditorCodeScriptView.png new file mode 100644 index 00000000..654da1eb Binary files /dev/null and b/website/versioned_docs/version-0.7.1/images/Editor/EditorCodeScriptView.png differ diff --git a/website/versioned_docs/version-0.7.1/images/Editor/EditorEffects.png b/website/versioned_docs/version-0.7.1/images/Editor/EditorEffects.png new file mode 100644 index 00000000..d69f3787 Binary files /dev/null and b/website/versioned_docs/version-0.7.1/images/Editor/EditorEffects.png differ diff --git a/website/versioned_docs/version-0.7.1/images/Editor/EditorEnvironment.png b/website/versioned_docs/version-0.7.1/images/Editor/EditorEnvironment.png new file mode 100644 index 00000000..c6f55a22 Binary files /dev/null and b/website/versioned_docs/version-0.7.1/images/Editor/EditorEnvironment.png differ diff --git a/website/versioned_docs/version-0.7.1/images/Editor/EditorInspectorView.png b/website/versioned_docs/version-0.7.1/images/Editor/EditorInspectorView.png new file mode 100644 index 00000000..04f65dce Binary files /dev/null and b/website/versioned_docs/version-0.7.1/images/Editor/EditorInspectorView.png differ diff --git a/website/versioned_docs/version-0.7.1/images/Editor/EditorMainShot-alt.png b/website/versioned_docs/version-0.7.1/images/Editor/EditorMainShot-alt.png new file mode 100644 index 00000000..2ba7138d Binary files /dev/null and b/website/versioned_docs/version-0.7.1/images/Editor/EditorMainShot-alt.png differ diff --git a/website/versioned_docs/version-0.7.1/images/Editor/EditorMainShot.png b/website/versioned_docs/version-0.7.1/images/Editor/EditorMainShot.png new file mode 100644 index 00000000..981a26e4 Binary files /dev/null and b/website/versioned_docs/version-0.7.1/images/Editor/EditorMainShot.png differ diff --git a/website/versioned_docs/version-0.7.1/images/Editor/EditorScenegraphView.png b/website/versioned_docs/version-0.7.1/images/Editor/EditorScenegraphView.png new file mode 100644 index 00000000..87b1cc9c Binary files /dev/null and b/website/versioned_docs/version-0.7.1/images/Editor/EditorScenegraphView.png differ diff --git a/website/versioned_docs/version-0.7.1/images/Editor/EditorSideShotWide-alt.png b/website/versioned_docs/version-0.7.1/images/Editor/EditorSideShotWide-alt.png new file mode 100644 index 00000000..42a9c804 Binary files /dev/null and b/website/versioned_docs/version-0.7.1/images/Editor/EditorSideShotWide-alt.png differ diff --git a/website/versioned_docs/version-0.7.1/images/Editor/EditorSideShotWide.png b/website/versioned_docs/version-0.7.1/images/Editor/EditorSideShotWide.png new file mode 100644 index 00000000..14ea9d47 Binary files /dev/null and b/website/versioned_docs/version-0.7.1/images/Editor/EditorSideShotWide.png differ diff --git a/website/versioned_docs/version-0.7.1/images/Editor/Editor_scene_empty.png b/website/versioned_docs/version-0.7.1/images/Editor/Editor_scene_empty.png new file mode 100644 index 00000000..8dbc2880 Binary files /dev/null and b/website/versioned_docs/version-0.7.1/images/Editor/Editor_scene_empty.png differ diff --git a/website/versioned_docs/version-0.7.1/images/Editor/Editor_scene_model_import.png b/website/versioned_docs/version-0.7.1/images/Editor/Editor_scene_model_import.png new file mode 100644 index 00000000..310df2be Binary files /dev/null and b/website/versioned_docs/version-0.7.1/images/Editor/Editor_scene_model_import.png differ diff --git a/website/versioned_docs/version-0.7.1/images/Editor/Editor_scene_model_viewport.png b/website/versioned_docs/version-0.7.1/images/Editor/Editor_scene_model_viewport.png new file mode 100644 index 00000000..321d2552 Binary files /dev/null and b/website/versioned_docs/version-0.7.1/images/Editor/Editor_scene_model_viewport.png differ diff --git a/website/versioned_docs/version-0.7.1/images/Editor/Editor_scene_name.png b/website/versioned_docs/version-0.7.1/images/Editor/Editor_scene_name.png new file mode 100644 index 00000000..09e711f6 Binary files /dev/null and b/website/versioned_docs/version-0.7.1/images/Editor/Editor_scene_name.png differ diff --git a/website/versioned_docs/version-0.7.1/images/Editor/Editor_scene_new.png b/website/versioned_docs/version-0.7.1/images/Editor/Editor_scene_new.png new file mode 100644 index 00000000..99bc768b Binary files /dev/null and b/website/versioned_docs/version-0.7.1/images/Editor/Editor_scene_new.png differ diff --git a/website/versioned_docs/version-0.7.1/images/Editor/Editor_scene_xcode.png b/website/versioned_docs/version-0.7.1/images/Editor/Editor_scene_xcode.png new file mode 100644 index 00000000..65b5c908 Binary files /dev/null and b/website/versioned_docs/version-0.7.1/images/Editor/Editor_scene_xcode.png differ diff --git a/website/versioned_docs/version-0.7.1/images/Editor/ScriptEditorAdd.png b/website/versioned_docs/version-0.7.1/images/Editor/ScriptEditorAdd.png new file mode 100644 index 00000000..f425394b Binary files /dev/null and b/website/versioned_docs/version-0.7.1/images/Editor/ScriptEditorAdd.png differ diff --git a/website/versioned_docs/version-0.7.1/images/Editor/ScriptReload.png b/website/versioned_docs/version-0.7.1/images/Editor/ScriptReload.png new file mode 100644 index 00000000..79f69854 Binary files /dev/null and b/website/versioned_docs/version-0.7.1/images/Editor/ScriptReload.png differ diff --git a/website/versioned_docs/version-0.7.1/images/UntoldEngineGrid.png b/website/versioned_docs/version-0.7.1/images/UntoldEngineGrid.png new file mode 100644 index 00000000..d6790ef1 Binary files /dev/null and b/website/versioned_docs/version-0.7.1/images/UntoldEngineGrid.png differ diff --git a/website/versioned_docs/version-0.7.1/images/add-animation-component.png b/website/versioned_docs/version-0.7.1/images/add-animation-component.png new file mode 100644 index 00000000..4fb63092 Binary files /dev/null and b/website/versioned_docs/version-0.7.1/images/add-animation-component.png differ diff --git a/website/versioned_docs/version-0.7.1/images/add-button-scenegraph.png b/website/versioned_docs/version-0.7.1/images/add-button-scenegraph.png new file mode 100644 index 00000000..17c6f06a Binary files /dev/null and b/website/versioned_docs/version-0.7.1/images/add-button-scenegraph.png differ diff --git a/website/versioned_docs/version-0.7.1/images/addcomponent.png b/website/versioned_docs/version-0.7.1/images/addcomponent.png new file mode 100644 index 00000000..cc2995fe Binary files /dev/null and b/website/versioned_docs/version-0.7.1/images/addcomponent.png differ diff --git a/website/versioned_docs/version-0.7.1/images/animation-assign.png b/website/versioned_docs/version-0.7.1/images/animation-assign.png new file mode 100644 index 00000000..9a36e09b Binary files /dev/null and b/website/versioned_docs/version-0.7.1/images/animation-assign.png differ diff --git a/website/versioned_docs/version-0.7.1/images/animation-running.png b/website/versioned_docs/version-0.7.1/images/animation-running.png new file mode 100644 index 00000000..73c84ad7 Binary files /dev/null and b/website/versioned_docs/version-0.7.1/images/animation-running.png differ diff --git a/website/versioned_docs/version-0.7.1/images/animationexportblender.png b/website/versioned_docs/version-0.7.1/images/animationexportblender.png new file mode 100644 index 00000000..da655385 Binary files /dev/null and b/website/versioned_docs/version-0.7.1/images/animationexportblender.png differ diff --git a/website/versioned_docs/version-0.7.1/images/animationexportblenderStandalone.png b/website/versioned_docs/version-0.7.1/images/animationexportblenderStandalone.png new file mode 100644 index 00000000..77666c05 Binary files /dev/null and b/website/versioned_docs/version-0.7.1/images/animationexportblenderStandalone.png differ diff --git a/website/versioned_docs/version-0.7.1/images/asset-browser-folder.png b/website/versioned_docs/version-0.7.1/images/asset-browser-folder.png new file mode 100644 index 00000000..6f0406ce Binary files /dev/null and b/website/versioned_docs/version-0.7.1/images/asset-browser-folder.png differ diff --git a/website/versioned_docs/version-0.7.1/images/asset-browser-model.png b/website/versioned_docs/version-0.7.1/images/asset-browser-model.png new file mode 100644 index 00000000..7b293ec8 Binary files /dev/null and b/website/versioned_docs/version-0.7.1/images/asset-browser-model.png differ diff --git a/website/versioned_docs/version-0.7.1/images/asset-browser-usdc-file.png b/website/versioned_docs/version-0.7.1/images/asset-browser-usdc-file.png new file mode 100644 index 00000000..e6d2f0cb Binary files /dev/null and b/website/versioned_docs/version-0.7.1/images/asset-browser-usdc-file.png differ diff --git a/website/versioned_docs/version-0.7.1/images/camera.png b/website/versioned_docs/version-0.7.1/images/camera.png new file mode 100644 index 00000000..4fdc106c Binary files /dev/null and b/website/versioned_docs/version-0.7.1/images/camera.png differ diff --git a/website/versioned_docs/version-0.7.1/images/demogame-noeditor.png b/website/versioned_docs/version-0.7.1/images/demogame-noeditor.png new file mode 100644 index 00000000..d0a39e9e Binary files /dev/null and b/website/versioned_docs/version-0.7.1/images/demogame-noeditor.png differ diff --git a/website/versioned_docs/version-0.7.1/images/editor-animation.png b/website/versioned_docs/version-0.7.1/images/editor-animation.png new file mode 100644 index 00000000..d54a8c8e Binary files /dev/null and b/website/versioned_docs/version-0.7.1/images/editor-animation.png differ diff --git a/website/versioned_docs/version-0.7.1/images/editorscreenshot.png b/website/versioned_docs/version-0.7.1/images/editorscreenshot.png new file mode 100644 index 00000000..7f78a96d Binary files /dev/null and b/website/versioned_docs/version-0.7.1/images/editorscreenshot.png differ diff --git a/website/versioned_docs/version-0.7.1/images/engine-assetbrowser.png b/website/versioned_docs/version-0.7.1/images/engine-assetbrowser.png new file mode 100644 index 00000000..c58c536c Binary files /dev/null and b/website/versioned_docs/version-0.7.1/images/engine-assetbrowser.png differ diff --git a/website/versioned_docs/version-0.7.1/images/engine-consolelog.png b/website/versioned_docs/version-0.7.1/images/engine-consolelog.png new file mode 100644 index 00000000..767e792c Binary files /dev/null and b/website/versioned_docs/version-0.7.1/images/engine-consolelog.png differ diff --git a/website/versioned_docs/version-0.7.1/images/engine-editor-startup.png b/website/versioned_docs/version-0.7.1/images/engine-editor-startup.png new file mode 100644 index 00000000..52519a1e Binary files /dev/null and b/website/versioned_docs/version-0.7.1/images/engine-editor-startup.png differ diff --git a/website/versioned_docs/version-0.7.1/images/engine-gizmo.png b/website/versioned_docs/version-0.7.1/images/engine-gizmo.png new file mode 100644 index 00000000..0faa3669 Binary files /dev/null and b/website/versioned_docs/version-0.7.1/images/engine-gizmo.png differ diff --git a/website/versioned_docs/version-0.7.1/images/engine-hdr.png b/website/versioned_docs/version-0.7.1/images/engine-hdr.png new file mode 100644 index 00000000..273b3854 Binary files /dev/null and b/website/versioned_docs/version-0.7.1/images/engine-hdr.png differ diff --git a/website/versioned_docs/version-0.7.1/images/engine-inspector.png b/website/versioned_docs/version-0.7.1/images/engine-inspector.png new file mode 100644 index 00000000..bd778f25 Binary files /dev/null and b/website/versioned_docs/version-0.7.1/images/engine-inspector.png differ diff --git a/website/versioned_docs/version-0.7.1/images/engine-lights.png b/website/versioned_docs/version-0.7.1/images/engine-lights.png new file mode 100644 index 00000000..a1883304 Binary files /dev/null and b/website/versioned_docs/version-0.7.1/images/engine-lights.png differ diff --git a/website/versioned_docs/version-0.7.1/images/engine-materials.png b/website/versioned_docs/version-0.7.1/images/engine-materials.png new file mode 100644 index 00000000..1f813dfc Binary files /dev/null and b/website/versioned_docs/version-0.7.1/images/engine-materials.png differ diff --git a/website/versioned_docs/version-0.7.1/images/engine-post-processing.png b/website/versioned_docs/version-0.7.1/images/engine-post-processing.png new file mode 100644 index 00000000..3e3f1f32 Binary files /dev/null and b/website/versioned_docs/version-0.7.1/images/engine-post-processing.png differ diff --git a/website/versioned_docs/version-0.7.1/images/engine-scenegraph.png b/website/versioned_docs/version-0.7.1/images/engine-scenegraph.png new file mode 100644 index 00000000..51e6e51a Binary files /dev/null and b/website/versioned_docs/version-0.7.1/images/engine-scenegraph.png differ diff --git a/website/versioned_docs/version-0.7.1/images/enginethumbnail.jpg b/website/versioned_docs/version-0.7.1/images/enginethumbnail.jpg new file mode 100644 index 00000000..882b7a07 Binary files /dev/null and b/website/versioned_docs/version-0.7.1/images/enginethumbnail.jpg differ diff --git a/website/versioned_docs/version-0.7.1/images/gamedemoscreenshot.png b/website/versioned_docs/version-0.7.1/images/gamedemoscreenshot.png new file mode 100644 index 00000000..7f78a96d Binary files /dev/null and b/website/versioned_docs/version-0.7.1/images/gamedemoscreenshot.png differ diff --git a/website/versioned_docs/version-0.7.1/images/gamescene1.png b/website/versioned_docs/version-0.7.1/images/gamescene1.png new file mode 100644 index 00000000..51251315 Binary files /dev/null and b/website/versioned_docs/version-0.7.1/images/gamescene1.png differ diff --git a/website/versioned_docs/version-0.7.1/images/howtoexport.png b/website/versioned_docs/version-0.7.1/images/howtoexport.png new file mode 100644 index 00000000..ccd4079c Binary files /dev/null and b/website/versioned_docs/version-0.7.1/images/howtoexport.png differ diff --git a/website/versioned_docs/version-0.7.1/images/howtoexportStandalone.png b/website/versioned_docs/version-0.7.1/images/howtoexportStandalone.png new file mode 100644 index 00000000..0858b82a Binary files /dev/null and b/website/versioned_docs/version-0.7.1/images/howtoexportStandalone.png differ diff --git a/website/versioned_docs/version-0.7.1/images/importassetbutton.png b/website/versioned_docs/version-0.7.1/images/importassetbutton.png new file mode 100644 index 00000000..a2ea71d9 Binary files /dev/null and b/website/versioned_docs/version-0.7.1/images/importassetbutton.png differ diff --git a/website/versioned_docs/version-0.7.1/images/importheader.gif b/website/versioned_docs/version-0.7.1/images/importheader.gif new file mode 100644 index 00000000..9a1b60a2 Binary files /dev/null and b/website/versioned_docs/version-0.7.1/images/importheader.gif differ diff --git a/website/versioned_docs/version-0.7.1/images/inspector.png b/website/versioned_docs/version-0.7.1/images/inspector.png new file mode 100644 index 00000000..0504eb30 Binary files /dev/null and b/website/versioned_docs/version-0.7.1/images/inspector.png differ diff --git a/website/versioned_docs/version-0.7.1/images/launchgame.gif b/website/versioned_docs/version-0.7.1/images/launchgame.gif new file mode 100644 index 00000000..f13e4908 Binary files /dev/null and b/website/versioned_docs/version-0.7.1/images/launchgame.gif differ diff --git a/website/versioned_docs/version-0.7.1/images/linkerissue.png b/website/versioned_docs/version-0.7.1/images/linkerissue.png new file mode 100644 index 00000000..192c9e5e Binary files /dev/null and b/website/versioned_docs/version-0.7.1/images/linkerissue.png differ diff --git a/website/versioned_docs/version-0.7.1/images/modelexportblender.png b/website/versioned_docs/version-0.7.1/images/modelexportblender.png new file mode 100644 index 00000000..bbfaa6c4 Binary files /dev/null and b/website/versioned_docs/version-0.7.1/images/modelexportblender.png differ diff --git a/website/versioned_docs/version-0.7.1/images/modelineditor.png b/website/versioned_docs/version-0.7.1/images/modelineditor.png new file mode 100644 index 00000000..951e24a5 Binary files /dev/null and b/website/versioned_docs/version-0.7.1/images/modelineditor.png differ diff --git a/website/versioned_docs/version-0.7.1/images/modelsriggedexportblender.png b/website/versioned_docs/version-0.7.1/images/modelsriggedexportblender.png new file mode 100644 index 00000000..1eb6740e Binary files /dev/null and b/website/versioned_docs/version-0.7.1/images/modelsriggedexportblender.png differ diff --git a/website/versioned_docs/version-0.7.1/images/render-component.png b/website/versioned_docs/version-0.7.1/images/render-component.png new file mode 100644 index 00000000..d15b36bf Binary files /dev/null and b/website/versioned_docs/version-0.7.1/images/render-component.png differ diff --git a/website/versioned_docs/version-0.7.1/images/script_component_selection.png b/website/versioned_docs/version-0.7.1/images/script_component_selection.png new file mode 100644 index 00000000..a3a65bcb Binary files /dev/null and b/website/versioned_docs/version-0.7.1/images/script_component_selection.png differ diff --git a/website/versioned_docs/version-0.7.1/images/script_open_in_xcode.png b/website/versioned_docs/version-0.7.1/images/script_open_in_xcode.png new file mode 100644 index 00000000..52976629 Binary files /dev/null and b/website/versioned_docs/version-0.7.1/images/script_open_in_xcode.png differ diff --git a/website/versioned_docs/version-0.7.1/images/script_properties.png b/website/versioned_docs/version-0.7.1/images/script_properties.png new file mode 100644 index 00000000..1a926da2 Binary files /dev/null and b/website/versioned_docs/version-0.7.1/images/script_properties.png differ diff --git a/website/versioned_docs/version-0.7.1/images/scripts_in_asset_browser.png b/website/versioned_docs/version-0.7.1/images/scripts_in_asset_browser.png new file mode 100644 index 00000000..002e8072 Binary files /dev/null and b/website/versioned_docs/version-0.7.1/images/scripts_in_asset_browser.png differ diff --git a/website/versioned_docs/version-0.7.1/images/setpathbutton.png b/website/versioned_docs/version-0.7.1/images/setpathbutton.png new file mode 100644 index 00000000..a2ea71d9 Binary files /dev/null and b/website/versioned_docs/version-0.7.1/images/setpathbutton.png differ diff --git a/website/versioned_docs/version-0.7.1/images/top_contributors/MioLogo.png b/website/versioned_docs/version-0.7.1/images/top_contributors/MioLogo.png new file mode 100644 index 00000000..dc0da303 Binary files /dev/null and b/website/versioned_docs/version-0.7.1/images/top_contributors/MioLogo.png differ diff --git a/website/versioned_docs/version-0.7.1/images/untoldenginewhite.png b/website/versioned_docs/version-0.7.1/images/untoldenginewhite.png new file mode 100644 index 00000000..b7440b8c Binary files /dev/null and b/website/versioned_docs/version-0.7.1/images/untoldenginewhite.png differ diff --git a/website/versioned_sidebars/version-0.7.1-sidebars.json b/website/versioned_sidebars/version-0.7.1-sidebars.json new file mode 100644 index 00000000..caea0c03 --- /dev/null +++ b/website/versioned_sidebars/version-0.7.1-sidebars.json @@ -0,0 +1,8 @@ +{ + "tutorialSidebar": [ + { + "type": "autogenerated", + "dirName": "." + } + ] +} diff --git a/website/versions.json b/website/versions.json index 51dfa5c8..d13b1e68 100644 --- a/website/versions.json +++ b/website/versions.json @@ -1,4 +1,5 @@ [ + "0.7.1", "0.7.0", "0.6.1" ]