HTML 5游戏开发第1部分

关于本文

我认为每个游戏玩家一生中至少曾想过“我想创造自己的游戏!”,而我也一样。 实际上,我在初中时会花费无数的时间在纸上制作冒险游戏,以便在学校里和我最好的朋友一起玩,这很有趣。 带着可笑的角色和荒谬的武器感到很有趣,让我的朋友掉入我的陷阱并努力解决我的难题也很有趣(不要为他感到难过,第二天他会做同样的事情)。 这就是我决定在高中学习编程的原因之一。 但是,在2000年代初期,互联网是一个与今天不同的地方,我既没有方法也没有主动性来自行启动和学习一些游戏编程。

几个月前,我最终(合法地)收到了一本书的pdf副本,名为HTML5 Games:Ninja的新手,将其放在Kindle Fire中,然后有点忘了,直到被要求为我们的每月技术讲座广告做演示HDE。 作为该公司为数不多的前端开发人员之一,我正在考虑谈论一种将使所有人,不仅对具有JavaScript知识的人都具有娱乐性的事物。 考虑了所有选项后,我决定以HTML5形式进行游戏开发的介绍,并认为一般而言,我对JavaScript和前端的了解将使我能够在短短的几个小时内创建一个有效的演示。

我错了。 当然,我错了。 游戏开发很难。
我认为我需要的几个小时变成了一个充满阅读,学习和想敲墙的几周时间,尽管我对演示文稿有很好的想法,但最后,我只能展示从书。 是的,这有点令人失望,但这只是因为我低估了掌握基础知识所需的时间。 最重要的是,我是那种不喜欢学习新知识的开发人员,只专注于完成任务所需的部分。 我真的很想尽可能深入地了解我所使用的工具及其周围的所有内容。 对于许多人来说,这似乎是浪费时间,但是我宁愿花更多的时间为旅行做准备,而不必停下来几次才能查看地图。

这是一段值得的旅程,尽管只是更大,更大的序幕,而且我有很多“ EUREKA”的时刻,我想提高自己的编码能力。


基本概念

游戏开发很难,但是所有游戏的共同点都不难理解。 创建视频游戏非常类似于在纸上创建动画。 一个接一个地绘制许多帧,人眼将产生魔力并给人以运动的印象。 就如此容易。 当然,在动画中,结局总是相同的;在游戏中,用户输入决定下一帧将是什​​么,但是概念是相同的,两者之间存在巨大的差异。

在游戏开发中,我们不会绘制每个单独的框架,而是告诉计算机要做什么,它会根据用户输入和碰撞/更改来为我们绘制图像。 而且这种情况不断发生,发生在获取用户输入,稍微移动所有内容,计算碰撞/变化并随后绘制场景的循环中,通常每秒60次。 这个概念对于老式的独立ASCII游戏来说都是正确的,对于现代平台上的AAA产品以及介于两者之间的所有产品而言,都是如此。

许多现代游戏开发工具(Unity可能是其中最受欢迎的工具)使用户可以专注于创建内容,从而将一些繁琐的任务卸载到引擎上,但是当您在引擎盖下浏览时会发生什么,这就是我之前所描述的。段。 这意味着掌握这些概念是能够更改产品的各个部分的唯一方法。

到目前为止,对于所有类型的游戏和平台而言,通用的说法是正确的,那么HTML 5 Game Development呢?

HTML 5游戏开发

简而言之,HTML 5游戏开发是我们在浏览器中运行的游戏开发,它使用与前端开发完全相同的语言和工具。 通过了解HTML,CSS和JavaScript,已经可以创建能够在装有浏览器的每个平台上运行的简单游戏。 但这已经有很长时间了,尽管可以使用该技术创建一些非常令人上瘾的游戏,但是谈论HTML 5游戏开发就是谈论canvas API。

由Apple创建并替代Flash的canvas是一种简单但功能强大的api,它允许通过脚本绘制图形,并对每个单个像素进行控制。 它可以用于2D图形和3D图形(通过webgl),但是在本系列文章中,我将重点介绍2D,因为它是我有经验的唯一上下文,并且不需要学习使用完全不同的上下文语言。

好的,很好,但是……为什么选择HTML 5? 有什么优势?

JavaScript是世界上最受欢迎的编程语言之一(最早在GitHub上),这意味着您可以得到的社区和支持无与伦比。
制作在浏览器中运行的游戏意味着用户无需更新它,因为每次运行该游戏时,他们都会自动使用最新版本。
而且,由于当今的浏览器会自动更新,这意味着您可以使用目标浏览器支持的所有功能,而不必担心会导致某些用户落后,因为这只会发生。
另外,由于它运行在浏览器中,因此用户无需安装任何其他库或工具。 很好吗?

让我们开始吧!

