Skip to content

Commit

Permalink
Merge pull request #158 from VaclavElias/feat-01-adding-extensions
Browse files Browse the repository at this point in the history
feat: New projects, tutorials, and extensive extension methods to enhance functionality and documentation
  • Loading branch information
VaclavElias authored Sep 21, 2024
2 parents 0f6da77 + 40b21de commit cfc78aa
Show file tree
Hide file tree
Showing 38 changed files with 5,431 additions and 34 deletions.
16 changes: 15 additions & 1 deletion Stride.CommunityToolkit.sln
Original file line number Diff line number Diff line change
Expand Up @@ -59,10 +59,14 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Stride.CommunityToolkit.Win
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Stride.CommunityToolkit.Benchmarks", "src\Stride.CommunityToolkit.Benchmarks\Stride.CommunityToolkit.Benchmarks.csproj", "{42C6F222-9D1E-4B6E-81F9-E3FE504472D6}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TextureMapping_Example01", "examples\snippets\TextureMapping_Example01\TextureMapping_Example01.csproj", "{6EC38B10-2FCB-48B1-A583-91FDD7C9A104}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TextureMapping_Example01", "examples\snippets\TextureMapping_Example01\TextureMapping_Example01.csproj", "{6EC38B10-2FCB-48B1-A583-91FDD7C9A104}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "snippets", "snippets", "{A9C673A6-1426-40DD-A060-B0749261DB7C}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Easing_Example01", "examples\snippets\Easing_Example01\Easing_Example01.csproj", "{991716B1-BECA-4D4F-9438-1CC1686962AC}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Physics_Example001", "examples\snippets\Physics_Example001\Physics_Example001.csproj", "{DE8458AC-2F74-428E-808F-C39EA986D110}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand Down Expand Up @@ -156,6 +160,14 @@ Global
{6EC38B10-2FCB-48B1-A583-91FDD7C9A104}.Debug|Any CPU.Build.0 = Debug|Any CPU
{6EC38B10-2FCB-48B1-A583-91FDD7C9A104}.Release|Any CPU.ActiveCfg = Release|Any CPU
{6EC38B10-2FCB-48B1-A583-91FDD7C9A104}.Release|Any CPU.Build.0 = Release|Any CPU
{991716B1-BECA-4D4F-9438-1CC1686962AC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{991716B1-BECA-4D4F-9438-1CC1686962AC}.Debug|Any CPU.Build.0 = Debug|Any CPU
{991716B1-BECA-4D4F-9438-1CC1686962AC}.Release|Any CPU.ActiveCfg = Release|Any CPU
{991716B1-BECA-4D4F-9438-1CC1686962AC}.Release|Any CPU.Build.0 = Release|Any CPU
{DE8458AC-2F74-428E-808F-C39EA986D110}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{DE8458AC-2F74-428E-808F-C39EA986D110}.Debug|Any CPU.Build.0 = Debug|Any CPU
{DE8458AC-2F74-428E-808F-C39EA986D110}.Release|Any CPU.ActiveCfg = Release|Any CPU
{DE8458AC-2F74-428E-808F-C39EA986D110}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand All @@ -177,6 +189,8 @@ Global
{D12C2C1E-9316-4C8D-B773-B84213AB4389} = {30457B66-9E10-4290-9744-D0079DE0448B}
{D2092F94-19E8-45CC-8B5F-DAE680A276AC} = {30457B66-9E10-4290-9744-D0079DE0448B}
{6EC38B10-2FCB-48B1-A583-91FDD7C9A104} = {A9C673A6-1426-40DD-A060-B0749261DB7C}
{991716B1-BECA-4D4F-9438-1CC1686962AC} = {A9C673A6-1426-40DD-A060-B0749261DB7C}
{DE8458AC-2F74-428E-808F-C39EA986D110} = {A9C673A6-1426-40DD-A060-B0749261DB7C}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {C7A8C18E-C1F5-492F-8173-51EC9495B78C}
Expand Down
2 changes: 1 addition & 1 deletion docs/manual/camera-extensions/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ Below is a list of available extension methods:
- [`ScreenToWorldPoint()`](xref:Stride.CommunityToolkit.Engine.CameraComponentExtensions.ScreenToWorldPoint(Stride.Engine.CameraComponent,Stride.Core.Mathematics.Vector3@)) - Converts the screen position to a point in world coordinates
- [`ScreenToWorldRaySegment()`](xref:Stride.CommunityToolkit.Engine.CameraComponentExtensions.ScreenToWorldRaySegment(Stride.Engine.CameraComponent,Stride.Core.Mathematics.Vector2)) - Converts the screen position to a `RaySegment` in world coordinates
- [`ScreenToWorldRaySegment()`](xref:Stride.CommunityToolkit.Engine.CameraComponentExtensions.ScreenToWorldRaySegment(Stride.Engine.CameraComponent,Stride.Core.Mathematics.Vector2@,Stride.CommunityToolkit.Scripts.RaySegment@)) - Converts the screen position to a `RaySegment` in world coordinates
- [`WorldToClipSpace()`](xref:Stride.CommunityToolkit.Engine.CameraComponentExtensions.WorldToClipSpace(Stride.Engine.CameraComponent,Stride.Core.Mathematics.Vector3@)) - Converts the world position to clip space coordinates relative to camera
- [`WorldToClip()`](xref:Stride.CommunityToolkit.Engine.CameraComponentExtensions.WorldToClip(Stride.Engine.CameraComponent,Stride.Core.Mathematics.Vector3@)) - Converts the world position to clip space coordinates relative to camera
- [`WorldToScreenPoint()`](xref:Stride.CommunityToolkit.Engine.CameraComponentExtensions.WorldToScreenPoint(Stride.Engine.CameraComponent,Stride.Core.Mathematics.Vector3@)) - Converts the world position to screen space coordinates relative to camera

Each of these methods is designed to offer streamlined, high-level operations that simplify camera manipulation tasks, allowing you to focus on creating immersive and dynamic 3D environments.
12 changes: 6 additions & 6 deletions docs/manual/code-only/index.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Code-Only

## Why Opt for Code-Only Over the Stride Editor?
## Why Opt for Code-Only Over Stride's Game Studio?

There are numerous reasons to consider using the code-only approach, especially if:

Expand All @@ -19,17 +19,17 @@ Have more reasons to add? Feel free to suggest them through our [GitHub Issues](

## Extensions and Helpers

Our extensions and helpers provide a simplified pathway for game creation, specifically designed for **code-only** projects within the Stride Game Engine. While they are not essential for running a game, they serve as time-saving tools to aid users, particularly those new to Stride, in quickly getting started.
Our code-only specific extensions and helpers provide a simplified pathway for game creation, specifically designed for **code-only** projects within the Stride Game Engine. While they are not essential for running a game, they serve as time-saving tools to help users, particularly those new to Stride, get started quickly.

These extensions rely heavily on default settings to ease your initiation into the engine. However, they are not rigid; if the default settings don't fully meet your needs, you have the option to delve into the extension's implementation and create a custom version tailored to your preferences.
These extensions rely heavily on default settings to ease your entry into the engine. However, they are flexible; if the default settings don't fully meet your needs, you can explore the extension's implementation and create a custom version tailored to your preferences.

Please note, although these extensions have been created with an opinionated approach to help beginners get up and running quickly, experienced users can also find value in them. They can serve as a foundation upon which you can build, modify, and extend to create more complex and customized solutions.
Please note that while these extensions have been created with a beginner-friendly, opinionated approach to help users get up and running quickly, experienced users can also benefit from them. They can serve as a foundation upon which you can build, modify, and extend to create more complex and customized solutions.

## Functionality

Some functionality you would expect and which works in the Stride Editor might not be possible yet. Please add your vote or submit another request in the [GitHub Issues](https://github.com/stride3d/stride-community-toolkit/issues).
Some functionality you might expect and which works in the Stride Game Studio may not yet be available. Please add your vote or submit a request in the [GitHub Issues](https://github.com/stride3d/stride-community-toolkit/issues).

## References

- [Stride Issue - Code-Only Approach](https://github.com/stride3d/stride/issues/1295)
- [Stride Discussions - Code-Only / Minimal Stride API Projec](https://github.com/stride3d/stride/discussions/1253)
- [Stride Discussions - Code-Only / Minimal Stride API Project](https://github.com/stride3d/stride/discussions/1253)
27 changes: 27 additions & 0 deletions docs/tutorials/mathematics/easing.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# Using Easing Functions: Animating Position and Material Color

**Easing functions** are used in animations to create smooth transitions between values over a specified time. In this tutorial, we'll explore how to use easing functions not only to move a 3D object but also to interpolate its material color. This will allow us to create animations that blend both movement and visual effects.

## What You'll Learn
- How to create a 3D primitive (cube).
- How to implement easing functions for smooth transitions in animations.
- How to animate the movement of a 3D object using easing functions.
- How to interpolate and change the material color of a 3D object dynamically.

## Code Walkthrough

[!code-csharp[Easing demo](../../../examples/snippets/Easing_Example01/Program.cs)]

## Code Breakdown

- **Position Animation:** The `MathUtilEx.Interpolate` method is used with a quintic easing function to smoothly transition the sphere's position from its start to its end position.
- **Material Color Animation:** The same interpolation approach is applied to change the color of the sphere’s material. A **linear easing function** is used to gradually change the color from white to a randomly generated color.
- **Resetting the Animation:** The animation is reset each time the spacebar is pressed, allowing the movement and color transition to start over.

## Running the Code

When you run the code, you'll see a 3D sphere smoothly moving from the starting position (8 units above the ground) to the bottom (2 units above the ground) over a duration of 2 seconds. At the same time, the sphere’s material color will gradually change from white to a randomly generated color. You can press the **spacebar** to reset the animation and see the sphere rise back to the top while its color returns to white.

## Summary

In this tutorial, you learned how to animate both the position and material color of a 3D object using easing functions. This technique allows you to create smooth and visually appealing transitions, which are essential for creating polished game experiences.
31 changes: 31 additions & 0 deletions docs/tutorials/physics/pick-and-aim.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
# Raycasting and Camera Focus

In this tutorial, we will learn how to use **raycasting** to detect entities in a 3D scene and adjust the camera to focus on them. This technique is useful for games or simulations where you need to interact with objects using the mouse and smoothly transition the camera's focus based on those interactions.

## What You'll Learn

- How to create 3D entities and assign materials to them.
- How to use **raycasting** to detect objects in a 3D scene.
- How to use the camera to smoothly look at the target entity.

## Code Walkthrough

[!code-csharp[Pick and Aim](../../../examples/snippets/Physics_Example001/Program.cs)]

## Code Walkthrough

- **Game Setup:** In the `Start()` method, we set up a basic 3D scene with lighting and a camera using the `SetupBase3DScene()` helper method. We then create two 3D entities, a **cube** and a **sphere**, and position them in the scene with different materials.

- **Raycasting with Mouse Input:** In the `Update()` method, we check if the left mouse button is pressed. If pressed, a ray is cast from the mouse position into the 3D world using `ScreenToWorldRaySegment()`. This ray is used to check for collisions with 3D entities in the scene via **raycasting**.

- **Camera Focus:** If the ray successfully hits an entity, that entity becomes the **target**. The camera then uses the `LookAt()` method to smoothly focus on the target entity, giving the player a clear view of the object they clicked on.

## Running the Code

When you run this code, the game will display a 3D scene with a cube and a sphere. By clicking on either object with the mouse, the camera will smoothly rotate to focus on the clicked object. The left mouse button controls the focus.

## Summary

This example demonstrates how to use raycasting to detect entities in a scene based on mouse input and how to adjust the camera to focus on those entities. This technique is useful for games that require interactive environments, object selection, or camera-based interactions.

Feel free to extend this concept by adding more entities, adjusting the camera's behavior, or experimenting with different easing functions for camera movement.
8 changes: 8 additions & 0 deletions docs/tutorials/toc.yml
Original file line number Diff line number Diff line change
@@ -1,5 +1,13 @@
- name: Tutorials
href: index.md
- name: Mathematics
items:
- name: Easing
href: mathematics/easing.md
- name: Physics
items:
- name: Pick and aim
href: physics/pick-and-aim.md
- name: Textures
items:
- name: Add a Texture at Runtime
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
</ItemGroup>

<ItemGroup>
<PackageReference Include="Myra.Stride" Version="1.5.5" />
<PackageReference Include="Myra.Stride" Version="1.5.6" />
</ItemGroup>

</Project>
14 changes: 14 additions & 0 deletions examples/snippets/Easing_Example01/Easing_Example01.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>

<ItemGroup>
<ProjectReference Include="..\..\..\src\Stride.CommunityToolkit.Windows\Stride.CommunityToolkit.Windows.csproj" />
</ItemGroup>

</Project>
88 changes: 88 additions & 0 deletions examples/snippets/Easing_Example01/Program.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
using Stride.CommunityToolkit.Engine;
using Stride.CommunityToolkit.Mathematics;
using Stride.CommunityToolkit.Rendering.ProceduralModels;
using Stride.Core.Mathematics;
using Stride.Engine;
using Stride.Games;
using Stride.Input;
using Stride.Rendering.Materials;

// Time elapsed since the start of the animation
var elapsed = TimeSpan.Zero;

// Duration of the animation (2 seconds)
var duration = TimeSpan.FromSeconds(2);

// Target position (where the object will ease to)
var bottom = new Vector3(0, 2, 0);

// Starting position of the object
var startPosition = new Vector3(0, 8, 0);

// 3D entity to be animated
var entity = new Entity();

// Color to interpolate to, initilized to white
Color color = Color.White;

// Initialize a new game instance
using var game = new Game();

// Run the game, specifying both the Start and Update methods
game.Run(start: Start, update: Update);

// Setup and initialize the scene
void Start(Scene scene)
{
// Set up a base 3D scene with default lighting and camera
game.SetupBase3DScene();

// Create a 3D sphere primitive and assign the material to it
entity = game.Create3DPrimitive(PrimitiveModelType.Sphere, new()
{
Material = game.CreateMaterial(Color.White)
});

// Add the sphere entity to the root scene
entity.Scene = scene;

var random = new Random();

// Generate a random color to interpolate to
color = random.NextColor();
}

// Update the scene every frame (for animations and input handling)
void Update(Scene scene, GameTime time)
{
// Calculate the progress of the animation as a ratio between 0 and 1
var progress = (float)(elapsed.TotalSeconds / duration.TotalSeconds);

if (progress > 1.0f)
{
progress = 1.0f;
}

// Interpolate the position of the object using a quintic easing function
var position = MathUtilEx.Interpolate(startPosition, bottom, progress, EasingFunction.QuinticEaseOut);

Console.WriteLine(position);

// Apply the new position to the entity
entity.Transform.Position = position;

// Interpolate the color using a linear easing function
var diffuse = MathUtilEx.Interpolate(Color.White, color, progress, EasingFunction.Linear);

// Apply the interpolated color to the material
entity.Get<ModelComponent>().SetMaterialParameter(MaterialKeys.DiffuseValue, diffuse);

// Update the elapsed time with the time since the last frame
elapsed += time.Elapsed;

// Reset the animation when the spacebar is pressed
if (game.Input.IsKeyPressed(Keys.Space))
{
elapsed = TimeSpan.Zero;
}
}
14 changes: 14 additions & 0 deletions examples/snippets/Physics_Example001/Physics_Example001.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>

<ItemGroup>
<ProjectReference Include="..\..\..\src\Stride.CommunityToolkit.Windows\Stride.CommunityToolkit.Windows.csproj" />
</ItemGroup>

</Project>
82 changes: 82 additions & 0 deletions examples/snippets/Physics_Example001/Program.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
using Stride.CommunityToolkit.Engine;
using Stride.CommunityToolkit.Games;
using Stride.CommunityToolkit.Physics;
using Stride.CommunityToolkit.Rendering.ProceduralModels;
using Stride.Core.Mathematics;
using Stride.Engine;
using Stride.Games;
using Stride.Physics;

Entity? target = null;
CameraComponent? camera = null;
Simulation? simulation = null;

using var game = new Game();

game.Run(start: Start, update: Update);

void Start(Scene scene)
{
// Set up a base 3D scene with default lighting and camera
game.SetupBase3DScene();

// Add a gizmo to help visualize the ground plane and axis directions
game.AddGroundGizmo(showAxisName: true);

// Create a cube entity with a violet material and position it in the scene
var cube = game.Create3DPrimitive(PrimitiveModelType.Cube, new()
{
Material = game.CreateMaterial(Color.Violet),
});

// Set the position of the cube
cube.Transform.Position = new Vector3(0, 8, -3);

// Add cube to the scene
cube.Scene = scene;

// Create a sphere entity with a wheat-colored material
var entity = game.Create3DPrimitive(PrimitiveModelType.Sphere, new()
{
Material = game.CreateMaterial(Color.Wheat),
});

// Set the position of the sphere
entity.Transform.Position = new Vector3(-4, 8, 0);

// Add sphere to the scene
entity.Scene = scene;

// Retrieve the camera and the physics simulation from the scene
camera = scene.GetCamera();
simulation = game.SceneSystem.SceneInstance.GetProcessor<PhysicsProcessor>()?.Simulation;
}

// Update method called every frame to handle game logic
void Update(Scene scene, GameTime gameTime)
{
// Ensure that the camera and simulation are initialized
if (simulation == null || camera is null) return;

// Check if the left mouse button is pressed
if (game.Input.IsMouseButtonPressed(Stride.Input.MouseButton.Left))
{
// Cast a ray from the mouse position into the world
var ray = camera.ScreenToWorldRaySegment(game.Input.MousePosition);

// Perform raycasting in the simulation to detect any entities
var hitResult = simulation.Raycast(ray);

if (hitResult.Succeeded)
{
// If the ray hits an entity, set it as the camera's target
target = hitResult.Collider.Entity;
}
}

// If a target entity is set, make the camera smoothly look at it
if (target != null)
{
camera.Entity.Transform.LookAt(target.Transform, game.DeltaTime() * 3.0f);
}
}
4 changes: 2 additions & 2 deletions examples/snippets/TextureMapping_Example01/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@

game.Run(start: Start);

void Start(Scene rootScene)
void Start(Scene scene)
{
// Set up a base 3D scene with default lighting and camera
game.SetupBase3DScene();
Expand Down Expand Up @@ -52,5 +52,5 @@ void Start(Scene rootScene)
entity.Transform.Position = new Vector3(0, 8, 0);

// Add the cube to the root scene
entity.Scene = rootScene;
entity.Scene = scene;
}
Loading

0 comments on commit cfc78aa

Please sign in to comment.