首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >How Can Unity+腾讯云开发=微信小游戏?

How Can Unity+腾讯云开发=微信小游戏?

原创
作者头像
蛋先生DX
修改于 2024-09-18 04:53:07
修改于 2024-09-18 04:53:07
82000
代码可运行
举报
文章被收录于专栏:蛋先生说识蛋先生说识
运行总次数:0
代码可运行

写在最前

时光飞逝,物是人非

技术方案总是带着时代的标签,曾经前沿的技术,经过时间的洗礼,可能已成为经典

如果你点进来是因实际需求而不是随意瞧瞧,请同时看看官方的最新进展,指不定有意外的收获

本故事主要讲解在使用 Unity 开发微信小游戏时,如何第一时间用上腾讯云开发的新能力,以及可能的最佳开发实践

***

故事背景

蛋先生:丹尼尔,好久不见,怎么愁眉苦脸的?

丹尼尔:蛋兄好,最近在折腾用 Unity 开发微信小游戏,服务用的是腾讯云开发,不过碰到些问题,一时半会儿搞不定

蛋先生:哦?什么问题,说来听听

丹尼尔:蛋兄,你也懂 Unity 吗?

蛋先生:略懂略懂

丹尼尔:如此甚好。我起初以为直接调用腾讯云开发,用官方的 Unity SDK 就行了

蛋先生:恩,这个想法没毛病

丹尼尔:但,官方并没有 Unity 版本的 SDK

蛋先生:然后呢?

丹尼尔:后来,我在将 Unity 转成微信小游戏的过程中,发现微信有提供 WeChatWASM 这个 Unity SDK,里面带了个 WX.cloud

蛋先生:那不就解了吗?

丹尼尔:我也天真地这么以为,可在 Unity 编辑器一运行,就...

蛋先生:这也正常,毕竟 Unity 编辑器又不是微信开发的,Play Mode 下没有微信小游戏运行环境,自然是跑不起来的

丹尼尔:所以我需要写代码,构建成 WebGL,再转换成微信小游戏,最后才能在微信开发者工具看到运行效果。而我运气不好,还遇到了开发者工具罢工,还得多走一步,用真机预览。这一个流程下来感觉要 1 分钟左右,每次改代码都得走这一长征路,想想头就大

蛋先生:会不会是使用姿势不对呢?

丹尼尔:我也怀疑过,直到我看到官方文档介绍的开发方式...

蛋先生:看来只能如此,不过对于微信本身的能力,大部分时间我们不需要怎么消费它的输出,好像问题也不大。比如:

代码语言:csharp
AI代码解释
复制
var bannerAd = WX.CreateBannerAd(new WXCreateBannerAdParam()
{
    adUnitId = "xxxx",
    adIntervals = 30,
    style = new Style()
    {
        left = 0,
        top = 0,
        width = 600,
        height = 200
    }
});

bannerAd.OnLoad(()=> {
    bannerAd.Show();
});
bannerAd.OnError((WXADErrorResponse res)=>
{
    Debug.Log(res.errCode);
});

丹尼尔:恩,这倒是。但对于服务接口,我们是重度消费输出数据的,比如排行榜,好友列表等。总不能来回盲写代码,走一遍长征路调试吧

蛋先生:这长征路是难免的,但可以减少次数。比如在 Unity 编辑器开发时使用 Mock 数据,等业务逻辑走通再走长征路

丹尼尔:我还是希望尽早看到集成了云开发服务后的实际效果,这样可以早点发现问题,减少在长征路上浪费的时间

蛋先生:恩...

丹尼尔:还有个问题,WeChatWASM 对云开发 SDK 的支持,存在滞后的问题,当前只支持 CallFunction,不支持最新的数据模型。我就是冲着腾讯云开发刚新鲜出炉不久的数据模型来的

蛋先生:哦...

丹尼尔:烦死了,这也不行,那也不行,蛋兄,你给出出主意呗

蛋先生:自己搞一个吧

丹尼尔:这,蛋兄,你不是开玩笑的吧?这可不是我的主业务,我只想用云开发服务而已

蛋先生:恩,可以搞,但不能瞎搞。我们来分析一下要解决的核心问题:

一 要能用上云开发的最新功能,比如数据模型;

二 争取可以早点看到实际效果,避免走长征路;

三 实现成本要低,毕竟这不是主业务

丹尼尔:恩,那怎么办?

解决用上云开发最新功能的问题

蛋先生:云开发推出新功能,总是第一时间在 JS 环境(包括云函数,小程序和 Web 页面)提供的,对吧

丹尼尔:没错

蛋先生:所以我们实际应该直接调用这些 SDK,在 Web 环境下就调用 js-sdk,在小游戏环境下就调用小程序 sdk,这样就能确保享受到最新的功能了

丹尼尔:这些是运行在 JS 环境的吧

蛋先生:没错!所以我们需要实现一个包裹层,这个包裹层对内使用 Unity 脚本去调用 Javascript 函数,对外提供云开发的 Unity 版本 SDK

