第一个简单的Dapp-猜拳游戏。本智能合约的功能很简单,就是用户与电脑猜拳,用户选择出手后,电脑随机一个选项,然后调用智能合约方法把两个选项值传过去,在智能合约上进行比较,并通过区块链合约事件广播结果,本地监听事件拿到结果后展示猜拳结果。

先大体声明下几个环境跟工具:

1、没有用truffle,直接MetaMask链接以太坊Ropsten测试链后,用Remix部署合约代码

2、前端用web3.js(1.6.1版本)

下面分成几步详细说明:

一、从Ropsten上获取eth

因为调用合约需要消耗eth,所以要先在Ropsten测试网上获取eth,可以复制自己的钱包地址后在这个网站上获取:https://faucet.ropsten.be/  获取过程可能会有延时,多点几次就好。

二、编写猜拳智能合约

Remix上新建GuessGame.sol文件,并写入以下内容:

  1. // SPDX-License-Identifier: MIT
  2. pragma solidity >=0.4.22 <0.9.0;
  3. contract GuessGame {
  4. event GuessResult(uint playerChoice,uint computerChoice,uint result);
  5. function play(uint playerChoice,uint computerChoice) public returns (bool){
  6. if(playerChoice > 0 && playerChoice <=3 && computerChoice > 0 && computerChoice <=3){
  7. if(playerChoice == computerChoice){
  8. //平手
  9. emit GuessResult(playerChoice,computerChoice,1);
  10. }else if(playerChoice == (computerChoice + 1) % 3){
  11. //电脑赢了
  12. emit GuessResult(playerChoice,computerChoice,2);
  13. }else{
  14. //其余都算玩家赢了
  15. emit GuessResult(playerChoice,computerChoice,3);
  16. }
  17. return true;
  18. }else{
  19. return false;
  20. }
  21. }
  22. }

