eth實戰專案遊戲開發 TICTACTOE 二
阿新 • • 發佈:2019-01-09
eth dapp,前端部分,使用使用truffle 框架,前端部分使用react,eht互動庫truffle-contract
合約部分請點選 https://blog.csdn.net/bondsui/article/details/85755186
github程式碼在文末
文章目錄
3 小白如何寫前端
github,全球最大的程式碼庫,你想要的基本都有。
3.1 github搜尋
TicTacToe,本例中使用react,直接搜尋 TicTacToe react,按照starts排序
3.2 clone buile 專案
➜ temp git clone [email protected]:trihargianto/reactjs-tictactoe.git
➜ temp cd reactjs-tictactoe
➜ npm install
➜ npm start
3.3 檢視效果和程式碼
效果圖,自帶動畫,重點檢視點選事件
render() {
const indexSquares = [0,1,2,3,4,5,6,7,8];
var squares = indexSquares.map(function(indexSquare, i) {
return (<Square
value={this.state.squares[i]}
key={i}
index={i}
winner={this.state.winner}
xIsNext={this.state.xIsNext}
onClick={this.handleOnClick.bind(this)} />)
},this)
return (
<div>
<h1 style={{textAlign: 'center', fontSize: '46px', color: 'rgba(52, 152, 219,1.0)'}} className="animated flipInY">Tic-Tac-Toe</h1>
<h3 style={{textAlign: 'center'}} id="titlePemenang">{this.state.winner !== null ? <span>Pemenangnya <b>{this.state.winner}</b></span> : ""}</h3>
<div className="container animated fadeInUp">
<div className="row">
<br />
<div className="col-xs-12">{squares}</div>
</div>
</div>
<br />
{this.state.winner !== null || this.state.full === true ? <ResetButton onClick={this.handleResetGame.bind(this)} /> : ""}
</div>
)
}
}
4 前端頁面編寫
4.1 頁面樣式
拷貝下載下來的git專案(別忘了css檔案一同拷貝),安裝包
"bootstrap": "^3.3.7",
"jquery": "^3.2.1",
"react": "^15.4.2",
"react-dom": "^15.4.2",
執行專案,檢視頁面
略
4.2 調整頁面
通過程式碼,得知,原頁面的棋盤的值為0-8,我們改為[[0, 0], [0, 1], [0, 2], [1, 0], [1, 1], [1, 2], [2, 0], [2, 1], [2, 2]],每個value即棋盤的座標。同時更改Square的handleClick,把值傳遞到頁面。
執行專案,點選第一個模組,顯示log 0,1
剩下的就是與合約互動。
class Board extends React.Component {
constructor() {
super();
this.state = {
squares : Array(9).fill(null),
xIsNext : true,
winner : null,
full : false
}
}
handleOnClick(index, turn) {
console.log(index,turn)
}
handleResetGame() {
window.location.reload()
}
render() {
const indexSquares = [[0, 0], [0, 1], [0, 2], [1, 0], [1, 1], [1, 2], [2, 0], [2, 1], [2, 2]];
var squares = indexSquares.map(function(indexSquare, i) {
return (<Square
value={this.state.squares[i]}
key={i}
index={i}
winner={this.state.winner}
xIsNext={this.state.xIsNext}
onClick={this.handleOnClick.bind(this)} />)
},this)
return (
<div>
<h1 style={{textAlign: 'center', fontSize: '46px', color: 'rgba(52, 152, 219,1.0)'}} className="animated flipInY">Tic-Tac-Toe</h1>
<h3 style={{textAlign: 'center'}} id="titlePemenang">{this.state.winner !== null ? <span>Pemenangnya <b>{this.state.winner}</b></span> : ""}</h3>
<div className="container animated fadeInUp">
<div className="row">
<br />
<div className="col-xs-12">{squares}</div>
</div>
</div>
<br />
{this.state.winner !== null || this.state.full === true ? <ResetButton onClick={this.handleResetGame.bind(this)} /> : ""}
</div>
)
}
}
4.3 下載專案引用包
"truffle-contract": "^3.0.7",
"web3": "^1.0.0-beta.37",
"xmlhttprequest": "^1.8.0"
4.4 搭建框架
補充頁面按鈕,更新square
import React from 'react'
import ReactDOM from 'react-dom'
import './index.css'
import 'bootstrap/dist/css/bootstrap.min.css'
import './animate.css'
import Square from './Square'
import MenuButtons from './MenuButtons'
import getWeb3 from "./utils/getWeb3"
import contract from 'truffle-contract'
import _TicTacToe from './contracts/TicTacToe.json'
// 棋盤值
const STONES = [[0, 0], [0, 1], [0, 2], [1, 0], [1, 1], [1, 2], [2, 0], [2, 1], [2, 2]];
const EMPTY_ADDRESS = "0x0000000000000000000000000000000000000000"
const GAME_COST = "1"; //1 eth
let web3 = null
class Board extends React.Component {
state = {
accounts: null, // 賬戶
// 棋盤相關
instance: null, // 遊戲例項
board: [['', '', ''], ['', '', ''], ['', '', '']],
player1: '', // 玩家一,等於建立者
player2: '', // 玩家二,
nextPlayer: '',// 該誰下棋
winner: '',
gameResult: '', // 遊戲結果,
}
// 獲取合約
getTicTacToe = () => {
let TicTacToe = contract(_TicTacToe)
TicTacToe.setProvider(web3.currentProvider);
return TicTacToe
}
componentDidMount = async () => {
try {
web3 = await getWeb3();
console.log("currentProvider", web3.currentProvider)
const accounts = await web3.eth.getAccounts();
console.log("accounts", accounts)
this.setState({accounts});
} catch (error) {
alert(`web3 載入失敗`,);
console.error(error);
}
}
componentWillUnmount() {
this.unRegistNextPlayerEvent()
}
// 點選建立遊戲
onCreateGameClick = () => {
console.log("建立遊戲")
}
// 加入遊戲
onJoinGameClick = async () => {
console.log("加入遊戲")
}
// 更新遊戲面板
updateBoard = () => {
console.log("更新面板")
}
// 設定棋盤
onStoneClick = (stone) => {
console.log("設定棋盤",stone)
}
// 重置遊戲
onResetGameClick = () => {
window.location.reload()
}
// 設定贏家
setWinner = (winner) => {
let gameResult = ""
if (winner === this.state.player1) {
gameResult = "恭喜勝利,再來一局"
} else if (winner === this.state.player2) {
gameResult = "失敗,再接再厲"
} else {
gameResult = "旗鼓相當,平局,再來一局"
}
this.setState({gameResult})
}
// 00 01 02
// 10 11 12
// 20 21 22
render() {
let {accounts, board, player1, player2, nextPlayer, instance, winner} = this.state
let gameAddress = instance == null ? "" : instance.address
console.log("state", this.state)
console.log("", instance)
if (winner != ''){
winner = winner == EMPTY_ADDRESS ? "平局,退回賭金" : "贏家為:"+winner
}
let squares = STONES.map((stone, i) => {
return (<Square
key={i}
stone={stone}
board={board}
account={accounts == null ? null : accounts[0]}
nextPlayer={nextPlayer}
onClick={this.onStoneClick}/>)
})
return (
<div style={{textAlign: 'center'}}>
{/*標題*/}
<h2 style={{fontSize: '42px', color: "red"}}
className="animated flipInY">性感荷官 線上發牌
</h2>
{/* 遊戲資訊展示*/}
<div>
<h5>當前使用者:{accounts == null ? "未檢測到" : accounts[0]}</h5>
<h5>遊戲地址:{gameAddress == "" ? "等待建立" : gameAddress}</h5>
<h5>player1:{player1 == "" ? "等待加入" : player1}</h5>
<h5>player2:{player2 == "" ? "等待加入" : player2}</h5>
<h5>nextPlayer:{player2 == "" ? "遊戲未開始" :
<span style={{color: "red"}}>{nextPlayer}</span>}</h5>
<h3 id="gameResult">
<span style={{fontSize: '32px', color: "red"}}>
<b>{winner}</b></span>
</h3>
</div>
{/*棋盤*/}
<div className="container animated fadeInUp">
<div className="row">
<div className="col-xs-12">{squares}</div>
</div>
</div>
<br/>
<MenuButtons
onCreateGameClick={this.onCreateGameClick}
onJoinGameClick={this.onJoinGameClick}
onResetGameClick={this.onResetGameClick}/>
</div>
)
}
}
ReactDOM.render(
<Board/>,
document.getElementById('root')
);
Square.js
es6語法普及,封包與解包
import React from 'react';
const EMPTY_ADDRESS = "0x0000000000000000000000000000000000000000"
export default class Square extends React.Component {
constructor(props) {
super(props)
// es6 語法
// 本頁面要設定狀態,使用者點選,提前顯示該位置內容,避免等待,如不需要否則可直接使用props或者無狀態元件
// 儲存所有屬性到狀態變數
this.state = {...props}
// 等價
// let {key,stone,board,account,nextPlayer,onClick}=props
// this.state = {key,stone,board,account,nextPlayer,onClick}
console.log(this.state)
}
componentWillReceiveProps(nextProps) {
this.state = {...nextProps}
}
// 狀態變數未Object,可以不寫預設值,
state = {}
// 點選事件
onItemClick(event) {
let errMsg = this.mustCheck()
if (errMsg != "") {
event.target.className += " animated shake";
alert(errMsg)
return
}
// 引用點選
this.state.onClick(this.state.stone);
// 設定 修改
event.target.className += " animated rubberBand square-container-active";
}
// 下棋校驗,返回錯誤資訊,沒有返回空
mustCheck() {
let {account, nextPlayer} = this.state
console.log(this.state)
if (this.state.account == null) {
return "使用者未登入"
}
if (nextPlayer == '') {
return "遊戲未開始"
}
if (account.toLowerCase() != nextPlayer.toLowerCase()) {
return "等待對方下子"