From 5fcf63c5a70f031fb7a808723fb8a25adb19ab39 Mon Sep 17 00:00:00 2001 From: Syntriax Date: Thu, 23 Nov 2023 22:07:49 +0300 Subject: [PATCH] chore: Added Initial Engine Code --- Engine.Core/.gitignore | 484 ++++++++++++++++++ .../Abstract/Assignable/IAssignable.cs | 6 + .../IAssignableBehaviourController.cs | 26 + .../Abstract/Assignable/IAssignableEntity.cs | 26 + .../Assignable/IAssignableGameObject.cs | 26 + .../Abstract/Assignable/IAssignableSprite.cs | 26 + .../Assignable/IAssignableStateEnable.cs | 26 + .../Assignable/IAssignableTransform.cs | 26 + Engine.Core/Abstract/IBehaviour.cs | 19 + Engine.Core/Abstract/IBehaviourController.cs | 85 +++ Engine.Core/Abstract/IEntity.cs | 5 + Engine.Core/Abstract/IGameObject.cs | 12 + Engine.Core/Abstract/IInitialize.cs | 13 + Engine.Core/Abstract/INameable.cs | 9 + Engine.Core/Abstract/ISprite.cs | 17 + Engine.Core/Abstract/IStateEnable.cs | 9 + Engine.Core/Abstract/ITransform.cs | 17 + Engine.Core/Behaviour.cs | 99 ++++ Engine.Core/BehaviourController.cs | 138 +++++ Engine.Core/BehaviourOverride.cs | 58 +++ Engine.Core/Behaviours/DrawableBehaviour.cs | 42 ++ Engine.Core/Behaviours/IDrawBehaviour.cs | 9 + Engine.Core/Engine.Core.csproj | 12 + Engine.Core/Exceptions/AssignException.cs | 20 + .../Exceptions/NotAssignedException.cs | 21 + Engine.Core/Factory/Abstract/IFactory.cs | 6 + .../Factory/BehaviourControllerFactory.cs | 21 + Engine.Core/Factory/BehaviourFactory.cs | 27 + Engine.Core/Factory/FactoryBase.cs | 23 + Engine.Core/Factory/GameObjectFactory.cs | 39 ++ Engine.Core/Factory/StateEnableFactory.cs | 19 + Engine.Core/Factory/TransformFactory.cs | 10 + Engine.Core/Factory/TypeFactory.cs | 21 + Engine.Core/GameManager.cs | 62 +++ Engine.Core/GameObject.cs | 141 +++++ Engine.Core/Sprite.cs | 59 +++ Engine.Core/StateEnable.cs | 39 ++ Engine.Core/Static/Internal/Constants.cs | 10 + Engine.Core/Transform.cs | 57 +++ Engine.sln | 8 + 40 files changed, 1773 insertions(+) create mode 100644 Engine.Core/.gitignore create mode 100644 Engine.Core/Abstract/Assignable/IAssignable.cs create mode 100644 Engine.Core/Abstract/Assignable/IAssignableBehaviourController.cs create mode 100644 Engine.Core/Abstract/Assignable/IAssignableEntity.cs create mode 100644 Engine.Core/Abstract/Assignable/IAssignableGameObject.cs create mode 100644 Engine.Core/Abstract/Assignable/IAssignableSprite.cs create mode 100644 Engine.Core/Abstract/Assignable/IAssignableStateEnable.cs create mode 100644 Engine.Core/Abstract/Assignable/IAssignableTransform.cs create mode 100644 Engine.Core/Abstract/IBehaviour.cs create mode 100644 Engine.Core/Abstract/IBehaviourController.cs create mode 100644 Engine.Core/Abstract/IEntity.cs create mode 100644 Engine.Core/Abstract/IGameObject.cs create mode 100644 Engine.Core/Abstract/IInitialize.cs create mode 100644 Engine.Core/Abstract/INameable.cs create mode 100644 Engine.Core/Abstract/ISprite.cs create mode 100644 Engine.Core/Abstract/IStateEnable.cs create mode 100644 Engine.Core/Abstract/ITransform.cs create mode 100644 Engine.Core/Behaviour.cs create mode 100644 Engine.Core/BehaviourController.cs create mode 100644 Engine.Core/BehaviourOverride.cs create mode 100644 Engine.Core/Behaviours/DrawableBehaviour.cs create mode 100644 Engine.Core/Behaviours/IDrawBehaviour.cs create mode 100644 Engine.Core/Engine.Core.csproj create mode 100644 Engine.Core/Exceptions/AssignException.cs create mode 100644 Engine.Core/Exceptions/NotAssignedException.cs create mode 100644 Engine.Core/Factory/Abstract/IFactory.cs create mode 100644 Engine.Core/Factory/BehaviourControllerFactory.cs create mode 100644 Engine.Core/Factory/BehaviourFactory.cs create mode 100644 Engine.Core/Factory/FactoryBase.cs create mode 100644 Engine.Core/Factory/GameObjectFactory.cs create mode 100644 Engine.Core/Factory/StateEnableFactory.cs create mode 100644 Engine.Core/Factory/TransformFactory.cs create mode 100644 Engine.Core/Factory/TypeFactory.cs create mode 100644 Engine.Core/GameManager.cs create mode 100644 Engine.Core/GameObject.cs create mode 100644 Engine.Core/Sprite.cs create mode 100644 Engine.Core/StateEnable.cs create mode 100644 Engine.Core/Static/Internal/Constants.cs create mode 100644 Engine.Core/Transform.cs diff --git a/Engine.Core/.gitignore b/Engine.Core/.gitignore new file mode 100644 index 0000000..104b544 --- /dev/null +++ b/Engine.Core/.gitignore @@ -0,0 +1,484 @@ +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. +## +## Get latest from `dotnet new gitignore` + +# dotenv files +.env + +# User-specific files +*.rsuser +*.suo +*.user +*.userosscache +*.sln.docstates + +# User-specific files (MonoDevelop/Xamarin Studio) +*.userprefs + +# Mono auto generated files +mono_crash.* + +# Build results +[Dd]ebug/ +[Dd]ebugPublic/ +[Rr]elease/ +[Rr]eleases/ +x64/ +x86/ +[Ww][Ii][Nn]32/ +[Aa][Rr][Mm]/ +[Aa][Rr][Mm]64/ +bld/ +[Bb]in/ +[Oo]bj/ +[Ll]og/ +[Ll]ogs/ + +# Visual Studio 2015/2017 cache/options directory +.vs/ +# Uncomment if you have tasks that create the project's static files in wwwroot +#wwwroot/ + +# Visual Studio 2017 auto generated files +Generated\ Files/ + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +# NUnit +*.VisualState.xml +TestResult.xml +nunit-*.xml + +# Build Results of an ATL Project +[Dd]ebugPS/ +[Rr]eleasePS/ +dlldata.c + +# Benchmark Results +BenchmarkDotNet.Artifacts/ + +# .NET +project.lock.json +project.fragment.lock.json +artifacts/ + +# Tye +.tye/ + +# ASP.NET Scaffolding +ScaffoldingReadMe.txt + +# StyleCop +StyleCopReport.xml + +# Files built by Visual Studio +*_i.c +*_p.c +*_h.h +*.ilk +*.meta +*.obj +*.iobj +*.pch +*.pdb +*.ipdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*_wpftmp.csproj +*.log +*.tlog +*.vspscc +*.vssscc +.builds +*.pidb +*.svclog +*.scc + +# Chutzpah Test files +_Chutzpah* + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opendb +*.opensdf +*.sdf +*.cachefile +*.VC.db +*.VC.VC.opendb + +# Visual Studio profiler +*.psess +*.vsp +*.vspx +*.sap + +# Visual Studio Trace Files +*.e2e + +# TFS 2012 Local Workspace +$tf/ + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper*/ +*.[Rr]e[Ss]harper +*.DotSettings.user + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# AxoCover is a Code Coverage Tool +.axoCover/* +!.axoCover/settings.json + +# Coverlet is a free, cross platform Code Coverage Tool +coverage*.json +coverage*.xml +coverage*.info + +# Visual Studio code coverage results +*.coverage +*.coveragexml + +# NCrunch +_NCrunch_* +.*crunch*.local.xml +nCrunchTemp_* + +# MightyMoose +*.mm.* +AutoTest.Net/ + +# Web workbench (sass) +.sass-cache/ + +# Installshield output folder +[Ee]xpress/ + +# DocProject is a documentation generator add-in +DocProject/buildhelp/ +DocProject/Help/*.HxT +DocProject/Help/*.HxC +DocProject/Help/*.hhc +DocProject/Help/*.hhk +DocProject/Help/*.hhp +DocProject/Help/Html2 +DocProject/Help/html + +# Click-Once directory +publish/ + +# Publish Web Output +*.[Pp]ublish.xml +*.azurePubxml +# Note: Comment the next line if you want to checkin your web deploy settings, +# but database connection strings (with potential passwords) will be unencrypted +*.pubxml +*.publishproj + +# Microsoft Azure Web App publish settings. Comment the next line if you want to +# checkin your Azure Web App publish settings, but sensitive information contained +# in these scripts will be unencrypted +PublishScripts/ + +# NuGet Packages +*.nupkg +# NuGet Symbol Packages +*.snupkg +# The packages folder can be ignored because of Package Restore +**/[Pp]ackages/* +# except build/, which is used as an MSBuild target. +!**/[Pp]ackages/build/ +# Uncomment if necessary however generally it will be regenerated when needed +#!**/[Pp]ackages/repositories.config +# NuGet v3's project.json files produces more ignorable files +*.nuget.props +*.nuget.targets + +# Microsoft Azure Build Output +csx/ +*.build.csdef + +# Microsoft Azure Emulator +ecf/ +rcf/ + +# Windows Store app package directories and files +AppPackages/ +BundleArtifacts/ +Package.StoreAssociation.xml +_pkginfo.txt +*.appx +*.appxbundle +*.appxupload + +# Visual Studio cache files +# files ending in .cache can be ignored +*.[Cc]ache +# but keep track of directories ending in .cache +!?*.[Cc]ache/ + +# Others +ClientBin/ +~$* +*~ +*.dbmdl +*.dbproj.schemaview +*.jfm +*.pfx +*.publishsettings +orleans.codegen.cs + +# Including strong name files can present a security risk +# (https://github.com/github/gitignore/pull/2483#issue-259490424) +#*.snk + +# Since there are multiple workflows, uncomment next line to ignore bower_components +# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) +#bower_components/ + +# RIA/Silverlight projects +Generated_Code/ + +# Backup & report files from converting an old project file +# to a newer Visual Studio version. Backup files are not needed, +# because we have git ;-) +_UpgradeReport_Files/ +Backup*/ +UpgradeLog*.XML +UpgradeLog*.htm +ServiceFabricBackup/ +*.rptproj.bak + +# SQL Server files +*.mdf +*.ldf +*.ndf + +# Business Intelligence projects +*.rdl.data +*.bim.layout +*.bim_*.settings +*.rptproj.rsuser +*- [Bb]ackup.rdl +*- [Bb]ackup ([0-9]).rdl +*- [Bb]ackup ([0-9][0-9]).rdl + +# Microsoft Fakes +FakesAssemblies/ + +# GhostDoc plugin setting file +*.GhostDoc.xml + +# Node.js Tools for Visual Studio +.ntvs_analysis.dat +node_modules/ + +# Visual Studio 6 build log +*.plg + +# Visual Studio 6 workspace options file +*.opt + +# Visual Studio 6 auto-generated workspace file (contains which files were open etc.) +*.vbw + +# Visual Studio 6 auto-generated project file (contains which files were open etc.) +*.vbp + +# Visual Studio 6 workspace and project file (working project files containing files to include in project) +*.dsw +*.dsp + +# Visual Studio 6 technical files +*.ncb +*.aps + +# Visual Studio LightSwitch build output +**/*.HTMLClient/GeneratedArtifacts +**/*.DesktopClient/GeneratedArtifacts +**/*.DesktopClient/ModelManifest.xml +**/*.Server/GeneratedArtifacts +**/*.Server/ModelManifest.xml +_Pvt_Extensions + +# Paket dependency manager +.paket/paket.exe +paket-files/ + +# FAKE - F# Make +.fake/ + +# CodeRush personal settings +.cr/personal + +# Python Tools for Visual Studio (PTVS) +__pycache__/ +*.pyc + +# Cake - Uncomment if you are using it +# tools/** +# !tools/packages.config + +# Tabs Studio +*.tss + +# Telerik's JustMock configuration file +*.jmconfig + +# BizTalk build output +*.btp.cs +*.btm.cs +*.odx.cs +*.xsd.cs + +# OpenCover UI analysis results +OpenCover/ + +# Azure Stream Analytics local run output +ASALocalRun/ + +# MSBuild Binary and Structured Log +*.binlog + +# NVidia Nsight GPU debugger configuration file +*.nvuser + +# MFractors (Xamarin productivity tool) working folder +.mfractor/ + +# Local History for Visual Studio +.localhistory/ + +# Visual Studio History (VSHistory) files +.vshistory/ + +# BeatPulse healthcheck temp database +healthchecksdb + +# Backup folder for Package Reference Convert tool in Visual Studio 2017 +MigrationBackup/ + +# Ionide (cross platform F# VS Code tools) working folder +.ionide/ + +# Fody - auto-generated XML schema +FodyWeavers.xsd + +# VS Code files for those working on multiple tools +.vscode/* +!.vscode/settings.json +!.vscode/tasks.json +!.vscode/launch.json +!.vscode/extensions.json +*.code-workspace + +# Local History for Visual Studio Code +.history/ + +# Windows Installer files from build outputs +*.cab +*.msi +*.msix +*.msm +*.msp + +# JetBrains Rider +*.sln.iml +.idea + +## +## Visual studio for Mac +## + + +# globs +Makefile.in +*.userprefs +*.usertasks +config.make +config.status +aclocal.m4 +install-sh +autom4te.cache/ +*.tar.gz +tarballs/ +test-results/ + +# Mac bundle stuff +*.dmg +*.app + +# content below from: https://github.com/github/gitignore/blob/master/Global/macOS.gitignore +# General +.DS_Store +.AppleDouble +.LSOverride + +# Icon must end with two \r +Icon + + +# Thumbnails +._* + +# Files that might appear in the root of a volume +.DocumentRevisions-V100 +.fseventsd +.Spotlight-V100 +.TemporaryItems +.Trashes +.VolumeIcon.icns +.com.apple.timemachine.donotpresent + +# Directories potentially created on remote AFP share +.AppleDB +.AppleDesktop +Network Trash Folder +Temporary Items +.apdisk + +# content below from: https://github.com/github/gitignore/blob/master/Global/Windows.gitignore +# Windows thumbnail cache files +Thumbs.db +ehthumbs.db +ehthumbs_vista.db + +# Dump file +*.stackdump + +# Folder config file +[Dd]esktop.ini + +# Recycle Bin used on file shares +$RECYCLE.BIN/ + +# Windows Installer files +*.cab +*.msi +*.msix +*.msm +*.msp + +# Windows shortcuts +*.lnk + +# Vim temporary swap files +*.swp diff --git a/Engine.Core/Abstract/Assignable/IAssignable.cs b/Engine.Core/Abstract/Assignable/IAssignable.cs new file mode 100644 index 0000000..d377e57 --- /dev/null +++ b/Engine.Core/Abstract/Assignable/IAssignable.cs @@ -0,0 +1,6 @@ +namespace Syntriax.Engine.Core.Abstract; + +/// +/// Indicates the class implementing it has Assignable fields that are necessary for the engine to work properly. +/// +public interface IAssignable { } diff --git a/Engine.Core/Abstract/Assignable/IAssignableBehaviourController.cs b/Engine.Core/Abstract/Assignable/IAssignableBehaviourController.cs new file mode 100644 index 0000000..c5e11fe --- /dev/null +++ b/Engine.Core/Abstract/Assignable/IAssignableBehaviourController.cs @@ -0,0 +1,26 @@ +using System; + +namespace Syntriax.Engine.Core.Abstract; + +/// +/// Indicates the object is an with an assignable field. +/// +public interface IAssignableBehaviourController : IAssignable +{ + /// + /// Callback triggered when the value has has been assigned a new value. + /// + Action? OnBehaviourControllerAssigned { get; set; } + + /// + IBehaviourController BehaviourController { get; } + + /// + /// Assign a value to the field of this object + /// + /// New to assign. + /// + /// , if the value given assigned successfully assigned, if not. + /// + bool Assign(IBehaviourController behaviourController); +} diff --git a/Engine.Core/Abstract/Assignable/IAssignableEntity.cs b/Engine.Core/Abstract/Assignable/IAssignableEntity.cs new file mode 100644 index 0000000..e47b45c --- /dev/null +++ b/Engine.Core/Abstract/Assignable/IAssignableEntity.cs @@ -0,0 +1,26 @@ +using System; + +namespace Syntriax.Engine.Core.Abstract; + +/// +/// Indicates the object is an with an assignable field. +/// +public interface IAssignableEntity : IAssignable +{ + /// + /// Callback triggered when the value has has been assigned a new value. + /// + Action? OnEntityAssigned { get; set; } + + /// + IEntity Entity { get; } + + /// + /// Assign a value to the field of this object + /// + /// New to assign. + /// + /// , if the value given assigned successfully assigned, if not. + /// + bool Assign(IEntity entity); +} diff --git a/Engine.Core/Abstract/Assignable/IAssignableGameObject.cs b/Engine.Core/Abstract/Assignable/IAssignableGameObject.cs new file mode 100644 index 0000000..6af3185 --- /dev/null +++ b/Engine.Core/Abstract/Assignable/IAssignableGameObject.cs @@ -0,0 +1,26 @@ +using System; + +namespace Syntriax.Engine.Core.Abstract; + +/// +/// Indicates the object is an with an assignable field. +/// +public interface IAssignableGameObject : IAssignable +{ + /// + /// Callback triggered when the value has has been assigned a new value. + /// + Action? OnGameObjectAssigned { get; set; } + + /// + IGameObject GameObject { get; } + + /// + /// Assign a value to the field of this object + /// + /// New to assign. + /// + /// , if the value given assigned successfully assigned, if not. + /// + bool Assign(IGameObject gameObject); +} diff --git a/Engine.Core/Abstract/Assignable/IAssignableSprite.cs b/Engine.Core/Abstract/Assignable/IAssignableSprite.cs new file mode 100644 index 0000000..8f05c68 --- /dev/null +++ b/Engine.Core/Abstract/Assignable/IAssignableSprite.cs @@ -0,0 +1,26 @@ +using System; + +namespace Syntriax.Engine.Core.Abstract; + +/// +/// Indicates the object is an with an assignable field. +/// +public interface IAssignableSprite : IAssignable +{ + /// + /// Callback triggered when the value has has been assigned a new value. + /// + Action? OnSpriteAssigned { get; set; } + + /// + ISprite Sprite { get; } + + /// + /// Assign a value to the field of this object + /// + /// New to assign. + /// + /// , if the value given assigned successfully assigned, if not. + /// + bool Assign(ISprite sprite); +} diff --git a/Engine.Core/Abstract/Assignable/IAssignableStateEnable.cs b/Engine.Core/Abstract/Assignable/IAssignableStateEnable.cs new file mode 100644 index 0000000..f18059c --- /dev/null +++ b/Engine.Core/Abstract/Assignable/IAssignableStateEnable.cs @@ -0,0 +1,26 @@ +using System; + +namespace Syntriax.Engine.Core.Abstract; + +/// +/// Indicates the object is an with an assignable field. +/// +public interface IAssignableStateEnable : IAssignable +{ + /// + /// Callback triggered when the value has has been assigned a new value. + /// + Action? OnStateEnableAssigned { get; set; } + + /// + IStateEnable StateEnable { get; } + + /// + /// Assign a value to the field of this object + /// + /// New to assign. + /// + /// , if the value given assigned successfully assigned, if not. + /// + bool Assign(IStateEnable stateEnable); +} diff --git a/Engine.Core/Abstract/Assignable/IAssignableTransform.cs b/Engine.Core/Abstract/Assignable/IAssignableTransform.cs new file mode 100644 index 0000000..1e1bdb5 --- /dev/null +++ b/Engine.Core/Abstract/Assignable/IAssignableTransform.cs @@ -0,0 +1,26 @@ +using System; + +namespace Syntriax.Engine.Core.Abstract; + +/// +/// Indicates the object is an with an assignable field. +/// +public interface IAssignableTransform : IAssignable +{ + /// + /// Callback triggered when the value has has been assigned a new value. + /// + Action? OnTransformAssigned { get; set; } + + /// + ITransform Transform { get; } + + /// + /// Assign a value to the field of this object + /// + /// New to assign. + /// + /// , if the value given assigned successfully assigned, if not. + /// + bool Assign(ITransform transform); +} diff --git a/Engine.Core/Abstract/IBehaviour.cs b/Engine.Core/Abstract/IBehaviour.cs new file mode 100644 index 0000000..47c30bc --- /dev/null +++ b/Engine.Core/Abstract/IBehaviour.cs @@ -0,0 +1,19 @@ +using System; + +namespace Syntriax.Engine.Core.Abstract; + +/// +/// Responsible for every behaviour an object in the game might have, controlled by . +/// +public interface IBehaviour : IEntity, IAssignableBehaviourController, IAssignableStateEnable, IInitialize +{ + /// + /// Callback triggered when the has changed. + /// + Action? OnPriorityChanged { get; set; } + + /// + /// Call priority of the . + /// + int Priority { get; set; } +} diff --git a/Engine.Core/Abstract/IBehaviourController.cs b/Engine.Core/Abstract/IBehaviourController.cs new file mode 100644 index 0000000..b5a1f2c --- /dev/null +++ b/Engine.Core/Abstract/IBehaviourController.cs @@ -0,0 +1,85 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; + +using Microsoft.Xna.Framework; + +namespace Syntriax.Engine.Core.Abstract; + +/// +/// Responsible for controlling s and notify them accordingly about the engine's updates. Connected to an . +/// +public interface IBehaviourController : IAssignableGameObject +{ + /// + /// Callback triggered when the is called. + /// + Action? OnUpdate { get; set; } + + /// + /// Callback triggered when the is called. + /// + Action? OnPreDraw { get; set; } + + + /// + /// Callback triggered when the has been registered a new . + /// + Action? OnBehaviourAdded { get; set; } + + /// + /// Callback triggered when the has been removed an existing . + /// + Action? OnBehaviourRemoved { get; set; } + + + /// + /// Registers the provided to be controlled by the . + /// + /// Uninitialized to be registered. + /// An implemented class of + /// The provided class after initialization. + T AddBehaviour(T behaviour) where T : class, IBehaviour; + + /// + /// Instantiates the provided type and registers it to the . + /// + /// Constructor parameters for the given class. + /// An implemented class of + /// The instantiated class after initialization. + T AddBehaviour(params object?[]? args) where T : class, IBehaviour; + + /// + /// Looks up and tries to get the that is controlled by the . + /// + /// If return value is outputs the class found in the . If the return value is falls, this parameter is + /// An implemented class or + /// + /// , if the type of is present in the , if not. + /// + bool TryGetBehaviour([NotNullWhen(returnValue: true)] out T? behaviour); + + /// An implemented class or of + /// Returns a list of all the matching s found in the . + IList GetBehaviours() where T : IBehaviour; + + /// + /// Removes the found in the . + /// + /// If all of the instances of the given Type is to be removed or not. + /// An implemented class or of + void RemoveBehaviour(bool removeAll = false) where T : IBehaviour; + + + /// + /// To be called in every frame of the engine. Responsible for notifying 's under the 's control that a new frame is happening. + /// + /// information from the game. + void Update(GameTime gameTime); + + /// + /// To be called before every draw call from the engine. Responsible for notifying 's under the 's control that the engine is about to start drawing into the screen. + /// + /// information from the game. + void UpdatePreDraw(GameTime gameTime); +} diff --git a/Engine.Core/Abstract/IEntity.cs b/Engine.Core/Abstract/IEntity.cs new file mode 100644 index 0000000..feecf7a --- /dev/null +++ b/Engine.Core/Abstract/IEntity.cs @@ -0,0 +1,5 @@ +namespace Syntriax.Engine.Core.Abstract; + +public interface IEntity : IAssignableStateEnable +{ +} diff --git a/Engine.Core/Abstract/IGameObject.cs b/Engine.Core/Abstract/IGameObject.cs new file mode 100644 index 0000000..6849e2a --- /dev/null +++ b/Engine.Core/Abstract/IGameObject.cs @@ -0,0 +1,12 @@ +using System; + +using Microsoft.Xna.Framework; + +namespace Syntriax.Engine.Core.Abstract; + +public interface IGameObject : IEntity, IAssignableTransform, IAssignableBehaviourController, INameable, IInitialize +{ + Action? OnUpdated { get; set; } + + void Update(GameTime time); +} diff --git a/Engine.Core/Abstract/IInitialize.cs b/Engine.Core/Abstract/IInitialize.cs new file mode 100644 index 0000000..3b54b09 --- /dev/null +++ b/Engine.Core/Abstract/IInitialize.cs @@ -0,0 +1,13 @@ +using System; + +namespace Syntriax.Engine.Core.Abstract; + +public interface IInitialize : IEntity +{ + Action? OnInitialized { get; set; } + Action? OnFinalized { get; set; } + bool Initialized { get; } + + bool Initialize(); + bool Finalize(); +} diff --git a/Engine.Core/Abstract/INameable.cs b/Engine.Core/Abstract/INameable.cs new file mode 100644 index 0000000..d7f8086 --- /dev/null +++ b/Engine.Core/Abstract/INameable.cs @@ -0,0 +1,9 @@ +using System; + +namespace Syntriax.Engine.Core.Abstract; + +public interface INameable +{ + Action? OnNameChanged { get; set; } + string Name { get; set; } +} diff --git a/Engine.Core/Abstract/ISprite.cs b/Engine.Core/Abstract/ISprite.cs new file mode 100644 index 0000000..c4c9d1f --- /dev/null +++ b/Engine.Core/Abstract/ISprite.cs @@ -0,0 +1,17 @@ +using System; +using Microsoft.Xna.Framework; +using Microsoft.Xna.Framework.Graphics; + +namespace Syntriax.Engine.Core.Abstract; + +// TODO Probably gonna have to rethink this +public interface ISprite +{ + Action? OnTextureChanged { get; set; } + Action? OnColorChanged { get; set; } + Action? OnDepthChanged { get; set; } + + Texture2D Texture2D { get; set; } + Color Color { get; set; } + float Depth { get; set; } +} diff --git a/Engine.Core/Abstract/IStateEnable.cs b/Engine.Core/Abstract/IStateEnable.cs new file mode 100644 index 0000000..d32cca2 --- /dev/null +++ b/Engine.Core/Abstract/IStateEnable.cs @@ -0,0 +1,9 @@ +using System; + +namespace Syntriax.Engine.Core.Abstract; + +public interface IStateEnable : IAssignableEntity +{ + Action? OnEnabledChanged { get; set; } + bool Enabled { get; set; } +} diff --git a/Engine.Core/Abstract/ITransform.cs b/Engine.Core/Abstract/ITransform.cs new file mode 100644 index 0000000..72adc38 --- /dev/null +++ b/Engine.Core/Abstract/ITransform.cs @@ -0,0 +1,17 @@ +using System; + +using Microsoft.Xna.Framework; + +namespace Syntriax.Engine.Core.Abstract; + +public interface ITransform +{ + Action? OnPositionChanged { get; set; } + Action? OnScaleChanged { get; set; } + Action? OnRotationChanged { get; set; } + + Vector2 Position { get; set; } + Vector2 Scale { get; set; } + + float Rotation { get; set; } +} diff --git a/Engine.Core/Behaviour.cs b/Engine.Core/Behaviour.cs new file mode 100644 index 0000000..9d41d61 --- /dev/null +++ b/Engine.Core/Behaviour.cs @@ -0,0 +1,99 @@ +using System; +using Syntriax.Engine.Core.Abstract; +using Syntriax.Engine.Core.Exceptions; + +namespace Syntriax.Engine.Core; + +public abstract class Behaviour : IBehaviour +{ + public Action? OnStateEnableAssigned { get; set; } = null; + public Action? OnBehaviourControllerAssigned { get; set; } = null; + + public Action? OnInitialized { get; set; } = null; + public Action? OnFinalized { get; set; } = null; + public Action? OnPriorityChanged { get; set; } = null; + + + private IBehaviourController _behaviourController = null!; + private IStateEnable _stateEnable = null!; + + private bool _initialized = false; + private int _priority = 0; + + public IStateEnable StateEnable => _stateEnable; + public IBehaviourController BehaviourController => _behaviourController; + + public bool Initialized + { + get => _initialized; + private set + { + if (value == _initialized) + return; + + _initialized = value; + if (value) + OnInitialized?.Invoke(this); + else + OnFinalized?.Invoke(this); + } + } + + public int Priority + { + get => _priority; + set + { + if (value == _priority) + return; + + _priority = value; + OnPriorityChanged?.Invoke(this); + } + } + + public bool Assign(IStateEnable stateEnable) + { + if (_initialized) + return false; + + _stateEnable = stateEnable; + _stateEnable.Assign(this); + OnStateEnableAssigned?.Invoke(this); + return true; + } + + public bool Assign(IBehaviourController behaviourController) + { + if (_behaviourController is not null) + return false; + + _behaviourController = behaviourController; + OnBehaviourControllerAssigned?.Invoke(this); + return true; + } + + public bool Initialize() + { + if (Initialized) + return false; + + NotAssignedException.Check(this, _behaviourController); + NotAssignedException.Check(this, _stateEnable); + + Initialized = true; + return true; + } + + public bool Finalize() + { + if (!Initialized) + return false; + + _behaviourController = null!; + _stateEnable = null!; + + Initialized = false; + return true; + } +} diff --git a/Engine.Core/BehaviourController.cs b/Engine.Core/BehaviourController.cs new file mode 100644 index 0000000..4201663 --- /dev/null +++ b/Engine.Core/BehaviourController.cs @@ -0,0 +1,138 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; + +using Microsoft.Xna.Framework; + +using Syntriax.Engine.Core.Abstract; + +namespace Syntriax.Engine.Core; + +public class BehaviourController : IBehaviourController +{ + public Action? OnUpdate { get; set; } = null; + public Action? OnPreDraw { get; set; } = null; + + public Action? OnBehaviourAdded { get; set; } = null; + public Action? OnBehaviourRemoved { get; set; } = null; + public Action? OnGameObjectAssigned { get; set; } = null; + + + private readonly IList behaviours = new List(Constants.BEHAVIOURS_SIZE_INITIAL); + + private IGameObject _gameObject = null!; + + + public IGameObject GameObject => _gameObject; + + public T AddBehaviour(T behaviour) where T : class, IBehaviour + { + InsertBehaviourByPriority(behaviour); + + behaviour.Initialize(); + behaviour.OnPriorityChanged += OnPriorityChange; + OnBehaviourAdded?.Invoke(this, behaviour); + return behaviour; + } + + public T AddBehaviour(params object?[]? args) where T : class, IBehaviour + => AddBehaviour(new Factory.BehaviourFactory().Instantiate(_gameObject, args)); + + public bool TryGetBehaviour([NotNullWhen(returnValue: true)] out T? behaviour) + { + foreach (var behaviourItem in behaviours) + { + if (behaviourItem is not T result) + continue; + + behaviour = result; + return true; + } + + behaviour = default; + return false; + } + + public IList GetBehaviours() where T : IBehaviour + { + IList behaviours = new List(); + foreach (var behaviourItem in this.behaviours) + { + if (behaviourItem is not T behaviour) + continue; + + behaviours ??= new List(); + behaviours.Add(behaviour); + } + + return behaviours; + } + + public void RemoveBehaviour(bool removeAll = false) where T : IBehaviour + { + for (int i = behaviours.Count; i >= 0; i--) + { + if (behaviours[i] is not T behaviour) + continue; + + behaviour.OnPriorityChanged -= OnPriorityChange; + behaviour.Finalize(); + behaviours.RemoveAt(i); + OnBehaviourRemoved?.Invoke(this, behaviour); + + if (!removeAll) + return; + } + } + + public bool Assign(IGameObject gameObject) + { + if (_gameObject is not null) + return false; + + _gameObject = gameObject; + OnGameObjectAssigned?.Invoke(this); + return true; + } + + public void Update(GameTime gameTime) + { + if (!GameObject.StateEnable.Enabled) + return; + + OnUpdate?.Invoke(this, gameTime); + } + public void UpdatePreDraw(GameTime gameTime) + { + if (!GameObject.StateEnable.Enabled) + return; + + OnPreDraw?.Invoke(this, gameTime); + } + + public BehaviourController() { } + public BehaviourController(IGameObject gameObject) => Assign(gameObject); + + private void InsertBehaviourByPriority(T behaviour) where T : class, IBehaviour + { + int i; + + for (i = 0; i < behaviours.Count; i++) + { + if (behaviours[i].Priority > behaviour.Priority) + continue; + + behaviours.Insert(i, behaviour); + return; + } + + if (i == 0 || i == behaviours.Count) + behaviours.Add(behaviour); + } + + private void OnPriorityChange(IBehaviour behaviour) + { + behaviours.Remove(behaviour); + InsertBehaviourByPriority(behaviour); + } +} diff --git a/Engine.Core/BehaviourOverride.cs b/Engine.Core/BehaviourOverride.cs new file mode 100644 index 0000000..69189b9 --- /dev/null +++ b/Engine.Core/BehaviourOverride.cs @@ -0,0 +1,58 @@ +using System; +using Microsoft.Xna.Framework; + +using Syntriax.Engine.Core.Abstract; + +namespace Syntriax.Engine.Core; + +public abstract class BehaviourOverride : Behaviour +{ + protected IGameObject GameObject => BehaviourController.GameObject; + protected ITransform Transform => BehaviourController.GameObject.Transform; + + public BehaviourOverride() + { + OnInitialized += OnInitialize; + OnFinalized += OnFinalize; + } + + protected virtual void OnInitialize() { } + private void OnInitialize(IInitialize _) + { + BehaviourController.OnPreDraw += PreDraw; + BehaviourController.OnUpdate += Update; + OnInitialize(); + } + + protected virtual void OnFinalize() { } + private void OnFinalize(IInitialize _) + { + BehaviourController.OnPreDraw -= PreDraw; + BehaviourController.OnUpdate -= Update; + OnFinalize(); + } + + protected virtual void OnUpdatePreEnabledCheck(GameTime time) { } + protected virtual void OnUpdate(GameTime time) { } + private void Update(IBehaviourController _, GameTime time) + { + OnUpdatePreEnabledCheck(time); + + if (!StateEnable.Enabled) + return; + + OnUpdate(time); + } + + protected virtual void OnPreDrawPreEnabledCheck(GameTime time) { } + protected virtual void OnPreDraw(GameTime time) { } + private void PreDraw(IBehaviourController _, GameTime time) + { + OnPreDrawPreEnabledCheck(time); + + if (!StateEnable.Enabled) + return; + + OnPreDraw(time); + } +} diff --git a/Engine.Core/Behaviours/DrawableBehaviour.cs b/Engine.Core/Behaviours/DrawableBehaviour.cs new file mode 100644 index 0000000..f1ffe81 --- /dev/null +++ b/Engine.Core/Behaviours/DrawableBehaviour.cs @@ -0,0 +1,42 @@ +using System; + +using Microsoft.Xna.Framework; +using Microsoft.Xna.Framework.Graphics; + +using Syntriax.Engine.Core.Abstract; + +using ISprite = Syntriax.Engine.Core.Abstract.ISprite; + +namespace Syntriax.Engine.Core.Behaviours; + +public class DrawableSpriteBehaviour : Behaviour, IDrawBehaviour, IAssignableSprite +{ + public Action? OnSpriteAssigned { get; set; } = null; + + private ISprite _sprite = null!; + + public ISprite Sprite => _sprite; + + public void Draw(SpriteBatch spriteBatch) + { + if (!StateEnable.Enabled) + return; + + Vector2 position = BehaviourController.GameObject.Transform.Position; + Vector2 scale = BehaviourController.GameObject.Transform.Scale; + + Rectangle rectangle = new Rectangle((int)position.X, (int)position.Y, (int)(Sprite.Texture2D.Width * scale.X), (int)(Sprite.Texture2D.Height * scale.Y)); + + spriteBatch.Draw(Sprite.Texture2D, rectangle, Sprite.Color); + } + + public bool Assign(ISprite sprite) + { + if (_sprite is not null) + return false; + + _sprite = sprite; + OnSpriteAssigned?.Invoke(this); + return true; + } +} diff --git a/Engine.Core/Behaviours/IDrawBehaviour.cs b/Engine.Core/Behaviours/IDrawBehaviour.cs new file mode 100644 index 0000000..0b5f65b --- /dev/null +++ b/Engine.Core/Behaviours/IDrawBehaviour.cs @@ -0,0 +1,9 @@ +using Microsoft.Xna.Framework.Graphics; +using Syntriax.Engine.Core.Abstract; + +namespace Syntriax.Engine.Core.Behaviours; + +public interface IDrawBehaviour : IBehaviour +{ + public void Draw(SpriteBatch spriteBatch); +} diff --git a/Engine.Core/Engine.Core.csproj b/Engine.Core/Engine.Core.csproj new file mode 100644 index 0000000..eaf7af4 --- /dev/null +++ b/Engine.Core/Engine.Core.csproj @@ -0,0 +1,12 @@ + + + + net8.0 + enable + enable + + + + + + diff --git a/Engine.Core/Exceptions/AssignException.cs b/Engine.Core/Exceptions/AssignException.cs new file mode 100644 index 0000000..c1e5d19 --- /dev/null +++ b/Engine.Core/Exceptions/AssignException.cs @@ -0,0 +1,20 @@ +using System; +using Syntriax.Engine.Core.Abstract; + +namespace Syntriax.Engine.Core.Exceptions; + +public class AssignException : Exception +{ + public AssignException() : base("Assign operation has failed.") { } + public AssignException(string? message) : base(message) { } + + // public static AssignException FromStateEnable(IStateEnable? stateEnable) + // => new AssignException($"{nameof(IGameObject.AssignStateEnable)} failed on type {stateEnable?.GetType().ToString() ?? "\"null\""}"); + public static AssignException From(T to, T2? value) + => new AssignException($"Assign operation has failed on T: {typeof(T).FullName}, value: {value?.GetType().ToString() ?? "\"null\""}"); + // public static AssignException FromBehaviourController(IBehaviourController? behaviourController) + // => new AssignException($"{nameof(IGameObject.AssignBehaviourController)} failed on type {behaviourController?.GetType().ToString() ?? "\"null\""}"); +} +// throw new Exception($"{nameof(IGameObject.AssignTransform)} failed on type {transform?.GetType().ToString() ?? "null"} for type {typeof(T).FullName}"); +// throw new Exception($"{nameof(IGameObject.AssignBehaviourController)} failed on type {behaviourController?.GetType().ToString() ?? "null"} for type {typeof(T).FullName}"); +// throw new Exception($"{nameof(IGameObject.AssignStateEnable)} failed on type {stateEnable?.GetType().ToString() ?? "null"} for type {typeof(T).FullName}"); diff --git a/Engine.Core/Exceptions/NotAssignedException.cs b/Engine.Core/Exceptions/NotAssignedException.cs new file mode 100644 index 0000000..8ff06df --- /dev/null +++ b/Engine.Core/Exceptions/NotAssignedException.cs @@ -0,0 +1,21 @@ +using System; +using Syntriax.Engine.Core.Abstract; + +namespace Syntriax.Engine.Core.Exceptions; + +public class NotAssignedException : Exception +{ + public NotAssignedException() : base("The object has not been assigned.") { } + public NotAssignedException(string? message) : base(message) { } + + public static NotAssignedException From(T1 to, T2? value) where T1 : IAssignable + => new NotAssignedException($"{typeof(T2).Name} has not been assigned to {typeof(T1).Name}"); + + public static void Check(T1 to, T2? value) where T1 : IAssignable + { + if (value is not null) + return; + + throw From(to, value); + } +} diff --git a/Engine.Core/Factory/Abstract/IFactory.cs b/Engine.Core/Factory/Abstract/IFactory.cs new file mode 100644 index 0000000..2d61656 --- /dev/null +++ b/Engine.Core/Factory/Abstract/IFactory.cs @@ -0,0 +1,6 @@ +namespace Syntriax.Engine.Core.Factory.Abstract; + +public interface IFactory where TInterface : class +{ + T Get(params object?[]? args) where T : class, TInterface; +} diff --git a/Engine.Core/Factory/BehaviourControllerFactory.cs b/Engine.Core/Factory/BehaviourControllerFactory.cs new file mode 100644 index 0000000..00cd97c --- /dev/null +++ b/Engine.Core/Factory/BehaviourControllerFactory.cs @@ -0,0 +1,21 @@ +using Syntriax.Engine.Core.Abstract; +using Syntriax.Engine.Core.Exceptions; + +namespace Syntriax.Engine.Core.Factory; + +public class BehaviourControllerFactory +{ + public IBehaviourController Instantiate(IGameObject gameObject) + => Instantiate(gameObject); + + public T Instantiate(IGameObject gameObject, params object?[]? args) + where T : class, IBehaviourController + { + T behaviourController = TypeFactory.Get(args); + + if (!behaviourController.Assign(gameObject)) + throw AssignException.From(behaviourController, gameObject); + + return behaviourController; + } +} diff --git a/Engine.Core/Factory/BehaviourFactory.cs b/Engine.Core/Factory/BehaviourFactory.cs new file mode 100644 index 0000000..f75518c --- /dev/null +++ b/Engine.Core/Factory/BehaviourFactory.cs @@ -0,0 +1,27 @@ +using Syntriax.Engine.Core.Abstract; +using Syntriax.Engine.Core.Exceptions; + +namespace Syntriax.Engine.Core.Factory; + +public class BehaviourFactory +{ + public T Instantiate(IGameObject gameObject, params object?[]? args) where T : class, IBehaviour + => Instantiate(gameObject, stateEnable: null, args); + + public T Instantiate(IGameObject gameObject, IStateEnable? stateEnable, params object?[]? args) + where T : class, IBehaviour + { + T behaviour = TypeFactory.Get(args); + + stateEnable ??= TypeFactory.Get(); + if (!stateEnable.Assign(behaviour)) + throw AssignException.From(stateEnable, behaviour); + + if (!behaviour.Assign(gameObject.BehaviourController)) + throw AssignException.From(behaviour, gameObject.BehaviourController); + if (!behaviour.Assign(stateEnable)) + throw AssignException.From(behaviour, stateEnable); + + return behaviour; + } +} diff --git a/Engine.Core/Factory/FactoryBase.cs b/Engine.Core/Factory/FactoryBase.cs new file mode 100644 index 0000000..97f8067 --- /dev/null +++ b/Engine.Core/Factory/FactoryBase.cs @@ -0,0 +1,23 @@ +using System; +using Syntriax.Engine.Core.Factory.Abstract; + +namespace Syntriax.Engine.Core.Factory; + +public abstract class FactoryBase : IFactory + where TInterface : class +{ + public virtual T Get(params object?[]? args) where T : class, TInterface + { + T? result; + + if (args is not null && args.Length != 0) + result = Activator.CreateInstance(typeof(T), args) as T; + else + result = Activator.CreateInstance(typeof(T)) as T; + + if (result is null) + throw new Exception($"{typeof(TInterface).Name} of type {typeof(T).Name} could not be created."); + + return result; + } +} diff --git a/Engine.Core/Factory/GameObjectFactory.cs b/Engine.Core/Factory/GameObjectFactory.cs new file mode 100644 index 0000000..f53ea9e --- /dev/null +++ b/Engine.Core/Factory/GameObjectFactory.cs @@ -0,0 +1,39 @@ +using Syntriax.Engine.Core.Abstract; +using Syntriax.Engine.Core.Exceptions; + +namespace Syntriax.Engine.Core.Factory; + +public class GameObjectFactory +{ + public T Instantiate(params object?[]? args) where T : class, IGameObject + => Instantiate(transform: null, behaviourController: null, stateEnable: null, args); + + public T Instantiate( + ITransform? transform = null, + IBehaviourController? behaviourController = null, + IStateEnable? stateEnable = null, + params object?[]? args + ) + where T : class, IGameObject + { + T gameObject = TypeFactory.Get(args); + + transform ??= TypeFactory.Get(); + behaviourController ??= TypeFactory.Get(); + stateEnable ??= TypeFactory.Get(); + + if (!behaviourController.Assign(gameObject)) + throw AssignException.From(behaviourController, gameObject); + if (!stateEnable.Assign(gameObject)) + throw AssignException.From(stateEnable, gameObject); + + if (!gameObject.Assign(transform)) + throw AssignException.From(gameObject, transform); + if (!gameObject.Assign(behaviourController)) + throw AssignException.From(gameObject, behaviourController); + if (!gameObject.Assign(stateEnable)) + throw AssignException.From(gameObject, stateEnable); + + return gameObject; + } +} diff --git a/Engine.Core/Factory/StateEnableFactory.cs b/Engine.Core/Factory/StateEnableFactory.cs new file mode 100644 index 0000000..1c00847 --- /dev/null +++ b/Engine.Core/Factory/StateEnableFactory.cs @@ -0,0 +1,19 @@ +using Syntriax.Engine.Core.Abstract; +using Syntriax.Engine.Core.Exceptions; + +namespace Syntriax.Engine.Core.Factory; + +public class StateEnableFactory +{ + public IStateEnable Instantiate(IEntity entity) => Instantiate(entity); + + public T Instantiate(IEntity entity, params object?[]? args) where T : class, IStateEnable + { + T stateEnable = TypeFactory.Get(args); + + if (!stateEnable.Assign(entity)) + throw AssignException.From(stateEnable, entity); + + return stateEnable; + } +} diff --git a/Engine.Core/Factory/TransformFactory.cs b/Engine.Core/Factory/TransformFactory.cs new file mode 100644 index 0000000..c4e7687 --- /dev/null +++ b/Engine.Core/Factory/TransformFactory.cs @@ -0,0 +1,10 @@ +using Syntriax.Engine.Core.Abstract; + +namespace Syntriax.Engine.Core.Factory; + +public class TransformFactory +{ + public ITransform Instantiate() => TypeFactory.Get(); + public T Instantiate(params object?[]? args) where T : class, ITransform + => TypeFactory.Get(args); +} diff --git a/Engine.Core/Factory/TypeFactory.cs b/Engine.Core/Factory/TypeFactory.cs new file mode 100644 index 0000000..7ba226a --- /dev/null +++ b/Engine.Core/Factory/TypeFactory.cs @@ -0,0 +1,21 @@ +using System; + +namespace Syntriax.Engine.Core.Factory; + +public static class TypeFactory +{ + public static T Get(params object?[]? args) where T : class + { + T? result; + + if (args is not null && args.Length != 0) + result = Activator.CreateInstance(typeof(T), args) as T; + else + result = Activator.CreateInstance(typeof(T)) as T; + + if (result is null) + throw new Exception($"{typeof(T).Name} of type {typeof(T).Name} could not be created."); + + return result; + } +} diff --git a/Engine.Core/GameManager.cs b/Engine.Core/GameManager.cs new file mode 100644 index 0000000..ed08fa9 --- /dev/null +++ b/Engine.Core/GameManager.cs @@ -0,0 +1,62 @@ +using System; +using System.Collections.Generic; + +using Microsoft.Xna.Framework; + +using Syntriax.Engine.Core.Abstract; +using Syntriax.Engine.Core.Factory; + +namespace Syntriax.Engine.Core; + +public class GameManager +{ + public Game Game { get; private set; } = null!; + private IList _gameObjects = new List(Constants.GAME_OBJECTS_SIZE_INITIAL); + + private GameObjectFactory _gameObjectFactory = null!; + private GameObjectFactory GameObjectFactory + { + get + { + if (_gameObjectFactory is null) + _gameObjectFactory = new GameObjectFactory(); + return _gameObjectFactory; + } + } + + public IList GameObjects => _gameObjects; + + public void RegisterGameObject(IGameObject gameObject) + { + if (_gameObjects.Contains(gameObject)) + throw new Exception($"{nameof(IGameComponent)} named {gameObject.Name} is already registered to the {nameof(GameManager)}."); + + _gameObjects.Add(gameObject); + } + + public T InstantiateGameObject() where T : class, IGameObject + { + T gameObject = GameObjectFactory.Instantiate(); + _gameObjects.Add(gameObject); + return gameObject; + } + + // public TGameObject RegisterGameObject() + // where TGameObject : class, IGameObject + // where TTransform : class, ITransform + // where TBehaviourController : class, IBehaviourController + // where TStateEnable : class, IStateEnable + // { + // TGameObject gameObject = Factory.GameObjectFactory.Get(); + // _gameObjects.Add(gameObject); + // return gameObject; + // } + + public void RemoveGameObject(IGameObject gameObject) + { + if (!_gameObjects.Contains(gameObject)) + throw new Exception($"{nameof(IGameComponent)} named {gameObject.Name} is not registered to the {nameof(GameManager)}."); + + _gameObjects.Remove(gameObject); + } +} diff --git a/Engine.Core/GameObject.cs b/Engine.Core/GameObject.cs new file mode 100644 index 0000000..373d1bf --- /dev/null +++ b/Engine.Core/GameObject.cs @@ -0,0 +1,141 @@ +using System; + +using Microsoft.Xna.Framework; + +using Syntriax.Engine.Core.Abstract; +using Syntriax.Engine.Core.Exceptions; + +namespace Syntriax.Engine.Core; + +public class GameObject : IGameObject +{ + public Action? OnStateEnableAssigned { get; set; } = null; + public Action? OnTransformAssigned { get; set; } = null; + public Action? OnBehaviourControllerAssigned { get; set; } = null; + + public Action? OnNameChanged { get; set; } = null; + + public Action? OnInitialized { get; set; } = null; + public Action? OnFinalized { get; set; } = null; + + public Action? OnUpdated { get; set; } = null; + + + private ITransform _transform = null!; + private IBehaviourController _behaviourController = null!; + private IStateEnable _stateEnable = null!; + + private string _name = nameof(GameObject); + private bool _initialized = false; + + public ITransform Transform => _transform; + public IBehaviourController BehaviourController => _behaviourController; + public IStateEnable StateEnable => _stateEnable; + + public bool Initialized + { + get => _initialized; + private set + { + if (value == _initialized) + return; + + _initialized = value; + if (value) + OnInitialized?.Invoke(this); + else + OnFinalized?.Invoke(this); + } + } + + public string Name + { + get => _name; + set + { + if (value == _name) return; + + _name = value; + OnNameChanged?.Invoke(this); + } + } + + public bool Initialize() + { + if (Initialized) + return false; + + NotAssignedException.Check(this, _transform); + NotAssignedException.Check(this, _behaviourController); + NotAssignedException.Check(this, _stateEnable); + + Initialized = true; + return true; + } + + public void Update(GameTime time) + { + if (!_stateEnable.Enabled) + return; + + OnUpdated?.Invoke(this, time); + } + + public bool Finalize() + { + if (!Initialized) + return false; + + + System.Threading.Tasks.Parallel.ForEach( + _behaviourController.GetBehaviours(), + behaviour => behaviour.Finalize() + ); + + _transform = null!; + _behaviourController = null!; + _stateEnable = null!; + + Initialized = false; + return true; + } + + public bool Assign(IStateEnable stateEnable) + { + if (_stateEnable is not null) + return false; + + _stateEnable = stateEnable; + OnStateEnableAssigned?.Invoke(this); + return true; + } + + public bool Assign(ITransform transform) + { + if (_transform is not null) + return false; + + _transform = transform; + OnTransformAssigned?.Invoke(this); + return true; + } + + public bool Assign(IBehaviourController behaviourController) + { + if (_behaviourController is not null) + return false; + + _behaviourController = behaviourController; + OnBehaviourControllerAssigned?.Invoke(this); + return true; + } + + public GameObject() { OnBehaviourControllerAssigned += ConnectBehaviourController; } + private void ConnectBehaviourController(IAssignableBehaviourController controller) + { + controller.BehaviourController.OnBehaviourAdded += OnBehaviourAdded; + controller.BehaviourController.OnBehaviourRemoved += OnBehaviourRemoved; + } + private void OnBehaviourRemoved(IBehaviourController _, IBehaviour behaviour) { if (Initialized) behaviour.Initialize(); } + private void OnBehaviourAdded(IBehaviourController _, IBehaviour behaviour) { if (Initialized) behaviour.Finalize(); } +} diff --git a/Engine.Core/Sprite.cs b/Engine.Core/Sprite.cs new file mode 100644 index 0000000..4c5eb0c --- /dev/null +++ b/Engine.Core/Sprite.cs @@ -0,0 +1,59 @@ +using System; + +using Microsoft.Xna.Framework; +using Microsoft.Xna.Framework.Graphics; + +using Syntriax.Engine.Core.Abstract; + +namespace Syntriax.Engine.Core; + +// TODO Probably gonna have to rethink this +public class Sprite : ISprite +{ + public Action? OnTextureChanged { get; set; } + public Action? OnColorChanged { get; set; } + public Action? OnDepthChanged { get; set; } + + private Texture2D _texture = null!; + private Color _color = Color.White; + private float _depth = 0f; + + public Texture2D Texture2D + { + get => _texture; + set + { + if (_texture == value) + return; + + _texture = value; + OnTextureChanged?.Invoke(this); + } + } + + public Color Color + { + get => _color; + set + { + if (_color == value) + return; + + _color = value; + OnColorChanged?.Invoke(this); + } + } + + public float Depth + { + get => _depth; + set + { + if (_depth == value) + return; + + _depth = value; + OnDepthChanged?.Invoke(this); + } + } +} diff --git a/Engine.Core/StateEnable.cs b/Engine.Core/StateEnable.cs new file mode 100644 index 0000000..7a1a461 --- /dev/null +++ b/Engine.Core/StateEnable.cs @@ -0,0 +1,39 @@ +using System; + +using Syntriax.Engine.Core.Abstract; + +namespace Syntriax.Engine.Core; + +public class StateEnable : IStateEnable +{ + public Action? OnEntityAssigned { get; set; } = null; + public Action? OnEnabledChanged { get; set; } = null; + + private bool _enabled = true; + private IEntity _entity = null!; + + public IEntity Entity => _entity; + + public bool Enabled + { + get => _enabled; + set + { + if (value == _enabled) + return; + + _enabled = value; + OnEnabledChanged?.Invoke(this); + } + } + + public bool Assign(IEntity entity) + { + if (_entity is not null) + return false; + + _entity = entity; + OnEntityAssigned?.Invoke(this); + return true; + } +} diff --git a/Engine.Core/Static/Internal/Constants.cs b/Engine.Core/Static/Internal/Constants.cs new file mode 100644 index 0000000..76ba5d8 --- /dev/null +++ b/Engine.Core/Static/Internal/Constants.cs @@ -0,0 +1,10 @@ +using System.Collections.Generic; +using Microsoft.Xna.Framework; + +namespace Syntriax.Engine.Core; + +internal static class Constants +{ + internal static int BEHAVIOURS_SIZE_INITIAL = 16; + internal static int GAME_OBJECTS_SIZE_INITIAL = 256; +} diff --git a/Engine.Core/Transform.cs b/Engine.Core/Transform.cs new file mode 100644 index 0000000..5603454 --- /dev/null +++ b/Engine.Core/Transform.cs @@ -0,0 +1,57 @@ +using System; + +using Microsoft.Xna.Framework; + +using Syntriax.Engine.Core.Abstract; + +namespace Syntriax.Engine.Core; + +public class Transform : ITransform +{ + public Action? OnPositionChanged { get; set; } = null; + public Action? OnScaleChanged { get; set; } = null; + public Action? OnRotationChanged { get; set; } = null; + + private Vector2 _position = Vector2.Zero; + private Vector2 _scale = Vector2.One; + private float _rotation = 0f; + + public Vector2 Position + { + get => _position; + set + { + if (value == _position) + return; + + _position = value; + OnPositionChanged?.Invoke(this); + } + } + + public Vector2 Scale + { + get => _scale; + set + { + if (value == _scale) + return; + + _scale = value; + OnScaleChanged?.Invoke(this); + } + } + + public float Rotation + { + get => _rotation; + set + { + if (value == _rotation) + return; + + _rotation = value; + OnRotationChanged?.Invoke(this); + } + } +} diff --git a/Engine.sln b/Engine.sln index 58ea566..8af0c45 100644 --- a/Engine.sln +++ b/Engine.sln @@ -3,6 +3,8 @@ Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio Version 17 VisualStudioVersion = 17.0.31903.59 MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Engine.Core", "Engine.Core\Engine.Core.csproj", "{71719EAD-1B6B-4229-B39E-E53A2E8BFAB1}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -11,4 +13,10 @@ Global GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {71719EAD-1B6B-4229-B39E-E53A2E8BFAB1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {71719EAD-1B6B-4229-B39E-E53A2E8BFAB1}.Debug|Any CPU.Build.0 = Debug|Any CPU + {71719EAD-1B6B-4229-B39E-E53A2E8BFAB1}.Release|Any CPU.ActiveCfg = Release|Any CPU + {71719EAD-1B6B-4229-B39E-E53A2E8BFAB1}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection EndGlobal