使用 p5.js 和 Matter.js 创建 Flappy Bird 克隆版
💪 强强联手
p5.js 和 Matter.js 是一对强大的组合。它们能让你以最小的投入创建出令人惊叹的基于物理的游戏。在阅读这篇博文之前,我建议你先访问https://p5js.org/和https://brm.io/matter-js/,了解一下这两个库的功能。
使用 p5.js,创建游戏变得更加轻松,无需费力处理 HTML5 画布及其工作方式。该库让您可以专注于编写您所需的特定功能,而无需浪费时间去弄清楚如何编写特定功能的代码。
在这个项目中,Matter.js 的任务很简单,但至关重要。Matter.js 允许我们将物理引擎集成到游戏中,以检测碰撞并对小鸟施加力,使其保持漂浮在空中。
👨💻👩💻 让我们开始吧
在这个项目中,我决定采用面向对象编程 (OOP) 方法,场景中的每个对象都对应一个拥有独立文件的类。总共有 4 个类(鸟、盒子、柱子、地面)。鸟代表试图躲避所有障碍物的玩家。盒子是一个通用类,表示一个可以用作地面或障碍物的物理盒子。柱子代表一根由两个中间有空隙的盒子组成的柱子。地面扩展了盒子类,它代表地面,充当判断玩家是否失败的触发器。
鸟类类非常简单,它本质上是一个使用 Matter.js 创建的圆圈的图像,以确定其边界。
constructor(x, y, r) {
const options = {
restitution: 0.5,
}
this.body = Matter.Bodies.circle(x, y, r, options);
Matter.Body.setMass(this.body, this.body.mass * 2);
Matter.World.add(world, this.body);
this.r = r;
}
在鸟类类的构造函数中,我们实例化了鸟体及其质量,并将其添加到世界(即场景)中。然后,我们用 p5.js 编写了一个 show 函数,将鸟儿显示在场景中(完整代码请见)。
初始化盒子类与鸟类类似,我们使用矩形作为碰撞器并确保它是静态的,这样它就不会受到重力的影响。
constructor(x, y, w, h, gap=false) {
var options = {
restitution: 0.5,
}
this.body = Matter.Bodies.rectangle(x, y, w, h, options);
this.body.inertia = Infinity
this.body.isStatic = true
Matter.World.add(world, this.body);
this.w = w;
this.h = h;
this.gap = gap
if (this.gap)
this.body.isSensor = true
}
两个盒子之间的空隙也是一个盒子,用于追踪用户成功通过的列数(也可以通过许多其他方式实现)。然而,为了避免任何物理碰撞,该空隙的 isSensor 属性设置为 true(这类似于 Unity 的 isTrigger)。该类还包含一个类似于 bird 类的 show 函数和一个 move 函数,该函数会以一定的力度移动盒子:
move() {
let pushVec = Matter.Vector.create(-2, 0)
Matter.Body.translate(this.body, pushVec)
}
在列类中,我们基本上创建了 3 个框对象,一个用于顶部,一个用于间隙,一个用于底部,如下所示:
constructor(box1Height, gapHeight, box2Height) {
this.box1 = new Box(width + 100, box1Height / 2, 100, box1Height)
this.box2 = new Box(width + 100, height - (box2Height / 2), 100, box2Height)
this.gap = new Box(width + 100, box1Height + (gapHeight / 2), 100, gapHeight, true)
}
列类还具有显示和移动功能,基本上调用所有 3 个框上的显示和移动功能。
Ground 类非常简单,只是扩展了 Box 类。其实不用创建它自己的类也可以,我这么做只是为了保持条理:
constructor(x, y, w, h) {
super(x, y, w, h);
this.body.isStatic = true;
}
如上所述,它还使用了 isStatic 属性来确保该实体不受重力影响。地面类也像其他类一样具有 show 函数,利用 p5.js 的功能将对象显示到屏幕上。
这些类就完成了。所有这些类随后被组合到sketch.js
文件中,以便使用 p5.js 完成游戏。
在每个基于 p5.js 的游戏/应用中,都有两个主要函数:setup
和draw
。setup
这两个函数在游戏加载/启动时调用一次,并draw
根据帧速率在一秒钟内调用多次。在设置中,我们调用createCanvas
它并赋予它画布的大小,然后创建 Matter.js 物理引擎。我们还创建了地面和小鸟。最后,我们调用generateAllColumns
每 3 秒生成一列的函数:
function setup() {
const canvas = createCanvas(displayWidth, displayHeight - 110)
engine = Engine.create()
world = engine.world
ground = new Ground(width / 2, height - 10, width, 20)
bird = new Bird(150, 300, 20)
generateAllColumns()
}
p5.js 可以非常简单地检测用户的输入,因此我们可以使用内置mousePressed
函数来检测用户是否点击了鼠标并对鸟施加一个力使其向上飞:
function mousePressed() {
if (canFly) {
let pushVec = Matter.Vector.create(0, -0.1)
let posVec = Matter.Vector.create(bird.body.position.x, bird.body.position.y)
Body.applyForce(bird.body, posVec, pushVec)
}
}
游戏的最后一个函数draw
包含所有逻辑。在这里,我们更新了 Matter.js 物理引擎,显示小鸟和地面,并检查碰撞。Matter.js 使碰撞检测比从头开始更容易。基本上,我们检查小鸟是否与顶部或底部发生碰撞,然后通过禁用用户点击飞行的功能来结束游戏。如果小鸟没有与任何东西发生碰撞,那么它们就通过了间隙,我们可以在它们的点数上加一(另一种方法是检查小鸟是否与游戏发生碰撞,而没有与其他部分发生碰撞,然后为它们的点数加一)。
columns.forEach(function (column, i) {
if (column !== undefined) {
let box1Collide = Matter.SAT.collides(bird.body, column.box1.body)
let box2Collide = Matter.SAT.collides(bird.body, column.box2.body)
let gapCollide = Matter.SAT.collides(bird.body, column.gap.body)
if (box1Collide.collided || box2Collide.collided)
canFly = false
if ((column.box1.body.position.x + column.box1.w / 2) < 0 &&
(column.box2.body.position.x + column.box2.w / 2) < 0 &&
(column.gap.body.position.x + column.gap.w / 2) < 0) {
console.log('removed column ' + i)
Matter.World.remove(world, column.box1)
Matter.World.remove(world, column.gap)
Matter.World.remove(world, column.box2)
columns[i] = undefined
points++;
console.log(columns)
} else {
if (canFly) {
column.move()
}
column.show()
}
}
})
我们可以看到,Matter.js 处理了碰撞,如果box1Collide.collided
或box2Collide.collided
为真,则设置canFly
为 false。其余代码只是检查该列是否已移出屏幕并将其移除。如果该列仍在屏幕上,则调用 move 函数并将其显示给用户。
✨ 尝试一下!
您可以在以下网址试玩该游戏:
https://gifted-babbage-7b9dab.netlify.com/
💭 最后的想法
完整代码可在此 GitHub 仓库中找到:
https://github.com/omarsinan/FlappyBirdClone
如果您想添加一些附加功能并改进它,请这样做并与我分享:)我建议您提高速度,尝试不同的值并使列显示得更快,而不是让用户在开始时等待很长时间。
最后一件事。如果你喜欢这篇文章,并且对类似的内容感兴趣,我建议你关注我的开发者推特账号@oohsinan 😁
鏂囩珷鏉ユ簮锛�https://dev.to/oohsinan/creating-a-flappy-bird-clone-with-p5-js-and-matter-js-22de