Posts 学习Pixi并制作一个小游戏
Post
Cancel

学习Pixi并制作一个小游戏

学习用 PixiJS 制作游戏和互动媒体。

初始化 pixi

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8" />
    <title>Hello World</title>
  </head>
  <script src="pixi.min.js"></script>
  <body>
    <script type="text/javascript">
      var type = "WebGL";
      if (!PIXI.utils.isWebGLSupported()) {
        type = "Canvas";
      }

      PIXI.utils.sayHello(type);
    </script>
  </body>
</html>

控制台会打印 pixi 使用的是 WebGL 还是 Canvas

1
Pixi.js 4.0.0 - ✰ WebGL ✰      http://www.pixijs.com/    ♥♥♥

创建渲染器和舞台

1
2
3
4
5
6
7
8
//Create the renderer
var renderer = PIXI.autoDetectRenderer(256, 256);
//Add the canvas to the HTML document
document.body.appendChild(renderer.view);
//Create a container object called the `stage`
var stage = new PIXI.Container();
//Tell the `renderer` to `render` the `stage`
renderer.render(stage);

renderer.view 对象只是一个再普通不过的 <canvas> 对象,所以你可以像控制其他任何 canvas 对象一样控制它。

stage 是一个 Pixi Container 对象。你可以把这个容器想象成一个可以把你所有想放的东西放进去的一种空盒子。 我们创建的 stage 对象是在你创建的场景中所有可视物体的根容器。Pixi 需要你有一个根容器,因为 renderer 需要有一个东西去渲染上去。不管你往这个 stage 里面放什么都会被渲染到 canvas 上面。现在这个 stage 是空的。

给 canvas 一个虚线边框:

1
renderer.view.style.border = "1px dashed black";

如果你想在创建 canvas 后改变它的背景颜色,设置 renderer 对象的 backgroundColor 属性为其他任何十六进制的颜色值:

1
renderer.backgroundColor = 0x061639;

如果你想获取 renderer 的宽和高,用 renderer.view.widthrenderer.view.height。尽管 stage 也有 width 和 height 属性,它们不是指渲染窗口的大小。舞台的 width 和 height 只是告诉你你放的东西所占用的区域。

可以用 renderer 的 resize 方法设置任何新的 width 和 height 值去改变 canvas 的大小。但是,请确保 canvas 和分辨率是大小相匹配的,设置 autoResize 为 true。

1
2
renderer.autoResize = true;
renderer.resize(512, 512);

如果你想让 canvas 占据整个窗口,你可以设置 CSS 样式并且调整渲染器的大小为浏览器窗口的大小。

1
2
3
4
renderer.view.style.position = "absolute";
renderer.view.style.display = "block";
renderer.autoResize = true;
renderer.resize(window.innerWidth, window.innerHeight);

Pixi 精灵

Pixi 有一个 Sprite 类,它是创建游戏精灵的通用方式。这里还有三个主要的方式去创建它们

  • 使用单独一个图片文件
  • 使用图片集的一个子图像。图片集是一个单独的,大的图像,它包含了所有游戏中你需要的图片。(雪碧图)
  • 使用纹理图集(一个定义了在雪碧图中每个子图的位置和大小的 JSON 文件)

加载图像到纹理缓存中

因为 Pixi 通过 WebGL 在 GPU 上渲染图像,图像需要被格式化为 GPU 可以处理的格式。一个为 WebGL 准备的图像称为 纹理。Pixi 使用了一个 纹理缓存 去存储和引用所有精灵图所需要的纹理。纹理的名字是一个指向图片文件的位置的字符串。可以通过这个方法来在纹理缓存中找到图像。

1
2
const catTexture = PIXI.utils.TextureCache["images/cat.png"];
const catSprite = new PIXI.Sprite(catTexture);

用 Pixi 的内置 loader 对象,可以加载一个图片并把它转化为一个纹理。Pixi 强大的 loader 对象是你加载任何一种图像的全部所需。这里告诉你了如何加载一个图像并在图像加载完成之后调用 setup 函数。

1
2
3
4
5
PIXI.loader.add("images/anyImage.png").load(setup);