编译后部署到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文件:

  1. <%--
  2. Created by IntelliJ IDEA.
  3. User: ****
  4. Date: 2021/12/13
  5. Time: 21:35
  6. To change this template use File | Settings | File Templates.
  7. --%>
  8. <%@ page contentType="text/html;charset=UTF-8" language="java" pageEncoding="UTF-8" isELIgnored="false" %>
  9. <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
  10. <html>
  11. <head>
  12. <meta charset="utf-8">
  13. <meta http-equiv="Access-Control-Allow-Origin" content="*" >
  14. <c:set var="ctx" value="${pageContext.request.contextPath}" />
  15. <script type="text/javascript" src="${ctx}/resource/js/jquery-1.9.1.min.js" charset="utf-8"></script>
  16. <script type="text/javascript" src="${ctx}/resource/js/web3.min-1.6.1.js"></script>
  17. <title>猜拳游戏</title>
  18. <style>
  19. *{margin:0; padding: 0; font-weight: 200;}
  20. .player,.computer{
  21. width: 50%;
  22. float: left;
  23. padding-top: 30px;
  24. text-align: center
  25. }
  26. .player,.computer dt{
  27. font-size: 28px;
  28. }
  29. .player img,.computer img{
  30. margin-top: 30px;
  31. width: 30%;
  32. }
  33. .player img{
  34. transform:rotateY(180deg);
  35. }
  36. .select{
  37. text-align: center;
  38. font-size: 18px;
  39. max-width: 800px;
  40. margin: 0 auto;
  41. padding-top: 2%;
  42. }
  43. .select dt{
  44. width: 100%;
  45. overflow: hidden;
  46. line-height: 50px;
  47. }
  48. .select button{
  49. width: 20%;
  50. border:none;
  51. color: #fff;
  52. border-radius: 8px;
  53. line-height: 45px;
  54. margin: 0 5%;
  55. outline: none;
  56. font-size: 18px;
  57. cursor: pointer;
  58. }
  59. #info{
  60. width: 100%;
  61. text-align: center;
  62. overflow: hidden;
  63. font-size: 25px;
  64. line-height: 50px;
  65. color: red;
  66. padding-top: 2%;
  67. opacity: 0;
  68. }
  69. </style>
  70. <script type="text/javascript">
  71. var web3,guessGameABI,guessGameContract,refresh_timer;
  72. $(function(){
  73. web3Auth();
  74. jspFun();
  75. //var version = web3.version;
  76. //console.log(version);
  77. //web3.eth.net.getNetworkType().then(console.log);
  78. web3.eth.getAccounts(console.log);
  79. $.getJSON('/resource/abi/GuessGame.json',function(data){
  80. guessGameABI = data;
  81. //创建合约实例
  82. guessGameContract = new web3.eth.Contract(guessGameABI, '0x85daAd7dbB5Ba1B4020444Ab2f1D84c58d409edF', []);
  83. console.log(guessGameContract.defaultAccount);
  84. console.log(guessGameContract.defaultBlock);
  85. listenEvent();
  86. });
  87.  
  88. })
  89.  
  90. function listenEvent(){
  91. guessGameContract.events.GuessResult({
  92. //filter: {myIndexedParam: [20,23], myOtherIndexedParam: '0x123456789...'}, // 使用数组表示 或:如 20 或 23。
  93. //fromBlock: 0
  94. }, function(error, event){
  95. console.log(event);
  96. }).on("connected", function(subscriptionId){
  97. console.log(subscriptionId);
  98. }).on('data', function(event){
  99. console.log(event); // 与上述可选的回调结果相同
  100. //uint playerChoice,uint computerChoice,uint result
  101. resultDeal(event.returnValues.playerChoice,event.returnValues.computerChoice,event.returnValues.result);
  102. }).on('changed', function(event){
  103. // 从本地数据库中删除事件
  104. console.log("事件删除");
  105. }).on('error', function(error, receipt) {
  106. // 如果交易被网络拒绝并带有交易收据,第二个参数将是交易收据。
  107. console.log("事件被网络拒绝");
  108. });
  109. }
  110.  
  111. function resultDeal(player_choice,computer_choice,r){
  112. //var r = result.args.result.toNumber();
  113. var info = "未知";
  114. if(r == 1){
  115. info = "平手";
  116. }else if(r == 2){
  117. info = "你输了";
  118. }else if(r == 3){
  119. info = "你赢了";
  120. }
  121. update_page(player_choice, computer_choice, info);
  122. }
  123.  
  124. function update_page(player,computer,result){
  125. console.log(player+"----"+computer+"-----"+result);
  126. var info = document.getElementById('info');
  127. var playerImg = document.getElementById('player');
  128. var comImg = document.getElementById('computer');
  129. info.style.opacity = '0';
  130. clearInterval(refresh_timer);
  131. playerImg.src = '/resource/images/'+player+'.png';
  132. comImg.src = '/resource/images/'+computer+'.png';
  133. info.style.opacity = 1;
  134. info.innerText = result;
  135. }
  136.  
  137. function guess(player_choice){
  138. //web3.eth.getCoinbase().then(console.log);
  139. //1:剪刀 2:石头 3:布
  140. var result;
  141. player_choice = parseInt(player_choice);
  142. computer_choice = parseInt(Math.random()*3)+1;
  143. document.getElementById('info').innerText = '';
  144. guessGameContract.methods.play(player_choice,computer_choice).send({
  145. from: '0x229Ea411D368C97b008c7bc19B01Fdd813163701'
  146. }).on('transactionHash', function(hash){
  147. console.log(hash);
  148. beginGame();
  149. }).on('confirmation', function(confirmationNumber, receipt){
  150. console.log(confirmationNumber);
  151. console.log(receipt);
  152. }).on('receipt', function(receipt) {
  153. // receipt 相关例子
  154. console.log(receipt);
  155. }).on('error', function(error, receipt) { // 如果交易被网络拒绝并带有交易收据,则第二个参数将是交易收据。
  156. console.log(error);
  157. console.log(receipt);
  158. });
  159.  
  160. }
  161.  
  162. function beginGame(){
  163. var playerImg = document.getElementById('player');
  164. var comImg = document.getElementById('computer');
  165. refresh_timer = setInterval(function(){
  166. this.n?this.n:this.n=1;this.n++
  167. this.n>3?this.n=1:this.n;
  168. playerImg.src = '/resource/images/'+this.n+'.png';
  169. comImg.src = '/resource/images/'+this.n+'.png';
  170. },100);
  171. }
  172.  
  173. function jspFun(){
  174. choices = $('button');
  175. for(var i=0; i<choices.length; i++){
  176. choices[i].onclick = function(){
  177. guess(this.value);
  178. }
  179. }
  180. }
  181.  
  182. function web3Auth(){
  183. //初始化过程
  184. //var Web3 = require('web3');
  185. if (typeof web3 !== 'undefined') {
  186. console.info("init web3");
  187. web3 = new Web3(web3.currentProvider);
  188. } else {
  189. console.info("init new web3");
  190. // set the provider you want from Web3.providers
  191. web3 = new Web3(new Web3.providers.HttpProvider("http://localhost:8545"));
  192. }
  193.  
  194. }
  195. </script>
  196. </head>
  197. <body>
  198. <div class="computer">
  199. <dl>
  200. <dt>对手</dt>
  201. <dd><img src="${ctx}/resource/images/2.png" id="computer" alt=""></dd>
  202. </dl>
  203. </div>
  204. <div class="player">
  205. <dl>
  206. <dt></dt>
  207. <dd><img src="${ctx}/resource/images/2.png" id="player" alt=""></dd>
  208. </dl>
  209. </div>
  210. <div id="info">平手</div>
  211. <div class="select">
  212. <dl>
  213. <dt>点击下列图标选择要出的选项:</dt>
  214. <dd>
  215. <button value="1"><img src='${ctx}/resource/images/1.png' style="width:80px"></button>
  216. <button value="2"><img src='${ctx}/resource/images/2.png' style="width:80px"></button>
  217. <button value="3"><img src='${ctx}/resource/images/3.png' style="width:80px"></button>
  218. </dd>
  219. </dl>
  220. </div>
  221. </body>
  222. </html>

详细内容参考web3文档看吧,我也是参考文档一点点写的,文档地址:https://learnblockchain.cn/docs/web3.js/

四、运行结果示例:

如果有学习计划的童鞋,可以加我QQ一起交流:

区块链开发学习第七章:第一个Dapp-猜拳游戏的更多相关文章

  1. 区块链开发学习第三章:私有链上部署helloBlockchain简单合约

    前面讲了部署私有链以及新增账户,现在进行到了部署合约了,此操作真是踩了无数无数无数的坑,到写文章为止确实是已经部署好了,但是还有些坑是还没有解决的! 一.Solidity编译器 开始的时候用的http ...

  2. 区块链开发(七)truffle使用入门汇总

    截止上篇博客,以太坊区块链开发的环境和框架基本上搭建完毕.这一篇博客重点梳理一下基本的流程和操作演示. 前奏 基于前面的安装配置,现在重新梳理一遍,以前博客讲到的就在这里一笔带过. (1)创建一个工作 ...

  3. 转:区块链开发(一)搭建基于以太坊go-ethereum的私有链环境

    区块链开发(一)搭建基于以太坊go-ethereum的私有链环境 wo541075754 · 2016-11-07 13:00:03 · 3730 次点击 · 预计阅读时间 3 分钟 · 约1小时前  ...

  4. golang区块链开发的视频教程推荐

    目前网上关于golang区块链开发的资源很少,以太坊智能合约相关的课程倒是很多,可能是由于前者的难度比后者难度大,课程开发需要投入更多精力.搜了一圈之后没结果,我就直接去之前没覆盖的视频网站找资源,包 ...

  5. Knockout应用开发指南 第七章:Mapping插件

    原文:Knockout应用开发指南 第七章:Mapping插件 Mapping插件 Knockout设计成允许你使用任何JavaScript对象作为view model.必须view model的一些 ...

  6. HyperLedger Fabric 1.4 区块链开发平台(4.1)

    目前区块链开发平台分“公有链平台”和“联盟链系统”两类,“公有链平台”主要以以太坊为主的平台,可以在该类平台上进行代币的发行和根据各种模块搭建应用:“联盟链系统”主要以超级账本为主的开源系统,该类开源 ...

  7. 微软Azure区块链开发工具包三大功能详解

    2018年11月15日,微软宣布了Azure区块链开发工具包,它基于微软的无服务器技术构建,并且利用微软和第三方SaaS,完美集成了区块链.该工具包扩展了微软的区块链开发模板和Azure Blockc ...

  8. FISCO BCOS WorkShop | 区块链开发特训营,开课啦!

    FISCO BCOS是完全开源的联盟区块链底层技术平台,由金融区块链合作联盟(深圳)(简称金链盟)成立开源工作组通力打造.开源工作组成员包括博彦科技.华为.深证通.神州数码.四方精创.腾讯.微众银行. ...

  9. Android TV开发总结(七)构建一个TV app中的剧集列表控件

    原文:Android TV开发总结(七)构建一个TV app中的剧集列表控件 版权声明:我已委托"维权骑士"(rightknights.com)为我的文章进行维权行动.转载务必转载 ...

随机推荐

  1. postman自动调用获取token

    Postman不光支持单次请求,还支持环境变量.全局变量.集合变量 本文使用Collection Variable Collection 如下图可以点击Collection然后可以添加请求和文件夹,以 ...

  2. Codeforces 983E - NN country(贪心+倍增优化)

    Codeforces 题面传送门 & 洛谷题面传送门 一道(绝对)偏简单的 D1E,但是我怕自己过若干年(大雾)忘了自己的解法了,所以过来水篇题解( 首先考虑怎么暴力地解决这个问题,不难发现我 ...

  3. 金蝶EAS——我的EAS报销流程怎么能让另一个人看到呢?即如何设置流程传阅功能?设置“代理报销”

    代理的话只能看到被代理人能看到的流程.设置"代理报销":应用--财务会计--费用管理--代理报销 选择报销人公司--"他人代理我报销"--选择报销人(zhaof ...

  4. 你不知道的iostat

    1.       作用 iostat是I/O statistics(输入/输出统计)的缩写,iostat工具将对系统的磁盘操作活动进行监视.它的特点是汇报磁盘活动统计情况,同时也会汇报出CPU使用情况 ...

  5. Perl哈希%hash

    哈希是 key/value 键/值对的集合. Perl中哈希变量以百分号 (%) 标记开始. 访问哈希元素格式:${key}. 以下是一个简单的哈希实例: 实例 #!/usr/bin/perl %da ...

  6. gg=G

    1.代码格式化对齐 2.直接按下ESE模式下就可以来执行了

  7. Hi3516开发笔记(六):通过HiTools使用USB/串口将uboot、kernel、roofts和userdata按照分区表烧写镜像

    若该文为原创文章,转载请注明原文出处本文章博客地址:https://hpzwl.blog.csdn.net/article/details/121706033红胖子(红模仿)的博文大全:开发技术集合( ...

  8. Identity Server 4 从入门到落地(五)—— 使用Ajax访问Web Api

    前面的部分: Identity Server 4 从入门到落地(一)-- 从IdentityServer4.Admin开始 Identity Server 4 从入门到落地(二)-- 理解授权码模式 ...

  9. 100个Shell脚本——【脚本1】打印形状

    [脚本1]打印形状 一.脚本 打印等腰三角形.直角三角形.倒直角三角形.菱形 #!/bin/bash #等腰三角形 read -p "Please input the length:&quo ...

  10. archive后upload to app store时遇到app id不可用的问题

    问题如下图 出现此问题的原因有两种: 1.此app id在AppStore中已经存在,也就是说你使用别人注册的app ID ,  如果是这样,你只能更换app ID 2.此app ID是自己的,突然之 ...