diff --git a/manual/scripting/advanced/curve.md b/manual/scripting/advanced/curve.md index 28fc80eb..6314f024 100644 --- a/manual/scripting/advanced/curve.md +++ b/manual/scripting/advanced/curve.md @@ -1,8 +1,36 @@ # Curve -Engine API contains **BezierCurve<T>** and **LinearCurve<T>** types that can be very useful for animations driven via game code. For instance, you can expose the curve, edit it in the editor and then use to perform smooth animation. +Curves are a nice way to represent a value over a certain time. They have a lot of use cases, which include easing harsh transitions, defining different output values for different input values or a really fine tuned jump arc. -Here is sa sample script that shows how to use a curves: +## Curve types + +Flax engine provides the [`BezierCurve`](https://docs.flaxengine.com/api/FlaxEngine.BezierCurve-1.html) and [`LinearCurve`](https://docs.flaxengine.com/api/FlaxEngine.LinearCurve-1.html) classes to represent a **bezier-** or **linear curve**. Both come with an extensive API and editor, that allows you to quickly create, modify and utilize curves in your game. + +Both curve classes have a *type wildcard* ``, which you can use to make a curve represent different types, like for example `int`s, `float`s or even more complex ones like `Vector3` or `Color`. The curve editor will adapt based on which type the curve has. + +## Curve editor + +The curve editor provides an easy and intuitive way to edit and visualize a curve. + +### Adding and editing curve points + +You can pan the editor by moving the mouse while the right mouse button is pressed down. Double click anywhere in the curve editor to create a new curve point. To move a point, click and drag on it. You can double click an existing point to edit its values, like the time, value, or in the case of a bezier curve, the easing. + +To bring up a menu with more edit options, right click anywhere in the curve editor. It allows you to copy and paste a point, edit multiple curve points at once, reset the view or show the whole curve. The latter one can also be done by pressing *F* on your keyboard. + +### Curve presets + +It is also possible to apply a preset to your curve: Simply bring up the right click menu, go to "*Apply Preset*" and chose the preset you want to apply. + +### Resizing + +The curve editor can be resized horizontally by dragging on the bottom bar, right below its horizontal scrollbar. + +![Curve editor in use](media/curve-editor.gif) + +## Example + +This sample script will show you how to use curves: ```cs public class CustomCurve : Script @@ -25,11 +53,12 @@ public class CustomCurve : Script { var time = (Time.GameTime - start) * speed; - FloatCurve.Evaluate(out var floatValue, time); - Vector2Curve.Evaluate(out var vector2Curve, time); - Vector3Curve.Evaluate(out var vector3Curve, time); + // Access the curve's data + FloatCurve.Evaluate(out float floatValue, time); + Vector2Curve.Evaluate(out Vector2 vector2value, time); + Vector3Curve.Evaluate(out Vector3 vector3value, time); - Debug.Log(string.Format("At {0}: float: {1}, vec2: {2}, vec3: {3}", time, floatValue, vector2Curve, vector3Curve)); + Debug.Log($"At {time}: float: {floatValue}, vec2: {vector2value}, vec3: {vector3value}") } } ``` diff --git a/manual/scripting/advanced/media/curve-editor.gif b/manual/scripting/advanced/media/curve-editor.gif new file mode 100644 index 00000000..3e540237 Binary files /dev/null and b/manual/scripting/advanced/media/curve-editor.gif differ diff --git a/manual/scripting/advanced/media/tags-editor.png b/manual/scripting/advanced/media/tags-editor.png index ac2d1b12..3681d1af 100644 Binary files a/manual/scripting/advanced/media/tags-editor.png and b/manual/scripting/advanced/media/tags-editor.png differ diff --git a/manual/scripting/advanced/tags.md b/manual/scripting/advanced/tags.md index 3b6084c5..3f14783f 100644 --- a/manual/scripting/advanced/tags.md +++ b/manual/scripting/advanced/tags.md @@ -1,22 +1,42 @@ # Tags -Gameplay tag that represents a hierarchical name of the form `X.Y.Z` (namespaces separated with a dot). Tags are defined in project [LayersAndTagsSettings](../../editor/game-settings/layers-and-tags-settings.md) asset but can be also created from code. +Flax has the concept of **tags**, which are can be used to mark an actor as part of a group (not to be confused with [Static Flags](https://docs.flaxengine.com/api/FlaxEngine.StaticFlags.html) or [Layers](https://docs.flaxengine.com/manual/editor/game-settings/layers-and-tags-settings.html)) or to track state by using the **tags** as a way to represent booleans. -Scripting API contains the structure `Tag` which holds index of the tag in a global `Tags.List` array. Tags comparison is very fast (`int32` compare), also single tag uses very little memory (4 bytes). Scripting API `Tags` contains utilities for using tag lists such as `HasTag`/`HasTagExact`/`HasAny`/`HasAnyExact`/`HasAll`/`HasAllExact` which use an array of tags (`Tag[]` in C#, `Array` in C++). +## Tags in Flax Engine + +In case you are not familiar with what a **tag** is in the context of Flax Engine, similar terms you might recognize are "*label*", "*keyword*", "*marker*" or "*identifier*". + +They are represented in a hierarchical form as `X.Y.Z` (**tags** separated with a dot) and can be defined in a Flax project's [LayersAndTagsSettings](../../editor/game-settings/layers-and-tags-settings.md) settings, or be created from code. + +As mentioned before, they are most commonly used to tag actors, but it is also possible to have an array of **tags** anywhere in your code, without the need for an *Actor* that holds the **tags**. ## Actor Tags -Every actor contains list of tags (`Actor.Tags`) and various utilities for quick checking for a tag (`Actor.HasTag`). Actors can be marked with specific tags to be used by different gameplay systems. For example, player rigidbody and collider can be marked with a tag `Player` to distinguish them when processing collision events or when calculating hit damage in a shooter game. +Every *Actor* contains a list of **tags** ([`Actor.Tags`](https://docs.flaxengine.com/api/FlaxEngine.Actor.html#FlaxEngine_Actor_Tags)) and an utility method for quick checking for a **tag** on the *Actor* with [`Actor.HasTag`](https://docs.flaxengine.com/api/FlaxEngine.Actor.html#FlaxEngine_Actor_HasTag). + +These can be edited in the *Properties Panel* under the *General/Tags* section by clicking the three dot button (`...`). + +Actors can be marked with specific **tags** to be used by different gameplay systems. A common use case is to distinguish between objects on the same *Layer* when processing a physics result, like for example a raycast or collision. ## Tag Editor +[`Tag`](https://docs.flaxengine.com/api-cpp/Tag.html) and `Tag[]` are represented in the *Properties Panel* by a dedicated editor, which allows to edit and visualize them in a tree hierarchy. + +**Tags** can be added or removed by ticking or unticking the **tag**'s checkbox. Each **tag** has a plus (`+`) button on the right side which can be used to add a **sub-tag** to the current **tag**. Utility buttons on the top of the editor provide quick access to frequently used actions and the search field allows to filter **tags** by their name. It is also possible to quickly add a new **tag** in the format of `X.Y.Z` via the *Add Tag* section. + +The **tag** editor will display all of the selected tags in a list next to the `...` button. + ![Tags Editor](media/tags-editor.png) -`Tag` and `Tag[]` are displayed in the properties panel with the ability to edit them via tree hierarchy. Each tag can contain nested child nodes. Tags can be selected via checkboxes. Each node has a plus (`+`) button on the right side which can be used to add a sub-tag to the list. Utility buttons on the top can help to edit tags, and the search field allows filtering tags by name. +## Tags in the Scripting API + +The scripting API contains the struct [`Tag`](https://docs.flaxengine.com/api-cpp/Tag.html), which holds the index of the tag in a global `Tags.List` array. The [`Tags`](https://docs.flaxengine.com/api-cpp/Tags.html) class contains utilities for comparing two arrays of [`Tag`](https://docs.flaxengine.com/api-cpp/Tag.html)s, like checking the array has a specific tag ([`HasTag()`](https://docs.flaxengine.com/api-cpp/Tags.html#Tags_HasTag_const_Array_Tag____const_Tag_)) or to check if the first array has any of the [`Tag`](https://docs.flaxengine.com/api-cpp/Tag.html)s from the second array ([`HasAny()`](https://docs.flaxengine.com/api-cpp/Tags.html#Tags_HasAny_const_Array_Tag____const_Array_Tag____)). + +**Tag** comparison is very fast (`int32` comparison) and memory usage is only 4 bytes per **tag**. -## Scripting +## Code Example -Follow code examples below to use tags in your gameplay code: +Follow these code examples to use **tags** in your gameplay code: # [C#](#tab/code-csharp) ```cs @@ -28,7 +48,6 @@ public class MyScript : Script public Tag PlayerTag = Tags.Get("Player"); public Tag[] EnemyTags; - /// public override void OnEnable() { _trigger = Level.FindActor(Tags.Get("ObjectDetector")) as BoxCollider; @@ -36,7 +55,6 @@ public class MyScript : Script _trigger.TriggerEnter += OnTriggerEnter; } - /// public override void OnDisable() { if (_trigger) diff --git a/manual/scripting/code-examples/event-examples-script.cs b/manual/scripting/code-examples/event-examples-script.cs new file mode 100644 index 00000000..55fc3e5d --- /dev/null +++ b/manual/scripting/code-examples/event-examples-script.cs @@ -0,0 +1,38 @@ +using FlaxEngine; + +public class EventExamples : Script +{ + public override void OnEnable() + { + Debug.Log("Script is now enabled"); + } + + public override void OnDisable() + { + Debug.Log("Script is now disabled"); + } + + public override void OnStart() + { + // Init the position to (0, 0, 0) once after the script is created + Actor.Position = Vector3.Zero; + } + + public override void OnUpdate() + { + // Adjusts the actors rotation to look at the world origin every frame + Actor.LookAt(Vector3.Zero); + } + + public override void OnFixedUpdate() + { + // Move the actor up by 10 centimeters every fixed framerate frame + Actor.Position += new Vector3(0f, 10f, 0); + } + + public override void OnDebugDraw() + { + // Draw the actors bounds using DebugDraw + DebugDraw.DrawWireBox(Actor.Box, Color.Red, 0f); + } +} diff --git a/manual/scripting/code-examples/event-examples-ui-control.cs b/manual/scripting/code-examples/event-examples-ui-control.cs new file mode 100644 index 00000000..17f4d40f --- /dev/null +++ b/manual/scripting/code-examples/event-examples-ui-control.cs @@ -0,0 +1,29 @@ +using FlaxEngine; +using FlaxEngine.GUI; + +public class ControlExample : Control +{ + private bool outlineBlack; + + + + public override void Draw() + { + // Draw the control using Render2D + Rectangle rect = new Rectangle(Float2.Zero, Width, Height); + Render2D.FillRectangle(rect, IsMouseOver ? Color.Green : Color.Red); + Render2D.DrawRectangle(rect, outlineBlack ? Color.Black : Color.White); + } + + public override bool OnKeyDown(KeyboardKeys key) + { + // Check if the pressed key was the C key + if (key == KeyboardKeys.C) + { + outlineBlack = !outlineBlack; + return true; + } + + return false; + } +} diff --git a/manual/scripting/code-examples/events.cs b/manual/scripting/code-examples/events.cs deleted file mode 100644 index 25416a61..00000000 --- a/manual/scripting/code-examples/events.cs +++ /dev/null @@ -1,24 +0,0 @@ -using FlaxEngine; - -public class MyScript : Script -{ - public override void OnStart() - { - // Here you can add code that needs to be called when script is created, just before the first game update - } - - public override void OnEnable() - { - // Here you can add code that needs to be called when script is enabled (eg. register for events) - } - - public override void OnDisable() - { - // Here you can add code that needs to be called when script is disabled (eg. unregister from events) - } - - public override void OnUpdate() - { - // Here you can add code that needs to be called every frame - } -} \ No newline at end of file diff --git a/manual/scripting/code-examples/properties.cs b/manual/scripting/code-examples/properties.cs index 06c05bda..89ab3e5f 100644 --- a/manual/scripting/code-examples/properties.cs +++ b/manual/scripting/code-examples/properties.cs @@ -3,6 +3,6 @@ public class MyScript : Script { public float Field1 = 11; - public Color Field2 = Color.Yellow; + public Color Field2 = Color.LightBlue; public DirectionalLight Field3 { get; set; } } \ No newline at end of file diff --git a/manual/scripting/code-examples/properties.h b/manual/scripting/code-examples/properties.h index 6bf9c7ad..c6d2e701 100644 --- a/manual/scripting/code-examples/properties.h +++ b/manual/scripting/code-examples/properties.h @@ -11,7 +11,7 @@ API_CLASS() class GAME_API MyScript : public Script DECLARE_SCRIPTING_TYPE(MyScript); API_FIELD() float Field1 = 11; - API_FIELD() Color Field2 = Color::Yellow; + API_FIELD() Color Field2 = Color::LightBlue; API_FIELD() ScriptingObjectReference Field3; // [Script] diff --git a/manual/scripting/empty-actor.md b/manual/scripting/empty-actor.md index f24a67dd..c475673e 100644 --- a/manual/scripting/empty-actor.md +++ b/manual/scripting/empty-actor.md @@ -1,3 +1,3 @@ # Empty Actor -**Empty Actor** is an actor type that does not contain any dedicated role or in-build behavior. Instead of, it can be used to build a scene hierarchy, transform child objects or to implement a custom actor types using C# scripts (attached as components). Using Empty Actor can be very useful when working on larger projects. +**Empty Actor** is an actor type that does not have any dedicated role and contains no in-build behavior. It can be used as an empty object/ actor in the scene hierarchy, transform child actors or to implement a custom actor type using attached C# scripts. diff --git a/manual/scripting/engine-api.md b/manual/scripting/engine-api.md index 8e147f73..46ca5eac 100644 --- a/manual/scripting/engine-api.md +++ b/manual/scripting/engine-api.md @@ -3,9 +3,9 @@ Scripting API list for gameplay programming (available in both C++, C# and Visual Scripting): * `Engine` - global engine API * `Content` - assets loading and content management -* `Audio` - audio effects and music playback +* `Audio` - audio effects and playback * `DebugDraw` - debug shapes drawing -* `DebugLog` - debug log messages sending +* `Debug` - info, warning and error messages * `Globals` - global engine variables container * `Screen` - utility for game viewport management * `Time` - game ticking and time management @@ -13,7 +13,7 @@ Scripting API list for gameplay programming (available in both C++, C# and Visua * `Input` - user input reading, access and processing * `Level` - scene manager for actors and scene object lifetime handling * `Navigation` - pathfinding and navigation utilities for AI -* `Physics` - physical simulation manager +* `Physics` - physics simulation manager * `Platform` - low-level runtime platform implementation (memory access, system info, etc.) * `Clipboard` - system clipboard * `MessageBox` - native platform message box popup utility @@ -24,15 +24,14 @@ Scripting API list for gameplay programming (available in both C++, C# and Visua ## Objects Hierarchy -The diagram with a hierarchy of the main object types used in Flax. +This diagram shows the hierarchy of the main object types used in Flax. -In C# and Visual Scripting API `FlaxEngine.Object` type is mapped into `ScriptingObject`. +In the C# and Visual Scripting API, the `FlaxEngine.Object` type is mapped into `ScriptingObject`. ![Flax Object Hierarchy Diagram](media/objects-hierarchy.png) ## Engine Architecture -The diagram below shows the simplified architecture of the engine and editor. +The diagram below shows the simplified architecture of the engine and the editor. ![Flax Engine Architecture](media/engine-architecture.png) - diff --git a/manual/scripting/events.md b/manual/scripting/events.md index 1715b3e9..8a119785 100644 --- a/manual/scripting/events.md +++ b/manual/scripting/events.md @@ -1,68 +1,97 @@ # Script events -Scripts in Flax does not work like the traditional programs where code runs continuously in a loop until end. -Instead, Flax calls declared in script functions to handle specific game events like update or physics collision. -These functions are called **event functions** because they are executed by Flax in response to events that occur during gameplay. Using these function allows you to implement gameplay logic and handle different situations inside your game. +Programming using scripts in Flax does not work like traditional programs, where code runs continuously in a loop until the program is exited. + +Instead, Flax calls different functions in `Script`s to handle game and editor events like the main update loop (`OnUpdate()`) or user input. These functions are called **event functions**, **events** or **callbacks**, because they are executed by Flax in response to events that have occurred. ## Examples +Example for `Script`: + # [C#](#tab/code-csharp) -[!code-csharp[Example1](code-examples/events.cs)] +[!code-csharp[Example1](code-examples/event-examples-script.cs)] # [C++](#tab/code-cpp) [!code-cpp[Example2](code-examples/events.h)] *** +
+Example for a custom UI `Control`: + +# [C#](#tab/code-csharp-ui) +[!code-csharp[Example3](code-examples/event-examples-ui-control.cs)] +*** + ## Event functions -The following table lists all the available event functions to override from the base **Script** class. +The following table lists all the available event functions to override from the base `Script` class. > [!TIP] -> You don't have to call the base class methods if you script inherits directly from Script type. The default implementations are empty. +> The default implementations of these methods are empty, so no need to call the base implementation if you script inherits directly from the `Script` type. | Event | Description | |--------|--------| -| **void OnAwake()** | Called after the object is loaded to initialize it. Before the enabling it or calling start (including any other scene objects). | -| **void OnEnable()** | Called when object becomes enabled and active. | -| **void OnDisable()** | Called when object becomes disabled and inactive. | -| **void OnDestroy()** | Called before the object will be destroyed. | -| **void OnStart()** | Called when a script is enabled just before any of the Update methods is called for the first time. | -| **void OnUpdate()** | Called every frame if object is enabled (C++ scripts need to set `_tickUpdate=true` in constructor). | -| **void OnLateUpdate()** | Called every frame (after *Update*) if object is enabled (C++ scripts need to set `_tickLateUpdate=true` in constructor). | -| **void OnFixedUpdate()** | Called every fixed framerate frame if object is enabled (C++ scripts need to set `_tickFixedUpdate=true` in constructor). | -| **void OnLateFixedUpdate()** | Called every fixed framerate frame (after *FixedUpdate*) if object is enabled (C++ scripts need to set `_tickLateFixedUpdate=true` in constructor). | -| **void OnDebugDraw()** | Called during drawing debug shapes in editor. Use [DebugDraw](https://docs.flaxengine.com/api/FlaxEngine.DebugDraw.html). | -| **void OnDebugDrawSelected()** | Called during drawing debug shapes in editor when the object is selected. Use [DebugDraw](https://docs.flaxengine.com/api/FlaxEngine.DebugDraw.html). | - -## Order of execution for event functions - -Script events are invoked in the following order: +| `void OnAwake()` | Called after the object is loaded but before `OnStart()` or `OnEnable()`. Can be used to initialize it. | +| `void OnEnable()` | Called when object becomes enabled and active, before any of the update methods will be called. | +| `void OnDisable()` | Called when object becomes disabled and inactive. | +| `void OnDestroy()` | Called before the object will be destroyed. | +| `void OnStart()` | Called when a script is enabled, just before `OnEnable()` is called. | +| `void OnUpdate()` | Called every frame if the object is enabled (C++ scripts need to set `_tickUpdate = true` in their constructor). | +| `void OnLateUpdate()` | Called every frame (after `OnUpdate()`) if the object is enabled (C++ scripts need to set `_tickLateUpdate = true` in their constructor). | +| `void OnFixedUpdate()` | Called every fixed framerate frame if object is enabled (C++ scripts need to set `_tickFixedUpdate = true` in their constructor). | +| `void OnLateFixedUpdate()` | Called every fixed framerate frame (after `OnFixedUpdate()`) if the object is enabled (C++ scripts need to set `_tickLateFixedUpdate = true` in their constructor). | +| `void OnDebugDraw()` | Called during the drawing of debug shapes in the editor. See [DebugDraw](https://docs.flaxengine.com/api/FlaxEngine.DebugDraw.html). | +| `void OnDebugDrawSelected()` | Called during the drawing of debug shapes in editor if the object is selected. See [DebugDraw](https://docs.flaxengine.com/api/FlaxEngine.DebugDraw.html). | + +## Order of execution + +This diagram shows the invocation order of all script events: ![Script Events Order](media/script-events.png) +### Update callbacks + +Flax supports performing the games update, physics update and drawing at different update-/ frame rates. This means that gameplay logic should not depend on `Script`s events like `OnUpdate()`, `OnFixedUpdate()` and `OnDebugDraw()` being called in a deterministic order. + +`OnUpdate()` is called during the game update, which is then followed by `OnLateUpdate()`. + +During physics update the engine invokes `OnFixedUpdate()` and then `OnLateFixedUpdate()`. + +During rendering, the engine will invoke `OnDebugDraw()` and `OnDebugDrawSelected()`. + ### Initialization -Every created and added to *Actor* script receives **OnAwake**. If Script and its parent are active in the hierarchy then **OnStart** and **OnEnable** are being called (on game start or object spawn). Otherwise, this call is postponed until someone enables that script. +Every script that was attached to an *Actor* receives the `OnAwake()` event after it was created. -Events OnAwake and OnStart can be called only once on a script. OnStart is always called before the first OnEnable. All scripts receive OnAwake first, before BeginPlay-phrase starts that enables the scripts. In general, OnAwake should be used to initialize the object itself (eg. setup game system manager or pre-allocate memory). Then OnStart/OnEnable should be utilized for cross-object interactions (eg. register to a game manager, cache player scripts, etc.). +If the script and the actor it is attached to are active in the scene hierarchy, `OnEnable()` will be called immediately, while `OnStart()` will be called right before the first call to `OnEnable()`. -### Game Logic +If the actor or script are disabled, these calls are postponed until the actor and script are enabled. -Engine main loop update is highly configurable and supports performing the game update, physics update and drawing at different framerates. This means that update, fixed update, and a draw might be desynchronized and not called in the same order. Event **OnUpdate** is called during the game update, then is followed by **OnLateUpdate**. During physics update engine invokes **OnFixedUpdate** and **OnLateFixedUpdate**. During rendering engine can invoke **OnDebugDraw** and **OnDebugDrawSelected** (used by the editor). +Note that `OnAwake()` and `OnStart()` are only called once per script instance. + +`OnAwake()` should be used to initialize the object itself (eg. to perform setup or pre-allocate memory). `OnStart()`/ `OnEnable()` should be used for cross-object interactions (eg. registering the object to a game manager, caching player scripts). ### Deinitialization -On game end all scripts are disabled and **OnDisable** event is called when removing the object from gameplay. Then during actual object destruction, the **OnDestroy** is invoked. Also, if the script becomes inactive (eg. someone disables it or one of its parents in its hierarchy) then the engine invokes **OnDisable**. The disabled script can be activated again and receive *OnEnable* to begin being part of the gameplay logic. +When the game ends, all scripts are disabled and the `OnDisable()` event is called when the object is removed from gameplay. Then, during the actual object destruction, the `OnDestroy()` callback is invoked. + +If the script becomes inactive (eg. it or the actor it is attached to are disabled), the engine invokes `OnDisable()`. The disabled script can be re-activated, receiving a call to `OnEnable()` and all subsequent calls to `OnUpdate()` and other update methods again. + +The `OnDestroy()` event can be called only once per a script. Flax does not use the script instance anymore after the `OnDestroy()` event was invoked. + +### Some Notes On Initialization and Deinitialization + +Initialization events (`OnAwake()`, `OnEnable()`, `OnStart()`) and deinitialization events (`OnDisable()`, `OnDestroy()`) are always called for the object that is being created or destroyed first, then further down into the hierarchy. -Event OnDestroy can be called only once on a script. Flax does not use the script anymore after OnDestroy event invocation. +This means that scripts can try to access child actors and their data while they might not be initialized yet. -### Events in Editor +However, you can still use initialization events to add child actors or scripts to the actor. Flax will invoke initialization events for the newly created scripts/ actors when required. -Flax does not invoke any script events during `edit-time` (when the scene is loaded and the user modifies it) except **OnDebugDraw** and **OnDebugDrawSelected**. Only when in-build play mode starts the actual game logic is being simulated. However, if the game script wants to receive events during editing it can be marked with `[ExecuteInEditMode]` attribute. Then all events will be called normally. +All the other script events are called when a script is already deserialized and has valid data ready to use, with the exception being `OnAwake()`. It only waits for the object itself to be ready - other objects might be not initialized yet. -### Order +## Events in Editor -The Script event's invocation order depends on the event type. Gameplay logic events (update, fixed update and debug drawing) are called in non-stable order so gameplay logic should not depend on it. Initialization events (awake, enable, start) and deinitialization events (disable, destroy) are always called for the parent objects first, then further down into the hierarchy. This means that script in parent actor can query the child actors' objects and scripts but they might not be initialized yet. +Flax by default does not invoke any script events during *edit-time* (when the scene is loaded in editor), except `OnDebugDraw()` and `OnDebugDrawSelected()`. -However, you can still use initialization events to add new objects as child actors/scripts because Flax will invoke initialization for them when required. +Only when the game is running, for example in in-editor play mode, will the actual game logic be simulated. -All script events are called when a script is already deserialized and has valid data ready to use (exception is OnAwake which relies to a single object readiness - other objects might be not initialized yet). +If you want a `Script` to receive events during editing, it can be marked with the `[ExecuteInEditMode]` attribute. Then all events will be called normally during *edit-time*, just like the game was actually running. \ No newline at end of file diff --git a/manual/scripting/index.md b/manual/scripting/index.md index 74d10921..681f0875 100644 --- a/manual/scripting/index.md +++ b/manual/scripting/index.md @@ -1,44 +1,64 @@ # Scripting Games -![Scripting](media/title.jpg) +![Scripting](media/title.png) -The most important part of every game are **Scripts**. Creating chunks of code that handle game events, respond to user input, and control objects is an essential ingredient in all games. In short, scripts make games interactive by adding gameplay. It applies to both small and huge production. This documentation section covers the most important parts of the scripting pipeline and helps with starting the game programming. +A **Script** is what implements logic for your game. Creating pieces of code that handle game events, respond to user input and control objects is an essential ingredient in the recipe for a game of all sorts. -Flax supports **C#**, **C++** and **Visual** scripting. The mix of those three languages is highly integrated into the engine as it's written in those languages (engine is C++, editor is C#). +This documentation section covers the most important parts of the scripting pipeline and helps you with getting started with scripting in Flax Engine. > [!Note] -> Explaining C#, C++ and vector math is out of the scope of this documentation. +> Explaining the basics of C# and C++ programming, as well as vector math is out of the scope of this documentation. -## Code Modules +### Scripting Languages -Important concepts related to programming in Flax are **binary modules**. Binary modules are compiled source code libraries that can reference other modules (eg. Editor, Graphics, or plugins). +Flax supports **C#**, **C++** and **Visual Scripting**. Every one of those three languages is highly integrated into the engine, as the engine is written in C++, while the editor is C#, which Visual Scripting also relies on. -In most cases, the main game code is in the module named `` or named `Game` located in `Source` folder (eg. `Source/Game`). That's the place where you can add new scripts so build tool will compile them. For more, advanced uses game can contain multiple modules and have code split for better organization (as for example engine does - it's made of multiple modules working together). For instance, you can create an editor-only module and use its code only in the Editor. +## Code/ Binary Modules -To learn more about build tools and infrastructure see [Flax.Build](../editor/flax-build/index.md) utility documentation. +An important concept related to programming in Flax are **binary modules**. Binary modules are compiled source code libraries that can be referenced in other modules (eg. Editor, Graphics, or plugins). + +In most cases, the main code of your game will be in the module named `Game` (automatically created by Flax in every new project). It is located in the `Source` folder at `Source/Game`. + +The `Game` folder/ module is the place where your games scripts live. They will be automatically compiled by the build tool as soon as it detects a new script or changes in an existing one. + +To learn more about build tools and infrastructure, see the [Flax.Build](../editor/flax-build/index.md) documentation. + +For more advanced uses, your Flax project can contain multiple modules and have code split between them for better organization (the engine does that for example - it is made of multiple modules all working together). ## C# Scripting -You can write scripts in **C#** and add them to scene objects. To learn more about it see the pages in this section. Most of the documentation related to scripting covers C# to implement various gameplay logic. If you need help with learning C# see [this page](http://www.letmegooglethat.com/?q=C%23+tutorial). +In Flax you can write scripts in **C#** (amongst other languages) and attach them to `Actor`s in your scene. Most of the documentation related to scripting covers C# scripting. + +If you need help with learning C# itself, that is unfortunately out of the scope of this documentation, but you can easily find some beginner tutorials online. Flax uses [.NET](https://dotnet.microsoft.com/en-us) to load, compile and execute C# scripts. -Currently the newest **C# 12** version is fully supported. Flax Editor requires [.NET SDK 8](https://dotnet.microsoft.com/en-us/download/dotnet/8.0) to be installed on a system. +Currently, the newest **C# 12** version is fully supported. The Flax Editor requires [.NET SDK 8](https://dotnet.microsoft.com/en-us/download/dotnet/8.0) to be installed. -If you want to use custom .NET libraries use build scripts to reference them as [shown here](tutorials/use-third-party-library.md). +If you want to use third party .NET libraries, you can use build scripts to reference them in your project (as [shown here](tutorials/use-third-party-library.md)). ## C++ Scripting -Flax supports native **C++** scripting with direct access to whole engine API. C++ scripts can be created side-by-side with C# scripts and expose own types/functions/properties via automatic bindings as decscribed [here](../editor/flax-build/api-tags.md). To write and use C\+\+ code engine headers and platform toolset are requried. +Flax supports native **C++** scripting with direct access to whole engine API. -To start native scripting in C\+\+ see the related documentation [here](cpp/index.md). +C++ scripts can be created side-by-side with C# scripts and expose their own types, functions and properties via automatic binding generation (more about that [here](../editor/flax-build/api-tags.md)). + +To write and use C++ code, engine headers and platform toolset are required. + +To start native scripting in C++ see the related documentation [here](cpp/index.md). ## Visual Scripting -Flax supports **Visual** scripting with fully-featured Editor tools for creating, using and debugging Visual Scripts. Visual Scripts can inherit from C++ or C# classes (eg. custom Actor or Script) to provide more logic and data. Visual Scripting is very light-weight and extensible solution for prototyping games especially boosting the rapid development. +Flax supports **Visual Scripting** with fully-featured Editor tools for creating and debugging Visual Scripts. + +As opposed to C# or C++ scripts, Visual Scripts can not be created in the `Source/Game` folder and live in your projects `/Content` folder instead. + +They can inherit from C++ or C# classes (eg. a custom Actor or Script). and access the whole engine API, as well as any existing C# or C++ code. Of course you can also define custom functions, classes and variables inside of Visual Scripts. + +It's a very light-weight and extensible solution for prototyping games, but can also be used by artists and other people with no or few coding experience to make a whole game. -Visual Scripts can access to whole engine API and the game code. Visual Scripts can be created side-by-side with C# and C++ scripts to expose own functions/properties. Also, Visual Scripting doesn't requrie any additional tools nor compiler as it's hot-reloading in Editor without any processing to provide even more robust development. +It does also not require any additional tooling or compiler, since it will hot-reload in editor to provide an even more robust and easy development. -To start visual scripting see the related documentation [here](visual/index.md). +To start visual scripting, see the related documentation [here](visual/index.md). ## In this section diff --git a/manual/scripting/media/create-new-script.gif b/manual/scripting/media/create-new-script.gif new file mode 100644 index 00000000..3598c850 Binary files /dev/null and b/manual/scripting/media/create-new-script.gif differ diff --git a/manual/scripting/media/editor-display-attribute.png b/manual/scripting/media/editor-display-attribute.png new file mode 100644 index 00000000..c0e969e1 Binary files /dev/null and b/manual/scripting/media/editor-display-attribute.png differ diff --git a/manual/scripting/media/editor-order-attribute.png b/manual/scripting/media/editor-order-attribute.png new file mode 100644 index 00000000..d930ef2c Binary files /dev/null and b/manual/scripting/media/editor-order-attribute.png differ diff --git a/manual/scripting/media/items-in-properties-panel.png b/manual/scripting/media/items-in-properties-panel.png new file mode 100644 index 00000000..ee51a9fd Binary files /dev/null and b/manual/scripting/media/items-in-properties-panel.png differ diff --git a/manual/scripting/media/new-script.gif b/manual/scripting/media/new-script.gif deleted file mode 100644 index ad22c6d0..00000000 Binary files a/manual/scripting/media/new-script.gif and /dev/null differ diff --git a/manual/scripting/media/read-only-attribute.png b/manual/scripting/media/read-only-attribute.png new file mode 100644 index 00000000..73aeda93 Binary files /dev/null and b/manual/scripting/media/read-only-attribute.png differ diff --git a/manual/scripting/media/script-reoder-set-reference.gif b/manual/scripting/media/script-reoder-set-reference.gif new file mode 100644 index 00000000..dddf2050 Binary files /dev/null and b/manual/scripting/media/script-reoder-set-reference.gif differ diff --git a/manual/scripting/media/script-reorder-with-drag.gif b/manual/scripting/media/script-reorder-with-drag.gif deleted file mode 100644 index 494096c9..00000000 Binary files a/manual/scripting/media/script-reorder-with-drag.gif and /dev/null differ diff --git a/manual/scripting/media/script-settings.png b/manual/scripting/media/script-settings.png index 3fa13aa0..e553e551 100644 Binary files a/manual/scripting/media/script-settings.png and b/manual/scripting/media/script-settings.png differ diff --git a/manual/scripting/media/script-ui.png b/manual/scripting/media/script-ui.png deleted file mode 100644 index 6edea2ad..00000000 Binary files a/manual/scripting/media/script-ui.png and /dev/null differ diff --git a/manual/scripting/media/scripts-workspace.jpg b/manual/scripting/media/scripts-workspace.jpg deleted file mode 100644 index 86fa5ed4..00000000 Binary files a/manual/scripting/media/scripts-workspace.jpg and /dev/null differ diff --git a/manual/scripting/media/scripts-workspace.png b/manual/scripting/media/scripts-workspace.png new file mode 100644 index 00000000..cae071f2 Binary files /dev/null and b/manual/scripting/media/scripts-workspace.png differ diff --git a/manual/scripting/media/title.jpg b/manual/scripting/media/title.jpg deleted file mode 100644 index 70850651..00000000 Binary files a/manual/scripting/media/title.jpg and /dev/null differ diff --git a/manual/scripting/media/title.png b/manual/scripting/media/title.png new file mode 100644 index 00000000..f6905364 Binary files /dev/null and b/manual/scripting/media/title.png differ diff --git a/manual/scripting/new-script.md b/manual/scripting/new-script.md index 6d1abab7..37ad99dd 100644 --- a/manual/scripting/new-script.md +++ b/manual/scripting/new-script.md @@ -1,42 +1,54 @@ # Create and use a script +> [!Note] +> If you want to use C++ scripting you can find out how [here](cpp/index.md). + Scripts in Flax are written in the **C#** language (source files with extension `.cs`). -If you want to create a C++ Script you can find out how [here](cpp/index.md). -To provide better organization in a project workspace script files are located in the `Source/` directory. -In that way scripts are separated from the assets which reduces mess and makes it easier to work with project sources. -Flax Editor creates a solution file (`.sln`) and C# projects (`.csproj`) for game scripts and editor plugins. +For organizational purposes, script files are located in the `Source/` directory of your Flax project. +This nicely separates scripts (logic) from assets (content). -![Workspace](media/scripts-workspace.jpg) +The editor creates a solution (`.sln`) file as well as C# projects (`.csproj`) for game scripts and editor plugins. -> [!Note] -> We recommend using Visual Studio for code editing with [Flax Engine Tools for Visual Studio](https://marketplace.visualstudio.com/items?itemName=Flax.FlaxVS) installed. +![Workspace](media/scripts-workspace.png) + +In Flax, like in many other engines, scripts are **attached to actors**. Every actor can contain an unlimited amount of individual scripts (including multiple instances of the same script type). This means that the script's lifetime is related to that of the actor. # Create a script -1. In the *Content* window, Navigate to '<project_name>/Source/<game_module_name>'. -
![Step 1](media/new-script.gif) - -2. Double-click to open the script. Wait for Flax to open your IDE, which will then open the new script. +1. In the *Content* window, navigate to the *Game module folder* located at *<project_name>/Source/<game_module_name>*. +By default that will be `Source/Game`. + +2. Right click in any empty space. Click on `New/C#/C# Script` in the context menu that has appeared to create a new C# script. There are many other templates available, but `C# Script` is the one you will use most commonly. +
The new script will automatically enter renaming mode after you create it, so you can just type in a name. It is recommended that you give the new script a name, since some of the templates will use as a class name. +
![Step 2](media/create-new-script.gif) -Once opened this is what the script file will look like. -[!code-csharp[Example1](code-examples/events.cs)] +3. Double-click the newly created script. Flax will now open it in your IDE. If your IDE isn't open yet, Flax will do that for you as well. + +Congratulations! You have now created a new script. Follow this manual to learn how to use a script in your Flax Project or continue on your own if you already know that part. Happy coding :) # Use a script -Scripts are **attached to actors**. Every actor can contain an unlimited amount of individual scripts (including multiple instances of the same script type). This means that the script's lifetime is related to that of the actor's and the scene's lifetime. For instance, if you load a scene, the scripts attached to the objects in that scene also will be loaded. +1. Select the actor you want to add a script to. +2. Drag and drop the script into the **Drag scripts here** area that shows in the *Properties* panel. + +Alternatively you can also: +- Drag a script over an actor in the *Scene* panel. +- Use the "Add script" button in the *Scripts* section shown in the *Properties* panel of the selected actor. +- Use the `AddScript()` method of an `Actor` (not recommended if you just want to attach and use a script normally). + +
![Reorder Script](media/create-new-script.gif) + +Each script is displayed collapsible panel within the `Scripts` section of the *Properties* panel. -1. Select an actor to add script to it (note label *Drag scripts here* in **Scripts** group in *Properties* window) -2. Drag and drop the script into the **Drag scripts here** area -3. Script is ready (sample script with 3 public fields) -
![Step 1](media/attach-script.gif) +It will show public properties and fields by default, but you can further control which members are visible in the *Properties* panel by using various attributes. -The Flax Editor shows public script properties and fields using a dedicated group (within `Scripts` group). Each script group header shows a script class type name, **settings button on the right** and **script toggle checkbox on the left**. You can disable or enable the script by using this checkbox. +Each script panel shows the scripts class type name and a **checkbox to toggle the scripts execution** and **`Enabled` state**. -To **remove**, **edit** or **reorder** a script use the **settings button** which shows a popup with various options. +To **remove**, **edit** or **reorder** a script, use the **settings button** on the right side of the script header, which shows a popup with various options. ![Script settings](media/script-settings.png) -You can also easily pick a reference to a script or reorder it. Simply click and drag the **three-bar icon button** as shown on a gif below: +You can also easily **pick a reference to a script or reorder it** by simply clicking and dragging the **three-bar icon** as shown on a gif below: -![Reorder Script](media/script-reorder-with-drag.gif) +![Reorder Script](media/script-reoder-set-reference.gif) diff --git a/manual/scripting/properties.md b/manual/scripting/properties.md index db9ab8df..ec8c3c63 100644 --- a/manual/scripting/properties.md +++ b/manual/scripting/properties.md @@ -1,6 +1,6 @@ # Script properties and fields -Every script can contain various fields and properties. By default Flax shows all **public fields and properties** in the *Properties* window so user may edit them (undo/redo is supported). +Every script can contain various fields and properties. By default, Flax shows all **public fields and properties** in the *Properties Panel*, allowing the user to modify them on a per script instance there. # Script @@ -9,39 +9,167 @@ Every script can contain various fields and properties. By default Flax shows al # [C++](#tab/code-cpp) [!code-cpp[Example2](code-examples/properties.h)] *** +
-![Script Properties](media/script-ui.png) +![Fields exposed to the Properties Panel](media/items-in-properties-panel.png) # Attributes -If you want to **hide** a public property or a field simply use [HideInEditor](https://docs.flaxengine.com/api/FlaxEngine.HideInEditorAttribute.html) attribute. +Attributes are a way to customize how a field or property will appear and behave in the *Properties Panel*. -# [C#](#tab/code-csharp) +This section will cover the most important attributes to help you get started. To learn more about the various attributes Flax provides or to get a full list of all of the available ones, see this [page](attributes.md). + +## Visibility + +If you want to **hide** a public property or field, simply put the [`[HideInEditor]`](https://docs.flaxengine.com/api/FlaxEngine.HideInEditorAttribute.html) attribute above it. + +# [C#](#tab/code-csharp-hide) ```cs [HideInEditor] -public float Field1 = 11; +public int MyPublicButHiddenInt = 11; ``` -# [C++](#tab/code-cpp) +# [C++](#tab/code-cpp-hide) ```cpp API_FIELD(Attributes="HideInEditor") -float Field1 = 11; +int MyPublicButHiddenInt = 11; ``` *** +
-If you **do not want to serialize** a public property or a field, use the [NoSerialize](https://docs.flaxengine.com/api/FlaxEngine.NoSerializeAttribute.html) attribute. +You can also make a private field or property visible by adding the [`[ShowInEditor]`](https://docs.flaxengine.com/api/FlaxEngine.ShowInEditorAttribute.html) attribute to it. -# [C#](#tab/code-csharp) +# [C#](#tab/code-csharp-show) +```cs +[ShowInEditor] +private int myPrivateButVisibleInt = 11; +``` +# [C++](#tab/code-cpp-show) +```cpp +API_FIELD(Attributes="ShowInEditor") +int myPrivateButVisibleInt = 11; +``` +*** +
+ +Visibility can also be controlled by other boolean fields or properties using the [`[VisibleIf]`](https://docs.flaxengine.com/api/FlaxEngine.VisibleIfAttribute.html) attribute. + +# [C#](#tab/code-csharp-visible-if) +```cs +private bool myBoolean = false; + +[VisibleIf("myBoolean")] // MyPublicButHiddenInt will be hidden since myBoolean is set to false +public int MyPublicButHiddenInt = 11; +``` +*** + +## Serialization + +If you **do not want to serialize** a field or property that would be otherwise serialized by default, use the [`[NoSerialize]`](https://docs.flaxengine.com/api/FlaxEngine.NoSerializeAttribute.html) attribute. + +# [C#](#tab/code-csharp-no-serialize) ```cs [NoSerialize] -public float Field1 = 11; +public int PublicButNotSerializedInt = 11; ``` -# [C++](#tab/code-cpp) +# [C++](#tab/code-cpp-no-serialize) ```cpp API_FIELD(Attributes="NoSerialize") -float Field1 = 11; +int PublicButNotSerializedInt = 11; +``` +*** +
+ +Of course you can also **serialize a property that would not be serialized** by default. To do that, simply apply the [`[Serialize]`](https://docs.flaxengine.com/api/FlaxEngine.SerializeAttribute.html) to it. + +# [C#](#tab/code-csharp-serialize) +```cs +[Serialize] +private int privateButSerializedInt = 11; +``` +# [C++](#tab/code-cpp-serialize) +```cpp +API_FIELD(Attributes="Serialize") +int privateButSerializedInt = 11; +``` +*** +
+ +To see when a property or field will be serialized by default, see [the documentation on serialization](serialization/index.md#serialization-rules). + +## Expose private members to Properties Panel + +It is very common that you need to expose a `private` field or property to the *Properties Panel*. In Flax you can achieve that by adding the [`[ShowInEditor]`](https://docs.flaxengine.com/api/FlaxEngine.ShowInEditorAttribute.html) and [`[Serialize]`](https://docs.flaxengine.com/api/FlaxEngine.SerializeAttribute.html) attributes to it. + +## Groups and custom names + +Flax supports displaying items in the *Properties Panel* in groups. To add a field or property to a group, use the [`[EditorDisplay]`](https://docs.flaxengine.com/api/FlaxEngine.EditorDisplayAttribute.html). It also allows you to show your property or field under a different name than the name it is declared as. + +# [C#](#tab/code-csharp-editor-display) +```cs +[EditorDisplay("My Group", "My custom name")] +public int MyGroupedIntWithCustomName = 11; +``` +# [C++](#tab/code-cpp-editor-display) +```cpp +API_FIELD(Attributes="EditorDisplay(\"My Group\", \"My custom name\")") +int MyGroupedIntWithCustomName = 11; ``` *** +
+![Custom Group in the Properties Panel](media/editor-display-attribute.png) + +If you want the group you declared to be expanded by default, you can add the [`[ExpandGroups]`](https://docs.flaxengine.com/api/FlaxEngine.ExpandGroupsAttribute.html) attribute to your property or field. + +## Order + +You can modify the order properties or fields appear in when shown in the *Properties Panel* by using the [`[EditorOrder]`](https://docs.flaxengine.com/api/FlaxEngine.EditorOrderAttribute.html). + +# [C#](#tab/code-csharp-editor-order) +```cs +[EditorOrder(1)] +public int MyFirstInt = 11; +[EditorOrder(0)] +public int MySecondInt = 11; +``` +# [C++](#tab/code-cpp-editor-order) +```cpp +API_FIELD(Attributes="EditorOrder(1)") +int MyFirstInt = 11; +API_FIELD(Attributes="EditorOrder(0)") +int MySecondInt = 11; +``` +*** +
+ +![Modified order of items in the Properties Panel](media/editor-order-attribute.png) + +Properties with a lower index will be displayed first. You can also use a negative index, which can be useful if you are exposing some properties or fields in a base class, but want to be able to start at index `0` again in any inherited class. + +Note that properties or fields that have the [`[EditorOrder]`](https://docs.flaxengine.com/api/FlaxEngine.EditorOrderAttribute.html) attributes attached will be displayed *before* any other properties or fields. + +## Read only + +Sometimes you may want to only show the value of a field or property in the *Properties Panel*, without a way to edit it. + +This can be be especially useful for debugging. + +To be able to do this, Flax provides the [`[ReadOnly]`](https://docs.flaxengine.com/api/FlaxEngine.ReadOnlyAttribute.html) attribute. + +# [C#](#tab/code-csharp-read-only) +```cs +[ReadOnly] +public int ReadOnlyInt = 11; +``` +# [C++](#tab/code-cpp-read-only) +```cpp +API_FIELD(Attributes="ReadOnly") +int ReadOnlyInt = 11; +``` +*** +
+ +![Read only attribute in the Properties Panel](media/read-only-attribute.png) -To learn more about using attributes see this [page](attributes.md). +## Combining attributes -To learn more about scripts serialization see this [page](serialization/index.md). +It is important to mention that often times you will have to combine multiple attributes to get the desired behavior (as seen in the ["Expose private members to Properties Panel" section](#expose-private-members-to-properties-panel)).