function setup() {
  //This code will run when the loader has finished loading the image
}

如果你使用了加载器,你应该通过引用纹理中的 loader 的 resources 对象来创建精灵。

1
2
3
var sprite = new PIXI.Sprite(
  PIXI.loader.resources["images/anyImage.png"].texture
);

可以通过它来加载一个图像,调用 setup 函数,并且从加载过的图像中创建一个精灵:

1
2
3
4
5
6
7
PIXI.loader.add("images/anyImage.png").load(setup);

function setup() {
  var sprite = new PIXI.Sprite(
    PIXI.loader.resources["images/anyImage.png"].texture
  );
}

一次性加载许多图像,可以把所有的你想加载的文件放到一个数组里:

1
2
3
PIXI.loader
  .add(["images/imageOne.png", "images/imageTwo.png", "images/imageThree.png"])
  .load(setup);

展示精灵

想要在 canvas 上看到它,需要做两件事

  • 通过 stage.addChild 方法把精灵添加到 Pixi 的 stage
  • 需要告诉 Pixi 的 renderer 去渲染这个舞台
1
2
3
stage.addChild(cat);

renderer.render(stage);

加载图像,创建一个精灵,并把它展示在 Pixi 舞台上的所有的 JavaScript 代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
var stage = new PIXI.Container(),
  renderer = PIXI.autoDetectRenderer(256, 256);
document.body.appendChild(renderer.view);

//Use Pixi's built-in `loader` object to load an image
PIXI.loader.add("images/cat.png").load(setup);

//This `setup` function will run when the image has loaded
function setup() {
  //Create the `cat` sprite from the texture
  var cat = new PIXI.Sprite(PIXI.loader.resources["images/cat.png"].texture);

  //Add the cat to the stage
  stage.addChild(cat);

  //Render the stage
  renderer.render(stage);
}

如果你想从舞台中移除一个精灵,用 removeChild 方法:

1
stage.removeChild(anySprite);

但是通常设置精灵的 visible 属性为 false 是一个让精灵消失的高效而且简单方式。

1
anySprite.visible = false;

创建别名

  • Sprite 是 PIXI.Sprite 的别名
  • TextureCache 是 PIXI.utils.TextureCache 的别名
  • resources 是 PIXI.loader.resources 的别名
  • Rectangle 是 PIXI.Rectangle 的别名

监控加载进度

Pixi 的加载器有一个特殊的 progress 事件会在每次当一个文件加载的时候调用一个可定制的函数。 progress 事件会被 loader 的 on 方法调用:

1
PIXI.loader.on("progress", loadProgressHandler);

可以明确的指明哪个文件已经加载了以及文件加载的百分比,可以通过给 loadProgressHandler 添加 loader 和 resource 参数:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
PIXI.loader
  .add(["images/one.png", "images/two.png", "images/three.png"])
  .on("progress", loadProgressHandler)
  .load(setup);

function loadProgressHandler(loader, resource) {
  //Display the file `url` currently being loaded
  console.log("loading: " + resource.url);

  //Display the precentage of files currently loaded
  console.log("progress: " + loader.progress + "%");

  //If you gave your files names as the first argument
  //of the `add` method, you can access them like this
  //console.log("loading: " + resource.name);
}

function setup() {
  console.log("All files loaded");
}

定位精灵

创建完精灵后可以更改其位置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
function setup() {
  //Create the `cat` sprite
  var cat = new Sprite(resources["images/cat.png"].texture);

  //Change the sprite's position
  cat.x = 96;
  cat.y = 96;

  //Add the cat to the stage so you can see it
  stage.addChild(cat);

  //Render the stage
  renderer.render(stage);
}

可以用一行代码把 x 和 y 的值一起设置,而不是单独设置:

1
sprite.position.set(x, y);

尺寸和缩放

设置尺寸

1
2
3
//Change the sprite's size
cat.width = 80;
cat.height = 120;

可以直接通过属性设置缩放,当然用 set 方法最好

1
cat.scale.set(0.5, 0.5);

旋转

旋转之前先设置中心点

