xml地图|网站地图|网站标签 [设为首页] [加入收藏]
基本形状转换那些事,游戏开发基础的教程
分类:web前端

JavaScript 深入之类数组对象与 arguments

2017/05/27 · JavaScript · arguments

原文出处: 冴羽   

聊聊 SVG 基本形状转换那些事

2017/01/20 · HTML5 · SVG

原文出处: 凹凸实验室   

图片 1

HTML5 游戏开发基础的教程

2017/03/24 · HTML5 · 2 评论 · 游戏

本文由 伯乐在线 - 紫洋 翻译,艾凌风 校稿。未经许可,禁止转载!
英文出处:Mikołaj Stolarski & Tomasz Grajewski。欢迎加入翻译组。

在游戏的视觉效果定义其整体外观、感觉和游戏玩法本身。玩家被好的视觉体验所吸引,从而可达到产生更多的流量。这是创建成功的游戏和为玩家提供很多乐趣的关键。

在这篇文章中,我们基于 HTML5 游戏的不同视觉效果实现,提出几个构思方案。这些示例将依据我们自己的游戏《Skytte 》所实现的效果。我会解释支持他们的基本思想, ,并提供应用于我们项目中的效果。

类数组对象

所谓的类数组对象:

拥有一个 length 属性和若干索引属性的对象

举个例子:

var array = ['name', 'age', 'sex']; var arrayLike = { 0: 'name', 1: 'age', 2: 'sex', length: 3 }

1
2
3
4
5
6
7
8
var array = ['name', 'age', 'sex'];
 
var arrayLike = {
    0: 'name',
    1: 'age',
    2: 'sex',
    length: 3
}

即便如此,为什么叫做类数组对象呢?

那让我们从读写、获取长度、遍历三个方面看看这两个对象。

一、前言

前段时间研究 SVG 压缩优化,发现SVG预定义的 rectcircleellipselinepolylinepolygon 六种基本形状可通过path路径转换实现,这样可以在一定程度上减少代码量。不仅如此,我们常用的 SVG Path 动画(路径动画),是以操作path中两个属性值stroke-dasharraystroke-dashoffset来实现,基本形状转换为path路径,有利于实现路径动画。

你会学到什么

在我们开始之前, 我想列出一些我希望你能从本文中学习的知识:

  • 基本的游戏设计
    我们来看看通常用于制造游戏和游戏效果的模式: 游戏循环、精灵、碰撞和粒子系统。
  • 视觉效果的基本实现
    我们还将探讨支持这些模式的理论和一些代码示例。

读写

console.log(array[0]); // name console.log(arrayLike[0]); // name array[0] = 'new name'; arrayLike[0] = 'new name';

1
2
3
4
5
console.log(array[0]); // name
console.log(arrayLike[0]); // name
 
array[0] = 'new name';
arrayLike[0] = 'new name';

二、SVG基本形状

SVG 提供了rectcircleellipselinepolylinepolygon六种基本形状用于图形绘制,这些形状可以直接用来绘制一些基本的形状,如矩形、椭圆等,而复杂图形的绘制则需要使用 path 路径来实现。

图片 2

常见的模式

让我们从游戏开发中常用的大一些模式和元素开始

长度

console.log(array.length); // 3 console.log(arrayLike.length); // 3

1
2
console.log(array.length); // 3
console.log(arrayLike.length); // 3

1.rect 矩形

XHTML

<rect x="10" y="10" width="30" height="30"/> <rect x="60" y="10" rx="10" ry="10" width="30" height="30"/>

1
2
<rect x="10" y="10" width="30" height="30"/>
<rect x="60" y="10" rx="10" ry="10" width="30" height="30"/>

SVG中rect元素用于绘制矩形、圆角矩形,含有6个基本属性用于控制矩形的形状以及坐标,具体如下:

x 矩形左上角x位置, 默认值为 0 y 矩形左上角y位置, 默认值为 0 width 矩形的宽度, 不能为负值否则报错, 0 值不绘制 height 矩形的高度, 不能为负值否则报错, 0 值不绘制 rx 圆角x方向半径, 不能为负值否则报错 ry 圆角y方向半径, 不能为负值否则报错

