diff --git a/samples/Audio/SimpleAudio/SimpleAudio.Game/SimpleAudio.Game.csproj b/samples/Audio/SimpleAudio/SimpleAudio.Game/SimpleAudio.Game.csproj index 84ccd03ced..b0e9775095 100644 --- a/samples/Audio/SimpleAudio/SimpleAudio.Game/SimpleAudio.Game.csproj +++ b/samples/Audio/SimpleAudio/SimpleAudio.Game/SimpleAudio.Game.csproj @@ -2,6 +2,8 @@ net8.0 SimpleAudio + enable + latest diff --git a/samples/Audio/SimpleAudio/SimpleAudio.Game/SoundScript.cs b/samples/Audio/SimpleAudio/SimpleAudio.Game/SoundScript.cs index 7ff46f7cd6..647e1809c3 100644 --- a/samples/Audio/SimpleAudio/SimpleAudio.Game/SoundScript.cs +++ b/samples/Audio/SimpleAudio/SimpleAudio.Game/SoundScript.cs @@ -1,95 +1,92 @@ // Copyright (c) .NET Foundation and Contributors (https://dotnetfoundation.org/ & https://stride3d.net) and Silicon Studio Corp. (https://www.siliconstudio.co.jp) // Distributed under the MIT license. See the LICENSE.md file in the project root for more information. -using System.Linq; -using System.Threading.Tasks; + +using Stride.Audio; using Stride.Core; using Stride.Core.Mathematics; -using Stride.Audio; using Stride.Engine; using Stride.Input; using Stride.UI; using Stride.UI.Controls; -using Stride.UI.Panels; -namespace SimpleAudio +namespace SimpleAudio; + +/// +/// The main script in charge of the sound. +/// +public class SoundScript : AsyncScript { /// - /// The main script in charge of the sound. + /// The page containing the UI elements /// - public class SoundScript : AsyncScript + public UIPage Page {get; set; } + + public Sound SoundMusic; + private SoundInstance music; + public Sound SoundEffect; + private SoundInstance effect; + + [DataMember(Mask = LiveScriptingMask)] // keep the value when reloading the script (live-scripting) + private float originalPositionX; + + [DataMember(Mask = LiveScriptingMask)] // keep the value when reloading the script (live-scripting) + private float fontColor; + + public override async Task Execute() { - /// - /// The page containing the UI elements - /// - public UIPage Page {get; set; } + var imgLeft = Page?.RootElement.FindVisualChildOfType("LeftWave"); + var imgRight = Page?.RootElement.FindVisualChildOfType("RightWave"); - public Sound SoundMusic; - private SoundInstance music; - public Sound SoundEffect; - private SoundInstance effect; + music = SoundMusic.CreateInstance(); + effect = SoundEffect.CreateInstance(); - [DataMember(Mask = LiveScriptingMask)] // keep the value when reloading the script (live-scripting) - private float originalPositionX; + if (!IsLiveReloading) + { + // start ambient music + music.IsLooping = true; + music.Play(); - [DataMember(Mask = LiveScriptingMask)] // keep the value when reloading the script (live-scripting) - private float fontColor; + fontColor = 0; + originalPositionX = (imgRight != null) ? imgRight.GetCanvasRelativePosition().X : 0.65f; + } - public override async Task Execute() + while (Game.IsRunning) { - var imgLeft = Page?.RootElement.FindVisualChildOfType("LeftWave"); - var imgRight = Page?.RootElement.FindVisualChildOfType("RightWave"); - - music = SoundMusic.CreateInstance(); - effect = SoundEffect.CreateInstance(); - - if (!IsLiveReloading) + if (Input.PointerEvents.Any(item => item.EventType == PointerEventType.Pressed)) // New click { - // start ambient music - music.IsLooping = true; - music.Play(); + if (imgLeft != null && imgRight != null) + { + // reset wave position + imgLeft.SetCanvasRelativePosition(new Vector3(1 - originalPositionX, 0.5f, 0)); + imgLeft.Opacity = 0; + + imgRight.SetCanvasRelativePosition(new Vector3(originalPositionX, 0.5f, 0)); + imgRight.Opacity = 0; + } + + // reset transparency + fontColor = 1; - fontColor = 0; - originalPositionX = (imgRight != null) ? imgRight.GetCanvasRelativePosition().X : 0.65f; + // play the sound effect on each touch on the screen + effect.Stop(); + effect.Play(); } - - while (Game.IsRunning) + else { - if (Input.PointerEvents.Any(item => item.EventType == PointerEventType.Pressed)) // New click + if (imgLeft != null && imgRight != null) { - if (imgLeft != null && imgRight != null) - { - // reset wave position - imgLeft.SetCanvasRelativePosition(new Vector3(1 - originalPositionX, 0.5f, 0)); - imgLeft.Opacity = 0; + imgLeft.SetCanvasRelativePosition(imgLeft.GetCanvasRelativePosition() - new Vector3(0.0025f, 0, 0)); + imgRight.SetCanvasRelativePosition(imgRight.GetCanvasRelativePosition() + new Vector3(0.0025f, 0, 0)); - imgRight.SetCanvasRelativePosition(new Vector3(originalPositionX, 0.5f, 0)); - imgRight.Opacity = 0; - } - - // reset transparency - fontColor = 1; - - // play the sound effect on each touch on the screen - effect.Stop(); - effect.Play(); + // changing font transparency + fontColor = 0.93f * fontColor; + imgLeft.Opacity = fontColor; + imgRight.Opacity = fontColor; } - else - { - if (imgLeft != null && imgRight != null) - { - imgLeft.SetCanvasRelativePosition(imgLeft.GetCanvasRelativePosition() - new Vector3(0.0025f, 0, 0)); - imgRight.SetCanvasRelativePosition(imgRight.GetCanvasRelativePosition() + new Vector3(0.0025f, 0, 0)); - - // changing font transparency - fontColor = 0.93f * fontColor; - imgLeft.Opacity = fontColor; - imgRight.Opacity = fontColor; - } - } - - // wait for next frame - await Script.NextFrame(); } + + // wait for next frame + await Script.NextFrame(); } } } diff --git a/samples/Audio/SimpleAudio/SimpleAudio.Windows/SimpleAudio.Windows.csproj b/samples/Audio/SimpleAudio/SimpleAudio.Windows/SimpleAudio.Windows.csproj index 2de591ec21..bee403944c 100644 --- a/samples/Audio/SimpleAudio/SimpleAudio.Windows/SimpleAudio.Windows.csproj +++ b/samples/Audio/SimpleAudio/SimpleAudio.Windows/SimpleAudio.Windows.csproj @@ -7,6 +7,8 @@ ..\Bin\Windows\$(Configuration)\ false STRIDE_PLATFORM_DESKTOP + enable + latest $(MSBuildThisFileDirectory)..\SimpleAudio.sdpkg diff --git a/samples/Games/JumpyJet/JumpyJet.Game/BackgroundScript.cs b/samples/Games/JumpyJet/JumpyJet.Game/BackgroundScript.cs index 24aa1919a5..022d342e2b 100644 --- a/samples/Games/JumpyJet/JumpyJet.Game/BackgroundScript.cs +++ b/samples/Games/JumpyJet/JumpyJet.Game/BackgroundScript.cs @@ -4,29 +4,27 @@ using System.Threading.Tasks; using Stride.Engine; using Stride.Engine.Events; -using Stride.Physics; using Stride.Rendering.Compositing; -namespace JumpyJet +namespace JumpyJet; + +public class BackgroundScript : AsyncScript { - public class BackgroundScript : AsyncScript + private readonly EventReceiver gameOverListener = new(GameGlobals.GameOverEventKey); + private readonly EventReceiver gameResetListener = new(GameGlobals.GameResetEventKey); + + public override async Task Execute() { - private EventReceiver gameOverListener = new EventReceiver(GameGlobals.GameOverEventKey); - private EventReceiver gameResetListener = new EventReceiver(GameGlobals.GameResetEventKey); + // Find our JumpyJetRenderer to start/stop parallax background + var renderer = (JumpyJetRenderer)((SceneCameraRenderer)SceneSystem.GraphicsCompositor.Game).Child; - public override async Task Execute() + while (Game.IsRunning) { - // Find our JumpyJetRenderer to start/stop parallax background - var renderer = (JumpyJetRenderer)((SceneCameraRenderer)SceneSystem.GraphicsCompositor.Game).Child; - - while (Game.IsRunning) - { - await gameOverListener.ReceiveAsync(); - renderer.StopScrolling(); + await gameOverListener.ReceiveAsync(); + renderer.StopScrolling(); - await gameResetListener.ReceiveAsync(); - renderer.StartScrolling(); - } + await gameResetListener.ReceiveAsync(); + renderer.StartScrolling(); } } } diff --git a/samples/Games/JumpyJet/JumpyJet.Game/BackgroundSection.cs b/samples/Games/JumpyJet/JumpyJet.Game/BackgroundSection.cs index 17098f582a..225b475c36 100644 --- a/samples/Games/JumpyJet/JumpyJet.Game/BackgroundSection.cs +++ b/samples/Games/JumpyJet/JumpyJet.Game/BackgroundSection.cs @@ -1,117 +1,117 @@ // Copyright (c) .NET Foundation and Contributors (https://dotnetfoundation.org/ & https://stride3d.net) and Silicon Studio Corp. (https://www.siliconstudio.co.jp) // Distributed under the MIT license. See the LICENSE.md file in the project root for more information. + using Stride.Core.Mathematics; using Stride.Graphics; -namespace JumpyJet +namespace JumpyJet; + +/// +/// A section of the parallax background. +/// +public class BackgroundSection { - /// - /// A section of the parallax background. - /// - public class BackgroundSection + private readonly float depth; + private readonly Int2 screenResolution; + private readonly Vector2 screenCenter; + + // Texture + private Texture texture; + private RectangleF textureRegion; + + // First quad parameters + private readonly Vector2 firstQuadPos; + private Vector2 firstQuadOrigin; + private RectangleF firstQuadRegion; + + // Second quad parameters + private Vector2 secondQuadPos; + private Vector2 secondQuadOrigin; + private RectangleF secondQuadRegion; + + public bool IsUpdating { get; set; } + public bool IsRunning { get; protected set; } + public bool IsVisible { get; protected set; } + public float ScrollPos { get; protected set; } + public float ScrollWidth { get; protected set; } + public float ScrollSpeed { get; protected set; } + + public BackgroundSection(Sprite backgroundSprite, Vector3 screenVirtualResolution, float scrollSpeed, float depth, Vector2 startPos = default) { - private readonly float depth; - private readonly Int2 screenResolution; - private readonly Vector2 screenCenter; - - // Texture - private Texture texture; - private RectangleF textureRegion; - - // First quad parameters - private readonly Vector2 firstQuadPos; - private Vector2 firstQuadOrigin; - private RectangleF firstQuadRegion; - - // Second quad parameters - private Vector2 secondQuadPos; - private Vector2 secondQuadOrigin; - private RectangleF secondQuadRegion; - - public bool IsUpdating { get; set; } - public bool IsRunning { get; protected set; } - public bool IsVisible { get; protected set; } - public float ScrollPos { get; protected set; } - public float ScrollWidth { get; protected set; } - public float ScrollSpeed { get; protected set; } - - public BackgroundSection(Sprite backgroundSprite, Vector3 screenVirtualResolution, float scrollSpeed, float depth, Vector2 startPos = default(Vector2)) - { - screenResolution = new Int2((int)screenVirtualResolution.X, (int)screenVirtualResolution.Y); - screenCenter = new Vector2(screenVirtualResolution.X / 2, screenVirtualResolution.Y / 2); + screenResolution = new Int2((int)screenVirtualResolution.X, (int)screenVirtualResolution.Y); + screenCenter = new Vector2(screenVirtualResolution.X / 2, screenVirtualResolution.Y / 2); - this.depth = depth; - firstQuadPos = startPos; - secondQuadPos = startPos; + this.depth = depth; + firstQuadPos = startPos; + secondQuadPos = startPos; - ScrollSpeed = scrollSpeed; - ScrollPos = 0; + ScrollSpeed = scrollSpeed; + ScrollPos = 0; - CreateBackground(backgroundSprite.Texture, backgroundSprite.Region); + CreateBackground(backgroundSprite.Texture, backgroundSprite.Region); - IsUpdating = true; - } + IsUpdating = true; + } - public void DrawSprite(float elapsedTime, SpriteBatch spriteBatch) + public void DrawSprite(float elapsedTime, SpriteBatch spriteBatch) + { + if (IsUpdating) { - if (IsUpdating) - { - // Update Scroll position - if (ScrollPos >= textureRegion.Width) - ScrollPos = 0; + // Update Scroll position + if (ScrollPos >= textureRegion.Width) + ScrollPos = 0; - ScrollPos += elapsedTime * ScrollSpeed; + ScrollPos += elapsedTime * ScrollSpeed; - UpdateSpriteQuads(); - } + UpdateSpriteQuads(); + } - // DrawParallax the first quad - spriteBatch.Draw(texture, firstQuadPos + screenCenter, firstQuadRegion, Color.White, 0f, firstQuadOrigin, 1f, SpriteEffects.None, ImageOrientation.AsIs, depth); + // DrawParallax the first quad + spriteBatch.Draw(texture, firstQuadPos + screenCenter, firstQuadRegion, Color.White, 0f, firstQuadOrigin, 1f, SpriteEffects.None, ImageOrientation.AsIs, depth); - if (secondQuadRegion.Width > 0) - { - // DrawParallax the second quad - spriteBatch.Draw(texture, secondQuadPos + screenCenter, secondQuadRegion, Color.White, 0f, secondQuadOrigin, 1f, SpriteEffects.None, ImageOrientation.AsIs, depth); - } + if (secondQuadRegion.Width > 0) + { + // DrawParallax the second quad + spriteBatch.Draw(texture, secondQuadPos + screenCenter, secondQuadRegion, Color.White, 0f, secondQuadOrigin, 1f, SpriteEffects.None, ImageOrientation.AsIs, depth); } + } - private void CreateBackground(Texture bgTexture, RectangleF texReg) - { - texture = bgTexture; - textureRegion = texReg; + private void CreateBackground(Texture bgTexture, RectangleF texReg) + { + texture = bgTexture; + textureRegion = texReg; - // Set offset to rectangle - firstQuadRegion.X = textureRegion.X; - firstQuadRegion.Y = textureRegion.Y; + // Set offset to rectangle + firstQuadRegion.X = textureRegion.X; + firstQuadRegion.Y = textureRegion.Y; - firstQuadRegion.Width = (textureRegion.Width > screenResolution.X) ? screenResolution.X : textureRegion.Width; - firstQuadRegion.Height = (textureRegion.Height > screenResolution.Y) ? screenResolution.Y : textureRegion.Height; + firstQuadRegion.Width = (textureRegion.Width > screenResolution.X) ? screenResolution.X : textureRegion.Width; + firstQuadRegion.Height = (textureRegion.Height > screenResolution.Y) ? screenResolution.Y : textureRegion.Height; - // Centering the content - firstQuadOrigin.X = 0.5f * firstQuadRegion.Width; - firstQuadOrigin.Y = 0.5f * firstQuadRegion.Height; + // Centering the content + firstQuadOrigin.X = 0.5f * firstQuadRegion.Width; + firstQuadOrigin.Y = 0.5f * firstQuadRegion.Height; - // Copy data from first quad to second one - secondQuadRegion = firstQuadRegion; - secondQuadOrigin = firstQuadOrigin; - } + // Copy data from first quad to second one + secondQuadRegion = firstQuadRegion; + secondQuadOrigin = firstQuadOrigin; + } - private void UpdateSpriteQuads() - { - // Update first Quad - var firstQuadNewWidth = textureRegion.Width - ScrollPos; - firstQuadRegion.Width = firstQuadNewWidth; - // Update X position of the first Quad - firstQuadRegion.X = ScrollPos; - - // Update second Quad - // Calculate new X position and width of the second quad - var secondQuadNewWidth = (ScrollPos + screenResolution.X) - textureRegion.Width; - var secondQuadNewXPosition = (screenResolution.X - secondQuadNewWidth) / 2; - - secondQuadRegion.Width = secondQuadNewWidth; - secondQuadPos.X = secondQuadNewXPosition; - secondQuadOrigin.X = secondQuadNewWidth / 2f; - } + private void UpdateSpriteQuads() + { + // Update first Quad + var firstQuadNewWidth = textureRegion.Width - ScrollPos; + firstQuadRegion.Width = firstQuadNewWidth; + // Update X position of the first Quad + firstQuadRegion.X = ScrollPos; + + // Update second Quad + // Calculate new X position and width of the second quad + var secondQuadNewWidth = (ScrollPos + screenResolution.X) - textureRegion.Width; + var secondQuadNewXPosition = (screenResolution.X - secondQuadNewWidth) / 2; + + secondQuadRegion.Width = secondQuadNewWidth; + secondQuadPos.X = secondQuadNewXPosition; + secondQuadOrigin.X = secondQuadNewWidth / 2f; } } diff --git a/samples/Games/JumpyJet/JumpyJet.Game/CharacterScript.cs b/samples/Games/JumpyJet/JumpyJet.Game/CharacterScript.cs index 9a93043225..3c6e72f985 100644 --- a/samples/Games/JumpyJet/JumpyJet.Game/CharacterScript.cs +++ b/samples/Games/JumpyJet/JumpyJet.Game/CharacterScript.cs @@ -1,5 +1,6 @@ // Copyright (c) .NET Foundation and Contributors (https://dotnetfoundation.org/ & https://stride3d.net) and Silicon Studio Corp. (https://www.siliconstudio.co.jp) // Distributed under the MIT license. See the LICENSE.md file in the project root for more information. + using System; using System.Linq; using System.Threading.Tasks; @@ -10,163 +11,160 @@ using Stride.Physics; using Stride.Rendering.Sprites; -namespace JumpyJet +namespace JumpyJet; + +/// +/// CharacterScript is controlled by a user. +/// The control is as follow, tapping a screen/clicking a mouse will make the agent jump up. +/// +public class CharacterScript : AsyncScript { - /// - /// CharacterScript is controlled by a user. - /// The control is as follow, tapping a screen/clicking a mouse will make the agent jump up. - /// - public class CharacterScript : AsyncScript - { - private EventReceiver gameResetListener = new EventReceiver(GameGlobals.GameResetEventKey); - private EventReceiver gameStartedListener = new EventReceiver(GameGlobals.GameStartedEventKey); + private readonly EventReceiver gameResetListener = new(GameGlobals.GameResetEventKey); + private readonly EventReceiver gameStartedListener = new(GameGlobals.GameStartedEventKey); - private static readonly Vector3 Gravity = new Vector3(0, -17, 0); - private static readonly Vector3 StartPos = new Vector3(-1, 0, 0); - private static readonly Vector3 StartVelocity = new Vector3(0, 7, 0); + private static readonly Vector3 Gravity = new(0, -17, 0); + private static readonly Vector3 StartPos = new(-1, 0, 0); + private static readonly Vector3 StartVelocity = new(0, 7, 0); - private const float TopLimit = (568 - 200) * GameGlobals.GamePixelToUnitScale; - private const float NormalVelocityY = 6.5f; - private const float VelocityAboveTopLimit = 2f; - private const int FlyingSpriteFrameIndex = 1; - private const int FallingSpriteFrameIndex = 0; + private const float TopLimit = (568 - 200) * GameGlobals.GamePixelToUnitScale; + private const float NormalVelocityY = 6.5f; + private const float VelocityAboveTopLimit = 2f; + private const int FlyingSpriteFrameIndex = 1; + private const int FallingSpriteFrameIndex = 0; - private Vector3 position; - private Vector3 rotation; + private Vector3 position; + private Vector3 rotation; - private bool isRunning; - private Vector3 velocity; + private bool isRunning; + private Vector3 velocity; - public void Start() - { - position = StartPos; - velocity = StartVelocity; + public void Start() + { + position = StartPos; + velocity = StartVelocity; - Reset(); + Reset(); - Script.AddTask(CountPassedPipes); - Script.AddTask(DetectGameOver); - } + Script.AddTask(CountPassedPipes); + Script.AddTask(DetectGameOver); + } - /// - /// Reset CharacterScript parameters: position, velocity and set state. - /// - public void Reset() - { - position.Y = 0; - rotation.Z = 0f; - UpdateTransformation(); + /// + /// Reset CharacterScript parameters: position, velocity and set state. + /// + public void Reset() + { + position.Y = 0; + rotation.Z = 0f; + UpdateTransformation(); - velocity = StartVelocity; - isRunning = false; + velocity = StartVelocity; + isRunning = false; - var provider = Entity.Get().SpriteProvider as SpriteFromSheet; - if (provider != null) - provider.CurrentFrame = FallingSpriteFrameIndex; - } + if (Entity.Get().SpriteProvider is SpriteFromSheet provider) + provider.CurrentFrame = FallingSpriteFrameIndex; + } - /// - /// Update the agent according to its states: {Idle, Alive, Die} - /// - public async Task CountPassedPipes() - { - var physicsComponent = Entity.Components.Get(); + /// + /// Update the agent according to its states: {Idle, Alive, Die} + /// + public async Task CountPassedPipes() + { + var physicsComponent = Entity.Components.Get(); - while (Game.IsRunning) - { - var collision = await physicsComponent.NewCollision(); + while (Game.IsRunning) + { + var collision = await physicsComponent.NewCollision(); - if (collision.ColliderA.CollisionGroup == CollisionFilterGroups.CustomFilter1 || // use collision group 1 to distinguish pipe passed trigger from other colliders. - collision.ColliderB.CollisionGroup == CollisionFilterGroups.CustomFilter1) - GameGlobals.PipePassedEventKey.Broadcast(); - } + if (collision.ColliderA.CollisionGroup == CollisionFilterGroups.CustomFilter1 || // use collision group 1 to distinguish pipe passed trigger from other colliders. + collision.ColliderB.CollisionGroup == CollisionFilterGroups.CustomFilter1) + GameGlobals.PipePassedEventKey.Broadcast(); } + } - /// - /// Update the agent according to its states: {Idle, Alive, Die} - /// - public async Task DetectGameOver() + /// + /// Update the agent according to its states: {Idle, Alive, Die} + /// + public async Task DetectGameOver() + { + var physicsComponent = Entity.Components.Get(); + + while (Game.IsRunning) { - var physicsComponent = Entity.Components.Get(); + await Script.NextFrame(); - while (Game.IsRunning) + // detect collisions with the pipes + var collision = await physicsComponent.NewCollision(); + if (collision.ColliderA.CollisionGroup == CollisionFilterGroups.DefaultFilter && + collision.ColliderB.CollisionGroup == CollisionFilterGroups.DefaultFilter) { - await Script.NextFrame(); - - // detect collisions with the pipes - var collision = await physicsComponent.NewCollision(); - if (collision.ColliderA.CollisionGroup == CollisionFilterGroups.DefaultFilter && - collision.ColliderB.CollisionGroup == CollisionFilterGroups.DefaultFilter) - { - isRunning = false; - GameGlobals.GameOverEventKey.Broadcast(); - } + isRunning = false; + GameGlobals.GameOverEventKey.Broadcast(); } } + } - /// - /// Update the agent according to its states: {Idle, Alive, Die} - /// - public override async Task Execute() - { - Start(); + /// + /// Update the agent according to its states: {Idle, Alive, Die} + /// + public override async Task Execute() + { + Start(); - while (Game.IsRunning) - { - await Script.NextFrame(); + while (Game.IsRunning) + { + await Script.NextFrame(); - if (gameResetListener.TryReceive()) - Reset(); + if (gameResetListener.TryReceive()) + Reset(); - if (gameStartedListener.TryReceive()) - isRunning = true; + if (gameStartedListener.TryReceive()) + isRunning = true; - if (!isRunning) - continue; + if (!isRunning) + continue; - var elapsedTime = (float)Game.UpdateTime.Elapsed.TotalSeconds; + var elapsedTime = (float)Game.UpdateTime.Elapsed.TotalSeconds; - // apply impulse on the touch/space - if (Input.IsKeyPressed(Keys.Space) || UserTappedScreen()) - velocity.Y = position.Y > TopLimit ? VelocityAboveTopLimit : NormalVelocityY; + // apply impulse on the touch/space + if (Input.IsKeyPressed(Keys.Space) || UserTappedScreen()) + velocity.Y = position.Y > TopLimit ? VelocityAboveTopLimit : NormalVelocityY; - // update position/velocity - velocity += Gravity * elapsedTime; - position += velocity * elapsedTime; + // update position/velocity + velocity += Gravity * elapsedTime; + position += velocity * elapsedTime; - // update animation and rotation value - UpdateAgentAnimation(); + // update animation and rotation value + UpdateAgentAnimation(); - // update the position/rotation - UpdateTransformation(); - } + // update the position/rotation + UpdateTransformation(); } + } - private void UpdateTransformation() - { - Entity.Transform.Position = position; - Entity.Transform.RotationEulerXYZ = rotation; - } + private void UpdateTransformation() + { + Entity.Transform.Position = position; + Entity.Transform.RotationEulerXYZ = rotation; + } - private bool UserTappedScreen() - { - return Input.PointerEvents.Any(pointerEvent => pointerEvent.EventType == PointerEventType.Pressed); - } + private bool UserTappedScreen() + { + return Input.PointerEvents.Any(pointerEvent => pointerEvent.EventType == PointerEventType.Pressed); + } - private void UpdateAgentAnimation() - { - var isFalling = velocity.Y < 0; - var rotationSign = isFalling ? -1 : 1; - - // Set falling sprite frame - var provider = Entity.Get().SpriteProvider as SpriteFromSheet; - if (provider != null) - provider.CurrentFrame = isFalling ? FallingSpriteFrameIndex : FlyingSpriteFrameIndex; - - // Rotate a sprite - rotation.Z += rotationSign * MathUtil.Pi * 0.01f; - if (rotationSign * rotation.Z > Math.PI / 10f) - rotation.Z = rotationSign * MathUtil.Pi / 10f; - } + private void UpdateAgentAnimation() + { + var isFalling = velocity.Y < 0; + var rotationSign = isFalling ? -1 : 1; + + // Set falling sprite frame + if (Entity.Get().SpriteProvider is SpriteFromSheet provider) + provider.CurrentFrame = isFalling ? FallingSpriteFrameIndex : FlyingSpriteFrameIndex; + + // Rotate a sprite + rotation.Z += rotationSign * MathUtil.Pi * 0.01f; + if (rotationSign * rotation.Z > Math.PI / 10f) + rotation.Z = rotationSign * MathUtil.Pi / 10f; } } diff --git a/samples/Games/JumpyJet/JumpyJet.Game/GameGlobals.cs b/samples/Games/JumpyJet/JumpyJet.Game/GameGlobals.cs index 1982544a03..0db4fc344b 100644 --- a/samples/Games/JumpyJet/JumpyJet.Game/GameGlobals.cs +++ b/samples/Games/JumpyJet/JumpyJet.Game/GameGlobals.cs @@ -3,16 +3,15 @@ using Stride.Engine.Events; -namespace JumpyJet +namespace JumpyJet; + +static class GameGlobals { - static class GameGlobals - { - public static EventKey GameOverEventKey = new EventKey("Global", "Game Over"); - public static EventKey GameStartedEventKey = new EventKey("Global", "Game Started"); - public static EventKey GameResetEventKey = new EventKey("Global", "Game Reset"); - public static EventKey PipePassedEventKey = new EventKey("Global", "Pipe Passed"); + public static EventKey GameOverEventKey = new("Global", "Game Over"); + public static EventKey GameStartedEventKey = new("Global", "Game Started"); + public static EventKey GameResetEventKey = new("Global", "Game Reset"); + public static EventKey PipePassedEventKey = new("Global", "Pipe Passed"); - public const float GameSpeed = 2.90f; - public const float GamePixelToUnitScale = 0.01f; - } + public const float GameSpeed = 2.90f; + public const float GamePixelToUnitScale = 0.01f; } diff --git a/samples/Games/JumpyJet/JumpyJet.Game/JumpyJetRenderer.cs b/samples/Games/JumpyJet/JumpyJet.Game/JumpyJetRenderer.cs index 33f5a49b80..4f9cbb80ea 100644 --- a/samples/Games/JumpyJet/JumpyJet.Game/JumpyJetRenderer.cs +++ b/samples/Games/JumpyJet/JumpyJet.Game/JumpyJetRenderer.cs @@ -7,113 +7,112 @@ using Stride.Rendering; using Stride.Rendering.Compositing; -namespace JumpyJet +namespace JumpyJet; + +public class JumpyJetRenderer : SceneRendererBase { - public class JumpyJetRenderer : SceneRendererBase - { - // Entities' depth - private const int Pal0Depth = 0; - private const int Pal1Depth = 1; - private const int Pal2Depth = 2; - private const int Pal3Depth = 3; + // Entities' depth + private const int Pal0Depth = 0; + private const int Pal1Depth = 1; + private const int Pal2Depth = 2; + private const int Pal3Depth = 3; - private SpriteBatch spriteBatch; + private SpriteBatch spriteBatch; - private readonly List backgroundParallax = new List(); + private readonly List backgroundParallax = []; - public SpriteSheet ParallaxBackgrounds; + public SpriteSheet ParallaxBackgrounds; - /// - /// The main render stage for opaque geometry. - /// - public RenderStage OpaqueRenderStage { get; set; } + /// + /// The main render stage for opaque geometry. + /// + public RenderStage OpaqueRenderStage { get; set; } - /// - /// The transparent render stage for transparent geometry. - /// - public RenderStage TransparentRenderStage { get; set; } + /// + /// The transparent render stage for transparent geometry. + /// + public RenderStage TransparentRenderStage { get; set; } - public void StartScrolling() - { - EnableAllParallaxesUpdate(true); - } + public void StartScrolling() + { + EnableAllParallaxesUpdate(true); + } - public void StopScrolling() - { - EnableAllParallaxesUpdate(false); - } + public void StopScrolling() + { + EnableAllParallaxesUpdate(false); + } - private void EnableAllParallaxesUpdate(bool isEnable) + private void EnableAllParallaxesUpdate(bool isEnable) + { + foreach (var pallarax in backgroundParallax) { - foreach (var pallarax in backgroundParallax) - { - pallarax.IsUpdating = isEnable; - } + pallarax.IsUpdating = isEnable; } + } - protected override void InitializeCore() - { - base.InitializeCore(); + protected override void InitializeCore() + { + base.InitializeCore(); - var virtualResolution = new Vector3(GraphicsDevice.Presenter.BackBuffer.Width, GraphicsDevice.Presenter.BackBuffer.Height, 20f); + var virtualResolution = new Vector3(GraphicsDevice.Presenter.BackBuffer.Width, GraphicsDevice.Presenter.BackBuffer.Height, 20f); - // Create Parallax Background - backgroundParallax.Add(new BackgroundSection(ParallaxBackgrounds.Sprites[0], virtualResolution, 100 * GameGlobals.GameSpeed / 4f, Pal0Depth)); - backgroundParallax.Add(new BackgroundSection(ParallaxBackgrounds.Sprites[1], virtualResolution, 100 * GameGlobals.GameSpeed / 3f, Pal1Depth)); - backgroundParallax.Add(new BackgroundSection(ParallaxBackgrounds.Sprites[2], virtualResolution, 100 * GameGlobals.GameSpeed / 1.5f, Pal2Depth)); + // Create Parallax Background + backgroundParallax.Add(new BackgroundSection(ParallaxBackgrounds.Sprites[0], virtualResolution, 100 * GameGlobals.GameSpeed / 4f, Pal0Depth)); + backgroundParallax.Add(new BackgroundSection(ParallaxBackgrounds.Sprites[1], virtualResolution, 100 * GameGlobals.GameSpeed / 3f, Pal1Depth)); + backgroundParallax.Add(new BackgroundSection(ParallaxBackgrounds.Sprites[2], virtualResolution, 100 * GameGlobals.GameSpeed / 1.5f, Pal2Depth)); - // For pal3Sprite: Ground, move it downward so that its bottom edge is at the bottom screen. - var screenHeight = virtualResolution.Y; - var pal3Height = ParallaxBackgrounds.Sprites[3].SizeInPixels.Y; - backgroundParallax.Add(new BackgroundSection(ParallaxBackgrounds.Sprites[3], virtualResolution, 100 * GameGlobals.GameSpeed, Pal3Depth, Vector2.UnitY * (screenHeight - pal3Height) / 2)); + // For pal3Sprite: Ground, move it downward so that its bottom edge is at the bottom screen. + var screenHeight = virtualResolution.Y; + var pal3Height = ParallaxBackgrounds.Sprites[3].SizeInPixels.Y; + backgroundParallax.Add(new BackgroundSection(ParallaxBackgrounds.Sprites[3], virtualResolution, 100 * GameGlobals.GameSpeed, Pal3Depth, Vector2.UnitY * (screenHeight - pal3Height) / 2)); - // allocate the sprite batch in charge of drawing the backgrounds. - spriteBatch = new SpriteBatch(GraphicsDevice) { VirtualResolution = virtualResolution }; - } + // allocate the sprite batch in charge of drawing the backgrounds. + spriteBatch = new SpriteBatch(GraphicsDevice) { VirtualResolution = virtualResolution }; + } - protected override void CollectCore(RenderContext context) + protected override void CollectCore(RenderContext context) + { + // Setup pixel formats for RenderStage + using (context.SaveRenderOutputAndRestore()) { - // Setup pixel formats for RenderStage - using (context.SaveRenderOutputAndRestore()) + // Fill RenderStage formats and register render stages to main view + if (OpaqueRenderStage != null) + { + context.RenderView.RenderStages.Add(OpaqueRenderStage); + OpaqueRenderStage.Output = context.RenderOutput; + } + if (TransparentRenderStage != null) { - // Fill RenderStage formats and register render stages to main view - if (OpaqueRenderStage != null) - { - context.RenderView.RenderStages.Add(OpaqueRenderStage); - OpaqueRenderStage.Output = context.RenderOutput; - } - if (TransparentRenderStage != null) - { - context.RenderView.RenderStages.Add(TransparentRenderStage); - TransparentRenderStage.Output = context.RenderOutput; - } + context.RenderView.RenderStages.Add(TransparentRenderStage); + TransparentRenderStage.Output = context.RenderOutput; } } + } - protected override void DrawCore(RenderContext context, RenderDrawContext drawContext) - { - var renderSystem = context.RenderSystem; + protected override void DrawCore(RenderContext context, RenderDrawContext drawContext) + { + var renderSystem = context.RenderSystem; - // Clear - drawContext.CommandList.Clear(drawContext.CommandList.DepthStencilBuffer, DepthStencilClearOptions.DepthBuffer); + // Clear + drawContext.CommandList.Clear(drawContext.CommandList.DepthStencilBuffer, DepthStencilClearOptions.DepthBuffer); - // Draw parallax background - spriteBatch.Begin(drawContext.GraphicsContext); + // Draw parallax background + spriteBatch.Begin(drawContext.GraphicsContext); - float elapsedTime = (float)context.Time.Elapsed.TotalSeconds; - foreach (var pallaraxBackground in backgroundParallax) - pallaraxBackground.DrawSprite(elapsedTime, spriteBatch); + float elapsedTime = (float)context.Time.Elapsed.TotalSeconds; + foreach (var pallaraxBackground in backgroundParallax) + pallaraxBackground.DrawSprite(elapsedTime, spriteBatch); - spriteBatch.End(); + spriteBatch.End(); - // Draw [main view | main stage] - if (OpaqueRenderStage != null) - renderSystem.Draw(drawContext, context.RenderView, OpaqueRenderStage); + // Draw [main view | main stage] + if (OpaqueRenderStage != null) + renderSystem.Draw(drawContext, context.RenderView, OpaqueRenderStage); - // Draw [main view | transparent stage] - if (TransparentRenderStage != null) - renderSystem.Draw(drawContext, context.RenderView, TransparentRenderStage); - } + // Draw [main view | transparent stage] + if (TransparentRenderStage != null) + renderSystem.Draw(drawContext, context.RenderView, TransparentRenderStage); } } diff --git a/samples/Games/JumpyJet/JumpyJet.Game/PipesScript.cs b/samples/Games/JumpyJet/JumpyJet.Game/PipesScript.cs index 2371ba1734..0fd9b98566 100644 --- a/samples/Games/JumpyJet/JumpyJet.Game/PipesScript.cs +++ b/samples/Games/JumpyJet/JumpyJet.Game/PipesScript.cs @@ -1,5 +1,6 @@ // Copyright (c) .NET Foundation and Contributors (https://dotnetfoundation.org/ & https://stride3d.net) and Silicon Studio Corp. (https://www.siliconstudio.co.jp) // Distributed under the MIT license. See the LICENSE.md file in the project root for more information. + using System; using System.Collections.Generic; using Stride.Core.Mathematics; @@ -7,104 +8,103 @@ using Stride.Engine; using Stride.Engine.Events; -namespace JumpyJet -{ - /// - /// The script in charge of creating and updating the pipes. - /// - public class PipesScript : SyncScript - { - private const float GapBetweenPipe = 4f; - private const float StartPipePosition = 4f; +namespace JumpyJet; - private EventReceiver gameOverListener = new EventReceiver(GameGlobals.GameOverEventKey); - private EventReceiver gameResetListener = new EventReceiver(GameGlobals.GameResetEventKey); - private EventReceiver gameStartedListener = new EventReceiver(GameGlobals.GameStartedEventKey); +/// +/// The script in charge of creating and updating the pipes. +/// +public class PipesScript : SyncScript +{ + private const float GapBetweenPipe = 4f; + private const float StartPipePosition = 4f; - private readonly List pipeSets = new List(); + private readonly EventReceiver gameOverListener = new(GameGlobals.GameOverEventKey); + private readonly EventReceiver gameResetListener = new(GameGlobals.GameResetEventKey); + private readonly EventReceiver gameStartedListener = new(GameGlobals.GameStartedEventKey); - private bool isScrolling; + private readonly List pipeSets = []; - private readonly Random random = new Random(); + private bool isScrolling; - private float sceneWidth; + private readonly Random random = new(); - // The width of pipe prefab - private float pipeOvervaluedWidth = 1f; + private float sceneWidth; - public UrlReference PipePrefabUrl { get; set; } + // The width of pipe prefab + private readonly float pipeOvervaluedWidth = 1f; - public override void Start() - { - var pipeSetPrefab = Content.Load(PipePrefabUrl); + public UrlReference PipePrefabUrl { get; set; } - // Create PipeSets - sceneWidth = GameGlobals.GamePixelToUnitScale * GraphicsDevice.Presenter.BackBuffer.Width; - var numberOfPipes = (int)Math.Ceiling((sceneWidth + 2 * pipeOvervaluedWidth) / GapBetweenPipe); - for (int i = 0; i < numberOfPipes; i++) - { - var pipeSet = pipeSetPrefab.Instantiate()[0]; - pipeSets.Add(pipeSet); - Entity.AddChild(pipeSet); - } + public override void Start() + { + var pipeSetPrefab = Content.Load(PipePrefabUrl); - // Reset the position of the PipeSets - Reset(); + // Create PipeSets + sceneWidth = GameGlobals.GamePixelToUnitScale * GraphicsDevice.Presenter.BackBuffer.Width; + var numberOfPipes = (int)Math.Ceiling((sceneWidth + 2 * pipeOvervaluedWidth) / GapBetweenPipe); + for (int i = 0; i < numberOfPipes; i++) + { + var pipeSet = pipeSetPrefab.Instantiate()[0]; + pipeSets.Add(pipeSet); + Entity.AddChild(pipeSet); } - public override void Update() - { - if (gameOverListener.TryReceive()) - isScrolling = false; + // Reset the position of the PipeSets + Reset(); + } - if (gameStartedListener.TryReceive()) - isScrolling = true; + public override void Update() + { + if (gameOverListener.TryReceive()) + isScrolling = false; - if (gameResetListener.TryReceive()) - Reset(); + if (gameStartedListener.TryReceive()) + isScrolling = true; - if (!isScrolling) - return; + if (gameResetListener.TryReceive()) + Reset(); - var elapsedTime = (float)Game.UpdateTime.Elapsed.TotalSeconds; + if (!isScrolling) + return; - for (int i = 0; i < pipeSets.Count; i++) - { - var pipeSetTransform = pipeSets[i].Transform; + var elapsedTime = (float)Game.UpdateTime.Elapsed.TotalSeconds; - // update the position of the pipe - pipeSetTransform.Position -= new Vector3(elapsedTime * GameGlobals.GameSpeed, 0, 0); + for (int i = 0; i < pipeSets.Count; i++) + { + var pipeSetTransform = pipeSets[i].Transform; + + // update the position of the pipe + pipeSetTransform.Position -= new Vector3(elapsedTime * GameGlobals.GameSpeed, 0, 0); - // move the pipe to the end of screen if not visible anymore - if (pipeSetTransform.Position.X + pipeOvervaluedWidth / 2 < -sceneWidth / 2) - { + // move the pipe to the end of screen if not visible anymore + if (pipeSetTransform.Position.X + pipeOvervaluedWidth / 2 < -sceneWidth / 2) + { - // When a pipe is determined to be reset, - // get its next position by adding an offset to the position - // of a pipe which index is before itself. - var prevPipeSetIndex = (i - 1 + pipeSets.Count) % pipeSets.Count; + // When a pipe is determined to be reset, + // get its next position by adding an offset to the position + // of a pipe which index is before itself. + var prevPipeSetIndex = (i - 1 + pipeSets.Count) % pipeSets.Count; - var nextPosX = pipeSets[prevPipeSetIndex].Transform.Position.X + GapBetweenPipe; - pipeSetTransform.Position = new Vector3(nextPosX, GetPipeRandomYPosition(), 0); - } + var nextPosX = pipeSets[prevPipeSetIndex].Transform.Position.X + GapBetweenPipe; + pipeSetTransform.Position = new Vector3(nextPosX, GetPipeRandomYPosition(), 0); } } + } - private float GetPipeRandomYPosition() - { - return GameGlobals.GamePixelToUnitScale * random.Next(50, 225); - } + private float GetPipeRandomYPosition() + { + return GameGlobals.GamePixelToUnitScale * random.Next(50, 225); + } - private void Reset() - { - for (var i = 0; i < pipeSets.Count; ++i) - pipeSets[i].Transform.Position = new Vector3(StartPipePosition + i * GapBetweenPipe, GetPipeRandomYPosition(), 0); - } + private void Reset() + { + for (var i = 0; i < pipeSets.Count; ++i) + pipeSets[i].Transform.Position = new Vector3(StartPipePosition + i * GapBetweenPipe, GetPipeRandomYPosition(), 0); + } - public override void Cancel() - { - // remove all the children pipes. - Entity.Transform.Children.Clear(); - } + public override void Cancel() + { + // remove all the children pipes. + Entity.Transform.Children.Clear(); } } diff --git a/samples/Games/JumpyJet/JumpyJet.Game/UIScript.cs b/samples/Games/JumpyJet/JumpyJet.Game/UIScript.cs index 8a14ba777f..cdd8b962fb 100644 --- a/samples/Games/JumpyJet/JumpyJet.Game/UIScript.cs +++ b/samples/Games/JumpyJet/JumpyJet.Game/UIScript.cs @@ -1,5 +1,6 @@ // Copyright (c) .NET Foundation and Contributors (https://dotnetfoundation.org/ & https://stride3d.net) and Silicon Studio Corp. (https://www.siliconstudio.co.jp) // Distributed under the MIT license. See the LICENSE.md file in the project root for more information. + using Stride.Core; using Stride.Core.Mathematics; using Stride.Engine; @@ -10,213 +11,212 @@ using Stride.UI.Controls; using Stride.UI.Panels; -namespace JumpyJet +namespace JumpyJet; + +/// +/// UIScript manages UIElements using in the game. +/// At one time UI.RootElement is one of each root which corresponding to each state of the game. +/// +/// It provides a ButtonClickedEvent Action that could be subscribed by its user. +/// This action provides the name of Button element that is clicked, +/// which is one of {startButton, MenuBotton and RestartButton} +/// +public class UIScript : SyncScript { - /// - /// UIScript manages UIElements using in the game. - /// At one time UI.RootElement is one of each root which corresponding to each state of the game. - /// - /// It provides a ButtonClickedEvent Action that could be subscribed by its user. - /// This action provides the name of Button element that is clicked, - /// which is one of {startButton, MenuBotton and RestartButton} - /// - public class UIScript : SyncScript - { - private EventReceiver gameOverListener = new EventReceiver(GameGlobals.GameOverEventKey); - private EventReceiver pipePassedListener = new EventReceiver(GameGlobals.PipePassedEventKey); + private readonly EventReceiver gameOverListener = new(GameGlobals.GameOverEventKey); + private readonly EventReceiver pipePassedListener = new(GameGlobals.PipePassedEventKey); - public SpriteFont Font; - public SpriteSheet UIImages; + public SpriteFont Font; + public SpriteSheet UIImages; - private ModalElement mainMenuRoot; - private Canvas gameRoot; - private ModalElement gameOverRoot; + private ModalElement mainMenuRoot; + private Canvas gameRoot; + private ModalElement gameOverRoot; - private TextBlock scoreTextBlock; - private ISpriteProvider buttonImage; + private TextBlock scoreTextBlock; + private ISpriteProvider buttonImage; - private int currentScore = 0; + private int currentScore; - /// - /// Load resource and construct ui components - /// - public override void Start() - { - // Load resources shared by different UI screens - buttonImage = SpriteFromSheet.Create(UIImages, "button"); - - // Load and create specific UI screens. - CreateMainMenuUI(); - CreateGameUI(); - CreateGameOverUI(); - - // set the default screen to main screen - StartMainMenuMode(); - } + /// + /// Load resource and construct ui components + /// + public override void Start() + { + // Load resources shared by different UI screens + buttonImage = SpriteFromSheet.Create(UIImages, "button"); - public override void Update() - { - // Increase the score if a new pipe has been passed - if (pipePassedListener.TryReceive()) - ++currentScore; + // Load and create specific UI screens. + CreateMainMenuUI(); + CreateGameUI(); + CreateGameOverUI(); - // move to game over UI - if (gameOverListener.TryReceive()) - { - currentScore = 0; - Entity.Get().Page = new UIPage { RootElement = gameOverRoot }; - } + // set the default screen to main screen + StartMainMenuMode(); + } - // Update the current score - scoreTextBlock.Text = "Score : {0,2}".ToFormat(currentScore); - } + public override void Update() + { + // Increase the score if a new pipe has been passed + if (pipePassedListener.TryReceive()) + ++currentScore; - /// - /// Change UI mode to main menu - /// - public void StartMainMenuMode() - { - Entity.Get().Page = new UIPage { RootElement = mainMenuRoot }; - } - /// - /// Change UI mode to game mode - /// - public void StartGameMode() + // move to game over UI + if (gameOverListener.TryReceive()) { - Entity.Get().Page = new UIPage { RootElement = gameRoot }; + currentScore = 0; + Entity.Get().Page = new UIPage { RootElement = gameOverRoot }; } - private void CreateMainMenuUI() - { - var strideLogo = new ImageElement { Source = SpriteFromSheet.Create(UIImages, "sd_logo") }; - - strideLogo.SetCanvasPinOrigin(new Vector3(0.5f, 0.5f, 1f)); - strideLogo.SetCanvasRelativeSize(new Vector3(0.75f, 0.5f, 1f)); - strideLogo.SetCanvasRelativePosition(new Vector3(0.5f, 0.3f, 1f)); + // Update the current score + scoreTextBlock.Text = "Score : {0,2}".ToFormat(currentScore); + } - var startButton = new Button - { - Content = new TextBlock - { - Font = Font, - Text = "Touch to Start", - TextColor = Color.Black, - HorizontalAlignment = HorizontalAlignment.Center, - VerticalAlignment = VerticalAlignment.Center - }, - NotPressedImage = buttonImage, - PressedImage = buttonImage, - MouseOverImage = buttonImage, - Padding = new Thickness(77, 30, 25, 30), - MinimumWidth = 250f, - }; - - startButton.SetCanvasPinOrigin(new Vector3(0.5f, 0.5f, 1f)); - startButton.SetCanvasRelativePosition(new Vector3(0.5f, 0.7f, 0f)); - startButton.Click += (sender, args) => - { - GameGlobals.GameStartedEventKey.Broadcast(); - StartGameMode(); - }; + /// + /// Change UI mode to main menu + /// + public void StartMainMenuMode() + { + Entity.Get().Page = new UIPage { RootElement = mainMenuRoot }; + } + /// + /// Change UI mode to game mode + /// + public void StartGameMode() + { + Entity.Get().Page = new UIPage { RootElement = gameRoot }; + } - var mainMenuCanvas = new Canvas(); - mainMenuCanvas.Children.Add(strideLogo); - mainMenuCanvas.Children.Add(startButton); + private void CreateMainMenuUI() + { + var strideLogo = new ImageElement { Source = SpriteFromSheet.Create(UIImages, "sd_logo") }; - mainMenuRoot = new ModalElement - { - HorizontalAlignment = HorizontalAlignment.Stretch, - VerticalAlignment = VerticalAlignment.Stretch, - Content = mainMenuCanvas - }; - } + strideLogo.SetCanvasPinOrigin(new Vector3(0.5f, 0.5f, 1f)); + strideLogo.SetCanvasRelativeSize(new Vector3(0.75f, 0.5f, 1f)); + strideLogo.SetCanvasRelativePosition(new Vector3(0.5f, 0.3f, 1f)); - private void CreateGameUI() + var startButton = new Button { - scoreTextBlock = new TextBlock + Content = new TextBlock { Font = Font, + Text = "Touch to Start", TextColor = Color.Black, + HorizontalAlignment = HorizontalAlignment.Center, VerticalAlignment = VerticalAlignment.Center - }; - scoreTextBlock.SetCanvasPinOrigin(new Vector3(0.5f, 0.5f, 1f)); - scoreTextBlock.SetCanvasRelativePosition(new Vector3(0.2f, 0.05f, 0f)); + }, + NotPressedImage = buttonImage, + PressedImage = buttonImage, + MouseOverImage = buttonImage, + Padding = new Thickness(77, 30, 25, 30), + MinimumWidth = 250f, + }; + + startButton.SetCanvasPinOrigin(new Vector3(0.5f, 0.5f, 1f)); + startButton.SetCanvasRelativePosition(new Vector3(0.5f, 0.7f, 0f)); + startButton.Click += (sender, args) => + { + GameGlobals.GameStartedEventKey.Broadcast(); + StartGameMode(); + }; - var scoreBoard = new ContentDecorator - { - BackgroundImage = SpriteFromSheet.Create(UIImages, "score_bg"), - Content = scoreTextBlock, - Padding = new Thickness(60, 31, 25, 35), - MinimumWidth = 190f // Set the minimum width of score button so that it wont modify when the content (text) changes, and less than minimum. - }; - - gameRoot = new Canvas(); - gameRoot.Children.Add(scoreBoard); - } + var mainMenuCanvas = new Canvas(); + mainMenuCanvas.Children.Add(strideLogo); + mainMenuCanvas.Children.Add(startButton); - private void CreateGameOverUI() + mainMenuRoot = new ModalElement { - var menuButton = new Button - { - Content = new TextBlock - { - Font = Font, - Text = "Menu", - TextColor = Color.Black, - HorizontalAlignment = HorizontalAlignment.Center, - VerticalAlignment = VerticalAlignment.Center - }, - PressedImage = buttonImage, - NotPressedImage = buttonImage, - MouseOverImage = buttonImage, - Padding = new Thickness(77, 30, 25, 30), - MinimumWidth = 190f, - }; - - menuButton.SetCanvasPinOrigin(new Vector3(0.5f, 0.5f, 1f)); - menuButton.SetCanvasRelativePosition(new Vector3(0.70f, 0.7f, 0f)); - menuButton.Click += (sender, args) => - { - GameGlobals.GameResetEventKey.Broadcast(); - StartMainMenuMode(); - }; + HorizontalAlignment = HorizontalAlignment.Stretch, + VerticalAlignment = VerticalAlignment.Stretch, + Content = mainMenuCanvas + }; + } + + private void CreateGameUI() + { + scoreTextBlock = new TextBlock + { + Font = Font, + TextColor = Color.Black, + VerticalAlignment = VerticalAlignment.Center + }; + scoreTextBlock.SetCanvasPinOrigin(new Vector3(0.5f, 0.5f, 1f)); + scoreTextBlock.SetCanvasRelativePosition(new Vector3(0.2f, 0.05f, 0f)); + + var scoreBoard = new ContentDecorator + { + BackgroundImage = SpriteFromSheet.Create(UIImages, "score_bg"), + Content = scoreTextBlock, + Padding = new Thickness(60, 31, 25, 35), + MinimumWidth = 190f // Set the minimum width of score button so that it wont modify when the content (text) changes, and less than minimum. + }; + + gameRoot = new Canvas(); + gameRoot.Children.Add(scoreBoard); + } - var retryButton = new Button + private void CreateGameOverUI() + { + var menuButton = new Button + { + Content = new TextBlock { - Content = new TextBlock - { - Font = Font, - Text = "Retry", - TextColor = Color.Black, - HorizontalAlignment = HorizontalAlignment.Center, - VerticalAlignment = VerticalAlignment.Center - }, - Padding = new Thickness(74, 30, 25, 30), - MinimumWidth = 190f, - PressedImage = buttonImage, - MouseOverImage = buttonImage, - NotPressedImage = buttonImage - }; - - retryButton.SetCanvasPinOrigin(new Vector3(0.5f, 0.5f, 1f)); - retryButton.SetCanvasRelativePosition(new Vector3(0.3f, 0.7f, 0f)); - retryButton.Click += (sender, args) => + Font = Font, + Text = "Menu", + TextColor = Color.Black, + HorizontalAlignment = HorizontalAlignment.Center, + VerticalAlignment = VerticalAlignment.Center + }, + PressedImage = buttonImage, + NotPressedImage = buttonImage, + MouseOverImage = buttonImage, + Padding = new Thickness(77, 30, 25, 30), + MinimumWidth = 190f, + }; + + menuButton.SetCanvasPinOrigin(new Vector3(0.5f, 0.5f, 1f)); + menuButton.SetCanvasRelativePosition(new Vector3(0.70f, 0.7f, 0f)); + menuButton.Click += (sender, args) => + { + GameGlobals.GameResetEventKey.Broadcast(); + StartMainMenuMode(); + }; + + var retryButton = new Button + { + Content = new TextBlock { - GameGlobals.GameResetEventKey.Broadcast(); - GameGlobals.GameStartedEventKey.Broadcast(); - StartGameMode(); - }; + Font = Font, + Text = "Retry", + TextColor = Color.Black, + HorizontalAlignment = HorizontalAlignment.Center, + VerticalAlignment = VerticalAlignment.Center + }, + Padding = new Thickness(74, 30, 25, 30), + MinimumWidth = 190f, + PressedImage = buttonImage, + MouseOverImage = buttonImage, + NotPressedImage = buttonImage + }; + + retryButton.SetCanvasPinOrigin(new Vector3(0.5f, 0.5f, 1f)); + retryButton.SetCanvasRelativePosition(new Vector3(0.3f, 0.7f, 0f)); + retryButton.Click += (sender, args) => + { + GameGlobals.GameResetEventKey.Broadcast(); + GameGlobals.GameStartedEventKey.Broadcast(); + StartGameMode(); + }; - var gameOverCanvas = new Canvas(); - gameOverCanvas.Children.Add(menuButton); - gameOverCanvas.Children.Add(retryButton); + var gameOverCanvas = new Canvas(); + gameOverCanvas.Children.Add(menuButton); + gameOverCanvas.Children.Add(retryButton); - gameOverRoot = new ModalElement - { - HorizontalAlignment = HorizontalAlignment.Stretch, - VerticalAlignment = VerticalAlignment.Stretch, - Content = gameOverCanvas - }; - } + gameOverRoot = new ModalElement + { + HorizontalAlignment = HorizontalAlignment.Stretch, + VerticalAlignment = VerticalAlignment.Stretch, + Content = gameOverCanvas + }; } } diff --git a/samples/Games/SpaceEscape/SpaceEscape.Game/Background/BackgroundInfo.cs b/samples/Games/SpaceEscape/SpaceEscape.Game/Background/BackgroundInfo.cs index 5912485d9d..ad693a1bb1 100644 --- a/samples/Games/SpaceEscape/SpaceEscape.Game/Background/BackgroundInfo.cs +++ b/samples/Games/SpaceEscape/SpaceEscape.Game/Background/BackgroundInfo.cs @@ -1,18 +1,12 @@ // Copyright (c) .NET Foundation and Contributors (https://dotnetfoundation.org/ & https://stride3d.net) and Silicon Studio Corp. (https://www.siliconstudio.co.jp) // Distributed under the MIT license. See the LICENSE.md file in the project root for more information. -using System.Collections.Generic; + using Stride.Engine; -namespace SpaceEscape.Background -{ - public class BackgroundInfo : ScriptComponent - { - public BackgroundInfo() - { - Holes = new List(); - } +namespace SpaceEscape.Background; - public int MaxNbObstacles { get; set; } - public List Holes { get; private set; } - } +public class BackgroundInfo : ScriptComponent +{ + public int MaxNbObstacles { get; set; } + public List Holes { get; private set; } = []; } diff --git a/samples/Games/SpaceEscape/SpaceEscape.Game/Background/BackgroundScript.cs b/samples/Games/SpaceEscape/SpaceEscape.Game/Background/BackgroundScript.cs index 9f1c6e9b60..5f8e202d97 100644 --- a/samples/Games/SpaceEscape/SpaceEscape.Game/Background/BackgroundScript.cs +++ b/samples/Games/SpaceEscape/SpaceEscape.Game/Background/BackgroundScript.cs @@ -1,249 +1,244 @@ // Copyright (c) .NET Foundation and Contributors (https://dotnetfoundation.org/ & https://stride3d.net) and Silicon Studio Corp. (https://www.siliconstudio.co.jp) // Distributed under the MIT license. See the LICENSE.md file in the project root for more information. -using System; -using System.Collections.Generic; +using SpaceEscape.Effects; using Stride.Core.Mathematics; -using Stride.Rendering; using Stride.Engine; -using SpaceEscape.Effects; -using System.Linq; -using Stride.Core.Extensions; +using Stride.Rendering; + +namespace SpaceEscape.Background; -namespace SpaceEscape.Background +/// +/// BackgroundScript controls background section in the game. +/// +public class BackgroundScript : SyncScript { - /// - /// BackgroundScript controls background section in the game. - /// - public class BackgroundScript : SyncScript - { - public event Action DistanceUpdated; + public event Action DistanceUpdated; - private const float GameSpeed = 30f; - private const float RemoveBlockPosition = -16f; - private const float AddBlockPosition = 280f; - private const int NumberOfStartBlock = 5; + private const float GameSpeed = 30f; + private const float RemoveBlockPosition = -16f; + private const float AddBlockPosition = 280f; + private const int NumberOfStartBlock = 5; - public Scene LevelBlocks; - public Model SkyplaneModel; // Cache to scroll its UV region. + public Scene LevelBlocks; + public Model SkyplaneModel; // Cache to scroll its UV region. - internal static readonly Random Random = new Random(); - private readonly List
levelBlocks = new List
(); - private LevelGenerator levelGenerator; - private float runningDistance; // Store how far the player progressed in m. + internal static readonly Random Random = new(); + private readonly List
levelBlocks = []; + private LevelGenerator levelGenerator; + private float runningDistance; // Store how far the player progressed in m. - private static readonly Vector3 SkyPlanePosition = new Vector3(0, -10f, 340f); - private Vector4 skyplaneUVRegion = new Vector4(0f, 0f, 1f, 1f); - private bool isScrolling; - private Entity skyplaneEntity; + private static readonly Vector3 SkyPlanePosition = new(0, -10f, 340f); + private Vector4 skyplaneUVRegion = new(0f, 0f, 1f, 1f); + private bool isScrolling; + private Entity skyplaneEntity; - private float RunningDistance + private float RunningDistance + { + get{ return runningDistance; } + set { - get{ return runningDistance; } - set - { - runningDistance = value; - if (DistanceUpdated != null) - DistanceUpdated(runningDistance); - } + runningDistance = value; + if (DistanceUpdated != null) + DistanceUpdated(runningDistance); } + } - public override void Start() - { - var levelBlockEntity = LevelBlocks.Entities.First(x => x.Name == "LevelBlocks"); - levelGenerator = levelBlockEntity.Get(); + public override void Start() + { + var levelBlockEntity = LevelBlocks.Entities.First(x => x.Name == "LevelBlocks"); + levelGenerator = levelBlockEntity.Get(); - RunningDistance = 0f; + RunningDistance = 0f; - // Load SkyPlane - skyplaneEntity = new Entity { new ModelComponent(SkyplaneModel) }; + // Load SkyPlane + skyplaneEntity = new Entity { new ModelComponent(SkyplaneModel) }; - skyplaneEntity.Transform.Position= SkyPlanePosition; - SkyplaneModel.Meshes[0].Parameters.Set(GameParameters.EnableBend, false); - SkyplaneModel.Meshes[0].Parameters.Set(GameParameters.EnableOnflyTextureUVChange, true); + skyplaneEntity.Transform.Position= SkyPlanePosition; + SkyplaneModel.Meshes[0].Parameters.Set(GameParameters.EnableBend, false); + SkyplaneModel.Meshes[0].Parameters.Set(GameParameters.EnableOnflyTextureUVChange, true); - // Add skyPlane with LevelBlocks to EntitySystem - SceneSystem.SceneInstance.RootScene.Entities.Add(skyplaneEntity); - CreateStartLevelBlocks(); - } + // Add skyPlane with LevelBlocks to EntitySystem + SceneSystem.SceneInstance.RootScene.Entities.Add(skyplaneEntity); + CreateStartLevelBlocks(); + } + + public override void Cancel() + { + Entity.Transform.Children.Clear(); + SceneSystem.SceneInstance.RootScene.Entities.Remove(skyplaneEntity); + } + + public override void Update() + { + if (!isScrolling) + return; - public override void Cancel() + var elapsedTime = (float)Game.UpdateTime.Elapsed.TotalSeconds; + + // Check if needed to remove the first block + var firstBlock = levelBlocks[0]; + if (firstBlock.PositionZ + firstBlock.Length * 0.5f < RemoveBlockPosition) { - Entity.Transform.Children.Clear(); - SceneSystem.SceneInstance.RootScene.Entities.Remove(skyplaneEntity); + RemoveLevelBlock(firstBlock); } - public override void Update() + // Check if needed to add new levelblock + var lastBlock = levelBlocks[^1]; + if (lastBlock.PositionZ - lastBlock.Length * 0.5f < AddBlockPosition) { - if (!isScrolling) - return; - - var elapsedTime = (float)Game.UpdateTime.Elapsed.TotalSeconds; - - // Check if needed to remove the first block - var firstBlock = levelBlocks[0]; - if (firstBlock.PositionZ + firstBlock.Length * 0.5f < RemoveBlockPosition) - { - RemoveLevelBlock(firstBlock); - } + AddLevelBlock(levelGenerator.RandomCreateLevelBlock()); + } - // Check if needed to add new levelblock - var lastBlock = levelBlocks[levelBlocks.Count - 1]; - if (lastBlock.PositionZ - lastBlock.Length * 0.5f < AddBlockPosition) - { - AddLevelBlock(levelGenerator.RandomCreateLevelBlock()); - } + // Move levelblocks + foreach (var levelBlock in levelBlocks) + { + var moveDist = GameSpeed * elapsedTime; + levelBlock.PositionZ -= moveDist; + RunningDistance += moveDist / 100f; + } - // Move levelblocks - foreach (var levelBlock in levelBlocks) - { - var moveDist = GameSpeed * elapsedTime; - levelBlock.PositionZ -= moveDist; - RunningDistance += moveDist / 100f; - } + if (skyplaneUVRegion.X < -1f) + // Reset scrolling position of Skyplane's UV + skyplaneUVRegion.X = 0f; - if (skyplaneUVRegion.X < -1f) - // Reset scrolling position of Skyplane's UV - skyplaneUVRegion.X = 0f; + // Move Scroll position by an offset every frame. + skyplaneUVRegion.X -= 0.0005f; - // Move Scroll position by an offset every frame. - skyplaneUVRegion.X -= 0.0005f; + // Update Parameters of the shader + SkyplaneModel.Meshes[0].Parameters.Set(TransformationTextureUVKeys.TextureRegion, skyplaneUVRegion); + } - // Update Parameters of the shader - SkyplaneModel.Meshes[0].Parameters.Set(TransformationTextureUVKeys.TextureRegion, skyplaneUVRegion); - } + public void Reset() + { + RunningDistance = 0f; + isScrolling = false; - public void Reset() + for (var i = levelBlocks.Count - 1; i >= 0; i--) { - RunningDistance = 0f; - isScrolling = false; + var levelBlock = levelBlocks[i]; - for (var i = levelBlocks.Count - 1; i >= 0; i--) - { - var levelBlock = levelBlocks[i]; - - Entity.RemoveChild(levelBlock.RootEntity); - levelBlocks.RemoveAt(i); - } - - CreateStartLevelBlocks(); + Entity.RemoveChild(levelBlock.RootEntity); + levelBlocks.RemoveAt(i); } - public bool DetectCollisions(ref BoundingBox agentBB) + CreateStartLevelBlocks(); + } + + public bool DetectCollisions(ref BoundingBox agentBB) + { + foreach (var levelBlock in levelBlocks) { - foreach (var levelBlock in levelBlocks) + foreach (var obst in levelBlock.CollidableObstacles) { - foreach (var obst in levelBlock.CollidableObstacles) - { - if (DetectCollision(ref agentBB, obst)) - return true; - } + if (DetectCollision(ref agentBB, obst)) + return true; } - - return false; } - private static bool DetectCollision(ref BoundingBox agentBB, - Obstacle obst) - { - var objTrans = obst.Entity.Transform; - objTrans.UpdateWorldMatrix(); - - var objWorldPos = objTrans.WorldMatrix.TranslationVector; + return false; + } - foreach (var boundingBox in obst.BoundingBoxes) - { - var minVec = objWorldPos + boundingBox.Minimum; - var maxVec = objWorldPos + boundingBox.Maximum; - var testBB = new BoundingBox(minVec, maxVec); + private static bool DetectCollision(ref BoundingBox agentBB, + Obstacle obst) + { + var objTrans = obst.Entity.Transform; + objTrans.UpdateWorldMatrix(); - if (CollisionHelper.BoxContainsBox(ref testBB, ref agentBB) != ContainmentType.Disjoint) - return true; - } - return false; - } + var objWorldPos = objTrans.WorldMatrix.TranslationVector; - /// - /// Starts the scrolling of the background - /// - public void StartScrolling() + foreach (var boundingBox in obst.BoundingBoxes) { - isScrolling = true; - } + var minVec = objWorldPos + boundingBox.Minimum; + var maxVec = objWorldPos + boundingBox.Maximum; + var testBB = new BoundingBox(minVec, maxVec); - /// - /// Stops the scrolling of the background - /// - public void StopScrolling() - { - isScrolling = false; + if (CollisionHelper.BoxContainsBox(ref testBB, ref agentBB) != ContainmentType.Disjoint) + return true; } + return false; + } - public bool DetectHoles(ref Vector3 agentWorldPos, out float height) - { - height = 0f; + /// + /// Starts the scrolling of the background + /// + public void StartScrolling() + { + isScrolling = true; + } + + /// + /// Stops the scrolling of the background + /// + public void StopScrolling() + { + isScrolling = false; + } - foreach (var levelBlock in levelBlocks) + public bool DetectHoles(ref Vector3 agentWorldPos, out float height) + { + height = 0f; + + foreach (var levelBlock in levelBlocks) + { + levelBlock.RootEntity.Transform.UpdateWorldMatrix(); + var worldPosZ = levelBlock.RootEntity.Transform.Position.Z; + foreach (var hole in levelBlock.Holes) { - levelBlock.RootEntity.Transform.UpdateWorldMatrix(); - var worldPosZ = levelBlock.RootEntity.Transform.Position.Z; - foreach (var hole in levelBlock.Holes) - { - if (DetectHole(ref agentWorldPos, out height, hole, - worldPosZ)) - return true; - } + if (DetectHole(ref agentWorldPos, out height, hole, + worldPosZ)) + return true; } - return false; } + return false; + } - private static bool DetectHole(ref Vector3 agentWorldPos, out float height, Hole hole, float blockPosZ) - { - var testArea = hole.Area; - testArea.Y += blockPosZ; - height = hole.Height; + private static bool DetectHole(ref Vector3 agentWorldPos, out float height, Hole hole, float blockPosZ) + { + var testArea = hole.Area; + testArea.Y += blockPosZ; + height = hole.Height; - var agentVec2Pos = new Vector2(-agentWorldPos.X, agentWorldPos.Z); - return RectContains(ref testArea, ref agentVec2Pos); - } + var agentVec2Pos = new Vector2(-agentWorldPos.X, agentWorldPos.Z); + return RectContains(ref testArea, ref agentVec2Pos); + } - private void CreateStartLevelBlocks() - { - AddLevelBlock(levelGenerator.CreateSafeLevelBlock()); + private void CreateStartLevelBlocks() + { + AddLevelBlock(levelGenerator.CreateSafeLevelBlock()); - for (var i = 0; i < NumberOfStartBlock; i++) - AddLevelBlock(levelGenerator.RandomCreateLevelBlock()); - } + for (var i = 0; i < NumberOfStartBlock; i++) + AddLevelBlock(levelGenerator.RandomCreateLevelBlock()); + } - private void AddLevelBlock(Section newSection) - { - var count = levelBlocks.Count; - levelBlocks.Add(newSection); + private void AddLevelBlock(Section newSection) + { + var count = levelBlocks.Count; + levelBlocks.Add(newSection); - if (count == 0) - { - Entity.AddChild(newSection.RootEntity); - return; - } + if (count == 0) + { + Entity.AddChild(newSection.RootEntity); + return; + } - var prevLatestBlock = levelBlocks[count - 1]; + var prevLatestBlock = levelBlocks[count - 1]; - var originDist = 0.5f * (prevLatestBlock.Length + newSection.Length); - newSection.PositionZ = prevLatestBlock.PositionZ + originDist; + var originDist = 0.5f * (prevLatestBlock.Length + newSection.Length); + newSection.PositionZ = prevLatestBlock.PositionZ + originDist; - Entity.AddChild(newSection.RootEntity); - } + Entity.AddChild(newSection.RootEntity); + } - private void RemoveLevelBlock(Section firstBlock) - { - levelBlocks.Remove(firstBlock); - Entity.RemoveChild(firstBlock.RootEntity); - } + private void RemoveLevelBlock(Section firstBlock) + { + levelBlocks.Remove(firstBlock); + Entity.RemoveChild(firstBlock.RootEntity); + } - private static bool RectContains(ref RectangleF rect, ref Vector2 agentPos) - { - return (rect.X <= agentPos.X) && (rect.X + rect.Width >= agentPos.X) - && (rect.Y >= agentPos.Y) && (rect.Y - rect.Height <= agentPos.Y); - } + private static bool RectContains(ref RectangleF rect, ref Vector2 agentPos) + { + return (rect.X <= agentPos.X) && (rect.X + rect.Width >= agentPos.X) + && (rect.Y >= agentPos.Y) && (rect.Y - rect.Height <= agentPos.Y); } } diff --git a/samples/Games/SpaceEscape/SpaceEscape.Game/Background/Hole.cs b/samples/Games/SpaceEscape/SpaceEscape.Game/Background/Hole.cs index 64b001fe61..097f65d70f 100644 --- a/samples/Games/SpaceEscape/SpaceEscape.Game/Background/Hole.cs +++ b/samples/Games/SpaceEscape/SpaceEscape.Game/Background/Hole.cs @@ -1,24 +1,24 @@ // Copyright (c) .NET Foundation and Contributors (https://dotnetfoundation.org/ & https://stride3d.net) and Silicon Studio Corp. (https://www.siliconstudio.co.jp) // Distributed under the MIT license. See the LICENSE.md file in the project root for more information. + using Stride.Core; using Stride.Core.Mathematics; -namespace SpaceEscape.Background +namespace SpaceEscape.Background; + +/// +/// This class contains information needed to describe a hole in the background. +/// +[DataContract("BackgroundElement")] +public class Hole { /// - /// This class contains information needed to describe a hole in the background. + /// The area of the hole. /// - [DataContract("BackgroundElement")] - public class Hole - { - /// - /// The area of the hole. - /// - public RectangleF Area { get; set; } + public RectangleF Area { get; set; } - /// - /// The height of the hole. - /// - public float Height { get; set; } - } + /// + /// The height of the hole. + /// + public float Height { get; set; } } diff --git a/samples/Games/SpaceEscape/SpaceEscape.Game/Background/LevelGenerator.cs b/samples/Games/SpaceEscape/SpaceEscape.Game/Background/LevelGenerator.cs index 7b9a7fa9ab..3915915755 100644 --- a/samples/Games/SpaceEscape/SpaceEscape.Game/Background/LevelGenerator.cs +++ b/samples/Games/SpaceEscape/SpaceEscape.Game/Background/LevelGenerator.cs @@ -1,126 +1,124 @@ // Copyright (c) .NET Foundation and Contributors (https://dotnetfoundation.org/ & https://stride3d.net) and Silicon Studio Corp. (https://www.siliconstudio.co.jp) // Distributed under the MIT license. See the LICENSE.md file in the project root for more information. -using System.Linq; + using Stride.Core.Mathematics; using Stride.Engine; -namespace SpaceEscape.Background -{ +namespace SpaceEscape.Background; + - public class LevelGenerator : ScriptComponent +public class LevelGenerator : ScriptComponent +{ + public Entity Background_a00; + public Entity Background_b00; + public Entity Background_b01; + public Entity Background_b02; + public Entity Background_b03; + public Entity Background_b04; + + public Entity Obstacle1; + public Entity Obstacle2; + + /// + /// Randomly create pattern from defined Factory method of each one. + /// + /// + public Section RandomCreateLevelBlock() { - public Entity Background_a00; - public Entity Background_b00; - public Entity Background_b01; - public Entity Background_b02; - public Entity Background_b03; - public Entity Background_b04; - - public Entity Obstacle1; - public Entity Obstacle2; - - /// - /// Randomly create pattern from defined Factory method of each one. - /// - /// - public Section RandomCreateLevelBlock() + Entity backgroundEntity; + switch (BackgroundScript.Random.Next(6)) { - Entity backgroundEntity; - switch (BackgroundScript.Random.Next(6)) - { - default: - case 0: backgroundEntity = Background_a00; break; - case 1: backgroundEntity = Background_b00; break; - case 2: backgroundEntity = Background_b01; break; - case 3: backgroundEntity = Background_b02; break; - case 4: backgroundEntity = Background_b03; break; - case 5: backgroundEntity = Background_b04; break; - } - - return CreateLevelBlock(backgroundEntity.Clone()); + default: + case 0: backgroundEntity = Background_a00; break; + case 1: backgroundEntity = Background_b00; break; + case 2: backgroundEntity = Background_b01; break; + case 3: backgroundEntity = Background_b02; break; + case 4: backgroundEntity = Background_b03; break; + case 5: backgroundEntity = Background_b04; break; } - public Section CreateSafeLevelBlock() + return CreateLevelBlock(backgroundEntity.Clone()); + } + + public Section CreateSafeLevelBlock() + { + return CreateLevelBlock(Background_a00.Clone(), 0); + } + + /// + /// Randomly get Obstacle from available keys and return the clone. + /// + /// + private Entity CloneRandomObstacle(out bool useSubmeshesBoundingBoxes) + { + Entity obstacleEntity; + switch (BackgroundScript.Random.Next(2)) { - return CreateLevelBlock(Background_a00.Clone(), 0); + default: + case 0: obstacleEntity = Obstacle1; break; + case 1: obstacleEntity = Obstacle2; break; } - /// - /// Randomly get Obstacle from available keys and return the clone. - /// - /// - private Entity CloneRandomObstacle(out bool useSubmeshesBoundingBoxes) - { - Entity obstacleEntity; - switch (BackgroundScript.Random.Next(2)) - { - default: - case 0: obstacleEntity = Obstacle1; break; - case 1: obstacleEntity = Obstacle2; break; - } + useSubmeshesBoundingBoxes = obstacleEntity.Get().UseSubMeshBoundingBoxes; + obstacleEntity = obstacleEntity.Clone(); - useSubmeshesBoundingBoxes = obstacleEntity.Get().UseSubMeshBoundingBoxes; - obstacleEntity = obstacleEntity.Clone(); + // Reset position + obstacleEntity.Transform.Position = Vector3.Zero; - // Reset position - obstacleEntity.Transform.Position = Vector3.Zero; + return obstacleEntity; + } - return obstacleEntity; - } + /// + /// Factory method to create Section from a given BackgroundEntity + /// + /// + /// The maximum number of obstacle in the block level + /// + private Section CreateLevelBlock(Entity backgroundEnt, int? maxObstacleOverride = null) + { + // Reset position + backgroundEnt.Transform.Position = Vector3.Zero; - /// - /// Factory method to create Section from a given BackgroundEntity - /// - /// - /// The maximum number of obstacle in the block level - /// - private Section CreateLevelBlock(Entity backgroundEnt, int? maxObstacleOverride = null) - { - // Reset position - backgroundEnt.Transform.Position = Vector3.Zero; + var levelBlock = new Section(); + var backgroundInfo = backgroundEnt.Get(); + levelBlock.AddBackgroundEntity(backgroundEnt).AddHoleRange(backgroundInfo.Holes); - var levelBlock = new Section(); - var backgroundInfo = backgroundEnt.Get(); - levelBlock.AddBackgroundEntity(backgroundEnt).AddHoleRange(backgroundInfo.Holes); + var len = levelBlock.Length; + RandomAddObstacles(levelBlock, len, maxObstacleOverride ?? backgroundInfo.MaxNbObstacles); - var len = levelBlock.Length; - RandomAddObstacles(levelBlock, len, maxObstacleOverride ?? backgroundInfo.MaxNbObstacles); + return levelBlock; + } - return levelBlock; - } + /// + /// Randomly add obstacles to the given level block, while + /// the number of obstacles to be added is from nbObst. + /// + /// + /// + /// + private void RandomAddObstacles(Section section, float patternLen, int nbObst) + { + var halfPatternLen = patternLen / 2f; - /// - /// Randomly add obstacles to the given level block, while - /// the number of obstacles to be added is from nbObst. - /// - /// - /// - /// - private void RandomAddObstacles(Section section, float patternLen, int nbObst) + for (var i = 0; i < nbObst; i++) { - var halfPatternLen = patternLen / 2f; - - for (var i = 0; i < nbObst; i++) - { - // Random val in {0.0-1.0} - var randVal = BackgroundScript.Random.NextDouble(); + // Random val in {0.0-1.0} + var randVal = BackgroundScript.Random.NextDouble(); - // Calculate position in Z axis by: - // changing the value in uniform space (randVal) to world space. - // the value is substracted with halfPatternLen because the origin (0) is at the center of the block. - var posZ = patternLen * (float)((i + randVal) / nbObst) - halfPatternLen; + // Calculate position in Z axis by: + // changing the value in uniform space (randVal) to world space. + // the value is substracted with halfPatternLen because the origin (0) is at the center of the block. + var posZ = patternLen * (float)((i + randVal) / nbObst) - halfPatternLen; - // Random lane, and get the world position in X axis. - var lane = BackgroundScript.Random.Next(3); - var posX = (1 - lane) * 5f; + // Random lane, and get the world position in X axis. + var lane = BackgroundScript.Random.Next(3); + var posX = (1 - lane) * 5f; - // Randomly get the obstacle, and set the position of this obstacle. - bool useSubBoundingBoxes; - var obsEnt = CloneRandomObstacle(out useSubBoundingBoxes); - obsEnt.Transform.Position = new Vector3(posX, 0, posZ); + // Randomly get the obstacle, and set the position of this obstacle. + var obsEnt = CloneRandomObstacle(out var useSubBoundingBoxes); + obsEnt.Transform.Position = new Vector3(posX, 0, posZ); - section.AddObstacleEntity(obsEnt, useSubBoundingBoxes); - } + section.AddObstacleEntity(obsEnt, useSubBoundingBoxes); } } } diff --git a/samples/Games/SpaceEscape/SpaceEscape.Game/Background/Obstacle.cs b/samples/Games/SpaceEscape/SpaceEscape.Game/Background/Obstacle.cs index 2abbc1a333..8af966878a 100644 --- a/samples/Games/SpaceEscape/SpaceEscape.Game/Background/Obstacle.cs +++ b/samples/Games/SpaceEscape/SpaceEscape.Game/Background/Obstacle.cs @@ -1,24 +1,23 @@ // Copyright (c) .NET Foundation and Contributors (https://dotnetfoundation.org/ & https://stride3d.net) and Silicon Studio Corp. (https://www.siliconstudio.co.jp) // Distributed under the MIT license. See the LICENSE.md file in the project root for more information. -using System.Collections.Generic; + using Stride.Core.Mathematics; using Stride.Engine; -namespace SpaceEscape.Background +namespace SpaceEscape.Background; + +/// +/// The class contains information needed to describe a collidable object. +/// +public class Obstacle { /// - /// The class contains information needed to describe a collidable object. + /// The list of bounding boxes used to determine the collision with the obstacle. /// - public class Obstacle - { - /// - /// The list of bounding boxes used to determine the collision with the obstacle. - /// - public List BoundingBoxes = new List(); + public List BoundingBoxes = []; - /// - /// The entity representing the collidable object. - /// - public Entity Entity { get; set; } - } + /// + /// The entity representing the collidable object. + /// + public Entity Entity { get; set; } } diff --git a/samples/Games/SpaceEscape/SpaceEscape.Game/Background/ObstacleInfo.cs b/samples/Games/SpaceEscape/SpaceEscape.Game/Background/ObstacleInfo.cs index 1826b6b939..ef6da6752a 100644 --- a/samples/Games/SpaceEscape/SpaceEscape.Game/Background/ObstacleInfo.cs +++ b/samples/Games/SpaceEscape/SpaceEscape.Game/Background/ObstacleInfo.cs @@ -1,11 +1,11 @@ // Copyright (c) .NET Foundation and Contributors (https://dotnetfoundation.org/ & https://stride3d.net) and Silicon Studio Corp. (https://www.siliconstudio.co.jp) // Distributed under the MIT license. See the LICENSE.md file in the project root for more information. + using Stride.Engine; -namespace SpaceEscape.Background +namespace SpaceEscape.Background; + +public class ObstacleInfo : ScriptComponent { - public class ObstacleInfo : ScriptComponent - { - public bool UseSubMeshBoundingBoxes; - } + public bool UseSubMeshBoundingBoxes; } diff --git a/samples/Games/SpaceEscape/SpaceEscape.Game/Background/Section.cs b/samples/Games/SpaceEscape/SpaceEscape.Game/Background/Section.cs index c7129761a9..57904fd39c 100644 --- a/samples/Games/SpaceEscape/SpaceEscape.Game/Background/Section.cs +++ b/samples/Games/SpaceEscape/SpaceEscape.Game/Background/Section.cs @@ -1,130 +1,129 @@ // Copyright (c) .NET Foundation and Contributors (https://dotnetfoundation.org/ & https://stride3d.net) and Silicon Studio Corp. (https://www.siliconstudio.co.jp) // Distributed under the MIT license. See the LICENSE.md file in the project root for more information. -using System.Collections.Generic; + using Stride.Core.Mathematics; using Stride.Engine; -namespace SpaceEscape.Background +namespace SpaceEscape.Background; + +/// +/// Represents a section of the background which contains other game objects. +/// +public class Section { /// - /// Represents a section of the background which contains other game objects. + /// Gets the length of the level block + /// + public float Length { get; private set; } + + /// + /// Gets the root entity of the level block + /// + public Entity RootEntity { get; } + + /// + /// Gets the list collidable obstacles of the level block + /// + public List CollidableObstacles { get; } + + /// + /// Gets the list of holes of the level block /// - public class Section + public List Holes { get; } + + /// + /// Create a new empty level block. + /// + public Section() { - /// - /// Gets the length of the level block - /// - public float Length { get; private set; } - - /// - /// Gets the root entity of the level block - /// - public Entity RootEntity { get; private set; } - - /// - /// Gets the list collidable obstacles of the level block - /// - public List CollidableObstacles { get; private set; } - - /// - /// Gets the list of holes of the level block - /// - public List Holes { get; private set; } - - /// - /// Create a new empty level block. - /// - public Section() - { - RootEntity = new Entity(); - CollidableObstacles = new List(); - Holes = new List(); - } + RootEntity = new Entity(); + CollidableObstacles = []; + Holes = []; + } - /// - /// Gets the distance in the Oz axis of the level block to the origin. - /// - public float PositionZ - { - get { return RootEntity.Transform.Position.Z; } - set { RootEntity.Transform.Position.Z = value; } - } + /// + /// Gets the distance in the Oz axis of the level block to the origin. + /// + public float PositionZ + { + get { return RootEntity.Transform.Position.Z; } + set { RootEntity.Transform.Position.Z = value; } + } - public Section AddBackgroundEntity(Entity backgroundEntity) - { - // Attach it in ModelEntity - RootEntity.AddChild(backgroundEntity); + public Section AddBackgroundEntity(Entity backgroundEntity) + { + // Attach it in ModelEntity + RootEntity.AddChild(backgroundEntity); - // Get length via its bounding box - var modelComponent = backgroundEntity.Get().Model; - var boundingBox = modelComponent.BoundingBox; + // Get length via its bounding box + var modelComponent = backgroundEntity.Get().Model; + var boundingBox = modelComponent.BoundingBox; - Length += boundingBox.Maximum.Z - boundingBox.Minimum.Z; + Length += boundingBox.Maximum.Z - boundingBox.Minimum.Z; - return this; - } + return this; + } - /// - /// Chaining method for adding an obstacle to this Section. - /// It initializes bounding boxes and stores in Collidable Obstacles. - /// - /// The entity containing the obstacle - /// true to use the bounding boxes of the sub-meshes - /// - public Section AddObstacleEntity(Entity obstacleEntity, bool useSubBoundingBoxes) - { - // Attach it in ModelEntity - RootEntity.AddChild(obstacleEntity); + /// + /// Chaining method for adding an obstacle to this Section. + /// It initializes bounding boxes and stores in Collidable Obstacles. + /// + /// The entity containing the obstacle + /// true to use the bounding boxes of the sub-meshes + /// + public Section AddObstacleEntity(Entity obstacleEntity, bool useSubBoundingBoxes) + { + // Attach it in ModelEntity + RootEntity.AddChild(obstacleEntity); - // Get and add bb to CollidableObstacles - var modelComponent = obstacleEntity.Get(); + // Get and add bb to CollidableObstacles + var modelComponent = obstacleEntity.Get(); - var collidableObstacle = new Obstacle { Entity = obstacleEntity }; + var collidableObstacle = new Obstacle { Entity = obstacleEntity }; - if (useSubBoundingBoxes) + if (useSubBoundingBoxes) + { + // Use bounding boxes from parts of the obstacle. + foreach (var mesh in modelComponent.Model.Meshes) { - // Use bounding boxes from parts of the obstacle. - foreach (var mesh in modelComponent.Model.Meshes) + var boundingBox = mesh.BoundingBox; + var nodeIndex = mesh.NodeIndex; + while (nodeIndex >= 0) { - var boundingBox = mesh.BoundingBox; - var nodeIndex = mesh.NodeIndex; - while (nodeIndex >= 0) - { - var node = modelComponent.Model.Skeleton.Nodes[nodeIndex]; - var transform = node.Transform; - var matrix = Matrix.Transformation(Vector3.Zero, Quaternion.Identity, transform.Scale, Vector3.Zero, transform.Rotation, transform.Position); + var node = modelComponent.Model.Skeleton.Nodes[nodeIndex]; + var transform = node.Transform; + var matrix = Matrix.Transformation(Vector3.Zero, Quaternion.Identity, transform.Scale, Vector3.Zero, transform.Rotation, transform.Position); - Vector3.TransformNormal(ref boundingBox.Minimum, ref matrix, out boundingBox.Minimum); - Vector3.TransformNormal(ref boundingBox.Maximum, ref matrix, out boundingBox.Maximum); + Vector3.TransformNormal(ref boundingBox.Minimum, ref matrix, out boundingBox.Minimum); + Vector3.TransformNormal(ref boundingBox.Maximum, ref matrix, out boundingBox.Maximum); - nodeIndex = node.ParentIndex; - } - - collidableObstacle.BoundingBoxes.Add(boundingBox); + nodeIndex = node.ParentIndex; } + + collidableObstacle.BoundingBoxes.Add(boundingBox); } - else - { - // Use bounding box of the whole model - collidableObstacle.BoundingBoxes.Add(modelComponent.Model.BoundingBox); - } + } + else + { + // Use bounding box of the whole model + collidableObstacle.BoundingBoxes.Add(modelComponent.Model.BoundingBox); + } - CollidableObstacles.Add(collidableObstacle); + CollidableObstacles.Add(collidableObstacle); - return this; - } + return this; + } - /// - /// Add list of Holes to this Section. - /// - /// - /// - public Section AddHoleRange(List holes) - { - if(holes != null) - Holes.AddRange(holes); + /// + /// Add list of Holes to this Section. + /// + /// + /// + public Section AddHoleRange(List holes) + { + if(holes != null) + Holes.AddRange(holes); - return this; - } + return this; } } diff --git a/samples/Games/SpaceEscape/SpaceEscape.Game/CharacterScript.cs b/samples/Games/SpaceEscape/SpaceEscape.Game/CharacterScript.cs index 4ffc5adfb8..c7658ce248 100644 --- a/samples/Games/SpaceEscape/SpaceEscape.Game/CharacterScript.cs +++ b/samples/Games/SpaceEscape/SpaceEscape.Game/CharacterScript.cs @@ -1,425 +1,420 @@ // Copyright (c) .NET Foundation and Contributors (https://dotnetfoundation.org/ & https://stride3d.net) and Silicon Studio Corp. (https://www.siliconstudio.co.jp) // Distributed under the MIT license. See the LICENSE.md file in the project root for more information. -using System; -using System.Collections.Generic; -using System.Threading.Tasks; +using Stride.Animations; using Stride.Core.Mathematics; using Stride.Engine; -using Stride.Animations; using Stride.Input; -namespace SpaceEscape +namespace SpaceEscape; + +/// +/// CharacterScript is the main character that is controllable by a user. +/// It could change lane to left and right, and slide. +/// +public class CharacterScript : AsyncScript { /// - /// CharacterScript is the main character that is controllable by a user. - /// It could change lane to left and right, and slide. + /// The sprite component containing the shadow of the vessel. /// - public class CharacterScript : AsyncScript + public SpriteComponent CharacterShadow; + + private enum AgentState { - /// - /// The sprite component containing the shadow of the vessel. - /// - public SpriteComponent CharacterShadow; + Run, + ChangeLaneLeft, + ChangeLaneRight, + Slide, + Die, + } - private enum AgentState - { - Run, - ChangeLaneLeft, - ChangeLaneRight, - Slide, - Die, - } + private enum InputState + { + None, + Left, + Right, + Down, + } - private enum InputState - { - None, - Left, - Right, - Down, - } + private enum AgentAnimationKeys + { + Active, + DodgeLeft, + DodgeRight, + Slide, + Crash, + } - private enum AgentAnimationKeys - { - Active, - DodgeLeft, - DodgeRight, - Slide, - Crash, - } + private enum BoundingBoxKeys + { + Normal, + Slide, + } + + private const int LeftLane = 0; + private const int MiddleLane = 1; + private const int RightLane = 2; + private const float LaneLength = 5f; + private float laneHeight; - private enum BoundingBoxKeys + public int CurLane { get; private set; } + private BoundingBox activeBoundingBox; + private AgentState State + { + get { return state; } + set { - Normal, - Slide, + state = value; + OnEnter(state); } + } - private const int LeftLane = 0; - private const int MiddleLane = 1; - private const int RightLane = 2; - private const float LaneLength = 5f; - private float laneHeight; + private bool shouldProcessInput; + private bool started; + private AgentState state; // Current state of the agent + private PlayingAnimation playingAnimation; // Current active animation + private float startChangeLanePosX; // Position of X before changing lane + private float targetChangeLanePosX; // Position of X after changning lane + private readonly Dictionary boundingBoxes = new(); + + public bool IsDead { get { return State == AgentState.Die; } } + + public void Start() + { + // Configure Gestures for controlling the agent + if (!IsLiveReloading) // Live scripting: add the gesture only once (on first load). + Input.Gestures.Add(new GestureConfigDrag(GestureShape.Free) { MinimumDragDistance = 0.02f, RequiredNumberOfFingers = 1 }); - public int CurLane { get; private set; } - private BoundingBox activeBoundingBox; - private AgentState State - { - get { return state; } - set - { - state = value; - OnEnter(state); - } - } + // Setup Normal pose BoundingBox with that of obtained by ModelComponent. + boundingBoxes[BoundingBoxKeys.Normal] = Entity.Get().Model.BoundingBox; + + // Create a slide pose BoundingBox by substracting it with a threshold for making the box, smaller in Y axis. + var modelMinBB = boundingBoxes[BoundingBoxKeys.Normal].Minimum; + var modelMaxBB = boundingBoxes[BoundingBoxKeys.Normal].Maximum; + boundingBoxes[BoundingBoxKeys.Slide] = new BoundingBox(modelMinBB, new Vector3(modelMaxBB.X, modelMaxBB.Y - 0.7f, modelMaxBB.Z)); + + started = true; + } + + /// + /// Script Function which awaits each frame and update the CharacterScript. + /// + /// + public override async Task Execute() + { + Start(); + + laneHeight = Entity.Transform.Position.Y; - private bool shouldProcessInput; - private bool started; - private AgentState state; // Current state of the agent - private PlayingAnimation playingAnimation; // Current active animation - private float startChangeLanePosX; // Position of X before changing lane - private float targetChangeLanePosX; // Position of X after changning lane - private readonly Dictionary boundingBoxes = new Dictionary(); - - public bool IsDead { get { return State == AgentState.Die; } } - - public void Start() + Reset(); + + while (Game.IsRunning) { - // Configure Gestures for controlling the agent - if (!IsLiveReloading) // Live scripting: add the gesture only once (on first load). - Input.Gestures.Add(new GestureConfigDrag(GestureShape.Free) { MinimumDragDistance = 0.02f, RequiredNumberOfFingers = 1 }); + await Script.NextFrame(); + + // Get input state from gesture, if none check from the keyboard. + var inputState = GetInputFromGesture(); - // Setup Normal pose BoundingBox with that of obtained by ModelComponent. - boundingBoxes[BoundingBoxKeys.Normal] = Entity.Get().Model.BoundingBox; + if (inputState == InputState.None) + inputState = GetInputFromKeyboard(); - // Create a slide pose BoundingBox by substracting it with a threshold for making the box, smaller in Y axis. - var modelMinBB = boundingBoxes[BoundingBoxKeys.Normal].Minimum; - var modelMaxBB = boundingBoxes[BoundingBoxKeys.Normal].Maximum; - boundingBoxes[BoundingBoxKeys.Slide] = new BoundingBox(modelMinBB, new Vector3(modelMaxBB.X, modelMaxBB.Y - 0.7f, modelMaxBB.Z)); + // Process obtained input in this frame + ProcessInput(inputState); - started = true; + // Update the agent + UpdateState(); } + } - /// - /// Script Function which awaits each frame and update the CharacterScript. - /// - /// - public override async Task Execute() - { - Start(); + /// + /// Activate the character. + /// + public void Activate() + { + shouldProcessInput = true; + } - laneHeight = Entity.Transform.Position.Y; + /// + /// Reset internal state of the agent. + /// + public void Reset() + { + if (!started) + return; + shouldProcessInput = false; + State = AgentState.Run; + CurLane = MiddleLane; + SetShadowTransparency(1); + Entity.Transform.Position.Y = laneHeight; + Entity.Transform.Position.X = GetXPosition(CurLane); + } - Reset(); + /// + /// Invoke from its user to indicate that the agent has died. + /// + public void OnDied(float floorHeight) + { + State = AgentState.Die; + Entity.Transform.Position.Y = floorHeight; + SetShadowTransparency(0); + } - while (Game.IsRunning) - { - await Script.NextFrame(); + /// + /// Calculate and returns the current bounding box of the character + /// + /// The bounding box + public BoundingBox CalculateCurrentBoundingBox() + { + var agentWorldPosition = Entity.Transform.Position; - // Get input state from gesture, if none check from the keyboard. - var inputState = GetInputFromGesture(); + // Calculate the CharacterScript bounding box + var minVec = agentWorldPosition + activeBoundingBox.Minimum; + var maxVec = agentWorldPosition + activeBoundingBox.Maximum; - if (inputState == InputState.None) - inputState = GetInputFromKeyboard(); + return new BoundingBox(minVec, maxVec); + } - // Process obtained input in this frame - ProcessInput(inputState); + private void SetShadowTransparency(float transparency) + { + CharacterShadow.Color = transparency*Color.White; + } - // Update the agent - UpdateState(); - } + /// + /// Retrieve input from the user by his/her keyboard, and transform to one of the agent's input state. + /// + /// + private InputState GetInputFromKeyboard() + { + if (Input.IsKeyPressed(Keys.Left)) + { + return InputState.Left; } - - /// - /// Activate the character. - /// - public void Activate() + if (Input.IsKeyPressed(Keys.Right)) { - shouldProcessInput = true; + return InputState.Right; } - - /// - /// Reset internal state of the agent. - /// - public void Reset() + if (Input.IsKeyPressed(Keys.Down)) { - if (!started) - return; - shouldProcessInput = false; - State = AgentState.Run; - CurLane = MiddleLane; - SetShadowTransparency(1); - Entity.Transform.Position.Y = laneHeight; - Entity.Transform.Position.X = GetXPosition(CurLane); + return InputState.Down; } + return InputState.None; + } - /// - /// Invoke from its user to indicate that the agent has died. - /// - public void OnDied(float floorHeight) + /// + /// Retrieve input from the user by Drag gesture, and determine the input state by + /// calculating the direction of drag by ProcessInputFromDragGesture(). + /// + /// + private InputState GetInputFromGesture() + { + // Gesture recognition + foreach (var gestureEvent in Input.GestureEvents) { - State = AgentState.Die; - Entity.Transform.Position.Y = floorHeight; - SetShadowTransparency(0); + // Select only Drag gesture with Began state. + if (gestureEvent.Type == GestureType.Drag && gestureEvent.State == GestureState.Began) + // From Draw gesture, determine the InputState from direction of the swipe. + return ProcessInputFromDragGesture((GestureEventDrag)gestureEvent); } - /// - /// Calculate and returns the current bounding box of the character - /// - /// The bounding box - public BoundingBox CalculateCurrentBoundingBox() - { - var agentWorldPosition = Entity.Transform.Position; + return InputState.None; + } - // Calculate the CharacterScript bounding box - var minVec = agentWorldPosition + activeBoundingBox.Minimum; - var maxVec = agentWorldPosition + activeBoundingBox.Maximum; + /// + /// Process gestureEvent to determine the input state. + /// + /// + /// + private InputState ProcessInputFromDragGesture(GestureEventDrag gestureEvent) + { + // Get drag vector and multiply by the screenRatio of the screen, also flip y (-screenRatio). + var screenRatio = (float)GraphicsDevice.Presenter.BackBuffer.Height / GraphicsDevice.Presenter.BackBuffer.Width; + var dragVector = (gestureEvent.CurrentPosition - gestureEvent.StartPosition) * new Vector2(1f, -screenRatio); + var dragDirection = Vector2.Normalize(dragVector); - return new BoundingBox(minVec, maxVec); - } + Vector2 comparedAxis; + float xDeg; + float yDeg; - private void SetShadowTransparency(float transparency) + // Head of dragDirection is in Quadrant 1. + if (dragDirection is { X: >= 0, Y: >= 0 }) { - CharacterShadow.Color = transparency*Color.White; - } + comparedAxis = Vector2.UnitX; + xDeg = FindAngleBetweenVector(ref dragDirection, ref comparedAxis); + comparedAxis = Vector2.UnitY; + yDeg = FindAngleBetweenVector(ref dragDirection, ref comparedAxis); - /// - /// Retrieve input from the user by his/her keyboard, and transform to one of the agent's input state. - /// - /// - private InputState GetInputFromKeyboard() - { - if (Input.IsKeyPressed(Keys.Left)) - { - return InputState.Left; - } - if (Input.IsKeyPressed(Keys.Right)) - { - return InputState.Right; - } - if (Input.IsKeyPressed(Keys.Down)) - { - return InputState.Down; - } - return InputState.None; + return xDeg <= yDeg ? InputState.Right : InputState.None; } - /// - /// Retrieve input from the user by Drag gesture, and determine the input state by - /// calculating the direction of drag by ProcessInputFromDragGesture(). - /// - /// - private InputState GetInputFromGesture() + // Head of dragDirection is in Quadrant 2. + if (dragDirection is { X: <= 0, Y: >= 0 }) { - // Gesture recognition - foreach (var gestureEvent in Input.GestureEvents) - { - // Select only Drag gesture with Began state. - if (gestureEvent.Type == GestureType.Drag && gestureEvent.State == GestureState.Began) - // From Draw gesture, determine the InputState from direction of the swipe. - return ProcessInputFromDragGesture((GestureEventDrag)gestureEvent); - } - - return InputState.None; + comparedAxis = -Vector2.UnitX; + xDeg = FindAngleBetweenVector(ref dragDirection, ref comparedAxis); + comparedAxis = Vector2.UnitY; + yDeg = FindAngleBetweenVector(ref dragDirection, ref comparedAxis); + + return xDeg <= yDeg ? InputState.Left : InputState.None; } - /// - /// Process gestureEvent to determine the input state. - /// - /// - /// - private InputState ProcessInputFromDragGesture(GestureEventDrag gestureEvent) + // Head of dragDirection is in Quadrant 3, check if the input is left or down. + if (dragDirection is { X: <= 0, Y: <= 0 }) { - // Get drag vector and multiply by the screenRatio of the screen, also flip y (-screenRatio). - var screenRatio = (float)GraphicsDevice.Presenter.BackBuffer.Height / GraphicsDevice.Presenter.BackBuffer.Width; - var dragVector = (gestureEvent.CurrentPosition - gestureEvent.StartPosition) * new Vector2(1f, -screenRatio); - var dragDirection = Vector2.Normalize(dragVector); - - Vector2 comparedAxis; - float xDeg; - float yDeg; - - // Head of dragDirection is in Quadrant 1. - if (dragDirection.X >= 0 && dragDirection.Y >= 0) - { - comparedAxis = Vector2.UnitX; - xDeg = FindAngleBetweenVector(ref dragDirection, ref comparedAxis); - comparedAxis = Vector2.UnitY; - yDeg = FindAngleBetweenVector(ref dragDirection, ref comparedAxis); - - return xDeg <= yDeg ? InputState.Right : InputState.None; - } - - // Head of dragDirection is in Quadrant 2. - if (dragDirection.X <= 0 && dragDirection.Y >= 0) - { - comparedAxis = -Vector2.UnitX; - xDeg = FindAngleBetweenVector(ref dragDirection, ref comparedAxis); - comparedAxis = Vector2.UnitY; - yDeg = FindAngleBetweenVector(ref dragDirection, ref comparedAxis); - - return xDeg <= yDeg ? InputState.Left : InputState.None; - } - - // Head of dragDirection is in Quadrant 3, check if the input is left or down. - if (dragDirection.X <= 0 && dragDirection.Y <= 0) - { - comparedAxis = -Vector2.UnitX; - xDeg = FindAngleBetweenVector(ref dragDirection, ref comparedAxis); - comparedAxis = -Vector2.UnitY; - yDeg = FindAngleBetweenVector(ref dragDirection, ref comparedAxis); - - return xDeg <= yDeg ? InputState.Left : InputState.Down; - } - - // Head of dragDirection is in Quadrant 4, check if the input is right or down. - comparedAxis = Vector2.UnitX; + comparedAxis = -Vector2.UnitX; xDeg = FindAngleBetweenVector(ref dragDirection, ref comparedAxis); comparedAxis = -Vector2.UnitY; yDeg = FindAngleBetweenVector(ref dragDirection, ref comparedAxis); - return xDeg <= yDeg ? InputState.Right : InputState.Down; + return xDeg <= yDeg ? InputState.Left : InputState.Down; } - private static float FindAngleBetweenVector(ref Vector2 v1, ref Vector2 v2) + // Head of dragDirection is in Quadrant 4, check if the input is right or down. + comparedAxis = Vector2.UnitX; + xDeg = FindAngleBetweenVector(ref dragDirection, ref comparedAxis); + comparedAxis = -Vector2.UnitY; + yDeg = FindAngleBetweenVector(ref dragDirection, ref comparedAxis); + + return xDeg <= yDeg ? InputState.Right : InputState.Down; + } + + private static float FindAngleBetweenVector(ref Vector2 v1, ref Vector2 v2) + { + Vector2.Dot(ref v1, ref v2, out var dotProd); + return (float)Math.Acos(dotProd); + } + + /// + /// Process user's input, according to the current state. + /// It might change state of the agent. + /// + /// + private void ProcessInput(InputState currentInputState) + { + if (!shouldProcessInput) + return; + + switch (currentInputState) { - float dotProd; - Vector2.Dot(ref v1, ref v2, out dotProd); - return (float)Math.Acos(dotProd); + case InputState.Left: + if (CurLane != LeftLane && State is AgentState.Run or AgentState.Slide) + State = AgentState.ChangeLaneLeft; + break; + case InputState.Right: + if (CurLane != RightLane && State is AgentState.Run or AgentState.Slide) + State = AgentState.ChangeLaneRight; + break; + case InputState.Down: + if (State == AgentState.Run) + State = AgentState.Slide; + break; } + } - /// - /// Process user's input, according to the current state. - /// It might change state of the agent. - /// - /// - private void ProcessInput(InputState currentInputState) + /// + /// Invoke upon enter each state. It sets initial behaviour of the CharacterScript for that state. + /// + /// + private void OnEnter(AgentState agentState) + { + activeBoundingBox = (agentState == AgentState.Slide) + ? boundingBoxes[BoundingBoxKeys.Slide] : + boundingBoxes[BoundingBoxKeys.Normal]; + + switch (agentState) { - if (!shouldProcessInput) - return; - - switch (currentInputState) - { - case InputState.Left: - if (CurLane != LeftLane && (State == AgentState.Run|| State == AgentState.Slide)) - State = AgentState.ChangeLaneLeft; - break; - case InputState.Right: - if (CurLane != RightLane && (State == AgentState.Run || State == AgentState.Slide)) - State = AgentState.ChangeLaneRight; - break; - case InputState.Down: - if (State == AgentState.Run) - State = AgentState.Slide; - break; - } + case AgentState.Run: + PlayAnimation(AgentAnimationKeys.Active); + break; + case AgentState.ChangeLaneLeft: + OnEnterChangeLane(true); + break; + case AgentState.ChangeLaneRight: + OnEnterChangeLane(false); + break; + case AgentState.Slide: + PlayAnimation(AgentAnimationKeys.Slide); + break; + case AgentState.Die: + PlayAnimation(AgentAnimationKeys.Crash); + break; + default: + throw new ArgumentOutOfRangeException(nameof(agentState)); } + } - /// - /// Invoke upon enter each state. It sets initial behaviour of the CharacterScript for that state. - /// - /// - private void OnEnter(AgentState agentState) + /// + /// Upon Enter ChangeLane state, cache the start X position, and determine X position that will arrive for interpolation. + /// And play animation accordingly. + /// + /// + private void OnEnterChangeLane(bool isChangeLaneLeft) + { + if (isChangeLaneLeft) { - activeBoundingBox = (agentState == AgentState.Slide) - ? boundingBoxes[BoundingBoxKeys.Slide] : - boundingBoxes[BoundingBoxKeys.Normal]; - - switch (agentState) - { - case AgentState.Run: - PlayAnimation(AgentAnimationKeys.Active); - break; - case AgentState.ChangeLaneLeft: - OnEnterChangeLane(true); - break; - case AgentState.ChangeLaneRight: - OnEnterChangeLane(false); - break; - case AgentState.Slide: - PlayAnimation(AgentAnimationKeys.Slide); - break; - case AgentState.Die: - PlayAnimation(AgentAnimationKeys.Crash); - break; - default: - throw new ArgumentOutOfRangeException("agentState"); - } + startChangeLanePosX = GetXPosition(CurLane--); + PlayAnimation(AgentAnimationKeys.DodgeLeft); } - - /// - /// Upon Enter ChangeLane state, cache the start X position, and determine X position that will arrive for interpolation. - /// And play animation accordingly. - /// - /// - private void OnEnterChangeLane(bool isChangeLaneLeft) + else { - if (isChangeLaneLeft) - { - startChangeLanePosX = GetXPosition(CurLane--); - PlayAnimation(AgentAnimationKeys.DodgeLeft); - } - else - { - startChangeLanePosX = GetXPosition(CurLane++); - PlayAnimation(AgentAnimationKeys.DodgeRight); - } - - targetChangeLanePosX = GetXPosition(CurLane); + startChangeLanePosX = GetXPosition(CurLane++); + PlayAnimation(AgentAnimationKeys.DodgeRight); } - /// - /// UpdateState updates the agent according to its state. - /// - private void UpdateState() + targetChangeLanePosX = GetXPosition(CurLane); + } + + /// + /// UpdateState updates the agent according to its state. + /// + private void UpdateState() + { + switch (State) { - switch (State) - { - case AgentState.ChangeLaneLeft: - case AgentState.ChangeLaneRight: - UpdateChangeLane(); - break; - case AgentState.Slide: - if (playingAnimation.CurrentTime.TotalSeconds >= playingAnimation.Clip.Duration.TotalSeconds) - State = AgentState.Run; - break; - } + case AgentState.ChangeLaneLeft: + case AgentState.ChangeLaneRight: + UpdateChangeLane(); + break; + case AgentState.Slide: + if (playingAnimation.CurrentTime.TotalSeconds >= playingAnimation.Clip.Duration.TotalSeconds) + State = AgentState.Run; + break; } - /// - /// In ChangeLane state, the agent's X position is determined by Linear interpolation of the current animation process. - /// - private void UpdateChangeLane() - { - var t = (float)(playingAnimation.CurrentTime.TotalSeconds / playingAnimation.Clip.Duration.TotalSeconds); + } + /// + /// In ChangeLane state, the agent's X position is determined by Linear interpolation of the current animation process. + /// + private void UpdateChangeLane() + { + var t = (float)(playingAnimation.CurrentTime.TotalSeconds / playingAnimation.Clip.Duration.TotalSeconds); - // Interpolate new X position in World coordinate. - var newPosX = MathUtil.Lerp(startChangeLanePosX, targetChangeLanePosX, t); - Entity.Transform.Position.X = newPosX; + // Interpolate new X position in World coordinate. + var newPosX = MathUtil.Lerp(startChangeLanePosX, targetChangeLanePosX, t); + Entity.Transform.Position.X = newPosX; - // Animation ends, changing state. - if (t >= 1.0f) - State = AgentState.Run; - } + // Animation ends, changing state. + if (t >= 1.0f) + State = AgentState.Run; + } - /// - /// Helper function for playing animation given AgentAnimationKey. - /// - /// - private void PlayAnimation(AgentAnimationKeys key) - { - var animationComponent = Entity.Get(); - - animationComponent.Play(key.ToString()); - playingAnimation = animationComponent.PlayingAnimations[0]; - } + /// + /// Helper function for playing animation given AgentAnimationKey. + /// + /// + private void PlayAnimation(AgentAnimationKeys key) + { + var animationComponent = Entity.Get(); + + animationComponent.Play(key.ToString()); + playingAnimation = animationComponent.PlayingAnimations[0]; + } - /// - /// Returns world position in X axis for the giving lane index. - /// - /// - /// - private static float GetXPosition(int lane) - { - return (1 - lane) * LaneLength; - } + /// + /// Returns world position in X axis for the giving lane index. + /// + /// + /// + private static float GetXPosition(int lane) + { + return (1 - lane) * LaneLength; } } diff --git a/samples/Games/SpaceEscape/SpaceEscape.Game/Effects/CustomFogEffect.sdsl.cs b/samples/Games/SpaceEscape/SpaceEscape.Game/Effects/CustomFogEffect.sdsl.cs index dacdbdaad0..7cab7e81fa 100644 --- a/samples/Games/SpaceEscape/SpaceEscape.Game/Effects/CustomFogEffect.sdsl.cs +++ b/samples/Games/SpaceEscape/SpaceEscape.Game/Effects/CustomFogEffect.sdsl.cs @@ -1,4 +1,4 @@ -// +// // Do not edit this file yourself! // // This code was generated by Stride Shader Mixin Code Generator. @@ -14,14 +14,13 @@ using Stride.Core.Mathematics; using Buffer = Stride.Graphics.Buffer; -namespace Stride.Rendering +namespace Stride.Rendering; + +public static partial class CustomFogEffectKeys { - public static partial class CustomFogEffectKeys - { - public static readonly ValueParameterKey FogColor = ParameterKeys.NewValue(new Color4(1,1,1,1)); - public static readonly ValueParameterKey fogNearPlaneZ = ParameterKeys.NewValue(80.0f); - public static readonly ValueParameterKey fogFarPlaneZ = ParameterKeys.NewValue(250.0f); - public static readonly ValueParameterKey fogNearPlaneY = ParameterKeys.NewValue(0.0f); - public static readonly ValueParameterKey fogFarPlaneY = ParameterKeys.NewValue(120.0f); - } + public static readonly ValueParameterKey FogColor = ParameterKeys.NewValue(new Color4(1,1,1,1)); + public static readonly ValueParameterKey fogNearPlaneZ = ParameterKeys.NewValue(80.0f); + public static readonly ValueParameterKey fogFarPlaneZ = ParameterKeys.NewValue(250.0f); + public static readonly ValueParameterKey fogNearPlaneY = ParameterKeys.NewValue(0.0f); + public static readonly ValueParameterKey fogFarPlaneY = ParameterKeys.NewValue(120.0f); } diff --git a/samples/Games/SpaceEscape/SpaceEscape.Game/Effects/SpaceEscapeEffectMain.sdfx.cs b/samples/Games/SpaceEscape/SpaceEscape.Game/Effects/SpaceEscapeEffectMain.sdfx.cs index e27e736cc5..4f902e22ba 100644 --- a/samples/Games/SpaceEscape/SpaceEscape.Game/Effects/SpaceEscapeEffectMain.sdfx.cs +++ b/samples/Games/SpaceEscape/SpaceEscape.Game/Effects/SpaceEscapeEffectMain.sdfx.cs @@ -1,4 +1,4 @@ -// +// // Do not edit this file yourself! // // This code was generated by Stride Shader Mixin Code Generator. @@ -14,35 +14,34 @@ using Stride.Core.Mathematics; using Buffer = Stride.Graphics.Buffer; -namespace SpaceEscape.Effects +namespace SpaceEscape.Effects; + +[DataContract]public partial class GameParameters : ShaderMixinParameters { - [DataContract]public partial class GameParameters : ShaderMixinParameters - { - public static readonly PermutationParameterKey EnableFog = ParameterKeys.NewPermutation(true); - public static readonly PermutationParameterKey EnableBend = ParameterKeys.NewPermutation(true); - public static readonly PermutationParameterKey EnableOnflyTextureUVChange = ParameterKeys.NewPermutation(false); - }; - internal static partial class ShaderMixins + public static readonly PermutationParameterKey EnableFog = ParameterKeys.NewPermutation(true); + public static readonly PermutationParameterKey EnableBend = ParameterKeys.NewPermutation(true); + public static readonly PermutationParameterKey EnableOnflyTextureUVChange = ParameterKeys.NewPermutation(false); +}; +internal static partial class ShaderMixins +{ + internal partial class SpaceEscapeEffectMain : IShaderMixinBuilder { - internal partial class SpaceEscapeEffectMain : IShaderMixinBuilder + public void Generate(ShaderMixinSource mixin, ShaderMixinContext context) { - public void Generate(ShaderMixinSource mixin, ShaderMixinContext context) - { - context.Mixin(mixin, "StrideForwardShadingEffect"); - if (context.GetParam(GameParameters.EnableOnflyTextureUVChange)) - context.Mixin(mixin, "TransformationTextureUV"); - if (context.GetParam(GameParameters.EnableBend)) - context.Mixin(mixin, "TransformationBendWorld"); - if (context.GetParam(GameParameters.EnableFog)) - context.Mixin(mixin, "CustomFogEffect"); - } + context.Mixin(mixin, "StrideForwardShadingEffect"); + if (context.GetParam(GameParameters.EnableOnflyTextureUVChange)) + context.Mixin(mixin, "TransformationTextureUV"); + if (context.GetParam(GameParameters.EnableBend)) + context.Mixin(mixin, "TransformationBendWorld"); + if (context.GetParam(GameParameters.EnableFog)) + context.Mixin(mixin, "CustomFogEffect"); + } - [ModuleInitializer] - internal static void __Initialize__() + [ModuleInitializer] + internal static void __Initialize__() - { - ShaderMixinManager.Register("SpaceEscapeEffectMain", new SpaceEscapeEffectMain()); - } + { + ShaderMixinManager.Register("SpaceEscapeEffectMain", new SpaceEscapeEffectMain()); } } } diff --git a/samples/Games/SpaceEscape/SpaceEscape.Game/Effects/TransformationBendWorld.sdsl.cs b/samples/Games/SpaceEscape/SpaceEscape.Game/Effects/TransformationBendWorld.sdsl.cs index a101da0495..6841833ad1 100644 --- a/samples/Games/SpaceEscape/SpaceEscape.Game/Effects/TransformationBendWorld.sdsl.cs +++ b/samples/Games/SpaceEscape/SpaceEscape.Game/Effects/TransformationBendWorld.sdsl.cs @@ -1,4 +1,4 @@ -// +// // Do not edit this file yourself! // // This code was generated by Stride Shader Mixin Code Generator. @@ -14,11 +14,10 @@ using Stride.Core.Mathematics; using Buffer = Stride.Graphics.Buffer; -namespace Stride.Rendering +namespace Stride.Rendering; + +public static partial class TransformationBendWorldKeys { - public static partial class TransformationBendWorldKeys - { - public static readonly ValueParameterKey DeformFactorX = ParameterKeys.NewValue(-0.001f); - public static readonly ValueParameterKey DeformFactorY = ParameterKeys.NewValue(-0.0006f); - } + public static readonly ValueParameterKey DeformFactorX = ParameterKeys.NewValue(-0.001f); + public static readonly ValueParameterKey DeformFactorY = ParameterKeys.NewValue(-0.0006f); } diff --git a/samples/Games/SpaceEscape/SpaceEscape.Game/Effects/TransformationTextureUV.sdsl.cs b/samples/Games/SpaceEscape/SpaceEscape.Game/Effects/TransformationTextureUV.sdsl.cs index 8a174442f7..c5cea0d1a6 100644 --- a/samples/Games/SpaceEscape/SpaceEscape.Game/Effects/TransformationTextureUV.sdsl.cs +++ b/samples/Games/SpaceEscape/SpaceEscape.Game/Effects/TransformationTextureUV.sdsl.cs @@ -1,4 +1,4 @@ -// +// // Do not edit this file yourself! // // This code was generated by Stride Shader Mixin Code Generator. @@ -14,10 +14,9 @@ using Stride.Core.Mathematics; using Buffer = Stride.Graphics.Buffer; -namespace Stride.Rendering +namespace Stride.Rendering; + +public static partial class TransformationTextureUVKeys { - public static partial class TransformationTextureUVKeys - { - public static readonly ValueParameterKey TextureRegion = ParameterKeys.NewValue(new Vector4(0,0,1,1)); - } + public static readonly ValueParameterKey TextureRegion = ParameterKeys.NewValue(new Vector4(0,0,1,1)); } diff --git a/samples/Games/SpaceEscape/SpaceEscape.Game/GameScript.cs b/samples/Games/SpaceEscape/SpaceEscape.Game/GameScript.cs index 08711f9690..1621ce875c 100644 --- a/samples/Games/SpaceEscape/SpaceEscape.Game/GameScript.cs +++ b/samples/Games/SpaceEscape/SpaceEscape.Game/GameScript.cs @@ -1,131 +1,126 @@ // Copyright (c) .NET Foundation and Contributors (https://dotnetfoundation.org/ & https://stride3d.net) and Silicon Studio Corp. (https://www.siliconstudio.co.jp) // Distributed under the MIT license. See the LICENSE.md file in the project root for more information. -using System; -using Stride.Core.Mathematics; -using Stride.Engine; -using Stride.Rendering; using SpaceEscape.Background; +using Stride.Engine; -namespace SpaceEscape +namespace SpaceEscape; + +/// +/// GameScript manages all entities in the game: Camera, CharacterScript, BackgroundScript and Obstacles. +/// +public class GameScript : SyncScript { /// - /// GameScript manages all entities in the game: Camera, CharacterScript, BackgroundScript and Obstacles. + /// The reference to the character script + /// + public CharacterScript CharacterScript; + + /// + /// The reference to the background script + /// + public BackgroundScript BackgroundScript; + + /// + /// The reference to the UI script + /// + public UIScript UIScript; + + public override void Start() + { + // Enable visual of mouse in the game + Game.Window.IsMouseVisible = true; + + // Update the distance displayed in the UI + BackgroundScript.DistanceUpdated += SetDistanceInUI; + + // set behavior of UI button + UIScript.StartButton.Click += StartGame; + UIScript.RetryButton.Click += RestartGame; + UIScript.MenuButton.Click += GoToMenu; + + GoToMenu(this, EventArgs.Empty); + } + + /// + /// Script update loop that detect collision between CharacterScript an obstacles, + /// and detect if the CharacterScript falls to any hole. + /// + /// + public override void Update() + { + if (CharacterScript.IsDead) + return; + + var agentBoundingBox = CharacterScript.CalculateCurrentBoundingBox(); + + // Detect collision between agents and real-world obstacles. + if (BackgroundScript.DetectCollisions(ref agentBoundingBox)) + KillAgent(0); + + // Detect if the CharacterScript falls into a hole + if (BackgroundScript.DetectHoles(ref CharacterScript.Entity.Transform.Position, out var floorHeight)) + KillAgent(floorHeight); + } + + public override void Cancel() + { + BackgroundScript.DistanceUpdated -= SetDistanceInUI; + + UIScript.StartButton.Click -= StartGame; + UIScript.RetryButton.Click -= RestartGame; + UIScript.MenuButton.Click -= GoToMenu; + } + + private void SetDistanceInUI(float curDist) + { + UIScript.SetDistance((int)curDist); + } + + /// + /// Kills the player. + /// + private void KillAgent(float height) + { + CharacterScript.OnDied(height); + UIScript.StartGameOverMode(); + BackgroundScript.StopScrolling(); + } + + /// + /// Reset game's entities: CharacterScript and LevelBlocks. + /// + private void ResetGame() + { + CharacterScript.Reset(); + BackgroundScript.Reset(); + } + + /// + /// Restart playing + /// + private void RestartGame(object sender, EventArgs args) + { + ResetGame(); + StartGame(sender, args); + } + + /// + /// Start playing + /// + private void StartGame(object sender, EventArgs args) + { + UIScript.StartPlayMode(); + BackgroundScript.StartScrolling(); + CharacterScript.Activate(); + } + + /// + /// Go to the menu screen /// - public class GameScript : SyncScript + private void GoToMenu(object sender, EventArgs args) { - /// - /// The reference to the character script - /// - public CharacterScript CharacterScript; - - /// - /// The reference to the background script - /// - public BackgroundScript BackgroundScript; - - /// - /// The reference to the UI script - /// - public UIScript UIScript; - - public override void Start() - { - // Enable visual of mouse in the game - Game.Window.IsMouseVisible = true; - - // Update the distance displayed in the UI - BackgroundScript.DistanceUpdated += SetDistanceInUI; - - // set behavior of UI button - UIScript.StartButton.Click += StartGame; - UIScript.RetryButton.Click += RestartGame; - UIScript.MenuButton.Click += GoToMenu; - - GoToMenu(this, EventArgs.Empty); - } - - /// - /// Script update loop that detect collision between CharacterScript an obstacles, - /// and detect if the CharacterScript falls to any hole. - /// - /// - public override void Update() - { - if (CharacterScript.IsDead) - return; - - float floorHeight; - var agentBoundingBox = CharacterScript.CalculateCurrentBoundingBox(); - - // Detect collision between agents and real-world obstacles. - if (BackgroundScript.DetectCollisions(ref agentBoundingBox)) - KillAgent(0); - - // Detect if the CharacterScript falls into a hole - if (BackgroundScript.DetectHoles(ref CharacterScript.Entity.Transform.Position, out floorHeight)) - KillAgent(floorHeight); - } - - public override void Cancel() - { - BackgroundScript.DistanceUpdated -= SetDistanceInUI; - - UIScript.StartButton.Click -= StartGame; - UIScript.RetryButton.Click -= RestartGame; - UIScript.MenuButton.Click -= GoToMenu; - } - - private void SetDistanceInUI(float curDist) - { - UIScript.SetDistance((int)curDist); - } - - /// - /// Kills the player. - /// - private void KillAgent(float height) - { - CharacterScript.OnDied(height); - UIScript.StartGameOverMode(); - BackgroundScript.StopScrolling(); - } - - /// - /// Reset game's entities: CharacterScript and LevelBlocks. - /// - private void ResetGame() - { - CharacterScript.Reset(); - BackgroundScript.Reset(); - } - - /// - /// Restart playing - /// - private void RestartGame(object sender, EventArgs args) - { - ResetGame(); - StartGame(sender, args); - } - - /// - /// Start playing - /// - private void StartGame(object sender, EventArgs args) - { - UIScript.StartPlayMode(); - BackgroundScript.StartScrolling(); - CharacterScript.Activate(); - } - - /// - /// Go to the menu screen - /// - private void GoToMenu(object sender, EventArgs args) - { - UIScript.StartMainMenuMode(); - ResetGame(); - } + UIScript.StartMainMenuMode(); + ResetGame(); } } diff --git a/samples/Games/SpaceEscape/SpaceEscape.Game/PlayIdleAnimationScript.cs b/samples/Games/SpaceEscape/SpaceEscape.Game/PlayIdleAnimationScript.cs index 00b7bcb11d..8a72059a80 100644 --- a/samples/Games/SpaceEscape/SpaceEscape.Game/PlayIdleAnimationScript.cs +++ b/samples/Games/SpaceEscape/SpaceEscape.Game/PlayIdleAnimationScript.cs @@ -1,21 +1,21 @@ // Copyright (c) .NET Foundation and Contributors (https://dotnetfoundation.org/ & https://stride3d.net) and Silicon Studio Corp. (https://www.siliconstudio.co.jp) // Distributed under the MIT license. See the LICENSE.md file in the project root for more information. + using Stride.Engine; -namespace SpaceEscape +namespace SpaceEscape; + +/// +/// Plays the idle animation of the entity if any +/// +public class PlayAnimationScript : StartupScript { - /// - /// Plays the idle animation of the entity if any - /// - public class PlayAnimationScript : StartupScript - { - public string AnimationName; + public string AnimationName; - public override void Start() - { - var animation = Entity.Get(); - if (animation != null) - animation.Play(AnimationName); - } + public override void Start() + { + var animation = Entity.Get(); + if (animation != null) + animation.Play(AnimationName); } } diff --git a/samples/Games/SpaceEscape/SpaceEscape.Game/Rendering/BendFogRenderFeature.cs b/samples/Games/SpaceEscape/SpaceEscape.Game/Rendering/BendFogRenderFeature.cs index ad84250825..6785786e4b 100644 --- a/samples/Games/SpaceEscape/SpaceEscape.Game/Rendering/BendFogRenderFeature.cs +++ b/samples/Games/SpaceEscape/SpaceEscape.Game/Rendering/BendFogRenderFeature.cs @@ -1,125 +1,118 @@ // Copyright (c) .NET Foundation and Contributors (https://dotnetfoundation.org/ & https://stride3d.net) and Silicon Studio Corp. (https://www.siliconstudio.co.jp) // Distributed under the MIT license. See the LICENSE.md file in the project root for more information. -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; + +using SpaceEscape.Effects; using Stride.Core.Mathematics; -using Stride.Graphics; using Stride.Rendering; -using Stride.Rendering.Materials; -using SpaceEscape.Effects; -namespace SpaceEscape.Rendering +namespace SpaceEscape.Rendering; + +/// +/// Custom render feature, that uploads constants needed by the SpaceEscapeEffectMain effect +/// +public class BendFogRenderFeature : SubRenderFeature { - /// - /// Custom render feature, that uploads constants needed by the SpaceEscapeEffectMain effect - /// - public class BendFogRenderFeature : SubRenderFeature - { - private StaticObjectPropertyKey renderEffectKey; + private StaticObjectPropertyKey renderEffectKey; - private ConstantBufferOffsetReference fog; - private ConstantBufferOffsetReference bend; - private ConstantBufferOffsetReference uvChange; + private ConstantBufferOffsetReference fog; + private ConstantBufferOffsetReference bend; + private ConstantBufferOffsetReference uvChange; - // Constant buffer layout for CustomFogEffect - private struct PerDrawFog - { - public Color4 FogColor; + // Constant buffer layout for CustomFogEffect + private struct PerDrawFog + { + public Color4 FogColor; - public float fogNearPlaneZ; - public float fogFarPlaneZ; + public float fogNearPlaneZ; + public float fogFarPlaneZ; - public float fogNearPlaneY; - public float fogFarPlaneY; - } + public float fogNearPlaneY; + public float fogFarPlaneY; + } - /// - protected override void InitializeCore() - { - base.InitializeCore(); + /// + protected override void InitializeCore() + { + base.InitializeCore(); - renderEffectKey = ((RootEffectRenderFeature)RootRenderFeature).RenderEffectKey; + renderEffectKey = ((RootEffectRenderFeature)RootRenderFeature).RenderEffectKey; - fog = ((RootEffectRenderFeature)RootRenderFeature).CreateDrawCBufferOffsetSlot(CustomFogEffectKeys.FogColor.Name); - bend = ((RootEffectRenderFeature)RootRenderFeature).CreateDrawCBufferOffsetSlot(TransformationBendWorldKeys.DeformFactorX.Name); - uvChange = ((RootEffectRenderFeature)RootRenderFeature).CreateDrawCBufferOffsetSlot(TransformationTextureUVKeys.TextureRegion.Name); - } + fog = ((RootEffectRenderFeature)RootRenderFeature).CreateDrawCBufferOffsetSlot(CustomFogEffectKeys.FogColor.Name); + bend = ((RootEffectRenderFeature)RootRenderFeature).CreateDrawCBufferOffsetSlot(TransformationBendWorldKeys.DeformFactorX.Name); + uvChange = ((RootEffectRenderFeature)RootRenderFeature).CreateDrawCBufferOffsetSlot(TransformationTextureUVKeys.TextureRegion.Name); + } + + /// + public override void PrepareEffectPermutations(RenderDrawContext context) + { + var renderEffects = RootRenderFeature.RenderData.GetData(renderEffectKey); + int effectSlotCount = ((RootEffectRenderFeature)RootRenderFeature).EffectPermutationSlotCount; - /// - public override void PrepareEffectPermutations(RenderDrawContext context) + foreach (var renderObject in RootRenderFeature.RenderObjects) { - var renderEffects = RootRenderFeature.RenderData.GetData(renderEffectKey); - int effectSlotCount = ((RootEffectRenderFeature)RootRenderFeature).EffectPermutationSlotCount; + var staticObjectNode = renderObject.StaticObjectNode; + var renderMesh = (RenderMesh)renderObject; - foreach (var renderObject in RootRenderFeature.RenderObjects) + for (int i = 0; i < effectSlotCount; ++i) { - var staticObjectNode = renderObject.StaticObjectNode; - var renderMesh = (RenderMesh)renderObject; + var staticEffectObjectNode = staticObjectNode * effectSlotCount + i; + var renderEffect = renderEffects[staticEffectObjectNode]; - for (int i = 0; i < effectSlotCount; ++i) - { - var staticEffectObjectNode = staticObjectNode * effectSlotCount + i; - var renderEffect = renderEffects[staticEffectObjectNode]; - - // Skip effects not used during this frame - if (renderEffect == null || !renderEffect.IsUsedDuringThisFrame(RenderSystem)) - continue; - - // Generate shader permuatations - renderEffect.EffectValidator.ValidateParameter(GameParameters.EnableBend, renderMesh.Mesh.Parameters.Get(GameParameters.EnableBend)); - renderEffect.EffectValidator.ValidateParameter(GameParameters.EnableFog, renderMesh.Mesh.Parameters.Get(GameParameters.EnableFog)); - renderEffect.EffectValidator.ValidateParameter(GameParameters.EnableOnflyTextureUVChange, renderMesh.Mesh.Parameters.Get(GameParameters.EnableOnflyTextureUVChange)); - } + // Skip effects not used during this frame + if (renderEffect == null || !renderEffect.IsUsedDuringThisFrame(RenderSystem)) + continue; + + // Generate shader permuatations + renderEffect.EffectValidator.ValidateParameter(GameParameters.EnableBend, renderMesh.Mesh.Parameters.Get(GameParameters.EnableBend)); + renderEffect.EffectValidator.ValidateParameter(GameParameters.EnableFog, renderMesh.Mesh.Parameters.Get(GameParameters.EnableFog)); + renderEffect.EffectValidator.ValidateParameter(GameParameters.EnableOnflyTextureUVChange, renderMesh.Mesh.Parameters.Get(GameParameters.EnableOnflyTextureUVChange)); } } + } - /// - public override unsafe void Prepare(RenderDrawContext context) + /// + public override unsafe void Prepare(RenderDrawContext context) + { + foreach (var renderNode in ((RootEffectRenderFeature)RootRenderFeature).RenderNodes) { - foreach (var renderNode in ((RootEffectRenderFeature)RootRenderFeature).RenderNodes) - { - var perDrawLayout = renderNode.RenderEffect.Reflection.PerDrawLayout; - if (perDrawLayout == null) - continue; + var perDrawLayout = renderNode.RenderEffect.Reflection.PerDrawLayout; + if (perDrawLayout == null) + continue; - var mappedCB = renderNode.Resources.ConstantBuffer.Data; - var renderMesh = (RenderMesh)renderNode.RenderObject; - var parameters = renderMesh.Mesh.Parameters; + var mappedCB = renderNode.Resources.ConstantBuffer.Data; + var renderMesh = (RenderMesh)renderNode.RenderObject; + var parameters = renderMesh.Mesh.Parameters; - // Upload fog parameters - var fogOffset = perDrawLayout.GetConstantBufferOffset(fog); - if (fogOffset != -1) - { - var perDraw = (PerDrawFog*)((byte*)mappedCB + fogOffset); - *perDraw = new PerDrawFog - { - FogColor = Color.FromAbgr(0xFF7D02FF), - fogNearPlaneZ = 80.0f, - fogFarPlaneZ = 250.0f, - fogNearPlaneY = 0.0f, - fogFarPlaneY = 120.0f - }; - } - - // Upload world bending parameters - var bendOffset = perDrawLayout.GetConstantBufferOffset(bend); - if (bendOffset != -1) - { - var perDraw = (float*)((byte*)mappedCB + bendOffset); - *perDraw++ = parameters.Get(TransformationBendWorldKeys.DeformFactorX); - *perDraw = parameters.Get(TransformationBendWorldKeys.DeformFactorX); - } - - // Updload uv change parameters - var uvChangeOffset = perDrawLayout.GetConstantBufferOffset(uvChange); - if (uvChangeOffset != -1) + // Upload fog parameters + var fogOffset = perDrawLayout.GetConstantBufferOffset(fog); + if (fogOffset != -1) + { + var perDraw = (PerDrawFog*)((byte*)mappedCB + fogOffset); + *perDraw = new PerDrawFog { - var perDraw = (Vector4*)((byte*)mappedCB + uvChangeOffset); - *perDraw = parameters.Get(TransformationTextureUVKeys.TextureRegion); - } + FogColor = Color.FromAbgr(0xFF7D02FF), + fogNearPlaneZ = 80.0f, + fogFarPlaneZ = 250.0f, + fogNearPlaneY = 0.0f, + fogFarPlaneY = 120.0f + }; + } + + // Upload world bending parameters + var bendOffset = perDrawLayout.GetConstantBufferOffset(bend); + if (bendOffset != -1) + { + var perDraw = (float*)((byte*)mappedCB + bendOffset); + *perDraw++ = parameters.Get(TransformationBendWorldKeys.DeformFactorX); + *perDraw = parameters.Get(TransformationBendWorldKeys.DeformFactorX); + } + + // Updload uv change parameters + var uvChangeOffset = perDrawLayout.GetConstantBufferOffset(uvChange); + if (uvChangeOffset != -1) + { + var perDraw = (Vector4*)((byte*)mappedCB + uvChangeOffset); + *perDraw = parameters.Get(TransformationTextureUVKeys.TextureRegion); } } } diff --git a/samples/Games/SpaceEscape/SpaceEscape.Game/SpaceEscape.Game.csproj b/samples/Games/SpaceEscape/SpaceEscape.Game/SpaceEscape.Game.csproj index c4fdb3c021..3f8120c249 100644 --- a/samples/Games/SpaceEscape/SpaceEscape.Game/SpaceEscape.Game.csproj +++ b/samples/Games/SpaceEscape/SpaceEscape.Game/SpaceEscape.Game.csproj @@ -3,6 +3,8 @@ net8.0 SpaceEscape true + enable + latest diff --git a/samples/Games/SpaceEscape/SpaceEscape.Game/UIScript.cs b/samples/Games/SpaceEscape/SpaceEscape.Game/UIScript.cs index 73a35f5d0f..f5c716862c 100644 --- a/samples/Games/SpaceEscape/SpaceEscape.Game/UIScript.cs +++ b/samples/Games/SpaceEscape/SpaceEscape.Game/UIScript.cs @@ -1,5 +1,6 @@ // Copyright (c) .NET Foundation and Contributors (https://dotnetfoundation.org/ & https://stride3d.net) and Silicon Studio Corp. (https://www.siliconstudio.co.jp) // Distributed under the MIT license. See the LICENSE.md file in the project root for more information. + using Stride.Core; using Stride.Core.Mathematics; using Stride.Engine; @@ -9,174 +10,173 @@ using Stride.UI.Controls; using Stride.UI.Panels; -namespace SpaceEscape +namespace SpaceEscape; + +/// +/// UIScript manages UIElements using in the game. +/// At one time UI.RootElement is one of each root which corresponding to each state of the game. +/// +/// It provides a ButtonClickedEvent Action that could be subscribed by its user. +/// This action provides the name of Button element that is clicked, +/// which is one of {StartButton, MenuBotton and RestartButton} +/// +public class UIScript : StartupScript { + internal Button StartButton { get; private set; } + internal Button MenuButton { get; private set; } + internal Button RetryButton { get; private set; } + + public SpriteFont Font; + public SpriteSheet UIImages; + + private ModalElement mainMenuRoot; + private Canvas gameRoot; + private ModalElement gameOverRoot; + + private TextBlock distanceTextBlock; + private ISpriteProvider buttonImage; + /// - /// UIScript manages UIElements using in the game. - /// At one time UI.RootElement is one of each root which corresponding to each state of the game. - /// - /// It provides a ButtonClickedEvent Action that could be subscribed by its user. - /// This action provides the name of Button element that is clicked, - /// which is one of {StartButton, MenuBotton and RestartButton} + /// Load resource and construct ui components /// - public class UIScript : StartupScript + public override void Start() { - internal Button StartButton { get; private set; } - internal Button MenuButton { get; private set; } - internal Button RetryButton { get; private set; } - - public SpriteFont Font; - public SpriteSheet UIImages; + base.Start(); + + // Load resources shared by different UI screens + buttonImage = SpriteFromSheet.Create(UIImages, "button"); + + // Load and create specific UI screens. + CreateMainMenuUI(); + CreateGameUI(); + CreateGameOverUI(); + } - private ModalElement mainMenuRoot; - private Canvas gameRoot; - private ModalElement gameOverRoot; + private void CreateMainMenuUI() + { + var strideLogo = new ImageElement { Source = SpriteFromSheet.Create(UIImages, "sd_logo") }; - private TextBlock distanceTextBlock; - private ISpriteProvider buttonImage; + strideLogo.SetCanvasPinOrigin(new Vector3(0.5f, 0.5f, 1f)); + strideLogo.SetCanvasRelativeSize(new Vector3(0.8f, 0.5f, 1f)); + strideLogo.SetCanvasRelativePosition(new Vector3(0.5f, 0.3f, 1f)); - /// - /// Load resource and construct ui components - /// - public override void Start() - { - base.Start(); - - // Load resources shared by different UI screens - buttonImage = SpriteFromSheet.Create(UIImages, "button"); - - // Load and create specific UI screens. - CreateMainMenuUI(); - CreateGameUI(); - CreateGameOverUI(); - } - - private void CreateMainMenuUI() - { - var strideLogo = new ImageElement { Source = SpriteFromSheet.Create(UIImages, "sd_logo") }; - - strideLogo.SetCanvasPinOrigin(new Vector3(0.5f, 0.5f, 1f)); - strideLogo.SetCanvasRelativeSize(new Vector3(0.8f, 0.5f, 1f)); - strideLogo.SetCanvasRelativePosition(new Vector3(0.5f, 0.3f, 1f)); - - StartButton = new Button - { - Content = new TextBlock { Font = Font, Text = "Touch to Start", TextColor = Color.Black, - HorizontalAlignment = HorizontalAlignment.Center, VerticalAlignment = VerticalAlignment.Center}, - NotPressedImage = buttonImage, - PressedImage = buttonImage, - MouseOverImage = buttonImage, - Padding = new Thickness(80, 27, 25, 35), - MinimumWidth = 250f, - }; - - StartButton.SetCanvasPinOrigin(new Vector3(0.5f, 0.5f, 1f)); - StartButton.SetCanvasRelativePosition(new Vector3(0.5f, 0.8f, 0f)); - - var mainMenuCanvas = new Canvas(); - mainMenuCanvas.Children.Add(strideLogo); - mainMenuCanvas.Children.Add(StartButton); - - mainMenuRoot = new ModalElement - { - HorizontalAlignment = HorizontalAlignment.Stretch, - VerticalAlignment = VerticalAlignment.Stretch, - Content = mainMenuCanvas - }; - } - - private void CreateGameUI() + StartButton = new Button { - distanceTextBlock = new TextBlock { Font = Font, TextColor = Color.Gold, VerticalAlignment = VerticalAlignment.Center }; - distanceTextBlock.SetCanvasPinOrigin(new Vector3(0.5f, 0.5f, 1f)); - distanceTextBlock.SetCanvasRelativePosition(new Vector3(0.2f, 0.05f, 0f)); - - var scoreBoard = new ContentDecorator - { - BackgroundImage = SpriteFromSheet.Create(UIImages, "distance_bg"), - Content = distanceTextBlock, - Padding = new Thickness(60, 31, 25, 35), - MinimumWidth = 290f // Set the minimum width of score button so that it wont modify when the content (text) changes, and less than minimum. - }; - - gameRoot = new Canvas(); - gameRoot.Children.Add(scoreBoard); - } - - private void CreateGameOverUI() + Content = new TextBlock { Font = Font, Text = "Touch to Start", TextColor = Color.Black, + HorizontalAlignment = HorizontalAlignment.Center, VerticalAlignment = VerticalAlignment.Center}, + NotPressedImage = buttonImage, + PressedImage = buttonImage, + MouseOverImage = buttonImage, + Padding = new Thickness(80, 27, 25, 35), + MinimumWidth = 250f, + }; + + StartButton.SetCanvasPinOrigin(new Vector3(0.5f, 0.5f, 1f)); + StartButton.SetCanvasRelativePosition(new Vector3(0.5f, 0.8f, 0f)); + + var mainMenuCanvas = new Canvas(); + mainMenuCanvas.Children.Add(strideLogo); + mainMenuCanvas.Children.Add(StartButton); + + mainMenuRoot = new ModalElement { - MenuButton = new Button - { - Content = new TextBlock { Font = Font, Text = "Menu", TextColor = Color.Black, - HorizontalAlignment = HorizontalAlignment.Center, VerticalAlignment = VerticalAlignment.Center}, - PressedImage = buttonImage, - NotPressedImage = buttonImage, - MouseOverImage = buttonImage, - Padding = new Thickness(77, 29, 25, 35), - MinimumWidth = 190f, - }; - - MenuButton.SetCanvasPinOrigin(new Vector3(0.5f, 0.5f, 1f)); - MenuButton.SetCanvasRelativePosition(new Vector3(0.70f, 0.7f, 0f)); - - RetryButton = new Button - { - Content = new TextBlock { Font = Font, Text = "Retry", TextColor = Color.Black, - HorizontalAlignment = HorizontalAlignment.Center, VerticalAlignment = VerticalAlignment.Center}, - Padding = new Thickness(74, 29, 25, 35), - MinimumWidth = 190f, - PressedImage = buttonImage, - MouseOverImage = buttonImage, - NotPressedImage = buttonImage - }; - - RetryButton.SetCanvasPinOrigin(new Vector3(0.5f, 0.5f, 1f)); - RetryButton.SetCanvasRelativePosition(new Vector3(0.3f, 0.7f, 0f)); - - var gameOverCanvas = new Canvas(); - gameOverCanvas.Children.Add(MenuButton); - gameOverCanvas.Children.Add(RetryButton); - - gameOverRoot = new ModalElement - { - HorizontalAlignment = HorizontalAlignment.Stretch, - VerticalAlignment = VerticalAlignment.Stretch, - Content = gameOverCanvas, - MinimumWidth = 200f, - }; - } - - /// - /// Change UI mode to main menu - /// - public void StartMainMenuMode() - { - Entity.Get().Page = new UIPage { RootElement = mainMenuRoot }; - } + HorizontalAlignment = HorizontalAlignment.Stretch, + VerticalAlignment = VerticalAlignment.Stretch, + Content = mainMenuCanvas + }; + } - /// - /// Change UI mode to game - /// - public void StartPlayMode() + private void CreateGameUI() + { + distanceTextBlock = new TextBlock { Font = Font, TextColor = Color.Gold, VerticalAlignment = VerticalAlignment.Center }; + distanceTextBlock.SetCanvasPinOrigin(new Vector3(0.5f, 0.5f, 1f)); + distanceTextBlock.SetCanvasRelativePosition(new Vector3(0.2f, 0.05f, 0f)); + + var scoreBoard = new ContentDecorator { - Entity.Get().Page = new UIPage { RootElement = gameRoot }; - } + BackgroundImage = SpriteFromSheet.Create(UIImages, "distance_bg"), + Content = distanceTextBlock, + Padding = new Thickness(60, 31, 25, 35), + MinimumWidth = 290f // Set the minimum width of score button so that it wont modify when the content (text) changes, and less than minimum. + }; + + gameRoot = new Canvas(); + gameRoot.Children.Add(scoreBoard); + } - /// - /// Change ui mode to game over - /// - public void StartGameOverMode() + private void CreateGameOverUI() + { + MenuButton = new Button + { + Content = new TextBlock { Font = Font, Text = "Menu", TextColor = Color.Black, + HorizontalAlignment = HorizontalAlignment.Center, VerticalAlignment = VerticalAlignment.Center}, + PressedImage = buttonImage, + NotPressedImage = buttonImage, + MouseOverImage = buttonImage, + Padding = new Thickness(77, 29, 25, 35), + MinimumWidth = 190f, + }; + + MenuButton.SetCanvasPinOrigin(new Vector3(0.5f, 0.5f, 1f)); + MenuButton.SetCanvasRelativePosition(new Vector3(0.70f, 0.7f, 0f)); + + RetryButton = new Button { - Entity.Get().Page = new UIPage { RootElement = gameOverRoot }; - } - - /// - /// A function to update UI distance element. - /// - /// - public void SetDistance(int distance) + Content = new TextBlock { Font = Font, Text = "Retry", TextColor = Color.Black, + HorizontalAlignment = HorizontalAlignment.Center, VerticalAlignment = VerticalAlignment.Center}, + Padding = new Thickness(74, 29, 25, 35), + MinimumWidth = 190f, + PressedImage = buttonImage, + MouseOverImage = buttonImage, + NotPressedImage = buttonImage + }; + + RetryButton.SetCanvasPinOrigin(new Vector3(0.5f, 0.5f, 1f)); + RetryButton.SetCanvasRelativePosition(new Vector3(0.3f, 0.7f, 0f)); + + var gameOverCanvas = new Canvas(); + gameOverCanvas.Children.Add(MenuButton); + gameOverCanvas.Children.Add(RetryButton); + + gameOverRoot = new ModalElement { - distanceTextBlock.Text = "Distance : {0,6}".ToFormat(distance); - } + HorizontalAlignment = HorizontalAlignment.Stretch, + VerticalAlignment = VerticalAlignment.Stretch, + Content = gameOverCanvas, + MinimumWidth = 200f, + }; + } + + /// + /// Change UI mode to main menu + /// + public void StartMainMenuMode() + { + Entity.Get().Page = new UIPage { RootElement = mainMenuRoot }; + } + + /// + /// Change UI mode to game + /// + public void StartPlayMode() + { + Entity.Get().Page = new UIPage { RootElement = gameRoot }; + } + + /// + /// Change ui mode to game over + /// + public void StartGameOverMode() + { + Entity.Get().Page = new UIPage { RootElement = gameOverRoot }; + } + + /// + /// A function to update UI distance element. + /// + /// + public void SetDistance(int distance) + { + distanceTextBlock.Text = "Distance : {0,6}".ToFormat(distance); } } diff --git a/samples/Games/SpaceEscape/SpaceEscape.Windows/SpaceEscape.Windows.csproj b/samples/Games/SpaceEscape/SpaceEscape.Windows/SpaceEscape.Windows.csproj index b9819ff48e..685b994001 100644 --- a/samples/Games/SpaceEscape/SpaceEscape.Windows/SpaceEscape.Windows.csproj +++ b/samples/Games/SpaceEscape/SpaceEscape.Windows/SpaceEscape.Windows.csproj @@ -7,6 +7,8 @@ ..\Bin\Windows\$(Configuration)\ false STRIDE_PLATFORM_DESKTOP + enable + latest $(MSBuildThisFileDirectory)..\SpaceEscape.sdpkg diff --git a/samples/Graphics/AnimatedModel/AnimatedModel.Game/AnimatedModel.Game.csproj b/samples/Graphics/AnimatedModel/AnimatedModel.Game/AnimatedModel.Game.csproj index a145f87cf8..8f4e1416a7 100644 --- a/samples/Graphics/AnimatedModel/AnimatedModel.Game/AnimatedModel.Game.csproj +++ b/samples/Graphics/AnimatedModel/AnimatedModel.Game/AnimatedModel.Game.csproj @@ -2,6 +2,8 @@ net8.0 AnimatedModel + enable + latest diff --git a/samples/Graphics/AnimatedModel/AnimatedModel.Game/AnimationScript.cs b/samples/Graphics/AnimatedModel/AnimatedModel.Game/AnimationScript.cs index de4be2098b..6c73e9f3fa 100644 --- a/samples/Graphics/AnimatedModel/AnimatedModel.Game/AnimationScript.cs +++ b/samples/Graphics/AnimatedModel/AnimatedModel.Game/AnimationScript.cs @@ -1,93 +1,92 @@ // Copyright (c) .NET Foundation and Contributors (https://dotnetfoundation.org/ & https://stride3d.net) and Silicon Studio Corp. (https://www.siliconstudio.co.jp) // Distributed under the MIT license. See the LICENSE.md file in the project root for more information. -using System; -using Stride.Core.Mathematics; + using Stride.Animations; +using Stride.Core.Mathematics; using Stride.Engine; using Stride.Rendering.Colors; using Stride.Rendering.Lights; -namespace AnimatedModel +namespace AnimatedModel; + +public class AnimationScript : StartupScript { - public class AnimationScript : StartupScript + public override void Start() { - public override void Start() - { - // Create an AnimationClip. Make sure to properly set it's duration. - var animationClip = new AnimationClip { Duration = TimeSpan.FromSeconds(1) }; + // Create an AnimationClip. Make sure to properly set it's duration. + var animationClip = new AnimationClip { Duration = TimeSpan.FromSeconds(1) }; - // Add some curves, specifying the path to the properties to animate. - // - Components can be index using a special syntax to their key. - // - Properties can be qualified with a type name in parenthesis - // - If a type is not serializable, it's fully qualified name must be used - var colorLightBaseName = typeof(ColorLightBase).AssemblyQualifiedName; - var colorRgbProviderName = typeof(ColorRgbProvider).AssemblyQualifiedName; + // Add some curves, specifying the path to the properties to animate. + // - Components can be index using a special syntax to their key. + // - Properties can be qualified with a type name in parenthesis + // - If a type is not serializable, it's fully qualified name must be used + var colorLightBaseName = typeof(ColorLightBase).AssemblyQualifiedName; + var colorRgbProviderName = typeof(ColorRgbProvider).AssemblyQualifiedName; - animationClip.AddCurve("[TransformComponent.Key].Rotation", CreateLightRotationCurve()); - animationClip.AddCurve(string.Format("[LightComponent.Key].Type.({0})Color.({1})Value", colorLightBaseName, colorRgbProviderName), CreateLightColorCurve()); + animationClip.AddCurve("[TransformComponent.Key].Rotation", CreateLightRotationCurve()); + animationClip.AddCurve($"[LightComponent.Key].Type.({colorLightBaseName})Color.({colorRgbProviderName})Value", CreateLightColorCurve()); - // Optional: Pack all animation channels into an optimized interleaved format - animationClip.Optimize(); + // Optional: Pack all animation channels into an optimized interleaved format + animationClip.Optimize(); - // Add an AnimationComponent to the current entity and register our custom clip - const string animationName = "MyCustomAnimation"; - var animationComponent = Entity.GetOrCreate(); - animationComponent.Animations.Add(animationName, animationClip); + // Add an AnimationComponent to the current entity and register our custom clip + const string animationName = "MyCustomAnimation"; + var animationComponent = Entity.GetOrCreate(); + animationComponent.Animations.Add(animationName, animationClip); - // Start playing the animation right away and keep repeating it - var playingAnimation = animationComponent.Play(animationName); - playingAnimation.RepeatMode = AnimationRepeatMode.LoopInfinite; - playingAnimation.TimeFactor = 0.1f; // slow down - playingAnimation.CurrentTime = TimeSpan.FromSeconds(0.6f); // start at different time - } + // Start playing the animation right away and keep repeating it + var playingAnimation = animationComponent.Play(animationName); + playingAnimation.RepeatMode = AnimationRepeatMode.LoopInfinite; + playingAnimation.TimeFactor = 0.1f; // slow down + playingAnimation.CurrentTime = TimeSpan.FromSeconds(0.6f); // start at different time + } - private AnimationCurve CreateLightColorCurve() + private static AnimationCurve CreateLightColorCurve() + { + return new AnimationCurve { - return new AnimationCurve + InterpolationType = AnimationCurveInterpolationType.Cubic, + KeyFrames = { - InterpolationType = AnimationCurveInterpolationType.Cubic, - KeyFrames = - { - CreateKeyFrame(0.00f, new Vector3(1, 0.45f, 0 * 0.7f)), // Dawn - CreateKeyFrame(0.05f, new Vector3(1, 0.15f, 0) * 0.3f), + CreateKeyFrame(0.00f, new Vector3(1, 0.45f, 0 * 0.7f)), // Dawn + CreateKeyFrame(0.05f, new Vector3(1, 0.15f, 0) * 0.3f), - CreateKeyFrame(0.10f, new Vector3(0)), - CreateKeyFrame(0.25f, new Vector3(0)), // Midnight - CreateKeyFrame(0.40f, new Vector3(0)), + CreateKeyFrame(0.10f, new Vector3(0)), + CreateKeyFrame(0.25f, new Vector3(0)), // Midnight + CreateKeyFrame(0.40f, new Vector3(0)), - CreateKeyFrame(0.45f, new Vector3(1, 0.15f, 0) * 0.3f), - CreateKeyFrame(0.50f, new Vector3(1, 0.45f, 0) * 0.7f), // Dusk - CreateKeyFrame(0.55f, new Vector3(1, 0.65f, 0)), + CreateKeyFrame(0.45f, new Vector3(1, 0.15f, 0) * 0.3f), + CreateKeyFrame(0.50f, new Vector3(1, 0.45f, 0) * 0.7f), // Dusk + CreateKeyFrame(0.55f, new Vector3(1, 0.65f, 0)), - CreateKeyFrame(0.60f, new Vector3(1, 1, 1)), - CreateKeyFrame(0.75f, new Vector3(1, 1, 1)), // Noon - CreateKeyFrame(0.90f, new Vector3(1, 1, 1)), + CreateKeyFrame(0.60f, new Vector3(1, 1, 1)), + CreateKeyFrame(0.75f, new Vector3(1, 1, 1)), // Noon + CreateKeyFrame(0.90f, new Vector3(1, 1, 1)), - CreateKeyFrame(0.95f, new Vector3(1, 0.65f, 0)), - CreateKeyFrame(1.00f, new Vector3(1, 0.35f, 0)), // Dawn - } - }; - } + CreateKeyFrame(0.95f, new Vector3(1, 0.65f, 0)), + CreateKeyFrame(1.00f, new Vector3(1, 0.35f, 0)), // Dawn + } + }; + } - private AnimationCurve CreateLightRotationCurve() + private static AnimationCurve CreateLightRotationCurve() + { + return new AnimationCurve { - return new AnimationCurve + InterpolationType = AnimationCurveInterpolationType.Linear, + KeyFrames = { - InterpolationType = AnimationCurveInterpolationType.Linear, - KeyFrames = - { - CreateKeyFrame(0.00f, Quaternion.RotationX(0)), - CreateKeyFrame(0.25f, Quaternion.RotationX(MathUtil.PiOverTwo)), - CreateKeyFrame(0.50f, Quaternion.RotationX(MathUtil.Pi)), - CreateKeyFrame(0.75f, Quaternion.RotationX(-MathUtil.PiOverTwo)), - CreateKeyFrame(1.00f, Quaternion.RotationX(MathUtil.TwoPi)) - } - }; - } - - private static KeyFrameData CreateKeyFrame(float keyTime, T value) - { - return new KeyFrameData((CompressedTimeSpan)TimeSpan.FromSeconds(keyTime), value); - } + CreateKeyFrame(0.00f, Quaternion.RotationX(0)), + CreateKeyFrame(0.25f, Quaternion.RotationX(MathUtil.PiOverTwo)), + CreateKeyFrame(0.50f, Quaternion.RotationX(MathUtil.Pi)), + CreateKeyFrame(0.75f, Quaternion.RotationX(-MathUtil.PiOverTwo)), + CreateKeyFrame(1.00f, Quaternion.RotationX(MathUtil.TwoPi)) + } + }; } + + private static KeyFrameData CreateKeyFrame(float keyTime, T value) + { + return new KeyFrameData((CompressedTimeSpan)TimeSpan.FromSeconds(keyTime), value); + } } diff --git a/samples/Graphics/AnimatedModel/AnimatedModel.Game/RenderTextureSceneRenderer.cs b/samples/Graphics/AnimatedModel/AnimatedModel.Game/RenderTextureSceneRenderer.cs index 2b122c5fa2..112879e7bc 100644 --- a/samples/Graphics/AnimatedModel/AnimatedModel.Game/RenderTextureSceneRenderer.cs +++ b/samples/Graphics/AnimatedModel/AnimatedModel.Game/RenderTextureSceneRenderer.cs @@ -1,46 +1,46 @@ // Copyright (c) .NET Foundation and Contributors (https://dotnetfoundation.org/ & https://stride3d.net) and Silicon Studio Corp. (https://www.siliconstudio.co.jp) // Distributed under the MIT license. See the LICENSE.md file in the project root for more information. + using Stride.Graphics; using Stride.Rendering; using Stride.Rendering.Compositing; -namespace AnimatedModel +namespace AnimatedModel; + +public class RenderTextureSceneRenderer : SceneRendererBase { - public class RenderTextureSceneRenderer : SceneRendererBase - { - public Texture RenderTexture { get; set; } + public Texture RenderTexture { get; set; } - public ISceneRenderer Child { get; set; } + public ISceneRenderer Child { get; set; } - protected override void CollectCore(RenderContext context) - { - base.CollectCore(context); + protected override void CollectCore(RenderContext context) + { + base.CollectCore(context); - if (RenderTexture == null) - return; + if (RenderTexture == null) + return; - using (context.SaveRenderOutputAndRestore()) - using (context.SaveViewportAndRestore()) - { - context.RenderOutput.RenderTargetFormat0 = RenderTexture.ViewFormat; - context.ViewportState.Viewport0 = new Viewport(0, 0, RenderTexture.ViewWidth, RenderTexture.ViewHeight); + using (context.SaveRenderOutputAndRestore()) + using (context.SaveViewportAndRestore()) + { + context.RenderOutput.RenderTargetFormat0 = RenderTexture.ViewFormat; + context.ViewportState.Viewport0 = new Viewport(0, 0, RenderTexture.ViewWidth, RenderTexture.ViewHeight); - Child?.Collect(context); - } + Child?.Collect(context); } + } - protected override void DrawCore(RenderContext context, RenderDrawContext drawContext) - { - if (RenderTexture == null) - return; + protected override void DrawCore(RenderContext context, RenderDrawContext drawContext) + { + if (RenderTexture == null) + return; - using (drawContext.PushRenderTargetsAndRestore()) - { - var depthBuffer = PushScopedResource(context.Allocator.GetTemporaryTexture2D(RenderTexture.ViewWidth, RenderTexture.ViewHeight, drawContext.CommandList.DepthStencilBuffer.ViewFormat, TextureFlags.DepthStencil)); - drawContext.CommandList.SetRenderTargetAndViewport(depthBuffer, RenderTexture); + using (drawContext.PushRenderTargetsAndRestore()) + { + var depthBuffer = PushScopedResource(context.Allocator.GetTemporaryTexture2D(RenderTexture.ViewWidth, RenderTexture.ViewHeight, drawContext.CommandList.DepthStencilBuffer.ViewFormat, TextureFlags.DepthStencil)); + drawContext.CommandList.SetRenderTargetAndViewport(depthBuffer, RenderTexture); - Child?.Draw(drawContext); - } + Child?.Draw(drawContext); } } } diff --git a/samples/Graphics/AnimatedModel/AnimatedModel.Game/RotateEntity.cs b/samples/Graphics/AnimatedModel/AnimatedModel.Game/RotateEntity.cs index 58f5143a5d..7fd9dd3e1b 100644 --- a/samples/Graphics/AnimatedModel/AnimatedModel.Game/RotateEntity.cs +++ b/samples/Graphics/AnimatedModel/AnimatedModel.Game/RotateEntity.cs @@ -1,32 +1,30 @@ // Copyright (c) .NET Foundation and Contributors (https://dotnetfoundation.org/ & https://stride3d.net) and Silicon Studio Corp. (https://www.siliconstudio.co.jp) // Distributed under the MIT license. See the LICENSE.md file in the project root for more information. -using System.Linq; -using System.Threading.Tasks; + using Stride.Core.Mathematics; using Stride.Engine; -namespace AnimatedModel +namespace AnimatedModel; + +/// +/// Rotate the entity when user slide its finger on the screen. +/// +public class RotateEntity : AsyncScript { - /// - /// Rotate the entity when user slide its finger on the screen. - /// - public class RotateEntity : AsyncScript + public override async Task Execute() { - public override async Task Execute() - { - var rotationSpeed = 0f; + var rotationSpeed = 0f; - while (Game.IsRunning) - { - await Script.NextFrame(); + while (Game.IsRunning) + { + await Script.NextFrame(); - if (Input.PointerEvents.Any()) - rotationSpeed = 200f * Input.PointerEvents.Sum(x => x.DeltaPosition.X); + if (Input.PointerEvents.Any()) + rotationSpeed = 200f * Input.PointerEvents.Sum(x => x.DeltaPosition.X); - rotationSpeed *= 0.93f; - var elapsedTime = (float) Game.UpdateTime.Elapsed.TotalSeconds; - Entity.Transform.Rotation *= Quaternion.RotationY(rotationSpeed * elapsedTime); - } + rotationSpeed *= 0.93f; + var elapsedTime = (float) Game.UpdateTime.Elapsed.TotalSeconds; + Entity.Transform.Rotation *= Quaternion.RotationY(rotationSpeed * elapsedTime); } } } diff --git a/samples/Graphics/AnimatedModel/AnimatedModel.Game/UIScript.cs b/samples/Graphics/AnimatedModel/AnimatedModel.Game/UIScript.cs index 0a85e78dfd..13b21e32fe 100644 --- a/samples/Graphics/AnimatedModel/AnimatedModel.Game/UIScript.cs +++ b/samples/Graphics/AnimatedModel/AnimatedModel.Game/UIScript.cs @@ -1,35 +1,33 @@ // Copyright (c) .NET Foundation and Contributors (https://dotnetfoundation.org/ & https://stride3d.net) and Silicon Studio Corp. (https://www.siliconstudio.co.jp) // Distributed under the MIT license. See the LICENSE.md file in the project root for more information. -using System; + using Stride.Engine; using Stride.Graphics; using Stride.UI; using Stride.UI.Controls; -using Stride.UI.Panels; -namespace AnimatedModel +namespace AnimatedModel; + +public class UIScript : StartupScript { - public class UIScript : StartupScript - { - public Entity Knight; + public Entity Knight; - public SpriteFont Font; + public SpriteFont Font; - public override void Start() - { - base.Start(); + public override void Start() + { + base.Start(); - // Bind the buttons - var page = Entity.Get().Page; + // Bind the buttons + var page = Entity.Get().Page; - var btnIdle = page.RootElement.FindVisualChildOfType