一座堤的博客 - 3D游戏编程与设计
type: channel
link: https://www.yizuodi.cn/category/3DGame/
items: Unity3d UI系统 UI 效果制作（拓展篇）
items: Unity3d游戏智能 坦克对战游戏AI设计
items: Unity3dUI系统 UI 效果制作
items: Unity3d粒子系统 汽车尾气模拟
items: Unity3d模型与动画 智能巡逻兵游戏
items: 基于Unity3D 编写简单的自定义组件
items: 基于Unity3D引擎构建简单的游戏场景
items: 基于Unity3D的物体抛物线运动实现
items: 基于Unity引擎的井字棋小游戏
items: 2022年9月上旬中国大陆游戏分类与热点分析

Unity3d UI系统 UI 效果制作（拓展篇）
type: item
date: 2023-03-23T15:34:00+08:00
description: 在之前的这一篇博客文章中(www.yizuodi.cn/archives/129)，我们进行了UI 效果制作。在另一篇文章中(www.yizuodi.cn/archives/119)，我们制作了一款智能巡逻兵游戏。本篇文章，我们做了一个简单的用户登录实现，来尝试让我们的智能巡逻兵游戏变成一款网络游戏。为什么要做“用户登录”的部分？对于我们之前的智能巡逻兵游戏中玩家得分的设计，我个人的想法是将得分和通关用时综合考虑。我们分析，得分为躲避得分（成功甩掉计一分）。任务点是随机刷新的，而较难完成的任务点会导致玩家“用时增加，得分增加”概率提升。所以我们可以将游戏得分和通关用时加权求和得到一个分数（类似与很多游戏的“段位分”），来作为玩家游戏成果的评估。“巡逻兵游戏”是一个单机游戏，那么我们怎么通过所谓“段位分”给予玩家满足感呢？我个人的想法是提供一个全球游戏榜单（我制作了一个示例game.233521.xyz）。为此，我们需要一个为玩家提供一个账号系统，需要一个服务端来让所有玩家可以提交他们的游戏结果。我们的设计1.在游戏中，我们有一个登录的UI，玩家点击按钮可以唤起浏览器打开网页进行登录（可拓展微信扫码登录等）。2.登录成功后可以获取到一个一次性登录令牌，玩家复制后在游戏中粘贴，点击登录按钮。若令牌有效即可成功登入。实现效果展示游戏中的登录的UI如下：唤起浏览器打开的登录页面如下(demo)：登录后玩家获取令牌：本人的“3D游戏编程与设计”系列合集，请访问：https://www.yizuodi.cn/category/3DGame/