1
2
3
4
5
6
x 矩形左上角x位置, 默认值为 0
y 矩形左上角y位置, 默认值为 0
width 矩形的宽度, 不能为负值否则报错, 0 值不绘制
height 矩形的高度, 不能为负值否则报错, 0 值不绘制
rx 圆角x方向半径, 不能为负值否则报错
ry 圆角y方向半径, 不能为负值否则报错

这里需要注意,rxry 的还有如下规则:

  • rxry 都没有设置, 则 rx = 0 ry = 0
  • rxry 有一个值为0, 则相当于 rx = 0 ry = 0,圆角无效
  • rxry 有一个被设置, 则全部取这个被设置的值
  • rx 的最大值为 width 的一半, ry 的最大值为 height 的一半
JavaScript

rx = rx || ry || 0; ry = ry || rx || 0;   rx = rx &gt; width / 2 ?
width / 2 : rx; ry = ry &gt; height / 2 ? height / 2 : ry;   if(0
=== rx || 0 === ry){ rx = 0, ry = 0;
//圆角不生效,等同于,rx,ry都为0 }

<table>
<colgroup>
<col style="width: 50%" />
<col style="width: 50%" />
</colgroup>
<tbody>
<tr class="odd">
<td><div class="crayon-nums-content" style="font-size: 13px !important; line-height: 15px !important;">
<div class="crayon-num" data-line="crayon-5b8f49eccc27a188181481-1">
1
</div>
<div class="crayon-num crayon-striped-num" data-line="crayon-5b8f49eccc27a188181481-2">
2
</div>
<div class="crayon-num" data-line="crayon-5b8f49eccc27a188181481-3">
3
</div>
<div class="crayon-num crayon-striped-num" data-line="crayon-5b8f49eccc27a188181481-4">
4
</div>
<div class="crayon-num" data-line="crayon-5b8f49eccc27a188181481-5">
5
</div>
<div class="crayon-num crayon-striped-num" data-line="crayon-5b8f49eccc27a188181481-6">
6
</div>
<div class="crayon-num" data-line="crayon-5b8f49eccc27a188181481-7">
7
</div>
<div class="crayon-num crayon-striped-num" data-line="crayon-5b8f49eccc27a188181481-8">
8
</div>
<div class="crayon-num" data-line="crayon-5b8f49eccc27a188181481-9">
9
</div>
<div class="crayon-num crayon-striped-num" data-line="crayon-5b8f49eccc27a188181481-10">
10
</div>
</div></td>
<td><div class="crayon-pre" style="font-size: 13px !important; line-height: 15px !important; -moz-tab-size:4; -o-tab-size:4; -webkit-tab-size:4; tab-size:4;">
<div id="crayon-5b8f49eccc27a188181481-1" class="crayon-line">
rx = rx || ry || 0;
</div>
<div id="crayon-5b8f49eccc27a188181481-2" class="crayon-line crayon-striped-line">
ry = ry || rx || 0;
</div>
<div id="crayon-5b8f49eccc27a188181481-3" class="crayon-line">
 
</div>
<div id="crayon-5b8f49eccc27a188181481-4" class="crayon-line crayon-striped-line">
rx = rx &gt; width / 2 ? width / 2 : rx;
</div>
<div id="crayon-5b8f49eccc27a188181481-5" class="crayon-line">
ry = ry &gt; height / 2 ? height / 2 : ry;
</div>
<div id="crayon-5b8f49eccc27a188181481-6" class="crayon-line crayon-striped-line">
 
</div>
<div id="crayon-5b8f49eccc27a188181481-7" class="crayon-line">
if(0 === rx || 0 === ry){
</div>
<div id="crayon-5b8f49eccc27a188181481-8" class="crayon-line crayon-striped-line">
rx = 0,
</div>
<div id="crayon-5b8f49eccc27a188181481-9" class="crayon-line">
ry = 0; //圆角不生效,等同于,rx,ry都为0
</div>
<div id="crayon-5b8f49eccc27a188181481-10" class="crayon-line crayon-striped-line">
}
</div>
</div></td>
</tr>
</tbody>
</table>

精灵

这些只是在游戏中代表一个对象的二维图像。精灵可以用于静态对象, 也可以用于动画对象, 当每个精灵代表一个帧序列动画。它们也可用于制作用户界面元素。

通常游戏包含从几十到几百精灵图片。为了减少内存的使用和处理这些映像所需的能力, 许多游戏使用精灵表。

遍历

for(var i = 0, len = array.length; i len; i++) { …… } for(var i = 0, len = arrayLike.length; i len; i++) { …… }

1
2
3
4
5
6
for(var i = 0, len = array.length; i  len; i++) {
   ……
}
for(var i = 0, len = arrayLike.length; i  len; i++) {
    ……
}

是不是很像?

那类数组对象可以使用数组的方法吗?比如:

arrayLike.push('4');

1
arrayLike.push('4');

然而上述代码会报错: arrayLike.push is not a function

所以终归还是类数组呐……

2.circle 圆形

XHTML

<circle cx="100" cy="100" r="50" fill="#fff"></circle>

1
<circle cx="100" cy="100" r="50" fill="#fff"></circle>

SVG中circle元素用于绘制圆形,含有3个基本属性用于控制圆形的坐标以及半径,具体如下:

r 半径 cx 圆心x位置, 默认为 0 cy 圆心y位置, 默认为 0

1
2
3
r 半径
cx 圆心x位置, 默认为 0
cy 圆心y位置, 默认为 0

精灵表

这些都用来在一个图像中合成一套单个精灵。这减少了在游戏中文件的数量,从而减少内存和处理电源使用。精灵表包含许多单精灵堆积彼此相邻的行和列,和类似精灵的图像文件,它们包含可用于静态或动画。

图片 3

精灵表例子。(图像来源: Kriplozoik)

下面是Code + Web的文章, 帮助您更好地理解使用精灵表的益处。

调用数组方法

如果类数组就是任性的想用数组的方法怎么办呢?

既然无法直接调用,我们可以用 Function.call 间接调用:

var arrayLike = {0: 'name', 1: 'age', 2: 'sex', length: 3 } Array.prototype.join.call(arrayLike, '&'); // name&age&sex Array.prototype.slice.call(arrayLike, 0); // ["name", "age", "sex"] // slice可以做到类数组转数组 Array.prototype.map.call(arrayLike, function(item){ return item.toUpperCase(); }); // ["NAME", "AGE", "SEX"]

1
2
3
4
5
6
7
8
9
10
11
var arrayLike = {0: 'name', 1: 'age', 2: 'sex', length: 3 }
 
Array.prototype.join.call(arrayLike, '&'); // name&age&sex
 
Array.prototype.slice.call(arrayLike, 0); // ["name", "age", "sex"]
// slice可以做到类数组转数组
 
Array.prototype.map.call(arrayLike, function(item){
    return item.toUpperCase();
});
// ["NAME", "AGE", "SEX"]

3.ellipse 椭圆

XHTML

<ellipse cx="75" cy="75" rx="20" ry="5"/>

1
<ellipse cx="75" cy="75" rx="20" ry="5"/>

SVG中ellipse元素用于绘制椭圆,是circle元素更通用的形式,含有4个基本属性用于控制椭圆的形状以及坐标,具体如下:

rx 椭圆x半径 ry 椭圆y半径 cx 圆心x位置, 默认为 0 cy 圆心y位置, 默认为 0

1
2
3
4
rx 椭圆x半径
ry 椭圆y半径
cx 圆心x位置, 默认为 0
cy 圆心y位置, 默认为 0

游戏循环

重要的是要认识到游戏对象并不真正在屏幕上移动。运动的假象是通过渲染一个游戏世界的屏幕快照, 随着游戏的时间的一点点推进 (通常是1/60 秒), 然后再渲染的东西。这实际上是一个停止和运动的效果, 并常在二维和三 维游戏中使用。游戏循环是一种实现此停止运动的机制。它是运行游戏所需的主要组件。它连续运行, 执行各种任务。在每个迭代中, 它处理用户输入, 移动实体, 检查碰撞, 并渲染游戏 (推荐按这个顺序)。它还控制了帧之间的游戏时间。

下面示例是用JavaScriptpgpg语言写的非常基本的游戏循环︰

JavaScript

var lastUpdate; function tick() { var now = window.Date.now(); if (lastUpdate) { var elapsed = (now-lastUpdate) / 1000; lastUpdate = now; // Update all game objects here. update(elapsed); // ...and render them somehow. render(); } else { // Skip first frame, so elapsed is not 0. lastUpdate = now; } // This makes the `tick` function run 60 frames per second (or slower, depends on monitor's refresh rate). window.requestAnimationFrame(tick); };

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
var lastUpdate;
 
function tick() {
  var now = window.Date.now();
 
  if (lastUpdate) {
    var elapsed = (now-lastUpdate) / 1000;
    lastUpdate = now;
 
    // Update all game objects here.
    update(elapsed);
    // ...and render them somehow.
    render();
  } else {
    // Skip first frame, so elapsed is not 0.
    lastUpdate = now;
  }
 
  // This makes the `tick` function run 60 frames per second (or slower, depends on monitor's refresh rate).
  window.requestAnimationFrame(tick);
};

请注意,上面的例子中是非常简单。它使用可变时间增量 (已用的变量),并建议升级此代码以使用固定的增量时间。有关详细信息, 请参阅本文。

类数组转对象

在上面的例子中已经提到了一种类数组转数组的方法,再补充三个:

var arrayLike = {0: 'name', 1: 'age', 2: 'sex', length: 3 } // 1. slice Array.prototype.slice.call(arrayLike); // ["name", "age", "sex"] // 2. splice Array.prototype.splice.call(arrayLike, 0); // ["name", "age", "sex"] // 3. ES6 Array.from Array.from(arrayLike); // ["name", "age", "sex"] // 4. apply Array.prototype.concat.apply([], arrayLike)

1
2
3
4
5
6
7
8
9
var arrayLike = {0: 'name', 1: 'age', 2: 'sex', length: 3 }
// 1. slice
Array.prototype.slice.call(arrayLike); // ["name", "age", "sex"]
// 2. splice
Array.prototype.splice.call(arrayLike, 0); // ["name", "age", "sex"]
// 3. ES6 Array.from
Array.from(arrayLike); // ["name", "age", "sex"]
// 4. apply
Array.prototype.concat.apply([], arrayLike)

那么为什么会讲到类数组对象呢?以及类数组有什么应用吗?

要说到类数组对象,Arguments 对象就是一个类数组对象。在客户端 JavaScript 中,一些 DOM 方法(document.getElementsByTagName()等)也返回类数组对象。

4.line 直线

XHTML

<line x1="10" x2="50" y1="110" y2="150"/>

1
<line x1="10" x2="50" y1="110" y2="150"/>

Line绘制直线。它取两个点的位置作为属性,指定这条线的起点和终点位置。

x1 起点的x位置 y1 起点的y位置 x2 终点的x位置 y2 终点的y位置

1
2
3
4
x1 起点的x位置
y1 起点的y位置
x2 终点的x位置
y2 终点的y位置

碰撞检测

碰撞检测是指发现物体之间的交点。这对于许多游戏是必不可少的, 因为它用来检测玩家击中墙壁或子弹击中敌人, 诸如此类等等。当检测到碰撞时, 它可以用于游戏逻辑设计中;例如, 当子弹击中玩家时, 健康分数会减少十点。

有很多碰撞检测算法, 因为它是一个性能繁重的操作, 明智的选择最好的方法是很重要的。要了解有关碰撞检测、算法以及如何实现它们的更多信息, 这里有一篇来自MDN 的文章。

Arguments对象

接下来重点讲讲 Arguments 对象。

Arguments 对象只定义在函数体中,包括了函数的参数和其他属性。在函数体中,arguments 指代该函数的 Arguments 对象。

举个例子:

function foo(name, age, sex) { console.log(arguments); } foo('name', 'age', 'sex')

1
2
3
4
5
function foo(name, age, sex) {
    console.log(arguments);
}
 
foo('name', 'age', 'sex')

打印结果如下:

图片 4

我们可以看到除了类数组的索引属性和length属性之外,还有一个callee属性,接下来我们一个一个介绍。

5.polyline 折线

XHTML

<polyline points="60 110, 65 120, 70 115, 75 130, 80 125, 85 140, 90 135, 95 150, 100 145"/>

1
<polyline points="60 110, 65 120, 70 115, 75 130, 80 125, 85 140, 90 135, 95 150, 100 145"/>

polyline是一组连接在一起的直线。因为它可以有很多的点,折线的的所有点位置都放在一个points属性中:

points 点集数列,每个数字用空白、逗号、终止命令符或者换行符分隔开,每个点必须包含2个数字,一个是x坐标,一个是y坐标 如0 0, 1 1, 2 2”

1
points 点集数列,每个数字用空白、逗号、终止命令符或者换行符分隔开,每个点必须包含2个数字,一个是x坐标,一个是y坐标 如0 0, 1 1, 2 2”

粒子和粒子系统

粒子基本上是用粒子系统的精灵。在游戏开发中一个粒子系统是由粒子发射器和分配给该发射器的粒子组成的一个组成部分。它用来模拟各种特效,像火灾、 爆炸、 烟、 和下雨的影响。随着时间的推移微粒和每个发射器有其自身的参数来定义各种变量,用于模拟的效果,如速度、 颜色、 粒子寿命或持续时间,重力、 摩擦和风速。

length属性

Arguments对象的length属性,表示实参的长度,举个例子:

function foo(b, c, d){ console.log("实参的长度为:" + arguments.length) } console.log("形参的长度为:" + foo.length) foo(1) // 形参的长度为:3 // 实参的长度为:1

1
2
3
4
5
6
7
8
9
10
function foo(b, c, d){
    console.log("实参的长度为:" + arguments.length)
}
 
console.log("形参的长度为:" + foo.length)
 
foo(1)
 
// 形参的长度为:3
// 实参的长度为:1

6.polygon 多边形

XHTML

<polygon points="50 160, 55 180, 70 180, 60 190, 65 205, 50 195, 35 205, 40 190, 30 180, 45 180"/>

1
<polygon points="50 160, 55 180, 70 180, 60 190, 65 205, 50 195, 35 205, 40 190, 30 180, 45 180"/>

polygon和折线很像,它们都是由连接一组点集的直线构成。不同的是,polygon的路径在最后一个点处自动回到第一个点。需要注意的是,矩形也是一种多边形,如果需要更多灵活性的话,你也可以用多边形创建一个矩形。

points 点集数列,每个数字用空白、逗号、终止命令符或者换行符分隔开,每个点必须包含2个数字,一个是x坐标,一个是y坐标 如0 0, 1 1, 2 2, 路径绘制完闭合图形”

1
points 点集数列,每个数字用空白、逗号、终止命令符或者换行符分隔开,每个点必须包含2个数字,一个是x坐标,一个是y坐标 如0 0, 1 1, 2 2, 路径绘制完闭合图形”

欧拉积分

欧拉积分是运动的积分方程的一种方法。每个对象的位置计算基于其速度,质量和力量,并需要重新计算每个 tick 在游戏循环。欧拉方法是最基本和最有用的像侧滚动的射击游戏,但也有其它的方法,如Verlet 积分和 RK4积分,会更好地完成其他任务。下面我将展示一个简单的实现的想法。

你需要一个基本的结构以容纳对象的位置、 速度和其他运动相关的数据。我们提出两个相同的结构,但每一个都有不同的意义,在世界空间中︰ 点和矢量。游戏引擎通常使用某种类型的矢量类,但点和矢量之间的区别是非常重要的,大大提高了代码的可读性 (例如,您计算不是两个矢量,但这两个点之间的距离,这是更自然)。

本文由澳门新葡亰手机版发布于web前端,转载请注明出处:基本形状转换那些事,游戏开发基础的教程

上一篇:没有了 下一篇:没有了
猜你喜欢
热门排行
精彩图文