使用 Kontra.js 为 JS13K 构建一个小游戏
你觉得你能在 30 天内用少于 13kB 的 JavaScript、CSS 和/或 HTML 代码开发一款游戏吗?我有个挑战给你!
由GitHub Star @end3r组织的2021 年 JS13K 竞赛刚刚拉开帷幕,主题为SPACE。
你可以随心所欲地诠释这个主题——重现经典的《太空侵略者》或《小行星》风格的游戏,制作一款只能用控制SPACE杆控制的游戏,构建一款探索两个物体之间空间的游戏,或者任何你能想到的其他方式。但要注意空间——你只有 13kB 可用😉
如果你从未做过类似的事情,甚至从未写过太多 JavaScript 代码,这可能会有点吓人。这里有一个简短的教程,教你如何使用Kontra.js (一个专为 JS13K 开发的小型游戏库)以及几行代码来构建这个超棒的游戏:
玩游戏,查看源代码,或按照以下步骤和相应的差异进行操作。
1. 生成 HTML 模板
如果您是 DEV 的常客读者,那么您可能不需要太多帮助,但让我们从一个超级简单的 HTML 模板开始:
<!DOCTYPE html>
<html>
<head>
</head>
<body>
<canvas width="250" height="250" id="game" style="background-color: black;"></canvas>
</body>
</html>
在您的浏览器中查看它,您应该会看到一个⬛ - 我们的游乐区。
2. 包含 Kontra.js 库
为了简单起见,我们只需从 CDN 中提取最新版本的 Kontra,并在标签后包含我们知道将要使用的函数/帮助程序</canvas>
:
<script src="https://cdn.jsdelivr.net/npm/kontra@7.1.3/kontra.min.js"></script>
<script>
let { GameLoop, Sprite, bindKeys, collides, init, initKeys, keyPressed, randInt } = kontra;
let { canvas } = init();
</script>
3. 玩家一号准备好了!
首先,让我们为玩家 1 定义一个图像let { canvas } = init();
。为了快速显示/提升自我,我们将使用我的 GitHub 头像:
let image1 = new Image();
image1.src = 'https://avatars.githubusercontent.com/u/121322?v=4'
image1.width = 40;
image1.height = 40;
接下来,我们将创建精灵并将其放置在屏幕的左上角:
let sprite1 = Sprite({
x: 40,
y: 40,
anchor: {
x: 0.5,
y: 0.5
},
image: image1
});
现在我们将定义我们的游戏循环并开始运行!
let loop = GameLoop({
render: function() {
sprite1.render();
}
});
如果你现在在浏览器中查看游戏,应该会看到我的头像在一个大大的黑色方块里。哇哦——进步了!
等等!那个图片 URL 是从哪里来的?我怎么用我自己的?你可以从 GitHub API 轻松获取头像 URL,例如
$ curl -s https://api.github.com/users/leereilly | jq -r '.avatar_url'
https://avatars.githubusercontent.com/u/121322?v=4
或者
$ curl -s https://api.github.com/users/leereilly | grep -i avatar_url
"avatar_url": "https://avatars.githubusercontent.com/u/121322?v=4",
不知道您怎么想,但每次我在终端中针对 GitHub API 运行命令curl
时,我的感受是这样的:jq
好了,跑题了。看着黑色方块上的静态精灵可不是什么好玩的事,所以,我们动起来吧!
4. 让玩家 1 移动
让我们在游戏循环中引入一个update()
函数,它可以响应↑ ↓ ← →并适当移动我们的精灵:
update: function() {
if (keyPressed('left')) {
sprite1.x = sprite1.x - 1;
}
if (keyPressed('right')) {
sprite1.x = sprite1.x + 1;
}
if (keyPressed('up')) {
sprite1.y = sprite1.y - 1;
}
if (keyPressed('down')) {
sprite1.y = sprite1.y + 1;
}
},
initKeys();
我们还需要在之前添加一个调用loop.start();
:
initKeys();
loop.start();
您现在应该能够在屏幕上移动玩家 1 了🕹️
5. 介绍敌人
我们绝对可以让这个游戏更有趣。让我们把我们的敌方玩家——我的好朋友@mishmanners *——添加到随机位置,但不要超出屏幕范围。
* 这与 Michelle 在 Fornite、Magic The Gathering 和蛇形建造/战斗等游戏中击败我无关。
我们首先定义精灵的最大 X 和 Y 值(基本上是画布尺寸),然后利用 Kontra 的randInt()
助手来设置精灵的位置:
let maxX = 250;
let maxY = 250;
let image2 = new Image();
image2.src = 'https://avatars.githubusercontent.com/u/36594527?v=4'
image2.width = 40;
image2.height = 40;
let sprite2 = Sprite({
x: randInt(0, maxX),
y: randInt(0, maxY),
anchor: {
x: 0.5,
y: 0.5
},
image: image2
});
6.添加一些碰撞检测
这时你的大学水平的数学知识就会派上用场。
collides()
开玩笑的。这听起来很吓人,但值得庆幸的是,Kontra 通过助手为我们完成了所有艰苦的工作。一旦发生碰撞,我们就通过在函数末尾添加以下内容将玩家 2 精灵移动到随机位置update()
:
if (collides(sprite1, sprite2)) {
sprite2.x = randInt(41, maxX - 40);
sprite2.y = randInt(41, maxY - 40);
}
7. 使用这个巧妙的技巧使其像素化/8 位!
这
提示让你的精灵看起来像素化的方法很简单。因为我们使用的是 GitHub Avatar URL,所以我们可以将查询参数从 更改为 ,v=4
以s=10
请求 10x10 像素的版本。
- https://avatars.githubusercontent.com/u/121322?v=4
+ https://avatars.githubusercontent.com/u/121322?s=10
由于我们在代码中将图像设置为 4 倍,因此浏览器将尝试调整其大小,使其看起来像素化。
注意:肯定有更复杂的技术,而且使用这么大的图像对 JS13K 来说是个糟糕的主意。最好使用Aseprite或Piskel之类的工具来创作你自己的像素艺术。
8.添加一些音效
JS13K 里没有太多空间容纳 OGG 和 MP3。还好,比我聪明的人开发了一些简洁的库和编辑器,只需几行代码就能创建音效和背景音乐。
以@xem的MiniSoundEditor为例,我可以从一些预定义的声音中进行选择,然后复制并粘贴 JavaScript。
我将这样做并将其复制并粘贴到块的末尾if (collides(sprite1, sprite2))
:
f = function(i){
var n=2e4;
if (i > n) return null;
var q = t(i,n);
i=i*0.7;
return (Math.pow(i*50,0.8)&66)?q:-q;
}
t=(i,n)=>(n-i)/n;
A=new AudioContext()
m=A.createBuffer(1,96e3,48e3)
b=m.getChannelData(0)
for(i=96e3;i--;)b[i]=f(i)
s=A.createBufferSource()
s.buffer=m
s.connect(A.destination)
s.start()
我完全不知道这段代码是干什么的,但复制粘贴之后感觉自己更聪明了。你也会的。试着把它(或者你自己的声音)复制粘贴到碰撞检测代码的末尾。
⚠️ 显然,如果你不知道代码的作用,就不要盲目地从网上复制粘贴和使用。值得庆幸的是,这样做是无害的。
现在,你的代码应该看起来有点像这样:
<!DOCTYPE html>
<html>
<head>
</head>
<body>
<canvas width="250" height="250" id="game" style="background-color: black;"></canvas>
</body>
<script src="https://cdn.jsdelivr.net/npm/kontra@7.1.3/kontra.min.js"></script>
<script>
let { GameLoop, Sprite, bindKeys, collides, init, initKeys, keyPressed, randInt } = kontra;
let { canvas } = init();
let maxX = 250;
let maxY = 250;
let image1 = new Image();
image1.src = 'https://avatars.githubusercontent.com/u/121322?s=10'
image1.width = 40;
image1.height = 40;
let sprite1 = Sprite({
x: 40,
y: 40,
anchor: {
x: 0.5,
y: 0.5
},
image: image1
});
let image2 = new Image();
image2.src = 'https://avatars.githubusercontent.com/u/36594527?s=10'
image2.width = 40;
image2.height = 40;
let sprite2 = Sprite({
x: randInt(0, maxX),
y: randInt(0, maxY),
anchor: {
x: 0.5,
y: 0.5
},
image: image2
});
let loop = GameLoop({
update: function() {
if (keyPressed('left')) {
sprite1.x = sprite1.x - 1;
}
if (keyPressed('right')) {
sprite1.x = sprite1.x + 1;
}
if (keyPressed('up')) {
sprite1.y = sprite1.y - 1;
}
if (keyPressed('down')) {
sprite1.y = sprite1.y + 1;
}
if (collides(sprite1, sprite2)) {
sprite2.x = randInt(41, maxX - 40);
sprite2.y = randInt(41, maxY - 40);
f = function(i) {
var n = 1e4;
var c = n / 3;
if (i > n) return null;
var q = Math.pow(t(i, n), 2.1);
return (Math.pow(i, 3) & (i < c ? 16 : 99)) ? q : -q;
}
t = (i, n) => (n - i) / n;
A = new AudioContext()
m = A.createBuffer(1, 96e3, 48e3)
b = m.getChannelData(0)
for (i = 96e3; i--;) b[i] = f(i)
s = A.createBufferSource()
s.buffer = m
s.connect(A.destination)
s.start()
}
},
render: function() {
sprite1.render();
sprite2.render();
}
});
initKeys();
loop.start();
</script>
</html>
它在您的浏览器中看起来应该有点像这样:
此 GIF 中的声音似乎不起作用,但每次精灵接触时你都应该听到哔声。
就是这样。这款游戏将提供
小时尽享欢乐时光。敬请关注 Steam 的完整版本。
更进一步
如果你查看文件大小,你会发现它比 13kB 稍大一点:
$ ls -lth
total 88
-rw-r--r--@ 1 leereilly staff 28K Aug 13 09:50 kontra.min.js
-rw-r--r--@ 1 leereilly staff 674B Aug 13 09:49 mishmanners.jpeg
-rw-r--r--@ 1 leereilly staff 679B Aug 13 09:48 leereilly.jpeg
-rw-r--r--@ 1 leereilly staff 2.2K Aug 13 08:07 index.html
我们使用的是 Kontra 的精简版,但其中仍然包含一些我们不需要的内容。有关进一步缩减文件大小的详细信息,请参阅 Kontra 网站。
加入 JS13K!!!
欢迎随意 fork 并扩展此内容,用于您自己的 JS13K 条目。还有很多地方可以改进……
- 使其成为双人游戏(玩家 2 可以回应W A S D)?
- 添加对高分的支持?
- 再介绍一些音效吗?
- 添加一些实际的游戏玩法 LOL
更好的是,从零开始,享受乐趣。以下是一些可能有用的资源:
祝你好运,玩得开心!期待看到你在下方评论区分享你的作品。<3
故障排除
你在学习本教程的过程中遇到过一些 bug 吗?如果你以前从未使用过Chrome 开发者控制台,那么它就是你的好帮手。
按⌘+ Option+ J(macOS) 或Control+ Shift+ J(Windows、Linux、Chrome OS) 直接进入控制台面板。从那里你可以看到哪些功能运行不正常……
如果您感觉自己像 L337 H4X0R 正在运行curl
或jq
发出命令,您会感觉自己现在就在矩阵中,可以在其中做各种事情。
您还可以查看此repo 的完整源代码。查看提交历史记录,您将看到上述每个步骤的差异/代码。
鏂囩珷鏉ユ簮锛�https://dev.to/github/build-a-tiny-game-for-js13k-with-kontra-js-8pb