之前看別人寫小遊戲覺得很厲害,正好最近閒來無聊,就寫了個入門級的小遊戲,貪喫蛇。
當你開始實現的時候,會發現其實並沒有你想的那麼難。下面進入正題。
項目源碼見: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項目,地址在文章開頭