资讯专栏INFORMATION COLUMN

从零开始开发一款H5小游戏(二) 创造游戏世界,启动发条

shaonbean / 579人阅读

摘要:图像的逐帧播放可以类比为放映电影,通过在荧幕上连续投放图像来产生动作的效果。敬请期待从零开始开发一款小游戏三攻守阵营,赋予粒子新的生命

本系列文章对应游戏代码已开源 Sinuous game

上一节介绍了canvas的基础用法,了解了游戏开发所要用到的API。这篇文章开始,我将介绍怎么运用这些API来完成各种各样的游戏效果。这个过程更重要的是参透一些游戏开发的思路和想法,而不是仅仅知道怎么写代码来完成这个游戏。

先用一张图来了解一下整个游戏的构成。

Map表示整个背景地图,作用很简单,就是渲染黑色背景。
Player 表示玩家粒子,它尾巴中带有生命点,我们用Life类来表示。
Enemy为红色的敌人粒子,因为技能粒子和Enemy粒子具有很多共性,所以Skill粒子继承自Enemy粒子。
粒子之间撞击后有爆炸效果,用Paticle来表示爆炸粒子。

简单来说,游戏就是一帧一帧图像的叠加播放,并通过捕获用户反馈来实现游戏中的人机交互。

图像的逐帧播放可以类比为放映电影,通过在荧幕上连续投放图像来产生动作的效果。

首先要创建这样一个荧幕, 并设置银幕的大小。

//index.js
const canvas = document.getElementById("world");
canvas.width = window.innerWidth > 1000 ? 1000 : window.innerWidth;
canvas.height = window.innerHeight;

在游戏中,荧幕对应一个地图,我们将这个地图抽象为一个类,并提供基本的渲染方法。

//Map.js
/**
 * 地图类
 */
class Map {
    init(options) {
        this.canvas = options.canvas;
        this.ctx = this.canvas.getContext("2d");
        this.width = options.width;
        this.height = options.height;
    }
    clear() {
        this.ctx.clearRect(0, 0, this.width, this.height);
    }
    render() {
        this.clear();
        this.ctx.fillStyle = "black";
        this.ctx.fillRect(0, 0, this.width, this.height);
    }
}
export default new Map();

在入口处初始化地图

map.init({
    canvas,
    width: window.innerWidth > 1000 ? 1000 : window.innerWidth,
    height: window.innerHeight
});

荧幕准备好后,怎么放映图像,对应于游戏中的放映机是什么呢?

想想在js中用于定时执行的方法有哪些,setInterval, setTimeout, requestAnimationFrame?

setInterval这个方法在游戏中是不能用的。由于js是单线程,setInterval开启的定时循环间隔会受到CPU使用情况的影响,同时电脑对setInterval的最短间隔也有不同的要求。由于游戏对帧率的要求比较高,所以在游戏中应该避免使用setInterval来执行定时任务。由于无法把握每帧执行的具体时间,setTimeout也有会遇到类似的问题。

懂的人已经懂了,现代的H5游戏开发都是通过requestAnimationFrame来执行循环播放的。它的优势就是能根据浏览器的实时渲染帧率来执行函数,使的动画播放比较流畅。而不会因为函数的执行时间跟定时器时间不同导致的播放卡顿现象。

一般requestAnimationFrame每帧的绘制时间是1000/60 ms。也就是每秒能绘制60帧。好就好在时间不需要我们自己设置,而是浏览器的内在机制。在不同的浏览器中方法名会有所不同,我们通过下面的方法来定义一个requestAnimationFrame函数

const raf = window.requestAnimationFrame
  || window.webkitRequestAnimationFrame
  || window.mozRequestAnimationFrame
  || window.oRequestAnimationFrame
  || window.msRequestAnimationFrame
  || function(callback) {
    window.setTimeout(callback, 1000 / 60); //每帧1000/60ms
  };

有个这个方法,我们如有神助。只需要在一个动画方法中使用raf调用自身方法。就能实现循环调用的功能,并且如丝般顺滑。使用如下:

(function animate() {
    map.render();
    raf(animate);
})();

这样就会不断调用map的render方法,实现逐帧播放。只不过map的render方法只是把画布涂黑,所以看起来并没有什么变化。

我们的游戏中有玩家粒子,敌人粒子,还有技能粒子,撞击爆破等效果。我们的游戏就是不断地往animate这个方法中添加内容,在每一帧中渲染多个不同东西,看起来就是整个游戏画面了。我们可以想象一下未来啊animate方法是这样的。

(function animate() {
    map.render();
    player.render();
    enemy.render();
    skill.render();
    effect.render();
    raf(animate);
})();