1
2
3
4
5
6
// 百分比设置法
cat.anchor.x = 0.5;
cat.anchor.y = 0.5;

// x 和 y 的值设置法
sprite.anchor.set(x, y);

用雪碧图的子图像制作精灵

你通常会把你的精灵图制作成图集(也叫雪碧图。)Pixi 有一些内置的简便的方式帮助你做到这些。

当图片加载完成,用一个雪碧图的矩形项去创造一个精灵图片。这里的代码就展示如何提取子图,创建火箭图像,定位并且在 canvas 中展示它。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
function setup() {
  //Create the `tileset` sprite from the texture
  var texture = TextureCache["images/tileset.png"];

  //Create a rectangle object that defines the position and
  //size of the sub-image you want to extract from the texture
  var rectangle = new Rectangle(192, 128, 64, 64);

  //Tell the texture to use that rectangular section
  texture.frame = rectangle;

  //Create the sprite from the texture
  var rocket = new Sprite(texture);

  //Position the rocket sprite on the canvas
  rocket.x = 32;
  rocket.y = 32;

  //Add the rocket to the stage
  stage.addChild(rocket);

  //Render the stage
  renderer.render(stage);
}

使用纹理图集

使用免费版的 Texture Packer,设置 Algorithm 为 Basic,设置 Trim mode 为 None,设置 Size constraints 为 Any size 然后滑动 PNG Opt Level 到最左为 0。这是让你利用免费版的 Texture Packer 创建你的文件不会报错和警告的最基本的做法。 )

当你完成之后,点击 Publish 按钮。选择文件的名字的位置,然后保存发布文件。你将会得到两个文件:一个 PNG 文件和一个 JSON 文件。在这个例子中我的文件名字叫 treasureHunter.json 和 treasureHunter.png。

1
2
3
4
5
6
7
8
9
"blob.png":
{
  "frame": {"x":55,"y":2,"w":32,"h":24},
  "rotated": false,
  "trimmed": false,
  "spriteSourceSize": {"x":0,"y":0,"w":32,"h":24},
  "sourceSize": {"w":32,"h":24},
  "pivot": {"x":0.5,"y":0.5}
},

加载纹理图集

为了把纹理图集加入 Pixi,用 Pixi 的 loader 加载它。如果你是用 Texture Packer 制作的 JSON 文件,loader 会自动在雪碧图上解释数据和创建纹理图。

1
loader.add("images/treasureHunter.json").load(setup);

从加载过的纹理图集创建精灵

用 TextureCache:

1
2
var texture = TextureCache["frameId.png"],
  sprite = new Sprite(texture);

移动精灵

用 requestAnimationFrame 创建一个循环函数。这被称为 游戏循环。 任何在游戏循环里的代码都会 1s 更新 60 次。你可以用下面的代码让 cat 精灵以每帧 1 像素的速率移动。

1
2
3
4
5
6
7
8
9
10
11
12
13
function gameLoop() {
  //Loop this function at 60 frames per second
  requestAnimationFrame(gameLoop);

  //Move the cat 1 pixel to the right each frame
  cat.x += 1;

  //Render the stage to see the animation
  renderer.render(stage);
}

//Start the game loop
gameLoop();

游戏状态

作为一种风格,也是为了帮你模块你的代码,我推荐在游戏循环里像这样组织你的代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
//Set the game's current state to `play`:
var state = play;

function gameLoop() {
  //Loop this function at 60 frames per second
  requestAnimationFrame(gameLoop);

  //Update the current game state:
  state();

  //Render the stage to see the animation
  renderer.render(stage);
}

function play() {
  //Move the cat 1 pixel to the right each frame
  cat.x += 1;
}

键盘移动