丹尼尔:具体怎么实现呢?

蛋先生:实现细节咱们后面再讲

解决少走长征路,尽早看到实际效果的问题

丹尼尔:好吧,我还有一个问题,为什么要考虑 Web 环境呢?我只想开发微信小游戏而已啊

蛋先生:这就是为了解决第二个核心问题 - 缩短调试路径。虽然我们在 Unity 编辑器的 Play Mode 无法预览效果,但我们可以退而求其次,构建成 WebGL。当你开发完实际的调用云开发的代码后,按 Command + B ,这会构建成 WebGL 应用,并自动在浏览器打开,你就可以直接预览实际效果了,这样可以省去转换成小游戏的步骤,时间上也会节省不少

丹尼尔:虽然不能在 Unity 编辑器直接预览,还是有点小遗憾,但这样的调试路径还是可以接受的

蛋先生:恩,是时候总结一下这种方案的可能的最佳开发流程了

【Unity 编辑器开发阶段】:使用 Mock 数据,这样可省去构建成 WebGL 的时间,同时可确定业务逻辑所使用接口的输入和输出数据结构

【浏览器调试阶段】:根据确定的业务逻辑接口,通过 Unity TCB SDK Wrapper 开发调用云开发服务的代码,构建成 WebGL,预览实际的效果

【微信小游戏预览阶段】:最后直接构建成微信小游戏,进行最终效果预览

技术实现细节

丹尼尔:哎呦,不错哦!不过,我现在比较好奇的是怎么实现这个,以及实现的成本咋样?

蛋先生:那咱们接着继续聊

Unity 调用 Javascript 同步方法

丹尼尔:首先,Unity 怎么调用 Javascript 方法呢?

蛋先生:分两种情况,同步和异步。同步方法比较简单,官方文档 已经很详细了,但咱们也来个小示例

首先,定义个要被 Unity 调用的 JavaScript 方法。我们在 Assets/Plugins 目录下创建 .jslib 后缀的文件,比如叫 tcbsdk.jslib

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// Assets/Plugins/tcbsdk.jslib

const asmLibraryArg = {
  Hello: function () {
    console.log("Hello, world!");
  },
  ...
}
mergeInto(LibraryManager.library, asmLibraryArg);

接着,在 C# 脚本里进行映射,比如 Assets/Scripts/DemoSDK.cs

代码语言:csharp
AI代码解释
复制
// Assets/Scripts/DemoSDK.cs

public class DemoSDK
{
    [DllImport("__Internal")]
    public static extern void Hello();
}

然后,你就可以通过 DemoSDK.Hello() 调用 tcbsdk.jslib 里的 Hello 方法了

丹尼尔:看上去挺简单的,有啥需要注意的吗?

蛋先生:还真有,tcbsdk.jslib 里的 asmLibraryArg 这个变量的存在是有意义的,且不能修改成其它变量名

丹尼尔:为啥?

蛋先生:它的存在主要是为了方法间互相调用。来,我们继续看例子,看看 HelloCallOtherFn 是怎么调用 Hello 的

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// Assets/Plugins/tcbsdk.jslib

const asmLibraryArg = {
  Hello: function () {
    console.log("Hello, world!");
  },
  HelloCallOtherFn: function () {
    console.log("Call HelloCallOtherFn");
    // 方法间调用方式一
    _Hello();
    // 方法间调用方式二
    asmLibraryArg.Hello();
  },
  ...
}
mergeInto(LibraryManager.library, asmLibraryArg);

丹尼尔:asmLibraryArg.Hello(); 这个我懂,但为啥是 _Hello();?明明方法名是 Hello 啊

蛋先生:嘿嘿,jslib 里的方法在构建成 WebGL 时都会经过加工后合并进 webgl.wasm.framework.unityweb.js ,这个文件你可以在生成的 WebGL 产物里找到,来看个代码片段

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// webgl.wasm.framework.unityweb.js

var unityFramework = (() => {
	return function (unityFramework) {
		...
		function _Hello() {
      		console.log("Hello, world!");
    	}
  		function _HelloCallOtherFn() {
    		console.log("Call HelloCallOtherFn");
    		// 方法间调用方式一
    		_Hello();
    		// 方法间调用方式二
		    asmLibraryArg.Hello();
  		},	
		...
		var asmLibraryArg = {
			Hello: _Hello,
			...	
		}	
		...
	}
})

看到没?真相就在这儿了。不过,我不推荐用 _Hello(),因为这样你就没法用编辑器的功能,比如点击跳转到方法定义。

我们前面提到变量名必须是 asmLibraryArg,这其实是一种取巧的方式,这样即可以实现方法间调用,又可以充分享受编辑器的智能辅助体验,一箭双雕

丹尼尔:蛋兄,你可真是个小机灵鬼

蛋先生:咳咳~

Unity 调用 Javascript 异步方法

丹尼尔:那接下来咱们聊聊如何调用异步方法

