}
class App extends Component {
state = initState;
render() {
return (
);
}
}
export default App;
把snake-dot的动态生成放到子组件Snake.js中:
import React from ‘react’
export const Snake = ({snakeDots}) => {
return (
<>
{
snakeDots.map((dot, index)=>{
let dotStyle = {
left:${dot[0]}%
,
top:${dot[1]}%
}
console.log(dotStyle)
return (
)
})
}
</>
)
}
这样初始化就完成了
贪吃蛇的上下左右移动根据键盘输入的上下左右(↑↓←→)键来确定,初始化时默认是向右移动的
先来看看键盘上下左右键的code值
| Key | Code |
| — | — |
| 左箭头 | 37 |
| 右箭头 | 39 |
| 上箭头 | 38 |
| 下箭头 | 40 |
游戏开始时,默认是向右走的,因此,我们增加一个表示方向的state:direction,走的速度是每隔200ms前进一步
const initState = {
snakeDots: [
[0, 0],
[2, 0]
],
direction: “RIGHT”,
speed: 200
}
当检测到上下左右键按下时,更新state中的方向,贪吃蛇沿该方向前进一步;
若没有按键按下,就沿着当前方向一路前进
贪吃蛇的头部(head)是小黑方块的最后一块,不断地删去第一个小黑方块并在direction方向上新增一小黑方块;视觉上,贪吃蛇就有不停向前移动的效果
componentDidMount() {
// 监听键盘按下事件
document.onkeydown = this.onkeydown;
// 每隔200ms前进一步
setInterval(this.onMove, this.state.speed);
}
onkeydown = (e) => {
// 根据按下的键盘键更新direction
switch (e.keyCode) {
case 37:
this.setState({ direction: “LEFT” });
break;
case 38:
this.setState({ direction: “UP” });
break;
case 39:
this.setState({ direction: “RIGHT” });
break;
case 40:
this.setState({ direction: “DOWN” });
break;
default:
this.setState({ direction: “RIGHT” });
}
}
onMove = () => {
// 根据direction指示的方向前进
let newSnakeDots = […this.state.snakeDots];
let header = newSnakeDots[newSnakeDots.length - 1];
switch (this.state.direction) {
case “UP”:
header = [header[0], header[1] - 2];
break;
case “DOWN”:
header = [header[0], header[1] + 2];
break;
case “LEFT”:
header = [header[0] - 2, header[1]];
break;
case “RIGHT”:
header = [header[0] + 2, header[1]];
break;
default:
header = [header[0] + 2, header[1]];
}
// 删去第一个小黑块,并在direction方向上新增新小黑块,更新snakeDots
newSnakeDots.shift();
newSnakeDots.push(header);
this.setState({ snakeDots: newSnakeDots })
}
效果:
当触碰边界或者撞击到自身时,游戏结束,弹窗提示,分数为贪吃蛇的长度-2(初始长度为2,其余均是吃到食物后变长的,吃一个食物长长1格)
componentDidUpdate() {
this.checkIfBordered();
}
checkIfBordered = () => {
let newSnakeDots = […this.state.snakeDots];
let header = newSnakeDots[newSnakeDots.length - 1];
if (header[0] < 0 || header[0] > 98 || header[1] < 0 || header[1] > 98) {
alert(触碰边界,游戏结束,你的得分是:${newSnakeDots.length - 2}
);
this.setState(initState);
}
}
由于我们规定,贪吃蛇触碰到边界时算游戏结束,因此,食物不能出现在边界上,否则,一吃到食物就代表触壁结束游戏(可以改进为:贪吃蛇每次前进1%,当食物被触碰比例达50%时可以当作贪吃蛇吃掉该食物,马上掉头避免触壁,以后再改吧~)
因此,食物出现的范围在top:2%~96%,left的范围也是如此
const getRandomFood = ()=>{
// 食物出现的范围是:[2, 96] 推算过程:[0,95)->[2, 97)->[1, 48.5]->[1,48]->[2,96]
let max = 95;
let min = 2;
let x = Math.floor((Math.random() * max + min) / 2) * 2;
let y = Math.floor((Math.random() * max + min) / 2) * 2;
return [x,y]
}
const initState = {
snakeDots: [
[0, 0],
[2, 0]
],
direction: “RIGHT”,
speed: 200,
food:getRandomFood() // 随机生成食物的位置
}
食物的展示:
import { Food } from ‘./components/Food’;
render() {
return (
);
}
import React from ‘react’
export const Food = ({food}) => {
let foodStyle = {
left:${food[0]}%
,
top:${food[1]}%
}
return (
)
}
食物的样式:
.food {
height: 2%;
width: 2%;
background-color: red;
border: 1px solid #fff;
position: absolute;
}
贪吃蛇的头(head)和食物重叠时,代表吃到
贪吃蛇变长,食物的位置变成新的head,重新放置食物
componentDidUpdate() {
// 每次更新都判断一下
this.checkIfBordered();
this.checkIfEated();
}
checkIfEated = ()=>{
let newSnakeDots = […this.state.snakeDots];
let header = newSnakeDots[newSnakeDots.length - 1];
// head与食物重叠时,代表吃到食物
if(header[0]==this.state.food[0] && header[1]==this.state.food[1]){
console.log(“吃到了”)
newSnakeDots.unshift([]);
this.setState({snakeDots:newSnakeDots});
this.setState({food:getRandomFood()});
}
}
效果:
完整代码:
新建文件夹component存放组件:
App.js
import React, { Component } from ‘react’
import { Snake } from ‘./components/Snake’;
import { Food } from ‘./components/Food’;
// 随机获取食物位置
const getRandomFood = ()=>{
// [2, 96]: [0,95)->[2, 97)->[1, 48.5]->[1,48]->[2,96]
let max = 95;
let min = 2;
let x = Math.floor((Math.random() * max + min) / 2) * 2;
let y = Math.floor((Math.random() * max + min) / 2) * 2;
console.log(“food-position”,x,y)
return [x,y]
}
// 另存state以便重新初始化
const initState = {
snakeDots: [
[0, 0],
[2, 0]
],
direction: “RIGHT”,
speed: 200,
food:getRandomFood()
}
class App extends Component {
state = initState;
// 监听与计时器
componentDidMount() {
document.onkeydown = this.onkeydown;
setInterval(this.onMove, this.state.speed);
}
// 更新时检测是否出界或吃到食物
componentDidUpdate() {
this.checkIfBordered();
this.checkIfEated();
}
// 判断键盘按键,更新direction
onkeydown = (e) => {
switch (e.keyCode) {
case 37:
this.setState({ direction: “LEFT” });
break;
case 38:
this.setState({ direction: “UP” });
break;
case 39:
this.setState({ direction: “RIGHT” });
break;
case 40:
this.setState({ direction: “DOWN” });
break;
default:
this.setState({ direction: “RIGHT” });
}
}
// 根据direction移动
onMove = () => {
let newSnakeDots = […this.state.snakeDots];
let header = newSnakeDots[newSnakeDots.length - 1];
switch (this.state.direction) {
case “UP”:
header = [header[0], header[1] - 2];
break;
case “DOWN”:
header = [header[0], header[1] + 2];
break;
case “LEFT”:
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。
深知大多数前端工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!
因此收集整理了一份《2024年Web前端开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上前端开发知识点,真正体系化!
由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!
如果你觉得这些内容对你有帮助,可以扫码获取!!(备注:前端)
核心竞争力,怎么才能提高呢?
成年人想要改变生活,逆转状态?那就开始学习吧~
万事开头难,但是程序员这一条路坚持几年后发展空间还是非常大的,一切重在坚持。
为了帮助大家更好更高效的准备面试,特别整理了《前端工程师面试手册》电子稿文件。
前端面试题汇总
JavaScript
性能
linux
前端资料汇总
完整版PDF资料免费分享,只需你点赞支持,动动手指点击此处就可免费领取了。
前端工程师岗位缺口一直很大,符合岗位要求的人越来越少,所以学习前端的小伙伴要注意了,一定要把技能学到扎实,做有含金量的项目,这样在找工作的时候无论遇到什么情况,问题都不会大。
48fd0fcb265f3401a21603bda2b.png)
前端面试题汇总
JavaScript
性能
linux
前端资料汇总
完整版PDF资料免费分享,只需你点赞支持,动动手指点击此处就可免费领取了。
前端工程师岗位缺口一直很大,符合岗位要求的人越来越少,所以学习前端的小伙伴要注意了,一定要把技能学到扎实,做有含金量的项目,这样在找工作的时候无论遇到什么情况,问题都不会大。