让我们看看Canvas是如何通过几个简单的示例工作的,这是我们进行游戏开发的第一步。
画布不过是绘制事物的一种简单方法,但是正如我之前说的,动画是指一帧接一帧地绘制,以给人一种运动的印象。

让我们创建一个简单的正方形。 我们将从添加一个html文件开始。 如您所见,它只包含嵌套在div中的画布。

  ---------------------------- index.html ------------------- --------- <!DOCTYPE html > 
< html lang =“ zh-CN” >
< >
< meta charset =“ UTF-8” >
< title >游戏</ title >
< 样式 >
身体 {
边距 :30 像素自动 ;
text-aligncenter ;
颜色#999 ;
}

#board画布 {
边框 :1 px实线#333
背景色#000 ;
-webkit-box-shadow :0 px 0 px 24 px 0 px rgba (0,0,0,1);
-moz-box-shadow :0 px 0 px 24 px 0 px rgba (0,0,0,1);
box-shadow :0 px 0 px 24 px 0 px rgba (0,0,0,1);
边框半径 :10 像素
}
</ style >
</ head >
< 身体 >
< div id =“ board” >
< canvas width =“ 640” height =“ 480” > </ canvas >
</ div >
< 脚本src =“ script.js” > </ 脚本 >
</ body >
</ html >

接下来,我们将创建脚本文件。 下面是我们script.js的第一行。

  ----------------------------- script.js ------------------ ---------- const canvas = document .querySelector( '#board canvas' ); 
const ctx = canvas.getContext( '2d' );
console.log(ctx)

让我们在浏览器中打开html文件,您可以欣赏柔和的画布。 好的,到目前为止没有什么特别的,有趣的部分现在开始。 让我们画一个正方形!

  ----------------------------- script.js ------------------ ---------- [...] const {宽度:w,高度:h} =画布;   x = w / 2; 
y = h / 2; //设置颜色
ctx.fillStyle ='黄色'//创建正方形
ctx.fillRect(x,y,50,50)

和魔术! 出现一个黄色正方形。 但是如何?
好吧,我们只是简单地告诉画布设置颜色(我们可以在其中使用rgb和hsl之类的CSS属性,而不是简单的黄色),然后填充矩形。
我们作为参数传递的数字是x和y坐标(0,0是左上角),宽度和高度。
想四处走动吗? 尝试使用前两个数字。 想要使其变大还是使其成为矩形? 玩最后两个。

现在让我们居中。

  ----------------------------- script.js ------------------ ---------- [...] const {width: w ,height: h } = canvas ; 

rectW = 50;
rectH = 50;
x = w / 2- rectW / 2;
y = h / 2- rectH / 2;
//设置颜色
ctxfillStyle = '黄色'
//创建正方形
ctx .fillRect( xyrectWrectH

在第一行中(获取上下文后),我们将获取当前画布的宽度和高度。 然后,我们为矩形的宽度和高度声明两个变量,为坐标声明两个变量。 我们的黄色矩形现在居中。 做得好!

矩形不是我们可以使用画布创建的唯一形状,而是具有专用命令的唯一形状。 其他所有内容都是使用“路径”绘制的,但由于一些原因,我们在本文中将不予赘述。 首先,它比绘制矩形要复杂得多,因此不再需要本文。 其次,您可以导入使用不同工具制作的图像和SVG。 要了解更多信息,请查看MDN上的Canvas API页面(或成为本教程的专业人士)。

我循环,所以我是

如我之前所说,动画无非是一系列接连绘制的图像。 我们可以一次绘制一个单帧,这虽然可行,但由于我们试图在此处制作游戏,因此毫无意义。 相反,我们要做的是创建一个每帧运行一次(每秒60次)的函数,每次绘制相同的矩形,但位置略有不同。

但是,我们如何创建循环? 使用一段时间会立即锁定整个浏览器。 SetTimeout和SetInterval可以工作,但是有点不一致,无法保证每16.7秒(在此更多有关这些问题)的帧,并且一致性对于游戏至关重要。 幸运的是,JavaScript通过使用一个名为requestAnimationFrame的函数帮助我们实现了目标。 它接受一个函数作为回调,并在下一帧执行它。 为了使其循环工作,我们需要在主函数中调用它以确保它也可以在下一帧执行。

  ----------------------------- script.js ------------------ ---------- 函数 循环 (){ 
//我们需要再次调用requestAnimationFrame,以使其在下次刷新时运行
requestAnimationFrame循环
//通过简单的检查使方块再次出现在屏幕之外
如果x > = w + rectW ){
x = 0- 矩形
}
//每帧向x坐标加1,向右移动1个像素
其他 {
x + = 1
}
//设置颜色
ctx .fillStyle = '黄色'
//创建正方形
ctx .fillRect( xyrectWrectH
} //在下一帧上,运行我们的循环功能
requestAnimationFrame循环

广场在移动! 您刚刚创建了一个基本动画,不是很好吗?
但是,等等,它不仅在移动,而且似乎还在留下痕迹。 当然是的! 我们将在屏幕上的上一帧中保留绘制的内容。 让我们通过删除屏幕上的所有内容来摆脱它。

  ----------------------------- script.js ------------------ ---------- [...] //将颜色设置为黑色以“清洁”屏幕 
ctx .fillStyle = '黑色'
// 把它涂黑!
ctx .fillRect(0,0,w,h) //设置颜色
ctx .fillStyle = '黄色'

哦,现在我们在说话! 您可以通过增加每帧添加的像素数量来使其更快。

好吧,花了我们一段时间,但我们终于能够找到一些动静。 距离互动还很远。 让我们创建一些键盘控件来移动正方形。

由于我们只使用一个JS文件(为了使本帖子变得简单),因此我们将在之前编写的所有内容的基础上编写该文件。

  ----------------------------- script.js ------------------ ----------  KeyControls { 
constructor(){
//按键将存储我们当前按下的按键
这个 = {};
//绑定事件处理程序
文档 .addEventListener(
'keydown'
e => {
if ([37,38,39,40] .indexOf(e。which)> = 0){
//为了避免用箭头滚动页面
e.preventDefault();
}
//将按键设置为true
这个 [e。 其中 ] = true ;
},
错误的
);

文档 .addEventListener(
'keyup'
e => {
//将释放的键设置为false
这个 [e。 其中 ] = false ;
},
错误的
);
}

//如果按下操作按钮(空格),则返回true
得到 action(){
返回这个 [32];
}

得到 x(){
//如果按下向左箭头或A键,则返回-1
如果 [37] || [65]) 返回 -1;
//如果按下向右箭头或D键,则返回1
如果 [39] || [68]) 返回 1;
返回 0;
}