只需再做一小点工作,你就可以建立一个通过鼠标控制精灵移动的简单系统。为了简化你的代码,我建议你用一个名为 keyboard 的自定义函数来监听和捕捉键盘事件。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
function keyboard(keyCode) {
  var key = {};
  key.code = keyCode;
  key.isDown = false;
  key.isUp = true;
  key.press = undefined;
  key.release = undefined;
  //The `downHandler`
  key.downHandler = function (event) {
    if (event.keyCode === key.code) {
      if (key.isUp && key.press) key.press();
      key.isDown = true;
      key.isUp = false;
    }
    event.preventDefault();
  };

  //The `upHandler`
  key.upHandler = function (event) {
    if (event.keyCode === key.code) {
      if (key.isDown && key.release) key.release();
      key.isDown = false;
      key.isUp = true;
    }
    event.preventDefault();
  };

  //Attach event listeners
  window.addEventListener("keydown", key.downHandler.bind(key), false);
  window.addEventListener("keyup", key.upHandler.bind(key), false);
  return key;
}

keyboard 函数很容易使用,可以像这样创建一个新的键盘对象:

1
var keyObject = keyboard(asciiKeyCodeNumber);

这个函数只接受一个参数就是键盘对应的 ASCII 键值数,也就是你想监听的键盘按键。然后给键盘对象赋值 press 和 release 方法:

1
2
3
4
5
6
keyObject.press = function () {
  //key object pressed
};
keyObject.release = function () {
  //key object released
};

更多

中间还有不少基础的教学

实战教学:宝藏猎手

玩耍地址:https://static.chenng.cn/treasure-hunter/index.html

宝藏猎手是一个简单的完整的游戏之一,它是一个很好的例子,它能让你把目前所学的所有工具都用上。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
// 设置别名
var Container = PIXI.Container,
  autoDetectRenderer = PIXI.autoDetectRenderer,
  loader = PIXI.loader,
  resources = PIXI.loader.resources,
  TextureCache = PIXI.utils.TextureCache,
  Texture = PIXI.Texture,
  Sprite = PIXI.Sprite,
  Text = PIXI.Text,
  Graphics = PIXI.Graphics;

//Create a Pixi stage and renderer and add the
//renderer.view to the DOM
// 创建 PIXI 舞台,renderer,添加 render.view 到 DOM 中
var stage = new Container(),
  renderer = autoDetectRenderer(512, 512);
document.body.appendChild(renderer.view);

loader.add("images/treasureHunter.json").load(setup);

// 定义不知在一个地方使用的变量
var state,
  explorer,
  treasure,
  blobs,
  chimes,
  exit,
  player,
  dungeon,
  door,
  healthBar,
  message,
  gameScene,
  gameOverScene,
  enemies,
  id;

