Appendix for the Zebedee Adventure Game Tutorial
SceneController.cs | |
using System; | |
using UnityEngine; | |
using System.Collections; | |
using UnityEngine.SceneManagement; | |
using UnityEngine.UI; | |
using ZbdUnitySDK.Logging; | |
using ZbdUnitySDK; | |
using System.Threading; | |
using System.Threading.Tasks; | |
using ZbdUnitySDK.Models; | |
using ZbdUnitySDK.Models.Zebedee; | |
using ZbdUnitySDK.Services; | |
using ZXing; | |
using ZXing.QrCode; | |
// This script exists in the Persistent scene and manages the content | |
// based scene's loading. It works on a principle that the | |
// Persistent scene will be loaded first, then it loads the scenes that | |
// contain the player and other visual elements when they are needed. | |
// At the same time it will unload the scenes that are not needed when | |
// the player leaves them. | |
public class SceneController : MonoBehaviour | |
{ | |
public event Action BeforeSceneUnload; // Event delegate that is called just before a scene is unloaded. | |
public event Action AfterSceneLoad; // Event delegate that is called just after a scene is loaded. | |
public CanvasGroup faderCanvasGroup; // The CanvasGroup that controls the Image used for fading to black. | |
public float fadeDuration = 1f; // How long it should take to fade to and from black. | |
public string startingSceneName = "SecurityRoom"; | |
// The name of the scene that should be loaded first. | |
public string initialStartingPositionName = "DoorToMarket"; | |
// The name of the StartingPosition in the first scene to be loaded. | |
public SaveData playerSaveData; // Reference to the ScriptableObject which stores the name of the StartingPosition in the next scene. | |
private bool isFading; // Flag used to determine if the Image is currently fading to or from black. | |
public string apiKey; | |
public string zebedeeBaseUrl; | |
public Image QRcodeImage; | |
public GameObject QRCodePanel; | |
public Text QRcodeText; | |
private IZdbLogger logger = LoggerFactory.GetLogger(); | |
private ZebedeeClient zbdClient = null; | |
private int totalSats = 10; | |
public int gamePlayFeeSats; | |
private async void Start() | |
{ | |
// Set the initial alpha to start off with a black screen. | |
faderCanvasGroup.alpha = 1f; | |
// Write the initial starting position to the playerSaveData so it can be loaded by the player when the first scene is loaded. | |
playerSaveData.Save(PlayerMovement.startingPositionKey, initialStartingPositionName); | |
QRcodeText.text = "Play Game for " + gamePlayFeeSats + " sats"; | |
zbdClient = new ZebedeeClient(zebedeeBaseUrl, apiKey); | |
PayForAGamePlay(); | |
} | |
///////////////// START USING ZEBEDEE SDK ///////////////////////////////////////////////// | |
private async void PayForAGamePlay() | |
{ | |
Charge charge = new Charge(); | |
charge.Description = gamePlayFeeSats + " sats for ZEBEDEE SDK DEMO GAME"; | |
charge.AmountInSatoshi = int.Parse(gamePlayFeeSats + ""); | |
Debug.Log(zebedeeBaseUrl + " " + apiKey + " " + gamePlayFeeSats); | |
await zbdClient.CreateChargeAsync(charge, handleInvoice); | |
} | |
private async void handleInvoice(ChargeResponse invoice) | |
{ | |
//3.Lightning BOLT invoice string | |
string boltInvoice = invoice.Data.Invoice.Request; | |
string chargeId = invoice.Data.Id; | |
if (string.IsNullOrEmpty(boltInvoice)) | |
{ | |
Debug.Log("bolt Invoice is not set in Invoice in reponse.Check the BTCpay server's lightning setup"); | |
return; | |
} | |
Texture2D texs = GenerateQR(boltInvoice);//Generate QR code image | |
//4.Set the QR code Image to image Gameobject | |
QRcodeImage.GetComponent<Image>().sprite = Sprite.Create(texs, new Rect(0.0f, 0.0f, texs.width, texs.height), new Vector2(0.5f, 0.5f), 100.0f); | |
//5.Subscribe the get notified about payment status | |
string status = await zbdClient.SubscribeChargeAsync(chargeId); | |
if ("completed".Equals(status)) | |
{ | |
//Change the image from QR to Paid | |
QRcodeImage.GetComponent<Image>().sprite = Resources.Load<Sprite>("image/paid"); | |
logger.Debug("payment is complete"); | |
await Task.Delay(2000); | |
QRCodePanel.SetActive(false); | |
totalSats += gamePlayFeeSats; | |
StartCoroutine(LoadSceneAndSetActive(startingSceneName)); | |
// Once the scene is finished loading, start fading in. | |
StartCoroutine(Fade(0f)); | |
} | |
else | |
{ | |
//for example, if the amount paid is not full, do something.the line below just print the status. | |
logger.Error("payment is not completed:" + status); | |
} | |
} | |
public async void DoWithdrawal() | |
{ | |
QRCodePanel.SetActive(true); | |
//1.New Withdrawal Preparation | |
Withdraw withdraw = new Withdraw(); | |
withdraw.Description = "ZEBEDEE SDK DEMO GAME"; | |
withdraw.AmountInSatoshi = totalSats; | |
//2.Create Invoice with initial data and get the full invoice | |
await zbdClient.WithDrawAsync(withdraw, handleWithdrawal); | |
} | |
private async void handleWithdrawal(WithdrawResponse withdraw) | |
{ | |
string lnURL = withdraw.Data.Invoice.Request; | |
if (string.IsNullOrEmpty(lnURL)) | |
{ | |
logger.Debug("lnURL is not set in withdrawal response."); | |
logger.Debug(withdraw.Data.Invoice.Request); | |
return; | |
} | |
QRcodeText.text = "Congrats! Withdraw " + gamePlayFeeSats + " sats"; | |
Texture2D texs = GenerateQR(lnURL);//Generate QR code image | |
//4.Set the QR code image to image Gameobject | |
QRcodeImage.GetComponent<Image>().sprite = Sprite.Create(texs, new Rect(0.0f, 0.0f, texs.width, texs.height), new Vector2(0.5f, 0.5f), 100.0f); | |
//5.Subscribe to a callback method with ID to be monitored | |
string status = await zbdClient.SubscribeWithDrawAsync(withdraw.Data.Id); | |
if ("completed".Equals(status)) | |
{ | |
//Change the image from QR to Paid | |
QRcodeImage.GetComponent<Image>().sprite = Resources.Load<Sprite>("image/withdrawn"); | |
logger.Debug("withdraw is success"); | |
} | |
else | |
{ | |
//for example, if the amount paid is not full, do something.the line below just print the status. | |
logger.Error("withdraw is not success:" + status); | |
} | |
} | |
private Texture2D GenerateQR(string text) | |
{ | |
logger.Debug("generateQR():generating Qr for text: " + text); | |
var encoded = new Texture2D(350, 350); | |
var color32 = Encode(text, encoded.width, encoded.height); | |
encoded.SetPixels32(color32); | |
encoded.Apply(); | |
return encoded; | |
} | |
private static Color32[] Encode(string textForEncoding, | |
int width, int height) | |
{ | |
var writer = new BarcodeWriter | |
{ | |
Format = BarcodeFormat.QR_CODE, | |
Options = new QrCodeEncodingOptions | |
{ | |
Height = height, | |
Width = width | |
} | |
}; | |
return writer.Write(textForEncoding); | |
} | |
///////////////// END USING ZEBEDEE SDK //////////////////////////////////////////////// | |
// This is the main external point of contact and influence from the rest of the project. | |
// This will be called by a SceneReaction when the player wants to switch scenes. | |
public void FadeAndLoadScene(SceneReaction sceneReaction) | |
{ | |
// If a fade isn't happening then start fading and switching scenes. | |
if (!isFading) | |
{ | |
StartCoroutine(FadeAndSwitchScenes(sceneReaction.sceneName)); | |
} | |
} | |
// This is the coroutine where the 'building blocks' of the script are put together. | |
private IEnumerator FadeAndSwitchScenes(string sceneName) | |
{ | |
// Start fading to black and wait for it to finish before continuing. | |
yield return StartCoroutine(Fade(1f)); | |
// If this event has any subscribers, call it. | |
if (BeforeSceneUnload != null) | |
BeforeSceneUnload(); | |
// Unload the current active scene. | |
yield return SceneManager.UnloadSceneAsync(SceneManager.GetActiveScene().buildIndex); | |
// Start loading the given scene and wait for it to finish. | |
yield return StartCoroutine(LoadSceneAndSetActive(sceneName)); | |
// If this event has any subscribers, call it. | |
if (AfterSceneLoad != null) | |
AfterSceneLoad(); | |
// Start fading back in and wait for it to finish before exiting the function. | |
yield return StartCoroutine(Fade(0f)); | |
} | |
private IEnumerator LoadSceneAndSetActive(string sceneName) | |
{ | |
// Allow the given scene to load over several frames and add it to the already loaded scenes (just the Persistent scene at this point). | |
yield return SceneManager.LoadSceneAsync(sceneName, LoadSceneMode.Additive); | |
// Find the scene that was most recently loaded (the one at the last index of the loaded scenes). | |
Scene newlyLoadedScene = SceneManager.GetSceneAt(SceneManager.sceneCount - 1); | |
// Set the newly loaded scene as the active scene (this marks it as the one to be unloaded next). | |
SceneManager.SetActiveScene(newlyLoadedScene); | |
} | |
private IEnumerator Fade(float finalAlpha) | |
{ | |
// Set the fading flag to true so the FadeAndSwitchScenes coroutine won't be called again. | |
isFading = true; | |
// Make sure the CanvasGroup blocks raycasts into the scene so no more input can be accepted. | |
faderCanvasGroup.blocksRaycasts = true; | |
// Calculate how fast the CanvasGroup should fade based on it's current alpha, it's final alpha and how long it has to change between the two. | |
float fadeSpeed = Mathf.Abs(faderCanvasGroup.alpha - finalAlpha) / fadeDuration; | |
// While the CanvasGroup hasn't reached the final alpha yet... | |
while (!Mathf.Approximately(faderCanvasGroup.alpha, finalAlpha)) | |
{ | |
// ... move the alpha towards it's target alpha. | |
faderCanvasGroup.alpha = Mathf.MoveTowards(faderCanvasGroup.alpha, finalAlpha, | |
fadeSpeed * Time.deltaTime); | |
// Wait for a frame then continue. | |
yield return null; | |
} | |
// Set the flag to false since the fade has finished. | |
isFading = false; | |
// Stop the CanvasGroup from blocking raycasts so input is no longer ignored. | |
faderCanvasGroup.blocksRaycasts = false; | |
} | |
} | |
LnurlReaction.cs | |
using System.Collections; | |
using System.Collections.Generic; | |
using UnityEngine; | |
public class LnurlReaction : Reaction | |
{ | |
private SceneController sceneController; // Reference to the SceneController to actually do the loading and unloading of scenes. | |
protected override void SpecificInit() | |
{ | |
sceneController = FindObjectOfType<SceneController>(); | |
} | |
protected override void ImmediateReaction() | |
{ | |
sceneController.DoWithdrawal(); | |
} | |
} | |
LnurlReactionEditor.cs | |
using UnityEditor; | |
[CustomEditor(typeof(LnurlReaction))] | |
public class LnurlReactionEditor : ReactionEditor | |
{ | |
protected override string GetFoldoutLabel() | |
{ | |
return "LNURL Reaction"; | |
} | |
} | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment