第一個簡單的Dapp-猜拳遊戲。本智慧合約的功能很簡單,就是使用者與電腦猜拳,使用者選擇出手後,電腦隨機一個選項,然後呼叫智慧合約方法把兩個選項值傳過去,在智慧合約上進行比較,並通過區塊鏈合約事件廣播結果,本地監聽事件拿到結果後展示猜拳結果。
先大體宣告下幾個環境跟工具:
1、沒有用truffle,直接MetaMask連結以太坊Ropsten測試鏈後,用Remix部署合約程式碼
2、前端用web3.js(1.6.1版本)
下面分成幾步詳細說明:
一、從Ropsten上獲取eth
因為呼叫合約需要消耗eth,所以要先在Ropsten測試網上獲取eth,可以複製自己的錢包地址後在這個網站上獲取:https://faucet.ropsten.be/ 獲取過程可能會有延時,多點幾次就好。
二、編寫猜拳智慧合約
Remix上新建GuessGame.sol檔案,並寫入以下內容:
// SPDX-License-Identifier: MIT pragma solidity >=0.4.22 <0.9.0; contract GuessGame { event GuessResult(uint playerChoice,uint computerChoice,uint result); function play(uint playerChoice,uint computerChoice) public returns (bool){ if(playerChoice > 0 && playerChoice <=3 && computerChoice > 0 && computerChoice <=3){ if(playerChoice == computerChoice){ //平手 emit GuessResult(playerChoice,computerChoice,1); }else if(playerChoice == (computerChoice + 1) % 3){ //電腦贏了 emit GuessResult(playerChoice,computerChoice,2); }else{ //其餘都算玩家贏了 emit GuessResult(playerChoice,computerChoice,3); } return true; }else{ return false; } } }
編譯後部署到Ropsten上,當然首先到MetaMask連上Ropsten網路,並且賬戶上有足夠的eth
部署成功後,這裡其實就顯示了智慧合約上的play方法了,可以直接在這裡傳值點選transact進行呼叫,呼叫成功後再控制檯會輸出結果,點選Debug可以檢視詳細資訊
三、前端用web3.js呼叫智慧合約
我後臺因為整合了專案,所以是用jsp寫的,大家簡單點可以直接寫Html,先貼下檔案目錄結構:
1、複製ABI檔案:在Remix上點選複製ABI檔案內容,並新建GuessGame.json檔案,將複製的abi內容貼進去
2、引入web3.js等其它js
3、編寫guessGame.jsp檔案:
<%-- Created by IntelliJ IDEA. User: **** Date: 2021/12/13 Time: 21:35 To change this template use File | Settings | File Templates. --%> <%@ page contentType="text/html;charset=UTF-8" language="java" pageEncoding="UTF-8" isELIgnored="false" %> <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%> <html> <head> <meta charset="utf-8"> <meta http-equiv="Access-Control-Allow-Origin" content="*" > <c:set var="ctx" value="${pageContext.request.contextPath}" /> <script type="text/javascript" src="${ctx}/resource/js/jquery-1.9.1.min.js" charset="utf-8"></script> <script type="text/javascript" src="${ctx}/resource/js/web3.min-1.6.1.js"></script> <title>猜拳遊戲</title> <style> *{margin:0; padding: 0; font-weight: 200;} .player,.computer{ width: 50%; float: left; padding-top: 30px; text-align: center } .player,.computer dt{ font-size: 28px; } .player img,.computer img{ margin-top: 30px; width: 30%; } .player img{ transform:rotateY(180deg); } .select{ text-align: center; font-size: 18px; max-width: 800px; margin: 0 auto; padding-top: 2%; } .select dt{ width: 100%; overflow: hidden; line-height: 50px; } .select button{ width: 20%; border:none; color: #fff; border-radius: 8px; line-height: 45px; margin: 0 5%; outline: none; font-size: 18px; cursor: pointer; } #info{ width: 100%; text-align: center; overflow: hidden; font-size: 25px; line-height: 50px; color: red; padding-top: 2%; opacity: 0; } </style> <script type="text/javascript"> var web3,guessGameABI,guessGameContract,refresh_timer; $(function(){ web3Auth(); jspFun(); //var version = web3.version; //console.log(version); //web3.eth.net.getNetworkType().then(console.log); web3.eth.getAccounts(console.log); $.getJSON('/resource/abi/GuessGame.json',function(data){ guessGameABI = data; //建立合約例項 guessGameContract = new web3.eth.Contract(guessGameABI, '0x85daAd7dbB5Ba1B4020444Ab2f1D84c58d409edF', []); console.log(guessGameContract.defaultAccount); console.log(guessGameContract.defaultBlock); listenEvent(); }); }) function listenEvent(){ guessGameContract.events.GuessResult({ //filter: {myIndexedParam: [20,23], myOtherIndexedParam: '0x123456789...'}, // 使用陣列表示 或:如 20 或 23。 //fromBlock: 0 }, function(error, event){ console.log(event); }).on("connected", function(subscriptionId){ console.log(subscriptionId); }).on('data', function(event){ console.log(event); // 與上述可選的回撥結果相同 //uint playerChoice,uint computerChoice,uint result resultDeal(event.returnValues.playerChoice,event.returnValues.computerChoice,event.returnValues.result); }).on('changed', function(event){ // 從本地資料庫中刪除事件 console.log("事件刪除"); }).on('error', function(error, receipt) { // 如果交易被網路拒絕並帶有交易收據,第二個引數將是交易收據。 console.log("事件被網路拒絕"); }); } function resultDeal(player_choice,computer_choice,r){ //var r = result.args.result.toNumber(); var info = "未知"; if(r == 1){ info = "平手"; }else if(r == 2){ info = "你輸了"; }else if(r == 3){ info = "你贏了"; } update_page(player_choice, computer_choice, info); } function update_page(player,computer,result){ console.log(player+"----"+computer+"-----"+result); var info = document.getElementById('info'); var playerImg = document.getElementById('player'); var comImg = document.getElementById('computer'); info.style.opacity = '0'; clearInterval(refresh_timer); playerImg.src = '/resource/images/'+player+'.png'; comImg.src = '/resource/images/'+computer+'.png'; info.style.opacity = 1; info.innerText = result; } function guess(player_choice){ //web3.eth.getCoinbase().then(console.log); //1:剪刀 2:石頭 3:布 var result; player_choice = parseInt(player_choice); computer_choice = parseInt(Math.random()*3)+1; document.getElementById('info').innerText = ''; guessGameContract.methods.play(player_choice,computer_choice).send({ from: '0x229Ea411D368C97b008c7bc19B01Fdd813163701' }).on('transactionHash', function(hash){ console.log(hash); beginGame(); }).on('confirmation', function(confirmationNumber, receipt){ console.log(confirmationNumber); console.log(receipt); }).on('receipt', function(receipt) { // receipt 相關例子 console.log(receipt); }).on('error', function(error, receipt) { // 如果交易被網路拒絕並帶有交易收據,則第二個引數將是交易收據。 console.log(error); console.log(receipt); }); } function beginGame(){ var playerImg = document.getElementById('player'); var comImg = document.getElementById('computer'); refresh_timer = setInterval(function(){ this.n?this.n:this.n=1;this.n++ this.n>3?this.n=1:this.n; playerImg.src = '/resource/images/'+this.n+'.png'; comImg.src = '/resource/images/'+this.n+'.png'; },100); } function jspFun(){ choices = $('button'); for(var i=0; i<choices.length; i++){ choices[i].onclick = function(){ guess(this.value); } } } function web3Auth(){ //初始化過程 //var Web3 = require('web3'); if (typeof web3 !== 'undefined') { console.info("init web3"); web3 = new Web3(web3.currentProvider); } else { console.info("init new web3"); // set the provider you want from Web3.providers web3 = new Web3(new Web3.providers.HttpProvider("http://localhost:8545")); } } </script> </head> <body> <div class="computer"> <dl> <dt>對手</dt> <dd><img src="${ctx}/resource/images/2.png" id="computer" alt=""></dd> </dl> </div> <div class="player"> <dl> <dt>你</dt> <dd><img src="${ctx}/resource/images/2.png" id="player" alt=""></dd> </dl> </div> <div id="info">平手</div> <div class="select"> <dl> <dt>點選下列圖示選擇要出的選項:</dt> <dd> <button value="1"><img src='${ctx}/resource/images/1.png' style="width:80px"></button> <button value="2"><img src='${ctx}/resource/images/2.png' style="width:80px"></button> <button value="3"><img src='${ctx}/resource/images/3.png' style="width:80px"></button> </dd> </dl> </div> </body> </html>
詳細內容參考web3文件看吧,我也是參考文件一點點寫的,文件地址:https://learnblockchain.cn/docs/web3.js/
四、執行結果示例:
如果有學習計劃的童鞋,可以加我QQ一起交流: