diff --git a/Source/Demos/Demo.EntityComponentSystem/Content/Content.mgcb b/Source/Demos/Demo.EntityComponentSystem/Content/Content.mgcb new file mode 100644 index 00000000..12686f98 --- /dev/null +++ b/Source/Demos/Demo.EntityComponentSystem/Content/Content.mgcb @@ -0,0 +1,40 @@ + +#----------------------------- Global Properties ----------------------------# + +/outputDir:bin/$(Platform) +/intermediateDir:obj/$(Platform) +/platform:Windows +/config: +/profile:Reach +/compress:False + +#-------------------------------- References --------------------------------# + +/reference:../../../MonoGame.Extended.Content.Pipeline/bin/MonoGame.Extended.Content.Pipeline.dll + +#---------------------------------- Content ---------------------------------# + +#begin logo-square-128.png +/importer:TextureImporter +/processor:TextureProcessor +/processorParam:ColorKeyColor=255,0,255,255 +/processorParam:ColorKeyEnabled=True +/processorParam:GenerateMipmaps=False +/processorParam:PremultiplyAlpha=True +/processorParam:ResizeToPowerOfTwo=False +/processorParam:MakeSquare=False +/processorParam:TextureFormat=Color +/build:logo-square-128.png + +#begin motw.png +/importer:TextureImporter +/processor:TextureProcessor +/processorParam:ColorKeyColor=255,0,255,255 +/processorParam:ColorKeyEnabled=True +/processorParam:GenerateMipmaps=False +/processorParam:PremultiplyAlpha=True +/processorParam:ResizeToPowerOfTwo=False +/processorParam:MakeSquare=False +/processorParam:TextureFormat=Color +/build:motw.png + diff --git a/Source/Demos/Demo.EntityComponentSystem/Content/logo-square-128.png b/Source/Demos/Demo.EntityComponentSystem/Content/logo-square-128.png new file mode 100644 index 00000000..1dbe3e85 Binary files /dev/null and b/Source/Demos/Demo.EntityComponentSystem/Content/logo-square-128.png differ diff --git a/Source/Demos/Demo.EntityComponentSystem/Content/motw.png b/Source/Demos/Demo.EntityComponentSystem/Content/motw.png new file mode 100644 index 00000000..08c0e6a1 Binary files /dev/null and b/Source/Demos/Demo.EntityComponentSystem/Content/motw.png differ diff --git a/Source/Demos/Demo.EntityComponentSystem/Demo.EntityComponentSystem.csproj b/Source/Demos/Demo.EntityComponentSystem/Demo.EntityComponentSystem.csproj new file mode 100644 index 00000000..4e824698 --- /dev/null +++ b/Source/Demos/Demo.EntityComponentSystem/Demo.EntityComponentSystem.csproj @@ -0,0 +1,81 @@ + + + + + Debug + AnyCPU + {A2B9E42A-B2D1-476D-9F4B-E64824DA57EE} + WinExe + Properties + Demo.EntityComponentSystem + Demo.EntityComponentSystem + DesktopGL + v4.5 + + + + true + full + false + bin\Debug + DEBUG; + prompt + 4 + false + false + + + true + bin\Release + prompt + 4 + false + false + + + Icon.ico + + + + + + + + + + + $(MonoGameInstallDirectory)\MonoGame\v3.0\Assemblies\$(MonoGamePlatform)\MonoGame.Framework.dll + + + + + + + + + + + + + + + + PreserveNewest + + + + + {41724c52-3d50-45bb-81eb-3c8a247eafd1} + MonoGame.Extended + + + + + + \ No newline at end of file diff --git a/Source/Demos/Demo.EntityComponentSystem/Game1.cs b/Source/Demos/Demo.EntityComponentSystem/Game1.cs new file mode 100644 index 00000000..ed2607bf --- /dev/null +++ b/Source/Demos/Demo.EntityComponentSystem/Game1.cs @@ -0,0 +1,122 @@ +using System; +using Microsoft.Xna.Framework; +using Microsoft.Xna.Framework.Graphics; +using Microsoft.Xna.Framework.Input; +using MonoGame.Extended; +using MonoGame.Extended.Animations.SpriteSheets; +using MonoGame.Extended.Entities; +using MonoGame.Extended.Entities.Systems; +using MonoGame.Extended.Particles; +using MonoGame.Extended.Particles.Modifiers; +using MonoGame.Extended.Particles.Modifiers.Containers; +using MonoGame.Extended.Particles.Modifiers.Interpolators; +using MonoGame.Extended.Particles.Profiles; +using MonoGame.Extended.Sprites; +using MonoGame.Extended.TextureAtlases; +using MonoGame.Extended.ViewportAdapters; + +namespace Demo.EntityComponentSystem +{ + public class Game1 : Game + { + // ReSharper disable once NotAccessedField.Local + private readonly GraphicsDeviceManager _graphicsDeviceManager; + private Camera2D _camera; + + private MonoGame.Extended.Entities.EntityComponentSystem _entityComponentSystem; + private Entity _entity; + + public Game1() + { + _graphicsDeviceManager = new GraphicsDeviceManager(this); + Content.RootDirectory = "Content"; + IsMouseVisible = true; + Window.AllowUserResizing = true; + } + + protected override void LoadContent() + { + var viewportAdapter = new BoxingViewportAdapter(Window, GraphicsDevice, 800, 480); + _camera = new Camera2D(viewportAdapter); + + _entityComponentSystem = new MonoGame.Extended.Entities.EntityComponentSystem(); + _entityComponentSystem.RegisterSystem(new SpriteBatchComponentSystem(GraphicsDevice, _camera)); + _entityComponentSystem.RegisterSystem(new AnimatedSpriteComponentSystem()); + _entityComponentSystem.RegisterSystem(new ParticleEmitterComponentSystem()); + + var logoTexture = Content.Load("logo-square-128"); + _entity = _entityComponentSystem.CreateEntity("logo", new Vector2(400, 240)); + _entity.AttachComponent(new Sprite(logoTexture)); + + var motwTexture = Content.Load("motw"); + var motwAtlas = TextureAtlas.Create(motwTexture, 52, 72); + var motwAnimationFactory = new SpriteSheetAnimationFactory(motwAtlas); + motwAnimationFactory.Add("idle", new SpriteSheetAnimationData(new[] { 0 })); + motwAnimationFactory.Add("walkSouth", new SpriteSheetAnimationData(new[] { 0, 1, 2, 1 }, isLooping: false)); + motwAnimationFactory.Add("walkWest", new SpriteSheetAnimationData(new[] { 12, 13, 14, 13 }, isLooping: false)); + motwAnimationFactory.Add("walkEast", new SpriteSheetAnimationData(new[] { 24, 25, 26, 25 }, isLooping: false)); + motwAnimationFactory.Add("walkNorth", new SpriteSheetAnimationData(new[] { 36, 37, 38, 37 }, isLooping: false)); + + var animatedEntity = _entityComponentSystem.CreateEntity("animated", new Vector2(50, 50)); + animatedEntity.AttachComponent(new AnimatedSprite(motwAnimationFactory, "walkSouth")); + + var particleEntity = _entityComponentSystem.CreateEntity("particles", new Vector2(500, 50)); + var particleEmitter = new ParticleEmitter(new TextureRegion2D(logoTexture), 500, TimeSpan.FromSeconds(0.5f), + Profile.Point()) + { + Parameters = new ParticleReleaseParameters + { + Speed = new Range(0f, 150f), + Quantity = 30, + Rotation = new Range(-1f, 1f), + Scale = new Range(3.0f, 4.0f) + }, + Modifiers = new IModifier[] + { + new AgeModifier + { + Interpolators = new IInterpolator[] + { + new ColorInterpolator + { + InitialColor = new HslColor(0.8f, 0.8f, 0.8f), + FinalColor = new HslColor(0.5f, 0.9f, 1.0f) + } + } + }, + new RotationModifier {RotationRate = -2.1f}, + new RectangleContainerModifier {Width = 800, Height = 480}, + new LinearGravityModifier {Direction = -Vector2.UnitY, Strength = 130f} + } + }; + particleEntity.AttachComponent(particleEmitter); + } + + protected override void UnloadContent() + { + } + + protected override void Update(GameTime gameTime) + { + var deltaTime = (float)gameTime.ElapsedGameTime.TotalSeconds; + var keyboardState = Keyboard.GetState(); + + if (keyboardState.IsKeyDown(Keys.Escape)) + Exit(); + + _entity.Rotation += deltaTime; + _entityComponentSystem.Update(gameTime); + + base.Update(gameTime); + } + + protected override void Draw(GameTime gameTime) + { + GraphicsDevice.Clear(Color.Black); + + _entityComponentSystem.Draw(gameTime); + + base.Draw(gameTime); + } + } +} \ No newline at end of file diff --git a/Source/Demos/Demo.EntityComponentSystem/Icon.ico b/Source/Demos/Demo.EntityComponentSystem/Icon.ico new file mode 100644 index 00000000..7d9dec18 Binary files /dev/null and b/Source/Demos/Demo.EntityComponentSystem/Icon.ico differ diff --git a/Source/Demos/Demo.EntityComponentSystem/OpenTK.dll.config b/Source/Demos/Demo.EntityComponentSystem/OpenTK.dll.config new file mode 100644 index 00000000..9342d688 --- /dev/null +++ b/Source/Demos/Demo.EntityComponentSystem/OpenTK.dll.config @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Source/Demos/Demo.EntityComponentSystem/Program.cs b/Source/Demos/Demo.EntityComponentSystem/Program.cs new file mode 100644 index 00000000..9c8da56e --- /dev/null +++ b/Source/Demos/Demo.EntityComponentSystem/Program.cs @@ -0,0 +1,16 @@ +using System; + +namespace Demo.EntityComponentSystem +{ + internal static class Program + { + [STAThread] + private static void Main(string[] args) + { + using (var game = new Game1()) + { + game.Run(); + } + } + } +} \ No newline at end of file diff --git a/Source/Demos/Demo.EntityComponentSystem/Properties/AssemblyInfo.cs b/Source/Demos/Demo.EntityComponentSystem/Properties/AssemblyInfo.cs new file mode 100644 index 00000000..e79fb489 --- /dev/null +++ b/Source/Demos/Demo.EntityComponentSystem/Properties/AssemblyInfo.cs @@ -0,0 +1,39 @@ +using System.Reflection; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. + +[assembly: AssemblyTitle("Demo.EntityComponentSystem")] +[assembly: AssemblyProduct("Demo.EntityComponentSystem")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyCopyright("Copyright © 2016")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. + +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM + +[assembly: Guid("9b7203c6-a9a6-40e9-a798-893df7f10bf1")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] + +[assembly: AssemblyVersion("3.4.0.456")] +[assembly: AssemblyFileVersion("3.4.0.456")] \ No newline at end of file diff --git a/Source/Demos/Demo.EntityComponentSystem/app.config b/Source/Demos/Demo.EntityComponentSystem/app.config new file mode 100644 index 00000000..5c73fc53 --- /dev/null +++ b/Source/Demos/Demo.EntityComponentSystem/app.config @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/Source/Demos/Demo.Particles/Game1.cs b/Source/Demos/Demo.Particles/Game1.cs index 05f20ab4..d098e9de 100644 --- a/Source/Demos/Demo.Particles/Game1.cs +++ b/Source/Demos/Demo.Particles/Game1.cs @@ -95,9 +95,8 @@ namespace Demo.Particles { Emitters = new[] { - new ParticleEmitter(500, TimeSpan.FromSeconds(2.5), Profile.Ring(150f, Profile.CircleRadiation.In)) + new ParticleEmitter(textureRegion, 500, TimeSpan.FromSeconds(2.5), Profile.Ring(150f, Profile.CircleRadiation.In)) { - TextureRegion = textureRegion, Parameters = new ParticleReleaseParameters { Speed = new Range(0f, 50f), diff --git a/Source/Demos/Demo.Platformer/Demo.Platformer.csproj b/Source/Demos/Demo.Platformer/Demo.Platformer.csproj index 66eb7999..dbe985bc 100644 --- a/Source/Demos/Demo.Platformer/Demo.Platformer.csproj +++ b/Source/Demos/Demo.Platformer/Demo.Platformer.csproj @@ -36,16 +36,6 @@ Icon.ico - - - - - - - - - - diff --git a/Source/Demos/Demo.Platformer/Entities/Components/EntityComponent.cs b/Source/Demos/Demo.Platformer/Entities/Components/EntityComponent.cs deleted file mode 100644 index ad8fed61..00000000 --- a/Source/Demos/Demo.Platformer/Entities/Components/EntityComponent.cs +++ /dev/null @@ -1,11 +0,0 @@ -namespace Demo.Platformer.Entities.Components -{ - public abstract class EntityComponent - { - protected EntityComponent() - { - } - - public Entity Entity { get; internal set; } - } -} \ No newline at end of file diff --git a/Source/Demos/Demo.Platformer/Entities/Components/SpriteAnimatorComponent.cs b/Source/Demos/Demo.Platformer/Entities/Components/SpriteAnimatorComponent.cs deleted file mode 100644 index f34d0973..00000000 --- a/Source/Demos/Demo.Platformer/Entities/Components/SpriteAnimatorComponent.cs +++ /dev/null @@ -1,17 +0,0 @@ -using MonoGame.Extended.Animations.SpriteSheets; - -namespace Demo.Platformer.Entities.Components -{ - public class SpriteAnimatorComponent : EntityComponent - { - public SpriteAnimatorComponent(SpriteSheetAnimationFactory animationFactory, string playAnimation = null) - { - Animator = new SpriteSheetAnimator(animationFactory); - - if (playAnimation != null) - Animator.Play(playAnimation); - } - - public SpriteSheetAnimator Animator { get; } - } -} \ No newline at end of file diff --git a/Source/Demos/Demo.Platformer/Entities/Components/SpriteComponent.cs b/Source/Demos/Demo.Platformer/Entities/Components/SpriteComponent.cs deleted file mode 100644 index c315aec4..00000000 --- a/Source/Demos/Demo.Platformer/Entities/Components/SpriteComponent.cs +++ /dev/null @@ -1,31 +0,0 @@ -using Microsoft.Xna.Framework; -using Microsoft.Xna.Framework.Graphics; -using MonoGame.Extended.TextureAtlases; - -namespace Demo.Platformer.Entities.Components -{ - public class SpriteComponent : EntityComponent - { - public SpriteComponent(TextureRegion2D textureRegion) - { - IsVisible = true; - TextureRegion = textureRegion; - Color = Color.White; - Origin = new Vector2(textureRegion.Size.Width, textureRegion.Size.Height)*0.5f; - Effect = SpriteEffects.None; - Alpha = 1.0f; - Depth = 0.0f; - } - - public bool IsVisible { get; set; } - public TextureRegion2D TextureRegion { get; set; } - public Color Color { get; set; } - public Vector2 Origin { get; set; } - public SpriteEffects Effect { get; set; } - public Vector2 Position => Entity.Position; - public float Rotation => Entity.Rotation; - public Vector2 Scale => Entity.Scale; - public float Alpha { get; set; } - public float Depth { get; set; } - } -} diff --git a/Source/Demos/Demo.Platformer/Entities/Systems/SpriteAnimatorComponentSystem.cs b/Source/Demos/Demo.Platformer/Entities/Systems/SpriteAnimatorComponentSystem.cs deleted file mode 100644 index 80409451..00000000 --- a/Source/Demos/Demo.Platformer/Entities/Systems/SpriteAnimatorComponentSystem.cs +++ /dev/null @@ -1,20 +0,0 @@ -using Demo.Platformer.Entities.Components; -using Microsoft.Xna.Framework; - -namespace Demo.Platformer.Entities.Systems -{ - public class SpriteAnimatorComponentSystem : UpdatableComponentSystem - { - public SpriteAnimatorComponentSystem() - { - } - - public override void Update(GameTime gameTime) - { - var components = GetComponents(); - - foreach (var component in components) - component.Animator.Update(gameTime); - } - } -} \ No newline at end of file diff --git a/Source/Demos/Demo.Platformer/Entities/Systems/SpriteBatchComponentSystem.cs b/Source/Demos/Demo.Platformer/Entities/Systems/SpriteBatchComponentSystem.cs deleted file mode 100644 index bf1807d6..00000000 --- a/Source/Demos/Demo.Platformer/Entities/Systems/SpriteBatchComponentSystem.cs +++ /dev/null @@ -1,36 +0,0 @@ -using Demo.Platformer.Entities.Components; -using Microsoft.Xna.Framework; -using Microsoft.Xna.Framework.Graphics; - -namespace Demo.Platformer.Entities.Systems -{ - public class SpriteBatchComponentSystem : DrawableComponentSystem - { - public SpriteBatchComponentSystem(GraphicsDevice graphicsDevice) - { - _spriteBatch = new SpriteBatch(graphicsDevice); - } - - private readonly SpriteBatch _spriteBatch; - - public override void Draw(GameTime gameTime) - { - var spriteComponents = GetComponents(); - - _spriteBatch.Begin(); - - foreach (var sprite in spriteComponents) - { - if (sprite.IsVisible) - { - var texture = sprite.TextureRegion.Texture; - var sourceRectangle = sprite.TextureRegion.Bounds; - - _spriteBatch.Draw(texture, sprite.Position, sourceRectangle, sprite.Color * sprite.Alpha, sprite.Rotation, sprite.Origin, - sprite.Scale, sprite.Effect, sprite.Depth); - } - } - _spriteBatch.End(); - } - } -} \ No newline at end of file diff --git a/Source/Demos/Demo.Platformer/Game1.cs b/Source/Demos/Demo.Platformer/Game1.cs index b6da1d2e..dd09cc27 100644 --- a/Source/Demos/Demo.Platformer/Game1.cs +++ b/Source/Demos/Demo.Platformer/Game1.cs @@ -1,11 +1,11 @@ -using Demo.Platformer.Entities; -using Demo.Platformer.Entities.Components; -using Demo.Platformer.Entities.Systems; -using Microsoft.Xna.Framework; +using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Graphics; using Microsoft.Xna.Framework.Input; using MonoGame.Extended; using MonoGame.Extended.Animations.SpriteSheets; +using MonoGame.Extended.Entities; +using MonoGame.Extended.Entities.Components; +using MonoGame.Extended.Entities.Systems; using MonoGame.Extended.Maps.Tiled; using MonoGame.Extended.TextureAtlases; using MonoGame.Extended.ViewportAdapters; diff --git a/Source/MonoGame.Extended.sln b/Source/MonoGame.Extended.sln index d4ee4ccc..357139c6 100644 --- a/Source/MonoGame.Extended.sln +++ b/Source/MonoGame.Extended.sln @@ -1,6 +1,6 @@ Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 14 -VisualStudioVersion = 14.0.25123.0 +VisualStudioVersion = 14.0.25420.1 MinimumVisualStudioVersion = 10.0.40219.1 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MonoGame.Extended", "MonoGame.Extended\MonoGame.Extended.csproj", "{41724C52-3D50-45BB-81EB-3C8A247EAFD1}" EndProject @@ -93,6 +93,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Demo.Screens", "Demos\Demo. EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Demo.Platformer", "Demos\Demo.Platformer\Demo.Platformer.csproj", "{A7A5E924-A49D-4052-ACA2-894161007B00}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Demo.EntityComponentSystem", "Demos\Demo.EntityComponentSystem\Demo.EntityComponentSystem.csproj", "{A2B9E42A-B2D1-476D-9F4B-E64824DA57EE}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -253,6 +255,14 @@ Global {A7A5E924-A49D-4052-ACA2-894161007B00}.Release|Any CPU.Build.0 = Release|Any CPU {A7A5E924-A49D-4052-ACA2-894161007B00}.Release|x86.ActiveCfg = Release|Any CPU {A7A5E924-A49D-4052-ACA2-894161007B00}.Release|x86.Build.0 = Release|Any CPU + {A2B9E42A-B2D1-476D-9F4B-E64824DA57EE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {A2B9E42A-B2D1-476D-9F4B-E64824DA57EE}.Debug|Any CPU.Build.0 = Debug|Any CPU + {A2B9E42A-B2D1-476D-9F4B-E64824DA57EE}.Debug|x86.ActiveCfg = Debug|Any CPU + {A2B9E42A-B2D1-476D-9F4B-E64824DA57EE}.Debug|x86.Build.0 = Debug|Any CPU + {A2B9E42A-B2D1-476D-9F4B-E64824DA57EE}.Release|Any CPU.ActiveCfg = Release|Any CPU + {A2B9E42A-B2D1-476D-9F4B-E64824DA57EE}.Release|Any CPU.Build.0 = Release|Any CPU + {A2B9E42A-B2D1-476D-9F4B-E64824DA57EE}.Release|x86.ActiveCfg = Release|Any CPU + {A2B9E42A-B2D1-476D-9F4B-E64824DA57EE}.Release|x86.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -275,5 +285,6 @@ Global {62E83B48-D581-4E85-B7E7-9A87A811A99C} = {932F8931-4A8D-4205-BFCF-98E794207786} {50C281D9-1D55-4E5C-836B-94110EC09605} = {932F8931-4A8D-4205-BFCF-98E794207786} {A7A5E924-A49D-4052-ACA2-894161007B00} = {932F8931-4A8D-4205-BFCF-98E794207786} + {A2B9E42A-B2D1-476D-9F4B-E64824DA57EE} = {932F8931-4A8D-4205-BFCF-98E794207786} EndGlobalSection EndGlobal diff --git a/Source/MonoGame.Extended/Animations/SpriteSheets/AnimatedSprite.cs b/Source/MonoGame.Extended/Animations/SpriteSheets/AnimatedSprite.cs new file mode 100644 index 00000000..8cf51d9d --- /dev/null +++ b/Source/MonoGame.Extended/Animations/SpriteSheets/AnimatedSprite.cs @@ -0,0 +1,45 @@ +using System; +using Microsoft.Xna.Framework; +using MonoGame.Extended.Sprites; + +namespace MonoGame.Extended.Animations.SpriteSheets +{ + public class AnimatedSprite : Sprite + { + public AnimatedSprite(SpriteSheetAnimationFactory animationFactory, string playAnimation) + : base(animationFactory.Frames[0]) + { + _animationFactory = animationFactory; + + Play(playAnimation).IsLooping = true; + } + + private readonly SpriteSheetAnimationFactory _animationFactory; + private SpriteSheetAnimation _currentAnimation; + + public SpriteSheetAnimation Play(string name, Action onCompleted = null) + { + if (_currentAnimation == null || _currentAnimation.IsComplete || _currentAnimation.Name != name) + { + _currentAnimation = _animationFactory.Create(name); + _currentAnimation.OnCompleted = onCompleted; + } + + return _currentAnimation; + } + + public void Update(float deltaTime) + { + if (_currentAnimation != null && !_currentAnimation.IsComplete) + { + _currentAnimation.Update(deltaTime); + TextureRegion = _currentAnimation.CurrentFrame; + } + } + + public void Update(GameTime gameTime) + { + Update(gameTime.GetElapsedSeconds()); + } + } +} \ No newline at end of file diff --git a/Source/MonoGame.Extended/Animations/SpriteSheets/SpriteSheetAnimator.cs b/Source/MonoGame.Extended/Animations/SpriteSheets/SpriteSheetAnimator.cs index 16796bf0..c7b4a0ba 100644 --- a/Source/MonoGame.Extended/Animations/SpriteSheets/SpriteSheetAnimator.cs +++ b/Source/MonoGame.Extended/Animations/SpriteSheets/SpriteSheetAnimator.cs @@ -5,6 +5,7 @@ using MonoGame.Extended.Sprites; namespace MonoGame.Extended.Animations.SpriteSheets { + [Obsolete("Please use AnimatedSprite instead")] public class SpriteSheetAnimator : IUpdate { public SpriteSheetAnimator(SpriteSheetAnimationFactory animationFactory) diff --git a/Source/MonoGame.Extended/Entities/Components/EntityComponent.cs b/Source/MonoGame.Extended/Entities/Components/EntityComponent.cs new file mode 100644 index 00000000..8d9194ec --- /dev/null +++ b/Source/MonoGame.Extended/Entities/Components/EntityComponent.cs @@ -0,0 +1,52 @@ +using Microsoft.Xna.Framework; + +namespace MonoGame.Extended.Entities.Components +{ + public abstract class EntityComponent : IMovable, IRotatable, IScalable + { + protected EntityComponent() + { + } + + public Entity Entity { get; internal set; } + + private Vector2 _position; + public Vector2 Position + { + get { return Entity?.Position ?? _position; } + set + { + _position = value; + + if (Entity != null) + Entity.Position = _position; + } + } + + private float _rotation; + public float Rotation + { + get { return Entity?.Rotation ?? _rotation; } + set + { + _rotation = value; + + if (Entity != null) + Entity.Rotation = value; + } + } + + private Vector2 _scale; + public Vector2 Scale + { + get { return Entity?.Scale ?? _scale; } + set + { + _scale = value; + + if (Entity != null) + _scale = value; + } + } + } +} \ No newline at end of file diff --git a/Source/Demos/Demo.Platformer/Entities/Entity.cs b/Source/MonoGame.Extended/Entities/Entity.cs similarity index 65% rename from Source/Demos/Demo.Platformer/Entities/Entity.cs rename to Source/MonoGame.Extended/Entities/Entity.cs index 7766015d..b35a0457 100644 --- a/Source/Demos/Demo.Platformer/Entities/Entity.cs +++ b/Source/MonoGame.Extended/Entities/Entity.cs @@ -1,9 +1,9 @@ using System; -using Demo.Platformer.Entities.Components; +using System.Linq; using Microsoft.Xna.Framework; -using MonoGame.Extended; +using MonoGame.Extended.Entities.Components; -namespace Demo.Platformer.Entities +namespace MonoGame.Extended.Entities { public class Entity : IMovable, IRotatable, IScalable { @@ -33,25 +33,22 @@ namespace Demo.Platformer.Entities public void AttachComponent(EntityComponent component) { - if (component.Entity != null) - throw new InvalidOperationException("Component already attached to another entity"); - - component.Entity = this; - _entityComponentSystem.AttachComponent(component); + _entityComponentSystem.AttachComponent(this, component); } public void DetachComponent(EntityComponent component) { - if (component.Entity != this) - throw new InvalidOperationException("Component not attached to entity"); - - component.Entity = null; - _entityComponentSystem.DetachComponent(component); + _entityComponentSystem.DetachComponent(this, component); } public void Destroy() { _entityComponentSystem.DestroyEntity(this); } + + public T GetComponent() where T : EntityComponent + { + return _entityComponentSystem.GetComponent(this); + } } } diff --git a/Source/Demos/Demo.Platformer/Entities/EntityComponentSystem.cs b/Source/MonoGame.Extended/Entities/EntityComponentSystem.cs similarity index 63% rename from Source/Demos/Demo.Platformer/Entities/EntityComponentSystem.cs rename to Source/MonoGame.Extended/Entities/EntityComponentSystem.cs index d831f729..25897ef4 100644 --- a/Source/Demos/Demo.Platformer/Entities/EntityComponentSystem.cs +++ b/Source/MonoGame.Extended/Entities/EntityComponentSystem.cs @@ -1,11 +1,11 @@ using System; using System.Collections.Generic; using System.Linq; -using Demo.Platformer.Entities.Components; -using Demo.Platformer.Entities.Systems; using Microsoft.Xna.Framework; +using MonoGame.Extended.Entities.Components; +using MonoGame.Extended.Entities.Systems; -namespace Demo.Platformer.Entities +namespace MonoGame.Extended.Entities { public class EntityComponentSystem { @@ -31,6 +31,14 @@ namespace Demo.Platformer.Entities _systems.Add(system); } + public Entity CreateEntity(string name, Vector2 position, float rotation = 0) + { + var entity = CreateEntity(name); + entity.Position = position; + entity.Rotation = rotation; + return entity; + } + public Entity CreateEntity(string name) { var entity = new Entity(this, _nextEntityId, name); @@ -39,7 +47,7 @@ namespace Demo.Platformer.Entities return entity; } - public Entity FindEntity(string name) + public Entity GetEntity(string name) { return _entities.FirstOrDefault(e => e.Name == name); } @@ -49,21 +57,6 @@ namespace Demo.Platformer.Entities _entities.Remove(entity); } - public void AttachComponent(EntityComponent component) - { - _components.Add(component); - } - - public void DetachComponent(EntityComponent component) - { - _components.Remove(component); - } - - internal IEnumerable GetComponents() - { - return _components.OfType(); - } - public void Update(GameTime gameTime) { foreach (var componentSystem in _systems.OfType()) @@ -75,5 +68,33 @@ namespace Demo.Platformer.Entities foreach (var componentSystem in _systems.OfType()) componentSystem.Draw(gameTime); } + + internal T GetComponent(Entity entity) where T : EntityComponent + { + return _components.OfType().FirstOrDefault(i => i.Entity == entity); + } + + internal void AttachComponent(Entity entity, EntityComponent component) + { + if (component.Entity != null) + throw new InvalidOperationException("Component already attached to another entity"); + + component.Entity = entity; + _components.Add(component); + } + + internal void DetachComponent(Entity entity, EntityComponent component) + { + if (component.Entity != entity) + throw new InvalidOperationException("Component not attached to entity"); + + component.Entity = null; + _components.Remove(component); + } + + internal IEnumerable GetComponents() + { + return _components.OfType(); + } } } \ No newline at end of file diff --git a/Source/MonoGame.Extended/Entities/Systems/AnimatedSpriteComponentSystem.cs b/Source/MonoGame.Extended/Entities/Systems/AnimatedSpriteComponentSystem.cs new file mode 100644 index 00000000..bf7471b8 --- /dev/null +++ b/Source/MonoGame.Extended/Entities/Systems/AnimatedSpriteComponentSystem.cs @@ -0,0 +1,17 @@ +using Microsoft.Xna.Framework; +using MonoGame.Extended.Animations.SpriteSheets; + +namespace MonoGame.Extended.Entities.Systems +{ + public class AnimatedSpriteComponentSystem : UpdatableComponentSystem + { + public override void Update(GameTime gameTime) + { + var deltaTime = gameTime.GetElapsedSeconds(); + var sprites = GetComponents(); + + foreach (var animatedSprite in sprites) + animatedSprite.Update(deltaTime); + } + } +} \ No newline at end of file diff --git a/Source/Demos/Demo.Platformer/Entities/Systems/ComponentSystem.cs b/Source/MonoGame.Extended/Entities/Systems/ComponentSystem.cs similarity index 88% rename from Source/Demos/Demo.Platformer/Entities/Systems/ComponentSystem.cs rename to Source/MonoGame.Extended/Entities/Systems/ComponentSystem.cs index 50b4516a..b55684ea 100644 --- a/Source/Demos/Demo.Platformer/Entities/Systems/ComponentSystem.cs +++ b/Source/MonoGame.Extended/Entities/Systems/ComponentSystem.cs @@ -1,6 +1,6 @@ using System.Collections.Generic; -namespace Demo.Platformer.Entities.Systems +namespace MonoGame.Extended.Entities.Systems { public abstract class ComponentSystem { diff --git a/Source/Demos/Demo.Platformer/Entities/Systems/DrawableComponentSystem.cs b/Source/MonoGame.Extended/Entities/Systems/DrawableComponentSystem.cs similarity index 79% rename from Source/Demos/Demo.Platformer/Entities/Systems/DrawableComponentSystem.cs rename to Source/MonoGame.Extended/Entities/Systems/DrawableComponentSystem.cs index d300e75d..a6c9a141 100644 --- a/Source/Demos/Demo.Platformer/Entities/Systems/DrawableComponentSystem.cs +++ b/Source/MonoGame.Extended/Entities/Systems/DrawableComponentSystem.cs @@ -1,6 +1,6 @@ using Microsoft.Xna.Framework; -namespace Demo.Platformer.Entities.Systems +namespace MonoGame.Extended.Entities.Systems { public abstract class DrawableComponentSystem : ComponentSystem { diff --git a/Source/MonoGame.Extended/Entities/Systems/ParticleEmitterComponentSystem.cs b/Source/MonoGame.Extended/Entities/Systems/ParticleEmitterComponentSystem.cs new file mode 100644 index 00000000..ea6bd109 --- /dev/null +++ b/Source/MonoGame.Extended/Entities/Systems/ParticleEmitterComponentSystem.cs @@ -0,0 +1,20 @@ +using Microsoft.Xna.Framework; +using MonoGame.Extended.Particles; + +namespace MonoGame.Extended.Entities.Systems +{ + public class ParticleEmitterComponentSystem : UpdatableComponentSystem + { + public override void Update(GameTime gameTime) + { + var deltaTime = gameTime.GetElapsedSeconds(); + var emitters = GetComponents(); + + foreach (var particleEmitter in emitters) + { + particleEmitter.Update(deltaTime); + particleEmitter.Trigger(); + } + } + } +} \ No newline at end of file diff --git a/Source/MonoGame.Extended/Entities/Systems/SpriteBatchComponentSystem.cs b/Source/MonoGame.Extended/Entities/Systems/SpriteBatchComponentSystem.cs new file mode 100644 index 00000000..74681561 --- /dev/null +++ b/Source/MonoGame.Extended/Entities/Systems/SpriteBatchComponentSystem.cs @@ -0,0 +1,35 @@ +using Microsoft.Xna.Framework; +using Microsoft.Xna.Framework.Graphics; +using MonoGame.Extended.Particles; +using MonoGame.Extended.Sprites; + +namespace MonoGame.Extended.Entities.Systems +{ + public class SpriteBatchComponentSystem : DrawableComponentSystem + { + public SpriteBatchComponentSystem(GraphicsDevice graphicsDevice, Camera2D camera) + { + _camera = camera; + _spriteBatch = new SpriteBatch(graphicsDevice); + } + + private readonly Camera2D _camera; + private readonly SpriteBatch _spriteBatch; + + public override void Draw(GameTime gameTime) + { + var sprites = GetComponents(); + var emitters = GetComponents(); + + _spriteBatch.Begin(transformMatrix: _camera.GetViewMatrix()); + + foreach (var sprite in sprites) + _spriteBatch.Draw(sprite); + + foreach (var particleEmitter in emitters) + _spriteBatch.Draw(particleEmitter); + + _spriteBatch.End(); + } + } +} \ No newline at end of file diff --git a/Source/Demos/Demo.Platformer/Entities/Systems/UpdatableComponentSystem.cs b/Source/MonoGame.Extended/Entities/Systems/UpdatableComponentSystem.cs similarity index 79% rename from Source/Demos/Demo.Platformer/Entities/Systems/UpdatableComponentSystem.cs rename to Source/MonoGame.Extended/Entities/Systems/UpdatableComponentSystem.cs index d463e258..d0960315 100644 --- a/Source/Demos/Demo.Platformer/Entities/Systems/UpdatableComponentSystem.cs +++ b/Source/MonoGame.Extended/Entities/Systems/UpdatableComponentSystem.cs @@ -1,6 +1,6 @@ using Microsoft.Xna.Framework; -namespace Demo.Platformer.Entities.Systems +namespace MonoGame.Extended.Entities.Systems { public abstract class UpdatableComponentSystem : ComponentSystem { diff --git a/Source/MonoGame.Extended/MonoGame.Extended.csproj b/Source/MonoGame.Extended/MonoGame.Extended.csproj index 133914e4..b3b81555 100644 --- a/Source/MonoGame.Extended/MonoGame.Extended.csproj +++ b/Source/MonoGame.Extended/MonoGame.Extended.csproj @@ -38,6 +38,7 @@ + @@ -59,6 +60,15 @@ + + + + + + + + + @@ -225,7 +235,6 @@ - diff --git a/Source/MonoGame.Extended/Particles/ParticleEffect.cs b/Source/MonoGame.Extended/Particles/ParticleEffect.cs index 20522a3b..29427775 100644 --- a/Source/MonoGame.Extended/Particles/ParticleEffect.cs +++ b/Source/MonoGame.Extended/Particles/ParticleEffect.cs @@ -1,6 +1,5 @@ using System.Linq; using Microsoft.Xna.Framework; -using MonoGame.Extended.Particles.Profiles; namespace MonoGame.Extended.Particles { diff --git a/Source/MonoGame.Extended/Particles/ParticleEmitter.cs b/Source/MonoGame.Extended/Particles/ParticleEmitter.cs index 9e1f9a87..126a1bfe 100644 --- a/Source/MonoGame.Extended/Particles/ParticleEmitter.cs +++ b/Source/MonoGame.Extended/Particles/ParticleEmitter.cs @@ -1,22 +1,24 @@ using System; using Microsoft.Xna.Framework; +using MonoGame.Extended.Entities.Components; using MonoGame.Extended.Particles.Modifiers; using MonoGame.Extended.Particles.Profiles; using MonoGame.Extended.TextureAtlases; namespace MonoGame.Extended.Particles { - public unsafe class ParticleEmitter : IDisposable + public unsafe class ParticleEmitter : EntityComponent, IDisposable { - public ParticleEmitter(int capacity, TimeSpan term, Profile profile) + public ParticleEmitter(TextureRegion2D textureRegion, int capacity, TimeSpan term, Profile profile) { if (profile == null) throw new ArgumentNullException(nameof(profile)); _term = (float)term.TotalSeconds; + TextureRegion = textureRegion; Buffer = new ParticleBuffer(capacity); - Offset = new Vector2(); + Offset = Vector2.Zero; Profile = profile; Modifiers = new IModifier[0]; ModifierExecutionStrategy = ParticleModifierExecutionStrategy.Serial; @@ -79,6 +81,11 @@ namespace MonoGame.Extended.Particles ModifierExecutionStrategy.ExecuteModifiers(Modifiers, elapsedSeconds, iterator); } + public void Trigger() + { + Trigger(Position); + } + public void Trigger(Vector2 position) { var numToRelease = _random.Next(Parameters.Quantity); diff --git a/Source/MonoGame.Extended/Particles/SpriteBatchExtensions.cs b/Source/MonoGame.Extended/Particles/SpriteBatchExtensions.cs index 0cdf285f..21136a6d 100644 --- a/Source/MonoGame.Extended/Particles/SpriteBatchExtensions.cs +++ b/Source/MonoGame.Extended/Particles/SpriteBatchExtensions.cs @@ -9,10 +9,15 @@ namespace MonoGame.Extended.Particles public static void Draw(this SpriteBatch spriteBatch, ParticleEffect effect) { foreach (var emitter in effect.Emitters) - Draw(spriteBatch, emitter); + UnsafeDraw(spriteBatch, emitter); } - private static unsafe void Draw(SpriteBatch spriteBatch, ParticleEmitter emitter) + public static void Draw(this SpriteBatch spriteBatch, ParticleEmitter emitter) + { + UnsafeDraw(spriteBatch, emitter); + } + + private static unsafe void UnsafeDraw(SpriteBatch spriteBatch, ParticleEmitter emitter) { var textureRegion = emitter.TextureRegion; var origin = new Vector2(textureRegion.Width / 2f, textureRegion.Height / 2f); diff --git a/Source/MonoGame.Extended/Sprites/Sprite.cs b/Source/MonoGame.Extended/Sprites/Sprite.cs index ae1f2c78..3fc298e8 100644 --- a/Source/MonoGame.Extended/Sprites/Sprite.cs +++ b/Source/MonoGame.Extended/Sprites/Sprite.cs @@ -2,13 +2,14 @@ using System.Linq; using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Graphics; +using MonoGame.Extended.Entities.Components; using MonoGame.Extended.SceneGraphs; using MonoGame.Extended.Shapes; using MonoGame.Extended.TextureAtlases; namespace MonoGame.Extended.Sprites { - public class Sprite : IMovable, IRotatable, IScalable, IColorable, ISceneEntity, ISpriteBatchDrawable + public class Sprite : EntityComponent, IColorable, ISceneEntity, ISpriteBatchDrawable { public Sprite(TextureRegion2D textureRegion) { @@ -33,9 +34,6 @@ namespace MonoGame.Extended.Sprites public float Alpha { get; set; } public Color Color { get; set; } public bool IsVisible { get; set; } - public Vector2 Position { get; set; } - public Vector2 Scale { get; set; } - public float Rotation { get; set; } public Vector2 Origin { get; set; } public SpriteEffects Effect { get; set; } public float Depth { get; set; } diff --git a/Source/MonoGame.Extended/Sprites/SpriteAnimator.cs b/Source/MonoGame.Extended/Sprites/SpriteAnimator.cs deleted file mode 100644 index 1212d847..00000000 --- a/Source/MonoGame.Extended/Sprites/SpriteAnimator.cs +++ /dev/null @@ -1,103 +0,0 @@ -using System; -using Microsoft.Xna.Framework; -using MonoGame.Extended.TextureAtlases; - -namespace MonoGame.Extended.Sprites -{ - [Obsolete("Please use the SpriteSheetAnimator instead")] - public class SpriteAnimator : IUpdate - { - public SpriteAnimator(Sprite sprite, TextureAtlas textureAtlas, int framesPerSecond = 60) - { - IsLooping = true; - IsPlaying = true; - FramesPerSecond = framesPerSecond; - - _sprite = sprite; - _textureAtlas = textureAtlas; - _frameIndex = 0; - _nextFrameDelay = 0; - _sprite.TextureRegion = _textureAtlas[_frameIndex]; - } - - private readonly Sprite _sprite; - private readonly TextureAtlas _textureAtlas; - private float _nextFrameDelay; - - public bool IsLooping { get; set; } - - private int _frameIndex; - public int FrameIndex - { - get { return _frameIndex; } - set - { - if (value < 0) - throw new ArgumentOutOfRangeException(nameof(value), "FrameIndex has to be equal or higher than 0."); - - if (value >= _textureAtlas.RegionCount) - throw new ArgumentOutOfRangeException(nameof(value), "FrameIndex cannot be higher than the ammount of frames that the sprite contains."); - - _frameIndex = value; - _sprite.TextureRegion = _textureAtlas[_frameIndex]; - } - } - - private float _framesPerSecond; - public float FramesPerSecond - { - get { return _framesPerSecond; } - set - { - if (_framesPerSecond < 0) - throw new ArgumentOutOfRangeException(nameof(value), "FramesPerSecond has to be equal or higher than 0."); - - _framesPerSecond = value; - } - } - - public bool IsPlaying { get; set; } - - public void Update(GameTime gameTime) - { - if (IsPlaying && FramesPerSecond > 0) - { - var deltaSeconds = (float)gameTime.ElapsedGameTime.TotalSeconds; - - if(_nextFrameDelay <= 0) - { - _nextFrameDelay = 1.0f / FramesPerSecond; - _frameIndex++; - - if (_frameIndex >= _textureAtlas.RegionCount) - { - if (IsLooping) - _frameIndex = 0; - else - IsPlaying = false; - } - - _sprite.TextureRegion = _textureAtlas[_frameIndex]; - } - - _nextFrameDelay -= deltaSeconds; - } - } - - public void Play() - { - IsPlaying = true; - } - - public void Pause() - { - IsPlaying = false; - } - - public void Stop() - { - IsPlaying = false; - _frameIndex = 0; - } - } -}