// 初始化 Pixi、加载地图册文件
function setup() {
  // 初始化地图精灵,将游戏状态设置为 play,然后开始游戏

  // 创建游戏运行场景分组
  gameScene = new Container();
  stage.addChild(gameScene);

  // 为获取资源的方法设置一个简短的别名
  id = resources["images/treasureHunter.json"].textures;

  // 创建地牢精灵
  dungeon = new Sprite(id["dungeon.png"]);
  gameScene.addChild(dungeon);

  // 创建门精灵
  door = new Sprite(id["door.png"]);
  door.position.set(32, 0);
  gameScene.addChild(door);

  // 创建探索者精灵
  explorer = new Sprite(id["explorer.png"]);
  explorer.x = 68;
  explorer.y = gameScene.height / 2 - explorer.height / 2;
  explorer.vx = 0;
  explorer.vy = 0;
  gameScene.addChild(explorer);

  // 创建宝藏精灵
  treasure = new Sprite(id["treasure.png"]);
  treasure.x = gameScene.width - treasure.width - 48;
  treasure.y = gameScene.height / 2 - treasure.height / 2;
  gameScene.addChild(treasure);

  // 设置游戏结束场景分组
  gameOverScene = new Container();
  gameOverScene.visible = false;
  stage.addChild(gameOverScene);

  // 创建一堆的怪物
  let numberOfBlobs = 6,
    spacing = 48,
    xOffset = 150,
    speed = 2,
    direction = 1;
  // 一个存储所有怪物的数组
  blobs = [];
  // 根据设置的数量制造怪物实体
  for (let i = 0; i < numberOfBlobs; i++) {
    let blob = new Sprite(id["blob.png"]);
    // 根据间距、偏移设置怪物实体的水平位置
    let x = spacing * i + xOffset;
    // 给实体一个随机的 y 位置
    let y = randomInt(0, stage.height - blob.height);
    // 设置实体的位置
    blob.x = x;
    blob.y = y;
    // 设置实体的垂直加速度
    blob.vy = speed * direction;
    // 翻转下一个实体的方向
    direction *= -1;
    // 将实体塞入集合
    blobs.push(blob);
    // 将实体加入游戏场景
    gameScene.addChild(blob);
  }

  // 添加血条
  healthBar = new PIXI.DisplayObjectContainer();
  healthBar.position.set(stage.width - 170, 6);
  gameScene.addChild(healthBar);
  // 创建后面的黑色矩形
  let innerBar = new PIXI.Graphics();
  innerBar.beginFill(0x000000);
  innerBar.drawRect(0, 0, 128, 8);
  innerBar.endFill();
  healthBar.addChild(innerBar);
  // 创建前面的红色矩形
  let outerBar = new PIXI.Graphics();
  outerBar.beginFill(0xff3300);
  outerBar.drawRect(0, 0, 128, 8);
  outerBar.endFill();
  healthBar.addChild(outerBar);
  // 在 healthBar 上面添加个红色矩形的引用,过会儿能很方便的获取
  // 如果你想控制红色 outerBar 的宽度,可以这么做 healthBar.outer.width = 30;
  healthBar.outer = outerBar;

  // 制作消息文字
  message = new Text("The End", { font: "64px Futura", fill: "white" });
  message.x = 120;
  message.y = stage.height / 2 - 32;
  gameOverScene.addChild(message);

  // 捕获键盘操作
  let left = keyboard(37),
    up = keyboard(38),
    right = keyboard(39),
    down = keyboard(40);
  left.press = function () {
    explorer.vx = -5;
    explorer.vy = 0;
  };
  left.release = function () {
    if (!right.isDown && explorer.vy === 0) {
      explorer.vx = 0;
    }
  };
  up.press = function () {
    explorer.vy = -5;
    explorer.vx = 0;
  };
  up.release = function () {
    if (!down.isDown && explorer.vx === 0) {
      explorer.vy = 0;
    }
  };
  right.press = function () {
    explorer.vx = 5;
    explorer.vy = 0;
  };
  right.release = function () {
    if (!left.isDown && explorer.vy === 0) {
      explorer.vx = 0;
    }
  };
  down.press = function () {
    explorer.vy = 5;
    explorer.vx = 0;
  };
  down.release = function () {
    if (!up.isDown && explorer.vx === 0) {
      explorer.vy = 0;
    }
  };

  // 设置游戏状态为 play
  state = play;

  // 开始游戏循环
  gameLoop();
}

// 游戏循环运行
function gameLoop() {
  // 每秒 60 次更新 state 函数
  requestAnimationFrame(gameLoop);

  // 更新游戏状态,state 函数有 play 和 end 两种状态
  state();

  // 渲染舞台
  renderer.render(stage);
}

// 所有让精灵移动的游戏逻辑都在 play 里,这是一个被循环执行的函数
function play() {
  // 移动探索者,并限制他在地牢范围内
  explorer.x += explorer.vx;
  explorer.y += explorer.vy;
  contain(explorer, { x: 28, y: 10, width: 488, height: 480 });

  // 在碰撞前设置 exploreHit 为 false
  let explorerHit = false;

  // 移动怪物实体
  blobs.forEach(function (blob) {
    // 移动怪物
    blob.y += blob.vy;
    // 检查怪物的屏幕边界
    let blobHitsWall = contain(blob, { x: 28, y: 10, width: 488, height: 488 });
    // 如果实体碰到上下边缘,改变它的方向
    if (["top", "bottom"].indexOf(blobHitsWall) > -1) {
      blob.vy *= -1;
    }
    // 碰撞测试,如果碰到归爱武,设置 exploreHit 为 true
    if (hitTestRectangle(explorer, blob)) {
      explorerHit = true;
    }
  });

  // 检查探索者与怪物的碰撞
  if (explorerHit) {
    // 设置探索者半透明
    explorer.alpha = 0.5;
    // 减少血条长度
    healthBar.outer.width -= 1;
  } else {
    // 设置探索者不透明
    explorer.alpha = 1;
  }

  // 检查探索者与宝藏的碰撞,携带宝藏移动
  if (hitTestRectangle(explorer, treasure)) {
    treasure.x = explorer.x + 8;
    treasure.y = explorer.y + 8;
  }

  // 检查宝藏与门的碰撞,赢得游戏
  if (hitTestRectangle(treasure, door)) {
    state = end;
    message.text = "You won!";
  }

  // 游戏失败,将 state 函数设为 end
  if (healthBar.outer.width < 0) {
    state = end;
    message.text = "You lost!";
  }
}