蛋先生:异步调用是个环,咱们得从一次异步方法调用的整个过程说起

丹尼尔:你说吧,反正那些又臭又长的代码我是不想看的

蛋先生:嘿嘿,代码是不可避免的,还得结合下边代码【脚本C】和【脚本J】来看(温馨提示:【脚本C】和【脚本J】为往下一点点的两个大的代码片段)。假设我们现在要调用以下异步方法

代码语言:csharp
AI代码解释
复制
HelloWithReturnResult result = await DemoSDK.Instance.HelloAsyncFn(new HelloWithInputParams() { name = "daniel666" });

在【脚本C】中,HelloAsyncFn 方法执行时,会先通过 GetAsyncTask() 取得这次调用的 callbackId 和对应的 TaskCompletionSource 异步任务,然后调用 JavaScript 方法,并等待 TaskCompletionSource 任务的完成。

丹尼尔:那谁来通知 TaskCompletionSource 任务完成呢?

蛋先生:好问题!看【脚本J】中 HelloAsyncFn 的实现

异步任务执行完后,会执行 asmLibraryArg.Utils().sendMessage(callbackId, result);

这个方法实际执行的发送消息代码是 Module.SendMessage("DemoSDK", "OnAsyncFnCompleted", param),它会通知名为 "DemoSDK" 的 GameObject 去执行脚本组件 DemoSDK 的 OnAsyncFnCompleted 方法

丹尼尔:哦哦,我刚才就想问【脚本C】里的这些代码是干嘛的,原来是为了创建一个 GameObject 来接收消息。

代码语言:csharp
AI代码解释
复制
GameObject gameObject = new("DemoSDK");
DemoSDK demoSDK = gameObject.AddComponent<DemoSDK>();

蛋先生:正解!你可真是个小聪明,这么快就看出来了

接下来【脚本C】的 OnAsyncFnCompleted 方法就会收到消息,然后根据 callbackId 让具体的 TaskCompletionSource 任务执行 SetResult,从而完成任务,这样整个异步调用就闭环了。

丹尼尔:懂了。但为什么是 Module.SendMessage 呢?这个 Module 是从哪儿冒出来的?

蛋先生:真相依然在 webgl.wasm.framework.unityweb.js

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// webgl.wasm.framework.unityweb.js

var unityFramework = (() => {
	return function (unityFramework) {
		...
		var Module = typeof unityFramework != "undefined" ? unityFramework : {};
		...
		function SendMessage(gameObject, func, param) {
      		...
    	}
  		Module["SendMessage"] = SendMessage;
		...
	}
})

丹尼尔:666,简直洞若观火

代码语言:csharp
AI代码解释
复制
//【脚本C】:Assets/Scripts/DemoSDK.cs

public class DemoSDK : MonoBehaviour
{
    private static readonly Lazy<DemoSDK> _instance = new Lazy<DemoSDK>(() =>
    {
        GameObject gameObject = new("DemoSDK");
        DemoSDK demoSDK = gameObject.AddComponent<DemoSDK>();
        return demoSDK;
    });
    public static DemoSDK Instance => _instance.Value;
    private DemoSDK() { }

	private Dictionary<string, TaskCompletionSource<string>> tcsDictionary = new();

    public async Task<HelloWithReturnResult> HelloAsyncFn(HelloWithInputParams input)
    {
        (string, TaskCompletionSource<string>) asyncTask = GetAsyncTask();

        // 调用 JavaScript 方法
        Internal.HelloAsyncFn(asyncTask.Item1, Internal.ParseInputParams(input));

        // 返回 Task 让调用方等待
        var result = await asyncTask.Item2.Task;
        return Internal.ParseOutputResult<HelloWithReturnResult>(result);
    }

    public void OnAsyncFnCompleted(string result)
    {
        AsyncResponse<string> res = Internal.ParseOutputResult<AsyncResponse<string>>(result);

        tcsDictionary[res.callbackId].SetResult(res.result);
        tcsDictionary.Remove(res.callbackId);
    }

    private (string, TaskCompletionSource<string>) GetAsyncTask()
    {
        string uuid = Guid.NewGuid().ToString();
        TaskCompletionSource<string> tcs = new();
        tcsDictionary.Add(uuid, tcs);
        return (uuid, tcs);
    }

	private class Internal
    {
		[DllImport("__Internal")]
        public static extern void HelloAsyncFn(string callbackId, string input);
	}

	private class AsyncResponse<T>
    {
        public string callbackId { get; set; }
        public T result { get; set; }
    }
}
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
//【脚本J】:Assets/Plugins/tcbsdk.jslib

