Added Base Project
This commit is contained in:
@@ -0,0 +1,22 @@
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"AppSettings": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"ScreenResolution": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"x": { "type": "integer" },
|
||||
"y": { "type": "integer" }
|
||||
},
|
||||
"required": [ "x", "y" ]
|
||||
},
|
||||
"Fullscreen": { "type": "boolean" },
|
||||
"Log" : {"type": "boolean"}
|
||||
},
|
||||
"Required": [ "ScreenResolution", "Fullscreen", "Log" ]
|
||||
}
|
||||
},
|
||||
"Required" : ["AppSettings"]
|
||||
}
|
||||
@@ -0,0 +1,144 @@
|
||||
using Firebird2D.Logger;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using Newtonsoft.Json.Schema;
|
||||
using SFML.Window;
|
||||
using System.Text;
|
||||
|
||||
|
||||
namespace Firebird2D.Configuration
|
||||
{
|
||||
public class GameConfig
|
||||
{
|
||||
public VideoMode VideoMode { get { return _videoMode; } set { _videoMode = value; updateConfig(); } }
|
||||
|
||||
public bool FullScreen { get { return _fullScreen; } set { _fullScreen = value; updateConfig(); } }
|
||||
|
||||
public bool LogActive { get { return _logActive; } set { _logActive = value; GameLogger.logActive = value; updateConfig(); } }
|
||||
|
||||
private static readonly string ConfigSchema = "Configuration/ConfigurationSchema/ConfigSchema.json";
|
||||
|
||||
private static readonly string ConfigPath = "Configuration/GameConfig.json";
|
||||
|
||||
private IConfigurationBuilder _configurationBuilder;
|
||||
|
||||
private IConfigurationSection _configurationSection;
|
||||
|
||||
private VideoMode _videoMode;
|
||||
|
||||
private bool _fullScreen;
|
||||
|
||||
private bool _logActive;
|
||||
|
||||
public GameConfig() {
|
||||
CheckFile();
|
||||
LoadConfig();
|
||||
}
|
||||
|
||||
private void updateConfig()
|
||||
{
|
||||
if (_configurationBuilder != null)
|
||||
{
|
||||
_configurationSection["ScreenResolution:x"] = _videoMode.Width.ToString();
|
||||
_configurationSection["ScreenResolution:y"] = _videoMode.Height.ToString();
|
||||
_configurationSection["Fullscreen"] = _fullScreen.ToString();
|
||||
_configurationSection["Log"] = _logActive.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
private void LoadConfig()
|
||||
{
|
||||
_configurationBuilder = new ConfigurationBuilder().AddJsonFile(ConfigPath, false, true);
|
||||
_configurationSection = _configurationBuilder.Build().GetSection("AppSettings");
|
||||
|
||||
_videoMode = new VideoMode();
|
||||
|
||||
if (_configurationSection != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
_videoMode.Width = uint.Parse(_configurationSection["ScreenResolution:x"]);
|
||||
_videoMode.Height = uint.Parse(_configurationSection["ScreenResolution:y"]);
|
||||
_fullScreen = bool.Parse(_configurationSection["Fullscreen"]);
|
||||
_logActive = bool.Parse(_configurationSection["Log"]);
|
||||
GameLogger.logActive = _logActive;
|
||||
}
|
||||
catch(Exception ex)
|
||||
{
|
||||
GameLogger.Log("GameConfig", LogType.Error, ex.Message);
|
||||
File.Delete(ConfigPath);
|
||||
MakeConfigFile();
|
||||
LoadConfig();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
GameLogger.Log("GameConfig", LogType.Error, "The Config File Was Corrupted");
|
||||
File.Delete(ConfigPath);
|
||||
MakeConfigFile();
|
||||
LoadConfig();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void CheckFile()
|
||||
{
|
||||
if (File.Exists(ConfigPath))
|
||||
{
|
||||
string schemaJson = File.ReadAllText(ConfigSchema);
|
||||
JSchema schema = JSchema.Parse(schemaJson);
|
||||
string ConfigData = File.ReadAllText(ConfigPath);
|
||||
JObject json = JObject.Parse(ConfigData);
|
||||
|
||||
IList<string> validationErrors = [];
|
||||
|
||||
if (schema != null)
|
||||
{
|
||||
if (!json.IsValid(schema,out validationErrors)){
|
||||
|
||||
File.Delete(ConfigPath);
|
||||
MakeConfigFile();
|
||||
GameLogger.Log("GameConfig", LogType.Error, "The Config File Was Corrupted");
|
||||
foreach (string error in validationErrors)
|
||||
{
|
||||
GameLogger.Log("GameConfig", LogType.Error, error);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
MakeConfigFile();
|
||||
}
|
||||
}
|
||||
|
||||
private void MakeConfigFile()
|
||||
{
|
||||
VideoMode desktopMode = VideoMode.DesktopMode;
|
||||
|
||||
using (FileStream stream = File.Create(ConfigPath))
|
||||
{
|
||||
AddText(stream, "{" +
|
||||
" \"AppSettings\":{" +
|
||||
" \"ScreenResolution\": {" +
|
||||
string.Format(" \"x\": {0},", desktopMode.Width) +
|
||||
string.Format(" \"y\": {0}", desktopMode.Height) +
|
||||
" }," +
|
||||
" \"Fullscreen\": false," +
|
||||
" \"Log\": true," +
|
||||
" }" +
|
||||
"}"
|
||||
);
|
||||
stream.Close();
|
||||
}
|
||||
}
|
||||
|
||||
private static void AddText(FileStream fs, string value)
|
||||
{
|
||||
byte[] info = new UTF8Encoding(true).GetBytes(value);
|
||||
fs.Write(info, 0, info.Length);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,266 @@
|
||||
using SFML.System;
|
||||
using SFML.Window;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Firebird2D.Core
|
||||
{
|
||||
internal struct JoystickMapping
|
||||
{
|
||||
public uint joysticnumber;
|
||||
public uint buttonnumber;
|
||||
}
|
||||
|
||||
public static class InputMapper
|
||||
{
|
||||
private static Dictionary<Keyboard.Key, KeyboardHandler> KeyboardMapping = new Dictionary<Keyboard.Key, KeyboardHandler>();
|
||||
private static Dictionary<JoystickMapping, JoystickButtonHandler> JoystickButtonMapping = new Dictionary<JoystickMapping, JoystickButtonHandler>();
|
||||
private static Dictionary<Mouse.Button, MouseHandler> MouseButtonMapping = new Dictionary<Mouse.Button, MouseHandler>();
|
||||
|
||||
private static List<(Keyboard.Key, Keyboard.Key)> Keyremaps = new List<(Keyboard.Key, Keyboard.Key)>();
|
||||
private static List<(Mouse.Button, Mouse.Button)> MouseButtonremaps = new List<(Mouse.Button, Mouse.Button)>();
|
||||
private static List<(uint, uint, uint)> JoystickButtonremaps = new List<(uint, uint, uint)>();
|
||||
|
||||
public delegate void KeyboardHandler(Keyboard.Key key);
|
||||
public delegate void MouseHandler(Mouse.Button button);
|
||||
public delegate void JoystickButtonHandler(uint JoystickId, uint ButtonNumber);
|
||||
public delegate void JoystickAxisHandler(uint JoystickId, float x, float y, float z, float r, float u, float v);
|
||||
public delegate void JoystickHatHandler(uint JoystickId, float PovX, float PovY);
|
||||
public delegate void MouseCursorPositionhandler(Vector2i mousePosition);
|
||||
|
||||
public static event JoystickAxisHandler? JoystickAxisEvent;
|
||||
public static event JoystickHatHandler? JoystickHatEvent;
|
||||
public static event MouseCursorPositionhandler? MouseCursorPositionEvent;
|
||||
|
||||
public static void Map(KeyboardHandler Method, Keyboard.Key key)
|
||||
{
|
||||
KeyboardMapping.Add(key, Method);
|
||||
}
|
||||
|
||||
public static void Map(MouseHandler Method, Mouse.Button button)
|
||||
{
|
||||
MouseButtonMapping.Add(button, Method);
|
||||
}
|
||||
|
||||
public static void Map(JoystickButtonHandler Method, uint joysticknumber, uint buttonnumber)
|
||||
{
|
||||
JoystickMapping mapping = new JoystickMapping { joysticnumber = joysticknumber, buttonnumber = buttonnumber };
|
||||
JoystickButtonMapping.Add(mapping, Method);
|
||||
}
|
||||
|
||||
public static void Remap(Keyboard.Key key1, Keyboard.Key key2)
|
||||
{
|
||||
if (KeyboardMapping.ContainsKey(key2)) throw new ArgumentException("Key2 already exists");
|
||||
if (!KeyboardMapping.ContainsKey(key1)) throw new ArgumentException("Key1 not existing");
|
||||
var keyboardHandler = KeyboardMapping[key1];
|
||||
KeyboardMapping.Remove(key1);
|
||||
KeyboardMapping.Add(key2, keyboardHandler);
|
||||
if (!Keyremaps.Contains((key1, key2)))
|
||||
Keyremaps.Add((key1, key2));
|
||||
}
|
||||
|
||||
public static void Remap(Mouse.Button button1, Mouse.Button button2)
|
||||
{
|
||||
if (MouseButtonMapping.ContainsKey(button2)) throw new ArgumentException("Button2 already exists");
|
||||
if (!MouseButtonMapping.ContainsKey(button1)) throw new ArgumentException("Button1 not existing");
|
||||
var mouseHandler = MouseButtonMapping[button1];
|
||||
MouseButtonMapping.Remove(button1);
|
||||
MouseButtonMapping.Add(button2, mouseHandler);
|
||||
if (!MouseButtonremaps.Contains((button1, button2)))
|
||||
MouseButtonremaps.Add((button1, button2));
|
||||
}
|
||||
|
||||
public static void Remap(uint joysticknumber, uint buttonnumber1, uint buttonnumber2)
|
||||
{
|
||||
JoystickMapping mappOld = new JoystickMapping { joysticnumber = joysticknumber, buttonnumber = buttonnumber1 };
|
||||
JoystickMapping mappNew = new JoystickMapping { joysticnumber = joysticknumber, buttonnumber = buttonnumber2 };
|
||||
|
||||
if (JoystickButtonMapping.ContainsKey(mappNew)) throw new ArgumentException("Button2 already exists");
|
||||
if (!JoystickButtonMapping.ContainsKey(mappOld)) throw new ArgumentException("Button1 not existing");
|
||||
|
||||
var joystickHandler = JoystickButtonMapping[mappOld];
|
||||
JoystickButtonMapping.Remove(mappOld);
|
||||
JoystickButtonMapping.Add(mappNew, joystickHandler);
|
||||
|
||||
if (!JoystickButtonremaps.Contains((joysticknumber, buttonnumber1, buttonnumber2)))
|
||||
JoystickButtonremaps.Add((joysticknumber, buttonnumber1, buttonnumber2));
|
||||
}
|
||||
|
||||
public static void ClearRemappingLog()
|
||||
{
|
||||
JoystickButtonremaps.Clear();
|
||||
MouseButtonremaps.Clear();
|
||||
Keyremaps.Clear();
|
||||
}
|
||||
|
||||
public static async Task UpdateOrSafeRemapsAsync(string filepath)
|
||||
{
|
||||
if (string.IsNullOrEmpty(filepath)) throw new ArgumentException(nameof(filepath));
|
||||
|
||||
if (File.Exists(filepath))
|
||||
{
|
||||
await UpdateRemapsAsync(filepath);
|
||||
}
|
||||
else
|
||||
{
|
||||
string directoryName = Path.GetDirectoryName(filepath);
|
||||
if (directoryName != null) Directory.CreateDirectory(directoryName);
|
||||
await SafeRemapsAsync(new FileStream(filepath, FileMode.Create));
|
||||
}
|
||||
}
|
||||
|
||||
private static async Task SafeRemapsAsync(FileStream fileStream)
|
||||
{
|
||||
using (StreamWriter writer = new StreamWriter(fileStream))
|
||||
{
|
||||
writer.WriteLine("<KeyMappings>");
|
||||
foreach (var keyRemap in Keyremaps)
|
||||
{
|
||||
writer.WriteLine($"{keyRemap.Item1};{keyRemap.Item2}");
|
||||
}
|
||||
writer.WriteLine("</KeyMappings>");
|
||||
writer.WriteLine("<MouseMappings>");
|
||||
foreach (var mouseRemap in MouseButtonremaps)
|
||||
{
|
||||
writer.WriteLine($"{mouseRemap.Item1};{mouseRemap.Item2}");
|
||||
}
|
||||
writer.WriteLine("</MouseMappings>");
|
||||
writer.WriteLine("<JoystickMappings>");
|
||||
foreach (var joyRemap in JoystickButtonremaps)
|
||||
{
|
||||
writer.WriteLine($"{joyRemap.Item1};{joyRemap.Item2};{joyRemap.Item3}");
|
||||
}
|
||||
writer.WriteLine("</JoystickMappings>");
|
||||
writer.Flush();
|
||||
}
|
||||
await fileStream.FlushAsync();
|
||||
fileStream.Close();
|
||||
}
|
||||
|
||||
private static async Task UpdateRemapsAsync(string filepath)
|
||||
{
|
||||
string Filecontent = null;
|
||||
using (StreamReader reader = new StreamReader(filepath))
|
||||
{
|
||||
Filecontent = await reader.ReadToEndAsync();
|
||||
}
|
||||
|
||||
string[] keyRemaps = ExtractMappings(Filecontent, "<KeyMappings>", "</KeyMappings>");
|
||||
string[] mouseButtonRemaps = ExtractMappings(Filecontent, "<MouseMappings>", "</MouseMappings>");
|
||||
string[] joyButtonRemaps = ExtractMappings(Filecontent, "<JoystickMappings>", "</JoystickMappings>");
|
||||
|
||||
Keyremaps.InsertRange(0, keyRemaps.Select(k => ParseKeyMapping(k)).ToArray());
|
||||
MouseButtonremaps.InsertRange(0, mouseButtonRemaps.Select(m => ParseMouseMapping(m)).ToArray());
|
||||
JoystickButtonremaps.InsertRange(0, joyButtonRemaps.Select(j => ParseJoystickMapping(j)).ToArray());
|
||||
|
||||
using (var fileStream = new FileStream(filepath, FileMode.Create))
|
||||
{
|
||||
await SafeRemapsAsync(fileStream);
|
||||
}
|
||||
}
|
||||
|
||||
private static string[] ExtractMappings(string content, string startTag, string endTag)
|
||||
{
|
||||
int start = content.IndexOf(startTag) + startTag.Length;
|
||||
int end = content.IndexOf(endTag);
|
||||
if (start < 0 || end < 0)
|
||||
return new string[0]; // Falls das Tag nicht gefunden wurde
|
||||
|
||||
string mappings = content.Substring(start, end - start);
|
||||
return mappings.Split(new[] { Environment.NewLine }, StringSplitOptions.RemoveEmptyEntries);
|
||||
}
|
||||
|
||||
private static (Keyboard.Key, Keyboard.Key) ParseKeyMapping(string keyMapping)
|
||||
{
|
||||
var keys = keyMapping.Split(";");
|
||||
return (Enum.Parse<Keyboard.Key>(keys[0]), Enum.Parse<Keyboard.Key>(keys[1]));
|
||||
}
|
||||
|
||||
private static (Mouse.Button, Mouse.Button) ParseMouseMapping(string mouseMapping)
|
||||
{
|
||||
var buttons = mouseMapping.Split(";");
|
||||
return (Enum.Parse<Mouse.Button>(buttons[0]), Enum.Parse<Mouse.Button>(buttons[1]));
|
||||
}
|
||||
|
||||
private static (uint, uint, uint) ParseJoystickMapping(string joystickMapping)
|
||||
{
|
||||
var joyButtons = joystickMapping.Split(";");
|
||||
return (uint.Parse(joyButtons[0]), uint.Parse(joyButtons[1]), uint.Parse(joyButtons[2]));
|
||||
}
|
||||
|
||||
public static void revertLastKeyRemap()
|
||||
{
|
||||
if (Keyremaps.Any())
|
||||
{
|
||||
var lastKeyRemap = Keyremaps.Last();
|
||||
Keyremaps.Remove(lastKeyRemap);
|
||||
KeyboardMapping[lastKeyRemap.Item2] = KeyboardMapping[lastKeyRemap.Item1];
|
||||
}
|
||||
}
|
||||
|
||||
public static void revertLastMouseButtonRemap()
|
||||
{
|
||||
if (MouseButtonremaps.Any())
|
||||
{
|
||||
var lastMouseButtonRemap = MouseButtonremaps.Last();
|
||||
MouseButtonremaps.Remove(lastMouseButtonRemap);
|
||||
MouseButtonMapping[lastMouseButtonRemap.Item2] = MouseButtonMapping[lastMouseButtonRemap.Item1];
|
||||
}
|
||||
}
|
||||
|
||||
public static void revertLastJoystickButtonRemap()
|
||||
{
|
||||
if (JoystickButtonremaps.Any())
|
||||
{
|
||||
var lastJoystickButtonRemap = JoystickButtonremaps.Last();
|
||||
JoystickButtonremaps.Remove(lastJoystickButtonRemap);
|
||||
|
||||
var mappOld = new JoystickMapping { joysticnumber = lastJoystickButtonRemap.Item1, buttonnumber = lastJoystickButtonRemap.Item2 };
|
||||
var mappNew = new JoystickMapping { joysticnumber = lastJoystickButtonRemap.Item1, buttonnumber = lastJoystickButtonRemap.Item3 };
|
||||
|
||||
JoystickButtonMapping[mappNew] = JoystickButtonMapping[mappOld];
|
||||
JoystickButtonMapping.Remove(mappOld);
|
||||
}
|
||||
}
|
||||
|
||||
public static void HandleKeyboardInput(Keyboard.Key key)
|
||||
{
|
||||
if (KeyboardMapping.ContainsKey(key))
|
||||
{
|
||||
KeyboardMapping[key](key); // Event auslösen
|
||||
}
|
||||
}
|
||||
|
||||
public static void HandleMouseInput(Mouse.Button button)
|
||||
{
|
||||
if (MouseButtonMapping.ContainsKey(button))
|
||||
{
|
||||
MouseButtonMapping[button](button);
|
||||
}
|
||||
}
|
||||
|
||||
public static void HandleJoystickButtonInput(uint joystickId, uint buttonNumber)
|
||||
{
|
||||
var joymap = new JoystickMapping { buttonnumber = buttonNumber, joysticnumber = joystickId };
|
||||
if (JoystickButtonMapping.ContainsKey(joymap))
|
||||
{
|
||||
JoystickButtonMapping[joymap](joystickId, buttonNumber);
|
||||
}
|
||||
}
|
||||
|
||||
public static void HandleMouseMovement(Vector2i mouseposition)
|
||||
{
|
||||
MouseCursorPositionEvent?.Invoke(mouseposition);
|
||||
}
|
||||
|
||||
public static void HandleJoytickMove(uint JoystickId, float x, float y, float z, float r, float u, float v, float PovX, float PovY)
|
||||
{
|
||||
JoystickAxisEvent?.Invoke(JoystickId, x, y, z, r, u, v);
|
||||
JoystickHatEvent?.Invoke(JoystickId, PovX, PovY);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,104 @@
|
||||
using Firebird2D.SceneSystem;
|
||||
using SFML.Graphics;
|
||||
using SFML.System;
|
||||
using SFML.Window;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Security.Cryptography.X509Certificates;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Firebird2D.Core
|
||||
{
|
||||
public class MainWindow
|
||||
{
|
||||
private RenderWindow renderWindow;
|
||||
|
||||
private Clock clock = new Clock();
|
||||
|
||||
private List<uint> joyStickMovement = new List<uint>();
|
||||
|
||||
public Vector2u mainWindowSize { get; private set; }
|
||||
|
||||
internal I_Scene? ActiveSecene { set; get; }
|
||||
|
||||
public MainWindow(VideoMode resolution, string GameName, Styles style = Styles.Default)
|
||||
{
|
||||
renderWindow = new RenderWindow(resolution, GameName, style);
|
||||
|
||||
renderWindow.Closed += (sender, e) => renderWindow.Close();
|
||||
|
||||
renderWindow.Resized += RenderWindow_Resized;
|
||||
|
||||
mainWindowSize = renderWindow.Size;
|
||||
renderWindow.KeyPressed += RenderWindow_KeyPressed;
|
||||
renderWindow.JoystickButtonPressed += RenderWindow_JoystickButtonPressed;
|
||||
renderWindow.MouseButtonPressed += RenderWindow_MouseButtonPressed;
|
||||
renderWindow.MouseMoved += RenderWindow_MouseMoved;
|
||||
renderWindow.JoystickMoved += RenderWindow_JoystickMoved;
|
||||
}
|
||||
|
||||
private void RenderWindow_JoystickMoved(object? sender, JoystickMoveEventArgs e)
|
||||
{
|
||||
if(!joyStickMovement.Contains(e.JoystickId)) joyStickMovement.Add(e.JoystickId);
|
||||
}
|
||||
|
||||
private void RenderWindow_MouseMoved(object? sender, MouseMoveEventArgs e)
|
||||
{
|
||||
Vector2i mousposition = new Vector2i(e.X, e.Y);
|
||||
InputMapper.HandleMouseMovement(mousposition);
|
||||
}
|
||||
|
||||
private void RenderWindow_MouseButtonPressed(object? sender, MouseButtonEventArgs e)
|
||||
{
|
||||
InputMapper.HandleMouseInput(e.Button);
|
||||
}
|
||||
|
||||
private void RenderWindow_JoystickButtonPressed(object? sender, JoystickButtonEventArgs e)
|
||||
{
|
||||
InputMapper.HandleJoystickButtonInput(e.JoystickId, e.Button);
|
||||
}
|
||||
|
||||
private void RenderWindow_KeyPressed(object? sender, KeyEventArgs e)
|
||||
{
|
||||
InputMapper.HandleKeyboardInput(e.Code);
|
||||
}
|
||||
|
||||
private void RenderWindow_Resized(object? sender, SizeEventArgs e)
|
||||
{
|
||||
//throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public void Gameloop()
|
||||
{
|
||||
while (renderWindow.IsOpen)
|
||||
{
|
||||
int delteMiliseconds = clock.Restart().AsMilliseconds();
|
||||
|
||||
renderWindow.DispatchEvents();
|
||||
|
||||
renderWindow.Clear();
|
||||
|
||||
if (ActiveSecene != null)
|
||||
{
|
||||
foreach (uint joystickId in joyStickMovement)
|
||||
InputMapper.HandleJoytickMove(joystickId
|
||||
,Joystick.GetAxisPosition(joystickId,Joystick.Axis.X)
|
||||
, Joystick.GetAxisPosition(joystickId, Joystick.Axis.Y)
|
||||
, Joystick.GetAxisPosition(joystickId, Joystick.Axis.Z)
|
||||
, Joystick.GetAxisPosition(joystickId, Joystick.Axis.R)
|
||||
, Joystick.GetAxisPosition(joystickId, Joystick.Axis.U)
|
||||
, Joystick.GetAxisPosition(joystickId, Joystick.Axis.V)
|
||||
, Joystick.GetAxisPosition(joystickId, Joystick.Axis.PovX)
|
||||
, Joystick.GetAxisPosition(joystickId, Joystick.Axis.PovY));
|
||||
ActiveSecene.TickScene(delteMiliseconds);
|
||||
ActiveSecene.RenderScene(renderWindow);
|
||||
}
|
||||
|
||||
renderWindow.Display();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,133 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Firebird2D.Datatypes
|
||||
{
|
||||
|
||||
|
||||
public class AVL_Tree<T> : BinarySearchTree<T>
|
||||
{
|
||||
public AVL_Tree(IComparer<T> comparer) : base(comparer) { }
|
||||
|
||||
internal AVL_Tree(BinaryNode<T> node, IComparer<T> comparer) : base (node, comparer) {}
|
||||
|
||||
public new void InsertItem(T item)
|
||||
{
|
||||
InsertItem(item, ref root);
|
||||
}
|
||||
|
||||
private void InsertItem(T item, ref BinaryNode<T>? node)
|
||||
{
|
||||
if(node == null)
|
||||
{
|
||||
node = new BinaryNode<T>(item);
|
||||
}
|
||||
else if (Comparer.Compare(item,node.content) < 0)
|
||||
{
|
||||
InsertItem(item, ref node.left);
|
||||
}
|
||||
else if (Comparer.Compare(item, node.content) > 0)
|
||||
{
|
||||
InsertItem(item, ref node.right);
|
||||
}
|
||||
else
|
||||
{
|
||||
InsertItem(item, ref node.left);
|
||||
}
|
||||
balanceTree(ref node);
|
||||
}
|
||||
|
||||
public new void RemoveItem(T item)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
private void RemoveItem(T item, ref BinaryNode<T>? node)
|
||||
{
|
||||
if (node != null)
|
||||
{
|
||||
if(Comparer.Compare(item, node.content) < 0)
|
||||
{
|
||||
RemoveItem(item, ref node.left);
|
||||
}
|
||||
else if (Comparer.Compare(item, node.content) > 0)
|
||||
{
|
||||
RemoveItem(item, ref node.right);
|
||||
}
|
||||
else if (Comparer.Compare(item, node.content) == 0)
|
||||
{
|
||||
if (node.left == null)
|
||||
{
|
||||
node = node.right;
|
||||
}
|
||||
else if (node.right == null)
|
||||
{
|
||||
node = node.left;
|
||||
}
|
||||
else
|
||||
{
|
||||
T newRoot = leastItem(node.right);
|
||||
node.content = newRoot;
|
||||
RemoveItem(newRoot, ref node.right);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return;
|
||||
}
|
||||
balanceTree(ref node);
|
||||
}
|
||||
|
||||
private void balanceTree(ref BinaryNode<T> node)
|
||||
{
|
||||
if (node != null)
|
||||
{
|
||||
node.balanceFactor = height(node.left) - height(node.right);
|
||||
if(node.balanceFactor <= -2)
|
||||
{
|
||||
rotateLeft(ref node);
|
||||
}
|
||||
if(node.balanceFactor >= 2)
|
||||
{
|
||||
rotateRight(ref node);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void rotateLeft(ref BinaryNode<T> node)
|
||||
{
|
||||
if ( node.left.balanceFactor > 0)
|
||||
{
|
||||
rotateRight(ref node);
|
||||
}
|
||||
|
||||
BinaryNode<T> oldRoot = node;
|
||||
BinaryNode<T> newRoot = node.right;
|
||||
|
||||
oldRoot.right = newRoot.left;
|
||||
newRoot.left = oldRoot;
|
||||
|
||||
node = newRoot;
|
||||
}
|
||||
|
||||
private void rotateRight(ref BinaryNode<T> node)
|
||||
{
|
||||
if (node.left.balanceFactor < 0)
|
||||
{
|
||||
rotateLeft(ref node.left);
|
||||
}
|
||||
|
||||
BinaryNode<T> oldRoot = node;
|
||||
BinaryNode <T> newRoot = node.left;
|
||||
|
||||
oldRoot.left = newRoot.right;
|
||||
newRoot.right = oldRoot;
|
||||
|
||||
node = newRoot;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Firebird2D.Datatypes
|
||||
{
|
||||
internal class BinaryNode<T>
|
||||
{
|
||||
public T content;
|
||||
public int balanceFactor;
|
||||
public BinaryNode<T>? left;
|
||||
public BinaryNode<T>? right;
|
||||
|
||||
public BinaryNode(T item)
|
||||
{
|
||||
content = item;
|
||||
left = null;
|
||||
right = null;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,139 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Firebird2D.Datatypes
|
||||
{
|
||||
public class BinarySearchTree<T> : BinaryTree<T>
|
||||
{
|
||||
public int Height { get { return height(root); } }
|
||||
|
||||
protected readonly IComparer<T> Comparer;
|
||||
|
||||
public BinarySearchTree(IComparer<T> comparer)
|
||||
{
|
||||
root = null;
|
||||
Comparer = comparer;
|
||||
}
|
||||
|
||||
internal BinarySearchTree(BinaryNode<T> node, IComparer<T> comparer)
|
||||
{
|
||||
root = node;
|
||||
Comparer = comparer;
|
||||
}
|
||||
|
||||
public void InsertItem(T item)
|
||||
{
|
||||
InsertItem(item, ref root);
|
||||
}
|
||||
|
||||
private void InsertItem(T item, ref BinaryNode<T>? node)
|
||||
{
|
||||
if (node == null)
|
||||
{
|
||||
node = new BinaryNode<T>(item);
|
||||
}
|
||||
else if(Comparer.Compare(item, node.content) < 0)
|
||||
{
|
||||
InsertItem(item, ref node.left);
|
||||
}
|
||||
else if(Comparer.Compare(item, node.content) > 0)
|
||||
{
|
||||
InsertItem(item, ref node.right);
|
||||
}
|
||||
}
|
||||
|
||||
internal int height(BinaryNode<T>? tree)
|
||||
{
|
||||
if(tree == null)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
return 1 + Math.Max(height(tree.left), height(tree.right));
|
||||
}
|
||||
}
|
||||
|
||||
public bool Contains(T item)
|
||||
{
|
||||
return Contains(item, root);
|
||||
}
|
||||
|
||||
private bool Contains(T item, BinaryNode<T>? node)
|
||||
{
|
||||
if(node != null)
|
||||
{
|
||||
if(item.Equals(node.content))
|
||||
return true;
|
||||
if(Comparer.Compare(item, node.content) < 0)
|
||||
{
|
||||
return Contains(item, node.left);
|
||||
}
|
||||
else
|
||||
{
|
||||
return Contains(item, node.right);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public void RemoveItem(T item)
|
||||
{
|
||||
RemoveItem(item, ref root);
|
||||
}
|
||||
|
||||
private void RemoveItem(T item, ref BinaryNode<T>? node)
|
||||
{
|
||||
if (node == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
else if (Comparer.Compare(item, node.content) < 0)
|
||||
{
|
||||
RemoveItem(item, ref node.left);
|
||||
}
|
||||
else if (Comparer.Compare(item, node.content) > 0)
|
||||
{
|
||||
RemoveItem(item, ref node.right);
|
||||
}
|
||||
|
||||
if (item.Equals(node.content))
|
||||
{
|
||||
if(node.left == null)
|
||||
{
|
||||
node = node.right;
|
||||
}
|
||||
else if (node.right == null)
|
||||
{
|
||||
node = node.left;
|
||||
}
|
||||
else
|
||||
{
|
||||
T newRoot = leastItem(node.right);
|
||||
node.content = newRoot;
|
||||
RemoveItem(newRoot, ref node.right );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal T leastItem(BinaryNode<T> node)
|
||||
{
|
||||
if(node.left == null)
|
||||
{
|
||||
return node.content;
|
||||
}
|
||||
else
|
||||
{
|
||||
return leastItem(node.left);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,137 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics.Metrics;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Firebird2D.Datatypes
|
||||
{
|
||||
public abstract class BinaryTree<T>
|
||||
{
|
||||
internal BinaryNode<T> root = null;
|
||||
|
||||
public int Count { get {
|
||||
int counter = 0;
|
||||
count(root, ref counter);
|
||||
return counter;
|
||||
} }
|
||||
|
||||
public T[]? InOrder()
|
||||
{
|
||||
if (root == null)
|
||||
return Array.Empty<T>();
|
||||
|
||||
List<T> result = new();
|
||||
Stack<BinaryNode<T>> stack = new();
|
||||
BinaryNode<T>? current = root;
|
||||
|
||||
while (current != null || stack.Count > 0)
|
||||
{
|
||||
// Gehe nach links, so weit wie möglich
|
||||
while (current != null)
|
||||
{
|
||||
stack.Push(current);
|
||||
current = current.left;
|
||||
}
|
||||
|
||||
// Knoten aus dem Stack holen
|
||||
current = stack.Pop();
|
||||
result.Add(current.content);
|
||||
|
||||
// Gehe nach rechts
|
||||
current = current.right;
|
||||
}
|
||||
|
||||
return result.ToArray();
|
||||
}
|
||||
|
||||
public T[]? PreOrder()
|
||||
{
|
||||
if (root == null)
|
||||
return Array.Empty<T>();
|
||||
|
||||
List<T> result = new();
|
||||
Stack<BinaryNode<T>> stack = new();
|
||||
stack.Push(root);
|
||||
|
||||
while (stack.Count > 0)
|
||||
{
|
||||
// Knoten aus dem Stack holen
|
||||
var current = stack.Pop();
|
||||
result.Add(current.content);
|
||||
|
||||
// Zuerst den rechten Knoten hinzufügen (wird später bearbeitet)
|
||||
if (current.right != null)
|
||||
stack.Push(current.right);
|
||||
|
||||
// Dann den linken Knoten hinzufügen
|
||||
if (current.left != null)
|
||||
stack.Push(current.left);
|
||||
}
|
||||
|
||||
return result.ToArray();
|
||||
}
|
||||
|
||||
public T[]? PostOrder()
|
||||
{
|
||||
if (root == null)
|
||||
return Array.Empty<T>();
|
||||
|
||||
List<T> result = new();
|
||||
Stack<BinaryNode<T>> stack1 = new();
|
||||
Stack<BinaryNode<T>> stack2 = new();
|
||||
stack1.Push(root);
|
||||
|
||||
while (stack1.Count > 0)
|
||||
{
|
||||
// Knoten aus dem ersten Stack holen
|
||||
var current = stack1.Pop();
|
||||
stack2.Push(current);
|
||||
|
||||
// Linken und rechten Knoten in den ersten Stack schieben
|
||||
if (current.left != null)
|
||||
stack1.Push(current.left);
|
||||
if (current.right != null)
|
||||
stack1.Push(current.right);
|
||||
}
|
||||
|
||||
// Ergebnis aus dem zweiten Stack lesen (umgekehrte Reihenfolge)
|
||||
while (stack2.Count > 0)
|
||||
{
|
||||
result.Add(stack2.Pop().content);
|
||||
}
|
||||
|
||||
return result.ToArray();
|
||||
}
|
||||
|
||||
public void Copy(BinaryTree<T> tree2)
|
||||
{
|
||||
Copy(ref root, tree2.root);
|
||||
}
|
||||
|
||||
private void Copy(ref BinaryNode<T>? tree, BinaryNode<T>? tree2)
|
||||
{
|
||||
if(tree == null && tree2 != null)
|
||||
{
|
||||
tree = new BinaryNode<T>(tree2.content);
|
||||
}
|
||||
if(tree != null && tree2 != null)
|
||||
{
|
||||
tree.content = tree2.content;
|
||||
Copy(ref tree.left, tree2.left);
|
||||
Copy(ref tree.right, tree2.right);
|
||||
}
|
||||
}
|
||||
|
||||
private void count(BinaryNode<T>? tree, ref int counter)
|
||||
{
|
||||
if (root != null)
|
||||
{
|
||||
counter++;
|
||||
count(tree.left, ref counter);
|
||||
count(tree.right, ref counter);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
using SFML.Graphics;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Firebird2D.Datatypes
|
||||
{
|
||||
public interface ISpatial
|
||||
{
|
||||
public FloatRect Bounds { get; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,257 @@
|
||||
using Firebird2D.Requirement;
|
||||
using SFML.Graphics;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using Firebird2D.SFMLExtensions;
|
||||
using System.Drawing;
|
||||
using SFML.System;
|
||||
using System.Collections;
|
||||
|
||||
namespace Firebird2D.Datatypes
|
||||
{
|
||||
public class Quadtree<T> where T : ISpatial
|
||||
{
|
||||
private readonly List<T> _elements = [];
|
||||
|
||||
private readonly int _bucketCapacity;
|
||||
|
||||
private readonly int _maxDepth;
|
||||
|
||||
private Quadtree<T>? _topLeft, _topRight, _bottomLeft, _bottomRight;
|
||||
|
||||
public FloatRect Bounds { get; }
|
||||
|
||||
public int Level { get; init; }
|
||||
|
||||
[MemberNotNullWhen(false, nameof(_topLeft), nameof(_topRight), nameof(_bottomLeft), nameof(_bottomRight))]
|
||||
public bool IsLeaf
|
||||
=> _topLeft == null || _topRight == null || _bottomLeft == null || _bottomRight == null;
|
||||
|
||||
public bool AllowOutOfBounds { get; set; }
|
||||
|
||||
public Quadtree(FloatRect bounds, int bucketCapacity, int maxDepth)
|
||||
{
|
||||
Bounds = bounds;
|
||||
_bucketCapacity = bucketCapacity;
|
||||
_maxDepth = maxDepth;
|
||||
}
|
||||
|
||||
public Quadtree(FloatRect bounds): this(bounds,32,5) { }
|
||||
|
||||
public void Insert(T element)
|
||||
{
|
||||
Require.NotNull(element, nameof(element));
|
||||
|
||||
if (!(Bounds.Contains(element.Bounds) || AllowOutOfBounds))
|
||||
throw new ArgumentException(string.Format("{0} is out of Quadtreebounds", nameof(element)), nameof(element));
|
||||
|
||||
if (_elements.Count >= _bucketCapacity)
|
||||
Split();
|
||||
|
||||
Quadtree<T>? containingChild = GetContainingChild(element.Bounds);
|
||||
|
||||
if (containingChild != null)
|
||||
{
|
||||
containingChild.Insert(element);
|
||||
}
|
||||
else
|
||||
{
|
||||
_elements.Add(element);
|
||||
}
|
||||
}
|
||||
|
||||
public bool Remove(T element)
|
||||
{
|
||||
Require.NotNull(element, nameof(element));
|
||||
|
||||
Quadtree<T>? containingChild = GetContainingChild(element.Bounds);
|
||||
|
||||
bool removed = containingChild?.Remove(element) ?? _elements.Remove(element);
|
||||
|
||||
if (removed && CountElements() <= _bucketCapacity)
|
||||
Merge();
|
||||
|
||||
return removed;
|
||||
}
|
||||
|
||||
public int CountElements()
|
||||
{
|
||||
int count = _elements.Count;
|
||||
if(!IsLeaf)
|
||||
{
|
||||
count += _topLeft.CountElements();
|
||||
count += _topRight.CountElements();
|
||||
count += _bottomLeft.CountElements();
|
||||
count += _bottomRight.CountElements();
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
public IEnumerable<T> GetElements()
|
||||
{
|
||||
List<T> children = new();
|
||||
Queue<Quadtree<T>> nodes = new Queue<Quadtree<T>>();
|
||||
|
||||
nodes.Enqueue(this);
|
||||
|
||||
while (nodes.Count > 0)
|
||||
{
|
||||
Quadtree<T> node = nodes.Dequeue();
|
||||
|
||||
if (!node.IsLeaf)
|
||||
{
|
||||
nodes.Enqueue(node._topLeft);
|
||||
nodes.Enqueue(node._topRight);
|
||||
nodes.Enqueue(node._bottomLeft);
|
||||
nodes.Enqueue(node._bottomRight);
|
||||
}
|
||||
|
||||
children.AddRange(node._elements);
|
||||
}
|
||||
|
||||
return children;
|
||||
}
|
||||
|
||||
private void Split()
|
||||
{
|
||||
if (!IsLeaf)
|
||||
return;
|
||||
|
||||
if (Level + 1 > _maxDepth)
|
||||
return;
|
||||
|
||||
_topLeft = CreateChild(Bounds.Location());
|
||||
_topRight = CreateChild(new Vector2f(Bounds.Center().X, Bounds.Location().Y));
|
||||
_bottomLeft = CreateChild(new Vector2f(Bounds.Location().X, Bounds.Center().Y));
|
||||
_bottomRight = CreateChild(Bounds.Center());
|
||||
|
||||
List<T> elements = _elements.ToList();
|
||||
|
||||
foreach (T element in elements)
|
||||
{
|
||||
Quadtree<T>? containingChild = GetContainingChild(element.Bounds);
|
||||
|
||||
if (containingChild != null)
|
||||
{
|
||||
_elements.Remove(element);
|
||||
|
||||
containingChild.Insert(element);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private Quadtree<T> CreateChild(Vector2f location)
|
||||
=> new(new FloatRect(location, Bounds.Size / 2), _bucketCapacity, _maxDepth) { Level = Level + 1 };
|
||||
|
||||
private void Merge()
|
||||
{
|
||||
if (IsLeaf)
|
||||
return;
|
||||
|
||||
_elements.AddRange(_topLeft._elements);
|
||||
_elements.AddRange(_topRight._elements);
|
||||
_elements.AddRange(_bottomLeft._elements);
|
||||
_elements.AddRange(_bottomRight._elements);
|
||||
|
||||
_topLeft = _topRight = _bottomLeft = _bottomRight = null;
|
||||
}
|
||||
|
||||
private Quadtree<T>? GetContainingChild(FloatRect bounds)
|
||||
{
|
||||
if (IsLeaf)
|
||||
return null;
|
||||
|
||||
if(_topLeft.Bounds.Contains(bounds))
|
||||
return _topLeft;
|
||||
|
||||
if (_topRight.Bounds.Contains(bounds))
|
||||
return _topRight;
|
||||
|
||||
if (_bottomLeft.Bounds.Contains(bounds))
|
||||
return _bottomLeft;
|
||||
|
||||
if (_bottomRight.Bounds.Contains(bounds))
|
||||
return _bottomRight;
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public IEnumerable<T> FindCollisions(T element)
|
||||
{
|
||||
Require.NotNull(element, nameof(element));
|
||||
|
||||
var nodes = new Queue<Quadtree<T>>();
|
||||
var collisions = new List<T>();
|
||||
|
||||
nodes.Enqueue(this);
|
||||
|
||||
while (nodes.Count > 0)
|
||||
{
|
||||
var node = nodes.Dequeue();
|
||||
|
||||
if (!element.Bounds.Intersects(node.Bounds))
|
||||
continue;
|
||||
|
||||
collisions.AddRange(node._elements.Where(e => e.Bounds.Intersects(element.Bounds)));
|
||||
|
||||
if (!node.IsLeaf)
|
||||
{
|
||||
if (element.Bounds.Intersects(node._topLeft.Bounds))
|
||||
nodes.Enqueue(node._topLeft);
|
||||
|
||||
if (element.Bounds.Intersects(node._topRight.Bounds))
|
||||
nodes.Enqueue(node._topRight);
|
||||
|
||||
if (element.Bounds.Intersects(node._bottomLeft.Bounds))
|
||||
nodes.Enqueue(node._bottomLeft);
|
||||
|
||||
if (element.Bounds.Intersects(node._bottomRight.Bounds))
|
||||
nodes.Enqueue(node._bottomRight);
|
||||
}
|
||||
}
|
||||
|
||||
return collisions;
|
||||
}
|
||||
|
||||
public IEnumerable<T> FindInRegion(FloatRect region)
|
||||
{
|
||||
var results = new List<T>();
|
||||
var stack = new Stack<Quadtree<T>>();
|
||||
stack.Push(this);
|
||||
|
||||
while (stack.Count > 0)
|
||||
{
|
||||
var node = stack.Pop();
|
||||
|
||||
if (!node.Bounds.Intersects(region))
|
||||
continue;
|
||||
|
||||
results.AddRange(node._elements.Where(e => region.Intersects(e.Bounds)));
|
||||
|
||||
if (!node.IsLeaf)
|
||||
{
|
||||
stack.Push(node._topLeft);
|
||||
stack.Push(node._topRight);
|
||||
stack.Push(node._bottomLeft);
|
||||
stack.Push(node._bottomRight);
|
||||
}
|
||||
}
|
||||
|
||||
return results;
|
||||
}
|
||||
|
||||
public AVL_Tree<T> FindInRegionAVL(FloatRect region, IComparer<T> comparer)
|
||||
{
|
||||
List<T> values = (List<T>)FindInRegion(region);
|
||||
AVL_Tree<T> returnTree = new(comparer);
|
||||
foreach (T elment in values)
|
||||
{
|
||||
returnTree.InsertItem(elment);
|
||||
}
|
||||
|
||||
return returnTree;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration" Version="9.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="9.0.0" />
|
||||
<PackageReference Include="Newtonsoft.Json.Schema" Version="4.0.1" />
|
||||
<PackageReference Include="SFML.Net" Version="2.6.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Firebird2D.Logger\Firebird2D.Logger.csproj" />
|
||||
<ProjectReference Include="..\Firebird2D.Requirement\Firebird2D.Requirement.csproj" />
|
||||
<ProjectReference Include="..\Firebird2D.SFMLExtensions\Firebird2D.SFMLExtensions.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Update="Configuration\ConfigurationSchema\ConfigSchema.json">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
@@ -0,0 +1,40 @@
|
||||
using SFML.Graphics;
|
||||
using SFML.Window;
|
||||
using SFML.System;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using System.Text;
|
||||
using Firebird2D.Core;
|
||||
using Firebird2D.Configuration;
|
||||
using Firebird2D.Logger;
|
||||
using Firebird2D.SceneSystem;
|
||||
|
||||
namespace Firebird2D
|
||||
{
|
||||
public static class GameSystem
|
||||
{
|
||||
|
||||
public static MainWindow? mainWindow {get; private set;}
|
||||
|
||||
public static GameConfig gameConfig = new GameConfig();
|
||||
|
||||
static void Main(string[] args)
|
||||
{
|
||||
GameLogger.Initalize();
|
||||
|
||||
if (VideoMode.DesktopMode.Width < gameConfig.VideoMode.Width || VideoMode.DesktopMode.Height < gameConfig.VideoMode.Height)
|
||||
{
|
||||
gameConfig.VideoMode = VideoMode.DesktopMode;
|
||||
}
|
||||
|
||||
Styles style = gameConfig.FullScreen ? Styles.Fullscreen : Styles.Default;
|
||||
|
||||
mainWindow = new MainWindow(gameConfig.VideoMode, "testgame", style);
|
||||
|
||||
SceneManager.LoadScenes(mainWindow);
|
||||
|
||||
mainWindow.Gameloop();
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,102 @@
|
||||
using SFML.Graphics;
|
||||
using SFML.System;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Firebird2D.SceneSystem.Actors
|
||||
{
|
||||
public enum ResizeMode
|
||||
{
|
||||
Resize,
|
||||
DontResize,
|
||||
CutImage
|
||||
}
|
||||
|
||||
public enum AnchorPoint
|
||||
{
|
||||
topLeft,
|
||||
topMiddle,
|
||||
topRight,
|
||||
bottomLeft,
|
||||
bottomMiddle,
|
||||
bottomRight,
|
||||
LeftMiddle,
|
||||
RightMiddle,
|
||||
Center
|
||||
}
|
||||
|
||||
public enum AnchorMode
|
||||
{
|
||||
stayInValue,
|
||||
stayInRatio,
|
||||
stayInPlace
|
||||
}
|
||||
|
||||
public struct Anchors
|
||||
{
|
||||
public bool top;
|
||||
public bool left;
|
||||
public bool right;
|
||||
public bool bottom;
|
||||
|
||||
AnchorPoint anchorPoint;
|
||||
|
||||
AnchorMode anchorMode;
|
||||
|
||||
|
||||
public Anchors() : this(true, true, false, false, AnchorPoint.Center, AnchorMode.stayInValue) { }
|
||||
|
||||
public Anchors(bool top, bool left, bool right, bool bottom) : this(top, left, right, bottom, AnchorPoint.Center, AnchorMode.stayInValue) { }
|
||||
|
||||
|
||||
public Anchors(bool top, bool left, bool right, bool bottom, AnchorPoint anchorPoint) : this(top, left, right, bottom, anchorPoint, AnchorMode.stayInValue) { }
|
||||
|
||||
public Anchors(bool top, bool left, bool right, bool bottom, AnchorPoint anchorPoint, AnchorMode anchorMode)
|
||||
{
|
||||
this.top = top;
|
||||
this.left = left;
|
||||
this.right = right;
|
||||
this.bottom = bottom;
|
||||
this.anchorPoint = anchorPoint;
|
||||
this.anchorMode = anchorMode;
|
||||
}
|
||||
}
|
||||
|
||||
public interface IRenderable
|
||||
{
|
||||
public void Render(RenderWindow window);
|
||||
}
|
||||
|
||||
public interface IUpdatable
|
||||
{
|
||||
void Tick(int timeDifference);
|
||||
}
|
||||
|
||||
public interface IResizable : IRenderable
|
||||
{
|
||||
void Resize(int width, int height);
|
||||
void OnWindowResize(int width, int height);
|
||||
}
|
||||
|
||||
public interface I_BaseActor : IRenderable, IUpdatable, IComparable
|
||||
{
|
||||
|
||||
public string Name { get; }
|
||||
|
||||
public ResizeMode resizeMode { get; set; }
|
||||
|
||||
public Anchors Anchors { get; set; }
|
||||
|
||||
public Vector2f Position { get; set; }
|
||||
|
||||
public Vector2f Size { get; set; }
|
||||
|
||||
public float Rotation { get; set; }
|
||||
|
||||
public int Z_Index { get; set; }
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Firebird2D.SceneSystem.Actors
|
||||
{
|
||||
public interface I_Clickable : I_BaseActor
|
||||
{
|
||||
public event EventHandler Click;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Firebird2D.SceneSystem.Actors
|
||||
{
|
||||
public interface I_HitboxActor
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Firebird2D.SceneSystem.Actors
|
||||
{
|
||||
public interface I_InteractableActor : I_BaseActor
|
||||
{
|
||||
public bool Interact(I_PlayerActor player);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Firebird2D.SceneSystem.Actors
|
||||
{
|
||||
public interface I_PlayerActor : I_BaseActor
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
using Firebird2D.SceneSystem.Actors;
|
||||
using SFML.Graphics;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Firebird2D.SceneSystem
|
||||
{
|
||||
public interface I_Scene
|
||||
{
|
||||
public string Name { get; }
|
||||
|
||||
public I_PlayerActor Player { get; }
|
||||
|
||||
public List<I_InteractableActor> Interactable { get; }
|
||||
|
||||
public List<I_HitboxActor> Hitbox { get; }
|
||||
|
||||
public List<I_Clickable> Clickables{ get; }
|
||||
|
||||
public I_Scene BuildScene();
|
||||
|
||||
public void DestroyScene();
|
||||
|
||||
public void TickScene(int TimeDifference);
|
||||
|
||||
public void RenderScene(RenderWindow window);
|
||||
|
||||
public void addActor(I_BaseActor Actor);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
using Firebird2D.SceneSystem.Actors;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Firebird2D.SceneSystem
|
||||
{
|
||||
public abstract class SceneGroup
|
||||
{
|
||||
public string? GroupName { get; protected set; }
|
||||
|
||||
public List<I_Scene>? Scenes { get; protected set; }
|
||||
|
||||
public abstract I_Scene SceneChangeAnimation { get; protected set; }
|
||||
|
||||
public abstract void InitializeGroup();
|
||||
|
||||
public abstract I_Scene getStartingScene();
|
||||
|
||||
public I_Scene? Get_Scene(Type type)
|
||||
{
|
||||
if (type != typeof(I_Scene) || Scenes == null) return null;
|
||||
|
||||
return Scenes.FirstOrDefault(instance => instance.GetType() == type);
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,94 @@
|
||||
using Firebird2D.Core;
|
||||
using Firebird2D.SceneSystem.Actors;
|
||||
using SFML.Graphics;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Firebird2D.SceneSystem
|
||||
{
|
||||
public static class SceneManager
|
||||
{
|
||||
//static List<I_Scene> scenes = new List<I_Scene>();
|
||||
|
||||
static string scenesPath = "scenes.dll";
|
||||
|
||||
static Assembly sceneDll = null;
|
||||
|
||||
static MainWindow mainWindow = null;
|
||||
|
||||
static SceneGroup ActiveSceneGroup = null;
|
||||
|
||||
public static void LoadScenes(MainWindow renderWindow)
|
||||
{
|
||||
if (mainWindow == null) return; // todo wenn render window null
|
||||
mainWindow = renderWindow;
|
||||
|
||||
sceneDll = Assembly.Load(scenesPath);
|
||||
|
||||
if (sceneDll == null) return; //Todo wenn scenes nicht geladen werden fehler
|
||||
|
||||
Type? scenesConfig = sceneDll.GetType("Scenes.Config");
|
||||
|
||||
if (scenesConfig == null) return; //Todo wenn die scenes config nicht gefunden wird
|
||||
|
||||
FieldInfo? startSceneGroup = scenesConfig.GetField("startingGroup", BindingFlags.Public | BindingFlags.Static);
|
||||
|
||||
if (startSceneGroup == null) return;// Todo wenn die scenes config nicht gefunden wird
|
||||
|
||||
SceneGroup? startingGroup = startSceneGroup.GetValue(null) as SceneGroup;
|
||||
|
||||
if (startingGroup == null) return;//Todo wenn die scenes config nicht gefunden wird
|
||||
|
||||
LoadSceneGroup(startingGroup, null);
|
||||
|
||||
}
|
||||
|
||||
private static async void LoadSceneGroup(SceneGroup sceneGroup, List<I_BaseActor>? carryOverActors)
|
||||
{
|
||||
if (sceneGroup == null) return; //todoo wenn scene group null
|
||||
|
||||
ActiveSceneGroup = sceneGroup;
|
||||
|
||||
changeScene(sceneGroup.SceneChangeAnimation, carryOverActors);
|
||||
|
||||
// Asynchrone Initialisierung der Szene im Hintergrund
|
||||
await Task.Run(() => sceneGroup.InitializeGroup());
|
||||
}
|
||||
|
||||
public static void changeScene(Type type, List<I_BaseActor> carryOverActors)
|
||||
{
|
||||
if (type != typeof(I_Scene)) return;
|
||||
|
||||
I_Scene? scene = ActiveSceneGroup.Get_Scene(type);
|
||||
|
||||
changeScene(scene,carryOverActors);
|
||||
}
|
||||
|
||||
private static void changeScene(I_Scene? scene, List<I_BaseActor>? carryOverActors)
|
||||
{
|
||||
if (scene == null) return; //todo reaction
|
||||
|
||||
if (mainWindow.ActiveSecene != null)
|
||||
mainWindow.ActiveSecene.DestroyScene();
|
||||
|
||||
if (carryOverActors != null)
|
||||
foreach (I_BaseActor actor in carryOverActors)
|
||||
{
|
||||
scene.addActor(actor);
|
||||
}
|
||||
|
||||
mainWindow.ActiveSecene = scene.BuildScene();
|
||||
}
|
||||
|
||||
public static void changeGroup(SceneGroup nextSceneGroup, List<I_BaseActor> carryOverActors)
|
||||
{
|
||||
LoadSceneGroup(nextSceneGroup, carryOverActors);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"AppSettings": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"ScreenResolution": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"x": { "type": "integer" },
|
||||
"y": { "type": "integer" }
|
||||
},
|
||||
"required": [ "x", "y" ]
|
||||
},
|
||||
"Fullscreen": { "type": "boolean" },
|
||||
"Log" : {"type": "boolean"}
|
||||
},
|
||||
"Required": [ "ScreenResolution", "Fullscreen", "Log" ]
|
||||
}
|
||||
},
|
||||
"Required" : ["AppSettings"]
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
{ "AppSettings":{ "ScreenResolution": { "x": 3840, "y": 2160 }, "Fullscreen": false, "Log": true, }}
|
||||
File diff suppressed because it is too large
Load Diff
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"runtimeOptions": {
|
||||
"tfm": "net8.0",
|
||||
"framework": {
|
||||
"name": "Microsoft.NETCore.App",
|
||||
"version": "8.0.0"
|
||||
},
|
||||
"configProperties": {
|
||||
"System.Runtime.Serialization.EnableUnsafeBinaryFormatterSerialization": false
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
===================08,12,24===================
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1 @@
|
||||
{ "AppSettings":{ "ScreenResolution": { "X": 3840, "Y": 2160 }, "Fullscreen": false }}
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user