Hi 游客

更多精彩,请登录!

比特池塘 区块链技术 正文

利用NEO与Unity制作游戏

杨远枫冠
68 0 0
至此,我们将开始添加更多自定义的逻辑并与NEO区块链进行交互。对于任何熟悉这个领域的人来说,这些是不言自明的,但是这个应用程序仅用于教学目的。一款游戏在很多方面来说就像一个钱包,作为用户和开发者,在最终将应用连接到主网或者将应用程序交付给用户时,都必须非常的谨慎。在这个领域中,大多数面向用户的项目都经过了彻底的测试和审核,以便发现代码漏洞和恶意代码。我建议你多花时间与社区合作然后做这些工作。本教程只介绍一些基本知识,为简单起见,我们会直接将私钥等内容保存在本地存储中,这是不安全的。不要在生产环境中这么做。! T4 ]2 S' W- s$ H; O

2 L) h4 H. V  J* ?9 ^    钱包管理
* a; e1 t9 i' z0 |1 ~& o( }  m+ g. v. W- b4 B
    下一部分会更多地涉及到Unity特定的工作流的内容,所以我会给你提供一个预置和脚本文件,你可以直接导入到你的项目中,这样可以节省一些时间。你可以直接在这里下载。这个脚本会管理你的NEO钱包的实例,如果你还没有这个实例的话,它会帮你新建一个。我提供这个脚本的原因是为了证明拥有良好入门体验的重要性。许多的加密货币项目(以及一些游戏)都会要求用户进行大量的学习从而学会如何使用这个应用程序。长远上来说,我们需要更好地了解如何引入新用户,同时在这么做的时候尽可能地减少摩擦。用户已经投入时间下载游戏了,当开始要求占用他们更多时间的时候,如果能在开始玩游戏的时候,有着越少的必要的点击操作和学习要求,他们就越不可能立马删除游戏。不要让用户去思考。
3 W& A' Q) a# F2 S* |0 i
  q6 F% P  t% @# V    理想情况下,我是希望能完全移除第一个界面,只需将用户直接放入游戏中即可。但持有资产的问题是很明显的,你必须非常清楚何时以及如何处理这些资产。当用户忘记或者丢失他们的密钥时,你无法直接进入后台帮助用户重置和检索他们的数据。一个好的中间解决方案是游戏的开始部分不用涉及到任何钱包内容,只有用户想要更好地尝试你的钱包功能时,才会提示用户输入这些钱包信息。希望你们能自行尝试探索自己的解决方案。
0 z. W! i! F4 A5 D4 b+ q7 i8 L) l  V  Q$ [! L: `
    发送通证" w' i4 v) ~3 y* a2 Y; U# g
/ J, O1 }3 |( r
    在后面的教程中,我们将更深入地研究智能合约,但是现在我们只想快速与NEO区块链进行交互。当玩家得分超过某个阈值时,我们会给他们代币作为奖励。GAS在某种程度上是NEO区块链中的实际代币,所以我们会使用它来作为奖励。+ J. d2 D! D  P; E0 ~/ m) s
  l8 u4 w% U$ B/ S( X& v* t
    在创建一个真正的游戏时,你将不得不与攻击作斗争,而斗争的同时又要保持游戏的趣味性和经济的流动性并不是一件容易的事情。出于演示的目的,我们在这里会进行简化。在真正的在线游戏中,你需要多种反作弊机制,但最终在游戏中,我们知道我们永远都无法避免所有的攻击。某个地方的某个人会下定决心去破坏你的游戏。否则的话你会遗漏一个关键的代码漏洞。我们试图通过防止最为常见的攻击和睡眠不足来找到平衡,我们经常以这样一种方式分割经济,以便其他玩家的游戏体验不会在这个过程中受到损害。
. o2 Y' t( i9 }- _* f4 E
8 R! r! ^/ u# t8 c2 Y% G) [4 K创建一个名为NEORewardManager的游戏对象GameObject,将它作为其他NEO管理器的子对象。创建一个名为NEORewardManager的脚本并复制粘贴以下代码:/ _5 g) G3 ^" M# h6 d2 y( l. ]& ~5 V3 R
using System;
! E8 q& v% b7 T using System.Collections;, F  j& S0 u7 I/ N2 M8 O$ l
using UniRx;8 _- N* \5 [. u) l- o
using UnityEngine;) |1 z4 @- `& _3 m' i6 e

2 O8 b# b( N6 q( v* `) p5 p public class NEORewardManager : MonoBehaviour
  P5 b0 n( K% w* p5 H! h+ H$ C4 @( {! b {& e, O7 t, r4 d8 {4 J) T7 W  S
     [SerializeField] private NEOManager neoManager;
! `1 A3 \! n% t, N2 Q% q+ Q     [SerializeField] private CompleteProject.PlayerHealth playerHealth;4 y0 u  h) m: }/ z$ c

1 C. c; x4 y8 @6 |- \; ^     [SerializeField] private int rewardThreshold = 50;
  b' |! d; M4 j6 y & e7 \6 ^7 N! z
     private bool isGameOver;
1 k: N  W1 p6 m* U- _
$ ]9 `% \& w) S7 ~9 V8 k# x) u     private void Update()  R: z  v& g3 t% ~
     {
# O. |! w1 C% Z7 P         if(playerHealth.currentHealth  0 && isGameOver)
" n& _3 ?/ ?3 ]6 @* h/ n         {
# N; d& _. l" k( E) v2 h% t5 I             isGameOver = false;
/ t/ Y! w2 C$ z; p7 J         }
. N' c% l, P1 U5 r4 Z2 }3 q     }* I& l  Z& _9 h- W; b
+ v& S7 @( J6 d: M. Y0 S
     private IEnumerator OnGameOver()$ d3 z+ E4 U6 x8 s
     {4 s+ A, I/ m# K; M: Q
         yield return new WaitForSeconds(1);
" ^" U4 Q% H  n5 I: W         Time.timeScale = 0;
2 D8 `* |. ~) l3 [3 R ! d# l, W8 B6 T3 R
         if(CompleteProject.ScoreManager.score >= rewardThreshold). E2 X. s! }2 x( F5 D# z
         {" j4 |0 f  z+ H& `
             StartCoroutine(TrySendGAS(1));  k1 A+ H* v1 j' \
         }/ V. R1 c( g4 ?& `% Y! u
         else
. r% m- }( v# F  [! K         {: o7 w' P9 k8 q  [1 X
             Time.timeScale = 1;
+ H, U% e. s& Z         }  P2 M' _' J4 W
     }
, o; }$ I: u( ~+ ]# `: c- m
) G1 K8 Y: v; ~' d/ B2 C" w     private IEnumerator TrySendGAS(int amount)
2 ~$ w9 h+ ?% a1 H! m6 p% W     {
9 u4 G' I- {) i2 H         yield return null;
; d; t$ A' I) ]5 F4 ]
, H6 u' {* V" W$ K- V! e         try, t0 x9 A0 P9 X2 e
         {
$ X# \# \7 [) r             var tx = neoManager.API.SendAsset(neoManager.MasterKeyPair, neoManager.PlayerKeyPair.Value.address, NEOManager.AssetSymbol, (decimal)amount);
$ n3 m, l7 C  s: n 4 ~4 W3 F. C% w) W) K! d
             if (tx == null)
: [* q% \2 a6 m             {
1 N8 ?: D8 z& j% s                 Debug.LogError("Null Transaction returned");
6 G7 S( i0 w/ ~3 o* m- w$ i                 Time.timeScale = 1;
3 z3 m: D# M( T2 H, Z; J( U8 o             }
9 F* q( y! v# e* N7 N2 p+ G% Z: @9 E             else2 g5 H9 G2 k/ T; M
             {$ u- f: S3 q. O) K
                 Debug.Log("TX received, checking sync...");
) J5 P4 A7 l8 D9 y- h! d8 ^' w                 Observable.FromCoroutine(SyncBalance).Subscribe().AddTo(this);) s! a; _$ A$ w- v! u- `
             }
$ D) U) x4 @4 K/ h% g3 A, V         }) ~6 T& B( v1 q' ?6 h. r8 t
         catch (NullReferenceException exception)
! T) ^7 F; d3 @8 q         {$ I# m1 d8 Z8 U; K2 i
             Debug.LogError("There was a problem...");
; C. P% @* _! u( l. A4 U0 F, u+ m( N             Time.timeScale = 1;& a, v  ^/ p3 m1 q5 ~
         }! `/ N4 i- s* K+ ]
         catch (Exception exception)
7 o) u& v( X) i3 M         {; S) ]4 V+ f; i' o- b0 p: c. X1 i9 f
             Debug.LogError("There was a problem...");
; y3 m  d& w; t* I$ f* f             Time.timeScale = 1;
1 r5 r$ ?% y5 t7 H' O         }
% z' x7 P1 z0 H     }' G; K% G& m( z

/ z2 r, ]: y- A$ P( [     private IEnumerator SyncBalance()
0 Q5 N& ?* t: m0 D) o  S     {
' I' l' R. _" c7 _' X+ c5 }0 n         yield return null;, p8 F: S5 J+ C4 Z0 d

; q1 `; N& E+ U/ E( I) }$ E$ d$ y# K         try3 t  n& z. S& ^5 b" g1 _/ L
         {
2 z" J; n7 r- {6 Z! a             //var balances = neoManager.API.GetAssetBalancesOf(neoManager.PlayerKeyPair.Value);
  G* ?) \& c8 ~! P: N% O6 G             //neoManager.GASBalance.Value = balances.ContainsKey(NEOManager.AssetSymbol) ? balances[NEOManager.AssetSymbol] : 0;
# C$ e: u9 }3 u; H# A1 B% S$ J# E             //if (Mathf.Approximately((float)NEOManager.GASBalance.Value, GameDataSystem.Coins.Value)); {. m1 y' ^; h$ y# w
             //{
: ?5 C- g0 p/ u; V4 y7 I             //    Debug.Log("GAS transferred successfully");  I: i& Q+ `; \6 y8 _) ]* ^
             //}
7 T$ n8 X4 R9 Z- ^             //else$ F' C2 _2 ]' Z) o+ Y; M, |& y
             //{$ Z6 V: r. |, e, ~( u' f
             //    Debug.LogWarning("Something's not right." +
, l- @$ a8 [6 X* ]& P             //                     //"\nCoins: " + GameDataSystem.Coins.Value +
5 d' k: I4 o/ V, F4 ]             //                     "\nGAS: " + NEOManager.GASBalance.Value);
: R! \' ~3 T1 p& T: }9 n             //}" j3 J  w* K& N2 s6 v' H, v
             Debug.Log("Balance synced!");
% G! ?9 U: c; b! s             Time.timeScale = 1;
7 D3 K* K% Y+ H6 |         }
2 s5 f, E$ y% V- t: s! B         catch (NullReferenceException exception)# w% w4 w3 [6 T9 l" N0 A0 G
         {
! Z% j) J7 e. ^; h             Debug.LogWarning("Something's not right." +
; y* J) T1 T9 z* [. i8 G$ z% C                  //"\nCoins: " + GameDataSystem.Coins.Value +' Q) |' z# B# [
                  "\nGAS: " + neoManager.GASBalance.Value);: |: C' K9 A2 W- u2 W; r
             Time.timeScale = 1;2 J7 C  ?/ q+ V
         }) z( |8 B4 v9 u- i  M: Z# J" M1 S
     }" E/ m. H( E5 E1 ^9 f) b& Z
}' e1 Y" a# C; Q) h1 q! a
系统会等待游戏结束状态,游戏结束后如果玩家得分超过某个特定的阈值,系统就会从主账户中转账GAS到本地玩家账户中。 通过拖放场景中的引用来连接NEOManager和PlayerHealth。 你还可以将奖励阈值设置为你想要的任何值; 玩玩看看。 在随后的回放中,你可以看到数量的更新,这可以反映出GAS已经转账正常了。恭喜,我们现在已经可以与NEO区块链进行一些基本的交互了,耶。% J* h, O8 c6 O, N) B, m& D' n
在接下来的教程中,我们将更深入地探讨智能合约,并探索系统能够提供的其他功能。
BitMere.com 比特池塘系信息发布平台,比特池塘仅提供信息存储空间服务。
声明:该文观点仅代表作者本人,本文不代表比特池塘立场,且不构成建议,请谨慎对待。
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

成为第一个吐槽的人

杨远枫冠 小学生
  • 粉丝

    0

  • 关注

    0

  • 主题

    2