Java编程网

分享 Java Web 开发相关知识

使用p5.js和Matter.js创建Flappy Bird Clone

Du强大的二重奏

p5.j​​s和Matter.js是强大的二重奏。它们一起使您能够以最小的努力创建出色的基于物理的游戏。在阅读此博客文章之前,建议您同时查看https://p5js.org/https://brm.io/matter-js/,以了解这两个库的功能。

使用p5.js,无需麻烦处理HTML5画布及其工作方式即可轻松创建游戏。该库使您可以将主要精力放在专门编写所需的代码上,而不用浪费时间试图弄清楚如何编写特定功能。

这个项目中Matter.js的任务很简单但很关键。Matter.js将使我们能够将物理引擎集成到我们的游戏中,以检测碰撞并向鸟类施加力以使其保持漂浮在空中。

💻‍💻👩‍💻让我们开始吧

在这个项目中,我决定采用一种OOP方法,其中场景中的每个对象都对应一个具有自己文件的类。总共我们有4个类别(鸟,盒子,圆柱,地面)。鸟是试图躲避所有障碍的球员。盒子是一个通用类,代表可以用作地面或障碍物的物理盒子。该列表示一个单列,中间有2个带间隙的框。地面延伸了盒类,并仅代表地面,它可以触发以确定玩家是否输了。

bird类非常简单,它本质上是带有使用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;
  }

在bird类的构造函数中,我们可以看到我们实例化了身体,其质量并将其添加到世界(即场景)中。然后,我们有了一个show函数,该函数使用p5.js将鸟显示在场景上(您可以在完整的代码中看到它)。

初始化box类类似于bird类,我们改用矩形作为对撞机,并确保它是静态的,以便不受重力影响。

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)
}

在column类中,我们基本上创建了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)
  }

column类还具有show and move函数,该函数基本上在所有3个框上调用show and move函数。

地面类非常简单,只是扩展了盒类。可以在不创建自己的类的情况下完成它,我只是为了使所有事情井井有条而这样做:

constructor(x, y, w, h) {
    super(x, y, w, h);
    this.body.isStatic = true;
  }

如上所述,它还使用isStatic属性来确保该实体不受重力影响。通过使用p5.js的功能将对象显示在屏幕上,地面类也具有与其他类一样的显示功能。

上课就是这样。然后将所有这些类合并到sketch.js文件中,以便使用p5.js完成游戏。

在每个由p5.js驱动的游戏/应用中,都有2个主要功能:setupdrawsetup在游戏加载/启动时调用一次,并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.j​​s使得检测用户输入变得非常简单,因此我们可以使用内置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.collidedbox2Collide.collided为true,则将其设置canFly为false。其余代码仅检查该列是否已移出屏幕并删除。或者,如果该列仍在屏幕上,则我们调用move函数并将其显示给用户。

✨试试吧!

您可以在以下网址尝试游戏:https :
//gifted-babbage-7b9dab.netlify.com/

💭最后的想法

完整的代码可以在这个GitHub仓库中找到:https :
//github.com/omarsinan/FlappyBirdClone

如果您想添加一些其他功能并加以改进,请与我分享:)我建议您提高速度,调整数值,使列显示更快,而不是让用户等待开始很长一段时间。

点赞

发表评论

电子邮件地址不会被公开。 必填项已用*标注