Compare commits
	
		
			30 Commits
		
	
	
		
			main
			...
			feat/netwo
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 1b1d9dcdac | |||
| 2565617ff9 | |||
| 01668c7be3 | |||
| cafbc55780 | |||
| ea3c4a2d2a | |||
| 89b756a615 | |||
| 6af84bcb6d | |||
| 3c1528d879 | |||
| 6f3e7b4ae5 | |||
| 86ef57fb62 | |||
| 6c326b1fc6 | |||
| b8b10de08a | |||
| edd2dd8511 | |||
| 70ac012a83 | |||
| d5a904fe8f | |||
| b1582ab5c2 | |||
| 8a0a0289f9 | |||
| 776d029e7e | |||
| 5afb8b69bf | |||
| 65073ec1ca | |||
| 0d62e5c986 | |||
| fe5a08840c | |||
| 1c7b1cb78a | |||
| 78010c266e | |||
| ef8b04648c | |||
| d4c57c0153 | |||
| 0e198afeab | |||
| de267a9d0f | |||
| 977a2abdd7 | |||
| 91e88bbff8 | 
							
								
								
									
										484
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										484
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							| @@ -1,484 +0,0 @@ | |||||||
| ## 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 |  | ||||||
							
								
								
									
										81
									
								
								.vscode/launch.json
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										81
									
								
								.vscode/launch.json
									
									
									
									
										vendored
									
									
								
							| @@ -1,80 +1,27 @@ | |||||||
| { | { | ||||||
|  |   // Use IntelliSense to learn about possible attributes. | ||||||
|  |   // Hover to view descriptions of existing attributes. | ||||||
|  |   // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 | ||||||
|   "version": "0.2.0", |   "version": "0.2.0", | ||||||
|   "configurations": [ |   "configurations": [ | ||||||
|     { |     { | ||||||
|       "name": ".NET Launch (Client) 1", |       "name": ".NET Core Launch (console)", | ||||||
|       "type": "coreclr", |       "type": "coreclr", | ||||||
|       "request": "launch", |       "request": "launch", | ||||||
|       "preLaunchTask": "build-client", |       "preLaunchTask": "build", | ||||||
|       "program": "${workspaceFolder}/Platforms/Desktop/bin/Debug/net9.0/Pong.dll", |       // If you have changed target frameworks, make sure to update the program path. | ||||||
|       "args": [], |       "program": "${workspaceFolder}/Game/bin/Debug/net8.0/Game.dll", | ||||||
|       "cwd": "${workspaceFolder}", |       "args": ["server"], | ||||||
|       "stopAtEntry": false, |       "cwd": "${workspaceFolder}/Game", | ||||||
|  |       // For more information about the 'console' field, see https://aka.ms/VSCode-CS-LaunchJson-Console | ||||||
|       "console": "internalConsole", |       "console": "internalConsole", | ||||||
|       "justMyCode": false, |       "stopAtEntry": false | ||||||
|       "logging": { |  | ||||||
|         "moduleLoad": false, |  | ||||||
|         "programOutput": true |  | ||||||
|       } |  | ||||||
|     }, |     }, | ||||||
|     { |     { | ||||||
|       "name": ".NET Launch (Client) 2", |       "name": ".NET Core Attach", | ||||||
|       "type": "coreclr", |       "type": "coreclr", | ||||||
|       "request": "launch", |       "request": "attach", | ||||||
|       "preLaunchTask": "build-client", |       "processId": "${command:pickProcess}" | ||||||
|       "program": "${workspaceFolder}/Platforms/Desktop/bin/Debug/net9.0/Desktop.dll", |  | ||||||
|       "args": [], |  | ||||||
|       "cwd": "${workspaceFolder}", |  | ||||||
|       "stopAtEntry": false, |  | ||||||
|       "console": "internalConsole", |  | ||||||
|       "justMyCode": false, |  | ||||||
|       "logging": { |  | ||||||
|         "moduleLoad": false, |  | ||||||
|         "programOutput": true |  | ||||||
|       } |  | ||||||
|     }, |  | ||||||
|     { |  | ||||||
|       "name": ".NET Launch (Server)", |  | ||||||
|       "type": "coreclr", |  | ||||||
|       "request": "launch", |  | ||||||
|       "preLaunchTask": "build-server", |  | ||||||
|       "program": "${workspaceFolder}/Platforms/Server/bin/Debug/net9.0/Server.dll", |  | ||||||
|       "args": [], |  | ||||||
|       "env": { |  | ||||||
|         "PORT": "8888", |  | ||||||
|       }, |  | ||||||
|       "cwd": "${workspaceFolder}", |  | ||||||
|       "stopAtEntry": false, |  | ||||||
|       "console": "internalConsole", |  | ||||||
|       "justMyCode": false, |  | ||||||
|       "logging": { |  | ||||||
|         "moduleLoad": false, |  | ||||||
|         "programOutput": true |  | ||||||
|       } |  | ||||||
|     } |  | ||||||
|   ], |  | ||||||
|   "compounds": [ |  | ||||||
|     { |  | ||||||
|       "name": ".NET Launch Client & Server", |  | ||||||
|       "configurations": [ |  | ||||||
|         ".NET Launch (Server)", |  | ||||||
|         ".NET Launch (Client) 1" |  | ||||||
|       ] |  | ||||||
|     }, |  | ||||||
|     { |  | ||||||
|       "name": ".NET Launch 2 Client & 1 Server", |  | ||||||
|       "configurations": [ |  | ||||||
|         ".NET Launch (Server)", |  | ||||||
|         ".NET Launch (Client) 1", |  | ||||||
|         ".NET Launch (Client) 2" |  | ||||||
|       ] |  | ||||||
|     }, |  | ||||||
|     { |  | ||||||
|       "name": ".NET Launch 2 Clients", |  | ||||||
|       "configurations": [ |  | ||||||
|         ".NET Launch (Client) 1", |  | ||||||
|         ".NET Launch (Client) 2" |  | ||||||
|       ] |  | ||||||
|     } |     } | ||||||
|   ] |   ] | ||||||
| } | } | ||||||
|   | |||||||
							
								
								
									
										7
									
								
								.vscode/settings.json
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								.vscode/settings.json
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,7 @@ | |||||||
|  | { | ||||||
|  |     "cSpell.words": [ | ||||||
|  |         "AABB", | ||||||
|  |         "DAABB", | ||||||
|  |         "Syntriax" | ||||||
|  |     ] | ||||||
|  | } | ||||||
							
								
								
									
										27
									
								
								.vscode/tasks.json
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										27
									
								
								.vscode/tasks.json
									
									
									
									
										vendored
									
									
								
							| @@ -2,31 +2,16 @@ | |||||||
|   "version": "2.0.0", |   "version": "2.0.0", | ||||||
|   "tasks": [ |   "tasks": [ | ||||||
|     { |     { | ||||||
|       "label": "build-client", |       "type": "dotnet", | ||||||
|       "command": "dotnet", |       "task": "build", | ||||||
|       "type": "process", |       "problemMatcher": ["$msCompile"], | ||||||
|       "args": [ |  | ||||||
|         "build", |  | ||||||
|         "${workspaceFolder}/Platforms/Desktop" |  | ||||||
|       ], |  | ||||||
|       "problemMatcher": "$msCompile", |  | ||||||
|       "group": { |       "group": { | ||||||
|         "kind": "build", |         "kind": "build", | ||||||
|         "isDefault": true |         "isDefault": true | ||||||
|       } |  | ||||||
|       }, |       }, | ||||||
|     { |       "label": "build", | ||||||
|       "label": "build-server", |       "options": { | ||||||
|       "command": "dotnet", |         "cwd": "${workspaceFolder}/Game" | ||||||
|       "type": "process", |  | ||||||
|       "args": [ |  | ||||||
|         "build", |  | ||||||
|         "${workspaceFolder}/Platforms/Server" |  | ||||||
|       ], |  | ||||||
|       "problemMatcher": "$msCompile", |  | ||||||
|       "group": { |  | ||||||
|         "kind": "build", |  | ||||||
|         "isDefault": true |  | ||||||
|       } |       } | ||||||
|     } |     } | ||||||
|   ] |   ] | ||||||
|   | |||||||
							
								
								
									
										16
									
								
								Dockerfile
									
									
									
									
									
								
							
							
						
						
									
										16
									
								
								Dockerfile
									
									
									
									
									
								
							| @@ -1,16 +0,0 @@ | |||||||
| FROM mcr.microsoft.com/dotnet/sdk:9.0 AS build |  | ||||||
|  |  | ||||||
| WORKDIR /App |  | ||||||
| COPY . ./ |  | ||||||
|  |  | ||||||
| RUN dotnet restore |  | ||||||
| RUN dotnet publish Platforms/Server -c Release -r linux-musl-x64 --self-contained true -o out |  | ||||||
|  |  | ||||||
| FROM alpine:latest |  | ||||||
|  |  | ||||||
| WORKDIR /App |  | ||||||
| COPY --from=build /App/out . |  | ||||||
|  |  | ||||||
| RUN apk add --no-cache icu-libs |  | ||||||
|  |  | ||||||
| ENTRYPOINT ["./Server"] |  | ||||||
							
								
								
									
										2
									
								
								Engine
									
									
									
									
									
								
							
							
								
								
								
								
								
							
						
						
									
										2
									
								
								Engine
									
									
									
									
									
								
							 Submodule Engine updated: 65dcb0c564...2cf6135063
									
								
							| @@ -3,31 +3,31 @@ | |||||||