我们需要扩展player, enemy...等等的render方法。让它们表现出不同的效果。

这样渲染出来的画面还是死的,怎样让每一帧渲染出来的图像有所不同,实现动画的效果呢?

在每个物体类中,都有一个update方法,该方法用于改变物体的位移形状等,所以每一帧渲染出来的画面都会不一样。

//通过update方法来控制物体位移或形态变化
update() {
    this.x += 1;
    this.y += 1;
}
render() {
    cxt.fillRect(this.x, this.y, 10, 10);
}

在animate中,我们需要在每次render后调用update方法

(function animate() {
    map.render();
    player.render();
    player.update();
    raf(animate);
})();

这样,借助于游戏的发条,player就动起来了!我们前面所过,游戏就是逐帧播放和人机交互。那怎样来处理玩家反馈呢?

在PC和手机中的所谓玩家反馈通常是鼠标的点击滑动以及手势等动作。通过监听鼠标或手势事件来改变物体的属性,达到控制物体变化的目的。例如让player跟随鼠标移动。

window.addEventListener("mousemove", (e) => {
    self.x = e.clientX;
    self.y = e.clientY;
});

达到的效果跟update方法本质上是一致的。

至此整个游戏基本原理已经讲得差不多了,下一节要讲的是如何创建各种粒子,还有player那条会动的尾巴。敬请期待《从零开始开发一款H5小游戏(三) 攻守阵营,赋予粒子新的生命》

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/60032.html

相关文章

  • SegmentFault 技术周刊 Vol.20 - 用 Canvas 画个星空

    摘要:在最后,推荐给大家几个相关的库,增加使用时的便捷。周刊筛选的每篇内容,是作者的独到见解,踩坑总结和经验分享。每周二更新,欢迎关注或者订阅。 showImg(https://sfault-image.b0.upaiyun.com/382/562/382562537-5874b30ad612b); SegmentFault 曾举办过一个社区官方的比赛「30 行 js 你能做出什么?」,产生...

    peixn 评论0 收藏0
  • 从零开始开发一款H5游戏(一) 重温canvas的基础用法

    摘要:初衷从萌发写一个小游戏的想法到完成游戏开发用了大概一周的业余时间。在这里打算写一个系列教程,讲述怎样从零开始开发一款小游戏。在开始介绍如何写游戏前有必要重温一下。敬请期待从零开始开发一款小游戏二创造游戏的世界,启动发动机。 本系列文章对应游戏代码已开源 Sinuous game。 初衷 从萌发写一个小游戏的想法到完成游戏开发用了大概一周的业余时间。这个过程积累了一些经验,也算是参透了一...

    Betta 评论0 收藏0
  • 从零开始开发一款H5游戏(五) 必要的包装,游戏规则和场景设计

    摘要:一个游戏要完整,还需要给它制定一个评分机制,它是整个游戏的关键所在。比如很久以前微信上的打飞机,围住神经猫,还有前段时间大火的。这部分可以极大增加游戏的热度。预加载当我在微信打开游戏的时候,发现开始画面和结束画面的图片加载很慢。 本系列文章对应游戏代码已开源 Sinuous game 到这里我们已经讲了游戏的整体设计和实现。一个游戏要完整,还需要给它制定一个评分机制,它是整个游戏的关键...

    caspar 评论0 收藏0
  • 从零开始开发一款H5游戏(三) 攻守阵营,赋予粒子新的生命

    摘要:入口处通过一个循环来创建粒子,随机生成粒子的位置。由于,所以粒子最开始是看不到的。视界之外的位置开始运动,并保证该位置的随机性。盾力慢小命到此游戏中的角色都介绍完了,下一节要讲的是从零开始开发一款小游戏四撞击吧粒子炫酷技能的实现。 本系列文章对应游戏代码已开源 Sinuous game。 每个游戏都会包含场景和角色。要实现一个游戏角色,就要清楚角色在场景中的位置,以及它的运动规律,并能...

    Kylin_Mountain 评论0 收藏0
  • 从零开始开发一款H5游戏(四) 撞击吧粒子,炫酷技能的实现

    摘要:粒子吃了技能粒子后就能表现各种特殊效果。碰撞检测游戏中粒子可能会撞击到粒子,也可能吃到粒子。然而一个游戏要完整,肯定少不了一些游戏的策略还有一些附属场景,下一节要讲的是从零开始开发一款小游戏五必要的包装,游戏规则和场景设计 本系列文章对应游戏代码已开源 Sinuous game。 本游戏有五种技能粒子,分别是 护盾,重力场,时间变慢,使敌人变小,增加生命。Player粒子吃了技能粒子后...

    hqman 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<