Unity3d游戏智能 坦克对战游戏AI设计
type: item
date: 2022-11-15T22:39:00+08:00
description: 本文内容为坦克对战游戏AI设计。我们构建 AI 对战坦克有几点目标：· 使用“感知-思考-行为”模型，建模 AI 坦克· 场景中要放置一些障碍阻挡对手视线· 坦克要放置一个矩阵包围盒触发器，保证 AI 坦克能使用射线探测对手方位· AI 坦克必须在有目标条件下使用导航，并能绕过障碍。· 实现人机对战我们使用了资源Tanks! Tutorial（Unity资源商店链接）。接下来我们构建AI对战坦克。游戏设计玩家操纵红色坦克，可以通过WASD按键移动坦克，按空格键发射弹药攻击。地图中有一些蓝色的AI坦克，当玩家出现在AI坦克的视野中，它们就会跟踪玩家并向玩家发射弹药。每辆坦克都有自己的血量值，受到攻击坦克血量会下降，当血量值将为0以下，则坦克被击毁。如果玩家的坦克被击毁则游戏失败，如果玩家击毁了所有的AI坦克则游戏胜利。对于“感知-思考-行为”模型——AI坦克会感知周围是否有玩家存在，进行思考:1.没有玩家，那么就进行行动巡逻。2.有玩家，那么就进行行动追捕。继续进行感知：1.若玩家进入AI坦克的射击范围，则进行行动射击。2.若玩家没有进入AI坦克的射击范围，则继续进行行动追捕。游戏展示场景布置我们先简单布置场景：NavMesh是unity提供的导航寻路功能。我们先将地图设置为“navigation static”，然后选中，选择最顶部的窗口-AI-导航。在Navigation窗口给地图中的各个对象设置walkable或者not walkable等，然后进行bake烘培，得到描述游戏对象可行走的表面的数据结构Navigation Mesh。可通过这些三角网格计算其中任意两点之间的最短路径用于游戏对象的导航，作为“感知-思考-行为”模型中的“感知”。然后我们制作三种预制件——敌方（AI）坦克、玩家坦克和炮弹。脚本编写我们考虑游戏的双方：AI坦克和玩家坦克的共性——都有血量。因而我们可以先定义一个共同的基类Tank如下：public class Tank : MonoBehaviour { private float hp; // 血量 public float getHp() // 获取血量 { return hp; // 返回血量 } public void setHp(float hp) // 设置血量 { this.hp = hp; // 设置血量 } }然后对于坦克的一些事件，我们有接口类IUserAction，包含坦克前进、后退、转向、射击和游戏状态获取：public interface IUserAction { void moveForward(); void moveBack(); void turn(float offsetX); void shoot(); bool isGameOver(); }我们有一个场景控制器SceneController来掌控全局。因此对于玩家的坦克PlayerTank，我们只需要在其发现自己血量低于零时，销毁自己并发布相应事件共控制器处理即可：public class PlayerTank : Tank { public delegate void destroy(); public static event destroy destroyEvent; void Start (){ setHp(1000f); } void Update (){ if(getHp() <= 0){ this.gameObject.SetActive(false); if (destroyEvent != null) destroyEvent(); } } }而对于AI坦克，我们有“思考”。如果其在自己附近没有发现玩家，则进行巡逻。若发现了玩家则开始追捕；一旦追捕使得玩家出现在其一定范围内（射程内），则其开炮射击。这一系列就是对应“行动”。using UnityEngine.AI; public class AITank : Tank { public delegate void recycle(GameObject tank); // 回收事件委托 public static event recycle recycleEvent; // 回收事件 private Vector3 target; // 目标点 private bool gameover; // 游戏结束状态 private static Vector3[] points = { new Vector3(37.6f,0,0), new Vector3(40.9f,0,39), new Vector3(13.4f, 0, 39), new Vector3(13.4f, 0, 21), new Vector3(0,0,0), new Vecto…

Unity3dUI系统 UI 效果制作
type: item
date: 2022-11-15T22:37:00+08:00
description: 本文主要涉及UI效果制作——UGUI实现Quest Log公告牌效果。进入 NGUI 官方网站，有以下效果• Inventory 背包系统• Quest Log 公告牌• Scroll View 选择板注：以上例子需要使用 Unity web player， 仅支持以下操作系统与浏览器，参见官方下载• Windows 版 IE11• Mac OS X 10.7 Safari注：出现界面需要等待较长时间，让它慢慢加载NGUI提供的示例如下图：而UGUI是由unity官方提供的UI工具套件。参考它们的区别：https://www.jianshu.com/p/5891e28aa766场景布置我们可以通过创建UI-面板创建一个panel（面板），其根目录为canvas（画布）。然后我们在panel中创建一个文本，作为公告栏的标题；在panel中添加一个ScollView（滚动视图）作为公告栏的主要内容部分；在panel中添加一个button（按钮）作为公告栏“关闭”按钮。略作调整后效果如图（这里我们使用了2D Casual UI资源包）：滚动视图的完善上面我们的UI界面中，只有滚动视图，里面还没有详细的内容，我们继续为其添加详细的内容。我们先在Viewport的Content中加入组件“Vertical Layout Group”，设置勾选“控制子对象大小-宽度”和“子力拓展-宽度”，其他不勾选。然后我们在Content下创建三个Button（命名为Button1，Button2，Button3）和三个Text（命名为Text1，Text2，Text3）。在Button的检查器中，我们将导航设置为None。我们需要为按钮加上脚本，使其被点击时，对应的文本展示/不展示。脚本extend内容如下：using UnityEngine.UI; public class extend : MonoBehaviour { public Text text; // 控制的Text对象 private int frame = 20; // 动画帧数 void Start() { Button btn = this.gameObject.GetComponent (); // 获取Button对象 btn.onClick.AddListener(TaskOnClick); // 添加点击事件 text.gameObject.SetActive(false); // 初始化时隐藏Text } IEnumerator FoldAndUnfold(bool isFold) { Vector2 fold = new Vector2(0, 120); // 折叠状态 Vector2 unfold = new Vector2(-90, 0); // 展开状态 Vector2 target = isFold ? fold : unfold; for (int i = 0; i < frame; i++) // 逐帧执行动画 { target.x += (isFold ? -90f : 90f) / frame; // 旋转角度逐帧增加或减少 target.y += (isFold ? -120f : 120f) / frame; // Text高度逐帧增加或减少 text.transform.rotation = Quaternion.Euler(target.x, 0, 0); // 设置旋转角度 text.rectTransform.sizeDelta = new Vector2(text.rectTransform.sizeDelta.x, target.y); // 设置Text高度 if (i == 0 || i == frame - 1) // 第一帧和最后一帧控制Text的显示状态 { if(isFold){ text.gameObject.SetActive(false); } else{ text.gameObject.SetActive(true); } } yield return null; } } void TaskOnClick() { if (text.gameObject.activeSelf) // 判断Text是否显示 { StartCoroutine(FoldAndUnfold(true)); // 执行折叠动画 } else { StartCoroutine(FoldAndUnfold(false)); // 执行展开动画 } } }这样我们就成功实现了与NGUI中例子类似的效果。效果展示本人的“3D游戏编程与设计”系列合集，请访问：https://www.yizuodi.cn/category/3DGame/

Unity3d粒子系统 汽车尾气模拟
type: item
date: 2022-11-15T10:15:00+08:00
description: 本文使用官方资源 Vehicle 的 car， 使用 Smoke 粒子系统模拟启动发动、运行、故障等场景效果，完善“汽车尾气”模拟场景布置我们需要先导入Unity3D 官方资源包Standard Assets，该资源包已经不再内置，而且资源商店也没有，我提供一份附在这里。Standard Assets.unitypackage（68.4M）网上找来的资源包导入后，可能会有一些问题，可参考：https://blog.csdn.net/Sakuya__/article/details/113815974我们导入资源包后，先在场景中放置一个3D平面对象（plane），然后在资源包中找到Vehicle 的 car的预制，拖入场景中，效果如下图：粒子效果模拟根据要求，我们模拟启动发动、运行、故障三种场景的尾气效果。预制的Car里面的Particles里有一个Smoke粒子系统ParticleBurnoutSmoke。我们的粒子系统叫做start、run和damage。在检查器中，粒子系统有很多设置选项，我们可以根据自己的需要选择。由于Standard Assets资源包内置了一些材质，我们可以在粒子系统的渲染器（render）-材质（material）选项中选用，从而让粒子有不同的形状。为了展示不同的尾气效果，我们编写脚本CarStatus加到Car这个游戏对象上，功能为按下键盘上的数字选择尾气的效果（数字1-4）。public class CarStatus : MonoBehaviour { // 定义需要切换的粒子效果 public ParticleSystem[] particleSystems; // 当前粒子效果的索引 public int currentIndex = 0; void Start() { particleSystems = new ParticleSystem[4]; particleSystems[0] = transform.Find("Particles/ParticleBurnoutSmoke").GetComponent<ParticleSystem>(); particleSystems[1] = transform.Find("Particles/start").GetComponent<ParticleSystem>(); particleSystems[2] = transform.Find("Particles/run").GetComponent<ParticleSystem>(); particleSystems[3] = transform.Find("Particles/damage").GetComponent<ParticleSystem>(); // 将所有粒子效果关闭 for (int i = 0; i < particleSystems.Length; i++) { particleSystems[i].Stop(); } } void Update() { // 当按下键盘对应数字键时，切换粒子效果 if (Input.GetKeyDown(KeyCode.Alpha1)) { // 将当前粒子效果关闭 particleSystems[currentIndex].Stop(); // 将当前粒子效果索引设置为0 currentIndex = 0; // 将当前粒子效果打开 particleSystems[currentIndex].Play(); } else if (Input.GetKeyDown(KeyCode.Alpha2)) { particleSystems[currentIndex].Stop(); currentIndex = 1; particleSystems[currentIndex].Play(); } else if (Input.GetKeyDown(KeyCode.Alpha3)) { particleSystems[currentIndex].Stop(); currentIndex = 2; particleSystems[currentIndex].Play(); } else if (Input.GetKeyDown(KeyCode.Alpha4)) { particleSystems[currentIndex].Stop(); currentIndex = 3; particleSystems[currentIndex].Play(); } } }为了方便观察，我们把之前项目中CameraMove脚本也拿来稍作修改，附加到主摄像头上。public class CameraMove : MonoBehaviour { public…

Unity3d模型与动画 智能巡逻兵游戏
type: item
date: 2022-11-15T10:11:00+08:00
description: 游戏设计： • 创建一个地图和若干巡逻兵(使用动画)；• 每个巡逻兵走一个3~5个边的凸多边型，位置数据是相对地址。即每次确定下一个目标位置，用自己当前位置为原点计算； • 巡逻兵碰撞到障碍物，则会自动选下一个点为目标； • 巡逻兵在设定范围内感知到玩家，会自动追击玩家； • 失去玩家目标后，继续巡逻； • 计分：玩家每次甩掉一个巡逻兵计一分，与巡逻兵碰撞游戏结束； 程序设计： • 使用订阅与发布模式传消息• 工厂模式生产巡逻兵游戏设计基于上面的几点，我们设计这样一个游戏场景：1.我们的地图有3×3共计9块区域，不同区域间有部分连通，每个区域有一个巡逻兵。2.地图上会随机生成一些任务点，作为玩家需要到达的目标位置，这些任务点需要玩家全部到达且未被巡逻兵碰撞到方为获胜。3.每到达一个任务点时为甩掉巡逻兵一次，计一分。4.每次游戏任务点位置随机分布在地图上，但总的任务点数量一定。5.玩家初始位置为地图区域的中心位置。游戏展示游戏操作演示1-游戏各项操作（11.7M）游戏操作演示2-失败（1.17M）游戏操作演示3-完成（0.9M）游戏预制制作基于上面的要求与设计，可以先为我们的游戏场景创建4个预制：地图、玩家、“任务点”、巡逻兵。地图我使用了Low Poly v2资源包进行预制制作。玩家和巡逻兵我基于SoldierFree资源包中的预制制作，我们为两个预制添加Rigidbody和Capsule Collider来实现玩家与巡逻兵的碰撞。对于巡逻兵的预制，我们添加了两个脚本，一个脚本用于记录巡逻兵对象的一些信息，另一个脚本用于处理玩家与巡逻兵相撞后的情况。另外我们添加了一块方形的碰撞器（设置为触发器）来探测玩家，并添加了相应的脚本来使得有玩家进入/离开该方形区域时，巡逻兵开始/停止追捕玩家。我们使用了Animator组件，通过控制器来使得对应的对象做出相应的动画行为。它是使用状态机来管理运动的，我们在脚本中可以设置状态的改变，从而对应有对象（玩家或巡逻兵）的动画表现。然后我们将玩家对象和巡逻兵对象对应的控制器加到预制上。“任务点”目前是简单的用红色圆球来代替（其碰撞体积也为圆球）。这样我们就拥有了一些游戏的基本元素。脚本编写我们的实现要求是：订阅与发布模式传消息和工厂模式生产巡逻兵。我们先给出主摄像机上附加脚本CameraMove，从而我们可以在移动玩家游戏对象时伴随镜头的移动。public class CameraMove : MonoBehaviour { public GameObject follow; // 跟随的对象 public float speed = 5f; // 相机跟随的速度 Vector3 offset; // 相机与物体相对偏移位置 void Start() { offset = transform.position - follow.transform.position; } void FixedUpdate() { Vector3 target = follow.transform.position + offset; // 计算目标位置 transform.position = Vector3.Lerp(transform.position, target, speed * Time.deltaTime); // 摄像机自身位置到目标位置平滑过渡 } }对于我们的巡逻兵，我们有一个脚本PatrolData附加其上，用于保存它的一些信息public class PatrolData : MonoBehaviour { public int block; // 巡逻兵所在区域编号 public bool follow_player = false; // 是否正在追逐玩家 public int player_block = -1; // 此时玩家所在区域编号 public GameObject player; // 玩家游戏对象 public Vector3 start_position; // 巡逻兵初始位置 }接着我们给出几个预制中与碰撞相关的脚本（里面使用了控制器等部分后续给出）。首先对于场景，我们对9块区域都附加上PlaneCollide脚本，以更新玩家所在的区域信息。public class PlaneCollide : MonoBehaviour { public int block = 0; FirstSceneController sceneController; private void Start() { sceneController = SSDirector.GetInstance().CurrentScenceController as FirstSceneController…

基于Unity3D 编写简单的自定义组件
type: item
date: 2022-10-16T08:09:00+08:00
description: 本文参考官方手册(https://docs.unity3d.com/ScriptReference/Editor.html)，编写一个简单的自定义Component(组件)，用自定义组件定义几种飞碟，编辑并赋予飞碟一些属性，做成预制首先我们可以定义飞碟的一些共有的属性，脚本DiskData：public class DiskData : MonoBehaviour { public int score = 1; // 射击命中得分 public Color color = Color.white; // 颜色 public Vector3 direction; // 初始的位置 public Vector3 scale = new Vector3(1 ,0.25f ,1); // 大小 }我们把它绑定到飞碟上，在检查器中可以看到几项属性：继续参考Unity的文档：https://docs.unity3d.com/cn/current/ScriptReference/Editor.html可知需要我们新建一个继承Editor的脚本类MyDiskEditor，让我们有一个使用 IMGUI 和多重选择的自定义检视面板。如下：using UnityEngine; using UnityEditor; using System.Collections; [CustomEditor(typeof(DiskData))] [CanEditMultipleObjects] public class MyDEditor : Editor { SerializedProperty score; // 分数 SerializedProperty color; // 颜色 SerializedProperty scale; // 大小 void OnEnable() { // 序列化属性 score = serializedObject.FindProperty("score"); color = serializedObject.FindProperty("color"); scale = serializedObject.FindProperty("scale"); } public override void OnInspectorGUI() { serializedObject.Update(); // 更新序列化属性 EditorGUILayout.IntSlider(score, 0, 5, new GUIContent("score")); // 分数 if (!score.hasMultipleDifferentValues) { ProgressBar(score.intValue / 5f, "score"); // 进度条 } EditorGUILayout.PropertyField(color); // 颜色 EditorGUILayout.PropertyField(scale); // 大小 serializedObject.ApplyModifiedProperties(); // 应用修改 } private void ProgressBar(float value, string label) { Rect rect = GUILayoutUtility.GetRect(18, 18, "TextField"); // 进度条的位置 EditorGUI.ProgressBar(rect, value, label); // 进度条 EditorGUILayout.Space(); // 空行 } }然后我们制作5款不同的飞碟，它们的大小、颜色不同，击中后得分亦不同：下面分别是第1个和第5个飞碟的情况：本人的“3D游戏编程与设计”系列合集，请访问：https://www.yizuodi.cn/category/3DGame/

基于Unity3D引擎构建简单的游戏场景
type: item
date: 2022-10-09T14:32:00+08:00
description: 本文主要基于资源商店中获取到的Fantasy Skybox FREE资源包，进行游戏场景构建，并为场景设计地形（有树木和草地等元素）首先我们从资源商店获取到Fantasy Skybox FREE资源包：https://assetstore.unity.com/packages/2d/textures-materials/sky/fantasy-skybox-free-18353然后在我们的项目中导入资源包（在包管理器中找到它，下载并导入）。导入完成后，我们在 窗口-渲染-光照 选项中，选择环境，选择天空盒材质以应用上述资源包中的材质。然后，我们在组件中找到上述资源包的SampleTerrain并添加，让我们的场景中有地形的存在，添加成功后效果如下：Unity Editor包含的地形(Terrain)功能，可以让我们添加地形，并对地形进行一些操作（地形升降、添加花草等），文档内容可见：https://docs.unity3d.com/cn/current/Manual/script-Terrain.html根据上述描述，在Fantasy Skybox FREE内置SampleTerrain的地形基础上，我们使用其“绘制细节”，里面的细节包含了两种草和一种花，可供我们直接使用，我们为场景添加后效果如下：另外，我们可能还需要一些树，Unity为我们提供了树编辑器(Tree Editor)，用于在编辑器内直接设计树。可见文档：https://docs.unity3d.com/cn/current/Manual/class-Tree.html在 游戏对象-3D对象-树 中，我们可以创建树，依据文档的指引，我们可以有一棵如下的树：我们为它的树枝和树叶加一些材质，就形成了一棵完整的树：添加到游戏里面，效果如下：当然，我们自行制作的树可能还不够美观，如果不喜欢的话，我们还可以选用资源商店中提供的资源包。比如使用Mobile Tree Package(https://assetstore.unity.com/packages/3d/vegetation/trees/mobile-tree-package-18866)资源包中的树，效果如下：这样，我们就构建了简单的游戏场景。本人的“3D游戏编程与设计”系列合集，请访问：https://www.yizuodi.cn/category/3DGame/

基于Unity3D的物体抛物线运动实现
type: item
date: 2022-10-05T21:31:00+08:00
description: 本文主要涉及基于Unity3D的物体的抛物线运动实现。方法 1：直接修改对象的Transform属性using System.Collections; using System.Collections.Generic; using UnityEngine; public class Move : MonoBehaviour { void Start(){} void Update() { this.transform.position += Vector3.right * Time.deltaTime * 3; this.transform.position += Vector3.down * Time.deltaTime * 3; } }方法 2：使用向量Vector3的方法我们将对象的最新位置用Vector3向量来表示，然后将这个向量赋给对象。下面我们让对象水平方向匀速，垂直方向受重力（模拟）影响下落。using System.Collections; using System.Collections.Generic; using UnityEngine; public class Move : MonoBehaviour { float accumulateTime = 0; void Start(){} void Update() { accumulateTime += Time.deltaTime; //水平方向匀速运动 float x = 5 * accumulateTime; //垂直方向重力加速度下落运动 float y = 30 - 9.8f * 0.5f * Mathf.Pow(accumulateTime, 2); Vector3 pos = new Vector3(x, y, 0); if (pos.y >= 0) { transform.position = pos; } } }方法 3：通过Rigidbody组件移动物体Rigidbody组件可以让对象受物理引擎的控制。我们可以开启重力作用，并赋予物体一个水平速度，从而实现抛物线运动。using System.Collections; using System.Collections.Generic; using UnityEngine; [RequireComponent(typeof(Rigidbody))] public class Move : MonoBehaviour { private Rigidbody rigidbody; private Vector3 initSpeed; void Start() { rigidbody = this.GetComponent<Rigidbody> (); initSpeed = new Vector3 (3, 0, 0); rigidbody.velocity = initSpeed; } void Update(){} }方法 4：通过CharacterController组件移动物体CharacterController，即角色控制器，我们可以用其提供的Move方法来实现抛物线运动。using System.Collections; using System.Collections.Generic; using UnityEngine; [RequireComponent(typeof(CharacterController))] public class Move : MonoBehaviour { private CharacterController cc; private Vector3 speed; void Start() { cc = this.GetComponent<CharacterController> (); speed = new Vector3 (5, 0, 0); } void Update() { speed += 3 * Time.deltaTime * Vector3.down; cc.Move (speed * Time.deltaTime); } }本人的“3D游戏编程与设计”系列合集，请访问：https://www.yizuodi.cn/category/3DGame/

基于Unity引擎的井字棋小游戏
type: item
date: 2022-09-24T21:53:00+08:00
description: 游戏玩法介绍井字棋，英文名叫Tic-Tac-Toe，是一种在3*3格子上进行的连珠游戏，和五子棋类似，由于棋盘一般不画边框，格线排成井字故得名。玩家需要轮流在一有九格方盘上做记号，谁先把三个同一记号排成横线、直线、斜线，谁就是获胜者。游戏演示下面的第一幅动图中，分别演示了“开始游戏”、“重新开始”游戏功能和A获胜、B获胜两种情况，还有获胜的三种方式(横、竖、对角线)。当然，我们也有平局的情况：代码展示完整的代码如下，OnGUI每帧都会被调用，从而实现我们的游戏功能。using System.Collections; using System.Collections.Generic; using UnityEngine; public class game : MonoBehaviour { private int[,] chess_state = new int[3, 3]; // 棋盘落子状态，0: empty, 1: playerA, 2: playerB private int turn = 1; // 回合，1: playerA, 2: playerB private bool start_state = false; // 用于标定游戏是否开始 private int game_state = 0; // 游戏状态0: 棋盘未满，1: playerA, 2: playerB, 3: 平局 // Start is called before the first frame update void Start() { start_state = false; newGame(); } // Update is called once per frame void Update() { } // 开始新的对局 private void newGame() { game_state = 0; turn = 1; for (int i = 0; i < 3; i++) for (int j = 0; j < 3; j++) chess_state[i, j] = 0; } // 判断是否获胜 private int getGameState() { for (int i = 0; i < 3; i++) { // 判断竖向是否有相同的棋子 if (chess_state[i, 0] != 0 && chess_state[i, 0] == chess_state[i, 1] && chess_state[i, 0] == chess_state[i, 2]) return chess_state[i, 0]; // 判断横向是否有相同的棋子 if (chess_state[0, i] != 0 && chess_state[0, i] == chess_state[1, i] && chess_state[0, i] == chess_state[2, i]) return chess_state[0, i]; } // 判断对角线是否有相同的棋子 if (chess_state[0, 0] != 0 && chess_state[0, 0] == chess_state[1, 1] && chess_state[0, 0] == chess_state[2, 2]) return chess_state[1, 1]; if (chess_state[0, 2] != 0 && chess_state[0, 2] == chess_state[1, 1] && chess_state[0, 2] == chess_state[2, 0]) return chess_state[1, 1]; // 判断棋盘是否已满，如果没有，则返回0 for (int i = 0; i < 3; i++) for (int j = 0; j < 3; j++) if (chess_state[i, j] == 0) return 0; return 3; } // OnGUI每帧都会被调用，用于绘制UI void OnGUI() { GUI.skin.button.fontSize = 20; GUI.skin.button.fontStyle = FontStyle.Bold; GUI.skin.button.normal.background = null; GUI.skin.button.hover.background = null; GUI.skin.button.active.background = null; GUI.skin.label.fontSize = 20; GUI.skin.label.normal.textColo…

2022年9月上旬中国大陆游戏分类与热点分析
type: item
date: 2022-09-05T00:00:00+08:00
description: 游戏分类简要描述首先我们需要了解，对于游戏的分类，我们没有严格的分类方法——游戏世界本就是丰富多彩的，我们可以依照游戏玩法、游戏平台、游戏内容、盈利模式、发行地区等等因素来进行分类。我绘制了如下的思维导图来进行展现（思维导图由幕布生成。）。点我在“幕布”中访问该思维导图手机游戏市场下载量/排名信息分析我们下面选取了iOS App Store、小米应用商店、魅族应用商店、华为应用商店、OPPO应用商店、豌豆荚、应用宝几大手机应用商店的游戏分类榜单和TapTap（心动网络旗下游戏社区）数据。数据均选取“中国区”数据（因此Google play数据不纳入分析范围）。统计时间：2022年9月11日20:00（下方仅作数据展示，查看分析请直接跳到本文末尾）App Store数据小米应用商店魅族应用商店华为应用商店OPPO应用商店豌豆荚应用宝TapTap热玩榜根据上面的榜单数据，简单统计得到部分游戏在上述榜单的出现次数：（上述分类参考游戏市场给予游戏的标签，由于游戏实际玩法多样，不能以单一类型定性，因而上述分类仅能用作参考）由此我们知晓，当前游戏市场的热点——1.主要市场由头部厂商占据。统计数据中，腾讯共上榜游戏12款，网易上榜4款，米哈游上榜2款，上榜的其他厂商均只有一款游戏上榜。2.动作游戏较为热门。包括像“和平精英”类型的“吃鸡”游戏，“王者荣耀”、“英雄联盟手游”为代表的moba游戏。它们用各种方式消灭敌人或保存自己以过关，不刻意追求故事情节，符合当代人通过“无脑”游戏来释放解压的短平快的需求。3.一些休闲益智游戏经久不衰。比如“贪吃蛇大作战”是一款2016年6月8日上线的竞技性质的休闲游戏，6年过去仍然上榜两次。带有策略属性的“开心消消乐”，2013年8月，正式在网页版上线，2014年2月推出iOS版本，2014年4月推出Android版本，至今仍能上榜4次。桌面类的“欢乐斗地主”从桌面，到PC、再到手机，也是经久不衰。这表现出玩家对于休闲益智游戏持续的需求，也正说明休闲益智游戏满足了玩家的需要。4.一些其他平台移植的游戏仍有热度。例如榜单上的“QQ飞车手游”、“使命召唤手游”。5.“二次元”类型游戏较为热门。以此类主题游戏起家的米哈游在上述统计中上榜两次，“明日方舟”在榜单上亦有较好表现。6.休闲的沙盒类游戏颇受欢迎。由Mojang开发、网易代理的“我的世界”上榜四次，迷你玩科技的类似产品“迷你世界”也上榜五次。