|   "isRoot": true, |   "isRoot": true, | ||||||
|   "tools": { |   "tools": { | ||||||
|     "dotnet-mgcb": { |     "dotnet-mgcb": { | ||||||
|       "version": "3.8.2.1105", |       "version": "3.8.1.303", | ||||||
|       "commands": [ |       "commands": [ | ||||||
|         "mgcb" |         "mgcb" | ||||||
|       ] |       ] | ||||||
|     }, |     }, | ||||||
|     "dotnet-mgcb-editor": { |     "dotnet-mgcb-editor": { | ||||||
|       "version": "3.8.2.1105", |       "version": "3.8.1.303", | ||||||
|       "commands": [ |       "commands": [ | ||||||
|         "mgcb-editor" |         "mgcb-editor" | ||||||
|       ] |       ] | ||||||
|     }, |     }, | ||||||
|     "dotnet-mgcb-editor-linux": { |     "dotnet-mgcb-editor-linux": { | ||||||
|       "version": "3.8.2.1105", |       "version": "3.8.1.303", | ||||||
|       "commands": [ |       "commands": [ | ||||||
|         "mgcb-editor-linux" |         "mgcb-editor-linux" | ||||||
|       ] |       ] | ||||||
|     }, |     }, | ||||||
|     "dotnet-mgcb-editor-windows": { |     "dotnet-mgcb-editor-windows": { | ||||||
|       "version": "3.8.2.1105", |       "version": "3.8.1.303", | ||||||
|       "commands": [ |       "commands": [ | ||||||
|         "mgcb-editor-windows" |         "mgcb-editor-windows" | ||||||
|       ] |       ] | ||||||
|     }, |     }, | ||||||
|     "dotnet-mgcb-editor-mac": { |     "dotnet-mgcb-editor-mac": { | ||||||
|       "version": "3.8.2.1105", |       "version": "3.8.1.303", | ||||||
|       "commands": [ |       "commands": [ | ||||||
|         "mgcb-editor-mac" |         "mgcb-editor-mac" | ||||||
|       ] |       ] | ||||||
							
								
								
									
										0
									
								
								.dockerignore → Game/.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										0
									
								
								.dockerignore → Game/.gitignore
									
									
									
									
										vendored
									
									
								
							
							
								
								
									
										8
									
								
								Game/Abstract/IContentLoader.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								Game/Abstract/IContentLoader.cs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,8 @@ | |||||||
|  | using Microsoft.Xna.Framework.Content; | ||||||
|  |  | ||||||
|  | namespace Pong.Behaviours; | ||||||
|  |  | ||||||
|  | public interface IMonoGameContentLoader | ||||||
|  | { | ||||||
|  |     void LoadContent(ContentManager content); | ||||||
|  | } | ||||||
							
								
								
									
										8
									
								
								Game/Abstract/IDisplayableShape.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								Game/Abstract/IDisplayableShape.cs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,8 @@ | |||||||
|  | using Apos.Shapes; | ||||||
|  |  | ||||||
|  | namespace Syntriax.Engine.Core.Abstract; | ||||||
|  |  | ||||||
|  | public interface IDisplayableShape | ||||||
|  | { | ||||||
|  |     void Draw(ShapeBatch shapeBatch); | ||||||
|  | } | ||||||
							
								
								
									
										8
									
								
								Game/Abstract/IDisplayableSprite.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								Game/Abstract/IDisplayableSprite.cs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,8 @@ | |||||||
|  | using Microsoft.Xna.Framework.Graphics; | ||||||
|  |  | ||||||
|  | namespace Syntriax.Engine.Core.Abstract; | ||||||
|  |  | ||||||
|  | public interface IDisplayableSprite | ||||||
|  | { | ||||||
|  |     public void Draw(SpriteBatch spriteBatch); | ||||||
|  | } | ||||||
							
								
								
									
										120
									
								
								Game/Behaviours/BallBehaviour.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										120
									
								
								Game/Behaviours/BallBehaviour.cs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,120 @@ | |||||||
|  | using System; | ||||||
|  |  | ||||||
|  | using Microsoft.Xna.Framework.Audio; | ||||||
|  | using Microsoft.Xna.Framework.Content; | ||||||
|  |  | ||||||
|  | using LiteNetLib; | ||||||
|  |  | ||||||
|  | using Syntriax.Engine.Core; | ||||||
|  | using Syntriax.Engine.Network; | ||||||
|  | using Syntriax.Engine.Network.Abstract; | ||||||
|  | using Syntriax.Engine.Physics2D; | ||||||
|  | using Syntriax.Engine.Physics2D.Abstract; | ||||||
|  |  | ||||||
|  | namespace Pong.Behaviours; | ||||||
|  |  | ||||||
|  | public class BallBehaviour : NetworkBehaviour, IMonoGameContentLoader | ||||||
|  | { | ||||||
|  |     public Vector2D StartDirection { get; private set; } = Vector2D.Zero; | ||||||
|  |     public float Speed { get; set; } = 500f; | ||||||
|  |     public float SpeedUpMultiplier { get; set; } = .0125f; | ||||||
|  |  | ||||||
|  |     private readonly Random random = new(); | ||||||
|  |     private IRigidBody2D rigidBody = null!; | ||||||
|  |     private INetworkCommunicator communicator = null!; | ||||||
|  |     private SoundEffect soundEffect = null!; | ||||||
|  |  | ||||||
|  |     public void LoadContent(ContentManager content) | ||||||
|  |     { | ||||||
|  |         soundEffect = content.Load<SoundEffect>("Hit"); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     protected override void OnFirstActiveFrame() | ||||||
|  |     { | ||||||
|  |         if (!BehaviourController.TryGetBehaviour(out IRigidBody2D? foundRigidBody)) | ||||||
|  |             throw new Exception($"{nameof(IRigidBody2D)} is missing on {GameObject.Name}."); | ||||||
|  |         if (!BehaviourController.TryGetBehaviour(out ICollider2D? foundCollider)) | ||||||
|  |             throw new Exception($"{nameof(ICollider2D)} is missing on {GameObject.Name}."); | ||||||
|  |         if (!GameObject.GameManager.TryFindBehaviour(out INetworkCommunicator? foundCommunicator)) | ||||||
|  |             throw new Exception($"{nameof(INetworkCommunicator)} is missing on GameManager."); | ||||||
|  |  | ||||||
|  |         foundCollider.OnCollisionDetected += OnCollisionDetected; | ||||||
|  |  | ||||||
|  |         rigidBody = foundRigidBody; | ||||||
|  |         communicator = foundCommunicator; | ||||||
|  |         if (GameObject.GameManager.TryFindBehaviour(out PongManagerBehaviour? pongManager)) | ||||||
|  |         { | ||||||
|  |             pongManager.OnReset += ResetBall; | ||||||
|  |             pongManager.OnScored += ResetBall; | ||||||
|  |             pongManager.OnFinished += DisableBall; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     private void DisableBall(PongManagerBehaviour pongManager) | ||||||
|  |     { | ||||||
|  |         BehaviourController.GameObject.Transform.Position = Vector2D.Zero; | ||||||
|  |         rigidBody.Velocity = Vector2D.Zero; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     private void ResetBall(PongManagerBehaviour pongManager) | ||||||
|  |     { | ||||||
|  |         StateEnable.Enabled = true; | ||||||
|  |         BehaviourController.GameObject.Transform.Position = Vector2D.Zero; | ||||||
|  |         rigidBody.Velocity = GetRandomDirection() * Speed; | ||||||
|  |  | ||||||
|  |         SendBallData(); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     private Vector2D GetRandomDirection() | ||||||
|  |     { | ||||||
|  |         const float AllowedRadians = 45f * Syntriax.Engine.Core.Math.DegreeToRadian; | ||||||
|  |         float rotation = (float)random.NextDouble() * 2f * AllowedRadians - AllowedRadians; | ||||||
|  |         bool isBackwards = (random.Next() % 2) == 1; | ||||||
|  |         return Vector2D.Right.Rotate(isBackwards ? rotation + Syntriax.Engine.Core.Math.PI : rotation); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     protected override void OnUpdate() | ||||||
|  |     { | ||||||
|  |         if (rigidBody.Velocity.MagnitudeSquared <= 0.01f) | ||||||
|  |             return; | ||||||
|  |  | ||||||
|  |         Vector2D speedUp = rigidBody.Velocity.Normalized * Time.DeltaTimeFrame; | ||||||
|  |         rigidBody.Velocity += speedUp * SpeedUpMultiplier; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     private void OnCollisionDetected(ICollider2D collider2D, CollisionDetectionInformation information) | ||||||
|  |     { | ||||||
|  |         if (Syntriax.Engine.Core.Math.Abs(information.Normal.Dot(Vector2D.Right)) > .25) | ||||||
|  |             rigidBody.Velocity = information.Left.Transform.Position.FromTo(information.Right.Transform.Position).Normalized * rigidBody.Velocity.Magnitude; | ||||||
|  |         else | ||||||
|  |             rigidBody.Velocity = rigidBody.Velocity.Reflect(information.Normal); | ||||||
|  |  | ||||||
|  |         soundEffect.Play(); | ||||||
|  |  | ||||||
|  |         SendBallData(); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     private void SendBallData() | ||||||
|  |     { | ||||||
|  |         if (communicator is not INetworkServer server) | ||||||
|  |             return; | ||||||
|  |  | ||||||
|  |         LiteNetLib.Utils.NetDataWriter dataWriter = communicator.GetMessageWriter(this); | ||||||
|  |         dataWriter.Put(rigidBody.Transform.Position); | ||||||
|  |         dataWriter.Put(rigidBody.Velocity); | ||||||
|  |         server.Manager.SendToAll(dataWriter, LiteNetLib.DeliveryMethod.ReliableOrdered); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     protected override void OnMessageReceived(NetPacketReader reader, NetPeer peer) | ||||||
|  |     { | ||||||
|  |         rigidBody.Transform.Position = reader.GetVector2D(); | ||||||
|  |         rigidBody.Velocity = reader.GetVector2D(); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public BallBehaviour() { } | ||||||
|  |     public BallBehaviour(Vector2D startDirection, float speed) | ||||||
|  |     { | ||||||
|  |         StartDirection = Vector2D.Normalize(startDirection); | ||||||
|  |         Speed = speed; | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										74
									
								
								Game/Behaviours/CameraController.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										74
									
								
								Game/Behaviours/CameraController.cs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,74 @@ | |||||||
|  | using Microsoft.Xna.Framework.Input; | ||||||
|  |  | ||||||
|  | using Syntriax.Engine.Core; | ||||||
|  | using Syntriax.Engine.Input; | ||||||
|  |  | ||||||
|  | namespace Pong.Behaviours; | ||||||
|  |  | ||||||
|  | public class CameraController : BehaviourOverride | ||||||
|  | { | ||||||
|  |     private MonoGameCamera2DBehaviour cameraBehaviour = null!; | ||||||
|  |     private IButtonInputs<Keys> buttonInputs = null!; | ||||||
|  |  | ||||||
|  |     private float defaultZoomLevel = 1f; | ||||||
|  |  | ||||||
|  |     protected override void OnFirstActiveFrame() | ||||||
|  |     { | ||||||
|  |         if (BehaviourController.TryGetBehaviour(out MonoGameCamera2DBehaviour? foundCameraBehaviour)) | ||||||
|  |             cameraBehaviour = foundCameraBehaviour; | ||||||
|  |  | ||||||
|  |         cameraBehaviour ??= BehaviourController.AddBehaviour<MonoGameCamera2DBehaviour>(); | ||||||
|  |  | ||||||
|  |         if (BehaviourController.TryGetBehaviour(out IButtonInputs<Keys>? foundButtonInputs)) | ||||||
|  |             buttonInputs = foundButtonInputs; | ||||||
|  |  | ||||||
|  |         buttonInputs ??= BehaviourController.AddBehaviour<KeyboardInputsBehaviour>(); | ||||||
|  |         buttonInputs.RegisterOnPress(Keys.F, SwitchToFullScreen); | ||||||
|  |         buttonInputs.RegisterOnPress(Keys.R, ResetCamera); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     protected override void OnUpdate() | ||||||
|  |     { | ||||||
|  |         if (buttonInputs.IsPressed(Keys.U)) | ||||||
|  |             cameraBehaviour.Zoom += Time.Elapsed.Nanoseconds * 0.00025f; | ||||||
|  |         if (buttonInputs.IsPressed(Keys.J)) | ||||||
|  |             cameraBehaviour.Zoom -= Time.Elapsed.Nanoseconds * 0.00025f; | ||||||
|  |  | ||||||
|  |  | ||||||
|  |         if (buttonInputs.IsPressed(Keys.NumPad8)) cameraBehaviour.BehaviourController.GameObject.Transform.Position += Vector2D.Up.Rotate(Transform.Rotation * Math.DegreeToRadian) * Time.DeltaTimeFrame; | ||||||
|  |         if (buttonInputs.IsPressed(Keys.NumPad2)) cameraBehaviour.BehaviourController.GameObject.Transform.Position -= Vector2D.Up.Rotate(Transform.Rotation * Math.DegreeToRadian) * Time.DeltaTimeFrame; | ||||||
|  |         if (buttonInputs.IsPressed(Keys.NumPad6)) cameraBehaviour.BehaviourController.GameObject.Transform.Position += Vector2D.Right.Rotate(Transform.Rotation * Math.DegreeToRadian) * Time.DeltaTimeFrame; | ||||||
|  |         if (buttonInputs.IsPressed(Keys.NumPad4)) cameraBehaviour.BehaviourController.GameObject.Transform.Position -= Vector2D.Right.Rotate(Transform.Rotation * Math.DegreeToRadian) * Time.DeltaTimeFrame; | ||||||
|  |  | ||||||
|  |  | ||||||
|  |         if (buttonInputs.IsPressed(Keys.Q)) | ||||||
|  |             cameraBehaviour.BehaviourController.GameObject.Transform.Rotation += Time.Elapsed.Nanoseconds * 0.0025f; | ||||||
|  |         if (buttonInputs.IsPressed(Keys.E)) | ||||||
|  |             cameraBehaviour.BehaviourController.GameObject.Transform.Rotation -= Time.Elapsed.Nanoseconds * 0.0025f; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     private void SwitchToFullScreen(IButtonInputs<Keys> inputs, Keys keys) | ||||||
|  |     { | ||||||
|  |         if (cameraBehaviour.Graphics.IsFullScreen) | ||||||
|  |             return; | ||||||
|  |  | ||||||
|  |         cameraBehaviour.Graphics.PreferMultiSampling = false; | ||||||
|  |         cameraBehaviour.Graphics.PreferredBackBufferWidth = cameraBehaviour.Graphics.GraphicsDevice.Adapter.CurrentDisplayMode.Width; | ||||||
|  |         cameraBehaviour.Graphics.PreferredBackBufferHeight = cameraBehaviour.Graphics.GraphicsDevice.Adapter.CurrentDisplayMode.Height; | ||||||
|  |         cameraBehaviour.Graphics.IsFullScreen = true; | ||||||
|  |         cameraBehaviour.Graphics.ApplyChanges(); | ||||||
|  |  | ||||||
|  |         float previousScreenSize = Math.Sqrt(Math.Sqr(cameraBehaviour.Viewport.Width) + Math.Sqr(cameraBehaviour.Viewport.Height)); | ||||||
|  |         float currentScreenSize = Math.Sqrt(Math.Sqr(cameraBehaviour.Graphics.GraphicsDevice.Viewport.Width) + Math.Sqr(cameraBehaviour.Graphics.GraphicsDevice.Viewport.Height)); | ||||||
|  |         defaultZoomLevel /= previousScreenSize / currentScreenSize; | ||||||
|  |         cameraBehaviour.Zoom /= previousScreenSize / currentScreenSize; | ||||||
|  |         cameraBehaviour.Viewport = cameraBehaviour.Graphics.GraphicsDevice.Viewport; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     private void ResetCamera(IButtonInputs<Keys> inputs, Keys keys) | ||||||
|  |     { | ||||||
|  |         cameraBehaviour.Zoom = defaultZoomLevel; | ||||||
|  |         Transform.Position = Vector2D.Zero; | ||||||
|  |         Transform.Rotation = 0f; | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										29
									
								
								Game/Behaviours/CircleBehaviour.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								Game/Behaviours/CircleBehaviour.cs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,29 @@ | |||||||
|  | using Microsoft.Xna.Framework; | ||||||
|  |  | ||||||
|  | using Apos.Shapes; | ||||||
|  |  | ||||||
|  | using Syntriax.Engine.Core.Abstract; | ||||||
|  | using Syntriax.Engine.Physics2D.Primitives; | ||||||
|  |  | ||||||
|  | namespace Pong.Behaviours; | ||||||
|  |  | ||||||
|  | public class CircleBehaviour : Syntriax.Engine.Physics2D.Collider2DCircleBehaviour, IDisplayableShape | ||||||
|  | { | ||||||
|  |     public Color Color { get; set; } = Color.White; | ||||||
|  |     public float Thickness { get; set; } = .5f; | ||||||
|  |  | ||||||
|  |     public void Draw(ShapeBatch shapeBatch) | ||||||
|  |     { | ||||||
|  |         if (!IsActive) | ||||||
|  |             return; | ||||||
|  |  | ||||||
|  |         Recalculate(); | ||||||
|  |  | ||||||
|  |         shapeBatch.BorderCircle(CircleWorld.Center.ToDisplayVector2(), CircleWorld.Radius, Color); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public CircleBehaviour(Circle circle) : base(circle) { } | ||||||
|  |     public CircleBehaviour(Circle circle, float thickness) : base(circle) { Thickness = thickness; } | ||||||
|  |     public CircleBehaviour(Circle circle, Color color) : base(circle) { Color = color; } | ||||||
|  |     public CircleBehaviour(Circle circle, Color color, float thickness) : base(circle) { Thickness = thickness; Color = color; } | ||||||
|  | } | ||||||
							
								
								
									
										106
									
								
								Game/Behaviours/KeyboardInputsBehaviour.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										106
									
								
								Game/Behaviours/KeyboardInputsBehaviour.cs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,106 @@ | |||||||
|  | using System; | ||||||
|  | using System.Collections.Generic; | ||||||
|  | using Microsoft.Xna.Framework.Input; | ||||||
|  |  | ||||||
|  | using Syntriax.Engine.Core; | ||||||
|  | using Syntriax.Engine.Input; | ||||||
|  |  | ||||||
|  | namespace Pong.Behaviours; | ||||||
|  |  | ||||||
|  | public class KeyboardInputsBehaviour : BehaviourOverride, IButtonInputs<Keys> | ||||||
|  | { | ||||||
|  |     private readonly Dictionary<Keys, Action<IButtonInputs<Keys>, Keys>?> OnPressed = new(256); | ||||||
|  |     private readonly Dictionary<Keys, Action<IButtonInputs<Keys>, Keys>?> OnReleased = new(256); | ||||||
|  |  | ||||||
|  |     private int cachePressedCurrentlyCount = 0; | ||||||
|  |     private readonly Keys[] cachePressedCurrently = new Keys[256]; | ||||||
|  |  | ||||||
|  |     private int cachePressedPreviouslyCount = 0; | ||||||
|  |     private readonly Keys[] cachePressedPreviously = new Keys[256]; | ||||||
|  |  | ||||||
|  |     public void RegisterOnPress(Keys key, Action<IButtonInputs<Keys>, Keys> callback) | ||||||
|  |     { | ||||||
|  |         if (OnPressed.TryGetValue(key, out var action)) | ||||||
|  |         { | ||||||
|  |             action += callback; | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         OnPressed.Add(key, callback); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public void UnregisterOnPress(Keys key, Action<IButtonInputs<Keys>, Keys> callback) | ||||||
|  |     { | ||||||
|  |         if (OnPressed.TryGetValue(key, out var action)) | ||||||
|  |             action -= callback; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public void RegisterOnRelease(Keys key, Action<IButtonInputs<Keys>, Keys> callback) | ||||||
|  |     { | ||||||
|  |         if (OnReleased.TryGetValue(key, out var action)) | ||||||
|  |         { | ||||||
|  |             action += callback; | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         OnReleased.Add(key, callback); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public void UnregisterOnRelease(Keys key, Action<IButtonInputs<Keys>, Keys> callback) | ||||||
|  |     { | ||||||
|  |         if (OnReleased.TryGetValue(key, out var action)) | ||||||
|  |             action -= callback; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     protected override void OnUpdate() | ||||||
|  |     { | ||||||
|  |         KeyboardState keyboardState = Keyboard.GetState(); | ||||||
|  |         keyboardState.GetPressedKeys(cachePressedCurrently); | ||||||
|  |         cachePressedCurrentlyCount = keyboardState.GetPressedKeyCount(); | ||||||
|  |  | ||||||
|  |         for (int i = 0; i < cachePressedCurrentlyCount; i++) | ||||||
|  |         { | ||||||
|  |             Keys currentlyPressedKey = cachePressedCurrently[i]; | ||||||
|  |  | ||||||
|  |             if (!OnPressed.TryGetValue(currentlyPressedKey, out var action)) | ||||||
|  |                 continue; | ||||||
|  |  | ||||||
|  |             if (WasPressed(currentlyPressedKey)) | ||||||
|  |                 continue; | ||||||
|  |  | ||||||
|  |             action?.Invoke(this, currentlyPressedKey); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         for (int i = 0; i < cachePressedPreviouslyCount; i++) | ||||||
|  |         { | ||||||
|  |             Keys previouslyPressedKey = cachePressedPreviously[i]; | ||||||
|  |  | ||||||
|  |             if (!OnReleased.TryGetValue(previouslyPressedKey, out var action)) | ||||||
|  |                 continue; | ||||||
|  |  | ||||||
|  |             if (IsPressed(previouslyPressedKey)) | ||||||
|  |                 continue; | ||||||
|  |  | ||||||
|  |             action?.Invoke(this, previouslyPressedKey); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         Array.Copy(cachePressedCurrently, cachePressedPreviously, cachePressedCurrentlyCount); | ||||||
|  |         cachePressedPreviouslyCount = cachePressedCurrentlyCount; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public bool IsPressed(Keys key) | ||||||
|  |     { | ||||||
|  |         for (int i = 0; i < cachePressedCurrentlyCount; i++) | ||||||
|  |             if (cachePressedCurrently[i] == key) | ||||||
|  |                 return true; | ||||||
|  |         return false; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public bool WasPressed(Keys key) | ||||||
|  |     { | ||||||
|  |         for (int i = 0; i < cachePressedPreviouslyCount; i++) | ||||||
|  |             if (cachePressedPreviously[i] == key) | ||||||
|  |                 return true; | ||||||
|  |         return false; | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										102
									
								
								Game/Behaviours/MonoGameCamera2DBehaviour.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										102
									
								
								Game/Behaviours/MonoGameCamera2DBehaviour.cs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,102 @@ | |||||||
|  | using Microsoft.Xna.Framework; | ||||||
|  | using Microsoft.Xna.Framework.Graphics; | ||||||
|  |  | ||||||
|  | using Syntriax.Engine.Core; | ||||||
|  | using Syntriax.Engine.Core.Abstract; | ||||||
|  |  | ||||||
|  | namespace Pong.Behaviours; | ||||||
|  |  | ||||||
|  | public class MonoGameCamera2DBehaviour(GraphicsDeviceManager Graphics) : BehaviourOverride, ICamera2D | ||||||
|  | { | ||||||
|  |     public System.Action<MonoGameCamera2DBehaviour>? OnMatrixTransformChanged { get; set; } = null; | ||||||
|  |     public System.Action<MonoGameCamera2DBehaviour>? OnViewportChanged { get; set; } = null; | ||||||
|  |     public System.Action<MonoGameCamera2DBehaviour>? OnZoomChanged { get; set; } = null; | ||||||
|  |  | ||||||
|  |     private Matrix _matrixTransform = Matrix.Identity; | ||||||
|  |  | ||||||
|  |     private Viewport _viewport = default; | ||||||
|  |     private float _zoom = 1f; | ||||||
|  |  | ||||||
|  |     public GraphicsDeviceManager Graphics { get; } = Graphics; | ||||||
|  |  | ||||||
|  |     public Matrix MatrixTransform | ||||||
|  |     { | ||||||
|  |         get => _matrixTransform; | ||||||
|  |         set | ||||||
|  |         { | ||||||
|  |             if (_matrixTransform == value) | ||||||
|  |                 return; | ||||||
|  |  | ||||||
|  |             _matrixTransform = value; | ||||||
|  |             OnMatrixTransformChanged?.Invoke(this); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public Vector2D Position | ||||||
|  |     { | ||||||
|  |         get => Transform.Position; | ||||||
|  |         set => Transform.Position = value; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public Viewport Viewport | ||||||
|  |     { | ||||||
|  |         get => _viewport; | ||||||
|  |         set | ||||||
|  |         { | ||||||
|  |             if (_viewport.Equals(value)) | ||||||
|  |                 return; | ||||||
|  |  | ||||||
|  |             _viewport = value; | ||||||
|  |             OnViewportChanged?.Invoke(this); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public float Zoom | ||||||
|  |     { | ||||||
|  |         get => _zoom; | ||||||
|  |         set | ||||||
|  |         { | ||||||
|  |             float newValue = Math.Max(0.1f, value); | ||||||
|  |  | ||||||
|  |             if (_zoom == newValue) | ||||||
|  |                 return; | ||||||
|  |  | ||||||
|  |             _zoom = newValue; | ||||||
|  |             OnZoomChanged?.Invoke(this); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public float Rotation | ||||||
|  |     { | ||||||
|  |         get => Transform.Rotation; | ||||||
|  |         set => Transform.Rotation = value; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     System.Action<IAssignableTransform>? IAssignableTransform.OnTransformAssigned { get => GameObject.OnTransformAssigned; set => GameObject.OnTransformAssigned = value; } | ||||||
|  |     ITransform IAssignableTransform.Transform => GameObject.Transform; | ||||||
|  |     bool IAssignableTransform.Assign(ITransform transform) => GameObject.Assign(transform); | ||||||
|  |  | ||||||
|  |     // TODO This causes delay since OnPreDraw calls assuming this is called in in Update  | ||||||
|  |     public Vector2D ScreenToWorldPosition(Vector2D screenPosition) | ||||||
|  |     { | ||||||
|  |         Vector2D worldPosition = Vector2.Transform(screenPosition.ToVector2(), Matrix.Invert(MatrixTransform)).ToVector2D(); | ||||||
|  |         return worldPosition.Scale(EngineConverter.screenScale); | ||||||
|  |     } | ||||||
|  |     public Vector2D WorldToScreenPosition(Vector2D worldPosition) | ||||||
|  |     { | ||||||
|  |         Vector2D screenPosition = Vector2.Transform(worldPosition.ToVector2(), MatrixTransform).ToVector2D(); | ||||||
|  |         return screenPosition.Scale(EngineConverter.screenScale); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     protected override void OnFirstActiveFrame() | ||||||
|  |         => Viewport = Graphics.GraphicsDevice.Viewport; | ||||||
|  |  | ||||||
|  |     protected override void OnPreDraw() | ||||||
|  |     { | ||||||
|  |         MatrixTransform = | ||||||
|  |             Matrix.CreateTranslation(new Vector3(-Position.X, Position.Y, 0f)) * | ||||||
|  |             Matrix.CreateRotationZ(Rotation * Math.DegreeToRadian) * | ||||||
|  |             Matrix.CreateScale(Zoom) * | ||||||
|  |             Matrix.CreateTranslation(new Vector3(_viewport.Width * .5f, _viewport.Height * .5f, 0f)); | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										53
									
								
								Game/Behaviours/MovementBallBehaviour.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										53
									
								
								Game/Behaviours/MovementBallBehaviour.cs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,53 @@ | |||||||
|  | using System; | ||||||
|  |  | ||||||
|  | using Syntriax.Engine.Core; | ||||||
|  | using Syntriax.Engine.Physics2D; | ||||||
|  | using Syntriax.Engine.Physics2D.Abstract; | ||||||
|  |  | ||||||
|  | namespace Pong.Behaviours; | ||||||
|  |  | ||||||
|  | public class MovementBallBehaviour : BehaviourOverride | ||||||
|  | { | ||||||
|  |     public Vector2D StartDirection { get; private set; } = Vector2D.Zero; | ||||||
|  |     public float Speed { get; set; } = 500f; | ||||||
|  |     public float SpeedUpMultiplier { get; set; } = .0125f; | ||||||
|  |  | ||||||
|  |     private IRigidBody2D rigidBody = null!; | ||||||
|  |  | ||||||
|  |     protected override void OnFirstActiveFrame() | ||||||
|  |     { | ||||||
|  |         if (!BehaviourController.TryGetBehaviour(out IRigidBody2D? foundRigidBody)) | ||||||
|  |             throw new Exception($"{nameof(IRigidBody2D)} is missing on {GameObject.Name}."); | ||||||
|  |         if (!BehaviourController.TryGetBehaviour(out ICollider2D? foundCollider)) | ||||||
|  |             throw new Exception($"{nameof(ICollider2D)} is missing on {GameObject.Name}."); | ||||||
|  |  | ||||||
|  |         foundRigidBody.Velocity = StartDirection * Speed; | ||||||
|  |         foundCollider.OnCollisionDetected += OnCollisionDetected; | ||||||
|  |  | ||||||
|  |         rigidBody = foundRigidBody; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     protected override void OnUpdate() | ||||||
|  |     { | ||||||
|  |         if (rigidBody.Velocity.MagnitudeSquared <= 0.01f) | ||||||
|  |             return; | ||||||
|  |  | ||||||
|  |         Vector2D speedUp = rigidBody.Velocity.Normalized * Time.DeltaTimeFrame; | ||||||
|  |         rigidBody.Velocity += speedUp * SpeedUpMultiplier; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     private void OnCollisionDetected(ICollider2D collider2D, CollisionDetectionInformation information) | ||||||
|  |     { | ||||||
|  |         if (Syntriax.Engine.Core.Math.Abs(information.Normal.Dot(Vector2D.Right)) > .25) | ||||||
|  |             rigidBody.Velocity = information.Left.Transform.Position.FromTo(information.Right.Transform.Position).Normalized * rigidBody.Velocity.Magnitude; | ||||||
|  |         else | ||||||
|  |             rigidBody.Velocity = rigidBody.Velocity.Reflect(information.Normal); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public MovementBallBehaviour() { } | ||||||
|  |     public MovementBallBehaviour(Vector2D startDirection, float speed) | ||||||
|  |     { | ||||||
|  |         StartDirection = Vector2D.Normalize(startDirection); | ||||||
|  |         Speed = speed; | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										154
									
								
								Game/Behaviours/NetworkedKeyboardInputs.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										154
									
								
								Game/Behaviours/NetworkedKeyboardInputs.cs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,154 @@ | |||||||
|  | using System; | ||||||
|  | using System.Collections.Generic; | ||||||
|  | using LiteNetLib; | ||||||
|  | using Microsoft.Xna.Framework.Input; | ||||||
|  | using Syntriax.Engine.Input; | ||||||
|  | using Syntriax.Engine.Network; | ||||||
|  |  | ||||||
|  | namespace Pong.Behaviours; | ||||||
|  |  | ||||||
|  | public class NetworkedKeyboardInputs : NetworkBehaviour, IButtonInputs<Keys> | ||||||
|  | { | ||||||
|  |     private readonly Dictionary<Keys, Action<IButtonInputs<Keys>, Keys>?> OnPressed = new(256); | ||||||
|  |     private readonly Dictionary<Keys, Action<IButtonInputs<Keys>, Keys>?> OnReleased = new(256); | ||||||
|  |  | ||||||
|  |     private int cachePressedCurrentlyCount = 0; | ||||||
|  |     private readonly Keys[] cachePressedCurrently = new Keys[256]; | ||||||
|  |  | ||||||
|  |     private int cachePressedPreviouslyCount = 0; | ||||||
|  |     private readonly Keys[] cachePressedPreviously = new Keys[256]; | ||||||
|  |  | ||||||
|  |     public void RegisterOnPress(Keys key, Action<IButtonInputs<Keys>, Keys> callback) | ||||||
|  |     { | ||||||
|  |         if (OnPressed.TryGetValue(key, out var action)) | ||||||
|  |         { | ||||||
|  |             action += callback; | ||||||
|  |             OnPressed.Remove(key); | ||||||
|  |             OnPressed.Add(key, action); | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         OnPressed.Add(key, callback); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public void UnregisterOnPress(Keys key, Action<IButtonInputs<Keys>, Keys> callback) | ||||||
|  |     { | ||||||
|  |         if (OnPressed.TryGetValue(key, out var action)) | ||||||
|  |             action -= callback; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public void RegisterOnRelease(Keys key, Action<IButtonInputs<Keys>, Keys> callback) | ||||||
|  |     { | ||||||
|  |         if (OnReleased.TryGetValue(key, out var action)) | ||||||
|  |         { | ||||||
|  |             action += callback; | ||||||
|  |             OnReleased.Remove(key); | ||||||
|  |             OnReleased.Add(key, action); | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         OnReleased.Add(key, callback); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public void UnregisterOnRelease(Keys key, Action<IButtonInputs<Keys>, Keys> callback) | ||||||
|  |     { | ||||||
|  |         if (OnReleased.TryGetValue(key, out var action)) | ||||||
|  |             action -= callback; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     protected override void OnUpdate() | ||||||
|  |     { | ||||||
|  |         if (!IsServer && !LocalAssigned) | ||||||
|  |             return; | ||||||
|  |  | ||||||
|  |         KeyboardState keyboardState = Keyboard.GetState(); | ||||||
|  |         keyboardState.GetPressedKeys(cachePressedCurrently); | ||||||
|  |         cachePressedCurrentlyCount = keyboardState.GetPressedKeyCount(); | ||||||
|  |  | ||||||
|  |         for (int i = 0; i < cachePressedCurrentlyCount; i++) | ||||||
|  |         { | ||||||
|  |             Keys currentlyPressedKey = cachePressedCurrently[i]; | ||||||
|  |  | ||||||
|  |             if (!OnPressed.TryGetValue(currentlyPressedKey, out var action)) | ||||||
|  |                 continue; | ||||||
|  |  | ||||||
|  |             if (WasPressed(currentlyPressedKey)) | ||||||
|  |                 continue; | ||||||
|  |  | ||||||
|  |             action?.Invoke(this, currentlyPressedKey); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         for (int i = 0; i < cachePressedPreviouslyCount; i++) | ||||||
|  |         { | ||||||
|  |             Keys previouslyPressedKey = cachePressedPreviously[i]; | ||||||
|  |  | ||||||
|  |             if (!OnReleased.TryGetValue(previouslyPressedKey, out var action)) | ||||||
|  |                 continue; | ||||||
|  |  | ||||||
|  |             if (IsPressed(previouslyPressedKey)) | ||||||
|  |                 continue; | ||||||
|  |  | ||||||
|  |             action?.Invoke(this, previouslyPressedKey); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         Array.Copy(cachePressedCurrently, cachePressedPreviously, cachePressedCurrentlyCount); | ||||||
|  |         cachePressedPreviouslyCount = cachePressedCurrentlyCount; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public bool IsPressed(Keys key) | ||||||
|  |     { | ||||||
|  |         for (int i = 0; i < cachePressedCurrentlyCount; i++) | ||||||
|  |             if (cachePressedCurrently[i] == key) | ||||||
|  |                 return true; | ||||||
|  |         return false; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public bool WasPressed(Keys key) | ||||||
|  |     { | ||||||
|  |         for (int i = 0; i < cachePressedPreviouslyCount; i++) | ||||||
|  |             if (cachePressedPreviously[i] == key) | ||||||
|  |                 return true; | ||||||
|  |         return false; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     protected override void OnInitialize() | ||||||
|  |     { | ||||||
|  |         base.OnInitialize(); | ||||||
|  |         foreach (Keys key in Enum.GetValues(typeof(Keys))) | ||||||
|  |         { | ||||||
|  |             RegisterOnPress(key, (keys, keyVal) => | ||||||
|  |             { | ||||||
|  |                 if (!LocalAssigned && !IsServer) | ||||||
|  |                     return; | ||||||
|  |  | ||||||
|  |                 var netDataWriter = NetworkCommunicator.GetMessageWriter(this); | ||||||
|  |                 netDataWriter.Put(true); | ||||||
|  |                 netDataWriter.Put((int)key); | ||||||
|  |                 NetworkCommunicator.Manager.SendToAll(netDataWriter, DeliveryMethod.ReliableOrdered); | ||||||
|  |             }); | ||||||
|  |             RegisterOnRelease(key, (keys, keyVal) => | ||||||
|  |             { | ||||||
|  |                 if (!LocalAssigned && !IsServer) | ||||||
|  |                     return; | ||||||
|  |  | ||||||
|  |                 var netDataWriter = NetworkCommunicator.GetMessageWriter(this); | ||||||
|  |                 netDataWriter.Put(false); | ||||||
|  |                 netDataWriter.Put((int)key); | ||||||
|  |                 NetworkCommunicator.Manager.SendToAll(netDataWriter, DeliveryMethod.ReliableOrdered); | ||||||
|  |             }); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     protected override void OnMessageReceived(NetPacketReader reader, NetPeer peer) | ||||||
|  |     { | ||||||
|  |         bool isPressed = reader.GetBool(); | ||||||
|  |         Keys key = (Keys)reader.GetInt(); | ||||||
|  |  | ||||||
|  |         if (isPressed) | ||||||
|  |             if (OnPressed.TryGetValue(key, out var action)) | ||||||
|  |                 action?.Invoke(this, key); | ||||||
|  |         if (!isPressed) | ||||||
|  |             if (OnReleased.TryGetValue(key, out var action)) | ||||||
|  |                 action?.Invoke(this, key); | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										101
									
								
								Game/Behaviours/PaddleBehaviour.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										101
									
								
								Game/Behaviours/PaddleBehaviour.cs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,101 @@ | |||||||
|  | using System; | ||||||
|  |  | ||||||
|  | using Microsoft.Xna.Framework.Input; | ||||||
|  |  | ||||||
|  | using LiteNetLib; | ||||||
|  | using LiteNetLib.Utils; | ||||||
|  |  | ||||||
|  | using Syntriax.Engine.Core; | ||||||
|  | using Syntriax.Engine.Input; | ||||||
|  | using Syntriax.Engine.Network; | ||||||
|  | using Syntriax.Engine.Network.Abstract; | ||||||
|  |  | ||||||
|  | namespace Pong.Behaviours; | ||||||
|  |  | ||||||
|  | public class PaddleBehaviour(Keys Up, Keys Down, float High, float Low, float Speed) : BehaviourOverride | ||||||
|  | { | ||||||
|  |     private Keys Up { get; } = Up; | ||||||
|  |     private Keys Down { get; } = Down; | ||||||
|  |     public float High { get; } = High; | ||||||
|  |     public float Low { get; } = Low; | ||||||
|  |     public float Speed { get; set; } = Speed; | ||||||
|  |  | ||||||
|  |     private bool isUpPressed = false; | ||||||
|  |     private bool isDownPressed = false; | ||||||
|  |  | ||||||
|  |     private IButtonInputs<Keys> inputs = null!; | ||||||
|  |     private INetworkCommunicator communicator = null!; | ||||||
|  |  | ||||||
|  |     protected override void OnUpdate() | ||||||
|  |     { | ||||||
|  |         if (isUpPressed && isDownPressed) | ||||||
|  |             return; | ||||||
|  |  | ||||||
|  |         if (isUpPressed) | ||||||
|  |             MovePaddle(Vector2D.Up * (float)Time.Elapsed.TotalSeconds * Speed); | ||||||
|  |         else if (isDownPressed) | ||||||
|  |             MovePaddle(-Vector2D.Up * (float)Time.Elapsed.TotalSeconds * Speed); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     private void MovePaddle(Vector2D vectorToAdd) | ||||||
|  |     { | ||||||
|  |         GameObject.Transform.Position += vectorToAdd; | ||||||
|  |         GameObject.Transform.Position = new Vector2D(GameObject.Transform.Position.X, MathF.Max(MathF.Min(GameObject.Transform.Position.Y, High), Low)); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     protected override void OnFirstActiveFrame() | ||||||
|  |     { | ||||||
|  |         BehaviourController.TryGetBehaviour<IButtonInputs<Keys>>(out var behaviourResult); | ||||||
|  |         inputs = behaviourResult ?? throw new Exception($"{nameof(IButtonInputs<Keys>)} is missing on {GameObject.Name}."); | ||||||
|  |  | ||||||
|  |         if (!GameObject.GameManager.TryFindBehaviour(out INetworkCommunicator? foundCommunicator)) | ||||||
|  |             throw new Exception($"{nameof(INetworkCommunicator)} is missing on GameManager."); | ||||||
|  |  | ||||||
|  |         inputs.RegisterOnPress(Up, OnUpPressed); | ||||||
|  |         inputs.RegisterOnRelease(Up, OnUpReleased); | ||||||
|  |  | ||||||
|  |         inputs.RegisterOnPress(Down, OnDownPressed); | ||||||
|  |         inputs.RegisterOnRelease(Down, OnDownReleased); | ||||||
|  |  | ||||||
|  |         communicator = foundCommunicator; | ||||||
|  |         communicator.RegisterEntityListener(this, OnDataReceived); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     protected override void OnFinalize() | ||||||
|  |     { | ||||||
|  |         inputs.UnregisterOnPress(Up, OnUpPressed); | ||||||
|  |         inputs.UnregisterOnRelease(Up, OnUpReleased); | ||||||
|  |  | ||||||
|  |         inputs.UnregisterOnPress(Down, OnDownPressed); | ||||||
|  |         inputs.UnregisterOnRelease(Down, OnDownReleased); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     private void UpdateNetwork() | ||||||
|  |     { | ||||||
|  |         NetDataWriter netDataWriter = communicator.GetEntityWriter(this); | ||||||
|  |         netDataWriter.Put(isUpPressed); | ||||||
|  |         netDataWriter.Put(isDownPressed); | ||||||
|  |         netDataWriter.Put(Transform.Position); | ||||||
|  |         communicator.Manager.SendToAll(netDataWriter, DeliveryMethod.ReliableOrdered); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     private void OnDataReceived(NetPacketReader reader, NetPeer peer) | ||||||
|  |     { | ||||||
|  |         if (communicator is INetworkServer server) | ||||||
|  |         { | ||||||
|  |             reader.Get(out isUpPressed); | ||||||
|  |             reader.Get(out isDownPressed); | ||||||
|  |         } | ||||||
|  |         else | ||||||
|  |         { | ||||||
|  |             reader.Get(out isUpPressed); | ||||||
|  |             reader.Get(out isDownPressed); | ||||||
|  |             Transform.Position = reader.GetVector2D(); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     private void OnUpPressed(IButtonInputs<Keys> inputs, Keys keys) { isUpPressed = true; UpdateNetwork(); } | ||||||
|  |     private void OnUpReleased(IButtonInputs<Keys> inputs, Keys keys) { isUpPressed = false; UpdateNetwork(); } | ||||||
|  |     private void OnDownPressed(IButtonInputs<Keys> inputs, Keys keys) { isDownPressed = true; UpdateNetwork(); } | ||||||
|  |     private void OnDownReleased(IButtonInputs<Keys> inputs, Keys keys) { isDownPressed = false; UpdateNetwork(); } | ||||||
|  | } | ||||||
							
								
								
									
										104
									
								
								Game/Behaviours/PongManagerBehaviour.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										104
									
								
								Game/Behaviours/PongManagerBehaviour.cs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,104 @@ | |||||||
|  | using System; | ||||||
|  |  | ||||||
|  | using Microsoft.Xna.Framework.Input; | ||||||
|  |  | ||||||
|  | using LiteNetLib; | ||||||
|  |  | ||||||
|  | using Syntriax.Engine.Core; | ||||||
|  | using Syntriax.Engine.Network; | ||||||
|  | using Syntriax.Engine.Network.Abstract; | ||||||
|  |  | ||||||
|  | namespace Pong.Behaviours; | ||||||
|  |  | ||||||
|  | public class PongManagerBehaviour : NetworkBehaviour | ||||||
|  | { | ||||||
|  |     public Action<PongManagerBehaviour>? OnReset { get; set; } = null; | ||||||
|  |     public Action<PongManagerBehaviour>? OnFinished { get; set; } = null; | ||||||
|  |     public Action<PongManagerBehaviour>? OnScoresUpdated { get; set; } = null; | ||||||
|  |     public Action<PongManagerBehaviour>? OnScored { get; set; } = null; | ||||||
|  |  | ||||||
|  |     private INetworkCommunicator communicator = null!; | ||||||
|  |  | ||||||
|  |     public int ScoreLeft { get; private set; } = 0; | ||||||
|  |     public int ScoreRight { get; private set; } = 0; | ||||||
|  |     public int ScoreSum => ScoreLeft + ScoreRight; | ||||||
|  |  | ||||||
|  |     public int WinScore { get; } = 5; | ||||||
|  |  | ||||||
|  |     public PongManagerBehaviour() => WinScore = 5; | ||||||
|  |     public PongManagerBehaviour(int winScore) => WinScore = winScore; | ||||||
|  |  | ||||||
|  |     protected override void OnFirstActiveFrame() | ||||||
|  |     { | ||||||
|  |         KeyboardInputsBehaviour? buttonInputs = null!; | ||||||
|  |  | ||||||
|  |         if (!BehaviourController.TryGetBehaviour(out buttonInputs)) | ||||||
|  |             buttonInputs = BehaviourController.AddBehaviour<KeyboardInputsBehaviour>(); | ||||||
|  |  | ||||||
|  |         if (!GameObject.GameManager.TryFindBehaviour(out INetworkCommunicator? foundCommunicator)) | ||||||
|  |             throw new Exception($"{nameof(INetworkCommunicator)} is missing on GameManager."); | ||||||
|  |  | ||||||
|  |         buttonInputs.RegisterOnRelease(Keys.Space, (_, _1) => Reset()); | ||||||
|  |  | ||||||
|  |         communicator = foundCommunicator; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public void ScoreToLeft() | ||||||
|  |     { | ||||||
|  |         ScoreLeft++; | ||||||
|  |         OnScoresUpdated?.Invoke(this); | ||||||
|  |         OnScored?.Invoke(this); | ||||||
|  |  | ||||||
|  |         SendData(); | ||||||
|  |  | ||||||
|  |         CheckFinish(); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public void ScoreToRight() | ||||||
|  |     { | ||||||
|  |         ScoreRight++; | ||||||
|  |         OnScoresUpdated?.Invoke(this); | ||||||
|  |         OnScored?.Invoke(this); | ||||||
|  |  | ||||||
|  |         SendData(); | ||||||
|  |  | ||||||
|  |         CheckFinish(); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public void Reset() | ||||||
|  |     { | ||||||
|  |         ScoreLeft = ScoreRight = 0; | ||||||
|  |         OnScoresUpdated?.Invoke(this); | ||||||
|  |         OnReset?.Invoke(this); | ||||||
|  |  | ||||||
|  |         SendData(); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     private void CheckFinish() | ||||||
|  |     { | ||||||
|  |         int halfwayScore = (int)(WinScore * .5f); | ||||||
|  |  | ||||||
|  |         if (ScoreLeft > halfwayScore || ScoreRight > halfwayScore) | ||||||
|  |             OnFinished?.Invoke(this); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     private void SendData() | ||||||
|  |     { | ||||||
|  |         if (communicator is not INetworkServer server) | ||||||
|  |             return; | ||||||
|  |  | ||||||
|  |         LiteNetLib.Utils.NetDataWriter dataWriter = communicator.GetMessageWriter(this); | ||||||
|  |         dataWriter.Put(ScoreLeft); | ||||||
|  |         dataWriter.Put(ScoreRight); | ||||||
|  |         server.Manager.SendToAll(dataWriter, LiteNetLib.DeliveryMethod.ReliableOrdered); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     protected override void OnMessageReceived(NetPacketReader reader, NetPeer peer) | ||||||
|  |     { | ||||||
|  |         ScoreLeft = reader.GetInt(); | ||||||
|  |         ScoreRight = reader.GetInt(); | ||||||
|  |         OnScoresUpdated?.Invoke(this); | ||||||
|  |  | ||||||
|  |         CheckFinish(); | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										48
									
								
								Game/Behaviours/ShapeAABBBehaviour.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										48
									
								
								Game/Behaviours/ShapeAABBBehaviour.cs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,48 @@ | |||||||
|  | using Microsoft.Xna.Framework; | ||||||
|  |  | ||||||
|  | using Apos.Shapes; | ||||||
|  |  | ||||||
|  | using Syntriax.Engine.Core; | ||||||
|  | using Syntriax.Engine.Core.Abstract; | ||||||
|  | using Syntriax.Engine.Input; | ||||||
|  | using Syntriax.Engine.Physics2D.Abstract; | ||||||
|  | using Syntriax.Engine.Physics2D.Primitives; | ||||||
|  |  | ||||||
|  | namespace Pong.Behaviours; | ||||||
|  |  | ||||||
|  | public class ShapeAABBBehaviour : BehaviourOverride, IDisplayableShape | ||||||
|  | { | ||||||
|  |     private IShapeCollider2D? shapeCollider = null; | ||||||
|  |  | ||||||
|  |     public Color Color { get; set; } = Color.White; | ||||||
|  |     public float Thickness { get; set; } = .5f; | ||||||
|  |     public bool display = true; | ||||||
|  |  | ||||||
|  |     protected override void OnFirstActiveFrame() | ||||||
|  |     { | ||||||
|  |         BehaviourController.TryGetBehaviour(out shapeCollider); | ||||||
|  |  | ||||||
|  |         if (BehaviourController.TryGetBehaviour(out IButtonInputs<Microsoft.Xna.Framework.Input.Keys>? keys)) | ||||||
|  |             keys.RegisterOnPress(Microsoft.Xna.Framework.Input.Keys.D, (_1, _2) => display = !display); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public void Draw(ShapeBatch shapeBatch) | ||||||
|  |     { | ||||||
|  |         if (!display) | ||||||
|  |             return; | ||||||
|  |  | ||||||
|  |         if (shapeCollider is null) | ||||||
|  |             return; | ||||||
|  |  | ||||||
|  |         AABB aabb = AABB.FromVectors(shapeCollider.ShapeWorld); | ||||||
|  |  | ||||||
|  |         shapeBatch.BorderCircle(aabb.Center.ToDisplayVector2(), 7.5f, Color.Beige); | ||||||
|  |  | ||||||
|  |         shapeBatch.DrawRectangle(aabb.Center.ApplyDisplayScale().Subtract(aabb.SizeHalf).ToVector2(), aabb.Size.ToVector2(), Color.Transparent, Color.Blue); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public ShapeAABBBehaviour() { } | ||||||
|  |     public ShapeAABBBehaviour(float Thickness) { this.Thickness = Thickness; } | ||||||
|  |     public ShapeAABBBehaviour(Color color) { Color = color; } | ||||||
|  |     public ShapeAABBBehaviour(Color color, float Thickness) { this.Thickness = Thickness; Color = color; } | ||||||
|  | } | ||||||
							
								
								
									
										33
									
								
								Game/Behaviours/ShapeBehaviour.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										33
									
								
								Game/Behaviours/ShapeBehaviour.cs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,33 @@ | |||||||
|  | using Microsoft.Xna.Framework; | ||||||
|  |  | ||||||
|  | using Apos.Shapes; | ||||||
|  |  | ||||||
|  | using Syntriax.Engine.Core.Abstract; | ||||||
|  | using Syntriax.Engine.Physics2D.Primitives; | ||||||
|  |  | ||||||
|  | namespace Pong.Behaviours; | ||||||
|  |  | ||||||
|  | public class ShapeBehaviour : Syntriax.Engine.Physics2D.Collider2DShapeBehaviour, IDisplayableShape | ||||||
|  | { | ||||||
|  |     public Color Color { get; set; } = Color.White; | ||||||
|  |     public float Thickness { get; set; } = .5f; | ||||||
|  |  | ||||||
|  |     public void Draw(ShapeBatch shapeBatch) | ||||||
|  |     { | ||||||
|  |         if (!IsActive) | ||||||
|  |             return; | ||||||
|  |  | ||||||
|  |         Recalculate(); | ||||||
|  |  | ||||||
|  |         int count = ShapeWorld.Vertices.Count; | ||||||
|  |  | ||||||
|  |         for (int i = 0; i < count - 1; i++) | ||||||
|  |             shapeBatch.DrawLine(ShapeWorld[i].ToDisplayVector2(), ShapeWorld[i + 1].ToDisplayVector2(), Thickness, Color, Color); | ||||||
|  |         shapeBatch.DrawLine(ShapeWorld[0].ToDisplayVector2(), ShapeWorld[^1].ToDisplayVector2(), Thickness, Color, Color); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public ShapeBehaviour(Shape shape) : base(shape) { } | ||||||
|  |     public ShapeBehaviour(Shape shape, float thickness) : base(shape) { Thickness = thickness; } | ||||||
|  |     public ShapeBehaviour(Shape shape, Color color) : base(shape) { Color = color; } | ||||||
|  |     public ShapeBehaviour(Shape shape, Color color, float thickness) : base(shape) { Thickness = thickness; Color = color; } | ||||||
|  | } | ||||||
							
								
								
									
										25
									
								
								Game/Behaviours/TextBehaviour.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								Game/Behaviours/TextBehaviour.cs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,25 @@ | |||||||
|  | using Microsoft.Xna.Framework; | ||||||
|  | using Microsoft.Xna.Framework.Graphics; | ||||||
|  |  | ||||||
|  | using Syntriax.Engine.Core; | ||||||
|  | using Syntriax.Engine.Core.Abstract; | ||||||
|  |  | ||||||
|  | namespace Pong.Behaviours; | ||||||
|  |  | ||||||
|  | public class TextBehaviour : BehaviourOverride, IDisplayableSprite | ||||||
|  | { | ||||||
|  |     public SpriteFont? Font { get; set; } = null; | ||||||
|  |     public int Size { get; set; } = 16; | ||||||
|  |     public string Text { get; set; } = string.Empty; | ||||||
|  |  | ||||||
|  |     public void Draw(SpriteBatch spriteBatch) | ||||||
|  |     { | ||||||
|  |         if (!IsActive || Font is null) | ||||||
|  |             return; | ||||||
|  |  | ||||||
|  |         spriteBatch.DrawString(Font, Text, Transform.Position.ToDisplayVector2(), Color.White, Transform.Rotation, Vector2.One * .5f, Transform.Scale.Magnitude, SpriteEffects.None, 0f); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public TextBehaviour() { } | ||||||
|  |     public TextBehaviour(SpriteFont font) => Font = font; | ||||||
|  | } | ||||||
							
								
								
									
										32
									
								
								Game/Behaviours/TextScoreBehaviour.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										32
									
								
								Game/Behaviours/TextScoreBehaviour.cs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,32 @@ | |||||||
|  | using Microsoft.Xna.Framework.Graphics; | ||||||
|  | using Syntriax.Engine.Core; | ||||||
|  |  | ||||||
|  | namespace Pong.Behaviours; | ||||||
|  |  | ||||||
|  | public class TextScoreBehaviour : TextBehaviour | ||||||
|  | { | ||||||
|  |     public bool IsLeft { get; } | ||||||
|  |  | ||||||
|  |     private PongManagerBehaviour? pongManager = null; | ||||||
|  |  | ||||||
|  |     protected override void OnFirstActiveFrame() | ||||||
|  |     { | ||||||
|  |         if (!GameObject.GameManager.TryFindBehaviour(out pongManager)) | ||||||
|  |             return; | ||||||
|  |  | ||||||
|  |         pongManager.OnScoresUpdated += UpdateScores; | ||||||
|  |  | ||||||
|  |         UpdateScores(pongManager); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     private void UpdateScores(PongManagerBehaviour pongManager) | ||||||
|  |     { | ||||||
|  |         if (IsLeft) | ||||||
|  |             Text = pongManager.ScoreLeft.ToString(); | ||||||
|  |         else | ||||||
|  |             Text = pongManager.ScoreRight.ToString(); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public TextScoreBehaviour(bool IsLeft) => this.IsLeft = IsLeft; | ||||||
|  |     public TextScoreBehaviour(bool IsLeft, SpriteFont font) : base(font) => this.IsLeft = IsLeft; | ||||||
|  | } | ||||||
							
								
								
									
										19
									
								
								Game/Behaviours/WallScoreBehaviour.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								Game/Behaviours/WallScoreBehaviour.cs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,19 @@ | |||||||
|  | using System; | ||||||
|  |  | ||||||
|  | using Syntriax.Engine.Core; | ||||||
|  | using Syntriax.Engine.Physics2D.Abstract; | ||||||
|  |  | ||||||
|  | namespace Pong.Behaviours; | ||||||
|  |  | ||||||
|  | public class WallScoreBehaviour(Action OnCollision) : BehaviourOverride | ||||||
|  | { | ||||||
|  |     private Action OnCollision { get; } = OnCollision; | ||||||
|  |  | ||||||
|  |     protected override void OnFirstActiveFrame() | ||||||
|  |     { | ||||||
|  |         if (!BehaviourController.TryGetBehaviour(out ICollider2D? collider2D)) | ||||||
|  |             return; | ||||||
|  |  | ||||||
|  |         collider2D.OnCollisionDetected += (_, _1) => OnCollision?.Invoke(); | ||||||
|  |     } | ||||||
|  | } | ||||||
| @@ -13,35 +13,11 @@ | |||||||
| 
 | 
 | ||||||
| #---------------------------------- Content ---------------------------------# | #---------------------------------- Content ---------------------------------# | ||||||
| 
 | 
 | ||||||
| #begin Audio/Bounce.wav | #begin Hit.wav | ||||||
| /importer:WavImporter | /importer:WavImporter | ||||||
| /processor:SoundEffectProcessor | /processor:SoundEffectProcessor | ||||||
| /processorParam:Quality=Best | /processorParam:Quality=Best | ||||||
| /build:Audio/Bounce.wav | /build:Hit.wav | ||||||
| 
 |  | ||||||
| #begin Audio/Score.wav |  | ||||||
| /importer:WavImporter |  | ||||||
| /processor:SoundEffectProcessor |  | ||||||
| /processorParam:Quality=Best |  | ||||||
| /build:Audio/Score.wav |  | ||||||
| 
 |  | ||||||
| #begin Audio/Win.wav |  | ||||||
| /importer:WavImporter |  | ||||||
| /processor:SoundEffectProcessor |  | ||||||
| /processorParam:Quality=Best |  | ||||||
| /build:Audio/Win.wav |  | ||||||
| 
 |  | ||||||
| #begin Audio/TimerTick.wav |  | ||||||
| /importer:WavImporter |  | ||||||
| /processor:SoundEffectProcessor |  | ||||||
| /processorParam:Quality=Best |  | ||||||
| /build:Audio/TimerTick.wav |  | ||||||
| 
 |  | ||||||
| #begin Audio/TimerEnd.wav |  | ||||||
| /importer:WavImporter |  | ||||||
| /processor:SoundEffectProcessor |  | ||||||
| /processorParam:Quality=Best |  | ||||||
| /build:Audio/TimerEnd.wav |  | ||||||
| 
 | 
 | ||||||
| #begin UbuntuMono.spritefont | #begin UbuntuMono.spritefont | ||||||
| /importer:FontDescriptionImporter | /importer:FontDescriptionImporter | ||||||
							
								
								
									
										
											BIN
										
									
								
								Game/Content/Hit.wav
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								Game/Content/Hit.wav
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										23
									
								
								Game/EngineConverter.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								Game/EngineConverter.cs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,23 @@ | |||||||
|  | using System.Runtime.CompilerServices; | ||||||
|  | using Microsoft.Xna.Framework; | ||||||
|  | using Syntriax.Engine.Core; | ||||||
|  |  | ||||||
|  | namespace Pong; | ||||||
|  |  | ||||||
|  | public static class EngineConverter | ||||||
|  | { | ||||||
|  |     public readonly static Vector2D screenScale = Vector2D.Down + Vector2D.Right; | ||||||
|  |  | ||||||
|  |     [MethodImpl(MethodImplOptions.AggressiveInlining)] | ||||||
|  |     public static EngineTime ToEngineTime(this GameTime gameTime) => new(gameTime.TotalGameTime, gameTime.ElapsedGameTime); | ||||||
|  |     [MethodImpl(MethodImplOptions.AggressiveInlining)] | ||||||
|  |     public static Vector2D ToVector2D(this Vector2 vector) => new(vector.X, vector.Y); | ||||||
|  |     [MethodImpl(MethodImplOptions.AggressiveInlining)] | ||||||
|  |     public static Vector2D ToVector2D(this Point point) => new(point.X, point.Y); | ||||||
|  |     [MethodImpl(MethodImplOptions.AggressiveInlining)] | ||||||
|  |     public static Vector2 ToVector2(this Vector2D vector) => new(vector.X, vector.Y); | ||||||
|  |     [MethodImpl(MethodImplOptions.AggressiveInlining)] | ||||||
|  |     public static Vector2 ToDisplayVector2(this Vector2D vector) => vector.Scale(screenScale).ToVector2(); | ||||||
|  |     [MethodImpl(MethodImplOptions.AggressiveInlining)] | ||||||
|  |     public static Vector2D ApplyDisplayScale(this Vector2D vector) => vector.Scale(screenScale); | ||||||
|  | } | ||||||
							
								
								
									
										37
									
								
								Game/Game.csproj
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										37
									
								
								Game/Game.csproj
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,37 @@ | |||||||
|  | <Project Sdk="Microsoft.NET.Sdk"> | ||||||
|  |   <PropertyGroup> | ||||||
|  |     <OutputType>WinExe</OutputType> | ||||||
|  |     <TargetFramework>net8.0</TargetFramework> | ||||||
|  |     <RollForward>Major</RollForward> | ||||||
|  |     <PublishReadyToRun>false</PublishReadyToRun> | ||||||
|  |     <TieredCompilation>false</TieredCompilation> | ||||||
|  |     <Nullable>enable</Nullable> | ||||||
|  |   </PropertyGroup> | ||||||
|  |   <PropertyGroup> | ||||||
|  |     <ApplicationManifest>app.manifest</ApplicationManifest> | ||||||
|  |     <ApplicationIcon>Icon.ico</ApplicationIcon> | ||||||
|  |   </PropertyGroup> | ||||||
|  |   <ItemGroup> | ||||||
|  |     <None Remove="Icon.ico" /> | ||||||
|  |     <None Remove="Icon.bmp" /> | ||||||
|  |   </ItemGroup> | ||||||
|  |   <ItemGroup> | ||||||
|  |     <EmbeddedResource Include="Icon.ico" /> | ||||||
|  |     <EmbeddedResource Include="Icon.bmp" /> | ||||||
|  |   </ItemGroup> | ||||||
|  |   <ItemGroup> | ||||||
|  |     <PackageReference Include="Apos.Shapes" Version="0.2.3" /> | ||||||
|  |     <PackageReference Include="LiteNetLib" Version="1.2.0" /> | ||||||
|  |     <PackageReference Include="MonoGame.Framework.DesktopGL" Version="3.8.1.303" /> | ||||||
|  |     <PackageReference Include="MonoGame.Content.Builder.Task" Version="3.8.1.303" /> | ||||||
|  |   </ItemGroup> | ||||||
|  |   <ItemGroup> | ||||||
|  |     <ProjectReference Include="..\Engine\Engine.Core\Engine.Core.csproj" /> | ||||||
|  |     <ProjectReference Include="..\Engine\Engine.Input\Engine.Input.csproj" /> | ||||||
|  |     <ProjectReference Include="..\Engine\Engine.Physics2D\Engine.Physics2D.csproj" /> | ||||||
|  |   </ItemGroup> | ||||||
|  |   <Target Name="RestoreDotnetTools" BeforeTargets="Restore"> | ||||||
|  |     <Message Text="Restoring dotnet tools" Importance="High" /> | ||||||
|  |     <Exec Command="dotnet tool restore" /> | ||||||
|  |   </Target> | ||||||
|  | </Project> | ||||||
							
								
								
									
										200
									
								
								Game/GamePong.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										200
									
								
								Game/GamePong.cs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,200 @@ | |||||||
|  | using System; | ||||||
|  |  | ||||||
|  | using Microsoft.Xna.Framework; | ||||||
|  | using Microsoft.Xna.Framework.Graphics; | ||||||
|  | using Microsoft.Xna.Framework.Input; | ||||||
|  |  | ||||||
|  | using Apos.Shapes; | ||||||
|  |  | ||||||
|  | using Pong.Behaviours; | ||||||
|  | using Syntriax.Engine.Network; | ||||||
|  |  | ||||||
|  | using Syntriax.Engine.Core; | ||||||
|  | using Syntriax.Engine.Core.Abstract; | ||||||
|  | using Syntriax.Engine.Physics2D; | ||||||
|  | using Syntriax.Engine.Physics2D.Abstract; | ||||||
|  | using Syntriax.Engine.Physics2D.Primitives; | ||||||
|  |  | ||||||
|  | namespace Pong; | ||||||
|  |  | ||||||
|  | public class GamePong : Game | ||||||
|  | { | ||||||
|  |     private readonly GraphicsDeviceManager graphics = null!; | ||||||
|  |     private IPhysicsEngine2D physicsEngine = null!; | ||||||
|  |     private SpriteBatch spriteBatch = null!; | ||||||
|  |     private ShapeBatch shapeBatch = null!; | ||||||
|  |  | ||||||
|  |     private GameManager gameManager = null!; | ||||||
|  |     private BehaviourCollector<IDisplayableSprite> displayableCollector = null!; | ||||||
|  |     private BehaviourCollector<IDisplayableShape> displayableShapeCollector = null!; | ||||||
|  |     private BehaviourCollector<IMonoGameContentLoader> monoGameContentLoaderCollector = null!; | ||||||
|  |     private MonoGameCamera2DBehaviour cameraBehaviour = null!; | ||||||
|  |  | ||||||
|  |     private PongManagerBehaviour pongManager = null!; | ||||||
|  |  | ||||||
|  |     private float physicsTimer = 0f; | ||||||
|  |  | ||||||
|  |     public GamePong() | ||||||
|  |     { | ||||||
|  |         graphics = new GraphicsDeviceManager(this) | ||||||
|  |         { | ||||||
|  |             PreferredBackBufferWidth = 1024, | ||||||
|  |             PreferredBackBufferHeight = 576, | ||||||
|  |             GraphicsProfile = GraphicsProfile.HiDef | ||||||
|  |         }; | ||||||
|  |  | ||||||
|  |         Content.RootDirectory = "Content"; | ||||||
|  |         IsMouseVisible = true; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     protected override void Initialize() | ||||||
|  |     { | ||||||
|  |         // TODO: Add your initialization logic here | ||||||
|  |         gameManager = new(); | ||||||
|  |         displayableCollector = new(gameManager); | ||||||
|  |         displayableShapeCollector = new(gameManager); | ||||||
|  |         monoGameContentLoaderCollector = new(gameManager); | ||||||
|  |         physicsEngine = new PhysicsEngine2DCollector(gameManager) { IterationPerStep = 3 }; | ||||||
|  |  | ||||||
|  |         monoGameContentLoaderCollector.OnCollected += (_, cached) => cached.LoadContent(Content); | ||||||
|  |  | ||||||
|  |         gameManager.Initialize(); | ||||||
|  |  | ||||||
|  |         base.Initialize(); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     protected override void LoadContent() | ||||||
|  |     { | ||||||
|  |         spriteBatch = new SpriteBatch(GraphicsDevice); | ||||||
|  |         shapeBatch = new ShapeBatch(GraphicsDevice, Content); | ||||||
|  |         SpriteFont spriteFont = Content.Load<SpriteFont>("UbuntuMono"); | ||||||
|  |  | ||||||
|  |         //////////////////////////////////////////////////////////////////////////////////// | ||||||
|  |  | ||||||
|  |         string[] commandLineArguments = Environment.GetCommandLineArgs(); | ||||||
|  |         if (commandLineArguments.Length != 1) | ||||||
|  |         { | ||||||
|  |             if (commandLineArguments[1].Equals("server", StringComparison.OrdinalIgnoreCase)) | ||||||
|  |             { | ||||||
|  |                 gameManager.InstantiateGameObject().BehaviourController.AddBehaviour<NetworkServer>().Start(8888, 2); | ||||||
|  |                 Window.Title = "Pong - Server"; | ||||||
|  |             } | ||||||
|  |             else | ||||||
|  |             { | ||||||
|  |                 Window.Title = $"Pong - Client -> {commandLineArguments[1]}"; | ||||||
|  |                 gameManager.InstantiateGameObject().BehaviourController.AddBehaviour<NetworkClient>().Connect(commandLineArguments[1], 8888); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |         else | ||||||
|  |         { | ||||||
|  |             gameManager.InstantiateGameObject().BehaviourController.AddBehaviour<NetworkClient>().Connect("127.0.0.1", 8888); | ||||||
|  |             Window.Title = $"Pong - Client -> 127.0.0.1"; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         //////////////////////////////////////////////////////////////////////////////////// | ||||||
|  |  | ||||||
|  |         IGameObject gameObjectCamera = gameManager.InstantiateGameObject().SetGameObject("Camera"); ; | ||||||
|  |         gameObjectCamera.BehaviourController.AddBehaviour<CameraController>(); | ||||||
|  |         cameraBehaviour = gameObjectCamera.BehaviourController.AddBehaviour<MonoGameCamera2DBehaviour>(graphics); | ||||||
|  |  | ||||||
|  |         //////////////////////////////////////////////////////////////////////////////////// | ||||||
|  |  | ||||||
|  |         IGameObject gameObjectPongManager = gameManager.InstantiateGameObject().SetGameObject("Pong Game Manager"); | ||||||
|  |         pongManager = gameObjectPongManager.BehaviourController.AddBehaviour<PongManagerBehaviour>(5); | ||||||
|  |         pongManager.Id = "pongManager"; | ||||||
|  |  | ||||||
|  |         //////////////////////////////////////////////////////////////////////////////////// | ||||||
|  |  | ||||||
|  |         IGameObject gameObjectBall = gameManager.InstantiateGameObject().SetGameObject("Ball"); | ||||||
|  |         gameObjectBall.Transform.SetTransform(position: new Vector2D(0, 0f), scale: new Vector2D(10f, 10f)); | ||||||
|  |  | ||||||
|  |         gameObjectBall.BehaviourController.AddBehaviour<CircleBehaviour>(new Circle(Vector2D.Zero, 1f)); | ||||||
|  |         gameObjectBall.BehaviourController.AddBehaviour<BallBehaviour>().Id = "ball"; | ||||||
|  |         gameObjectBall.BehaviourController.AddBehaviour<RigidBody2D>(); | ||||||
|  |  | ||||||
|  |         //////////////////////////////////////////////////////////////////////////////////// | ||||||
|  |  | ||||||
|  |         IGameObject gameObjectLeftPaddle = gameManager.InstantiateGameObject().SetGameObject("Left Paddle"); | ||||||
|  |         gameObjectLeftPaddle.Transform.SetTransform(position: new Vector2D(-468f, 0f), scale: new Vector2D(15f, 60f)); | ||||||
|  |  | ||||||
|  |         gameObjectLeftPaddle.BehaviourController.AddBehaviour<NetworkedKeyboardInputs>().Id = "leftPaddleInput"; | ||||||
|  |         gameObjectLeftPaddle.BehaviourController.AddBehaviour<PaddleBehaviour>(Keys.W, Keys.S, 228f, -228f, 400f).Id = "leftPaddle"; | ||||||
|  |         gameObjectLeftPaddle.BehaviourController.AddBehaviour<ShapeBehaviour>(Shape.Box); | ||||||
|  |         gameObjectLeftPaddle.BehaviourController.AddBehaviour<RigidBody2D>().IsStatic = true; | ||||||
|  |  | ||||||
|  |         IGameObject gameObjectRightPaddle = gameManager.InstantiateGameObject().SetGameObject("Right Paddle"); | ||||||
|  |         gameObjectRightPaddle.Transform.SetTransform(position: new Vector2D(468f, 0f), scale: new Vector2D(15f, 60f)); | ||||||
|  |         gameObjectRightPaddle.BehaviourController.AddBehaviour<NetworkedKeyboardInputs>().Id = "rightPaddleInput"; | ||||||
|  |         gameObjectRightPaddle.BehaviourController.AddBehaviour<PaddleBehaviour>(Keys.Up, Keys.Down, 228f, -228f, 400f).Id = "rightPaddle"; | ||||||
|  |         gameObjectRightPaddle.BehaviourController.AddBehaviour<ShapeBehaviour>(Shape.Box); | ||||||
|  |         gameObjectRightPaddle.BehaviourController.AddBehaviour<RigidBody2D>().IsStatic = true; | ||||||
|  |  | ||||||
|  |         //////////////////////////////////////////////////////////////////////////////////// | ||||||
|  |  | ||||||
|  |         IGameObject gameObjectWallTop = gameManager.InstantiateGameObject().SetGameObject("Wall Top"); | ||||||
|  |         gameObjectWallTop.Transform.SetTransform(position: new Vector2D(0f, 308f), scale: new Vector2D(552f, 20f)); | ||||||
|  |         gameObjectWallTop.BehaviourController.AddBehaviour<ShapeBehaviour>(Shape.Box); | ||||||
|  |         gameObjectWallTop.BehaviourController.AddBehaviour<RigidBody2D>().IsStatic = true; | ||||||
|  |  | ||||||
|  |         IGameObject gameObjectWallBottom = gameManager.InstantiateGameObject().SetGameObject("Wall Bottom"); | ||||||
|  |         gameObjectWallBottom.Transform.SetTransform(position: new Vector2D(0f, -308f), scale: new Vector2D(552f, 20f)); | ||||||
|  |         gameObjectWallBottom.BehaviourController.AddBehaviour<ShapeBehaviour>(Shape.Box); | ||||||
|  |         gameObjectWallBottom.BehaviourController.AddBehaviour<RigidBody2D>().IsStatic = true; | ||||||
|  |  | ||||||
|  |         IGameObject gameObjectWallRight = gameManager.InstantiateGameObject().SetGameObject("Wall Right"); | ||||||
|  |         gameObjectWallRight.Transform.SetTransform(position: new Vector2D(532f, 0f), scale: new Vector2D(20f, 328f)); | ||||||
|  |         gameObjectWallRight.BehaviourController.AddBehaviour<WallScoreBehaviour>((Action)pongManager.ScoreToLeft); | ||||||
|  |         gameObjectWallRight.BehaviourController.AddBehaviour<ShapeBehaviour>(Shape.Box); | ||||||
|  |         gameObjectWallRight.BehaviourController.AddBehaviour<RigidBody2D>().IsStatic = true; | ||||||
|  |  | ||||||
|  |         IGameObject gameObjectWallLeft = gameManager.InstantiateGameObject().SetGameObject("Wall Left"); | ||||||
|  |         gameObjectWallLeft.Transform.SetTransform(position: new Vector2D(-532f, 0f), scale: new Vector2D(20f, 328f)); | ||||||
|  |         gameObjectWallLeft.BehaviourController.AddBehaviour<WallScoreBehaviour>((Action)pongManager.ScoreToRight); | ||||||
|  |         gameObjectWallLeft.BehaviourController.AddBehaviour<ShapeBehaviour>(Shape.Box); | ||||||
|  |         gameObjectWallLeft.BehaviourController.AddBehaviour<RigidBody2D>().IsStatic = true; | ||||||
|  |  | ||||||
|  |         //////////////////////////////////////////////////////////////////////////////////// | ||||||
|  |  | ||||||
|  |         IGameObject gameObjectLeftScoreText = gameManager.InstantiateGameObject().SetGameObject("Score Left"); | ||||||
|  |         gameObjectLeftScoreText.Transform.SetTransform(position: new Vector2D(-250f, 250f), scale: Vector2D.One * .25f); | ||||||
|  |         gameObjectLeftScoreText.BehaviourController.AddBehaviour<TextScoreBehaviour>(true, spriteFont); | ||||||
|  |  | ||||||
|  |         IGameObject gameObjectRightScoreText = gameManager.InstantiateGameObject().SetGameObject("Score Right"); | ||||||
|  |         gameObjectRightScoreText.Transform.SetTransform(position: new Vector2D(250f, 250f), scale: Vector2D.One * .25f); | ||||||
|  |         gameObjectRightScoreText.BehaviourController.AddBehaviour<TextScoreBehaviour>(false, spriteFont); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     protected override void Update(GameTime gameTime) | ||||||
|  |     { | ||||||
|  |         if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed || Keyboard.GetState().IsKeyDown(Keys.Escape)) | ||||||
|  |             Exit(); | ||||||
|  |  | ||||||
|  |         gameManager.Update(gameTime.ToEngineTime()); | ||||||
|  |         while (physicsTimer + 0.01f < gameTime.TotalGameTime.TotalMilliseconds * .001f)//seconds) | ||||||
|  |         { | ||||||
|  |             physicsTimer += 0.01f; | ||||||
|  |             physicsEngine.Step(.01f); | ||||||
|  |         } | ||||||
|  |         base.Update(gameTime); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     protected override void Draw(GameTime gameTime) | ||||||
|  |     { | ||||||
|  |         GraphicsDevice.Clear(new Color() { R = 32, G = 32, B = 32 }); | ||||||
|  |  | ||||||
|  |         // TODO: Add your drawing code here | ||||||
|  |         gameManager.PreDraw(); | ||||||
|  |  | ||||||
|  |         spriteBatch.Begin(SpriteSortMode.Deferred, transformMatrix: cameraBehaviour.MatrixTransform); | ||||||
|  |         foreach (var displayable in displayableCollector) | ||||||
|  |             displayable.Draw(spriteBatch); | ||||||
|  |         spriteBatch.End(); | ||||||
|  |  | ||||||
|  |         shapeBatch.Begin(cameraBehaviour.MatrixTransform); | ||||||
|  |         foreach (var displayableShape in displayableShapeCollector) | ||||||
|  |             displayableShape.Draw(shapeBatch); | ||||||
|  |         shapeBatch.End(); | ||||||
|  |  | ||||||
|  |         base.Draw(gameTime); | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										
											BIN
										
									
								
								Game/Icon.bmp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								Game/Icon.bmp
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| After Width: | Height: | Size: 256 KiB | 
							
								
								
									
										
											BIN
										
									
								
								Game/Icon.ico
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								Game/Icon.ico
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| After Width: | Height: | Size: 144 KiB | 
							
								
								
									
										18
									
								
								Game/Network/Abstract/INetworkBehaviour.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								Game/Network/Abstract/INetworkBehaviour.cs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,18 @@ | |||||||
|  | using Syntriax.Engine.Core.Abstract; | ||||||
|  |  | ||||||
|  | namespace Syntriax.Engine.Network.Abstract; | ||||||
|  |  | ||||||
|  | public interface INetworkBehaviour : IBehaviour | ||||||
|  | { | ||||||
|  |     int NetworkId { get; } | ||||||
|  |  | ||||||
|  |     bool LocalAssigned { get; } | ||||||
|  |  | ||||||
|  |     bool IsServer { get; } | ||||||
|  |     bool IsClient { get; } | ||||||
|  |  | ||||||
|  |     INetworkCommunicator NetworkCommunicator { get; } | ||||||
|  |  | ||||||
|  |     public void RequestAssignment(); | ||||||
|  |     public void ReleaseAssignment(); | ||||||
|  | } | ||||||
							
								
								
									
										6
									
								
								Game/Network/Abstract/INetworkClient.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								Game/Network/Abstract/INetworkClient.cs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,6 @@ | |||||||
|  | namespace Syntriax.Engine.Network.Abstract; | ||||||
|  |  | ||||||
|  | public interface INetworkClient : INetworkCommunicator | ||||||
|  | { | ||||||
|  |     void Connect(string address, int port, string? password = null); | ||||||
|  | } | ||||||
							
								
								
									
										22
									
								
								Game/Network/Abstract/INetworkCommunicator.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								Game/Network/Abstract/INetworkCommunicator.cs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,22 @@ | |||||||
|  | using System; | ||||||
|  |  | ||||||
|  | using LiteNetLib; | ||||||
|  | using LiteNetLib.Utils; | ||||||
|  |  | ||||||
|  | using Syntriax.Engine.Core.Abstract; | ||||||
|  |  | ||||||
|  | namespace Syntriax.Engine.Network.Abstract; | ||||||
|  |  | ||||||
|  | public interface INetworkCommunicator | ||||||
|  | { | ||||||
|  |     EventBasedNetListener Listener { get; } | ||||||
|  |     NetManager Manager { get; } | ||||||
|  |  | ||||||
|  |     void PollEvents(); | ||||||
|  |     void Stop(); | ||||||
|  |  | ||||||
|  |     void RegisterEntityListener(IEntity entity, Action<NetPacketReader, NetPeer> onDataReceived); | ||||||
|  |     void UnregisterEntityListener(IEntity entity); | ||||||
|  |     NetDataWriter GetEntityWriter(IEntity entity); | ||||||
|  |     NetDataWriter GetMessageWriter(IEntity entity); | ||||||
|  | } | ||||||
							
								
								
									
										11
									
								
								Game/Network/Abstract/INetworkEntity.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								Game/Network/Abstract/INetworkEntity.cs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,11 @@ | |||||||
|  | using System; | ||||||
|  |  | ||||||
|  | namespace Syntriax.Engine.Network.Abstract; | ||||||
|  |  | ||||||
|  | internal interface INetworkEntity | ||||||
|  | { | ||||||
|  |     Action<INetworkEntity, int> OnNetworkIdChanged { get; set; } | ||||||
|  |     int NetworkId { get; set; } | ||||||
|  |  | ||||||
|  |     void SetNetworkId(int id); | ||||||
|  | } | ||||||
							
								
								
									
										10
									
								
								Game/Network/Abstract/INetworkManager.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								Game/Network/Abstract/INetworkManager.cs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,10 @@ | |||||||
|  | namespace Syntriax.Engine.Network.Abstract; | ||||||
|  |  | ||||||
|  | public interface INetworkManager | ||||||
|  | { | ||||||
|  |     // Action<IGameObject>? OnNetworkGameObjectInstantiated { get; set; } | ||||||
|  |  | ||||||
|  |     INetworkCommunicator NetworkCommunicator { get; } | ||||||
|  |  | ||||||
|  |     // Task<T> Instantiate<T>(params object?[]? args) where T : class, IGameObject; | ||||||
|  | } | ||||||
							
								
								
									
										10
									
								
								Game/Network/Abstract/INetworkServer.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								Game/Network/Abstract/INetworkServer.cs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,10 @@ | |||||||
|  | namespace Syntriax.Engine.Network.Abstract; | ||||||
|  |  | ||||||
|  | public interface INetworkServer : INetworkCommunicator | ||||||
|  | { | ||||||
|  |     string Password { get; } | ||||||
|  |     int MaxConnectionCount { get; } | ||||||
|  |     int Port { get; } | ||||||
|  |  | ||||||
|  |     void Start(int port, int maxConnectionCount, string? password = null); | ||||||
|  | } | ||||||
							
								
								
									
										81
									
								
								Game/Network/NetworkBase.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										81
									
								
								Game/Network/NetworkBase.cs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,81 @@ | |||||||
|  | using System; | ||||||
|  | using System.Collections.Generic; | ||||||
|  |  | ||||||
|  | using LiteNetLib; | ||||||
|  | using LiteNetLib.Utils; | ||||||
|  |  | ||||||
|  | using Syntriax.Engine.Core; | ||||||
|  | using Syntriax.Engine.Core.Abstract; | ||||||
|  | using Syntriax.Engine.Network.Abstract; | ||||||
|  |  | ||||||
|  | namespace Syntriax.Engine.Network; | ||||||
|  |  | ||||||
|  | public abstract class NetworkBase : BehaviourOverride, INetworkCommunicator | ||||||
|  | { | ||||||
|  |     public EventBasedNetListener Listener { get; private set; } = null!; | ||||||
|  |     public NetManager Manager { get; private set; } = null!; | ||||||
|  |  | ||||||
|  |     public NetworkBase() | ||||||
|  |     { | ||||||
|  |         Priority = 10; | ||||||
|  |  | ||||||
|  |         Listener = new EventBasedNetListener(); | ||||||
|  |         Manager = new NetManager(Listener); | ||||||
|  |  | ||||||
|  |         Listener.NetworkReceiveEvent += NetworkReceiveEvent; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public void PollEvents() => Manager.PollEvents(); | ||||||
|  |     public void Stop() => Manager.Stop(); | ||||||
|  |  | ||||||
|  |     protected override void OnUpdate() => PollEvents(); | ||||||
|  |     protected override void OnFinalize() => Stop(); | ||||||
|  |  | ||||||
|  |     private readonly Dictionary<string, Action<NetPacketReader, NetPeer>> callbacks = new(32); | ||||||
|  |  | ||||||
|  |     private void NetworkReceiveEvent(NetPeer peer, NetPacketReader reader, byte channel, DeliveryMethod deliveryMethod) | ||||||
|  |     { | ||||||
|  |         if (callbacks.TryGetValue(reader.GetString(), out var action)) | ||||||
|  |             action?.Invoke(reader, peer); | ||||||
|  |  | ||||||
|  |         reader.Recycle(); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public void RegisterEntityListener(IEntity entity, Action<NetPacketReader, NetPeer> onDataReceived) | ||||||
|  |     { | ||||||
|  |         if (callbacks.ContainsKey(entity.Id)) | ||||||
|  |             return; | ||||||
|  |  | ||||||
|  |         callbacks.Add(entity.Id, onDataReceived); | ||||||
|  |         entity.OnIdChanged += OnEntityIdChanged; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public void UnregisterEntityListener(IEntity entity) | ||||||
|  |     { | ||||||
|  |         if (!callbacks.Remove(entity.Id)) | ||||||
|  |             return; | ||||||
|  |  | ||||||
|  |         entity.OnIdChanged -= OnEntityIdChanged; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public NetDataWriter GetMessageWriter(IEntity entity) | ||||||
|  |     { | ||||||
|  |         NetDataWriter netDataWriter = GetEntityWriter(entity); | ||||||
|  |         netDataWriter.Put((int)MessageType.Message); | ||||||
|  |         return netDataWriter; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public NetDataWriter GetEntityWriter(IEntity entity) | ||||||
|  |     { | ||||||
|  |         NetDataWriter netDataWriter = new(); | ||||||
|  |         netDataWriter.Put(entity.Id); | ||||||
|  |         return netDataWriter; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     private void OnEntityIdChanged(IEntity entity, string previousId) | ||||||
|  |     { | ||||||
|  |         var action = callbacks[previousId]; | ||||||
|  |         callbacks.Remove(previousId); | ||||||
|  |         callbacks.Add(entity.Id, action); | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										99
									
								
								Game/Network/NetworkBehaviour.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										99
									
								
								Game/Network/NetworkBehaviour.cs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,99 @@ | |||||||
|  | using System; | ||||||
|  |  | ||||||
|  | using LiteNetLib; | ||||||
|  |  | ||||||
|  | using Syntriax.Engine.Core; | ||||||
|  | using Syntriax.Engine.Network.Abstract; | ||||||
|  |  | ||||||
|  | namespace Syntriax.Engine.Network; | ||||||
|  |  | ||||||
|  | public abstract class NetworkBehaviour : BehaviourOverride, INetworkBehaviour | ||||||
|  | { | ||||||
|  |     public int NetworkId { get; private set; } = 0; | ||||||
|  |  | ||||||
|  |     public bool LocalAssigned { get; private set; } = false; | ||||||
|  |  | ||||||
|  |     public bool IsServer { get; private set; } = false; | ||||||
|  |     public bool IsClient { get; private set; } = false; | ||||||
|  |  | ||||||
|  |     public INetworkCommunicator NetworkCommunicator { get; private set; } = null!; | ||||||
|  |  | ||||||
|  |     protected override void OnInitialize() | ||||||
|  |     { | ||||||
|  |         NetworkCommunicator = BehaviourController.GetBehaviourInParent<INetworkCommunicator>() | ||||||
|  |                               ?? GameObject.GameManager.FindBehaviour<INetworkCommunicator>() | ||||||
|  |                               ?? throw new Exception($"Could not find an {nameof(INetworkCommunicator)}."); | ||||||
|  |  | ||||||
|  |         NetworkCommunicator.RegisterEntityListener(this, OnMessageReceivedInternal); | ||||||
|  |  | ||||||
|  |         if (NetworkCommunicator is INetworkClient client) | ||||||
|  |         { | ||||||
|  |             IsClient = true; | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         IsServer = true; | ||||||
|  |         LocalAssigned = true; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public void ReleaseAssignment() | ||||||
|  |     { | ||||||
|  |         if (IsServer) | ||||||
|  |             return; | ||||||
|  |  | ||||||
|  |         var netDataWriter = NetworkCommunicator.GetEntityWriter(this); | ||||||
|  |         netDataWriter.Put((int)MessageType.AssignmentRelease); | ||||||
|  |         NetworkCommunicator.Manager.SendToAll(netDataWriter, DeliveryMethod.ReliableOrdered); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public void RequestAssignment() | ||||||
|  |     { | ||||||
|  |         if (IsServer) | ||||||
|  |             return; | ||||||
|  |  | ||||||
|  |         var netDataWriter = NetworkCommunicator.GetEntityWriter(this); | ||||||
|  |         netDataWriter.Put((int)MessageType.AssignmentRequest); | ||||||
|  |         NetworkCommunicator.Manager.SendToAll(netDataWriter, DeliveryMethod.ReliableOrdered); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     protected abstract void OnMessageReceived(NetPacketReader reader, NetPeer peer); | ||||||
|  |     private void OnMessageReceivedInternal(NetPacketReader reader, NetPeer peer) | ||||||
|  |     { | ||||||
|  |         MessageType messageType = (MessageType)reader.GetInt(); | ||||||
|  |  | ||||||
|  |         if (IsServer) | ||||||
|  |         { | ||||||
|  |             switch (messageType) | ||||||
|  |             { | ||||||
|  |                 case MessageType.Message: OnMessageReceived(reader, peer); break; | ||||||
|  |                 case MessageType.AssignmentRequest: | ||||||
|  |                 case MessageType.AssignmentRelease: | ||||||
|  |                     var netDataWriter = NetworkCommunicator.GetEntityWriter(this); | ||||||
|  |                     netDataWriter.Put((int)(messageType == MessageType.AssignmentRequest ? MessageType.Assigned : MessageType.Unassigned)); | ||||||
|  |                     peer.Send(netDataWriter, DeliveryMethod.ReliableOrdered); | ||||||
|  |                     break; | ||||||
|  |                 default: | ||||||
|  |                     break; | ||||||
|  |             } | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         switch (messageType) | ||||||
|  |         { | ||||||
|  |             case MessageType.Message: OnMessageReceived(reader, peer); break; | ||||||
|  |             case MessageType.Assigned: LocalAssigned = true; break; | ||||||
|  |             case MessageType.Unassigned: LocalAssigned = false; break; | ||||||
|  |             default: | ||||||
|  |                 break; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | internal enum MessageType | ||||||
|  | { | ||||||
|  |     Message, | ||||||
|  |     AssignmentRequest, | ||||||
|  |     AssignmentRelease, | ||||||
|  |     Assigned, | ||||||
|  |     Unassigned, | ||||||
|  | } | ||||||
							
								
								
									
										12
									
								
								Game/Network/NetworkClient.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								Game/Network/NetworkClient.cs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,12 @@ | |||||||
|  | using Syntriax.Engine.Network.Abstract; | ||||||
|  |  | ||||||
|  | namespace Syntriax.Engine.Network; | ||||||
|  |  | ||||||
|  | public class NetworkClient : NetworkBase, INetworkClient | ||||||
|  | { | ||||||
|  |     public void Connect(string address, int port, string? password = null) | ||||||
|  |     { | ||||||
|  |         Manager.Start(); | ||||||
|  |         Manager.Connect(address, port, password ?? string.Empty); | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										20
									
								
								Game/Network/NetworkExtensions.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								Game/Network/NetworkExtensions.cs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,20 @@ | |||||||
|  | using LiteNetLib; | ||||||
|  | using LiteNetLib.Utils; | ||||||
|  |  | ||||||
|  | using Syntriax.Engine.Core; | ||||||
|  |  | ||||||
|  | namespace Syntriax.Engine.Network; | ||||||
|  |  | ||||||
|  | public static class NetworkExtensions | ||||||
|  | { | ||||||
|  |     public static Vector2D GetVector2D(this NetPacketReader reader) | ||||||
|  |         => new(reader.GetFloat(), reader.GetFloat()); | ||||||
|  |     public static void GetVector2D(this NetPacketReader reader, out Vector2D vector2D) | ||||||
|  |         => vector2D = new(reader.GetFloat(), reader.GetFloat()); | ||||||
|  |  | ||||||
|  |     public static void Put(this NetDataWriter writer, Vector2D vector) | ||||||
|  |     { | ||||||
|  |         writer.Put(vector.X); | ||||||
|  |         writer.Put(vector.Y); | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										31
									
								
								Game/Network/NetworkManager.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										31
									
								
								Game/Network/NetworkManager.cs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,31 @@ | |||||||
|  | using LiteNetLib; | ||||||
|  | using Syntriax.Engine.Core; | ||||||
|  |  | ||||||
|  | using Syntriax.Engine.Network.Abstract; | ||||||
|  |  | ||||||
|  | namespace Syntriax.Engine.Network; | ||||||
|  |  | ||||||
|  | public class NetworkManager : NetworkBehaviour, INetworkManager | ||||||
|  | { | ||||||
|  |     private BehaviourCollector<INetworkEntity> entities = null!; | ||||||
|  |  | ||||||
|  |     private static int networkIdIndex = 0; | ||||||
|  |  | ||||||
|  |     protected override void OnInitialize() | ||||||
|  |     { | ||||||
|  |         base.OnInitialize(); | ||||||
|  |  | ||||||
|  |         ((INetworkEntity)this).SetNetworkId(networkIdIndex++); | ||||||
|  |  | ||||||
|  |         entities = new(GameObject.GameManager); | ||||||
|  |         foreach (var entity in entities) | ||||||
|  |             entity.SetNetworkId(networkIdIndex++); | ||||||
|  |  | ||||||
|  |         entities.OnCollected += OnCollected; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     private void OnCollected(BehaviourCollector<INetworkEntity> collector, INetworkEntity entity) | ||||||
|  |         => entity.SetNetworkId(networkIdIndex++); | ||||||
|  |  | ||||||
|  |     protected override void OnMessageReceived(NetPacketReader reader, NetPeer peer) { } | ||||||
|  | } | ||||||
							
								
								
									
										30
									
								
								Game/Network/NetworkServer.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										30
									
								
								Game/Network/NetworkServer.cs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,30 @@ | |||||||
|  | using Syntriax.Engine.Network.Abstract; | ||||||
|  |  | ||||||
|  | namespace Syntriax.Engine.Network; | ||||||
|  |  | ||||||
|  | public class NetworkServer : NetworkBase, INetworkServer | ||||||
|  | { | ||||||
|  |     public string Password { get; private set; } = string.Empty; | ||||||
|  |     public int MaxConnectionCount { get; private set; } = 0; | ||||||
|  |     public int Port { get; private set; } = 8888; | ||||||
|  |  | ||||||
|  |     public NetworkServer() : base() | ||||||
|  |     { | ||||||
|  |         Listener.ConnectionRequestEvent += request => | ||||||
|  |         { | ||||||
|  |             if (Manager.ConnectedPeersCount < MaxConnectionCount) | ||||||
|  |                 request.AcceptIfKey(Password); | ||||||
|  |             else | ||||||
|  |                 request.Reject(); | ||||||
|  |         }; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public void Start(int port, int maxConnectionCount, string? password = null) | ||||||
|  |     { | ||||||
|  |         Password = password ?? string.Empty; | ||||||
|  |         MaxConnectionCount = maxConnectionCount; | ||||||
|  |         Port = port; | ||||||
|  |  | ||||||
|  |         Manager.Start(port); | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										3
									
								
								Game/Program.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								Game/Program.cs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,3 @@ | |||||||
|  |  | ||||||
|  | using var game = new Pong.GamePong(); | ||||||
|  | game.Run(); | ||||||
| @@ -1,6 +1,6 @@ | |||||||
| <?xml version="1.0" encoding="utf-8"?> | <?xml version="1.0" encoding="utf-8"?> | ||||||
| <assembly manifestVersion="1.0" xmlns="urn:schemas-microsoft-com:asm.v1"> | <assembly manifestVersion="1.0" xmlns="urn:schemas-microsoft-com:asm.v1"> | ||||||
|   <assemblyIdentity version="1.0.0.0" name="Desktop"/> |   <assemblyIdentity version="1.0.0.0" name="Game"/> | ||||||
|   <trustInfo xmlns="urn:schemas-microsoft-com:asm.v2"> |   <trustInfo xmlns="urn:schemas-microsoft-com:asm.v2"> | ||||||
|     <security> |     <security> | ||||||
|       <requestedPrivileges xmlns="urn:schemas-microsoft-com:asm.v3"> |       <requestedPrivileges xmlns="urn:schemas-microsoft-com:asm.v3"> | ||||||
| @@ -1,11 +0,0 @@ | |||||||
| public class ClientConfiguration |  | ||||||
| { |  | ||||||
|     public bool Host = false; |  | ||||||
|     public int HostPort = 8888; |  | ||||||
|  |  | ||||||
|     public string ServerAddress = "localhost"; |  | ||||||
|     public int ServerPort = 8888; |  | ||||||
|  |  | ||||||
|     public int windowWidth = 1024; |  | ||||||
|     public int windowHeight = 576; |  | ||||||
| } |  | ||||||
| @@ -1,15 +0,0 @@ | |||||||
|  |  | ||||||
| #----------------------------- Global Properties ----------------------------# |  | ||||||
|  |  | ||||||
| /outputDir:bin/$(Platform) |  | ||||||
| /intermediateDir:obj/$(Platform) |  | ||||||
| /platform:DesktopGL |  | ||||||
| /config: |  | ||||||
| /profile:Reach |  | ||||||
| /compress:False |  | ||||||
|  |  | ||||||
| #-------------------------------- References --------------------------------# |  | ||||||
|  |  | ||||||
|  |  | ||||||
| #---------------------------------- Content ---------------------------------# |  | ||||||
|  |  | ||||||
| @@ -1,90 +0,0 @@ | |||||||
| <Project Sdk="Microsoft.NET.Sdk"> |  | ||||||
|   <PropertyGroup> |  | ||||||
|     <OutputType>WinExe</OutputType> |  | ||||||
|     <TargetFramework>net9.0</TargetFramework> |  | ||||||
|     <RollForward>Major</RollForward> |  | ||||||
|     <PublishReadyToRun>false</PublishReadyToRun> |  | ||||||
|     <TieredCompilation>false</TieredCompilation> |  | ||||||
|     <Nullable>enable</Nullable> |  | ||||||
|     <RootNamespace>Pong.Platforms.Desktop</RootNamespace> |  | ||||||
|     <AssemblyName>Pong</AssemblyName> |  | ||||||
|   </PropertyGroup> |  | ||||||
|   <PropertyGroup> |  | ||||||
|     <ApplicationManifest>app.manifest</ApplicationManifest> |  | ||||||
|     <ApplicationIcon>Icon.ico</ApplicationIcon> |  | ||||||
|   </PropertyGroup> |  | ||||||
|   <ItemGroup> |  | ||||||
|     <None Remove="Icon.ico" /> |  | ||||||
|     <None Remove="Icon.bmp" /> |  | ||||||
|   </ItemGroup> |  | ||||||
|   <ItemGroup> |  | ||||||
|     <EmbeddedResource Include="Icon.ico"> |  | ||||||
|       <LogicalName>Icon.ico</LogicalName> |  | ||||||
|     </EmbeddedResource> |  | ||||||
|     <EmbeddedResource Include="Icon.bmp"> |  | ||||||
|       <LogicalName>Icon.bmp</LogicalName> |  | ||||||
|     </EmbeddedResource> |  | ||||||
|   </ItemGroup> |  | ||||||
|   <ItemGroup> |  | ||||||
|     <PackageReference Include="MonoGame.Framework.DesktopGL" Version="3.8.2.1105" /> |  | ||||||
|     <PackageReference Include="MonoGame.Content.Builder.Task" Version="3.8.2.1105" /> |  | ||||||
|     <PackageReference Include="nulastudio.NetBeauty" Version="2.1.5" /> |  | ||||||
|   </ItemGroup> |  | ||||||
|   <ItemGroup> |  | ||||||
|     <ProjectReference Include="../../Shared/Shared.csproj" /> |  | ||||||
|   </ItemGroup> |  | ||||||
|  |  | ||||||
|   <ItemGroup> |  | ||||||
|     <MonoGameContentReference Include="../../Shared/Content/Content.mgcb"> |  | ||||||
|       <Link>Content/Content.mgcb</Link> |  | ||||||
|     </MonoGameContentReference> |  | ||||||
|   </ItemGroup> |  | ||||||
|   <ItemGroup> |  | ||||||
|     <ProjectReference Include="../../Shared/Shared.csproj" /> |  | ||||||
|     <ProjectReference Include="..\..\Engine\Engine.Integration\Engine.Integration.Yaml\Engine.Integration.Yaml.csproj" /> |  | ||||||
|   </ItemGroup> |  | ||||||
|   <Target Name="RestoreDotnetTools" BeforeTargets="Restore"> |  | ||||||
|     <Message Text="Restoring dotnet tools" Importance="High" /> |  | ||||||
|     <Exec Command="dotnet tool restore" /> |  | ||||||
|   </Target> |  | ||||||
|  |  | ||||||
|   <PropertyGroup> |  | ||||||
|     <BeautySharedRuntimeMode>False</BeautySharedRuntimeMode> |  | ||||||
|     <!-- beauty into sub-directory, default is libs, quote with "" if contains space  --> |  | ||||||
|     <BeautyLibsDir Condition="$(BeautySharedRuntimeMode) == 'True'">../Libraries</BeautyLibsDir> |  | ||||||
|     <BeautyLibsDir Condition="$(BeautySharedRuntimeMode) != 'True'">./Libraries</BeautyLibsDir> |  | ||||||
|     <!-- dlls that you don't want to be moved or can not be moved --> |  | ||||||
|     <!-- <BeautyExcludes>dll1.dll;lib*;...</BeautyExcludes> --> |  | ||||||
|     <BeautyExcludes>SDL2.dll</BeautyExcludes> |  | ||||||
|     <!-- dlls that end users never needed, so hide them --> |  | ||||||
|     <BeautyHiddens>hostfxr;hostpolicy;*.deps.json;*.runtimeconfig*.json</BeautyHiddens> |  | ||||||
|     <!-- set to True if you want to disable --> |  | ||||||
|     <DisableBeauty>False</DisableBeauty> |  | ||||||
|     <!-- set to False if you want to beauty on build --> |  | ||||||
|     <BeautyOnPublishOnly>False</BeautyOnPublishOnly> |  | ||||||
|     <!-- DO NOT TOUCH THIS OPTION --> |  | ||||||
|     <BeautyNoRuntimeInfo>False</BeautyNoRuntimeInfo> |  | ||||||
|     <!-- valid values: auto|with|without --> |  | ||||||
|     <BeautyNBLoaderVerPolicy>auto</BeautyNBLoaderVerPolicy> |  | ||||||
|     <!-- set to True if you want to allow 3rd debuggers(like dnSpy) debugs the app --> |  | ||||||
|     <BeautyEnableDebugging>False</BeautyEnableDebugging> |  | ||||||
|     <!-- the patch can reduce the file count --> |  | ||||||
|     <!-- set to False if you want to disable --> |  | ||||||
|     <!-- SCD Mode Feature Only --> |  | ||||||
|     <BeautyUsePatch>True</BeautyUsePatch> |  | ||||||
|     <!-- App Entry Dll = BeautyDir + BeautyAppHostDir + BeautyAppHostEntry --> |  | ||||||
|     <!-- see https://github.com/nulastudio/NetBeauty2#customize-apphost for more details --> |  | ||||||
|     <!-- relative path based on AppHostDir --> |  | ||||||
|     <!-- .NET Core Non Single-File Only --> |  | ||||||
|     <!-- <BeautyAppHostEntry>bin/MyApp.dll</BeautyAppHostEntry> --> |  | ||||||
|     <!-- relative path based on BeautyDir --> |  | ||||||
|     <!-- .NET Core Non Single-File Only --> |  | ||||||
|     <!-- <BeautyAppHostDir>..</BeautyAppHostDir> --> |  | ||||||
|     <!-- <BeautyAfterTasks></BeautyAfterTasks> --> |  | ||||||
|     <!-- valid values: Error|Detail|Info --> |  | ||||||
|     <BeautyLogLevel>Info</BeautyLogLevel> |  | ||||||
|     <!-- set to a repo mirror if you have troble in connecting github --> |  | ||||||
|     <!-- <BeautyGitCDN>https://gitee.com/liesauer/HostFXRPatcher</BeautyGitCDN> --> |  | ||||||
|     <!-- <BeautyGitTree>master</BeautyGitTree> --> |  | ||||||
|   </PropertyGroup> |  | ||||||
| </Project> |  | ||||||
										
											Binary file not shown.
										
									
								
							| Before Width: | Height: | Size: 192 KiB | 
										
											Binary file not shown.
										
									
								
							| Before Width: | Height: | Size: 7.2 KiB | 
										
											Binary file not shown.
										
									
								
							| Before Width: | Height: | Size: 7.2 KiB | 
| @@ -1,74 +0,0 @@ | |||||||
| using System; |  | ||||||
| using System.IO; |  | ||||||
|  |  | ||||||
| using Microsoft.Xna.Framework.Graphics; |  | ||||||
|  |  | ||||||
| using Engine.Core; |  | ||||||
| using Engine.Core.Debug; |  | ||||||
| using Engine.Core.Serialization; |  | ||||||
| using Engine.Integration.MonoGame; |  | ||||||
| using Engine.Serializers.Yaml; |  | ||||||
|  |  | ||||||
| Universe universe = new(); |  | ||||||
|  |  | ||||||
| ISerializer serializer = new YamlSerializer(); |  | ||||||
|  |  | ||||||
| ILogger logger = new FileLogger($"Logs/{DateTime.UtcNow:yyyy-MM-dd_HH-mm-ss-ffffff}.log"); |  | ||||||
|  |  | ||||||
| #if DEBUG |  | ||||||
| logger = new LoggerWrapper(logger, new ConsoleLogger()); |  | ||||||
| #endif |  | ||||||
|  |  | ||||||
| universe.InstantiateUniverseObject().SetUniverseObject("Logger").BehaviourController.AddBehaviour<LoggerContainer>().Logger = ILogger.Shared = logger; |  | ||||||
|  |  | ||||||
| string settingsPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "settings.yaml"); |  | ||||||
| ClientConfiguration clientConfiguration = GetOrCreateConfiguration(serializer, logger, settingsPath); |  | ||||||
|  |  | ||||||
| if (clientConfiguration.Host) |  | ||||||
|     Pong.PongUniverse.ApplyPongServer(universe, clientConfiguration.HostPort); |  | ||||||
|  |  | ||||||
| Pong.PongUniverse.ApplyPongClient(universe, clientConfiguration.ServerAddress, clientConfiguration.ServerPort); |  | ||||||
| Pong.PongUniverse.ApplyPongUniverse(universe); |  | ||||||
|  |  | ||||||
| universe.InstantiateUniverseObject().SetUniverseObject("Desktop HO") |  | ||||||
|     .BehaviourController.AddBehaviour<KeyboardInputs>(); |  | ||||||
|  |  | ||||||
| using MonoGameWindow monoGameWindow = new(universe); |  | ||||||
|  |  | ||||||
| monoGameWindow.Graphics.PreferredBackBufferWidth = clientConfiguration.windowWidth; |  | ||||||
| monoGameWindow.Graphics.PreferredBackBufferHeight = clientConfiguration.windowHeight; |  | ||||||
| monoGameWindow.Graphics.GraphicsProfile = GraphicsProfile.HiDef; |  | ||||||
|  |  | ||||||
| universe.FindBehaviour<Engine.Systems.Network.INetworkCommunicatorClient>()? |  | ||||||
|     .OnConnectionEstablished.AddOneTimeListener( |  | ||||||
|         (sender, connection) => monoGameWindow.Window.Title = $"Client {connection.Id}" |  | ||||||
|     ); |  | ||||||
|  |  | ||||||
| monoGameWindow.Run(); |  | ||||||
|  |  | ||||||
| static ClientConfiguration GetOrCreateConfiguration(ISerializer serializer, ILogger logger, string settingsPath) |  | ||||||
| { |  | ||||||
|     ClientConfiguration clientConfiguration; |  | ||||||
|  |  | ||||||
|     try |  | ||||||
|     { |  | ||||||
|         clientConfiguration = serializer.Deserialize<ClientConfiguration>(File.ReadAllText(settingsPath)); |  | ||||||
|         logger.Log(clientConfiguration, $"Configuration is successfully read"); |  | ||||||
|     } |  | ||||||
|     catch (FileNotFoundException) |  | ||||||
|     { |  | ||||||
|         clientConfiguration = new(); |  | ||||||
|         logger.Log(clientConfiguration, $"Configuration does not exist"); |  | ||||||
|         File.WriteAllText(settingsPath, serializer.Serialize(clientConfiguration)); |  | ||||||
|     } |  | ||||||
|     catch (Exception exception) |  | ||||||
|     { |  | ||||||
|         clientConfiguration = new(); |  | ||||||
|         logger.LogError(clientConfiguration, $"Error loading configuration"); |  | ||||||
|         logger.LogException(clientConfiguration, exception); |  | ||||||
|         File.WriteAllText(settingsPath, serializer.Serialize(clientConfiguration)); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     logger.Log(clientConfiguration, $"Creating new configuration file at {settingsPath}"); |  | ||||||
|     return clientConfiguration; |  | ||||||
| } |  | ||||||
| @@ -1,131 +0,0 @@ | |||||||
| <?xml version="1.0" encoding="UTF-8" standalone="no"?> |  | ||||||
| <!-- Created with Inkscape (http://www.inkscape.org/) --> |  | ||||||
|  |  | ||||||
| <svg |  | ||||||
|    width="100mm" |  | ||||||
|    height="100mm" |  | ||||||
|    viewBox="0 0 100 100" |  | ||||||
|    version="1.1" |  | ||||||
|    id="svg5" |  | ||||||
|    inkscape:version="1.2.2 (b0a8486541, 2022-12-01)" |  | ||||||
|    sodipodi:docname="icon.svg" |  | ||||||
|    inkscape:export-filename="Icon.png" |  | ||||||
|    inkscape:export-xdpi="65.024002" |  | ||||||
|    inkscape:export-ydpi="65.024002" |  | ||||||
|    xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" |  | ||||||
|    xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" |  | ||||||
|    xmlns="http://www.w3.org/2000/svg" |  | ||||||
|    xmlns:svg="http://www.w3.org/2000/svg"> |  | ||||||
|   <sodipodi:namedview |  | ||||||
|      id="namedview7" |  | ||||||
|      pagecolor="#505050" |  | ||||||
|      bordercolor="#eeeeee" |  | ||||||
|      borderopacity="1" |  | ||||||
|      inkscape:showpageshadow="0" |  | ||||||
|      inkscape:pageopacity="0" |  | ||||||
|      inkscape:pagecheckerboard="0" |  | ||||||
|      inkscape:deskcolor="#505050" |  | ||||||
|      inkscape:document-units="mm" |  | ||||||
|      showgrid="false" |  | ||||||
|      inkscape:zoom="0.76791526" |  | ||||||
|      inkscape:cx="-14.975611" |  | ||||||
|      inkscape:cy="272.16545" |  | ||||||
|      inkscape:window-width="1920" |  | ||||||
|      inkscape:window-height="1008" |  | ||||||
|      inkscape:window-x="0" |  | ||||||
|      inkscape:window-y="36" |  | ||||||
|      inkscape:window-maximized="1" |  | ||||||
|      inkscape:current-layer="layer1" /> |  | ||||||
|   <defs |  | ||||||
|      id="defs2"> |  | ||||||
|     <inkscape:path-effect |  | ||||||
|        effect="taper_stroke" |  | ||||||
|        id="path-effect1965" |  | ||||||
|        is_visible="true" |  | ||||||
|        lpeversion="1" |  | ||||||
|        stroke_width="14.57" |  | ||||||
|        attach_start="0.99999" |  | ||||||
|        end_offset="1e-07" |  | ||||||
|        start_smoothing="0" |  | ||||||
|        end_smoothing="0" |  | ||||||
|        jointype="extrapolated" |  | ||||||
|        start_shape="center" |  | ||||||
|        end_shape="center" |  | ||||||
|        miter_limit="1000.5" /> |  | ||||||
|     <inkscape:path-effect |  | ||||||
|        effect="join_type" |  | ||||||
|        id="path-effect1959" |  | ||||||
|        is_visible="true" |  | ||||||
|        lpeversion="1" |  | ||||||
|        linecap_type="square" |  | ||||||
|        line_width="0.26458299" |  | ||||||
|        linejoin_type="extrp_arc" |  | ||||||
|        miter_limit="100" |  | ||||||
|        attempt_force_join="true" /> |  | ||||||
|     <inkscape:path-effect |  | ||||||
|        effect="powerstroke" |  | ||||||
|        id="path-effect1957" |  | ||||||
|        is_visible="true" |  | ||||||
|        lpeversion="1" |  | ||||||
|        offset_points="0.2,0.1322915 | 1,0.1322915 | 1.8,0.1322915" |  | ||||||
|        not_jump="false" |  | ||||||
|        sort_points="true" |  | ||||||
|        interpolator_type="Linear" |  | ||||||
|        interpolator_beta="1" |  | ||||||
|        start_linecap_type="zerowidth" |  | ||||||
|        linejoin_type="miter" |  | ||||||
|        miter_limit="11100" |  | ||||||
|        scale_width="20" |  | ||||||
|        end_linecap_type="butt" /> |  | ||||||
|     <inkscape:path-effect |  | ||||||
|        effect="fill_between_many" |  | ||||||
|        method="bsplinespiro" |  | ||||||
|        linkedpaths="#path1175,0,1" |  | ||||||
|        id="path-effect1961" |  | ||||||
|        is_visible="true" |  | ||||||
|        lpeversion="0" |  | ||||||
|        join="true" |  | ||||||
|        close="true" |  | ||||||
|        autoreverse="true" /> |  | ||||||
|     <inkscape:path-effect |  | ||||||
|        effect="fill_between_many" |  | ||||||
|        method="bsplinespiro" |  | ||||||
|        linkedpaths="#path1175,0,1" |  | ||||||
|        id="path-effect1967" |  | ||||||
|        is_visible="true" |  | ||||||
|        lpeversion="0" |  | ||||||
|        join="true" |  | ||||||
|        close="true" |  | ||||||
|        autoreverse="true" /> |  | ||||||
|   </defs> |  | ||||||
|   <g |  | ||||||
|      inkscape:label="Layer 1" |  | ||||||
|      inkscape:groupmode="layer" |  | ||||||
|      id="layer1"> |  | ||||||
|     <rect |  | ||||||
|        style="fill:#25202c;fill-opacity:1;stroke:none;stroke-width:0.264583;stroke-linecap:square;stroke-linejoin:bevel;stroke-opacity:1;paint-order:fill markers stroke" |  | ||||||
|        id="rect4712" |  | ||||||
|        width="100" |  | ||||||
|        height="100" |  | ||||||
|        x="0" |  | ||||||
|        y="0" |  | ||||||
|        ry="24.342688" /> |  | ||||||
|     <circle |  | ||||||
|        style="fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:0.296213;stroke-linecap:square;stroke-linejoin:bevel;paint-order:fill markers stroke" |  | ||||||
|        id="path234" |  | ||||||
|        cx="32.183838" |  | ||||||
|        cy="37.277283" |  | ||||||
|        r="11.198684" /> |  | ||||||
|     <rect |  | ||||||
|        style="fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:0.296213;stroke-linecap:square;stroke-linejoin:bevel;paint-order:fill markers stroke" |  | ||||||
|        id="rect1054" |  | ||||||
|        width="19.398724" |  | ||||||
|        height="71.576004" |  | ||||||
|        x="59.616123" |  | ||||||
|        y="14.211996" /> |  | ||||||
|     <path |  | ||||||
|        id="path1175" |  | ||||||
|        style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:4.31583;stroke-linecap:square;stroke-linejoin:bevel;stroke-opacity:1;paint-order:fill markers stroke" |  | ||||||
|        d="m 45.710924,37.909235 c -0.08308,1.7843 -0.506133,3.552079 -1.278577,5.16464 -1.067261,2.404981 -2.906892,4.366553 -5.129349,5.714834 l 10.696654,4.40096 -13.418115,24.765056 21.254461,-19.595787 c 5.44e-4,-4.297076 -4.96e-4,-8.593943 5.78e-4,-12.891057 z" /> |  | ||||||
|   </g> |  | ||||||
| </svg> |  | ||||||
| Before Width: | Height: | Size: 4.2 KiB | 
| @@ -1,39 +0,0 @@ | |||||||
| using System; |  | ||||||
| using System.Threading.Tasks; |  | ||||||
|  |  | ||||||
| using Microsoft.AspNetCore.Builder; |  | ||||||
| using Microsoft.AspNetCore.Http; |  | ||||||
| using Microsoft.Extensions.DependencyInjection; |  | ||||||
|  |  | ||||||
| using Engine.Core; |  | ||||||
| using Engine.Systems.Network; |  | ||||||
|  |  | ||||||
| namespace Server; |  | ||||||
|  |  | ||||||
| public class PongEndpoints : Behaviour, IFirstFrameUpdate |  | ||||||
| { |  | ||||||
|     private INetworkCommunicatorServer? server = null!; |  | ||||||
|  |  | ||||||
|     public PongEndpoints() |  | ||||||
|     { |  | ||||||
|         Task.Run(() => |  | ||||||
|         { |  | ||||||
|             WebApplicationBuilder builder = WebApplication.CreateBuilder(); |  | ||||||
|  |  | ||||||
|             builder.Services.AddHealthChecks(); |  | ||||||
|  |  | ||||||
|             WebApplication app = builder.Build(); |  | ||||||
|  |  | ||||||
|             app.MapHealthChecks("/health"); |  | ||||||
|  |  | ||||||
|             app.MapGet("/stats", GetStats); |  | ||||||
|  |  | ||||||
|             app.Run($"http://0.0.0.0:{Environment.GetEnvironmentVariable("PORT") ?? "8888"}"); |  | ||||||
|         }); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     private IResult GetStats() => Results.Json(new { Count = server?.Connections.Count ?? 0 }); |  | ||||||
|  |  | ||||||
|     public void FirstActiveFrame() => server = Universe.FindRequiredBehaviour<INetworkCommunicatorServer>(); |  | ||||||
|     protected override void OnExitedUniverse(IUniverse universe) => server = null; |  | ||||||
| } |  | ||||||
| @@ -1,34 +0,0 @@ | |||||||
| using System; |  | ||||||
| using System.Threading; |  | ||||||
|  |  | ||||||
| using Engine.Core; |  | ||||||
| using Engine.Core.Debug; |  | ||||||
|  |  | ||||||
| Universe universe = new(); |  | ||||||
|  |  | ||||||
| FileLogger fileLogger = new($"Logs/{DateTime.UtcNow:yyyy-MM-dd_HH-mm-ss-ffffff}.log"); |  | ||||||
| universe.InstantiateUniverseObject().SetUniverseObject("Logger").BehaviourController |  | ||||||
|     .AddBehaviour<LoggerContainer>().Logger = ILogger.Shared = new LoggerWrapper(fileLogger, new ConsoleLogger()); |  | ||||||
|  |  | ||||||
| Pong.PongUniverse.ApplyPongServer(universe, int.Parse(Environment.GetEnvironmentVariable("PORT") ?? "8888")); |  | ||||||
| Pong.PongUniverse.ApplyPongUniverse(universe); |  | ||||||
|  |  | ||||||
| universe.InstantiateUniverseObject().SetUniverseObject("Endpoints").BehaviourController |  | ||||||
|     .AddBehaviour<Server.PongEndpoints>(); |  | ||||||
|  |  | ||||||
| DateTime lastRun = DateTime.UtcNow; |  | ||||||
| TimeSpan interval = new(0, 0, 0, 0, 16); |  | ||||||
| TimeSpan timeSinceStart = new(0); |  | ||||||
|  |  | ||||||
| universe.Initialize(); |  | ||||||
|  |  | ||||||
| while (true) |  | ||||||
| { |  | ||||||
|     if (lastRun + interval <= DateTime.UtcNow) |  | ||||||
|     { |  | ||||||
|         lastRun += interval; |  | ||||||
|         timeSinceStart += interval; |  | ||||||
|         universe.Update(new(timeSinceStart, interval)); |  | ||||||
|     } |  | ||||||
|     Thread.Sleep(1); |  | ||||||
| } |  | ||||||
| @@ -1,22 +0,0 @@ | |||||||
| <Project Sdk="Microsoft.NET.Sdk.Web"> |  | ||||||
|  |  | ||||||
|   <PropertyGroup> |  | ||||||
|     <OutputType>Exe</OutputType> |  | ||||||
|     <TargetFramework>net9.0</TargetFramework> |  | ||||||
|     <ImplicitUsings>disable</ImplicitUsings> |  | ||||||
|     <Nullable>enable</Nullable> |  | ||||||
|     <RootNamespace>Pong.Platforms.Server</RootNamespace> |  | ||||||
|     <AssemblyName>Server</AssemblyName> |  | ||||||
|   </PropertyGroup> |  | ||||||
|  |  | ||||||
|   <ItemGroup> |  | ||||||
|     <ProjectReference Include="../../Shared/Shared.csproj" /> |  | ||||||
|   </ItemGroup> |  | ||||||
|  |  | ||||||
|   <ItemGroup> |  | ||||||
|     <PackageReference Include="Microsoft.AspNetCore" Version="2.3.0" /> |  | ||||||
|     <PackageReference Include="Microsoft.Extensions.Diagnostics.HealthChecks" Version="10.0.0-preview.5.25277.114" /> |  | ||||||
|     <PackageReference Include="MonoGame.Framework.DesktopGL" Version="3.8.2.1105" /> |  | ||||||
|   </ItemGroup> |  | ||||||
|  |  | ||||||
| </Project> |  | ||||||
							
								
								
									
										176
									
								
								Pong.sln
									
									
									
									
									
								
							
							
						
						
									
										176
									
								
								Pong.sln
									
									
									
									
									
								
							| @@ -7,171 +7,41 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Engine", "Engine", "{F7F626 | |||||||
| EndProject | EndProject | ||||||
| Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Engine.Core", "Engine\Engine.Core\Engine.Core.csproj", "{990CA10C-1EBB-4395-A43A-456B7029D8C9}" | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Engine.Core", "Engine\Engine.Core\Engine.Core.csproj", "{990CA10C-1EBB-4395-A43A-456B7029D8C9}" | ||||||
| EndProject | EndProject | ||||||
|  | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Game", "Game\Game.csproj", "{500E1B05-39D7-4232-8051-E7351D745306}" | ||||||
|  | EndProject | ||||||
|  | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Engine.Input", "Engine\Engine.Input\Engine.Input.csproj", "{7EED4EC3-79D5-4C6C-A54D-1B396213C0E4}" | ||||||
|  | EndProject | ||||||
| Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Engine.Physics2D", "Engine\Engine.Physics2D\Engine.Physics2D.csproj", "{0D97F83C-B043-48B1-B155-7354C4E84FC0}" | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Engine.Physics2D", "Engine\Engine.Physics2D\Engine.Physics2D.csproj", "{0D97F83C-B043-48B1-B155-7354C4E84FC0}" | ||||||
| EndProject | EndProject | ||||||
| Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Engine", "Engine\Engine\Engine.csproj", "{2F6B1E26-1217-4EFD-874C-05ADEE4C7969}" |  | ||||||
| EndProject |  | ||||||
| Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Shared", "Shared\Shared.csproj", "{590E392E-9FB3-49FA-B4DA-6C8F7126FFE5}" |  | ||||||
| EndProject |  | ||||||
| Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Platforms", "Platforms", "{FECFFD54-338F-4060-9161-1E5770D1DC33}" |  | ||||||
| EndProject |  | ||||||
| Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Desktop", "Platforms\Desktop\Desktop.csproj", "{2B627F66-5A61-4F69-B479-62EEAB603D01}" |  | ||||||
| EndProject |  | ||||||
| Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Engine.Systems", "Engine\Engine.Systems\Engine.Systems.csproj", "{8863A1BA-2E83-419F-BACB-D4A4156EC71C}" |  | ||||||
| EndProject |  | ||||||
| Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Engine.Integration", "Engine.Integration", "{9059393F-4073-9273-0EEC-2B1BA61B620B}" |  | ||||||
| EndProject |  | ||||||
| Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Engine.Integration.MonoGame", "Engine\Engine.Integration\Engine.Integration.MonoGame\Engine.Integration.MonoGame.csproj", "{7CC31BC4-38EE-40F4-BBBA-9FC2F4CF6283}" |  | ||||||
| EndProject |  | ||||||
| Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Server", "Platforms\Server\Server.csproj", "{A15263DB-DF65-4A07-8CA1-33A2919501A0}" |  | ||||||
| EndProject |  | ||||||
| Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Engine.Integration.Yaml", "Engine\Engine.Integration\Engine.Integration.Yaml\Engine.Integration.Yaml.csproj", "{79F870AB-249E-4CA0-9DF0-F265514581DF}" |  | ||||||
| EndProject |  | ||||||
| Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Engine.Integration.LiteNetLib", "Engine\Engine.Integration\Engine.Integration.LiteNetLib\Engine.Integration.LiteNetLib.csproj", "{7AA22306-772F-45F4-8F30-97EBD1FC124D}" |  | ||||||
| EndProject |  | ||||||
| Global | Global | ||||||
| 	GlobalSection(SolutionConfigurationPlatforms) = preSolution | 	GlobalSection(SolutionConfigurationPlatforms) = preSolution | ||||||
| 		Debug|Any CPU = Debug|Any CPU | 		Debug|Any CPU = Debug|Any CPU | ||||||
| 		Debug|x64 = Debug|x64 |  | ||||||
| 		Debug|x86 = Debug|x86 |  | ||||||
| 		Release|Any CPU = Release|Any CPU | 		Release|Any CPU = Release|Any CPU | ||||||
| 		Release|x64 = Release|x64 |  | ||||||
| 		Release|x86 = Release|x86 |  | ||||||
| 	EndGlobalSection |  | ||||||
| 	GlobalSection(ProjectConfigurationPlatforms) = postSolution |  | ||||||
| 		{990CA10C-1EBB-4395-A43A-456B7029D8C9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU |  | ||||||
| 		{990CA10C-1EBB-4395-A43A-456B7029D8C9}.Debug|Any CPU.Build.0 = Debug|Any CPU |  | ||||||
| 		{990CA10C-1EBB-4395-A43A-456B7029D8C9}.Debug|x64.ActiveCfg = Debug|Any CPU |  | ||||||
| 		{990CA10C-1EBB-4395-A43A-456B7029D8C9}.Debug|x64.Build.0 = Debug|Any CPU |  | ||||||
| 		{990CA10C-1EBB-4395-A43A-456B7029D8C9}.Debug|x86.ActiveCfg = Debug|Any CPU |  | ||||||
| 		{990CA10C-1EBB-4395-A43A-456B7029D8C9}.Debug|x86.Build.0 = Debug|Any CPU |  | ||||||
| 		{990CA10C-1EBB-4395-A43A-456B7029D8C9}.Release|Any CPU.ActiveCfg = Release|Any CPU |  | ||||||
| 		{990CA10C-1EBB-4395-A43A-456B7029D8C9}.Release|Any CPU.Build.0 = Release|Any CPU |  | ||||||
| 		{990CA10C-1EBB-4395-A43A-456B7029D8C9}.Release|x64.ActiveCfg = Release|Any CPU |  | ||||||
| 		{990CA10C-1EBB-4395-A43A-456B7029D8C9}.Release|x64.Build.0 = Release|Any CPU |  | ||||||
| 		{990CA10C-1EBB-4395-A43A-456B7029D8C9}.Release|x86.ActiveCfg = Release|Any CPU |  | ||||||
| 		{990CA10C-1EBB-4395-A43A-456B7029D8C9}.Release|x86.Build.0 = Release|Any CPU |  | ||||||
| 		{0D97F83C-B043-48B1-B155-7354C4E84FC0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU |  | ||||||
| 		{0D97F83C-B043-48B1-B155-7354C4E84FC0}.Debug|Any CPU.Build.0 = Debug|Any CPU |  | ||||||
| 		{0D97F83C-B043-48B1-B155-7354C4E84FC0}.Debug|x64.ActiveCfg = Debug|Any CPU |  | ||||||
| 		{0D97F83C-B043-48B1-B155-7354C4E84FC0}.Debug|x64.Build.0 = Debug|Any CPU |  | ||||||
| 		{0D97F83C-B043-48B1-B155-7354C4E84FC0}.Debug|x86.ActiveCfg = Debug|Any CPU |  | ||||||
| 		{0D97F83C-B043-48B1-B155-7354C4E84FC0}.Debug|x86.Build.0 = Debug|Any CPU |  | ||||||
| 		{0D97F83C-B043-48B1-B155-7354C4E84FC0}.Release|Any CPU.ActiveCfg = Release|Any CPU |  | ||||||
| 		{0D97F83C-B043-48B1-B155-7354C4E84FC0}.Release|Any CPU.Build.0 = Release|Any CPU |  | ||||||
| 		{0D97F83C-B043-48B1-B155-7354C4E84FC0}.Release|x64.ActiveCfg = Release|Any CPU |  | ||||||
| 		{0D97F83C-B043-48B1-B155-7354C4E84FC0}.Release|x64.Build.0 = Release|Any CPU |  | ||||||
| 		{0D97F83C-B043-48B1-B155-7354C4E84FC0}.Release|x86.ActiveCfg = Release|Any CPU |  | ||||||
| 		{0D97F83C-B043-48B1-B155-7354C4E84FC0}.Release|x86.Build.0 = Release|Any CPU |  | ||||||
| 		{2F6B1E26-1217-4EFD-874C-05ADEE4C7969}.Debug|Any CPU.ActiveCfg = Debug|Any CPU |  | ||||||
| 		{2F6B1E26-1217-4EFD-874C-05ADEE4C7969}.Debug|Any CPU.Build.0 = Debug|Any CPU |  | ||||||
| 		{2F6B1E26-1217-4EFD-874C-05ADEE4C7969}.Debug|x64.ActiveCfg = Debug|Any CPU |  | ||||||
| 		{2F6B1E26-1217-4EFD-874C-05ADEE4C7969}.Debug|x64.Build.0 = Debug|Any CPU |  | ||||||
| 		{2F6B1E26-1217-4EFD-874C-05ADEE4C7969}.Debug|x86.ActiveCfg = Debug|Any CPU |  | ||||||
| 		{2F6B1E26-1217-4EFD-874C-05ADEE4C7969}.Debug|x86.Build.0 = Debug|Any CPU |  | ||||||
| 		{2F6B1E26-1217-4EFD-874C-05ADEE4C7969}.Release|Any CPU.ActiveCfg = Release|Any CPU |  | ||||||
| 		{2F6B1E26-1217-4EFD-874C-05ADEE4C7969}.Release|Any CPU.Build.0 = Release|Any CPU |  | ||||||
| 		{2F6B1E26-1217-4EFD-874C-05ADEE4C7969}.Release|x64.ActiveCfg = Release|Any CPU |  | ||||||
| 		{2F6B1E26-1217-4EFD-874C-05ADEE4C7969}.Release|x64.Build.0 = Release|Any CPU |  | ||||||
| 		{2F6B1E26-1217-4EFD-874C-05ADEE4C7969}.Release|x86.ActiveCfg = Release|Any CPU |  | ||||||
| 		{2F6B1E26-1217-4EFD-874C-05ADEE4C7969}.Release|x86.Build.0 = Release|Any CPU |  | ||||||
| 		{590E392E-9FB3-49FA-B4DA-6C8F7126FFE5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU |  | ||||||
| 		{590E392E-9FB3-49FA-B4DA-6C8F7126FFE5}.Debug|Any CPU.Build.0 = Debug|Any CPU |  | ||||||
| 		{590E392E-9FB3-49FA-B4DA-6C8F7126FFE5}.Debug|x64.ActiveCfg = Debug|Any CPU |  | ||||||
| 		{590E392E-9FB3-49FA-B4DA-6C8F7126FFE5}.Debug|x64.Build.0 = Debug|Any CPU |  | ||||||
| 		{590E392E-9FB3-49FA-B4DA-6C8F7126FFE5}.Debug|x86.ActiveCfg = Debug|Any CPU |  | ||||||
| 		{590E392E-9FB3-49FA-B4DA-6C8F7126FFE5}.Debug|x86.Build.0 = Debug|Any CPU |  | ||||||
| 		{590E392E-9FB3-49FA-B4DA-6C8F7126FFE5}.Release|Any CPU.ActiveCfg = Release|Any CPU |  | ||||||
| 		{590E392E-9FB3-49FA-B4DA-6C8F7126FFE5}.Release|Any CPU.Build.0 = Release|Any CPU |  | ||||||
| 		{590E392E-9FB3-49FA-B4DA-6C8F7126FFE5}.Release|x64.ActiveCfg = Release|Any CPU |  | ||||||
| 		{590E392E-9FB3-49FA-B4DA-6C8F7126FFE5}.Release|x64.Build.0 = Release|Any CPU |  | ||||||
| 		{590E392E-9FB3-49FA-B4DA-6C8F7126FFE5}.Release|x86.ActiveCfg = Release|Any CPU |  | ||||||
| 		{590E392E-9FB3-49FA-B4DA-6C8F7126FFE5}.Release|x86.Build.0 = Release|Any CPU |  | ||||||
| 		{2B627F66-5A61-4F69-B479-62EEAB603D01}.Debug|Any CPU.ActiveCfg = Debug|Any CPU |  | ||||||
| 		{2B627F66-5A61-4F69-B479-62EEAB603D01}.Debug|Any CPU.Build.0 = Debug|Any CPU |  | ||||||
| 		{2B627F66-5A61-4F69-B479-62EEAB603D01}.Debug|x64.ActiveCfg = Debug|Any CPU |  | ||||||
| 		{2B627F66-5A61-4F69-B479-62EEAB603D01}.Debug|x64.Build.0 = Debug|Any CPU |  | ||||||
| 		{2B627F66-5A61-4F69-B479-62EEAB603D01}.Debug|x86.ActiveCfg = Debug|Any CPU |  | ||||||
| 		{2B627F66-5A61-4F69-B479-62EEAB603D01}.Debug|x86.Build.0 = Debug|Any CPU |  | ||||||
| 		{2B627F66-5A61-4F69-B479-62EEAB603D01}.Release|Any CPU.ActiveCfg = Release|Any CPU |  | ||||||
| 		{2B627F66-5A61-4F69-B479-62EEAB603D01}.Release|Any CPU.Build.0 = Release|Any CPU |  | ||||||
| 		{2B627F66-5A61-4F69-B479-62EEAB603D01}.Release|x64.ActiveCfg = Release|Any CPU |  | ||||||
| 		{2B627F66-5A61-4F69-B479-62EEAB603D01}.Release|x64.Build.0 = Release|Any CPU |  | ||||||
| 		{2B627F66-5A61-4F69-B479-62EEAB603D01}.Release|x86.ActiveCfg = Release|Any CPU |  | ||||||
| 		{2B627F66-5A61-4F69-B479-62EEAB603D01}.Release|x86.Build.0 = Release|Any CPU |  | ||||||
| 		{8863A1BA-2E83-419F-BACB-D4A4156EC71C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU |  | ||||||
| 		{8863A1BA-2E83-419F-BACB-D4A4156EC71C}.Debug|Any CPU.Build.0 = Debug|Any CPU |  | ||||||
| 		{8863A1BA-2E83-419F-BACB-D4A4156EC71C}.Debug|x64.ActiveCfg = Debug|Any CPU |  | ||||||
| 		{8863A1BA-2E83-419F-BACB-D4A4156EC71C}.Debug|x64.Build.0 = Debug|Any CPU |  | ||||||
| 		{8863A1BA-2E83-419F-BACB-D4A4156EC71C}.Debug|x86.ActiveCfg = Debug|Any CPU |  | ||||||
| 		{8863A1BA-2E83-419F-BACB-D4A4156EC71C}.Debug|x86.Build.0 = Debug|Any CPU |  | ||||||
| 		{8863A1BA-2E83-419F-BACB-D4A4156EC71C}.Release|Any CPU.ActiveCfg = Release|Any CPU |  | ||||||
| 		{8863A1BA-2E83-419F-BACB-D4A4156EC71C}.Release|Any CPU.Build.0 = Release|Any CPU |  | ||||||
| 		{8863A1BA-2E83-419F-BACB-D4A4156EC71C}.Release|x64.ActiveCfg = Release|Any CPU |  | ||||||
| 		{8863A1BA-2E83-419F-BACB-D4A4156EC71C}.Release|x64.Build.0 = Release|Any CPU |  | ||||||
| 		{8863A1BA-2E83-419F-BACB-D4A4156EC71C}.Release|x86.ActiveCfg = Release|Any CPU |  | ||||||
| 		{8863A1BA-2E83-419F-BACB-D4A4156EC71C}.Release|x86.Build.0 = Release|Any CPU |  | ||||||
| 		{7CC31BC4-38EE-40F4-BBBA-9FC2F4CF6283}.Debug|Any CPU.ActiveCfg = Debug|Any CPU |  | ||||||
| 		{7CC31BC4-38EE-40F4-BBBA-9FC2F4CF6283}.Debug|Any CPU.Build.0 = Debug|Any CPU |  | ||||||
| 		{7CC31BC4-38EE-40F4-BBBA-9FC2F4CF6283}.Debug|x64.ActiveCfg = Debug|Any CPU |  | ||||||
| 		{7CC31BC4-38EE-40F4-BBBA-9FC2F4CF6283}.Debug|x64.Build.0 = Debug|Any CPU |  | ||||||
| 		{7CC31BC4-38EE-40F4-BBBA-9FC2F4CF6283}.Debug|x86.ActiveCfg = Debug|Any CPU |  | ||||||
| 		{7CC31BC4-38EE-40F4-BBBA-9FC2F4CF6283}.Debug|x86.Build.0 = Debug|Any CPU |  | ||||||
| 		{7CC31BC4-38EE-40F4-BBBA-9FC2F4CF6283}.Release|Any CPU.ActiveCfg = Release|Any CPU |  | ||||||
| 		{7CC31BC4-38EE-40F4-BBBA-9FC2F4CF6283}.Release|Any CPU.Build.0 = Release|Any CPU |  | ||||||
| 		{7CC31BC4-38EE-40F4-BBBA-9FC2F4CF6283}.Release|x64.ActiveCfg = Release|Any CPU |  | ||||||
| 		{7CC31BC4-38EE-40F4-BBBA-9FC2F4CF6283}.Release|x64.Build.0 = Release|Any CPU |  | ||||||
| 		{7CC31BC4-38EE-40F4-BBBA-9FC2F4CF6283}.Release|x86.ActiveCfg = Release|Any CPU |  | ||||||
| 		{7CC31BC4-38EE-40F4-BBBA-9FC2F4CF6283}.Release|x86.Build.0 = Release|Any CPU |  | ||||||
| 		{A15263DB-DF65-4A07-8CA1-33A2919501A0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU |  | ||||||
| 		{A15263DB-DF65-4A07-8CA1-33A2919501A0}.Debug|Any CPU.Build.0 = Debug|Any CPU |  | ||||||
| 		{A15263DB-DF65-4A07-8CA1-33A2919501A0}.Debug|x64.ActiveCfg = Debug|Any CPU |  | ||||||
| 		{A15263DB-DF65-4A07-8CA1-33A2919501A0}.Debug|x64.Build.0 = Debug|Any CPU |  | ||||||
| 		{A15263DB-DF65-4A07-8CA1-33A2919501A0}.Debug|x86.ActiveCfg = Debug|Any CPU |  | ||||||
| 		{A15263DB-DF65-4A07-8CA1-33A2919501A0}.Debug|x86.Build.0 = Debug|Any CPU |  | ||||||
| 		{A15263DB-DF65-4A07-8CA1-33A2919501A0}.Release|Any CPU.ActiveCfg = Release|Any CPU |  | ||||||
| 		{A15263DB-DF65-4A07-8CA1-33A2919501A0}.Release|Any CPU.Build.0 = Release|Any CPU |  | ||||||
| 		{A15263DB-DF65-4A07-8CA1-33A2919501A0}.Release|x64.ActiveCfg = Release|Any CPU |  | ||||||
| 		{A15263DB-DF65-4A07-8CA1-33A2919501A0}.Release|x64.Build.0 = Release|Any CPU |  | ||||||
| 		{A15263DB-DF65-4A07-8CA1-33A2919501A0}.Release|x86.ActiveCfg = Release|Any CPU |  | ||||||
| 		{A15263DB-DF65-4A07-8CA1-33A2919501A0}.Release|x86.Build.0 = Release|Any CPU |  | ||||||
| 		{79F870AB-249E-4CA0-9DF0-F265514581DF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU |  | ||||||
| 		{79F870AB-249E-4CA0-9DF0-F265514581DF}.Debug|Any CPU.Build.0 = Debug|Any CPU |  | ||||||
| 		{79F870AB-249E-4CA0-9DF0-F265514581DF}.Debug|x64.ActiveCfg = Debug|Any CPU |  | ||||||
| 		{79F870AB-249E-4CA0-9DF0-F265514581DF}.Debug|x64.Build.0 = Debug|Any CPU |  | ||||||
| 		{79F870AB-249E-4CA0-9DF0-F265514581DF}.Debug|x86.ActiveCfg = Debug|Any CPU |  | ||||||
| 		{79F870AB-249E-4CA0-9DF0-F265514581DF}.Debug|x86.Build.0 = Debug|Any CPU |  | ||||||
| 		{79F870AB-249E-4CA0-9DF0-F265514581DF}.Release|Any CPU.ActiveCfg = Release|Any CPU |  | ||||||
| 		{79F870AB-249E-4CA0-9DF0-F265514581DF}.Release|Any CPU.Build.0 = Release|Any CPU |  | ||||||
| 		{79F870AB-249E-4CA0-9DF0-F265514581DF}.Release|x64.ActiveCfg = Release|Any CPU |  | ||||||
| 		{79F870AB-249E-4CA0-9DF0-F265514581DF}.Release|x64.Build.0 = Release|Any CPU |  | ||||||
| 		{79F870AB-249E-4CA0-9DF0-F265514581DF}.Release|x86.ActiveCfg = Release|Any CPU |  | ||||||
| 		{79F870AB-249E-4CA0-9DF0-F265514581DF}.Release|x86.Build.0 = Release|Any CPU |  | ||||||
| 		{7AA22306-772F-45F4-8F30-97EBD1FC124D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU |  | ||||||
| 		{7AA22306-772F-45F4-8F30-97EBD1FC124D}.Debug|Any CPU.Build.0 = Debug|Any CPU |  | ||||||
| 		{7AA22306-772F-45F4-8F30-97EBD1FC124D}.Debug|x64.ActiveCfg = Debug|Any CPU |  | ||||||
| 		{7AA22306-772F-45F4-8F30-97EBD1FC124D}.Debug|x64.Build.0 = Debug|Any CPU |  | ||||||
| 		{7AA22306-772F-45F4-8F30-97EBD1FC124D}.Debug|x86.ActiveCfg = Debug|Any CPU |  | ||||||
| 		{7AA22306-772F-45F4-8F30-97EBD1FC124D}.Debug|x86.Build.0 = Debug|Any CPU |  | ||||||
| 		{7AA22306-772F-45F4-8F30-97EBD1FC124D}.Release|Any CPU.ActiveCfg = Release|Any CPU |  | ||||||
| 		{7AA22306-772F-45F4-8F30-97EBD1FC124D}.Release|Any CPU.Build.0 = Release|Any CPU |  | ||||||
| 		{7AA22306-772F-45F4-8F30-97EBD1FC124D}.Release|x64.ActiveCfg = Release|Any CPU |  | ||||||
| 		{7AA22306-772F-45F4-8F30-97EBD1FC124D}.Release|x64.Build.0 = Release|Any CPU |  | ||||||
| 		{7AA22306-772F-45F4-8F30-97EBD1FC124D}.Release|x86.ActiveCfg = Release|Any CPU |  | ||||||
| 		{7AA22306-772F-45F4-8F30-97EBD1FC124D}.Release|x86.Build.0 = Release|Any CPU |  | ||||||
| 	EndGlobalSection | 	EndGlobalSection | ||||||
| 	GlobalSection(SolutionProperties) = preSolution | 	GlobalSection(SolutionProperties) = preSolution | ||||||
| 		HideSolutionNode = FALSE | 		HideSolutionNode = FALSE | ||||||
| 	EndGlobalSection | 	EndGlobalSection | ||||||
|  | 	GlobalSection(ProjectConfigurationPlatforms) = postSolution | ||||||
|  | 		{990CA10C-1EBB-4395-A43A-456B7029D8C9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU | ||||||
|  | 		{990CA10C-1EBB-4395-A43A-456B7029D8C9}.Debug|Any CPU.Build.0 = Debug|Any CPU | ||||||
|  | 		{990CA10C-1EBB-4395-A43A-456B7029D8C9}.Release|Any CPU.ActiveCfg = Release|Any CPU | ||||||
|  | 		{990CA10C-1EBB-4395-A43A-456B7029D8C9}.Release|Any CPU.Build.0 = Release|Any CPU | ||||||
|  | 		{500E1B05-39D7-4232-8051-E7351D745306}.Debug|Any CPU.ActiveCfg = Debug|Any CPU | ||||||
|  | 		{500E1B05-39D7-4232-8051-E7351D745306}.Debug|Any CPU.Build.0 = Debug|Any CPU | ||||||
|  | 		{500E1B05-39D7-4232-8051-E7351D745306}.Release|Any CPU.ActiveCfg = Release|Any CPU | ||||||
|  | 		{500E1B05-39D7-4232-8051-E7351D745306}.Release|Any CPU.Build.0 = Release|Any CPU | ||||||
|  | 		{7EED4EC3-79D5-4C6C-A54D-1B396213C0E4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU | ||||||
|  | 		{7EED4EC3-79D5-4C6C-A54D-1B396213C0E4}.Debug|Any CPU.Build.0 = Debug|Any CPU | ||||||
|  | 		{7EED4EC3-79D5-4C6C-A54D-1B396213C0E4}.Release|Any CPU.ActiveCfg = Release|Any CPU | ||||||
|  | 		{7EED4EC3-79D5-4C6C-A54D-1B396213C0E4}.Release|Any CPU.Build.0 = Release|Any CPU | ||||||
|  | 		{0D97F83C-B043-48B1-B155-7354C4E84FC0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU | ||||||
|  | 		{0D97F83C-B043-48B1-B155-7354C4E84FC0}.Debug|Any CPU.Build.0 = Debug|Any CPU | ||||||
|  | 		{0D97F83C-B043-48B1-B155-7354C4E84FC0}.Release|Any CPU.ActiveCfg = Release|Any CPU | ||||||
|  | 		{0D97F83C-B043-48B1-B155-7354C4E84FC0}.Release|Any CPU.Build.0 = Release|Any CPU | ||||||
|  | 	EndGlobalSection | ||||||
| 	GlobalSection(NestedProjects) = preSolution | 	GlobalSection(NestedProjects) = preSolution | ||||||
| 		{990CA10C-1EBB-4395-A43A-456B7029D8C9} = {F7F62670-237A-4C93-A30E-CE661C6FC401} | 		{990CA10C-1EBB-4395-A43A-456B7029D8C9} = {F7F62670-237A-4C93-A30E-CE661C6FC401} | ||||||
|  | 		{7EED4EC3-79D5-4C6C-A54D-1B396213C0E4} = {F7F62670-237A-4C93-A30E-CE661C6FC401} | ||||||
| 		{0D97F83C-B043-48B1-B155-7354C4E84FC0} = {F7F62670-237A-4C93-A30E-CE661C6FC401} | 		{0D97F83C-B043-48B1-B155-7354C4E84FC0} = {F7F62670-237A-4C93-A30E-CE661C6FC401} | ||||||
| 		{2F6B1E26-1217-4EFD-874C-05ADEE4C7969} = {F7F62670-237A-4C93-A30E-CE661C6FC401} |  | ||||||
| 		{2B627F66-5A61-4F69-B479-62EEAB603D01} = {FECFFD54-338F-4060-9161-1E5770D1DC33} |  | ||||||
| 		{8863A1BA-2E83-419F-BACB-D4A4156EC71C} = {F7F62670-237A-4C93-A30E-CE661C6FC401} |  | ||||||
| 		{9059393F-4073-9273-0EEC-2B1BA61B620B} = {F7F62670-237A-4C93-A30E-CE661C6FC401} |  | ||||||
| 		{7CC31BC4-38EE-40F4-BBBA-9FC2F4CF6283} = {9059393F-4073-9273-0EEC-2B1BA61B620B} |  | ||||||
| 		{A15263DB-DF65-4A07-8CA1-33A2919501A0} = {FECFFD54-338F-4060-9161-1E5770D1DC33} |  | ||||||
| 		{7AA22306-772F-45F4-8F30-97EBD1FC124D} = {9059393F-4073-9273-0EEC-2B1BA61B620B} |  | ||||||
| 	EndGlobalSection | 	EndGlobalSection | ||||||
| EndGlobal | EndGlobal | ||||||
|   | |||||||
| @@ -1,36 +0,0 @@ | |||||||
| { |  | ||||||
|   "version": 1, |  | ||||||
|   "isRoot": true, |  | ||||||
|   "tools": { |  | ||||||
|     "dotnet-mgcb": { |  | ||||||
|       "version": "3.8.2.1105", |  | ||||||
|       "commands": [ |  | ||||||
|         "mgcb" |  | ||||||
|       ] |  | ||||||
|     }, |  | ||||||
|     "dotnet-mgcb-editor": { |  | ||||||
|       "version": "3.8.2.1105", |  | ||||||
|       "commands": [ |  | ||||||
|         "mgcb-editor" |  | ||||||
|       ] |  | ||||||
|     }, |  | ||||||
|     "dotnet-mgcb-editor-linux": { |  | ||||||
|       "version": "3.8.2.1105", |  | ||||||
|       "commands": [ |  | ||||||
|         "mgcb-editor-linux" |  | ||||||
|       ] |  | ||||||
|     }, |  | ||||||
|     "dotnet-mgcb-editor-windows": { |  | ||||||
|       "version": "3.8.2.1105", |  | ||||||
|       "commands": [ |  | ||||||
|         "mgcb-editor-windows" |  | ||||||
|       ] |  | ||||||
|     }, |  | ||||||
|     "dotnet-mgcb-editor-mac": { |  | ||||||
|       "version": "3.8.2.1105", |  | ||||||
|       "commands": [ |  | ||||||
|         "mgcb-editor-mac" |  | ||||||
|       ] |  | ||||||
|     } |  | ||||||
|   } |  | ||||||
| } |  | ||||||
| @@ -1,110 +0,0 @@ | |||||||
| using Microsoft.Xna.Framework.Audio; |  | ||||||
| using Microsoft.Xna.Framework.Content; |  | ||||||
|  |  | ||||||
| using Engine.Core; |  | ||||||
| using Engine.Integration.MonoGame; |  | ||||||
| using Engine.Systems.Network; |  | ||||||
| using Engine.Physics2D; |  | ||||||
| using Engine.Systems.Tween; |  | ||||||
|  |  | ||||||
| namespace Pong.Behaviours; |  | ||||||
|  |  | ||||||
| public class Ball : Behaviour2D, IFirstFrameUpdate, ILoadContent, IPhysicsUpdate, INetworkEntity, |  | ||||||
|     IPacketListenerClient<Ball.BallUpdatePacket>, |  | ||||||
|     IPacketListenerClient<Ball.BallResetPacket> |  | ||||||
| { |  | ||||||
|     public float Speed { get; set; } = 500f; |  | ||||||
|     public float SpeedUpMultiplier { get; set; } = .025f; |  | ||||||
|  |  | ||||||
|     public IRigidBody2D RigidBody { get; private set; } = null!; |  | ||||||
|  |  | ||||||
|     private IPhysicsEngine2D physicsEngine2D = null!; |  | ||||||
|     private ITweenManager tweenManager = null!; |  | ||||||
|     private INetworkCommunicatorServer? networkServer = null; |  | ||||||
|     private ITween? networkTween = null; |  | ||||||
|  |  | ||||||
|     private SoundEffect? bounceSoundEffect = null; |  | ||||||
|  |  | ||||||
|     public void FirstActiveFrame() |  | ||||||
|     { |  | ||||||
|         BehaviourController.GetRequiredBehaviour<ICollider2D>().OnCollisionDetected.AddListener(OnCollisionDetected); |  | ||||||
|         physicsEngine2D = Universe.FindRequiredBehaviour<IPhysicsEngine2D>(); |  | ||||||
|         tweenManager = Universe.FindRequiredBehaviour<ITweenManager>(); |  | ||||||
|         RigidBody = BehaviourController.GetRequiredBehaviour<IRigidBody2D>(); |  | ||||||
|         networkServer = Universe.FindBehaviour<INetworkCommunicatorServer>(); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     public void LoadContent(ContentManager content) |  | ||||||
|     { |  | ||||||
|         bounceSoundEffect = content.Load<SoundEffect>("Audio/Bounce"); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     public void LaunchBall(Vector2D launchDirection) |  | ||||||
|     { |  | ||||||
|         ResetBall(); |  | ||||||
|         RigidBody.Velocity = launchDirection * Speed; |  | ||||||
|         networkServer?.SendToAll(new BallUpdatePacket(this)); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     public void ResetBall() |  | ||||||
|     { |  | ||||||
|         if (networkTween is not null) |  | ||||||
|             tweenManager.CancelTween(networkTween); |  | ||||||
|         Transform.Position = Vector2D.Zero; |  | ||||||
|         RigidBody.Velocity = Vector2D.Zero; |  | ||||||
|         networkServer?.SendToAll(new BallResetPacket()); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     public void PhysicsUpdate(float delta) |  | ||||||
|     { |  | ||||||
|         if (RigidBody.Velocity.MagnitudeSquared <= 0.01f) |  | ||||||
|             return; |  | ||||||
|  |  | ||||||
|         Vector2D direction = RigidBody.Velocity.Normalized; |  | ||||||
|         RigidBody.Velocity += direction * delta * SpeedUpMultiplier; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     private void OnCollisionDetected(ICollider2D collider2D, CollisionDetectionInformation information) |  | ||||||
|     { |  | ||||||
|         if (Math.Abs(information.Normal.Dot(Vector2D.Right)) > .25) |  | ||||||
|             RigidBody.Velocity = information.Detected.Transform.Position.FromTo(information.Detector.Transform.Position).Normalized * RigidBody.Velocity.Magnitude; |  | ||||||
|         else |  | ||||||
|             RigidBody.Velocity = RigidBody.Velocity.Reflect(information.Normal); |  | ||||||
|  |  | ||||||
|         if (information.Detected.Transform.BehaviourController.GetBehaviour<ScoreWall>() is null) |  | ||||||
|             networkServer?.SendToAll(new BallUpdatePacket(this)); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     public Ball() { } |  | ||||||
|     public Ball(float speed) => Speed = speed; |  | ||||||
|  |  | ||||||
|     void IPacketListenerClient<BallResetPacket>.OnClientPacketArrived(IConnection sender, BallResetPacket packet) => ResetBall(); |  | ||||||
|     void IPacketListenerClient<BallUpdatePacket>.OnClientPacketArrived(IConnection sender, BallUpdatePacket packet) |  | ||||||
|     { |  | ||||||
|         Vector2D localToServerPosition = Transform.Position.FromTo(packet.Position); |  | ||||||
|         if (localToServerPosition.MagnitudeSquared < 4f) |  | ||||||
|             networkTween = Transform.TweenPositionAdditive(tweenManager, .25f, localToServerPosition); |  | ||||||
|         else |  | ||||||
|             Transform.Position = packet.Position; |  | ||||||
|  |  | ||||||
|         if (RigidBody.Velocity.MagnitudeSquared >= .01f) |  | ||||||
|             bounceSoundEffect?.Play(); |  | ||||||
|  |  | ||||||
|         RigidBody.Velocity = packet.Velocity; |  | ||||||
|         physicsEngine2D.StepIndividual(RigidBody, sender.Ping); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     private class BallResetPacket : INetworkPacket; |  | ||||||
|     private class BallUpdatePacket : INetworkPacket |  | ||||||
|     { |  | ||||||
|         public Vector2D Position { get; set; } = Vector2D.Zero; |  | ||||||
|         public Vector2D Velocity { get; set; } = Vector2D.Zero; |  | ||||||
|  |  | ||||||
|         public BallUpdatePacket() { } |  | ||||||
|         public BallUpdatePacket(Ball ballBehaviour) |  | ||||||
|         { |  | ||||||
|             Position = ballBehaviour.Transform.Position; |  | ||||||
|             Velocity = ballBehaviour.RigidBody.Velocity; |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @@ -1,69 +0,0 @@ | |||||||
| using Microsoft.Xna.Framework.Input; |  | ||||||
|  |  | ||||||
| using Engine.Core; |  | ||||||
| using Engine.Integration.MonoGame; |  | ||||||
| using Engine.Systems.Input; |  | ||||||
|  |  | ||||||
| namespace Pong.Behaviours; |  | ||||||
|  |  | ||||||
| public class CameraController : Behaviour, IFirstFrameUpdate, IUpdate |  | ||||||
| { |  | ||||||
|     private MonoGameCamera2D cameraBehaviour = null!; |  | ||||||
|     private IButtonInputs<Keys> buttonInputs = null!; |  | ||||||
|  |  | ||||||
|     private float defaultZoomLevel = 1f; |  | ||||||
|  |  | ||||||
|     public void FirstActiveFrame() |  | ||||||
|     { |  | ||||||
|         cameraBehaviour = BehaviourController.GetRequiredBehaviour<MonoGameCamera2D>(); |  | ||||||
|         buttonInputs = Universe.FindRequiredBehaviour<IButtonInputs<Keys>>(); |  | ||||||
|  |  | ||||||
|         buttonInputs.RegisterOnPress(Keys.F, SwitchToFullScreen); |  | ||||||
|         buttonInputs.RegisterOnPress(Keys.R, ResetCamera); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     public void Update() |  | ||||||
|     { |  | ||||||
|         if (buttonInputs.IsPressed(Keys.U)) |  | ||||||
|             cameraBehaviour.Zoom += Universe.Time.DeltaTime * 5f; |  | ||||||
|         if (buttonInputs.IsPressed(Keys.J)) |  | ||||||
|             cameraBehaviour.Zoom -= Universe.Time.DeltaTime * 5f; |  | ||||||
|  |  | ||||||
|  |  | ||||||
|         if (buttonInputs.IsPressed(Keys.NumPad8)) cameraBehaviour.Transform.LocalPosition += Vector2D.Up * Universe.Time.DeltaTime * 500f; |  | ||||||
|         if (buttonInputs.IsPressed(Keys.NumPad2)) cameraBehaviour.Transform.LocalPosition -= Vector2D.Up * Universe.Time.DeltaTime * 500f; |  | ||||||
|         if (buttonInputs.IsPressed(Keys.NumPad6)) cameraBehaviour.Transform.LocalPosition += Vector2D.Right * Universe.Time.DeltaTime * 500f; |  | ||||||
|         if (buttonInputs.IsPressed(Keys.NumPad4)) cameraBehaviour.Transform.LocalPosition -= Vector2D.Right * Universe.Time.DeltaTime * 500f; |  | ||||||
|  |  | ||||||
|  |  | ||||||
|         if (buttonInputs.IsPressed(Keys.Q)) |  | ||||||
|             cameraBehaviour.Transform.Rotation += Universe.Time.DeltaTime * 45f; |  | ||||||
|         if (buttonInputs.IsPressed(Keys.E)) |  | ||||||
|             cameraBehaviour.Transform.Rotation -= Universe.Time.DeltaTime * 45f; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     private void SwitchToFullScreen(IButtonInputs<Keys> sender, IButtonInputs<Keys>.ButtonCallbackArguments args) |  | ||||||
|     { |  | ||||||
|         if (cameraBehaviour.Graphics.IsFullScreen) |  | ||||||
|             return; |  | ||||||
|  |  | ||||||
|         cameraBehaviour.Graphics.PreferMultiSampling = false; |  | ||||||
|         cameraBehaviour.Graphics.PreferredBackBufferWidth = cameraBehaviour.Graphics.GraphicsDevice.Adapter.CurrentDisplayMode.Width; |  | ||||||
|         cameraBehaviour.Graphics.PreferredBackBufferHeight = cameraBehaviour.Graphics.GraphicsDevice.Adapter.CurrentDisplayMode.Height; |  | ||||||
|         cameraBehaviour.Graphics.IsFullScreen = true; |  | ||||||
|         cameraBehaviour.Graphics.ApplyChanges(); |  | ||||||
|  |  | ||||||
|         float previousScreenSize = Math.Sqrt(Math.Sqr(cameraBehaviour.Viewport.Width) + Math.Sqr(cameraBehaviour.Viewport.Height)); |  | ||||||
|         float currentScreenSize = Math.Sqrt(Math.Sqr(cameraBehaviour.Graphics.GraphicsDevice.Viewport.Width) + Math.Sqr(cameraBehaviour.Graphics.GraphicsDevice.Viewport.Height)); |  | ||||||
|         defaultZoomLevel /= previousScreenSize / currentScreenSize; |  | ||||||
|         cameraBehaviour.Zoom /= previousScreenSize / currentScreenSize; |  | ||||||
|         cameraBehaviour.Viewport = cameraBehaviour.Graphics.GraphicsDevice.Viewport; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     private void ResetCamera(IButtonInputs<Keys> sender, IButtonInputs<Keys>.ButtonCallbackArguments args) |  | ||||||
|     { |  | ||||||
|         cameraBehaviour.Zoom = defaultZoomLevel; |  | ||||||
|         cameraBehaviour.Transform.LocalPosition = Vector2D.Zero; |  | ||||||
|         cameraBehaviour.Transform.LocalRotation = 0f; |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @@ -1,29 +0,0 @@ | |||||||
| using Engine.Core; |  | ||||||
| using Engine.Integration.MonoGame; |  | ||||||
|  |  | ||||||
| namespace Pong.Behaviours; |  | ||||||
|  |  | ||||||
| public class DrawableColliderCircle : Engine.Physics2D.Collider2DCircle, IDrawableTriangle |  | ||||||
| { |  | ||||||
|     private const float CIRCLE_SEGMENT_COUNT = 32f; |  | ||||||
|  |  | ||||||
|     public ColorRGBA Color { get; set; } = new ColorRGBA(255, 255, 255); |  | ||||||
|  |  | ||||||
|     public void Draw(ITriangleBatch triangleBatch) |  | ||||||
|     { |  | ||||||
|         Recalculate(); |  | ||||||
|  |  | ||||||
|         for (int i = 0; i < CIRCLE_SEGMENT_COUNT; i++) |  | ||||||
|         { |  | ||||||
|             float iPi1 = i / CIRCLE_SEGMENT_COUNT * 2f * Math.Pi; |  | ||||||
|             float iPi2 = (i + 1f).Mod(CIRCLE_SEGMENT_COUNT) / CIRCLE_SEGMENT_COUNT * 2f * Math.Pi; |  | ||||||
|  |  | ||||||
|             Vector2D firstVertex = new Vector2D(Math.Sin(iPi1), Math.Cos(iPi1)) * CircleWorld.Radius; |  | ||||||
|             Vector2D secondVertex = new Vector2D(Math.Sin(iPi2), Math.Cos(iPi2)) * CircleWorld.Radius; |  | ||||||
|             triangleBatch.Draw(new(CircleWorld.Center, CircleWorld.Center + firstVertex, CircleWorld.Center + secondVertex), Color); |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     public DrawableColliderCircle(Circle circle) : base(circle) { } |  | ||||||
|     public DrawableColliderCircle(Circle circle, ColorRGBA color) : base(circle) { Color = color; } |  | ||||||
| } |  | ||||||
| @@ -1,26 +0,0 @@ | |||||||
| using System.Collections.Generic; |  | ||||||
|  |  | ||||||
| using Engine.Core; |  | ||||||
| using Engine.Integration.MonoGame; |  | ||||||
|  |  | ||||||
| namespace Pong.Behaviours; |  | ||||||
|  |  | ||||||
| public class DrawableColliderShape : Engine.Physics2D.Collider2DShape, IDrawableTriangle |  | ||||||
| { |  | ||||||
|     private readonly IList<Triangle> triangles = []; |  | ||||||
|  |  | ||||||
|     public ColorRGBA Color { get; set; } = new ColorRGBA(255, 255, 255); |  | ||||||
|  |  | ||||||
|     public void Draw(ITriangleBatch triangleBatch) |  | ||||||
|     { |  | ||||||
|         Recalculate(); |  | ||||||
|  |  | ||||||
|         ShapeWorld.ToTrianglesConvex(triangles); |  | ||||||
|  |  | ||||||
|         foreach (Triangle triangle in triangles) |  | ||||||
|             triangleBatch.Draw(triangle, Color); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     public DrawableColliderShape(Shape2D shape) : base(shape) { } |  | ||||||
|     public DrawableColliderShape(Shape2D shape, ColorRGBA color) : base(shape) { Color = color; } |  | ||||||
| } |  | ||||||
| @@ -1,31 +0,0 @@ | |||||||
| using Microsoft.Xna.Framework.Content; |  | ||||||
| using Microsoft.Xna.Framework.Graphics; |  | ||||||
|  |  | ||||||
| using Engine.Core; |  | ||||||
| using Engine.Integration.MonoGame; |  | ||||||
|  |  | ||||||
| namespace Pong.Behaviours; |  | ||||||
|  |  | ||||||
| public class Label : Behaviour2D, IDrawableSprite, ILoadContent |  | ||||||
| { |  | ||||||
|     public SpriteFont? Font { get; set; } = null; |  | ||||||
|     public ColorRGBA Color { get; set; } = new ColorRGBA(255, 255, 255, 255); |  | ||||||
|     public int Size { get; set; } = 16; |  | ||||||
|     public string Text { get; set; } = string.Empty; |  | ||||||
|  |  | ||||||
|     public void Draw(ISpriteBatch spriteBatch) |  | ||||||
|     { |  | ||||||
|         if (Font is null) |  | ||||||
|             return; |  | ||||||
|  |  | ||||||
|         spriteBatch.DrawString(Font, Text, Transform.Position, Color.ToPreMultipliedColor(), Transform.Rotation, Vector2D.One * .5f, Transform.Scale.Magnitude, SpriteEffects.None, 0f); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     public void LoadContent(ContentManager content) |  | ||||||
|     { |  | ||||||
|         Font ??= content.Load<SpriteFont>("UbuntuMono"); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     public Label() { } |  | ||||||
|     public Label(SpriteFont font) => Font = font; |  | ||||||
| } |  | ||||||
| @@ -1,117 +0,0 @@ | |||||||
| using System; |  | ||||||
|  |  | ||||||
| using Microsoft.Xna.Framework.Input; |  | ||||||
|  |  | ||||||
| using Engine.Core; |  | ||||||
| using Engine.Systems.Network; |  | ||||||
| using Engine.Physics2D; |  | ||||||
| using Engine.Systems.Input; |  | ||||||
| using Engine.Systems.Tween; |  | ||||||
|  |  | ||||||
| namespace Pong.Behaviours; |  | ||||||
|  |  | ||||||
| public class Paddle(Keys Up, Keys Down, float High, float Low, float Speed) : Behaviour2D, |  | ||||||
|     IFirstFrameUpdate, IPhysicsIteration, IPostPhysicsUpdate, |  | ||||||
|     IPacketListenerServer<Paddle.PaddleKeyStatePacket>, IPacketListenerClient<Paddle.PaddleKeyStatePacket> |  | ||||||
| { |  | ||||||
|     private Keys Up { get; } = Up; |  | ||||||
|     private Keys Down { get; } = Down; |  | ||||||
|     public float High { get; } = High; |  | ||||||
|     public float Low { get; } = Low; |  | ||||||
|     public float Speed { get; set; } = Speed; |  | ||||||
|  |  | ||||||
|     private bool isUpPressed = false; |  | ||||||
|     private bool isDownPressed = false; |  | ||||||
|  |  | ||||||
|     private IButtonInputs<Keys>? inputs = null; |  | ||||||
|     private INetworkCommunicatorClient? networkClient = null!; |  | ||||||
|     private INetworkCommunicatorServer? networkServer = null; |  | ||||||
|     private IRigidBody2D rigidBody = null!; |  | ||||||
|     private IPhysicsEngine2D physicsEngine2D = null!; |  | ||||||
|  |  | ||||||
|     private ITween? networkTween = null; |  | ||||||
|     private ITweenManager tweenManager = null!; |  | ||||||
|  |  | ||||||
|     public void PhysicsIterate(float delta) |  | ||||||
|     { |  | ||||||
|         if (isUpPressed) |  | ||||||
|             rigidBody.Transform.Position += Vector2D.Up * Speed * delta; |  | ||||||
|         else if (isDownPressed) |  | ||||||
|             rigidBody.Transform.Position -= Vector2D.Up * Speed * delta; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     public void PostPhysicsUpdate(float delta) |  | ||||||
|     { |  | ||||||
|         Transform.Position = new Vector2D(Transform.Position.X, MathF.Max(MathF.Min(Transform.Position.Y, High), Low)); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     public void FirstActiveFrame() |  | ||||||
|     { |  | ||||||
|         physicsEngine2D = Universe.FindRequiredBehaviour<IPhysicsEngine2D>(); |  | ||||||
|         inputs = Universe.FindBehaviour<IButtonInputs<Keys>>(); |  | ||||||
|         networkClient = Universe.FindBehaviour<INetworkCommunicatorClient>(); |  | ||||||
|         networkServer = Universe.FindBehaviour<INetworkCommunicatorServer>(); |  | ||||||
|         rigidBody = BehaviourController.GetRequiredBehaviour<IRigidBody2D>(); |  | ||||||
|         tweenManager = Universe.FindRequiredBehaviour<ITweenManager>(); |  | ||||||
|  |  | ||||||
|         inputs?.RegisterOnPress(Up, OnUpPressed); |  | ||||||
|         inputs?.RegisterOnRelease(Up, OnUpReleased); |  | ||||||
|  |  | ||||||
|         inputs?.RegisterOnPress(Down, OnDownPressed); |  | ||||||
|         inputs?.RegisterOnRelease(Down, OnDownReleased); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     private void OnUpPressed(IButtonInputs<Keys> sender, IButtonInputs<Keys>.ButtonCallbackArguments args) { isUpPressed = true; networkClient?.SendToServer(new PaddleKeyStatePacket(this)); } |  | ||||||
|     private void OnUpReleased(IButtonInputs<Keys> sender, IButtonInputs<Keys>.ButtonCallbackArguments args) { isUpPressed = false; networkClient?.SendToServer(new PaddleKeyStatePacket(this)); } |  | ||||||
|     private void OnDownPressed(IButtonInputs<Keys> sender, IButtonInputs<Keys>.ButtonCallbackArguments args) { isDownPressed = true; networkClient?.SendToServer(new PaddleKeyStatePacket(this)); } |  | ||||||
|     private void OnDownReleased(IButtonInputs<Keys> sender, IButtonInputs<Keys>.ButtonCallbackArguments args) { isDownPressed = false; networkClient?.SendToServer(new PaddleKeyStatePacket(this)); } |  | ||||||
|  |  | ||||||
|     public void OnServerPacketArrived(IConnection sender, PaddleKeyStatePacket packet) |  | ||||||
|     { |  | ||||||
|         physicsEngine2D.StepIndividual(rigidBody, -sender.Ping.Min(.05f)); |  | ||||||
|  |  | ||||||
|         isUpPressed = packet.IsUpPressed; |  | ||||||
|         isDownPressed = packet.IsDownPressed; |  | ||||||
|  |  | ||||||
|         physicsEngine2D.StepIndividual(rigidBody, sender.Ping.Min(.05f)); |  | ||||||
|         networkServer?.SendToAll(new PaddleKeyStatePacket(this)); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     public void OnClientPacketArrived(IConnection sender, PaddleKeyStatePacket packet) |  | ||||||
|     { |  | ||||||
|         if (packet.IsDownPressed || packet.IsUpPressed) // Check if the server paddle is moving |  | ||||||
|             if (isDownPressed == packet.IsDownPressed && isUpPressed == packet.IsUpPressed) // Check if we are the ones giving the inputs |  | ||||||
|                 return; |  | ||||||
|  |  | ||||||
|         physicsEngine2D.StepIndividual(rigidBody, -sender.Ping); |  | ||||||
|  |  | ||||||
|         isUpPressed = packet.IsUpPressed; |  | ||||||
|         isDownPressed = packet.IsDownPressed; |  | ||||||
|  |  | ||||||
|         physicsEngine2D.StepIndividual(rigidBody, sender.Ping); |  | ||||||
|  |  | ||||||
|         Vector2D localToServerPosition = Transform.Position.FromTo(packet.Position); |  | ||||||
|         networkTween = Transform.TweenPositionAdditive(tweenManager, .1f, localToServerPosition); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     public class PaddleKeyStatePacket : IEntityNetworkPacket |  | ||||||
|     { |  | ||||||
|         public string EntityId { get; set; } = default!; |  | ||||||
|         public Vector2D Position { get; set; } = default!; |  | ||||||
|         public bool IsUpPressed { get; set; } = default!; |  | ||||||
|         public bool IsDownPressed { get; set; } = default!; |  | ||||||
|  |  | ||||||
|         public PaddleKeyStatePacket Set(Paddle paddleBehaviour) |  | ||||||
|         { |  | ||||||
|             EntityId = paddleBehaviour.Id; |  | ||||||
|             Position = paddleBehaviour.Transform.Position; |  | ||||||
|             IsUpPressed = paddleBehaviour.isUpPressed; |  | ||||||
|             IsDownPressed = paddleBehaviour.isDownPressed; |  | ||||||
|  |  | ||||||
|             return this; |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         public PaddleKeyStatePacket() { } |  | ||||||
|         public PaddleKeyStatePacket(Paddle paddleBehaviour) => Set(paddleBehaviour); |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @@ -1,107 +0,0 @@ | |||||||
| using Microsoft.Xna.Framework.Audio; |  | ||||||
| using Microsoft.Xna.Framework.Content; |  | ||||||
| using Microsoft.Xna.Framework.Input; |  | ||||||
|  |  | ||||||
| using Engine.Core; |  | ||||||
| using Engine.Core.Debug; |  | ||||||
| using Engine.Integration.MonoGame; |  | ||||||
| using Engine.Systems.Network; |  | ||||||
| using Engine.Systems.Input; |  | ||||||
| using Engine.Systems.Time; |  | ||||||
| using Engine.Systems.Tween; |  | ||||||
|  |  | ||||||
| namespace Pong.Behaviours; |  | ||||||
|  |  | ||||||
| public class PongGameStarter : Behaviour, INetworkEntity, IFirstFrameUpdate, ILoadContent, |  | ||||||
|     IPacketListenerServer<PongGameStarter.RequestStartPacket>, |  | ||||||
|     IPacketListenerClient<PongGameStarter.RequestStartPacket> |  | ||||||
| { |  | ||||||
|     private const float START_COUNTDOWN = 3f; |  | ||||||
|  |  | ||||||
|     private INetworkCommunicatorServer? networkServer = null; |  | ||||||
|     private INetworkCommunicatorClient? networkClient = null; |  | ||||||
|     private ITweenManager? tweenManager = null; |  | ||||||
|     private PongManager pongManager = null!; |  | ||||||
|  |  | ||||||
|     private ILogger? logger = null; |  | ||||||
|  |  | ||||||
|     private Label? label = null; |  | ||||||
|     private TickerTimer timer = null!; |  | ||||||
|  |  | ||||||
|     private SoundEffectInstance? tickSoundEffect = null; |  | ||||||
|     private SoundEffectInstance? startSoundEffect = null; |  | ||||||
|  |  | ||||||
|     public void FirstActiveFrame() |  | ||||||
|     { |  | ||||||
|         IButtonInputs<Keys>? buttonInputs = Universe.FindBehaviour<IButtonInputs<Keys>>(); |  | ||||||
|         buttonInputs?.RegisterOnRelease(Keys.Space, (_, _1) => networkClient?.SendToServer(new RequestStartPacket())); |  | ||||||
|  |  | ||||||
|         networkClient = Universe.FindBehaviour<INetworkCommunicatorClient>(); |  | ||||||
|         networkServer = Universe.FindBehaviour<INetworkCommunicatorServer>(); |  | ||||||
|         tweenManager = Universe.FindBehaviour<ITweenManager>(); |  | ||||||
|         pongManager = BehaviourController.GetRequiredBehaviourInParent<PongManager>(); |  | ||||||
|         label = BehaviourController.GetRequiredBehaviour<Label>(); |  | ||||||
|         logger = Universe.FindBehaviour<ILogger>(); |  | ||||||
|  |  | ||||||
|         if (!BehaviourController.TryGetBehaviour(out timer!)) |  | ||||||
|         { |  | ||||||
|             timer = BehaviourController.AddBehaviour<TickerTimer>(); |  | ||||||
|             timer.OnStarted.AddListener(OnCountdownStart); |  | ||||||
|             timer.OnTick.AddListener(DisplayCountdown); |  | ||||||
|             timer.OnStopped.AddListener(StartPong); |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     public void LoadContent(ContentManager content) |  | ||||||
|     { |  | ||||||
|         tickSoundEffect = content.Load<SoundEffect>("Audio/TimerTick").CreateInstance(); |  | ||||||
|         startSoundEffect = content.Load<SoundEffect>("Audio/TimerEnd").CreateInstance(); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     private void OnCountdownStart(IReadOnlyTimer sender) |  | ||||||
|     { |  | ||||||
|         pongManager.Reset(); |  | ||||||
|         DisplayCountdown(timer); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     private void DisplayCountdown(ITicker sender) |  | ||||||
|     { |  | ||||||
|         tickSoundEffect?.Play(); |  | ||||||
|  |  | ||||||
|         if (label != null) |  | ||||||
|         { |  | ||||||
|             label.Text = $"{START_COUNTDOWN - timer.TickCounter}"; |  | ||||||
|             label.Color = new ColorRGBA(255, 255, 255, 255); |  | ||||||
|             if (tweenManager is not null) |  | ||||||
|                 label.Color.TweenColor(tweenManager, 1f, new ColorRGBA(255, 255, 255, 0), (x) => label.Color = x); |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     private void StartPong(IReadOnlyTimer sender) |  | ||||||
|     { |  | ||||||
|         startSoundEffect?.Play(); |  | ||||||
|         pongManager.Start(); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     void IPacketListenerServer<RequestStartPacket>.OnServerPacketArrived(IConnection sender, RequestStartPacket packet) |  | ||||||
|     { |  | ||||||
|         logger?.Log(this, $"{sender} requested start"); |  | ||||||
|  |  | ||||||
|         if (pongManager.IsGameInProgress) |  | ||||||
|         { |  | ||||||
|             logger?.Log(this, $"The game is already in progress"); |  | ||||||
|             return; |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         timer.Start(START_COUNTDOWN); |  | ||||||
|         networkServer?.SendToAll(packet); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     void IPacketListenerClient<RequestStartPacket>.OnClientPacketArrived(IConnection sender, RequestStartPacket packet) |  | ||||||
|     { |  | ||||||
|         logger?.Log(this, $"Server is starting the game"); |  | ||||||
|         timer.Start(START_COUNTDOWN - sender.Ping); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     private class RequestStartPacket : INetworkPacket; |  | ||||||
| } |  | ||||||
| @@ -1,154 +0,0 @@ | |||||||
| using System; |  | ||||||
|  |  | ||||||
| using Microsoft.Xna.Framework.Audio; |  | ||||||
| using Microsoft.Xna.Framework.Content; |  | ||||||
|  |  | ||||||
| using Engine.Core; |  | ||||||
| using Engine.Core.Debug; |  | ||||||
| using Engine.Integration.MonoGame; |  | ||||||
| using Engine.Systems.Network; |  | ||||||
|  |  | ||||||
| namespace Pong.Behaviours; |  | ||||||
|  |  | ||||||
| public class PongManager : Behaviour, INetworkEntity, IFirstFrameUpdate, ILoadContent, |  | ||||||
|     IPacketListenerClient<PongManager.StartPacket>, |  | ||||||
|     IPacketListenerClient<PongManager.ScorePacket> |  | ||||||
| { |  | ||||||
|     public Action<PongManager>? OnReset { get; set; } = null; |  | ||||||
|     public Action<PongManager>? OnFinished { get; set; } = null; |  | ||||||
|     public Action<PongManager>? OnScoreUpdated { get; set; } = null; |  | ||||||
|  |  | ||||||
|     private Random random = new(); |  | ||||||
|  |  | ||||||
|     private INetworkCommunicatorServer? networkServer = null; |  | ||||||
|     private ILogger? logger = null; |  | ||||||
|     private SoundEffectInstance? scoreSoundEffect = null; |  | ||||||
|     private SoundEffectInstance? gameEndSoundEffect = null; |  | ||||||
|  |  | ||||||
|     public int ScoreLeft { get; private set; } = 0; |  | ||||||
|     public int ScoreRight { get; private set; } = 0; |  | ||||||
|     public int ScoreSum => ScoreLeft + ScoreRight; |  | ||||||
|  |  | ||||||
|     public int WinScore { get; } = 5; |  | ||||||
|     public Ball Ball { get; private set; } = null!; |  | ||||||
|     public bool IsGameInProgress { get; private set; } = false; |  | ||||||
|  |  | ||||||
|     public PongManager() => WinScore = 5; |  | ||||||
|     public PongManager(int winScore) => WinScore = winScore; |  | ||||||
|  |  | ||||||
|     public void FirstActiveFrame() |  | ||||||
|     { |  | ||||||
|         Ball = Universe.FindRequiredBehaviour<Ball>(); |  | ||||||
|         networkServer = Universe.FindBehaviour<INetworkCommunicatorServer>(); |  | ||||||
|         logger = Universe.FindBehaviour<ILogger>(); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     public void LoadContent(ContentManager content) |  | ||||||
|     { |  | ||||||
|         gameEndSoundEffect = content.Load<SoundEffect>("Audio/Win").CreateInstance(); |  | ||||||
|         scoreSoundEffect = content.Load<SoundEffect>("Audio/Score").CreateInstance(); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     public void ScoreToLeft() |  | ||||||
|     { |  | ||||||
|         ScoreLeft++; |  | ||||||
|         PostScoreUpdate(); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     public void ScoreToRight() |  | ||||||
|     { |  | ||||||
|         ScoreRight++; |  | ||||||
|         PostScoreUpdate(); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     public bool Start() |  | ||||||
|     { |  | ||||||
|         if (networkServer is null) |  | ||||||
|             return false; |  | ||||||
|  |  | ||||||
|         if (Ball.RigidBody.Velocity.MagnitudeSquared > 0.01f) |  | ||||||
|             return false; |  | ||||||
|  |  | ||||||
|         Reset(); |  | ||||||
|         IsGameInProgress = true; |  | ||||||
|         PostScoreUpdate(); |  | ||||||
|         networkServer.SendToAll(new StartPacket()); |  | ||||||
|         logger?.Log(this, $"Game started"); |  | ||||||
|         return true; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     public void Reset() |  | ||||||
|     { |  | ||||||
|         ScoreLeft = ScoreRight = 0; |  | ||||||
|         IsGameInProgress = false; |  | ||||||
|  |  | ||||||
|         Ball.ResetBall(); |  | ||||||
|  |  | ||||||
|         OnReset?.Invoke(this); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     private void PostScoreUpdate() |  | ||||||
|     { |  | ||||||
|         OnScoreUpdated?.Invoke(this); |  | ||||||
|         Ball.ResetBall(); |  | ||||||
|  |  | ||||||
|         if (networkServer is not null) |  | ||||||
|         { |  | ||||||
|             networkServer.SendToAll(new ScorePacket(this)); |  | ||||||
|             logger?.Log(this, $"Sending score update packet to all: {ScoreLeft} - {ScoreRight}"); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         int halfwayScore = (int)(WinScore * .5f); |  | ||||||
|         if (ScoreLeft > halfwayScore || ScoreRight > halfwayScore) |  | ||||||
|         { |  | ||||||
|             IsGameInProgress = false; |  | ||||||
|             gameEndSoundEffect?.Play(); |  | ||||||
|             OnFinished?.Invoke(this); |  | ||||||
|             logger?.Log(this, $"Game finished: {ScoreLeft} - {ScoreRight}"); |  | ||||||
|             return; |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         Ball.LaunchBall(GetBallLaunchDirection()); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     private Vector2D GetBallLaunchDirection() |  | ||||||
|     { |  | ||||||
|         const float AllowedRadians = 45f * Engine.Core.Math.DegreeToRadian; |  | ||||||
|         float rotation = (float)random.NextDouble() * 2f * AllowedRadians - AllowedRadians; |  | ||||||
|         bool isBackwards = (random.Next() % 2) == 1; |  | ||||||
|         return Vector2D.Right.Rotate(isBackwards ? rotation + Engine.Core.Math.Pi : rotation); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     void IPacketListenerClient<ScorePacket>.OnClientPacketArrived(IConnection sender, ScorePacket packet) |  | ||||||
|     { |  | ||||||
|         ScoreLeft = packet.Left; |  | ||||||
|         ScoreRight = packet.Right; |  | ||||||
|  |  | ||||||
|         PostScoreUpdate(); |  | ||||||
|  |  | ||||||
|         if (IsGameInProgress && (ScoreLeft != 0 || ScoreRight != 0)) |  | ||||||
|             scoreSoundEffect?.Play(); |  | ||||||
|  |  | ||||||
|         logger?.Log(this, $"Client score update packet arrived: {packet.Left} - {packet.Right}"); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     void IPacketListenerClient<StartPacket>.OnClientPacketArrived(IConnection sender, StartPacket packet) |  | ||||||
|     { |  | ||||||
|         IsGameInProgress = true; |  | ||||||
|         logger?.Log(this, $"Game started"); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     private class StartPacket : INetworkPacket; |  | ||||||
|     private class ScorePacket : INetworkPacket |  | ||||||
|     { |  | ||||||
|         public int Left { get; set; } |  | ||||||
|         public int Right { get; set; } |  | ||||||
|  |  | ||||||
|         public ScorePacket() { } |  | ||||||
|         public ScorePacket(PongManager pongManagerBehaviour) |  | ||||||
|         { |  | ||||||
|             Left = pongManagerBehaviour.ScoreLeft; |  | ||||||
|             Right = pongManagerBehaviour.ScoreRight; |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @@ -1,28 +0,0 @@ | |||||||
| using Engine.Core; |  | ||||||
|  |  | ||||||
| namespace Pong.Behaviours; |  | ||||||
|  |  | ||||||
| public class ScoreLabel(bool IsLeft) : Label, IFirstFrameUpdate |  | ||||||
| { |  | ||||||
|     public readonly bool IsLeft = IsLeft; |  | ||||||
|  |  | ||||||
|     private PongManager pongManager = null!; |  | ||||||
|  |  | ||||||
|     public void FirstActiveFrame() |  | ||||||
|     { |  | ||||||
|         pongManager = Universe.FindRequiredBehaviour<PongManager>(); |  | ||||||
|  |  | ||||||
|         pongManager.OnScoreUpdated += UpdateScores; |  | ||||||
|         pongManager.OnReset += UpdateScores; |  | ||||||
|  |  | ||||||
|         UpdateScores(pongManager); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     private void UpdateScores(PongManager pongManager) |  | ||||||
|     { |  | ||||||
|         if (IsLeft) |  | ||||||
|             Text = pongManager.ScoreLeft.ToString(); |  | ||||||
|         else |  | ||||||
|             Text = pongManager.ScoreRight.ToString(); |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @@ -1,19 +0,0 @@ | |||||||
| using System; |  | ||||||
|  |  | ||||||
| using Engine.Core; |  | ||||||
| using Engine.Physics2D; |  | ||||||
|  |  | ||||||
| namespace Pong.Behaviours; |  | ||||||
|  |  | ||||||
| public class ScoreWall(Action OnCollision) : Behaviour2D, IFirstFrameUpdate |  | ||||||
| { |  | ||||||
|     private Action OnCollision { get; } = OnCollision; |  | ||||||
|  |  | ||||||
|     public void FirstActiveFrame() |  | ||||||
|     { |  | ||||||
|         if (!BehaviourController.TryGetBehaviour(out ICollider2D? collider2D)) |  | ||||||
|             return; |  | ||||||
|  |  | ||||||
|         collider2D.OnCollisionDetected.AddListener((_, _1) => OnCollision?.Invoke()); |  | ||||||
|     } |  | ||||||
| } |  | ||||||
										
											Binary file not shown.
										
									
								
							
										
											Binary file not shown.
										
									
								
							
										
											Binary file not shown.
										
									
								
							
										
											Binary file not shown.
										
									
								
							
										
											Binary file not shown.
										
									
								
							
										
											Binary file not shown.
										
									
								
							| @@ -1,128 +0,0 @@ | |||||||
| using System; |  | ||||||
|  |  | ||||||
| using Microsoft.Xna.Framework.Input; |  | ||||||
|  |  | ||||||
| using Pong.Behaviours; |  | ||||||
|  |  | ||||||
| using Engine.Core; |  | ||||||
| using Engine.Core.Factory; |  | ||||||
| using Engine.Integration.MonoGame; |  | ||||||
| using Engine.Systems.Network; |  | ||||||
| using Engine.Physics2D; |  | ||||||
| using Engine.Systems.Tween; |  | ||||||
|  |  | ||||||
| namespace Pong; |  | ||||||
|  |  | ||||||
| public static class PongUniverse |  | ||||||
| { |  | ||||||
|     public static IUniverse ApplyPongClient(Universe universe, string server, int port) |  | ||||||
|     { |  | ||||||
|         LiteNetLibClient client = universe.InstantiateUniverseObject().SetUniverseObject("Client").BehaviourController.AddBehaviour<LiteNetLibClient>(); |  | ||||||
|         client.BehaviourController.AddBehaviour<NetworkManager>(); |  | ||||||
|         universe.OnPreUpdate.AddOneTimeListener((_, _) => client.Connect(server, port)); |  | ||||||
|  |  | ||||||
|         DrawManager drawManager = universe.InstantiateUniverseObject().SetUniverseObject("Draw Manager").BehaviourController.AddBehaviour<DrawManager>(); |  | ||||||
|         universe.InstantiateUniverseObject().SetUniverseObject("Triangle Batcher", drawManager.UniverseObject).BehaviourController.AddBehaviour<TriangleBatcher>(); |  | ||||||
|         universe.InstantiateUniverseObject().SetUniverseObject("Sprite Batcher", drawManager.UniverseObject).BehaviourController.AddBehaviour<SpriteBatcher>(); |  | ||||||
|  |  | ||||||
|         //////////////////////////////////////////////////////////////////////////////////// |  | ||||||
|  |  | ||||||
|         universe.InstantiateUniverseObject().SetUniverseObject("Camera") |  | ||||||
|             .BehaviourController.AddBehaviour<Transform2D>() |  | ||||||
|             .BehaviourController.AddBehaviour<CameraController>() |  | ||||||
|             .BehaviourController.AddBehaviour<MonoGameCamera2D>(); |  | ||||||
|  |  | ||||||
|         //////////////////////////////////////////////////////////////////////////////////// |  | ||||||
|  |  | ||||||
|         universe.InstantiateUniverseObject().SetUniverseObject("Score Left") |  | ||||||
|             .BehaviourController.AddBehaviour<Transform2D>().SetTransform(position: new Vector2D(-250f, 250f), scale: Vector2D.One * .25f) |  | ||||||
|             .BehaviourController.AddBehaviour<ScoreLabel>(true); |  | ||||||
|  |  | ||||||
|         universe.InstantiateUniverseObject().SetUniverseObject("Score Right") |  | ||||||
|             .BehaviourController.AddBehaviour<Transform2D>().SetTransform(position: new Vector2D(250f, 250f), scale: Vector2D.One * .25f) |  | ||||||
|             .BehaviourController.AddBehaviour<ScoreLabel>(false); |  | ||||||
|  |  | ||||||
|         return universe; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     public static IUniverse ApplyPongServer(Universe universe, int port) |  | ||||||
|     { |  | ||||||
|         LiteNetLibServer server = universe.InstantiateUniverseObject().SetUniverseObject("Server").BehaviourController.AddBehaviour<LiteNetLibServer>(); |  | ||||||
|         server.BehaviourController.AddBehaviour<NetworkManager>(); |  | ||||||
|         universe.OnPreUpdate.AddOneTimeListener((_, _) => server.Start(port, 2)); |  | ||||||
|  |  | ||||||
|         return universe; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     public static IUniverse ApplyPongUniverse(Universe universe) |  | ||||||
|     { |  | ||||||
|         universe.InstantiateUniverseObject().SetUniverseObject("Update Manager").BehaviourController.AddBehaviour<UpdateManager>(); |  | ||||||
|         universe.InstantiateUniverseObject().SetUniverseObject("Coroutine Manager").BehaviourController.AddBehaviour<CoroutineManager>(); |  | ||||||
|         universe.InstantiateUniverseObject().SetUniverseObject("Tween Manager").BehaviourController.AddBehaviour<TweenManager>(); |  | ||||||
|         universe.InstantiateUniverseObject().SetUniverseObject("Physics Engine 2D").BehaviourController.AddBehaviour<PhysicsEngine2D>(); |  | ||||||
|  |  | ||||||
|         //////////////////////////////////////////////////////////////////////////////////// |  | ||||||
|  |  | ||||||
|         PongManager pongManager = universe.InstantiateUniverseObject().SetUniverseObject("Pong Game Manager") |  | ||||||
|             .BehaviourController.AddBehaviour<PongManager>(5); |  | ||||||
|  |  | ||||||
|         universe.InstantiateUniverseObject().SetUniverseObject("Pong Game Starter", parent: pongManager.UniverseObject) |  | ||||||
|             .BehaviourController.AddBehaviour<PongGameStarter>() |  | ||||||
|             .BehaviourController.AddBehaviour<Transform2D>().SetTransform(position: new Vector2D(-24, 250f), scale: Vector2D.One * .5f) |  | ||||||
|             .BehaviourController.AddBehaviour<Label>(); |  | ||||||
|  |  | ||||||
|         //////////////////////////////////////////////////////////////////////////////////// |  | ||||||
|  |  | ||||||
|         universe.InstantiateUniverseObject().SetUniverseObject("Ball") |  | ||||||
|                 .BehaviourController.AddBehaviour<Transform2D>().SetTransform(position: new Vector2D(0, 0f), scale: new Vector2D(10f, 10f)) |  | ||||||
|                 .BehaviourController.AddBehaviour<DrawableColliderCircle>(new Circle(Vector2D.Zero, 1f)) |  | ||||||
|                 .BehaviourController.AddBehaviour<Ball>() |  | ||||||
|                 .BehaviourController.AddBehaviour<RigidBody2D>(); |  | ||||||
|  |  | ||||||
|         //////////////////////////////////////////////////////////////////////////////////// |  | ||||||
|  |  | ||||||
|         IUniverseObject leftPaddle = UniverseObjectFactory.Instantiate().SetUniverseObject("Left Paddle"); |  | ||||||
|         leftPaddle.BehaviourController.AddBehaviour<Transform2D>().SetTransform(position: new Vector2D(-468f, 0f), scale: new Vector2D(15f, 60f)) |  | ||||||
|                 .BehaviourController.AddBehaviour<DrawableColliderShape>(Shape2D.Square) |  | ||||||
|                 .BehaviourController.AddBehaviour<RigidBody2D>().IsStatic = true; |  | ||||||
|         Paddle leftPaddleBehaviour = BehaviourFactory.Instantiate<Paddle>(Keys.W, Keys.S, 228f, -228f, 400f); |  | ||||||
|         leftPaddleBehaviour.Id = "lp"; |  | ||||||
|         leftPaddle.BehaviourController.AddBehaviour(leftPaddleBehaviour); |  | ||||||
|         universe.Register(leftPaddle); |  | ||||||
|  |  | ||||||
|         IUniverseObject rightPaddle = UniverseObjectFactory.Instantiate().SetUniverseObject("Right Paddle"); |  | ||||||
|         rightPaddle.BehaviourController.AddBehaviour<Transform2D>().SetTransform(position: new Vector2D(468f, 0f), scale: new Vector2D(15f, 60f)) |  | ||||||
|                 .BehaviourController.AddBehaviour<DrawableColliderShape>(Shape2D.Square) |  | ||||||
|                 .BehaviourController.AddBehaviour<RigidBody2D>().IsStatic = true; |  | ||||||
|         Paddle rightPaddleBehaviour = BehaviourFactory.Instantiate<Paddle>(Keys.Up, Keys.Down, 228f, -228f, 400f); |  | ||||||
|         rightPaddleBehaviour.Id = "rp"; |  | ||||||
|         rightPaddle.BehaviourController.AddBehaviour(rightPaddleBehaviour); |  | ||||||
|         universe.Register(rightPaddle); |  | ||||||
|  |  | ||||||
|         //////////////////////////////////////////////////////////////////////////////////// |  | ||||||
|  |  | ||||||
|         universe.InstantiateUniverseObject().SetUniverseObject("Wall Top") |  | ||||||
|             .BehaviourController.AddBehaviour<Transform2D>().SetTransform(position: new Vector2D(0f, 308f), scale: new Vector2D(552f, 20f)) |  | ||||||
|             .BehaviourController.AddBehaviour<DrawableColliderShape>(Shape2D.Square) |  | ||||||
|             .BehaviourController.AddBehaviour<RigidBody2D>().IsStatic = true; |  | ||||||
|  |  | ||||||
|         universe.InstantiateUniverseObject().SetUniverseObject("Wall Bottom") |  | ||||||
|             .BehaviourController.AddBehaviour<Transform2D>().SetTransform(position: new Vector2D(0f, -308f), scale: new Vector2D(552f, 20f)) |  | ||||||
|             .BehaviourController.AddBehaviour<DrawableColliderShape>(Shape2D.Square) |  | ||||||
|             .BehaviourController.AddBehaviour<RigidBody2D>().IsStatic = true; |  | ||||||
|  |  | ||||||
|         universe.InstantiateUniverseObject().SetUniverseObject("Wall Right") |  | ||||||
|             .BehaviourController.AddBehaviour<Transform2D>().SetTransform(position: new Vector2D(532f, 0f), scale: new Vector2D(20f, 328f)) |  | ||||||
|             .BehaviourController.AddBehaviour<ScoreWall>((Action)pongManager.ScoreToLeft) |  | ||||||
|             .BehaviourController.AddBehaviour<DrawableColliderShape>(Shape2D.Square) |  | ||||||
|             .BehaviourController.AddBehaviour<RigidBody2D>().IsStatic = true; |  | ||||||
|  |  | ||||||
|         universe.InstantiateUniverseObject().SetUniverseObject("Wall Left") |  | ||||||
|             .BehaviourController.AddBehaviour<Transform2D>().SetTransform(position: new Vector2D(-532f, 0f), scale: new Vector2D(20f, 328f)) |  | ||||||
|             .BehaviourController.AddBehaviour<ScoreWall>((Action)pongManager.ScoreToRight) |  | ||||||
|             .BehaviourController.AddBehaviour<DrawableColliderShape>(Shape2D.Square) |  | ||||||
|             .BehaviourController.AddBehaviour<RigidBody2D>().IsStatic = true; |  | ||||||
|  |  | ||||||
|         return universe; |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @@ -1,18 +0,0 @@ | |||||||
| <Project Sdk="Microsoft.NET.Sdk"> |  | ||||||
|   <PropertyGroup> |  | ||||||
|     <TargetFramework>net9.0</TargetFramework> |  | ||||||
|     <Nullable>enable</Nullable> |  | ||||||
|     <RootNamespace>Pong.Shared</RootNamespace> |  | ||||||
|     <AssemblyName>Pong.Shared</AssemblyName> |  | ||||||
|   </PropertyGroup> |  | ||||||
|   <ItemGroup> |  | ||||||
|     <PackageReference Include="MonoGame.Framework.DesktopGL" Version="3.8.2.1105"> |  | ||||||
|       <PrivateAssets>All</PrivateAssets> |  | ||||||
|     </PackageReference> |  | ||||||
|   </ItemGroup> |  | ||||||
|   <ItemGroup> |  | ||||||
|     <ProjectReference Include="../Engine/Engine/Engine.csproj" /> |  | ||||||
|     <ProjectReference Include="../Engine/Engine.Integration/Engine.Integration.MonoGame/Engine.Integration.MonoGame.csproj" /> |  | ||||||
|     <ProjectReference Include="../Engine/Engine.Integration/Engine.Integration.LiteNetLib/Engine.Integration.LiteNetLib.csproj" /> |  | ||||||
|   </ItemGroup> |  | ||||||
| </Project> |  | ||||||
		Reference in New Issue
	
	Block a user