const asmLibraryArg = {
  HelloAsyncFn: async function (callbackId, input) {
    ...
    const result = await new Promise((resolve) =>
      setTimeout(() => {
        resolve(input), 2000;
      })
    );
    asmLibraryArg.Utils().sendMessage(callbackId, result);
  },
  Utils: function () {
    const utils = {
      ...
      sendMessage(callbackId, result) {
        const unityInstance = Module;
        const constants = asmLibraryArg.Constants();
        unityInstance.SendMessage(
          constants.DEMO_CALLBACK_OBJECT_NAME,
          constants.CALLBACK_METHOD_NAME,
          JSON.stringify({
            callbackId,
            result: JSON.stringify(result || ""),
          })
        );
      },
    };
    return utils;
  },
  Constants: function () {
    return {
      ...
      DEMO_CALLBACK_OBJECT_NAME: "DemoSDK",
      CALLBACK_METHOD_NAME: "OnAsyncFnCompleted",
    };
  },
  ...
}
mergeInto(LibraryManager.library, asmLibraryArg);

集成腾讯云开发 js-sdk 和小程序 sdk

丹尼尔:说了这么多,好像还不知道要怎么集成 js-sdk 和小程序 sdk

蛋先生:搞清楚了如何实现 Unity 调用 Javascript 之后,问题不就迎刃而解了嘛

因为 @cloudbase/wx-cloud-client-sdk@cloudbase/js-sdk 都提供了 UMD 格式的完整版本,所以我们只需要将 SDK 的完整代码复制放到 jslib 里面(请留意 CloudbaseJSSdkScript 和 CloudbaseWXCloudClientSdkScript 方法)即可。以下是 init 的实现示例

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// Assets/Plugins/tcbsdk.jslib

const asmLibraryArg = {

  /**
   * params.env: 环境ID
   */
  CloudInit: async function (callbackId, params) {
    ...
	const input = asmLibraryArg.Utils().parseInputParams(params);
    if (platform === constants.PLATFROM.WX) {
      const { init } = asmLibraryArg.GetCloudbaseWXCloudClientSdkInstance();
      await wx.cloud.init({
        env: input.env,
      });
      const app = init(wx.cloud);
	  ...
    } else if (platform === constants.PLATFROM.WEB) {
      const cloudbase = asmLibraryArg.GetCloudbaseJSSdkScriptInstance();
      const app = cloudbase.init({
        env: input.env,
      });
      ...
    }
    asmLibraryArg.Utils().sendMessage(callbackId);
  },

  /**
   * 获取 @cloudbase/wx-cloud-client-sdk 实例
   */
  GetCloudbaseWXCloudClientSdkInstance: function () {
    const global = asmLibraryArg.GetGlobalData();
    if (!global.wxCloudClientSDK) {
      asmLibraryArg.CloudbaseWXCloudClientSdkScript.call(global);
    }
    return global.wxCloudClientSDK;
  },

  /**
   * 获取 cloudbase-js-sdk 实例
   */
  GetCloudbaseJSSdkScriptInstance: function () {
    const global = asmLibraryArg.GetGlobalData();
    if (!global.cloudbase) {
      asmLibraryArg.CloudbaseJSSdkScript.call(global);
    }
    return global.cloudbase;
  },

  /**
   * 加载 @cloudbase/wx-cloud-client-sdk
   */
  CloudbaseWXCloudClientSdkScript: function () {
    (function (exports) {
      /**
       * 以下代码来自于 https://unpkg.com/@cloudbase/wx-cloud-client-sdk@1.2.1/lib/wxCloudClientSDK.umd.js
       */
      ...
    })();
  },

  /**
   * 加载 cloudbase-js-sdk
   */
  CloudbaseJSSdkScript: function () {
    (function (exports) {
      /**
       * 以下代码来自于 https://static.cloudbase.net/cloudbase-js-sdk/2.7.13-beta.0/cloudbase.full.js
       */
      ...
    })();
  },
};

mergeInto(LibraryManager.library, asmLibraryArg);

丹尼尔:在微信小游戏中并不需要 js-sdk,这样岂不是会将 js-sdk 打包进小游戏里,不太合适吧

蛋先生:没错,不过别担心,办法是有滴。在 jslib 定义的方法并非都会打包,只有那些显示声明 [DllImport("__Internal")] 的才会打包进去,如下

代码语言:csharp
AI代码解释
复制
[DllImport("__Internal")]
public static extern void Hello();

所以,我们可以定义一个 Preprocessor Symbols(比如 WEIXINMINIGAME),在准备转换成小游戏时,可以在构建 WebGL 的设置中提供这个预定义符号,这样 CloudbaseJSSdkScript 方法就会忽略掉了

代码语言:csharp
AI代码解释
复制
#if !WEIXINMINIGAME
            [DllImport("__Internal")]
            private static extern void CloudbaseJSSdkScript();
#endif

丹尼尔:Nice

云开发数据模型的实现建议

丹尼尔:感觉我现在就可以动手了,想要什么功能就搞什么功能,主动权在手上的感觉真好。就先拿数据模型开刀吧,蛋兄有什么建议吗?

蛋先生:通过查阅 云开发数据模型 SDK 文档,我们可以发现一个规律,就是所有方法都是同一种固定模式 models.[model name].[api name](JSON input)

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
models.post.create({...})
models.post.delete({...})
models.post.get({...})
models.post.update({...})

