我正在参加掘金社区游戏创意投稿大赛团队赛,详情请看:游戏创意投稿大赛
前言
2022 年,我加入了“猿创营”,我在大帅带领下,参加了掘金游戏创意大赛,感觉收益颇多,这也是我首次在掘金写文章,希望以后多多参加这样的活动,收获更多的知识。
演示地址:game.runjs.cool
队友文章:《 使用 phaser3 从零实现一个战疫小游戏》
技术选型
我之前也没有开发过 H5 游戏,我和我的群友在群里讨论,大家选择的技术栈多大多都是保底实现 HTML+JS+CSS
,而我们队伍想通过本次开发,希望在以后的工作中也能够快速开发出一款小游戏;所以我们选择比较新的技术架构。
- 游戏引擎:Phaser,一个开源的 JavaScript 2D 游戏开发框架;
- 项目脚手架: Vite: ,可快速启动 web 开发服务器,可以快速热更新,
- 开发语言:Typescript: 使用 ts 可以有非常强大类型提示功能,可以减少我们查 api 文档的次数
寓意
细心的掘友们,应该不难发现,这个是一个很简单英雄消灭怪物,寻找食物的游戏。结合当下疫情的严峻形式,我们融入了一些元素到这款游戏中,由于很久没有出门玩耍了,我们选择了绿色的草坪,这样的游戏场景。然后我们给英雄也戴上了口罩,希望疫情早日结束吧!
PS:寓意消灭新冠病毒,争取生命。
游戏介绍
进入游戏后,方向键控制英雄行走,空格键攻击怪物。当英雄走到怪物一定距离后怪物能追踪英雄,英雄靠近怪物后可以攻击怪物,当英雄不小心让怪物近身后英雄会掉血,直到血掉完了,游戏也就完了。英雄看见食物可以拾取,拾取到一个食物得 10 份,第一关 30 分,进入下一关,第二个 100 分。
游戏关卡
我来开发负责这个关卡的功能。下面来说说我加入的关卡逻辑:
根据获得积分来定位关卡,当获得 30 分后就进入下一关,获得 100 分又进入下一关等以此类推。
因此我们先定义一个数据结构:
[
{
name: "Level-1",
score: 30,
},
{
name: "Level-2",
score: 100,
},
]
Level-1
和Level-2
正好对应 Tiled JSON 文件用来作为游戏地图名称。
下面是加载游戏地图的主要代码
第一步:
function preload ()
{
this.load.tilemapTiledJSON('Level-1', 'maps/Level1.json');
}
先在 preload 加载游戏资源
第二步
function create ()
{
var map = this.make.tilemap({ key: 'Level-1' });
}
将资源地图作为当前的地图。
我们从 loading 场景中加载第一关的游戏地图
create(): void {
this.scene.start("game-scene", {
name: "Level-1",
});
this.scene.start("ui-scene", {
name: "Level-1",
});
}
然后在初始化地图的 initMap
方法可以接收一个参数 name
private initMap(name: string): void {
this.map = this.make.tilemap({
key: name,
tileWidth: 16,
tileHeight: 16,
});
this.tileset = this.map.addTilesetImage("Grass", "Grass");
this.groundLayer = this.map.createLayer("Ground", this.tileset, 0, 0);
this.wallsLayer = this.map.createLayer("Walls", this.tileset, 0, 0);
this.wallsLayer.setCollisionByProperty({ collides: true });
this.physics.world.setBounds(
0,
0,
this.wallsLayer.width,
this.wallsLayer.height
);
//this.showDebugWalls();
}
在不增加游戏元素的时候,以上代码就可以做到同一个 Game 类来实现多张地图的逻辑。
UI 显示游戏关卡
同样,在 UI 场景我们需要显示当前是第几关
create(props: any): void {
this.levelName = props.name;
this.score = new Score(this, 20, 20, 0);
new Text(this, 20, 100, `关卡:${this.levelName}`);
this.initListeners();
}
我们可以在 create 方法中 实例化一个文本,坐标是 (20,100)
, 并且将当前关卡名称保存在当前类中,方便在当前类中获取关卡名称。
接下来就是监听英雄获得食物的逻辑
private initListeners(): void {
this.game.events.on(EVENTS_NAME.chestLoot, this.chestLootHandler, this);
this.game.events.once(EVENTS_NAME.gameEnd, this.gameEndHandler, this);
}
下面代码是监听英雄获得食物后要处理的事情,获得一个食物加 10 分。
this.chestLootHandler = () => {
this.score.changeValue(ScoreOperations.INCREASE, 10);
const currentIndex = LEVELS.findIndex(
(item) => item.name === this.levelName
);
if (LEVELS[currentIndex].score === this.score.getValue()) {
const nextLevel = LEVELS[currentIndex + 1];
if (nextLevel) {
this.game.events.off(EVENTS_NAME.chestLoot, this.chestLootHandler);
this.game.events.off(EVENTS_NAME.gameEnd, this.gameEndHandler);
this.scene.get("game-scene").scene.restart({ name: nextLevel.name });
this.scene.restart({ name: nextLevel.name });
} else {
if (this.score.getValue() === gameConfig.winScore) {
this.game.events.emit(EVENTS_NAME.gameEnd, "win");
}
}
}
};
先找到当前关卡的数据,然后判断当前的得分是否跟关卡的预设得分是否相同,如果相同,说明关卡要进入下一关,如果没有下一关,当前游戏就结束了,如果有下一关,我们就重新加载 game 场景和 UI 场景。 有一点需要注意的是,我们重新加载当前场景,需要将绑定的全局监听事件取消绑定,如果不取消绑定就会触发 2 次。 以上就是关卡的主要内容。
小结
当然我们可以加入更复杂的逻辑,由于时间关系,就先开发到这里了,以后有时间再继续开发吧,如果有小伙伴有好的想法,也可以加入进来一起开发。接下来来总结下开发小游戏的主要点吧
- 一:JavaScript 基础还是要巩固下,扎实的基础才能更快地融入开发
- 二: 地图设计第一次尝试可能会比较慢,熟练之后就很快了,只有有好的想法,就可以设计出更复杂的关卡
- 三:对应 phaser3 的框架的熟悉程度可以一步一步来,边开发边学习,并不是要 api 都熟悉了才可以进入开发。
最后
我在小游戏项目开发中获得了很多宝贵的知识,如精灵图,精灵表,地图,动画、碰撞检查、事件通知等。这些相加就可以创造出一个小的游戏,也懂的了靠几段代码就可以创造出一个小游戏。这也是我第一次开发项目。
最后祝大家早日抗疫成功!!!
感谢小马在这个小游戏里面投入很多精力,也为我打开了一扇大门。
感谢@大帅老猿帮忙设计的口罩精灵图, 大帅还创建了“猿创营”,群里有很多开发大佬可以互相帮忙答疑和交流技术,同时大帅还会分享做外包,搞副业等,感兴趣的小伙伴可以留言“入群”。