之前看别人写小游戏觉得很厉害,正好最近闲来无聊,就写了个入门级的小游戏,贪吃蛇。
当你开始实现的时候,会发现其实并没有你想的那么难。下面进入正题。
项目源码见:https://github.com/Eveveen/react-snake
1. 首先画出背景
2. 然后初始化初始蛇的位置,蛇为黑色,食物为红色
renderBackground() { // 其中 size = {row: 20, col: 20}
let trs = [];
for (let i = 0; i < size.row; i++) {
let tds = [];
for (let j = 0; j < size.col; j++) {
let value = this.getSnack(i, j);
if (value === 0) { // 空白
// 这里的key只是为了使这个td唯一
tds.push(<td key={i * 200 + j}></td>);
} else if (value === 1) { // 有蛇,黑色
tds.push(<td key={i * 100 + j}>{black}</td>)
} else if (value === 2) { // 食物,红色
tds.push(<td key={i * 5 + j}>{red}</td>)
}
}
trs.push(<tr key={i}>{tds}</tr>)
}
return <tbody>{trs}</tbody>;
}
// 获取在方块中蛇以及食物的显示
getSnack = (c, r) => {
const { snake, food } = this.state;
for (let s in snake) {
// 如果这个点是蛇,则返回1
if (snake[s].x === c && snake[s].y === r) {
return 1;
}
// 如果这个点是食物,则返回2
if (food.x === c && food.y === r) {
return 2;
}
}
// 如果这个点什么都不是返回0
return 0;
}
3. 蛇可以定时移动
// 定时自己移动
timer = () => {
let interval = setInterval(function () {
this.move(this.state.dir);
}.bind(this), 600);
this.setState({ interval, status: 'start' })
}
4. 通过键盘控制蛇的移动
componentDidMount() {
// 键盘点击事件
document.onkeydown = function (event) {
var e = event || window.event;
var keyCode = e.keyCode;
if (keyCode === 37 || keyCode === 65) { // left a
this.move(direction.left);
this.setState({ dir: direction.left })
} else if (keyCode === 38 || keyCode === 87) { // up w
this.move(direction.up);
this.setState({ dir: direction.up })
} else if (keyCode === 39 || keyCode === 68) { //right d
this.move(direction.right);
this.setState({ dir: direction.right })
} else if (keyCode === 40 || keyCode === 83) { // down s
this.move(direction.down);
this.setState({ dir: direction.down })
}
}.bind(this);
// 初次渲染的时候开启定时
this.timer();
}
5. 蛇吃完食物变长,继续行走,蛇头撞到自己失败,重新开始
6. 蛇的每个部分统一行走,转换方向时,后一个按照前一个的轨迹进行行走
7. 超过边界时,重新开始
move = (dir) => {
const { snake, food } = this.state;
let first = { x: snake[0].x, y: snake[0].y }
let last = {};
// move
if (dir === direction.up) {
first.x -= 1;
} else if (dir === direction.down) {
first.x += 1;
} else if (dir === direction.left) {
first.y -= 1;
} else if (dir === direction.right) {
first.y += 1;
}
// 撞到自己
let _snake = snake.filter(item => item.x === first.x && item.y === first.y)
if (first.y > size.col - 1 || first.y < 0 || first.x < 0 || first.x > size.row - 1 || _snake.length > 0) {
this.handleRestart();
return;
}
let eat = false;
// 吃到食物
if (first.x === food.x && first.y === food.y) {
eat = true;
last = { x: snake[snake.length - 1].x, y: snake[snake.length - 1].y }
this.showFood();
}
// 蛇整体动起来
for (let s in snake) {
var next_first = { x: snake[s].x, y: snake[s].y };
snake[s].x = first.x;
snake[s].y = first.y;
first = next_first;
}
// 吃到食物之后蛇变长
if (eat) {
snake[snake.length] = last
}
this.setState({ snake })
}
8. 暂停,游戏暂停,蛇不动
// 暂停
pause = () => {
let i = this.state.interval;
window.clearInterval(i); //清除定时器
this.setState({ status: 'pause' })
}
9. 开始,蛇继续行走
// 开始
handleStart = () => {
const { status } = this.state;
if (status === 'pause') {
this.timer(); // 重新开启定时器
}
}
10. 计分,每吃一个食物,则加一分
// 显示新的食物
showFood = () => {
let x = parseInt(Math.random() * size.row);
let y = parseInt(Math.random() * size.col);
if (this.getSnack() !== 0) {
x = parseInt(Math.random() * size.row);
y = parseInt(Math.random() * size.col);
}
//每次显示新的食物意味着吃了上一个食物,加1分
let score = this.state.score + 1;
this.setState({ food: { x: x, y: y }, score })
}
11. 重新开始,回到初始化状态
// 重新开始
handleRestart = () => {
let i = this.state.interval;
window.clearInterval(i);
this.setState({
snake: [{ x: 1, y: 1 }],
food: { x: 1, y: 4 },
dir: direction.right,
interval: 2,
status: 'start',
score: 0
})
this.timer()
}
12. 优化界面,对页面布局进行优化
好了,以上就是我的思路,源码可以见我的git项目,地址在文章开头