1200字范文,内容丰富有趣,写作的好帮手!
1200字范文 > 使用React实现井字棋小游戏

使用React实现井字棋小游戏

时间:2022-07-31 02:54:45

相关推荐

使用React实现井字棋小游戏

使用React实现井字棋小游戏

按照React官方教程来实现一个井字棋小游戏并完善其他功能,这里主要讲怎么完善这些功能 在游戏历史记录列表显示每一步棋的坐标,格式为 (列号, 行号)。在历史记录列表中加粗显示当前选择的项目。使用两个循环来渲染出棋盘的格子,而不是在代码里写死(hardcode)。添加一个可以升序或降序显示历史记录的按钮。每当有人获胜时,高亮显示连成一线的 3 颗棋子。当无人获胜时,显示一个平局的消息。 点击此处获取React官方井字棋小游戏源码———官方代码.点击此处获取已完善的井字棋的源码———已完善代码.

1.添加坐标功能

在state的history中添加coordinate

this.state = {// square: Array(9).fill(null),xIsNext: true,history: [{square: Array(9).fill(null),coordinate: 0}],stepNumber: 0,order: false}

点击时根据index添加坐标信息

handleClick(i) {let history = this.state.history.slice(0, this.state.stepNumber + 1);let current = history[history.length - 1]let square = current.square.slice();//如果存在获胜者或此棋格已有值,则返回if (calculateWinner(square) || square[i]) {return;}//根据xIsNext判断值为X或0square[i] = this.state.xIsNext ? "X" : "O";//计算此步的x坐标let x = Math.floor(i / 3) + 1//计算此步的y坐标let y = i % 3 + 1//生成坐标信息let coordinate = square[i] + '(' + x + ',' + y + ')'this.setState({history: history.concat([{square: square,coordinate: coordinate}]),stepNumber: history.length,xIsNext: !this.state.xIsNext});}

渲染时渲染坐标

const moves = history.map((step, index) => {const desc = index ?'Go to move : ' + step.coordinate :'Go to game start';return (<li key={index}><button onClick={() => this.jumpTo(index)} className='btn' {desc}</button></li>);});

效果图:

2.加粗显示当前选择的项目

根据stepNumber判断按钮是否对应当前项目,对应的话加入相应的样式

const moves = history.map((step, index) => {const desc = index ?'Go to move : ' + step.coordinate :'Go to game start';let light = {color: 'rgb(158, 147, 147)'};if(index === this.state.stepNumber){if(winner){light={color: 'red'}}else{light={color: '#000'}}}return (<li key={index}><button onClick={() => this.jumpTo(index)} className='btn' style={light}>{desc}</button></li>);});

效果图:

3.使用两个循环来渲染出棋盘的格子

通过两个for循环来生成3X3表格

const SquareRow = []for (let i = 0; i < 3; i++) {let str = [];//两重循环遍历出棋盘for (let j = 0; j < 3; j++) {let light = false;if (this.props.winnnerStep.indexOf(i * 3 + j) != -1) {light = true;} else {light = false;}str.push(<Squarevalue={this.props.square[i * 3 + j]}key={i * 3 + j}onClick={() => this.props.handleClick(i * 3 + j)}light={light}/>)}let square = <div className="board-row">{str}</div>SquareRow.push(square)}let showSquare = SquareRow.map((item, index) => {return <div key={index}>{item}</div>})return (<div><div>{showSquare}</div><div><button onClick={() => this.props.reSetClick()} className='reset_btn'>重置</button></div></div>);

4.添加一个可以升序或降序显示历史记录的按钮

添加一个state:order,(order为false时为正序,true时为倒序)

this.state = {xIsNext: true,history: [{square: Array(9).fill(null),coordinate: 0}],stepNumber: 0,order: false}

渲染按钮列表时判断order的值,并根据值渲染按钮列表和标题箭头

let order = this.state.order ? '▲' : '▼'const moves = history.map((step, index) => {const desc = index ?'Go to move : ' + step.coordinate :'Go to game start';return (<li key={index}><button onClick={() => this.jumpTo(index)} className='btn'>{desc}</button></li>);});if (this.state.order) {moves.reverse()}return (<div className="game"><div className="game-board"><Boardsquare={current.square}handleClick={this.handleClick.bind(this)}winnnerStep={winnerStep} reSetClick={this.reSetClick.bind(this)}/></div><div className="game-info"><div onClick={this.changeOrder.bind(this)}><div className='status'>{status}</div><div className='order'>{order}</div></div><ul>{moves}</ul></div></div>);

效果图:

5.每当有人获胜时,高亮显示连成一线的 3 颗棋子

获胜时获取3连棋子的位置(step)

function calculateWinner(squares) {const lines = [[0, 1, 2],[3, 4, 5],[6, 7, 8],[0, 3, 6],[1, 4, 7],[2, 5, 8],[0, 4, 8],[2, 4, 6]];for (let i = 0; i < lines.length; i++) {const [a, b, c] = lines[i];if (squares[a] && squares[a] === squares[b] && squares[a] === squares[c]) {//返回获胜的value和三连棋子的位置return {user: squares[a], step: [a, b, c] };}}return null;}

将step传给子组件

let history = this.state.history;let current = history[this.state.stepNumber];let winner = calculateWinner(current.square);//初始化获胜者获胜步的位置数组let winnerStep = [] if (winner) {status = '获胜者:' + winner.user;//将连成一线的 3 颗棋子的位置放入数组winnerStep = winner.step}<Boardsquare={current.square}handleClick={this.handleClick.bind(this)}winnnerStep={winnerStep} reSetClick={this.reSetClick.bind(this)}/>

在循环渲染棋盘时判断当前棋子是否在3连棋子数组内

if (this.props.winnnerStep.indexOf(i * 3 + j) != -1) {light = true;} else {light = false;}str.push(<Squarevalue={this.props.square[i * 3 + j]}key={i * 3 + j}onClick={() => this.props.handleClick(i * 3 + j)}light={light}/>)

效果图:

6.当无人获胜时,显示一个平局的消息

渲染时判断棋盘是否已满,如果已满则将status改为平局

//设置标量标记棋盘是否已满let flag = true;//遍历判断棋盘是否已满for (let i = 0; i < current.square.length; i++) {if (current.square[i] === null) {flag = false;}}//初始化状态信息(显示对局情况)let status;if (winner) {status = '获胜者:' + winner.user;//将连成一线的 3 颗棋子的位置放入数组winnerStep = winner.step} else {if(flag){status = '平局'}else{status = "下一位选手: " + (this.state.xIsNext ? "X" : "O");} }

效果图:

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。