所以呢,我们只需要在 .jslib 文件里定一个万能的 Models_API 方法,就全都搞定了

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// Assets/Plugins/tcbsdk.jslib

Models_API: async function (callbackId, apiName, params) {
    callbackId = UTF8ToString(callbackId);
    apiName = UTF8ToString(apiName);
    const { modelName, options: optionsStr } = asmLibraryArg
      .Utils()
      .parseInputParams(params);
    const options = JSON.parse(optionsStr);
    const app = asmLibraryArg.Utils().getApp();
    
    const models = app.models;
    const { data } = await models[modelName][apiName](options);
    asmLibraryArg.Utils().sendMessage(callbackId, data);
},

同样在 C# 脚本中实现一个万能的 ModelAPI 方法,而 Get, Create 等方法其实就是通过 ModelAPI 方法来实现的

代码语言:csharp
AI代码解释
复制
// Assets/Scripts/TCBSDK.cs

public class TCBSDK : MonoBehaviour
{        
    private class Models : IModels
    {
        private static readonly Lazy<Models> _instance = new Lazy<Models>(() => new());
        public static Models Instance => _instance.Value;
        private Models() { }

        public Task<T> Get<T>(ModelsReqParams input)
        {
            return ModelAPI<T>(input, "get");
        }
		public Task<T> Create<T>(ModelsReqParams input)
        {
            return ModelAPI<T>(input, "create");
        }	
		...

        private async Task<T> ModelAPI<T>(ModelsReqParams input, string apiName)
        {
            var realInput = new Dictionary<string, object>
            {
                ["modelName"] = input.modelName,
                ["options"] = JsonConvert.SerializeObject(input.options)
            };

            (string, TaskCompletionSource<string>) asyncTask = Internal.GetAsyncTask();

            Internal.Models_API(asyncTask.Item1, apiName, Internal.ParseInputParams(realInput));

            string result = await asyncTask.Item2.Task;
            return Internal.ParseOutputResult<T>(result);
        }
    }

	private class Internal
	{
		[DllImport("__Internal")]
    	public static extern void Models_API(string callbackId, string apiName, string input);
	}	
}	

public class ModelsReqParams
{
    public string modelName { get; set; }
    public Dictionary<string, object> options { get; set; }
}

丹尼尔:入参 options 是个 Dictionary 类型,会不会不太好,是不是还是明确类型好点?

蛋先生:这个问题问得好!如果从代码编写规范来说,当然是要定义类型的,裸奔毕竟不太好。但从实际使用角度来看,Dictionary 反而可能是个不错的选择。因为它省时省力,还对开发者相当友好。

丹尼尔:对开发者友好,这怎么说?

蛋先生:你看看腾讯云开发的云后台,在每个数据模型旁边,都会贴心地给出常用 API 的代码范例,基本上复制过来,稍微改改就能用。

所以,你可以在 web 环境下先尽情调试 JSON 入参,直到结果符合预期。然后再把这 JSON 扔给 GPT,让它帮你生成对应的 C# Dictionary,一气呵成

最后,把代码贴过来,大功告成~

代码语言:csharp
AI代码解释
复制
var options = new Dictionary<string, object>
{
    ["filter"] = new Dictionary<string, object>
    {
        ["where"] = new Dictionary<string, object>
        {
            ["$and"] = new List<Dictionary<string, object>>
                {
                    new Dictionary<string, object>
                    {
                        ["_id"] = new Dictionary<string, string>
                        {
                            ["$eq"] = id
                        }
                    }
                }
        }
    }
};
ModelHello hello = await TCBSDK.Instance.ModelsGet<ModelHello>(new ModelsReqParams() { modelName = "hello", options = options });

丹尼尔:也对,真正的类型校验,云开发的数据模型会严格把关,SDK 只要开发者用得顺手,问题不大

业务逻辑服务接口实现

丹尼尔:最后聊一下业务逻辑服务接口的实现吧,你觉得 Mock 数据要如何实现比较优雅?

蛋先生:通过 interface 声明接口,然后通过 UNITY_EDITOR 预处理符号来判断应该采用哪种实现,编辑器环境用 MockGameAPI,其它则用 RealGameAPI

代码语言:csharp
AI代码解释
复制
    public interface IGameAPI
    {
        Task<ModelsList<GameRealm>> GetRealmList();
        ...
    }

	public class GameAPI
    {
#if UNITY_EDITOR
        public static IGameAPI Instance = new MockGameAPI();
#else
        public static IGameAPI Instance = new RealGameAPI();
#endif
    }

    public class MockGameAPI : IGameAPI
    {
        public Task<ModelsList<GameRealm>> GetRealmList()
        {
            return Task.FromResult(new ModelsList<GameRealm>() { records = new List<GameRealm> { new() { _id = "mock_realm_id", name = "默认" } }, total = 1 });
        }
		...
	}

    public class RealGameAPI : IGameAPI
    {
        public Task<ModelsList<GameRealm>> GetRealmList()
        {

            var options = new Dictionary<string, object>
            {
                ...
            };

            return TCBSDK.Instance.ModelsList<ModelsList<GameRealm>>(new ModelsReqParams() { modelName = Constants.ModelName.GameRealm, options = options });
        }
	}

