diff --git a/Behavior/DotRPG.Behavior.csproj b/Behavior/DotRPG.Behavior.csproj
index 65a43cc..1c14586 100644
--- a/Behavior/DotRPG.Behavior.csproj
+++ b/Behavior/DotRPG.Behavior.csproj
@@ -8,6 +8,12 @@
1.3.6.0
+
+
+
+
+
+
diff --git a/Behavior/Routines/DotRPG.Behavior.Routines.csproj b/Behavior/Routines/DotRPG.Behavior.Routines.csproj
new file mode 100644
index 0000000..e6fe793
--- /dev/null
+++ b/Behavior/Routines/DotRPG.Behavior.Routines.csproj
@@ -0,0 +1,12 @@
+
+
+
+ netcoreapp3.1
+ DotRPG
+ red-the-random-dev
+ red-the-random-dev
+ 1.3.6.0
+ 1.3.6.0
+
+
+
diff --git a/Behavior/Routines/FrameLoader.cs b/Behavior/Routines/FrameLoader.cs
new file mode 100644
index 0000000..9372e10
--- /dev/null
+++ b/Behavior/Routines/FrameLoader.cs
@@ -0,0 +1,52 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+using System.Threading;
+
+namespace DotRPG.Behavior.Routines
+{
+ public class FrameLoader
+ {
+ public ILoadable Loaded;
+
+ public Single LoadPercentage
+ {
+ get
+ {
+ if (Loaded.ContentTasks_Total + Loaded.ObjectTasks_Total == 0)
+ {
+ return Single.NaN;
+ }
+ return (Single)Math.Round((100.0m * Loaded.ContentTasks_Done + Loaded.ObjectTasks_Done) / (Loaded.ContentTasks_Total + Loaded.ObjectTasks_Total), 1);
+ }
+ }
+
+ public void Update()
+ {
+ if (Loaded.Loaded)
+ {
+ return;
+ }
+ else if (!Loaded.ReadyForLoad)
+ {
+ Loaded.PreloadTask();
+ }
+ else if (Loaded.ContentTasks_Done < Loaded.ContentTasks_Total)
+ {
+ Loaded.PerformContentTask();
+ }
+ else if (Loaded.ObjectTasks_Done < Loaded.ObjectTasks_Total)
+ {
+ Loaded.PerformObjectTask();
+ }
+ else
+ {
+ Loaded.PostLoadTask();
+ }
+ }
+ public FrameLoader(ILoadable il)
+ {
+ Loaded = il;
+ }
+ }
+}
diff --git a/Behavior/Routines/ILoadable.cs b/Behavior/Routines/ILoadable.cs
new file mode 100644
index 0000000..a0b4755
--- /dev/null
+++ b/Behavior/Routines/ILoadable.cs
@@ -0,0 +1,25 @@
+using System;
+
+namespace DotRPG.Behavior.Routines
+{
+ public interface ILoadable
+ {
+ public Boolean ReadyForLoad { get; }
+ public Boolean Loaded { get; }
+ public Int32 ContentTasks_Total { get; }
+ public Int32 ObjectTasks_Total { get; }
+ public Int32 ContentTasks_Done { get; }
+ public Int32 ObjectTasks_Done { get; }
+ // Do single task per call
+ public void PerformContentTask();
+ public void PerformObjectTask();
+
+ public Boolean SupportsMultiLoading { get; }
+ // Do multiple tasks at once
+ public void PerformContentTasks(Int32 step);
+ public void PerformObjectTasks(Int32 step);
+
+ public void PreloadTask();
+ public void PostLoadTask();
+ }
+}
diff --git a/DotRPG.sln b/DotRPG.sln
index 42d2b9f..9b5d69f 100644
--- a/DotRPG.sln
+++ b/DotRPG.sln
@@ -15,7 +15,9 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DotRPG.Scripting.Pipeline",
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DotRPG.Scripting", "Scripting\DotRPG.Scripting.csproj", "{610FDEAE-E1EB-475C-A095-2F337FBB5A2C}"
EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DotRPG.Behavior", "Behavior\DotRPG.Behavior.csproj", "{7D48C09E-EDCF-4D41-9687-F32BC4F8DFC6}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DotRPG.Behavior", "Behavior\DotRPG.Behavior.csproj", "{7D48C09E-EDCF-4D41-9687-F32BC4F8DFC6}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DotRPG.Behavior.Routines", "Behavior\Routines\DotRPG.Behavior.Routines.csproj", "{67A8F31C-34A8-4DEC-9AB6-57F5A41018C7}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
@@ -51,6 +53,10 @@ Global
{7D48C09E-EDCF-4D41-9687-F32BC4F8DFC6}.Debug|Any CPU.Build.0 = Debug|Any CPU
{7D48C09E-EDCF-4D41-9687-F32BC4F8DFC6}.Release|Any CPU.ActiveCfg = Release|Any CPU
{7D48C09E-EDCF-4D41-9687-F32BC4F8DFC6}.Release|Any CPU.Build.0 = Release|Any CPU
+ {67A8F31C-34A8-4DEC-9AB6-57F5A41018C7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {67A8F31C-34A8-4DEC-9AB6-57F5A41018C7}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {67A8F31C-34A8-4DEC-9AB6-57F5A41018C7}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {67A8F31C-34A8-4DEC-9AB6-57F5A41018C7}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
diff --git a/_Example/DotRPG.Example.csproj b/_Example/DotRPG.Example.csproj
index bc88727..e29756e 100644
--- a/_Example/DotRPG.Example.csproj
+++ b/_Example/DotRPG.Example.csproj
@@ -41,6 +41,7 @@
+
diff --git a/_Example/Game1.cs b/_Example/Game1.cs
index 3f7c4c4..0265ed5 100644
--- a/_Example/Game1.cs
+++ b/_Example/Game1.cs
@@ -10,6 +10,7 @@
using System.Xml.Linq;
using System.IO;
using System.Reflection;
+using DotRPG.Behavior.Routines;
namespace DotRPG._Example
{
@@ -166,10 +167,29 @@ protected override void Update(GameTime gameTime)
}
if (ActiveFrame != null)
{
- if (ActiveFrame.FrameID == -128 && stageSelect.SelectedOption != -1)
+ if (ActiveFrame is LoadingScreen l)
{
- ActiveFrame = Frames[stageSelect.SelectedOption];
- ActiveFrame.LoadContent();
+ if (l.LoadedFrame.Loaded)
+ {
+ ActiveFrame = l.LoadedFrame as Frame;
+ }
+ if (ActiveFrame == null)
+ {
+ ActiveFrame = stageSelect;
+ }
+ }
+ else if (ActiveFrame.FrameID == -128 && stageSelect.SelectedOption != -1)
+ {
+ Frame toLoad = Frames[stageSelect.SelectedOption];
+ if (toLoad is ILoadable load)
+ {
+ ActiveFrame = new LoadingScreen(load, this, ResourceHGlobal, LogicEventSet);
+ }
+ else
+ {
+ ActiveFrame = toLoad;
+ ActiveFrame.LoadContent();
+ }
}
else if (ActiveFrame.FrameID != -128 && Keyboard.GetState().IsKeyDown(Keys.F2))
{
diff --git a/_Example/LoadingScreen.cs b/_Example/LoadingScreen.cs
new file mode 100644
index 0000000..f43233d
--- /dev/null
+++ b/_Example/LoadingScreen.cs
@@ -0,0 +1,83 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+using DotRPG.Behavior;
+using DotRPG.Behavior.Routines;
+using DotRPG.Behavior.Routines;
+using DotRPG.Objects;
+using Microsoft.Xna.Framework;
+using Microsoft.Xna.Framework.Graphics;
+
+namespace DotRPG._Example
+{
+ class LoadingScreen : Frame
+ {
+ public FrameLoader Loader;
+ TextObject percentage;
+ public ILoadable LoadedFrame
+ {
+ get
+ {
+ return Loader.Loaded;
+ }
+ set
+ {
+ Loader = new FrameLoader(value);
+ }
+ }
+ public override int FrameID
+ {
+ get
+ {
+ return -129;
+ }
+ }
+ public LoadingScreen(ILoadable il, Game owner, ResourceHeap globalGameResources, HashSet globalEventSet) : base(owner, globalGameResources, globalEventSet)
+ {
+ Loader = new FrameLoader(il);
+ percentage = new TextObject(globalGameResources.Fonts["vcr_large"], "00.0%", 0.5f, 0.35f, Color.White, AlignMode.BottomCenter, 1080);
+ }
+ public override void SetPlayerPosition(object sender, EventArgs e, GameTime gameTime)
+ {
+ throw new NotImplementedException();
+ }
+ public override void Update(GameTime gameTime, bool[] controls)
+ {
+ Loader.Update();
+ percentage.Text = Loader.LoadPercentage.ToString() + "%";
+ base.Update(gameTime, controls);
+ }
+ public override void Draw(GameTime gameTime, SpriteBatch spriteBatch, Rectangle drawZone)
+ {
+ Vector2 v = new Vector2(drawZone.X + (drawZone.Width / 8), drawZone.Y + (drawZone.Height / 2));
+ Texture2D t1 = new Texture2D(spriteBatch.GraphicsDevice, drawZone.Width * 3 / 4, drawZone.Height / 20);
+ Texture2D t2 = new Texture2D(spriteBatch.GraphicsDevice, Math.Max(drawZone.Width * 3 / 4 * (Int32)Loader.LoadPercentage/100, 1), drawZone.Height / 20);
+
+ Color[] d1 = new Color[drawZone.Width * 3 / 4 * drawZone.Height / 20];
+ Color[] d2 = new Color[Math.Max(drawZone.Width * 3 / 4 * (Int32)Loader.LoadPercentage / 100, 1) * drawZone.Height / 20];
+
+ for (int i = 0; i < d1.Length; i++) d1[i] = Color.Gray;
+ for (int i = 0; i < d2.Length; i++) d2[i] = Color.White;
+
+ t1.SetData(d1);
+ t2.SetData(d2);
+
+ spriteBatch.Draw(t1, v, Color.White);
+ spriteBatch.Draw(t2, v, Color.White);
+
+ percentage.Draw(spriteBatch, Owner.Window);
+ }
+ public override void Initialize()
+ {
+
+ }
+ public override void LoadContent()
+ {
+
+ }
+ public override void UnloadContent()
+ {
+
+ }
+ }
+}
diff --git a/_Example/ScriptTest_Dynamic.cs b/_Example/ScriptTest_Dynamic.cs
index 0c81950..1834467 100644
--- a/_Example/ScriptTest_Dynamic.cs
+++ b/_Example/ScriptTest_Dynamic.cs
@@ -11,11 +11,12 @@
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Media;
using DotRPG.Scripting;
+using DotRPG.Behavior.Routines;
namespace DotRPG.Example
{
[SceneBuilder("example/topdown", true)]
- public class ScriptTest_Dynamic : Frame, IXMLSceneBuilder
+ public class ScriptTest_Dynamic : Frame, IXMLSceneBuilder, ILoadable
{
CameraFrameObject cam = new CameraFrameObject();
PlayerObject player;
@@ -28,74 +29,175 @@ public class ScriptTest_Dynamic : Frame, IXMLSceneBuilder
Dictionary props = new Dictionary();
Dictionary interactable = new Dictionary();
- public override int FrameID
+
+ #region ILoadable implementation
+ Int32 content = 0;
+ Int32 objects = 0;
+ Boolean ready = false;
+ Boolean loaded = false;
+ public Int32 ContentTasks_Total
{
get
{
- return _id;
+ return resourceLoad.Count;
+ }
+ }
+ public Int32 ObjectTasks_Total
+ {
+ get
+ {
+ return objectPrototypes.Count;
+ }
+ }
+ public Int32 ContentTasks_Done
+ {
+ get
+ {
+ return content;
+ }
+ }
+ public Int32 ObjectTasks_Done
+ {
+ get
+ {
+ return objects;
+ }
+ }
+ public Boolean ReadyForLoad
+ {
+ get
+ {
+ return ready;
+ }
+ }
+ public Boolean Loaded
+ {
+ get
+ {
+ return loaded;
}
}
- public override void SetPlayerPosition(object sender, EventArgs e, GameTime gameTime)
+ public void PerformContentTask()
{
- throw new NotImplementedException();
+ PerformContentTasks(1);
}
- #region Loader
- public override void LoadContent()
+ public void PerformObjectTask()
+ {
+ PerformObjectTasks(1);
+ }
+ public void PerformContentTasks(Int32 step)
+ {
+ Int32 x = content;
+ for (int i = content; i < Math.Min(x+step, resourceLoad.Count); i++)
+ {
+ ResourceLoadTask rlt = resourceLoad[i];
+ LoadResource(rlt);
+ content = i+1;
+ }
+ }
+ public void PerformObjectTasks(Int32 step)
+ {
+ Int32 x = objects;
+ for (int i = objects; i < Math.Min(x + step, objectPrototypes.Count); i++)
+ {
+ XElement xe = objectPrototypes[i];
+ LoadObject(xe);
+ objects = i+1;
+ }
+ }
+ public void PreloadTask()
{
cam.CameraVelocity = 300.0f;
cam.DefaultHeight = 540;
- foreach (ResourceLoadTask rlt in resourceLoad)
+ ready = true;
+ }
+ public void PostLoadTask()
+ {
+ cam.Focus = player.Location.ToPoint();
+ foreach (LuaModule x in Scripts)
+ {
+ x.Runtime["obj"] = props;
+ }
+ loaded = true;
+ }
+ public Boolean SupportsMultiLoading
+ {
+ get
{
- switch (rlt.Resource)
+ return true;
+ }
+ }
+ #endregion
+ public override int FrameID
+ {
+ get
+ {
+ return _id;
+ }
+ }
+ public override void SetPlayerPosition(object sender, EventArgs e, GameTime gameTime)
+ {
+ if (e is FrameShiftEventArgs fs)
+ {
+ if (fs.IncludesPlayerLocation && player != null)
{
- case ResourceType.Texture2D:
- foreach (String x in FrameResources.Textures.Keys)
+ player.Location = fs.PlayerLocation.ToVector2();
+ }
+ }
+ }
+ #region Loader
+ void LoadResource(ResourceLoadTask rlt)
+ {
+ switch (rlt.Resource)
+ {
+ case ResourceType.Texture2D:
+ foreach (String x in FrameResources.Textures.Keys)
+ {
+ if (x == rlt.ResourceID)
{
- if (x == rlt.ResourceID)
- {
- goto end_t;
- }
+ goto end_t;
}
- FrameResources.Textures.Add(rlt.ResourceID, Owner.Content.Load(rlt.ResourcePath));
- end_t: break;
- case ResourceType.SoundEffect:
- foreach (String x in FrameResources.Sounds.Keys)
+ }
+ FrameResources.Textures.Add(rlt.ResourceID, Owner.Content.Load(rlt.ResourcePath));
+ end_t: break;
+ case ResourceType.SoundEffect:
+ foreach (String x in FrameResources.Sounds.Keys)
+ {
+ if (x == rlt.ResourceID)
{
- if (x == rlt.ResourceID)
- {
- goto end_s;
- }
+ goto end_s;
}
- FrameResources.Sounds.Add(rlt.ResourceID, Owner.Content.Load(rlt.ResourcePath));
- end_s: break;
- case ResourceType.SpriteFont:
- foreach (String x in FrameResources.Textures.Keys)
+ }
+ FrameResources.Sounds.Add(rlt.ResourceID, Owner.Content.Load(rlt.ResourcePath));
+ end_s: break;
+ case ResourceType.SpriteFont:
+ foreach (String x in FrameResources.Textures.Keys)
+ {
+ if (x == rlt.ResourceID)
{
- if (x == rlt.ResourceID)
- {
- goto end_f;
- }
+ goto end_f;
}
- FrameResources.Fonts.Add(rlt.ResourceID, Owner.Content.Load(rlt.ResourcePath));
- end_f: break;
- case ResourceType.Song:
- foreach (String x in FrameResources.Textures.Keys)
+ }
+ FrameResources.Fonts.Add(rlt.ResourceID, Owner.Content.Load(rlt.ResourcePath));
+ end_f: break;
+ case ResourceType.Song:
+ foreach (String x in FrameResources.Textures.Keys)
+ {
+ if (x == rlt.ResourceID)
{
- if (x == rlt.ResourceID)
- {
- goto end_m;
- }
+ goto end_m;
}
- FrameResources.Music.Add(rlt.ResourceID, Owner.Content.Load(rlt.ResourcePath));
- end_m: break;
- }
+ }
+ FrameResources.Music.Add(rlt.ResourceID, Owner.Content.Load(rlt.ResourcePath));
+ end_m: break;
}
- foreach (XElement xe in objectPrototypes)
+ }
+ void LoadObject(XElement xe)
+ {
+ switch (xe.Name.LocalName.ToLower())
{
- switch (xe.Name.LocalName.ToLower())
- {
- case "player":
+ case "player":
{
#region Parameters definition
Point startPos = XMLSceneLoader.ResolveVector2(xe.Attribute(XName.Get("startPos")).Value).ToPoint();
@@ -131,7 +233,7 @@ public override void LoadContent()
}
break;
}
- case "prop":
+ case "prop":
{
#region Parameters definition
String ID = xe.Attribute(XName.Get("id")).Value;
@@ -155,13 +257,13 @@ public override void LoadContent()
}
break;
}
- case "script":
+ case "script":
{
String scriptContent = File.ReadAllText(Path.Combine(Owner.Content.RootDirectory, xe.Attribute(XName.Get("location")).Value));
Scripts.Add(new LuaModule(scriptContent));
break;
}
- case "backdrop":
+ case "backdrop":
{
Texture2D t = null;
Vector2 p = Vector2.Zero;
@@ -186,13 +288,22 @@ public override void LoadContent()
}
break;
}
- }
}
- cam.Focus = player.Location.ToPoint();
- foreach (LuaModule x in Scripts)
+ }
+ public override void LoadContent()
+ {
+ PreloadTask();
+ foreach (ResourceLoadTask rlt in resourceLoad)
{
- x.Runtime["obj"] = props;
+ LoadResource(rlt);
+ }
+ foreach (XElement xe in objectPrototypes)
+ {
+ LoadObject(xe);
}
+ PostLoadTask();
+ objects = objectPrototypes.Count;
+ content = resourceLoad.Count;
}
public Frame BuildFromXML(XDocument Document, Object[] parameters)
@@ -328,6 +439,10 @@ public override void UnloadContent()
player = null;
Scripts.Clear();
backdrops.Clear();
+ content = 0;
+ objects = 0;
+ ready = false;
+ loaded = false;
}
}
}