得到 y(){
//如果按下向上箭头或W键,则返回-1
如果 [38] || [87]) 返回 -1;
//如果按下向下箭头或S键,则返回1
如果 [40] || [83]) 返回 1;
返回 0;
}
}

乍一看,它看起来很复杂,但是通过检查代码,您看不到它什么都做,只是拿起我们按下的每个键并将其设置为key对象内的true,并在释放它时将其设置为false。

另外,根据所按下的按钮,它为x和y吸气剂返回+1或-1。

让我们来看看它的作用。

  ----------------------------- script.js ------------------ ----------  KeyControls { 
[...]
} const 控件 = 新的 KeyControls

const canvas = document .querySelector( '#board canvas' );
const ctx = canvas .getContext( '2d' );

const {width: w ,height: h } = canvas ;

rectW = 50;
rectH = 50;
x = w / 2- rectW / 2;
y = h / 2- rectH / 2;
颜色 = 0;

函数 循环 (){
//我们需要再次调用requestAnimationFrame,以使其在下次刷新时运行
requestAnimationFrame循环
x + = 控制 .x;
y + = 控制 .y;

//我们将能够通过操作按钮更改颜色
如果控制 .action){
颜色 + = 10;
如果颜色 > 360){
颜色 -= 360;
}
}

//将颜色设置为黑色以“清洁”屏幕
ctxfillStyle = '黑色'
// 把它涂黑!
ctx .fillRect(0,0, wh

//使用hsl设置颜色(色相,饱和度,亮度)
ctxfillStyle = `hsl( $ { color } ,50%,50%)` ;
ctx .fillRect( xy ,50,50);
}

requestAnimationFrame循环

在脚本文件的最新版本中,我们准备好了。 x和y值最初居中,但现在绑定到控件文件。 颜色设置为0,但可以通过按操作按钮进行更改(查看CSS属性hsl以了解更多信息)。

现在,您可以自由移动广场了。 恭喜,您已经创建了最基本的视频游戏形式。 它缺少您需要使它变得更好的一切,它不是很有趣,不是很漂亮,也没有目标,但这是一切开始的地方。 您只需编写几行代码就可以做到这一点。 恭喜你!

结论

到达这里花了一段时间,我们所拥有的并不是那么好,但是本文的目的并不是创造一个好的游戏。 由于这是一系列文章的第1部分,所以我只想让您了解基础知识,我想我们涵盖了所有内容。

现在,您应该熟悉循环的概念,绘制每个单独的帧以赋予动画效果并实现控件。 还有很多东西要学习(我们甚至没有碰到过碰撞),但是当我说这些是基本概念时,请相信我,您几乎可以在其中的每一个游戏中找到这些基本概念。

我认为这是个好点,因为之后发生的所有事情都非常复杂,以至于不使用任何模块捆绑程序就无法完成,并且涉及很多面向对象的编程。 下次,我将尽最大努力解释如何导入图像并为简单的射击者创建一个简单的引擎。

感谢您的阅读和关注!