30分钟带你零基础入门小游戏开发

1,147 阅读5分钟

前言

这两天在独立开发群里有做web的小伙伴想搞下小游戏开发,我突然想到,之前在语雀写了一个入门小游戏的文档知识库,本来想做成章节视频来分享,然而我发现B站号出了点问题,所以准备在掘金上先写一篇文。

我最近愈发觉得那种动辄几千上万字的技术文章,且里面掺杂了各种代码块的技术分享,在现在的一个大环境下不是那么适合了,其一是容易陷进去细节里面,我觉得代码细节查阅文档或者去问AI都是可以的,其二就是大而全的技术文章很难完全吃透,甚至可能陷入知识盲点的循环,然后又去解决盲点,最终无始无终。

所以我看了下我语雀的那些文档,瞬间就想尝试下用不求甚解+ 高性价比的学习法,来写这篇文章,希望用尽量少贴甚至不贴代码块的方式,来搞一篇技术分享来给那些对小游戏感兴趣的小伙伴。如果能让小伙伴付出最少得成本入门,我需要尽量减少模棱两可得描述,尽量再每一段给出一个无歧义的结论(个人拙见,不对请指正哈);更需要尽量减少字数,可以快速阅读完。

引擎选择

结论:cocos creatorlayaAir 二选一。

原因:

  1. 用TS开发,省去了语言学习的成本。
  2. 国人开发的,中文文档支持更好,开发习惯更适合国人。
  3. 学习新技能能更快速获得正向反馈,学习成果越好,效率越高;等熟悉入门了再换别的引擎不迟。

引擎开发游戏的整体思路

  1. 引擎一般自带一个IDE,类似于一个拖拽的低代码编辑器,大部分操作都在IDE里面靠鼠标拖拽完成。
  2. 游戏逻辑需要写脚本,脚本挂载在固定的节点元素上,所有的逻辑都是操作节点(类似jquery)。
  3. 抛弃已经熟悉的现代化web框架 MVVM 那种疯狂操作数据的方式,引擎的核心是脚本操作节点。
  4. 动画需要美术制作图集,引擎一键生成动效。

引擎开发游戏极简学习内容

场景

  • 场景就是界面,当然也就有 创建场景销毁场景场景切换等动作,一般游戏界面很少,小游戏就那么几个,不像web动辄几十几百

资源

  • 大部分是美术资源,预制体资源

节点

  • 主要是指精灵,类似于web的div,万能容器,什么都能用它,游戏界面上所有的元素其实都是节点。

UI节点

  • 主要是引擎官方高度封装的各种常规UI组件,比如输入框,列表什么的,不细说。

脚本

  • 操作界面元素的TS脚本,官方封装了生命周期,不同的生命周期做不同的操作。

物理

  • 主要是刚体和碰撞体。一般不会用纯数学逻辑检测物体碰撞,而是用引擎封装的刚体和碰撞体检测。

网络

  • 引擎官方一般提供HTTPWebSocket两种,就按照平时封装 axios、fetch、websocket的方法整体封装一遍即可。
  • 联网小游戏需要额外封装 websocket,主要就是 广播全服、广播房间和广播某个具体用户之类的方法。

事件

  • 场景、节点、UI节点的回调事件,主要是什么点击、触屏、滑动、失焦聚焦之类的。

编译发布

  • 引擎非常成熟,配置1分钟,点一下按钮即可编译成各个平台的应用,主流就是移动双端(安卓、ios)和小程序双端(微信、抖音)。

部分游戏逻辑极简说明

操作玩家移动

  1. 给玩家节点挂载纹理,也就是玩家的美术资源,比如玩家是一只坤
  2. 给玩家节点挂载脚本,脚本监听键盘或者触屏事件,比如按A向左移动,那么就监听到按A,则将玩家节点的x坐标减少一定数值,监听的间隔帧数越小,则手感越好,同样的,占用内存越多,也越消耗性能。
handleMouseMove(e: any | null = null) {
 if (!this._started) return;
 if (!this.enabled) return;
 const touchPos = KeyBoardManager.getTouchPos();
 const mouseX = touchPos?.x, mouseY = touchPos?.y;
 if (mouseX === this.mouseX && mouseY === this.mouseY) {
  return;
 }
 if ((this.mouseX === 0 && this.mouseY === 0) || (mouseX === 0 && mouseY === 0)) {
  return;
 }
 let angle = Math.atan2(mouseY - this.mouseY, mouseX - this.mouseX);
 let playerX = Math.round(this.player.x + this.speed * Math.cos(angle));
 let playerY = Math.round(this.player.y + this.speed * Math.sin(angle));
 this.player.pos(playerX, playerY);
 this.mouseX = mouseX;
 this.mouseY = mouseY;
}

碰撞检测

  1. 给玩家、地形、怪物等挂载刚体和碰撞体组件。
  2. 玩家遇到障碍物、玩家遇到怪物等情况,一般需要进行碰撞检测,在碰撞检测的回调里写相关逻辑,比如玩家掉血,释放被动技能等。

释放技能

  1. 当玩家下达释放技能指令,创建技能动画节点,并挂在刚体碰撞体。
  2. 进行检测,技能命中怪物,则执行怪物脚本的方法,比如掉血、被击中动效等。

怪物AI

  1. 怪物身上挂载了怪物脚本,定时检测指定半径内是否有玩家出现。
  2. 如出现,则以一定速率向玩家移动,普通三角函数计算即可。
  3. 如果玩家移动,则获取玩家新坐标,变换方向继续向玩家移动。
moveToPlayer(): void {
 const enabled = GameRT.instance.getEnabled();
 if (!enabled) {
  return
 }
 const pos = GameRT.instance.getPLayerPos();
 const direction = {
  x: pos.x - this.owner.x,
  y: pos.y - this.owner.y
 }
 // 计算向量的长度
 const length = Math.sqrt(direction.x * direction.x + direction.y * direction.y);
 // 归一化方向向量
 direction.x /= length;
 direction.y /= length;
 this.owner.pos(this.owner.x + direction.x * this.speed, this.owner.y + direction.y * this.speed)
}

怪物生成

  • 固定位置生成,将怪物列表及生成时间存储在list里面,按照死亡间隔定时生成怪物。
  • 随机生成怪物,通过游戏设定在玩家指定半径外随机生成。

小游戏整体开发流程

image.png

写在最后

有正反馈,更有获得感的学习才是我们所追求的,为了学技能而学技能属于自我感动,共勉!