1 目的
使用Replit.com的Kaboom库实现贪食蛇。
2 修复Demo的错误
修复Replit.com案例代码中的碰撞事件错误。
主要修改了 area() 的参数,官方案例代码中的 area()无参数,会导致 snake 的身体块儿自己与自己接触也属于碰撞。
3 总结
3.1 Kaboom
Kaboom库文档非常的简陋,但是作为框架十分易用和简单。
3.2 Replit
Replit十分好用,国内CSDN的inscode有可能就是抄袭的它。 可以免费在线创建 Python、PHP、Java项目,拥有免费数据库、免费存储。 国内还不是很流行,这也好,不然过不多久就要被墙了。
4 游戏实现简要说明
4.1 蛇身体的变化
贪食蛇全网各个语言的版本都有,但是对蛇身体的实现方式有两种。
4.1.1 尾移到头
尾部节点移动到新头部节点位置。
4.1.2 加头去尾
直接创建新头部,移除尾部。
建议用第二种方案,下面代码也是采用第二种方案。
5 运行效果
点击 fcck--hiqilei.repl.co/ 可以试玩。
6 关键源代码
import kaboom from "kaboom"
import "kaboom/global"
kaboom();
const block_size = 20;
const block_margin = 2;
const map = addLevel(
[
"==============",
"= = ",
"= = ",
"= = ",
"= = ",
"= = ",
"= = ",
"= = ",
"= = ",
"= = ",
"= = ",
"= = ",
"= = ",
"==============",
],
{
tileWidth: block_size,
tileHeight: block_size,
pos: vec2(0, 0),
tiles: {
"=": () => [rect(block_size, block_size), color(255, 0, 0), area(), "wall"],
}
}
);
const directions = {
UP: "up",
DOWN: "down",
LEFT: "left",
RIGHT: "right",
};
let current_direction = directions.RIGHT;
let run_action = false;
let snake_length = 3;
let snake_body = [];
function respawn_snake() {
destroyAll("snake");
snake_body = [];
snake_length = 3;
for (let i = 1; i <= snake_length; i++) {
let segment = add([
rect(block_size, block_size),
pos(block_size, block_size * i),
color(0, 0, 255),
// 主要是改动了这些,缩小了蛇身体的碰撞区域
area({ shape: new Rect(vec2(0+block_margin), block_size-2*block_margin, block_size-2*block_margin) }),
"snake",
]);
snake_body.push(segment);
}
current_direction = directions.RIGHT;
}
function respawn_all() {
run_action = false;
wait(0.5, function() {
respawn_snake();
respawn_food();
run_action = true;
});
}
respawn_all();
onKeyPress("up", () => {
if (current_direction != directions.DOWN) {
current_direction = directions.UP;
}
});
onKeyPress("down", () => {
if (current_direction != directions.UP) {
current_direction = directions.DOWN;
}
});
onKeyPress("left", () => {
if (current_direction != directions.RIGHT) {
current_direction = directions.LEFT;
}
});
onKeyPress("right", () => {
if (current_direction != directions.LEFT) {
current_direction = directions.RIGHT;
}
});
let move_delay = 0.2;
let timer = 0;
onUpdate(() => {
if (!run_action) return;
timer += dt();
if (timer < move_delay) return;
timer = 0;
let move_x = 0;
let move_y = 0;
switch (current_direction) {
case directions.DOWN:
move_x = 0;
move_y = block_size;
break;
case directions.UP:
move_x = 0;
move_y = -1 * block_size;
break;
case directions.LEFT:
move_x = -1 * block_size;
move_y = 0;
break;
case directions.RIGHT:
move_x = block_size;
move_y = 0;
break;
}
// Get the last element (the snake head)
let snake_head = snake_body[snake_body.length - 1];
snake_body.push(
add([
rect(block_size, block_size),
pos(snake_head.pos.x + move_x, snake_head.pos.y + move_y),
color(0, 0, 255),
// 主要是改动了这些,缩小了蛇身体的碰撞区域
area({ shape: new Rect(vec2(0+block_margin), block_size-2*block_margin, block_size-2*block_margin) }),
"snake",
])
);
if (snake_body.length > snake_length) {
let tail = snake_body.shift(); // Remove the last of the tail
destroy(tail);
}
});
let food = null;
function respawn_food() {
let new_pos = rand(vec2(1, 1), vec2(13, 13));
new_pos.x = Math.floor(new_pos.x);
new_pos.y = Math.floor(new_pos.y);
new_pos = new_pos.scale(block_size);
if (food) {
destroy(food);
}
food = add([
rect(block_size, block_size),
color(0, 255, 0),
pos(new_pos),
area({ shape: new Rect(vec2(0+block_margin), block_size-2*block_margin, block_size-2*block_margin) }),
"food",
]);
}
onCollide("snake", "food", (s, f) => {
snake_length++;
respawn_food();
});
onCollide("snake", "wall", (s, w) => {
run_action = false;
shake(12);
respawn_all();
});
onCollide("snake", "snake", (s, t) => {
run_action = false;
shake(12);
respawn_all();
});