这样在调用服务接口来实现游戏业务逻辑时就不用关心环境了

代码语言:csharp
AI代码解释
复制
var tcbList = await GameAPI.Instance.GetRealmList();

丹尼尔:明白了,感谢蛋兄,我准备大干一场了

蛋先生:加油,再见

以上完整代码请移步到仓库:https://github.com/daniel-dx/unity-cloudbase-demo 代码有点粗糙,仅供参考,还望见谅!

***

写在最后,别有用心

作为一个前端开发者,零 Unity 零 C# 基础,2 周时间从入门到“精通”( _( ゚Д゚)ノ 从没见过如此厚颜无耻之人),交出这份作业对我来说还算满意

但还是想通过这篇文章来抛砖引玉,指不定有哪位大神能提供其它意想不到的解决方案呢,您说,是吧!( ̄︶ ̄)↗

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
客户评分全球第三国内第一!腾讯云连续3年入选Gartner®容器管理魔力象限
近日,国际市场研究机构Gartner发布2025《容器管理客户之声报告》(Gartner Peer lnsights“Voice of the Customer” for Container Management)与2025《容器管理魔力象限》报告(Magic Quadrant™ for Container Management)。
腾讯云原生
2025/08/10
1330
客户评分全球第三国内第一!腾讯云连续3年入选Gartner®容器管理魔力象限
一不小心,就入选Gartner魔力象限了
就在今天,Gartner发布权威报告《Magic Quadrant for Cloud Database Management Systems》称,凭借在产品矩阵、技术性能方面的领先优势,腾讯云数据库正式进入Gartner云数据库管理系统魔力象限,被评为特定领域者。 可能大家不清楚Gartner和它的魔力象限,怎么说呢,在云计算这个圈子,Gartner基本就是电影届的奥斯卡,音乐界的格莱美,总之就是NB!它的魔力象限就是全球范围的金字招牌,是很多企业组织参考决策的重要依据,因此,这次腾讯云数据库的入选也
腾讯云数据库 TencentDB
2020/11/26
1.1K0
腾讯云数据库入选Gartner®亚太地区云数据库管理系统“客户之选”
近日,Gartner发布《2023年云数据库管理系统“客户之选”》(Gartner Peer Insights™ Voice of the Customer for Cloud Database Management Systems)行业洞察报告,其中腾讯云数据库TDSQL入选卓越表现者象限(Strong Performer),并入选亚太地区“客户之选”象限,受到97%的客户推荐。
腾讯云数据库 TencentDB
2023/07/25
5140
腾讯云数据库入选Gartner®亚太地区云数据库管理系统“客户之选”
执行能力亚太第一!腾讯云连续三年领跑 Gartner® CPaaS 魔力象限“挑战者”
近日,全球权威研究与咨询机构 Gartner®发布《Gartner® 2025 Magic Quadrant™ for Communications Platform as a Service》报告 (下称《报告》),腾讯云成为此次唯一入选的中国厂商,连续三年被评为 CPaaS 市场“挑战者”,在象限执行力维度位居亚太第一,在前瞻性维度表现优异,进一步接近领导者象限。
腾讯云音视频
2025/07/29
1610
执行能力亚太第一!腾讯云连续三年领跑 Gartner® CPaaS 魔力象限“挑战者”
进了,Gartner这个报告有魔力!腾讯云数据库喜提双料第一
12月16日,在刚刚发布的 Gartner® 2022年度《云数据库管理系统魔力象限》研究报告中,腾讯云数据库进入特定领域者(Niche Players)象限。同时,据Gartner云数据库管理系统运行用例关键功能报告,腾讯云数据库在OLTP(TDSQL/TDSQL-C)及轻量级TP能力(KeeWiDB)得分均为国内第一。 根据Gartner云数据库管理系统运行用例关键功能报告,腾讯云数据库TDSQL在OLTP事务、轻量级事务和增强事务三个用例中得分均高于3.0(总分5分,3分以上代表满足要求),其中O
腾讯云数据库 TencentDB
2022/12/18
9900
进了,Gartner这个报告有魔力!腾讯云数据库喜提双料第一
连续两年执行能力位居亚太地区最高位置!腾讯云再获认可,入选Gartner® CPaaS魔力象限报告
值得一提的是,在前不久Gartner®发布的《Market Share: All Software Markets, Worldwide, 2023》报告中显示,2023年,在CPaaS领域,腾讯市场收入稳居亚太第一、中国第一,同时增速位列全球第一。据了解,在CPaaS领域,腾讯云的市场份额已连续三年稳居亚太第一。
腾讯云音视频
2024/07/08
3500
连续两年执行能力位居亚太地区最高位置!腾讯云再获认可,入选Gartner® CPaaS魔力象限报告
腾讯云入选2023 Gartner分布式混合基础设施魔力象限
10月18日,腾讯云入选Gartner最近发布《分布式混合基础设施魔力象限》报告(Magic Quadrant for Distributed Hybrid Infrastructure, September 2023)。
腾讯专有云
2023/10/23
8670
腾讯云入选2023 Gartner分布式混合基础设施魔力象限
IDC发布中国视频云市场报告,腾讯云蝉联解决方案市场排名“七连冠”
4月12日,国际数据公司(IDC)发布《中国视频云市场跟踪(2023下半年)》报告,腾讯云音视频的解决方案份额连续七次获得市场冠军。其中,在视频直播、生产创作与媒资管理赛道也位列首位,在实时互动赛道保持高增长,为企业在全真互联时代的高质量发展提供了坚实的数字化助力。
腾讯云音视频
2024/04/22
6180
IDC发布中国视频云市场报告,腾讯云蝉联解决方案市场排名“七连冠”
腾讯云CPaaS:连续三年上榜,国内唯一,多项第一
全球顶级IT研究机构Gartner® 最新发布2025年CPaaS魔力象限报告(《Gartner® 2025 Magic Quadrant™ for Communications Platform as a Service》):
小腾资讯君
2025/08/12
1380
再次入选!腾讯云列入Gartner®中国基础设施战略成熟度曲线ZTNA领域代表厂商
近日,Gartner®发布“Hype Cycle™ for Infrastructure Strategies in China,2025(《2025年中国基础设施战略成熟度曲线》报告)”,腾讯云入选ZTNA零信任网络访问领域“代表厂商”(Sample Vendors),这是腾讯云第二次入选该系列报告。今年以来,腾讯云已有WAF、NDR、云防火墙、威胁暴露管理、多方安全计算等多项安全能力入选Gartner Hype Cycle年度报告,对腾讯而言,这夯实了作为云安全领导者的市场地位。
用户7206901
2025/07/29
1700
再获认可!腾讯凭借零信任iOA入选Gartner®市场指南
近日,Gartner发布《Market Guide for Zero Trust Network Access, China》(2023年9月)报告,腾讯凭借零信任安全解决方案(iOA)入选中国零信任代表供应商(Representative Vendors)!
小腾资讯君
2023/10/19
4970
再获认可!腾讯凭借零信任iOA入选Gartner®市场指南
To B业务成为腾讯收入的重要支柱,连续五季收入占比超30%
刚刚,腾讯发布2022年Q2财报 二季度,实现营收1340亿元 金融科技及企业服务业务实现营收422亿元 其中,To B业务成为腾讯收入的重要支柱 连续五季收入占比超30% Q2,我们减少亏损订单,并降低成本 营收结构优化,毛利率持续改善 进入高质量发展阶段 未来,我们将跑得更“稳” 深入各行各业,为客户创造价值 本季度,腾讯宣布自研业务全面上云 上云规模突破5000万核 累计节省成本超30亿 “自研上云”全面锤炼了腾讯云 这些领先技术正持续开发给外部客户 更好服务伙伴生态 自研技术获权威认可! 腾讯持
腾讯专有云
2022/08/26
9200
To B业务成为腾讯收入的重要支柱,连续五季收入占比超30%
全球第二!腾讯视觉AI再突破
近日,国际权威研究机构Gartner发布2022年度《Magic Quadrant for Cloud AI Developer Services》研究报告: 腾讯位列“挑战者“象限! 至此,腾讯连续三年入选Gartner云AI开发者服务魔力象限,为中国云厂商中唯一。 同时,腾讯在计算机视觉方面获得了全球第二的评分排名,再次印证了腾讯云在云AI开发者服务领域的国际领先地位。 Gartner指出●● ○作为该领域领先的“挑战者”,腾讯将其丰富的人工智能资源用于游戏、视觉和其他服务,不断创新与完善服务能力;
腾讯云TI平台
2022/06/07
8260
全球第二!腾讯视觉AI再突破
腾讯云凭借零信任iOA连续两年入选Gartner®市场指南代表厂商
近日,Gartner®发布《Market Guide for Zero-Trust Network Access, China》(2024年9月)报告,腾讯云凭借零信任安全解决方案(iOA)入选中国零信任代表供应商(Representative Vendors),这也是腾讯云连续两年再次入选该市场指南。
小腾资讯君
2024/11/01
2510
腾讯云入选Gartner魔力象限!
国际研究机构Gartner最新发布的《Magic Quadrant for Cloud Infrastructure and Platform Services》报告显示—— 腾讯云入选魔力象限 这是Gartner首份以IaaS和PaaS综合服务能力为评估标准的报告。 报告重点提到腾讯云: 技术敏锐 业务增长迅猛 和腾讯其他业务协同效应强大 腾讯在云计算领域有确定性投入计划 唯一在俄罗斯拥有可用区的全球性云服务商   …… 实际上,今年四月Gartner发布的全球云计算市场份额排名报告显示,腾讯云从2
腾讯云AI
2020/09/07
1.3K0
七项安全技术代表厂商!腾讯云再获Gartner®认可
近日,国际研究机构Gartner® 发布《2023中国网络安全技术成熟度曲线(Hype Cycle for Security in China, 2023)》报告,腾讯云在零信任、云工作负载保护平台、态势感知、攻击面管理、机密计算、多方安全计算和开发安全等七大技术领域被列为代表厂商,再度获得Gartner®认可。
小腾资讯君
2023/10/26
5450
数据库半月谈(2022.12.10~2022.12.24)
IDC于12月15日发布了 “2022年上半年中国关系型数据库软件市场跟踪报告”。在本地部署模式,Oracle 仍然是份额最高的厂商,华为云以16.59%的份额排名国内厂商第一。报告指出,2022上半年,中国关系型数据库市场规模为15.5亿美元,同比增长30.4%。本地部署关系型数据库规模6.0亿美元,同比增长15.6%,与2021年同期相比增速下降8.1%;公有云关系型数据库规模9.5亿美元,同比增长42.0%。
用户5548425
2023/02/16
5380
数据库半月谈(2022.12.10~2022.12.24)
Gartner “叫板”IDC,天翼云“原是我不配”!
近日,Gartner 发布《云基础设施和平台服务(CIPS)魔力象限》。CIPS魔力象限研究报告针对厂商的基础设施即服务(IaaS)和平台即服务(PaaS)进行评估,包括应用程序 PaaS (aPaaS)、功能即服务 (FaaS)、数据库 PaaS (dbPaaS)、应用程序开发人员 PaaS (adPaaS) 以及通常部署在企业数据中心的工业化分布式云产品。
SDNLAB
2022/12/14
2.4K0
Gartner “叫板”IDC,天翼云“原是我不配”!
技术立身,精进不止,华为主存储实现Gartner魔力象限两个方向持续提升
最新Gartner全球主存储魔力象限报告《Magic Quadrant for Primary Storage, 2022》中,华为存储再次成为唯一入选领导者象限的中国存储厂商,并且在2021年基准上大幅进步,战略(愿景)完整性和执行能力两方面均显著提升。
大数据在线
2022/12/13
9910
技术立身,精进不止,华为主存储实现Gartner魔力象限两个方向持续提升
从Gartner报告,看中国数据库崛起
近日,多篇新闻引起数据库圈子的广泛关注。随着11月国际权威机构Gartner报告的披露,多家国内厂商入围。以阿里、腾讯、华为等公司,取得了长足的进步。特别是阿里云,在Gartner公布2020年度全球数据库魔力象限评估结果,作为中国科技公司代表,首次挺进全球数据库第一阵营——领导者(LEADERS)象限,这也是中国数据库40年来首次进入全球顶级数据库行列。本文将从Gartner报告入手,谈谈中国数据库力量的崛起。
用户5548425
2020/12/02
9470
从Gartner报告,看中国数据库崛起
推荐阅读
客户评分全球第三国内第一!腾讯云连续3年入选Gartner®容器管理魔力象限
1330
一不小心,就入选Gartner魔力象限了
1.1K0
腾讯云数据库入选Gartner®亚太地区云数据库管理系统“客户之选”
5140
执行能力亚太第一!腾讯云连续三年领跑 Gartner® CPaaS 魔力象限“挑战者”
1610
进了,Gartner这个报告有魔力!腾讯云数据库喜提双料第一
9900
连续两年执行能力位居亚太地区最高位置!腾讯云再获认可,入选Gartner® CPaaS魔力象限报告
3500
腾讯云入选2023 Gartner分布式混合基础设施魔力象限
8670
IDC发布中国视频云市场报告,腾讯云蝉联解决方案市场排名“七连冠”
6180
腾讯云CPaaS:连续三年上榜,国内唯一,多项第一
1380
再次入选!腾讯云列入Gartner®中国基础设施战略成熟度曲线ZTNA领域代表厂商
1700
再获认可!腾讯凭借零信任iOA入选Gartner®市场指南
4970
To B业务成为腾讯收入的重要支柱,连续五季收入占比超30%
9200
全球第二!腾讯视觉AI再突破
8260
腾讯云凭借零信任iOA连续两年入选Gartner®市场指南代表厂商
2510
腾讯云入选Gartner魔力象限!
1.3K0
七项安全技术代表厂商!腾讯云再获Gartner®认可
5450
数据库半月谈(2022.12.10~2022.12.24)
5380
Gartner “叫板”IDC,天翼云“原是我不配”!
2.4K0
技术立身,精进不止,华为主存储实现Gartner魔力象限两个方向持续提升
9910
从Gartner报告,看中国数据库崛起
9470
相关推荐
客户评分全球第三国内第一!腾讯云连续3年入选Gartner®容器管理魔力象限
更多 >
交个朋友
加入腾讯云官网粉丝站
蹲全网底价单品 享第一手活动信息
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档