diff --git a/en/manual/game-studio/index.md b/en/manual/game-studio/index.md index c1d07fc5b..b7b61f617 100644 --- a/en/manual/game-studio/index.md +++ b/en/manual/game-studio/index.md @@ -15,7 +15,7 @@ Game Studio is also integrated with your Visual Studio projects, so you can seam ![Game Studio](../get-started/media/game-studio-main-interface.png) -The **asset editor** (A) is used to edit assets and scenes. Some asset types, such as scenes [scenes](create-a-scene.md), have dedicated editors where you can make complex changes to the asset. To open a dedicated editor (when available), double-click the asset or right-click it and select **Edit asset**. +The **asset editor** (A) is used to edit assets and scenes. Some asset types, such as [scenes](create-a-scene.md), have dedicated editors where you can make complex changes to the asset. To open a dedicated editor (when available), double-click the asset or right-click it and select **Edit asset**. The **Property Grid** (B) displays the properties of the asset or entity you select. You can edit the properties here. @@ -47,4 +47,4 @@ You can show and hide different parts of the Game Studio in the View menu. You c * [Edit prefabs](prefabs/edit-prefabs.md) * [Nested prefabs](prefabs/nested-prefabs.md) * [Override prefab properties](prefabs/override-prefab-properties.md) -* [World units](world-units.md) \ No newline at end of file +* [World units](world-units.md) diff --git a/en/manual/index.md b/en/manual/index.md index b07be0fc2..9e061ab13 100644 --- a/en/manual/index.md +++ b/en/manual/index.md @@ -10,6 +10,7 @@ These pages contain information about how to use Stride, an open-source C# game ## Latest documentation ### Recent updates +- New [Scripts - Gizmos](scripts/gizmos.md) - Description and example of the Flexible Processing system - New [ECS - Flexible Processing](engine/entity-component-system/flexible-processing.md) - Description and example of the Flexible Processing system - Updated [Linux - Setup and requirements](platforms/linux/setup-and-requirements.md) - Fedora OS option added - New [Scripts - Serialization](scripts/serialization.md) - Explanation of serialization diff --git a/en/manual/scripts/gizmos.md b/en/manual/scripts/gizmos.md new file mode 100644 index 000000000..be60d4c8a --- /dev/null +++ b/en/manual/scripts/gizmos.md @@ -0,0 +1,172 @@ +# Gizmos + +Intermediate +Programmer + +**Gizmos** are a tool which you can implement over your components to provide visual assistance for designers when manipulating component values. + +Here's an exhaustive example one could implement: +```cs +using Stride.Core; +using Stride.Core.Mathematics; +using Stride.Engine; +using Stride.Engine.Gizmos; +using Stride.Graphics; +using Stride.Graphics.GeometricPrimitives; +using Stride.Rendering; +using Stride.Rendering.Materials; +using Stride.Rendering.Materials.ComputeColors; + +// We will be implementing a Gizmo for the following class +public class MyScript : StartupScript +{ + +} + +// This attribute specifies to the engine that the following gizmo class is bound to 'MyScript', +// the game studio will pick that up and spawn an instance of that class for each 'MyScript' in the scene +[GizmoComponent(typeof(MyScript), isMainGizmo:false/*When true, only the first gizmo on an entity with true is visible, false means that it is always visible*/)] +public class Gizmo : IEntityGizmo +{ + private bool _selected, _enabled; + private MyScript _component; + private ModelComponent _model; + private Material _material, _materialOnSelect; + + // This property is set based on whether the gizmo is globally turned on or off in the editor's view settings + public bool IsEnabled + { + get + { + return _enabled; + } + set + { + _enabled = value; + _model.Enabled = _enabled; + } + } + + // The size slider value in the view settings pane + public float SizeFactor { get; set; } + + // The editor will set this property whenever the entity the component is on is selected + public bool IsSelected + { + get + { + return _selected; + } + set + { + _selected = value; + _model.Materials[0] = _selected ? _materialOnSelect : _material; + // The logic below shows gizmos for all components when they are on in the gizmo settings, and when off, only shows the one from the selected entity + // Removing the line hides gizmos even when selected when the gizmo settings is off + _model.Enabled = _selected || _enabled; + } + } + + // This constructor is called by the editor, + // A gizmo class MUST contain a constructor with a single parameter of the component's type + public Gizmo(MyScript component) + { + _component = component; + } + + public bool HandlesComponentId(OpaqueComponentId pickedComponentId, out Entity? selection) + { + // This function is called when scene picking/mouse clicking in the scene on a gizmo + // The engine calls this function on each gizmos, gizmos in term notify the engine + // when the given component comes from them by returning true, and provide the editor with the corresponding entity this gizmo represents + if (pickedComponentId.Match(_model)) + { + selection = _component.Entity; + return true; + } + selection = null; + return false; + } + + public void Initialize(IServiceRegistry services, Scene editorScene) + { + // As part of initialization, we create a model in the editor scene to visualize the gizmo + var graphicsDevice = services.GetSafeServiceAs().GraphicsDevice; + + // In our case we'll just rely on the GeometricPrimitive API to create a sphere for us + // You don't have to create one right away, you can delay it until the component is in the appropriate state + // You can also dynamically create and update one in the Update() function further below + var sphere = GeometricPrimitive.Sphere.New(graphicsDevice); + + var vertexBuffer = sphere.VertexBuffer; + var indexBuffer = sphere.IndexBuffer; + var vertexBufferBinding = new VertexBufferBinding(vertexBuffer, new VertexPositionNormalTexture().GetLayout(), vertexBuffer.ElementCount); + var indexBufferBinding = new IndexBufferBinding(indexBuffer, sphere.IsIndex32Bits, indexBuffer.ElementCount); + + _material = Material.New(graphicsDevice, new MaterialDescriptor + { + Attributes = + { + Emissive = new MaterialEmissiveMapFeature(new ComputeColor(new Color4(0.25f,0.75f,0.25f,0.05f).ToColorSpace(graphicsDevice.ColorSpace))) { UseAlpha = true }, + Transparency = new MaterialTransparencyBlendFeature() + }, + }); + _materialOnSelect = Material.New(graphicsDevice, new MaterialDescriptor + { + Attributes = + { + Emissive = new MaterialEmissiveMapFeature(new ComputeColor(new Color4(0.25f,0.75f,0.25f,0.5f).ToColorSpace(graphicsDevice.ColorSpace))) { UseAlpha = true }, + Transparency = new MaterialTransparencyBlendFeature() + }, + }); + + _model = new ModelComponent + { + Model = new Model + { + (_selected ? _materialOnSelect : _material), + new Mesh + { + Draw = new MeshDraw + { + StartLocation = 0, + // You can swap to LineList or LineStrip to show the model in wireframe mode, you'll have to adapt your index buffer to that new type though + PrimitiveType = PrimitiveType.TriangleList, + VertexBuffers = new[] { vertexBufferBinding }, + IndexBuffer = indexBufferBinding, + DrawCount = indexBuffer.ElementCount, + } + } + }, + RenderGroup = IEntityGizmo.PickingRenderGroup, // This RenderGroup allows scene picking/selection, use a different one if you don't want selection + Enabled = _selected || _enabled + }; + + var entity = new Entity($"{nameof(Gizmo)} for {_component.Entity.Name}"){ _model }; + entity.Transform.UseTRS = false; // We're controlling the matrix directly in this case + entity.Scene = editorScene; + + vertexBuffer.DisposeBy(entity); + indexBuffer.DisposeBy(entity); // Attach buffers to the entity for manual disposal later + } + + public void Dispose() + { + _model.Entity.Scene = null; + _model.Entity.Dispose(); // Clear the two buffers we attached above + } + + public void Update() + { + // This is where you'll update how the gizmo looks based on MyScript's state + // Here we'll just ensure the gizmo follows the entity it is representing whenever that entity moves, + // note that UseTRS is disabled above to improve performance and ensure that there are no world space issues + _model.Entity.Transform.LocalMatrix = _component.Entity.Transform.WorldMatrix; + } +} +``` +And the result: + +![Green sphere gizmo](media/gizmo.png) + +Do note that you may have to restart the editor if it was open while you introduced this new gizmo. \ No newline at end of file diff --git a/en/manual/scripts/index.md b/en/manual/scripts/index.md index 3cc081fbc..96aa06820 100644 --- a/en/manual/scripts/index.md +++ b/en/manual/scripts/index.md @@ -39,4 +39,5 @@ You can still use standard C# classes in Stride, but these aren't called scripts * [Events](events.md) * [Debugging](debugging.md) * [Preprocessor variables](preprocessor-variables.md) -* [Create a model from code](create-a-model-from-code.md) \ No newline at end of file +* [Create a model from code](create-a-model-from-code.md) +* [Create Gizmos for you components](gizmos.md) \ No newline at end of file diff --git a/en/manual/scripts/media/gizmo.png b/en/manual/scripts/media/gizmo.png new file mode 100644 index 000000000..bc199a16e --- /dev/null +++ b/en/manual/scripts/media/gizmo.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:0a62f0db688ba96190cb147747afcb9c43818717b62eb334f86ca6a0dceb0c86 +size 92679 diff --git a/en/manual/toc.yml b/en/manual/toc.yml index 61c2dcdb7..3b89b3431 100644 --- a/en/manual/toc.yml +++ b/en/manual/toc.yml @@ -498,6 +498,8 @@ items: href: scripts/preprocessor-variables.md - name: Create a model from code href: scripts/create-a-model-from-code.md + - name: Create Gizmos for you components + href: scripts/gizmos.md - name: Sprites href: sprites/index.md diff --git a/en/tutorials/toc.yml b/en/tutorials/toc.yml index 55a98778f..9b43fd3c2 100644 --- a/en/tutorials/toc.yml +++ b/en/tutorials/toc.yml @@ -76,7 +76,7 @@ items: href: csharpintermediate/ui-basics.md - name: Collision triggers href: csharpintermediate/collision-triggers.md - - name: Racyasting + - name: Raycasting href: csharpintermediate/raycasting.md - name: Project and Unproject href: csharpintermediate/project-and-unproject.md