首页 > 其他分享 >几十行JS代码简单编写一个小游戏

几十行JS代码简单编写一个小游戏

时间:2022-12-12 11:34:24浏览次数:37  
标签:me 几十 游戏 鼠标 JS game 小游戏 new sprite


前言

如你所见,这是一个萌系休闲类小游戏,应该非常适合在深夜里一个人打发寂寞时光!(查询作者精神状态

游戏是这样的,通过控制鼠标可以在这个被黑夜笼罩的都市中打开一束光,照亮某片区域,玩家要尽可能快地寻找到 的身影,鼠标只要命中即为游戏结束,此时如果继续滑动鼠标则会看到 向你鬼畜而来.....(期初可能只是一个BUG,但我觉得挺有趣的就保留了下来,我们通常应该可以将此类事件称之为——"创意")

本游戏采用 melonJS 2 进行开发,melonJS 2melonJS 游戏引擎的现代版本。它几乎完全使用 ES6 的类、继承和语义等进行了重建,并使用 Rollup 打包以提供现代功能。了解更多可以查看我的这篇文章: ​​全新轻量级 2D 开源游戏引擎,采用现代化构建​​,只需要会使用 JS(ES6语法) 即可开始编写游戏,接下来进入正题。

创建场景

import * as me from "https://esm.run/melonjs";

me.device.onReady(function () {
// 初始化
if (!me.video.init(728, 360, { parent: "screen", scaleMethod: "flex-width", renderer: me.video.WEBGL })) {
return;
}
// 注册事件
me.state.set(me.state.PLAY, new PlayScreen());
me.state.set(me.state.GAME_END, new EndingScreen());
// 加载资源
me.loader.crossOrigin = "anonymous" // 这里因为我加载的是网络资源
me.loader.preload(resource, () => {
me.state.change(me.state.PLAY);
startTime = new Date().getTime()
});
});

var resource = [{ name: "background", type: "image", src: "https://p1-jue.byteimg.com/tos-cn-i-k3u1fbpfcp/33127b0ebc424d188c048574fa8f4dc0~tplv-k3u1fbpfcp-watermark.image?" }, { name: "jjj", type: "image", src: "https://p3-jue.byteimg.com/tos-cn-i-k3u1fbpfcp/cf2e426ed75a4df099433c8a169cf029~tplv-k3u1fbpfcp-watermark.image?" }]
var isEnd = false // 结束标识
var startTime = 0 // 开始时间戳
var endTime = 0 // 结束时间戳

在设备与引擎准备完毕时,会触发 ​​onReady​​​ 回调,这里我们先初始化一个画布,​​renderer​​​ 可以改变渲染器的方式,默认是 ​​Canvas​​​,因为我使用到了​​2D点光源​​的效果,所以改成在 ​​WebGL​​ 渲染更好。

​me.state​​ 命名空间是重要的一个概念,它用来设置和改变游戏中的生命周期状态,比如 暂停游戏开始/结束游戏进入菜单等等,这里通过 ​​set​​ 方法分别设置了游戏启动时的场景实例和游戏结束时的场景实例。

​loader.preload​​​ 是用于预加载资源的方法,资源通过对象数组注入,其中​​name​​参数标识了对应资源的名称,后续引用资源不需要变量,可以直接使用名称就能找到对应资源。当资源加载完毕后,触发回调函数,回调中修改状态来开始游戏,并记录下一个时间戳,用于过程中统计游戏进行的时间。

下面我们开始为游戏编写第一个场景。

游戏场景

class PlayScreen extends me.Stage {
onResetEvent() {
// 背景元素
var bg_sprite = new me.Sprite( me.game.viewport.width / 2, me.game.viewport.height / 2, { image: "background", anchorPoint: { x: 0.5, y: 0.5 }} );
// 添加目标
var target_sprite = new me.Sprite(point.x, point.y, { image: "jjj" });
// 添加元素进画布
me.game.world.addChild(bg_sprite);
me.game.world.addChild(target_sprite);
}
};

通过 ​​Sprite​​ 对象创建精灵图,在2D游戏中,通常以一张顺序包含帧动画的图片来制作动态的图像,没错,就跟CSS精灵技术是同种原理,不过这里我们并不做到那么复杂,只是静态显示。

几十行JS代码简单编写一个小游戏_游戏开发

我们继续丰富场景,作为游戏中的上帝,怎么能没有光呢?场景继承的基类 ​​Stage​​ 中有一个 ​​lights​​ 属性用于设置光源列表,我们找到一个 ​​Light2d​​ 聚光灯的类,实例化一个灯光系统设置进光源列表中,这样我们的场景中就有了一束光:

// 灯光系统
var whiteLight = new me.Light2d(0, 0, 100, 70, "#fff", 0.7);
// 设置灯光
this.lights.set("whiteLight", whiteLight);

现在该让光束随着鼠标移动起来了,你完全可以使用 DOM 的监听事件来做,当然melonJS下同样内置了许多输入监听事件,这里的 ​​pointermove​​​ 事件是不是跟 ​​document​​​ 中的 ​​mousemove​​ 事件很类似?只不过它以传入第二个参数的方式来设置监听范围:

// 光随着鼠标事件移动
me.input.registerPointerEvent("pointermove", me.game.viewport, (event) => {
whiteLight.centerOn(event.gameX, event.gameY);
});

动起来了,是不是很简单?

几十行JS代码简单编写一个小游戏_游戏引擎_02

最后为场景添加一个纯黑遮罩,营造出一点氛围感~就是开头看到的效果

this.ambientLight.parseCSS("#000");

创建角色

上面我们往游戏中添加了静态的精灵图,但是游戏需要交互动作才能进行下去,这时我们就需要创建一个新的类继承精灵图,就叫它 ​​Actor​​ 好了,接着扩展一下这个类,这里我们使用游戏引擎提供的物理模型 ​​Ellipse​​ 对象,只是单纯为了添加一个椭圆作为物理身体,参数比较随意,然后设置了这个类的碰撞事件,在触发碰撞检测时执行游戏结束的相关动作。

class Actor extends me.Sprite {
constructor() {
super(me.Math.random(-15, me.game.viewport.width), me.Math.random(-15, me.game.viewport.height), { image: "jjj" });
// 为角色设置身体
this.body = new me.Body(this, new me.Ellipse(6, 6, this.width - 6, this.height - 6));
this.body.gravityScale = 0; // 消除掉重力
}
onCollision() {
// 标记游戏结束,在鼠标移动事件中会读取该全局变量进行判断
isEnd = true
// 记录下游戏结束时间,计算游戏时长
endTime = new Date().getTime()
// 改变游戏场景,进入 GAME END 游戏结束场景
me.state.change(me.state.GAME_END)
return false;
}
};

对于游戏引擎中的物理模型来说,通常都会有一个重力属性,我们的游戏本质还是静态的角色,所以这里需要把重力 ​​gravityScale​​ 设置为 0 ,否则我们的 会像这样掉下去(原谅我不厚道地笑了):

几十行JS代码简单编写一个小游戏_游戏引擎_03

由于我们的光源并没有物理模型,那要怎么让鼠标和酱之间产生碰撞呢?这里我取巧了一下,利用 ​​Actor​​ 类,创建了一个"小酱",让它跟随鼠标移动,然后隐藏它,这样就能触发物理碰撞的判定了(画外音:这个类取名 Actor 原来是这个意思吗!):

const point_sprite = me.game.world.addChild(new Actor());
point_sprite.scale(0.5) // 缩小一点
point_sprite.setOpacity(0) // 变成透明
// 鼠标移动事件:
me.input.registerPointerEvent("pointermove", me.game.viewport, (event) => {
if (!isEnd) {
// 移动光源
whiteLight.centerOn(event.gameX, event.gameY);
// 移动透明的物理模型,把它当成鼠标指针
point_sprite.centerOn(event.gameX + 22, event.gameY + 22);
} else {
target_sprite.setOpacity(0.7)
target_sprite.scale(1.02)
}
});

几十行JS代码简单编写一个小游戏_JavaScript_04

结束场景

这个场景就蛮简单的了,就是输出文字内容,代码很好理解:

class EndingScreen extends me.Stage {
onResetEvent() {
me.game.world.addChild(new me.Text(me.game.viewport.width / 2, me.game.viewport.height / 2 - 20, {
font: "Arial",
size: 50,
fillStyle: "#FFFFFF",
textAlign: "center",
text: "恭喜你找到了酱!\n通关时间:" + ((endTime - startTime) / 1000).toFixed(2) + '秒'
}));
}
}

完整的代码和游戏演示

完整的代码和游戏演示(由于引用资源第一次加载可能需要等待时间),因为懒没有做游戏界面,所以猛戳上面的 ○ 运行 按钮来重复开始游戏:

几十行JS代码简单编写一个小游戏_游戏开发_05

试玩一下吧!看看你最快多少秒可以抓住酱?

结束

总结一下,利用 melonJS 我们仅用了几十行代码就完成了一个小游戏,虽然这个游戏并不复杂,即使用原生 JS 可能也不难实现,但你却很难自己轻易实现一个 WebGL / Canvas 级别的渲染器,使用游戏引擎可以做到更多,这里只是现学现卖小试了一下牛刀,顺便也可以练习 ES6 语法,如果你感兴趣,也可以仔细参阅官方的API文档和Demo,做出更好玩的东西~

标签:me,几十,游戏,鼠标,JS,game,小游戏,new,sprite
From: https://blog.51cto.com/palxp/5929293

相关文章