// 游戏结束
function end() {
  gameScene.visible = false;
  gameOverScene.visible = true;
}

// The game's helper functions:
// `keyboard`, `hitTestRectangle`, `contain` and `randomInt`
function keyboard(keyCode) {
  let key = {};
  key.code = keyCode;
  key.isDown = false;
  key.isUp = true;
  key.press = undefined;
  key.release = undefined;
  key.downHandler = function (event) {
    if (event.keyCode === key.code) {
      if (key.isUp && key.press) {
        key.press();
      }
      key.isDown = true;
      key.isUp = false;
    }
    event.preventDefault();
  };
  key.upHandler = function (event) {
    if (event.keyCode === key.code) {
      if (key.isDown && key.release) {
        key.release();
      }
      key.isDown = false;
      key.isUp = true;
    }
    event.preventDefault();
  };
  window.addEventListener("keydown", key.downHandler.bind(key), false);
  window.addEventListener("keyup", key.upHandler.bind(key), false);
  return key;
}

function hitTestRectangle(r1, r2) {
  // 定义我们需要计算的变量
  let hit, combinedHalfWidths, combinedHalfHeights, vx, vy;
  // hit决定是否有碰撞
  hit = false;
  // 找到每个精灵的中心点
  r1.centerX = r1.x + r1.width / 2;
  r1.centerY = r1.y + r1.height / 2;
  r2.centerX = r2.x + r2.width / 2;
  r2.centerY = r2.y + r2.height / 2;

  // 找到每个精灵的一半宽度和一半高度
  r1.halfWidth = r1.width / 2;
  r1.halfHeight = r1.height / 2;
  r2.halfWidth = r2.width / 2;
  r2.halfHeight = r2.height / 2;
  // 计算精灵之间的向量距离
  vx = r1.centerX - r2.centerX;
  vy = r1.centerY - r2.centerY;
  // 计算出两个精灵的的一半宽度和一半高度的和
  combinedHalfWidths = r1.halfWidth + r2.halfWidth;
  combinedHalfHeights = r1.halfHeight + r2.halfHeight;
  // 检测 x 轴的碰撞
  if (Math.abs(vx) < combinedHalfWidths) {
    // 碰撞可能发生,检查 y 轴碰撞
    if (Math.abs(vy) < combinedHalfHeights) {
      //确实有碰撞发生
      hit = true;
    } else {
      // 在 y 轴没有碰撞
      hit = false;
    }
  } else {
    // 在x轴没有碰撞
    hit = false;
  }
  // `hit` 返回 `true` 或者 `false`
  return hit;
}

function contain(sprite, container) {
  let collision = undefined;
  // Left
  if (sprite.x < container.x) {
    sprite.x = container.x;
    collision = "left";
  }
  // Top
  if (sprite.y < container.y) {
    sprite.y = container.y;
    collision = "top";
  }
  // Right
  if (sprite.x + sprite.width > container.width) {
    sprite.x = container.width - sprite.width;
    collision = "right";
  }
  // Bottom
  if (sprite.y + sprite.height > container.height) {
    sprite.y = container.height - sprite.height;
    collision = "bottom";
  }
  // 返回 collision 结果
  return collision;
}

function randomInt(min, max) {
  return Math.floor(Math.random() * (max - min + 1)) + min;
}

// Pixi的类继承体系
// DisplayObject > Container > Sprite
This post is licensed under CC BY 4.0 by the author.
Trending Tags

Trending Tags