Awesome, thank you for the guidance. I haven't used Commands in c# directly yet, so I was a bit unsure how to use them and, of course, since they are simply another class, instantiating them with the new keyword makes sense.
I played around with Gosub() but had some trouble sending the proper Path argument to the Goto().
Tried to store new NamedStringParameter().SetValueFromScriptText(scriptPlaybackspot, scriptName, out errors) into a "path" variable and send that to the Gosub with await new Gosub(){ Path = path }.ExecuteAsync() and even though it was somewhat functional it had some issues.
Scripts somehow skipped a line, so for example, in a 3 line script if we pause execution on the first line it would return at line 3 and not line 2. Since Gosub() increments one line of the playbackspot.LineIndex for the next play position I figured that this might be a problem of the initial Playbackspot sent to the method, I was using IScriptPlayer.PlaybackSpot to get the current position but since I haven't thoroughly debug the variables at runtime I'm still not sure why this happened.
I also triggered the Goto:72 error for an empty label.
This is because the path I sent through Gosub() would be "Scriptname.null" (ex. "MyTestScript.null") and there is no "null" label to look for in the script. However, this error was not disruptive and the game run fine.
Anyway, this approach was too clunky and I decided to take a look at the Gosub() and Goto() classes to try a more direct approach without the need for commands. It was just a matter of pushing the current playbackspot to the GosubReturnSpots stack. Finalizing the triggered nani script with a @return command will return to the previous position without any issues whatsoever. Quite simple and quite awesome! This is the snippet of the relevant code.
Code: Select all
scriptPlayer.GosubReturnSpots.Push(scriptPlayer.PlaybackSpot);
scriptPlayer.Play(hotspot.NaniScript);
For future reference, I'll leave here the classes where I implemented this so that anyone trying it can have a practical example to use. This is part of a navigation system I'm working on. Locations are objects that hold several LocationHotspots, the hotspots can be a reference to another location, a character or an item, if the hotspot is of Location type the target Location object will be loaded and the process repeats. A NavigationUI (CustomUI) will then manage these Locations and change them accordingly, it also handles changes to the background actor based on current location and time (using my calendar extension variables).
Location.cs:
Code: Select all
using System.Collections.Generic;
using Naninovel;
using UniRx.Async;
using UnityEngine;
using UnityEngine.UI;
namespace NaninovelNavigation.UI
{
[System.Serializable]
public enum LocationType
{
Interior,
Exterior
}
[System.Serializable]
public class Location : ScriptableUIBehaviour
{
public string LocationName { get => locationName; private set=> locationName = value; }
public LocationType LocationType { get => locationType; private set => locationType = value; }
[SerializeField] private string locationName;
[SerializeField] private LocationType locationType;
[SerializeField] private List<LocationHotspot> hotspots;
private NavigationUI navigationUi;
private IScriptPlayer scriptPlayer;
protected override void Awake()
{
base.Awake();
navigationUi = Engine.GetService<IUIManager>().GetUI<NavigationUI>();
scriptPlayer = Engine.GetService<IScriptPlayer>();
foreach (var hotspot in hotspots)
{
hotspot.gameObject.GetComponent<Button>().onClick.AddListener(delegate{HotspotClicked(hotspot);});
}
}
protected override void HandleVisibilityChanged(bool visible)
{
base.HandleVisibilityChanged(visible);
if (visible)
{
foreach (var hotspot in hotspots)
{
hotspot.SetVisibility(true);
}
}
}
private async UniTask HotspotClicked(LocationHotspot hotspot)
{
switch (hotspot.InteractionType)
{
case HotspotInteraction.Location:
navigationUi.Location = hotspot.InteractionTarget;
await navigationUi.ChangeLocation();
break;
}
if (hotspot.NaniScript != null)
{
scriptPlayer.GosubReturnSpots.Push(scriptPlayer.PlaybackSpot);
scriptPlayer.Play(hotspot.NaniScript);
}
}
}
}
LocationHotspot.cs:
Code: Select all
using Naninovel;
using UnityEngine;
namespace NaninovelNavigation.UI
{
[System.Serializable]
public enum HotspotInteraction
{
Location,
Character,
Item
}
public class LocationHotspot : ScriptableButton
{
public HotspotInteraction InteractionType { get => interactionType; private set => interactionType = value; }
public string InteractionTarget { get => interactionTarget; private set => interactionTarget = value; }
public Script NaniScript { get => naniScript; private set => naniScript = value; }
[SerializeField] private HotspotInteraction interactionType;
[SerializeField] private string interactionTarget;
[SerializeField] private Script naniScript = null;
}
}