├── .gitignore ├── README.md ├── package-lock.json ├── package.json ├── public ├── img │ ├── 1.jpg │ ├── 2.jpg │ ├── 3.jpg │ ├── 4.jpg │ ├── 5.jpg │ ├── 6.jpg │ ├── Batman.png │ ├── Catwoman.png │ ├── Green Lantern.png │ ├── Harley Quinn.png │ ├── Joker.png │ ├── Robin.png │ ├── Superman.png │ ├── arrow.png │ ├── c1.png │ ├── c2.png │ ├── c3.png │ ├── c4.png │ ├── c5.png │ ├── l1.png │ ├── l2.png │ ├── l3.png │ ├── s1.jpg │ └── s2.jpg ├── index.html ├── index.js └── monopoly.css ├── src ├── index.js └── js │ ├── data.js │ ├── dom-binding.js │ ├── initializing.js │ └── monopoly.js └── webpack.config.js /.gitignore: -------------------------------------------------------------------------------- 1 | /node_modules -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # JavaScript Monopoly 2 | JavaScript大富翁,复刻了童年与小伙伴玩的经典大富翁游戏。 3 | 4 | 在线试玩:https://seanboy.club/game/monopoly 5 | 6 | 7 | 8 | ## 思路 9 | 10 | ### HTML & CSS 11 | 12 | - 配置选项框:选择金钱、玩家人数、电脑人数 13 | - 选择角色框:选择角色 14 | - 主地图:通过grid布局实现,通过JS动态添加棋格;中间的超大格子用来存放各种游戏信息,从上到下依次为:当前玩家、游戏选项、掷骰子区、玩家信息区。 15 | - 各种组件:角色棋子、房子、升级房子的动画、购买框、消息框、地产信息卡片。 16 | 17 | ### 开始(initializing.js) 18 | 19 | - 选择人数 20 | - 选择角色 21 | - 游戏开局 22 | 23 | ### 进行时(monopoly.js) 24 | 25 | #### 主线 26 | 27 | - 掷骰子 28 | - 角色根据骰子点数setInterval移动 29 | - setTimeout停下后触发棋格事件 30 | - 事件完成后轮到下一个玩家 31 | 32 | #### 其他 33 | 34 | - 处理买地和升级地产 35 | - 判断玩家顺序(避开停止和破产状态) 36 | - 判断玩家破产 37 | - 判断游戏结束 38 | 39 | ### 数据(data.js) 40 | 41 | - 角色棋子 42 | - 名字 43 | - 金钱 44 | - 状态(活跃或破产) 45 | - 停止(代表天数,默认为0) 46 | - 是否玩家控制 47 | - 对应DOM节点 48 | - 当前在棋格位置 49 | - 棋格 50 | - 地名 51 | - 地价 52 | - 状态(对应普通地产的等级或特殊区域) 53 | - 对应DOM节点 54 | - 机会命运 55 | - 说明文字 56 | - 金钱数值 57 | - 是否停止 58 | 59 | ### DOM操作(dom-binding.js) 60 | 61 | - 实现所有界面内容显示相关内容 62 | 63 | 64 | 65 | ## 花絮 66 | 67 | - 这个大富翁是19年10月11日开始制作的,那时刚学JavaScript才半个月。最终花了7天左右时间做出了完整,无bug,游戏性强的版本(共两千多行代码)。 68 | - 半年后,20年4月7日晚上,打算往前端方向发展求职之后,从现在的视角用原生JS重制了一遍,把多达一千五百行的JS代码缩到了仅六百多行,并新增了不少功能。 69 | - 下一步将结合Vue框架来重制,很是期待现代化框架的功力能帮助我省多少功夫。 -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "javascript-monopoly", 3 | "version": "1.0.0", 4 | "description": "JavaScript大富翁,复刻了童年与小伙伴玩的经典大富翁游戏。", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "repository": { 10 | "type": "git", 11 | "url": "git+https://github.com/HumanSean/javascript-monopoly.git" 12 | }, 13 | "author": "Human Sean", 14 | "license": "ISC", 15 | "bugs": { 16 | "url": "https://github.com/HumanSean/javascript-monopoly/issues" 17 | }, 18 | "homepage": "https://github.com/HumanSean/javascript-monopoly#readme", 19 | "devDependencies": { 20 | "webpack": "^4.42.1", 21 | "webpack-cli": "^3.3.11" 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /public/img/1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HumanSean/javascript-monopoly/5dd959ca32ff452a764993d404a683f3c7fb54e0/public/img/1.jpg -------------------------------------------------------------------------------- /public/img/2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HumanSean/javascript-monopoly/5dd959ca32ff452a764993d404a683f3c7fb54e0/public/img/2.jpg -------------------------------------------------------------------------------- /public/img/3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HumanSean/javascript-monopoly/5dd959ca32ff452a764993d404a683f3c7fb54e0/public/img/3.jpg -------------------------------------------------------------------------------- /public/img/4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HumanSean/javascript-monopoly/5dd959ca32ff452a764993d404a683f3c7fb54e0/public/img/4.jpg -------------------------------------------------------------------------------- /public/img/5.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HumanSean/javascript-monopoly/5dd959ca32ff452a764993d404a683f3c7fb54e0/public/img/5.jpg -------------------------------------------------------------------------------- /public/img/6.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HumanSean/javascript-monopoly/5dd959ca32ff452a764993d404a683f3c7fb54e0/public/img/6.jpg -------------------------------------------------------------------------------- /public/img/Batman.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HumanSean/javascript-monopoly/5dd959ca32ff452a764993d404a683f3c7fb54e0/public/img/Batman.png -------------------------------------------------------------------------------- /public/img/Catwoman.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HumanSean/javascript-monopoly/5dd959ca32ff452a764993d404a683f3c7fb54e0/public/img/Catwoman.png -------------------------------------------------------------------------------- /public/img/Green Lantern.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HumanSean/javascript-monopoly/5dd959ca32ff452a764993d404a683f3c7fb54e0/public/img/Green Lantern.png -------------------------------------------------------------------------------- /public/img/Harley Quinn.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HumanSean/javascript-monopoly/5dd959ca32ff452a764993d404a683f3c7fb54e0/public/img/Harley Quinn.png -------------------------------------------------------------------------------- /public/img/Joker.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HumanSean/javascript-monopoly/5dd959ca32ff452a764993d404a683f3c7fb54e0/public/img/Joker.png -------------------------------------------------------------------------------- /public/img/Robin.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HumanSean/javascript-monopoly/5dd959ca32ff452a764993d404a683f3c7fb54e0/public/img/Robin.png -------------------------------------------------------------------------------- /public/img/Superman.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HumanSean/javascript-monopoly/5dd959ca32ff452a764993d404a683f3c7fb54e0/public/img/Superman.png -------------------------------------------------------------------------------- /public/img/arrow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HumanSean/javascript-monopoly/5dd959ca32ff452a764993d404a683f3c7fb54e0/public/img/arrow.png -------------------------------------------------------------------------------- /public/img/c1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HumanSean/javascript-monopoly/5dd959ca32ff452a764993d404a683f3c7fb54e0/public/img/c1.png -------------------------------------------------------------------------------- /public/img/c2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HumanSean/javascript-monopoly/5dd959ca32ff452a764993d404a683f3c7fb54e0/public/img/c2.png -------------------------------------------------------------------------------- /public/img/c3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HumanSean/javascript-monopoly/5dd959ca32ff452a764993d404a683f3c7fb54e0/public/img/c3.png -------------------------------------------------------------------------------- /public/img/c4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HumanSean/javascript-monopoly/5dd959ca32ff452a764993d404a683f3c7fb54e0/public/img/c4.png -------------------------------------------------------------------------------- /public/img/c5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HumanSean/javascript-monopoly/5dd959ca32ff452a764993d404a683f3c7fb54e0/public/img/c5.png -------------------------------------------------------------------------------- /public/img/l1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HumanSean/javascript-monopoly/5dd959ca32ff452a764993d404a683f3c7fb54e0/public/img/l1.png -------------------------------------------------------------------------------- /public/img/l2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HumanSean/javascript-monopoly/5dd959ca32ff452a764993d404a683f3c7fb54e0/public/img/l2.png -------------------------------------------------------------------------------- /public/img/l3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HumanSean/javascript-monopoly/5dd959ca32ff452a764993d404a683f3c7fb54e0/public/img/l3.png -------------------------------------------------------------------------------- /public/img/s1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HumanSean/javascript-monopoly/5dd959ca32ff452a764993d404a683f3c7fb54e0/public/img/s1.jpg -------------------------------------------------------------------------------- /public/img/s2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HumanSean/javascript-monopoly/5dd959ca32ff452a764993d404a683f3c7fb54e0/public/img/s2.jpg -------------------------------------------------------------------------------- /public/index.html: -------------------------------------------------------------------------------- 1 | 8 | 9 | 10 | 11 | 12 | JavaScript大富翁 13 | 14 | 15 | 16 | 17 |
18 |
欢迎来到Sean自制的JavaScript大富翁~
19 |
20 |

起始金钱

21 | 27 |
28 |
29 |

请选择角色

30 | 39 |
40 |
41 | 42 |
43 | 44 |
45 |

46 | 47 | 48 | 49 | 50 | 当前天数:0 51 | 52 |
53 |
54 |
55 | 56 |
57 |
58 |

特色介绍

59 |
    60 |
  • 每次路过起点都会获得$1000,如果刚好停在上面还有机会获得更多。
  • 61 | 62 |
  • 建议玩家多的时候起始金钱选少点、少的时候选多点,已增加游戏性。
  • 63 |
  • 点击改变速度按钮可以让游戏速度变得更快,或者恢复原样。
  • 64 |
  • 点击开启托管按钮,可以让电脑控制玩家角色,不过如果刚好轮到玩家角色的话还得再掷一次骰子托管才生效。
  • 65 |
66 |

玩法说明

67 |
    68 |
  • 点击骰子进行游戏;电脑玩家会自动掷骰子。
  • 69 |
  • 游戏目标:让除了你外的所有玩家破产,你便是最有钱的那个仔!
  • 70 |
  • 每个棋格都会触发对应事件,分为以下几种:
  • 71 |
  • 普通地产:玩家可以自由购买并且升级造房子。别的玩家经过你的地产时就需要向你缴纳地租。鼠标放在棋格上会显示地产的详细信息。
  • 72 |
  • 机会 & 命运:随机触发一个好运或者厄运。
  • 73 |
  • 交所得税:缴纳随机数额的税。
  • 74 |
  • 赌场:获得掷骰子的点数乘以500的奖金。
  • 75 |
  • 捡到钱 & 起点:获得随机数量的金钱。
  • 76 |
  • 监狱:随机的天数内停止不能行动。
  • 77 |
  • 阿尔卑斯山:随机的天数不能行动以及花费随机的金钱。
  • 78 |
  • 机场:花费一定金钱来回穿梭。
  • 79 |
  • 地租机制:一共有4个等级,分别是空地、房子、别墅、酒店。越高等级收的地租就越高,对应比率分别是地价的五分之一、二分之一、原价、双倍价钱。
  • 80 |
  • 破产机制:一旦有玩家的钱低于0了,马上宣告破产,并且拥有的地产全部充公,其他玩家可以再次购买。
  • 81 |
82 |

玩得开心~

83 |
84 |
85 |
86 | 87 |
88 |

89 |

购买地产

90 |
确定
91 |
取消
92 |
93 | 94 |
95 | 96 |
97 |

俄罗斯

98 | 103 |
104 | 105 | 109 | 110 | 111 | -------------------------------------------------------------------------------- /public/index.js: -------------------------------------------------------------------------------- 1 | !function(e){var n={};function t(o){if(n[o])return n[o].exports;var i=n[o]={i:o,l:!1,exports:{}};return e[o].call(i.exports,i,i.exports,t),i.l=!0,i.exports}t.m=e,t.c=n,t.d=function(e,n,o){t.o(e,n)||Object.defineProperty(e,n,{enumerable:!0,get:o})},t.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},t.t=function(e,n){if(1&n&&(e=t(e)),8&n)return e;if(4&n&&"object"==typeof e&&e&&e.__esModule)return e;var o=Object.create(null);if(t.r(o),Object.defineProperty(o,"default",{enumerable:!0,value:e}),2&n&&"string"!=typeof e)for(var i in e)t.d(o,i,function(n){return e[n]}.bind(null,i));return o},t.n=function(e){var n=e&&e.__esModule?function(){return e.default}:function(){return e};return t.d(n,"a",n),n},t.o=function(e,n){return Object.prototype.hasOwnProperty.call(e,n)},t.p="",t(t.s=0)}([function(e,n){var t=document.querySelector(".map"),o=document.querySelector(".dice"),i=document.querySelector(".choosebox"),r=document.querySelector(".choosechr"),l=document.querySelector(".title"),s=document.querySelector(".info"),a=document.querySelector(".dialog"),c=document.querySelector(".infobox"),u=document.querySelector(".msgbox");for(let e=0;e<30;e++){let e=document.createElement("div"),n=document.createElement("h3");e.className="box",e.append(n),t.prepend(e)}function d(e,n,t){i.firstElementChild.innerHTML=e,Array.from(i.lastElementChild.children).forEach((e,o)=>{switch(e.innerHTML=n+o,t){case 3:m();break;case 2:o>1&&p(e);break;case 1:o>2&&p(e);break;case 0:o<1&&p(e)}})}function p(e){e.style.pointerEvents="none",e.style.background="grey"}function m(){i.style.display="none",r.style.display="block"}Array.from(document.querySelectorAll(".choosebox li")).forEach((e,n)=>{e.addEventListener("click",()=>{var e;e=n,O?q?(A=+e,m()):(d("电脑人数",0,e),q=+e+1):(d("玩家人数",1),O=5e3*e+1e4)})});let f=document.createElement("div");f.className="arrow";let h=document.createElement("img");function g(e){let n=F(1,2);o.style.background=`url(img/s${n}.jpg)`,setTimeout((function(){o.style.background=`url(img/${e}.jpg)`}),300),y(!1)}function y(e){o.style.pointerEvents=e?"auto":"none"}function w(e){l.innerHTML=e,l.style.background=P[e]}function v(){let e=q+A;for(let n=0;n{e.removeChild(t),e.append(function(e){let n=document.createElement("img");return n.src=`img/l${e+1}.png`,n.className="house",n}(n)),_(C)},2e3)}function E(e){u.style.display="block",u.innerHTML=e,setTimeout(()=>{u.style.display="none"},1.6*N)}function b(e,n){let t,o;a.style.display="block";let{name:i,value:r,state:l}=M[j.position];"purchase"===e?(t="购买地产",o=`请问你要花费$${r*(l+1)}来购买${i}吗?`):(t="升级地产",o=`请问你要花费$${r/2}来升级${i}吗?`),a.children[1].innerHTML=t,a.firstElementChild.innerHTML=o,n?(a.children[2].style.pointerEvents="auto",a.children[2].style.background="#f2f2f2"):(a.children[2].style.pointerEvents="none",a.children[2].style.background="#454545"),a.children[2].onclick=()=>{I(e,!0)}}function x(){a.style.display="none"}h.src="img/arrow.png",f.append(h),Array.from(r.lastElementChild.children).forEach(e=>{e.firstElementChild.addEventListener("mouseover",(function(){e.appendChild(f)})),e.firstElementChild.addEventListener("click",()=>{e.firstElementChild.style.border="1px solid #666";let n=document.createElement("div");n.innerHTML=""+(T.length+1),n.className="index",e.appendChild(n),e.removeChild(f),e.style.pointerEvents="none";let t=e.children[1].innerHTML,o=document.createElement("img");o.className="chr",o.src=`img/${t}.png`,M[0].node.append(o),function(e,n){let t=T.length{e.node.addEventListener("mouseover",()=>{if(e.state>=0)if(c.style.display="block",c.firstElementChild.innerHTML=e.name,c.lastElementChild.children[0].innerHTML="地主:"+e.owner,c.lastElementChild.children[1].innerHTML="价格:"+e.value,e.owner){let n=5/(3*e.state+1),t=e.value/(n>.5?Math.ceil(n):n);c.lastElementChild.children[2].innerHTML="住宿:"+t}else c.lastElementChild.children[2].innerHTML=""}),e.node.addEventListener("mouseout",()=>{c.style.display="none"})}),j=T[0])}(o,t)})}),o.addEventListener("click",()=>{B()}),a.children[3].addEventListener("click",()=>{I("",!1)}),document.querySelectorAll(".big-box button")[0].addEventListener("click",(function(){"规则介绍"===this.innerHTML?(this.innerHTML="返回",document.querySelector(".instruction").style.height="100%"):(this.innerHTML="规则介绍",document.querySelector(".instruction").style.height="0")})),document.querySelectorAll(".big-box button")[1].addEventListener("click",(function(){let e=N>600?"正常":"加快";this.innerHTML=e+"速度",N=1300-N})),document.querySelectorAll(".big-box button")[2].addEventListener("click",(function(){"开启托管"===this.innerHTML?(this.innerHTML="取消托管",T.forEach(e=>{e.control&&(e.control="")})):(this.innerHTML="开启托管",T.forEach(e=>{""===e.control&&(e.control=1)}))})),window.addEventListener("load",()=>{let e=[];["img/arrow.png","img/batman.png","img/superman.png","img/green lantern.png","img/robin.png","img/catwoman.png","img/harley quinn.png","img/joker.png","img/1.jpg","img/2.jpg","img/3.jpg","img/4.jpg","img/5.jpg","img/6.jpg","img/s1.jpg","img/s2.jpg","img/c1.png","img/c2.png","img/c3.png","img/c4.png","img/c5.png","img/l1.png","img/l2.png","img/l3.png"].forEach((n,t)=>{e[t]=new Image,e[t].src=n})});var T=[];function L(e,n,t,o,i,r,l){this.name=e,this.index=n,this.money=t,this.state=o,this.stop=i,this.control=r,this.node=l,this.position=0,T.push(this)}var M=[];function k(e,n,t,o,i){this.name=e,this.value=n,this.state=t,this.owner=o,this.node=document.querySelectorAll(".map>div")[i],this.node.firstElementChild.append(e),M.push(this)}new k("起点",2e3,"goodEvent","sean",18),new k("中国",5e3,0,"",19),new k("越南",1e3,0,"",20),new k("韩国",1300,0,"",21),new k("机会",1e3,"surprise","sean",22),new k("日本",3e3,0,"",23),new k("俄罗斯",4e3,0,"",24),new k("白云机场",1e3,"airport","sean",25),new k("交所得税",1e3,"badEvent","sean",26),new k("命运",1e3,"surprise","sean",27),new k("埃及",1600,0,"",28),new k("监狱",0,"jail","sean",29),new k("澳大利亚",2400,0,"",17),new k("新西兰",1800,0,"",15),new k("南极洲",2e4,0,"",13),new k("赌场",1e3,"casino","sean",11),new k("机会",1e3,"surprise","sean",10),new k("捡到钱",1e3,"goodEvent","sean",9),new k("巴西",2e3,0,"",8),new k("阿根廷",2200,0,"",7),new k("墨西哥",2400,0,"",6),new k("美国",4500,0,"",5),new k("意大利",3e3,0,"",4),new k("伦敦机场",1e3,"airport","sean",3),new k("英国",3600,0,"",2),new k("命运",1e3,"surprise","sean",1),new k("阿尔卑斯山",1e3,"trip","sean",0),new k("德国",3400,0,"",12),new k("法国",3200,0,"",14),new k("西班牙",2800,0,"",16);var H=[];function S(e,n,t){this.text=e,this.value=n,this.stop=t,H.push(this)}new S("扶老奶奶过马路的事迹被大家知道了,村委会颁发$1000奖金",1e3,0),new S("中了彩票,获得头奖$5000",5e3,0),new S("在街边被劫匪抢劫,为了保住性命,失去$3000",-3e3,0),new S("喝了一杯一点点,花费$30",-30,0),new S("路边捡到$500",500,0),new S("吃鱼卡到鱼刺,去医院花了$800",-800,0),new S("钱包落在出租车里,丢失$1000",-1e3,0),new S("空闲时间去兼职家教,收获$2000",2e3,0),new S("扶老奶奶过马路摔了一跤,买药花了$100",-100,0),new S("手机突然坏了,换了部最新款iPhone,花费$1300",-1300,0),new S("吃羊肉火锅,花费$500",-500,0),new S("去日本看樱花,花费$2000",-2e3,0),new S("什么也没有发生,除了钱包少了$800",-800,0),new S("什么也没有发生, 除了钱包多了$1000",1e3,0),new S("在广交会做翻译,获得$1000",1e3,0),new S("在校门口发传单,得到$100",100,0),new S("获得三好学生奖学金,奖金$3000",3e3,0),new S("抢了个微信红包,获得$1",1,0),new S("梦见得到$3000奖金,醒来决定花$50去拜神",-50,0),new S("获得了$3000奖金!赶紧花$500去还愿",2500,0),new S("卖闲置赚了$100",100,0),new S("什么也没有发生",0,0),new S("看电影花费了$100",-100,0),new S("还花呗欠款$999",-999,0),new S("一年一度的双十一到了,剁手花了$2000",-2e3,0),new S("突然很渴想买瓶矿泉水,花费$5",-5,0),new S("去工地搬砖赚了$500",500,0),new S("偷税漏税罚款$1000,拘留1日",-1e3,1),new S("超速行驶被罚款$2000,拘留2天",-2e3,2),new S("被查水表发现有违建,罚款$1000并拘留3日",-1e3,3),new S("考试作弊被拘留5日",0,5);var j,C=0,q=0,A=0,O=0,N=800,P={Joker:"#5E45AB",Batman:"#121212",Superman:"#274D7A",Catwoman:"#B04E58","Harley Quinn":"pink",Robin:"#FA2A14","Green Lantern":"#5FAE2E"};function _(e){e===q+A-1?(e=0,function(){let e=+document.querySelector(".big-box span b").innerHTML+1;document.querySelector(".big-box span b").innerHTML=e}()):e++,setTimeout(()=>{(function(e){let n=T[e];return n.stop?(11===n.position?E(`${n.name}还有${n.stop}天可以出狱`):E(`${n.name}离难得的假期结束还有${n.stop}天`),n.stop--,!1):"bankrupt"!==n.state&&(n.control?y(!0):setTimeout(()=>{B()},2*N),C=e,w(n.name),!0)})(e)||_(e)},N)}function B(){let e=F(1,6);g(e),j=T[C];let n=setInterval(()=>{var e;e=C,29===j.position&&(j.position=-1,M[0].node.append(T[e].node),v(),T[e].money+=1e3),j.position++,M[j.position].node.append(T[e].node)},N);setTimeout(()=>{clearInterval(n);let e=M[j.position];if(e.owner)if(e.owner&&e.owner!==j.name&&"sean"!=e.owner){let n=T.find(n=>n.name===e.owner);if(n.stop)E("房子主人不在,免费过夜1晚!");else{let t=5/(3*e.state+1),o=e.value/(t>.5?Math.ceil(t):t);j.money-=o,n.money+=o,E(`${n.name}感谢${j.name}在${e.name}消费$${o}`),D()}_(C)}else if(e.owner===j.name)3===e.state?_(C):j.control?b("upgrade",j.money>.5*e.value):I("upgrade",j.money-e.value/2>2e3);else if("goodEvent"===e.state){let e=500*F(0,7);j.money+=e,E("恭喜你捡到了$"+e),_(C)}else if("badEvent"===e.state){let e=300*F(0,7);j.money-=e,E("你需要向税务局缴纳税收$"+e),D(),_(C)}else if("jail"===e.state)j.stop=F(1,3),E(`偷税漏税被抓,关押${j.stop}天`),_(C);else if("casino"===e.state){let e=F(1,6);g(e),setTimeout(()=>{let n=500*e;j.money+=n,E("恭喜你获得了$"+n),v(),_(C)},2*N)}else if("surprise"===e.state){var t=F(0,31);j.money+=H[t].value,H[t].stop?setTimeout((function(){j.position=11,j.stop=H[t].stop,M[11].node.append(j.node),D(),_(C)}),1.5*N):(D(),_(C)),E(H[t].text)}else if("airport"===e.state){E("你花费$800搭乘飞机前往"+("白云机场"===e.name?"英国":"中国")),setTimeout(()=>{j.position=30-j.position,M[j.position].node.append(j.node),D(),_(C)},1.5*N),j.money-=800}else"trip"===e.state&&(j.stop=F(1,3),j.money-=1e3*j.stop,E(`${j.name}花费${1e3*j.stop}享受旅游度假${j.stop}天`),D(),_(C));else j.control?b("purchase",j.money>e.value):setTimeout(()=>I("purchase",j.money-e.value>3e3),N/3);v()},N*(e+.9))}function I(e,n){let t=M[j.position];if(!n)return x(),void _(C);if("purchase"===e){t.owner=j.name,j.money-=t.value;let e=P[j.name];!function(e,n){e.style.boxShadow=`3px 3px 3px inset ${n},3px -3px 3px inset ${n},-3px 3px 3px inset ${n}, -3px -3px 3px inset ${n}`}(t.node,e),E("恭喜你获得了"+t.name),_(C)}else{let e=["一座小房子","一套大别墅","一栋大酒店"];j.money-=t.value/2,t.state++,E(`恭喜你在${t.name}建了${e[t.state-1]}`),$(t.node,t.state-1)}x(),v()}function F(e,n){return Math.floor(Math.random()*(n-e))+e}function D(){j.money<0&&setTimeout(()=>{var e,n;j.stop=0,j.state="bankrupt",alert(`很遗憾,${j.name}破产了,所有地产将充公处理。`),e=j.node,n=T.indexOf(j),s.children[n].firstElementChild.style.display="none",s.children[n].append(e),M.forEach(e=>{e.owner===j.name&&(e.owner="",e.node.style.boxShadow="1px 1px 1px inset #454545, 1px -1px 1px inset #454545, -1px 1px 1px inset #454545, -1px -1px 1px inset #454545")}),function(){let e,n=0;T.forEach(t=>{"active"===t.state&&(n++,e=t)}),1===n&&setTimeout(()=>{alert(e.name+"赢啦!恭喜你成为最有钱的人!"),location.reload()},2*N)}()},N/2)}}]); -------------------------------------------------------------------------------- /public/monopoly.css: -------------------------------------------------------------------------------- 1 | /*全局设定*/ 2 | * { 3 | margin: 0; 4 | padding: 0; 5 | font-family: "Comic Sans MS", "微软雅黑"; 6 | user-select: none; 7 | outline: transparent; 8 | } 9 | 10 | li { 11 | list-style-type: none; 12 | } 13 | 14 | html, body { 15 | width: 100%; 16 | height: 100%; 17 | overflow: hidden; 18 | color: #454545; 19 | } 20 | 21 | ::-webkit-scrollbar { 22 | display: none; 23 | } 24 | 25 | .blacknwhite { 26 | color: #fff; 27 | background: #454545; 28 | } 29 | 30 | .middle { 31 | position: absolute; 32 | top: 50%; 33 | left: 50%; 34 | transform: translate(-50%, -50%); 35 | } 36 | 37 | .full { 38 | position: absolute; 39 | width: 100%; 40 | height: 100%; 41 | left: 0; 42 | top: 0; 43 | } 44 | 45 | /*设置选项*/ 46 | .setting { 47 | background: rgba(0, 0, 0, .8); 48 | z-index: 5; 49 | } 50 | 51 | .welcome { 52 | top: 13%; 53 | color: #fff; 54 | font-size: 36px; 55 | white-space: nowrap; 56 | } 57 | 58 | /*人数*/ 59 | .choosebox { 60 | width: 400px; 61 | height: 300px; 62 | background: #f2f2f2; 63 | border-radius: 13px; 64 | } 65 | 66 | .choosebox h2 { 67 | text-align: center; 68 | height: 26px; 69 | padding: 26px; 70 | border-top-left-radius: 10px; 71 | border-top-right-radius: 10px; 72 | } 73 | 74 | .choosebox ul { 75 | width: 100%; 76 | height: calc(100% - 78px); 77 | } 78 | 79 | .choosebox li { 80 | float: left; 81 | width: 50%; 82 | height: 50%; 83 | text-align: center; 84 | font-size: 26px; 85 | line-height: 111px; 86 | cursor: pointer; 87 | box-shadow: .5px .5px .5px inset #454545, -.5px -.5px .5px inset #454545; 88 | } 89 | 90 | .choosebox li:hover { 91 | background: #ccc; 92 | } 93 | 94 | .choosebox li:nth-of-type(3) { 95 | border-bottom-left-radius: 13px 96 | } 97 | 98 | .choosebox li:nth-of-type(4) { 99 | border-bottom-right-radius: 13px 100 | } 101 | 102 | /*选角*/ 103 | .choosechr { 104 | width: 700px; 105 | height: 200px; 106 | background: #f2f2f2; 107 | border-radius: 13px; 108 | display: none; 109 | } 110 | 111 | .choosechr h2 { 112 | text-align: center; 113 | line-height: 26px; 114 | padding: 13px; 115 | border-top-left-radius: 10px; 116 | border-top-right-radius: 10px; 117 | } 118 | 119 | .choosechr ul { 120 | width: 100%; 121 | height: calc(100% - 52px); 122 | } 123 | 124 | .choosechr ul h3 { 125 | font-size: 13px; 126 | text-align: center; 127 | background: #42AFE1; 128 | color: #fff; 129 | } 130 | 131 | .choosechr li { 132 | position: relative; 133 | float: left; 134 | width: 100px; 135 | height: 100%; 136 | } 137 | 138 | .choosechr img { 139 | width: 80%; 140 | } 141 | 142 | .choosechr img:hover { 143 | width: 95%; 144 | cursor: pointer; 145 | transition: .5s; 146 | } 147 | .index { 148 | position: absolute; 149 | bottom: 3%; 150 | left: 50%; 151 | transform: translateX(-50%); 152 | } 153 | .arrow { 154 | position: absolute; 155 | width: 16px; 156 | left: 50%; 157 | transform: translateX(-50%); 158 | animation: arrow 1s infinite; 159 | } 160 | 161 | 162 | /*地图*/ 163 | .map { 164 | display: grid; 165 | grid-template-columns: repeat(12, 1fr); 166 | grid-template-rows: repeat(5, 1fr); 167 | grid-gap: 3px; 168 | overflow: hidden; 169 | } 170 | .box { 171 | position: relative; 172 | height: 100%; 173 | width: 100%; 174 | box-shadow: 1px 1px 1px inset #454545, 1px -1px 1px inset #454545, -1px 1px 1px inset #454545, -1px -1px 1px inset #454545; 175 | text-align: center; 176 | border-radius: 13px; 177 | } 178 | 179 | .box h3, .dialog h2, .infobox h2 { 180 | background: #454545; 181 | color: #fff; 182 | font-weight: 100; 183 | position: absolute; 184 | top: 0; 185 | left: 0; 186 | font-size: 15px; 187 | width: 100%; 188 | height: 30px; 189 | line-height: 30px; 190 | border-top-right-radius: 13px; 191 | border-top-left-radius: 13px; 192 | overflow: hidden; 193 | white-space: nowrap; 194 | } 195 | 196 | /* 角色棋子 */ 197 | .box .chr { 198 | width: 85%; 199 | position: absolute; 200 | bottom: 5%; 201 | left: 50%; 202 | transform: translateX(-50%); 203 | animation: moving .8s; 204 | z-index: 1; 205 | } 206 | 207 | /* 中间区域 */ 208 | .big-box { 209 | position: relative; 210 | background: #fff; 211 | box-shadow: none; 212 | grid-area: 2 / 2 / -2 / -2; 213 | text-align: left; 214 | } 215 | 216 | /* 当前玩家 */ 217 | .title { 218 | display: inline-block; 219 | padding: 5px 13px; 220 | color: #fff; 221 | border-radius: 10px; 222 | } 223 | 224 | /* 设置按钮 */ 225 | .big-box button, .big-box span { 226 | position: relative; 227 | float: right; 228 | border: none; 229 | margin-left: 3px; 230 | padding: 7px 13px; 231 | border-radius: 10px; 232 | cursor: pointer; 233 | } 234 | 235 | /* 角色信息区域 */ 236 | .info { 237 | position: absolute; 238 | bottom: 0; 239 | left: 0; 240 | width: 100%; 241 | height: 99px; 242 | } 243 | 244 | .info>div { 245 | display: inline-block; 246 | position: relative; 247 | width: calc(25% - 5px); 248 | height: 100%; 249 | } 250 | 251 | .info h2 { 252 | position: absolute; 253 | bottom: 0; 254 | left: 50%; 255 | transform: translateX(-50%); 256 | padding: 3px 13px; 257 | border-radius: 10px; 258 | color: #fff; 259 | white-space: nowrap; 260 | } 261 | 262 | .info h3 { 263 | position: absolute; 264 | bottom: 40px; 265 | left: 50%; 266 | transform: translateX(-50%); 267 | } 268 | 269 | .info .chr { 270 | position: absolute; 271 | width: 65px; 272 | left: 50%; 273 | transform: translateX(-50%); 274 | z-index: 3; 275 | bottom: 36px; 276 | } 277 | 278 | /* 游戏说明 */ 279 | .instruction { 280 | background: #f2f2f2; 281 | border-radius: 10px; 282 | transition: .5s; 283 | z-index: 2; 284 | height: 0; 285 | overflow: scroll; 286 | } 287 | 288 | .instruction h2 { 289 | text-align: center; 290 | margin-top: 20px; 291 | } 292 | 293 | .instruction ul { 294 | box-sizing: border-box; 295 | padding: 13px; 296 | } 297 | 298 | .instruction li { 299 | list-style-type: circle; 300 | list-style-position: inside; 301 | margin: 5px; 302 | } 303 | 304 | /*掷骰子区*/ 305 | .control { 306 | width: 169px; 307 | height: 169px; 308 | border-radius: 50%; 309 | box-shadow: 2px 2px 2px #888, -2px 2px 2px #888, 2px -2px 2px #888, -2px -2px 2px #888, 310 | 4px 4px 4px #999 inset, -4px -4px 4px #999 inset, 4px -4px 4px #999 inset, -4px 4px 4px #999 inset; 311 | top: 40%; 312 | } 313 | 314 | .dice { 315 | width: 100px; 316 | height: 100px; 317 | background-image: url(img/1.jpg); 318 | cursor: pointer; 319 | border-radius: 25%; 320 | } 321 | 322 | /* 购买框 */ 323 | .dialog { 324 | width: 600px; 325 | height: 260px; 326 | border-radius: 13px; 327 | background: #fff; 328 | border: 3px solid #454545; 329 | display: none; 330 | } 331 | 332 | .dialog p { 333 | width: 100%; 334 | font-size: 22px; 335 | text-align: center; 336 | } 337 | 338 | .dialog h2, .infobox h2 { 339 | height: 52px; 340 | line-height: 52px; 341 | text-indent: 1em; 342 | font-size: 20px; 343 | letter-spacing: 13px; 344 | border-top-left-radius: 8px; 345 | border-top-right-radius: 8px; 346 | } 347 | 348 | .btn { 349 | background: #f2f2f2; 350 | width: 50%; 351 | height: 20%; 352 | position: absolute; 353 | bottom: 0%; 354 | text-align: center; 355 | line-height: 60px; 356 | } 357 | 358 | .btn:first-of-type { 359 | left: 0; 360 | border-bottom-left-radius: 8px; 361 | color: #000; 362 | box-shadow: -1px 0 silver inset; 363 | } 364 | 365 | .btn:last-of-type { 366 | right: 0; 367 | border-bottom-right-radius: 8px; 368 | } 369 | 370 | .btn:hover { 371 | box-shadow: 0 5em inset silver; 372 | cursor: pointer; 373 | } 374 | 375 | /* 消息框 */ 376 | .msgbox { 377 | border: 2px solid #666; 378 | border-radius: 13px; 379 | font-weight: 100; 380 | font-size: 22px; 381 | padding: 2em 2em; 382 | background: #f1f1f1; 383 | top: 45%; 384 | white-space: nowrap; 385 | display: none; 386 | } 387 | 388 | /* 地产信息卡片 */ 389 | .infobox { 390 | width: 200px; 391 | height: 300px; 392 | border-radius: 13px; 393 | background: #f2f2f2; 394 | border: 3px solid #454545; 395 | display: none; 396 | } 397 | 398 | .infobox ul { 399 | width: 100%; 400 | height: 80%; 401 | border-bottom-left-radius: 10px; 402 | border-bottom-right-radius: 10px; 403 | position: absolute; 404 | top: 20%; 405 | left: 0; 406 | } 407 | 408 | .infobox li { 409 | display: block; 410 | width: calc(100% - 20px); 411 | padding: 10px; 412 | } 413 | 414 | /*施工*/ 415 | .construct img { 416 | position: absolute; 417 | z-index: 3; 418 | } 419 | 420 | .construct img:first-child { 421 | width: 100%; 422 | bottom: 0%; 423 | left: 50%; 424 | transform: translateX(-50%); 425 | animation: c1 2s; 426 | } 427 | 428 | .construct img:nth-child(2) { 429 | width: 100%; 430 | bottom: 3%; 431 | right: -30%; 432 | animation: c2 2s; 433 | } 434 | 435 | .construct img:nth-child(3) { 436 | width: 100%; 437 | bottom: 3%; 438 | left: -30%; 439 | animation: c3 2s; 440 | } 441 | 442 | .construct img:nth-child(4) { 443 | width: 50%; 444 | bottom: 30%; 445 | right: 0%; 446 | transform: rotate(-45deg); 447 | animation: c4 2s; 448 | } 449 | 450 | .construct img:nth-child(5) { 451 | width: 180%; 452 | bottom: -13%; 453 | left: -30%; 454 | animation: c5 2s; 455 | } 456 | 457 | /*房子*/ 458 | .box img.house { 459 | position: absolute; 460 | bottom: 5%; 461 | left: 50%; 462 | transform: translateX(-50%); 463 | width: 90%; 464 | } 465 | 466 | /*动画都在这里*/ 467 | @keyframes arrow { 468 | 0% { 469 | bottom: 1%; 470 | } 471 | 472 | 50% { 473 | bottom: 3%; 474 | } 475 | 476 | 100% { 477 | bottom: 1%; 478 | } 479 | } 480 | 481 | @keyframes moving { 482 | 0% { 483 | width: 85%; 484 | } 485 | 486 | 50% { 487 | width: 100%; 488 | } 489 | 490 | 100% { 491 | width: 85%; 492 | } 493 | } 494 | 495 | @keyframes c1 { 496 | 0% { 497 | opacity: 0; 498 | } 499 | 500 | 80% { 501 | opacity: 1; 502 | } 503 | 504 | 100% { 505 | opacity: 0; 506 | } 507 | } 508 | 509 | @keyframes c2 { 510 | 0% { 511 | opacity: 0; 512 | right: -100%; 513 | } 514 | 515 | 80% { 516 | opacity: 1; 517 | } 518 | 519 | 100% { 520 | opacity: 0; 521 | right: -30%; 522 | } 523 | } 524 | 525 | @keyframes c3 { 526 | 0% { 527 | opacity: 0; 528 | left: -100%; 529 | } 530 | 531 | 80% { 532 | opacity: 1; 533 | } 534 | 535 | 100% { 536 | opacity: 0; 537 | left: -30%; 538 | } 539 | } 540 | 541 | @keyframes c4 { 542 | 0% { 543 | opacity: 0; 544 | transform: rotate(-45deg); 545 | } 546 | 547 | 20% { 548 | opacity: 1; 549 | transform: rotate(-45deg); 550 | } 551 | 552 | 40% { 553 | transform: rotate(-90deg); 554 | } 555 | 556 | 60% { 557 | transform: rotate(-45deg); 558 | } 559 | 560 | 80% { 561 | opacity: 1; 562 | transform: rotate(-90deg); 563 | } 564 | 565 | 100% { 566 | opacity: 0; 567 | transform: rotate(-45deg); 568 | } 569 | } 570 | 571 | @keyframes c5 { 572 | 0% { 573 | opacity: 0; 574 | } 575 | 576 | 50% { 577 | opacity: 0; 578 | } 579 | 580 | 80% { 581 | opacity: 1; 582 | } 583 | 584 | 100% { 585 | opacity: 0; 586 | } 587 | } -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @Author: Human Sean 3 | * @Email: humansean@qq.com 4 | * @Date: 2020-04-09 14:26:45 5 | * @LastEditTime: 2020-04-11 17:46:24 6 | * @Description: 一切跟DOM有关的操作 7 | */ 8 | // 快捷编号 9 | var map = document.querySelector('.map') 10 | var dice = document.querySelector(".dice") 11 | var choosebox = document.querySelector(".choosebox") 12 | var choosechr = document.querySelector(".choosechr") 13 | var title = document.querySelector(".title") 14 | var info = document.querySelector('.info') 15 | var dialog = document.querySelector(".dialog") 16 | var infobox = document.querySelector(".infobox") 17 | var msgbox = document.querySelector(".msgbox") 18 | // 创建升级造房动画 19 | function construct() { 20 | let construct = document.createElement('div') 21 | construct.className = 'construct' 22 | for (let i = 0; i < 5; i++) { 23 | const img = document.createElement('img') 24 | img.src = `img/c${i + 1}.png` 25 | construct.append(img) 26 | } 27 | return construct 28 | } 29 | // 创建升级的房子 30 | function buidings(index) { 31 | let img = document.createElement('img') 32 | img.src = `img/l${index + 1}.png` 33 | img.className = 'house' 34 | return img 35 | } 36 | // 写入地图棋格 37 | for (let i = 0; i < 30; i++) { 38 | let box = document.createElement('div') 39 | let h3 = document.createElement('h3') 40 | box.className = 'box' 41 | box.append(h3) 42 | map.prepend(box) 43 | } 44 | // 绑定选择 45 | Array.from(document.querySelectorAll('.choosebox li')).forEach((node, index) => { 46 | node.addEventListener('click', () => { 47 | chooseNumber(index) 48 | }) 49 | }) 50 | // 更改选择配置时的DOM显示 51 | function writeSetting(title, startNum, num) { 52 | choosebox.firstElementChild.innerHTML = title 53 | Array.from(choosebox.lastElementChild.children).forEach((node, index) => { 54 | node.innerHTML = startNum + index 55 | switch (num) { 56 | case 3: 57 | finishChooseNumber() 58 | break 59 | case 2: 60 | if (index > 1) { 61 | disableBox(node) 62 | } 63 | break 64 | case 1: 65 | if (index > 2) { 66 | disableBox(node) 67 | } 68 | break 69 | case 0: 70 | if (index < 1) { 71 | disableBox(node) 72 | } 73 | break 74 | } 75 | }) 76 | } 77 | // 禁用选框,避免人数总和大于四 78 | function disableBox(node) { 79 | node.style.pointerEvents = "none" 80 | node.style.background = "grey" 81 | } 82 | // 结束人数选择,开启角色选择,并画上地图 83 | function finishChooseNumber() { 84 | choosebox.style.display = "none" 85 | choosechr.style.display = "block" 86 | } 87 | // 创造复用的箭头 88 | let arrow = document.createElement('div') 89 | arrow.className = 'arrow' 90 | let img = document.createElement('img') 91 | img.src = "img/arrow.png" 92 | arrow.append(img) 93 | // 选择角色 94 | Array.from(choosechr.lastElementChild.children).forEach(item => { 95 | item.firstElementChild.addEventListener('mouseover', function(){ // 下标箭头 96 | item.appendChild(arrow) 97 | }) 98 | item.firstElementChild.addEventListener('click', () => { // 绑定角色 99 | // 处理选中效果 100 | item.firstElementChild.style.border = "1px solid #666" 101 | let index = document.createElement('div') 102 | index.innerHTML = `${players.length + 1}` 103 | index.className = 'index' 104 | item.appendChild(index) 105 | item.removeChild(arrow) 106 | item.style.pointerEvents = "none" 107 | // 创建角色对应棋子 108 | let name = item.children[1].innerHTML 109 | let node = document.createElement('img') 110 | node.className = 'chr' 111 | node.src = `img/${name}.png` 112 | places[0].node.append(node) 113 | // 处理角色逻辑 114 | binding(node, name) 115 | }) 116 | }) 117 | // 开始游戏 118 | function gameStart() { 119 | choosechr.parentElement.style.display = "none" 120 | title.style.visibility = "visible" 121 | updatePlayer(players[s].name) 122 | writeInfo() 123 | placeInfo() 124 | person = players[0] 125 | } 126 | // # 界面显示相关 127 | 128 | // 掷骰区 129 | dice.addEventListener("click", () => { 130 | game() 131 | }) 132 | 133 | function rollDice(num) { // 掷骰子 134 | let bg = generateNum(1, 2) 135 | dice.style.background = `url(img/s${bg}.jpg)` 136 | setTimeout(function(){ 137 | dice.style.background = `url(img/${num}.jpg)` 138 | }, 300) 139 | toggleDice(false) 140 | } 141 | 142 | function toggleDice(state) { 143 | if (state) { 144 | dice.style.pointerEvents = "auto" 145 | } else { 146 | dice.style.pointerEvents = "none" 147 | } 148 | } 149 | 150 | // 游戏信息区 151 | 152 | // 当前行动玩家 153 | function updatePlayer(name) { 154 | title.innerHTML = name 155 | title.style.background = colorScheme[name] 156 | } 157 | // 当前回合数 158 | function updateRound() { 159 | let num = +document.querySelector('.big-box span b').innerHTML + 1 160 | document.querySelector('.big-box span b').innerHTML = num 161 | // if (num % 7 === 0) { // 每周新闻 // - 也许能插入随机的机会命运 162 | 163 | // } 164 | // if (num % 30 === 0) { // 发工资啦 165 | // let salary = 5000 * num / 30 166 | // players.forEach(player => { 167 | // player.money += salary 168 | // }) 169 | // updateInfo() 170 | // setTimeout(() => { 171 | // showMsgbox(`又到了每月的发薪日啦!每位玩家获得$${salary}`) 172 | // }, v * .5) 173 | // } 174 | } 175 | // 显示玩家信息 176 | function writeInfo() { 177 | let num = playerNumber + npcNumber 178 | for (let i = 0; i < num; i++) { 179 | let node = document.createElement('div') 180 | let h2 = document.createElement('h2') 181 | let h3 = document.createElement('h3') 182 | h3.innerHTML = `$${players[i].money}` 183 | h2.innerHTML = players[i].name 184 | h2.style.background = colorScheme[players[i].name] 185 | node.append(h3) 186 | node.append(h2) 187 | info.append(node) 188 | } 189 | } 190 | // 实时显示金钱 191 | function updateInfo() { 192 | let num = playerNumber + npcNumber 193 | for (let i = 0; i < num; i++) { 194 | info.children[i].firstElementChild.innerHTML = "$" + players[i].money 195 | } 196 | } 197 | // 判断后把角色挪走 198 | function updateBankrupt(node, index) { 199 | info.children[index].firstElementChild.style.display = "none" 200 | info.children[index].append(node) 201 | } 202 | 203 | // 提前隐藏区 204 | // 显示地皮归属 205 | function buyPlace(node, color) { 206 | node.style.boxShadow = `3px 3px 3px inset ${color},3px -3px 3px inset ${color},-3px 3px 3px inset ${color}, -3px -3px 3px inset ${color}` 207 | } 208 | // 显示造房动画 209 | function upgradeHouse(node, state) { 210 | let upgrade = construct() 211 | node.prepend(upgrade) 212 | setTimeout(() => { 213 | node.removeChild(upgrade) 214 | node.append(buidings(state)) 215 | gameSequence(s) 216 | }, 2000) 217 | } 218 | // 显示地产信息 219 | function placeInfo() { 220 | places.forEach(place => { 221 | place.node.addEventListener('mouseover', () => { 222 | if (place.state >= 0) { 223 | infobox.style.display = "block" 224 | infobox.firstElementChild.innerHTML = place.name 225 | infobox.lastElementChild.children[0].innerHTML = `地主:${place.owner}` 226 | infobox.lastElementChild.children[1].innerHTML = `价格:${place.value}` 227 | if (place.owner) { 228 | let state = 5 / (place.state * 3 + 1) 229 | let cost = place.value / (state > .5 ? Math.ceil(state) : state) 230 | infobox.lastElementChild.children[2].innerHTML = `住宿:${cost}` 231 | } else { 232 | infobox.lastElementChild.children[2].innerHTML = "" 233 | } 234 | } else { 235 | return 236 | } 237 | }) 238 | place.node.addEventListener('mouseout', () => { 239 | infobox.style.display = "none" 240 | }) 241 | }) 242 | } 243 | // 显示消息框 244 | function showMsgbox(msg){ 245 | msgbox.style.display = "block" 246 | msgbox.innerHTML = msg 247 | setTimeout(() => { 248 | msgbox.style.display = "none" 249 | },v * 1.6) 250 | } 251 | // 显示购买框 252 | function showDialog(type, allowButton) { 253 | dialog.style.display = 'block' 254 | let title, msg 255 | let {name, value, state} = places[person.position] 256 | if (type === "purchase") { 257 | title = "购买地产" 258 | msg = `请问你要花费$${value * (state + 1)}来购买${name}吗?` 259 | } else { 260 | title = "升级地产" 261 | msg = `请问你要花费$${value / 2}来升级${name}吗?` 262 | } 263 | dialog.children[1].innerHTML = title 264 | dialog.firstElementChild.innerHTML = msg 265 | if (allowButton) { 266 | dialog.children[2].style.pointerEvents = "auto" 267 | dialog.children[2].style.background = "#f2f2f2" 268 | } else { 269 | dialog.children[2].style.pointerEvents = "none" 270 | dialog.children[2].style.background = "#454545" 271 | } 272 | dialog.children[2].onclick = () => { // 确定按钮 273 | dialogClicked(type , true) 274 | } 275 | } 276 | dialog.children[3].addEventListener('click', () => { // 取消按钮 277 | dialogClicked("", false) 278 | }) 279 | // 关闭购买框 280 | function closeDialog() { 281 | dialog.style.display = "none" 282 | } 283 | 284 | 285 | // 设置区域 286 | document.querySelectorAll('.big-box button')[0].addEventListener('click', function() { // 开启指南 287 | if (this.innerHTML === "规则介绍") { 288 | this.innerHTML = "返回" 289 | document.querySelector('.instruction').style.height = "100%" 290 | } else { 291 | this.innerHTML = "规则介绍" 292 | document.querySelector('.instruction').style.height = "0" 293 | } 294 | }) 295 | document.querySelectorAll('.big-box button')[1].addEventListener('click', function() { // 设置速度 296 | let text = v > 600 ? '正常' : '加快' 297 | this.innerHTML = `${text}速度` 298 | v = 1300 - v 299 | }) 300 | document.querySelectorAll('.big-box button')[2].addEventListener('click', function() { // 托管 301 | if (this.innerHTML === "开启托管") { 302 | this.innerHTML = "取消托管" 303 | players.forEach(player => { 304 | if (player.control) { 305 | player.control = "" 306 | } 307 | }) 308 | } else { 309 | this.innerHTML = "开启托管" 310 | players.forEach(player => { 311 | if (player.control === "") { 312 | player.control = 1 313 | } 314 | }) 315 | } 316 | 317 | }) 318 | 319 | // 预加载图片 320 | window.addEventListener('load', () => { 321 | let images = [] 322 | let src = [ 323 | "img/arrow.png", "img/batman.png", "img/superman.png", "img/green lantern.png", "img/robin.png", "img/catwoman.png", "img/harley quinn.png", "img/joker.png", 324 | "img/1.jpg", "img/2.jpg", "img/3.jpg", "img/4.jpg", "img/5.jpg", "img/6.jpg", "img/s1.jpg", "img/s2.jpg", 325 | "img/c1.png", "img/c2.png", "img/c3.png", "img/c4.png", "img/c5.png", "img/l1.png", "img/l2.png", "img/l3.png" 326 | ] 327 | src.forEach((src, index) => { 328 | images[index] = new Image() 329 | images[index].src = src 330 | }) 331 | }) 332 | /* 333 | * @Author: Human Sean 334 | * @Email: humansean@qq.com 335 | * @Date: 2020-03-16 10:58:11 336 | * @LastEditTime: 2020-04-09 20:44:06 337 | * @Description: 所有的数据存放,包括角色棋子、棋格以及机会命运 338 | */ 339 | // 定义角色 340 | var players = [] 341 | function CreatePlayer(name, index, money, state, stop, control, node) { // 创建角色 342 | this.name = name // 名字 343 | this.index = index // 顺序 344 | this.money = money // 金钱 345 | this.state = state // 状态:活跃或破产 346 | this.stop = stop // 停止天数 347 | this.control = control // 是否玩家控制 348 | this.node = node // 对应DOM棋子 349 | this.position = 0 // 当前位置 350 | players.push(this) 351 | } 352 | // 棋格数据 353 | var places = [] 354 | function CreateBox(name, value, state, owner, index) { // 创建棋格 355 | this.name = name // 地名 356 | this.value = value // 价值 357 | this.state = state // 状态:特殊事件 / 普通地产的等级 358 | this.owner = owner // 有无地主 / 特殊棋格 359 | this.node = document.querySelectorAll('.map>div')[index] // 对应DOM 注:此处的index是乱序的,为了达到棋格顺时针排列的效果 360 | this.node.firstElementChild.append(name) // 顺手写入地名 361 | places.push(this) 362 | } 363 | new CreateBox("起点", 2000, "goodEvent", "sean", 18) 364 | new CreateBox("中国", 5000, 0, "", 19) 365 | new CreateBox("越南", 1000, 0, "", 20) 366 | new CreateBox("韩国", 1300, 0, "", 21) 367 | new CreateBox("机会", 1000, "surprise", "sean", 22) 368 | new CreateBox("日本", 3000, 0, "", 23) 369 | new CreateBox("俄罗斯", 4000, 0, "", 24) 370 | new CreateBox("白云机场", 1000, "airport", "sean", 25) 371 | new CreateBox("交所得税", 1000, "badEvent", "sean", 26) 372 | new CreateBox("命运", 1000, "surprise", "sean", 27) 373 | new CreateBox("埃及", 1600, 0, "", 28) 374 | new CreateBox("监狱", 0, "jail", "sean", 29) 375 | new CreateBox("澳大利亚", 2400, 0, "", 17) 376 | new CreateBox("新西兰", 1800, 0, "", 15) 377 | new CreateBox("南极洲", 20000, 0, "", 13) 378 | new CreateBox("赌场", 1000, "casino", "sean", 11) 379 | new CreateBox("机会", 1000, "surprise", "sean", 10) 380 | new CreateBox("捡到钱", 1000, "goodEvent", "sean", 9) 381 | new CreateBox("巴西", 2000, 0, "", 8) 382 | new CreateBox("阿根廷", 2200, 0, "", 7) 383 | new CreateBox("墨西哥", 2400, 0, "", 6) 384 | new CreateBox("美国", 4500, 0, "", 5) 385 | new CreateBox("意大利", 3000, 0, "", 4) 386 | new CreateBox("伦敦机场", 1000, "airport", "sean", 3) 387 | new CreateBox("英国", 3600, 0, "", 2) 388 | new CreateBox("命运", 1000, "surprise", "sean", 1) 389 | new CreateBox("阿尔卑斯山", 1000, "trip", "sean", 0) 390 | new CreateBox("德国", 3400, 0, "", 12) 391 | new CreateBox("法国", 3200, 0, "", 14) 392 | new CreateBox("西班牙", 2800, 0, "", 16) 393 | // 机会命运 394 | var fates = [] 395 | function CreateFate(text, value, stop) { // 创建机会命运 396 | this.text = text // 对应说明 397 | this.value = value // 金钱变动值 398 | this.stop = stop // 是否需要坐牢 399 | fates.push(this) 400 | } 401 | new CreateFate("扶老奶奶过马路的事迹被大家知道了,村委会颁发$1000奖金", 1000, 0) 402 | new CreateFate("中了彩票,获得头奖$5000", 5000, 0) 403 | new CreateFate("在街边被劫匪抢劫,为了保住性命,失去$3000", -3000, 0) 404 | new CreateFate("喝了一杯一点点,花费$30", -30, 0) 405 | new CreateFate("路边捡到$500", 500, 0) 406 | new CreateFate("吃鱼卡到鱼刺,去医院花了$800", -800, 0) 407 | new CreateFate("钱包落在出租车里,丢失$1000", -1000, 0) 408 | new CreateFate("空闲时间去兼职家教,收获$2000", 2000, 0) 409 | new CreateFate("扶老奶奶过马路摔了一跤,买药花了$100", -100, 0) 410 | new CreateFate("手机突然坏了,换了部最新款iPhone,花费$1300", -1300, 0) 411 | new CreateFate("吃羊肉火锅,花费$500", -500, 0) 412 | new CreateFate("去日本看樱花,花费$2000", -2000, 0) 413 | new CreateFate("什么也没有发生,除了钱包少了$800", -800, 0) 414 | new CreateFate("什么也没有发生, 除了钱包多了$1000", 1000, 0) 415 | new CreateFate("在广交会做翻译,获得$1000", 1000, 0) 416 | new CreateFate("在校门口发传单,得到$100", 100, 0) 417 | new CreateFate("获得三好学生奖学金,奖金$3000", 3000, 0) 418 | new CreateFate("抢了个微信红包,获得$1", 1, 0) 419 | new CreateFate("梦见得到$3000奖金,醒来决定花$50去拜神", -50, 0) 420 | new CreateFate("获得了$3000奖金!赶紧花$500去还愿", 2500, 0) 421 | new CreateFate("卖闲置赚了$100", 100, 0) 422 | new CreateFate("什么也没有发生", 0, 0) 423 | new CreateFate("看电影花费了$100", -100, 0) 424 | new CreateFate("还花呗欠款$999", -999, 0) 425 | new CreateFate("一年一度的双十一到了,剁手花了$2000", -2000, 0) 426 | new CreateFate("突然很渴想买瓶矿泉水,花费$5", -5, 0) 427 | new CreateFate("去工地搬砖赚了$500", 500, 0) 428 | new CreateFate("偷税漏税罚款$1000,拘留1日", -1000, 1) 429 | new CreateFate("超速行驶被罚款$2000,拘留2天", -2000, 2) 430 | new CreateFate("被查水表发现有违建,罚款$1000并拘留3日", -1000, 3) 431 | new CreateFate("考试作弊被拘留5日", 0, 5) 432 | /* 433 | * @Author: Human Sean 434 | * @Email: humansean@qq.com 435 | * @Date: 2020-03-16 10:58:11 436 | * @LastEditTime: 2020-04-09 21:28:45 437 | * @Description: 完成游戏开局前的初始化 438 | */ 439 | var s = 0 // 初始化玩家顺序 / sequence 440 | var playerNumber = 0 // 玩家数量 441 | var npcNumber = 0 // npc数量 442 | var startMoney = 0 // 初始化金钱 443 | var v = 800 // 初始速度 444 | var person // 初始化当前玩家 445 | var colorScheme = { // 不同角色对应颜色方案 446 | "Joker": "#5E45AB", 447 | "Batman": "#121212", 448 | "Superman": "#274D7A", 449 | "Catwoman": "#B04E58", 450 | "Harley Quinn": "pink", 451 | "Robin": "#FA2A14", 452 | "Green Lantern": "#5FAE2E" 453 | } 454 | 455 | function chooseNumber(num) { // 选择配置 456 | if (!startMoney) { // 选择起始金钱 457 | writeSetting("玩家人数", 1) 458 | startMoney = num * 5000 + 10000 459 | } else if (!playerNumber) { // 选择玩家数量 460 | writeSetting("电脑人数", 0, num) 461 | playerNumber = +num + 1 462 | } else { // 选择npc数量 463 | npcNumber = +num 464 | finishChooseNumber() 465 | } 466 | } 467 | function binding(node, name){ // 角色选择 468 | let control = players.length < playerNumber ? 1 : 0 // 玩家还是电脑控制 469 | new CreatePlayer(name, players.length, startMoney, "active", 0, control, node) // 创建一个人物 470 | if (players.length == (playerNumber + npcNumber)) { // 游戏开局 471 | gameStart() 472 | } 473 | } 474 | /* 475 | * @Author: Human Sean 476 | * @Email: humansean@qq.com 477 | * @Date: 2020-03-16 10:58:11 478 | * @LastEditTime: 2020-04-09 21:32:19 479 | * @Description: 大富翁的核心逻辑处理 480 | */ 481 | // 轮骰顺序 482 | function gameSequence(index){ 483 | if (index === (playerNumber + npcNumber) - 1) { // 从最后一位玩家到第一位玩家 484 | index = 0 485 | updateRound() 486 | } else { // 下一位玩家 487 | index ++ 488 | } 489 | 490 | setTimeout(() => { 491 | if (!checkPlayerState(index)) { // 检查下一位玩家状态:false的话就继续轮骰 492 | gameSequence(index) 493 | } 494 | }, v) 495 | 496 | } 497 | 498 | function playerMove(index) { // 角色移动一步 499 | if (person.position === 29) { 500 | person.position = -1 501 | places[0].node.append(players[index].node) 502 | updateInfo() 503 | players[index].money += 1000 504 | } 505 | person.position ++ 506 | places[person.position].node.append(players[index].node) 507 | } 508 | 509 | function game(){ // 掷筛到动作完成 510 | //骰子点数显示 511 | let num = generateNum(1, 6) 512 | rollDice(num) 513 | //绑定对应角色 514 | person = players[s] 515 | let move = setInterval(() => { // 角色按速度间隔向下一个棋格移动 516 | playerMove(s) 517 | }, v) 518 | 519 | setTimeout(() => { // 停下后触发棋格事件 520 | clearInterval(move) // 停止移动 521 | let place = places[person.position] 522 | // 买地产 // - 涉及异步 523 | if (!place.owner) { // 该地产没有地主 524 | if(person.control){ // 玩家角色才出现选择框 525 | showDialog("purchase", person.money > place.value) 526 | } else { // NPC行为,买了后还有3000保底才决定买 527 | setTimeout(() => dialogClicked("purchase", (person.money - place.value) > 3000), v / 3) 528 | } 529 | } else if (place.owner && place.owner !== person.name && place.owner != "sean") { // 住房:存在地主且不属于本人或特殊区域 530 | let owner = players.find(player => player.name === place.owner) // 找到主人 531 | if(owner.stop){ // 主人不在家 532 | showMsgbox("房子主人不在,免费过夜1晚!") 533 | } else{ // 付地租 534 | let state = 5 / (place.state * 3 + 1) // 5 / (1 4 7 10) 535 | let cost = place.value / (state > .5 ? Math.ceil(state) : state) // 根据地产等级计算房租 536 | person.money -= cost 537 | owner.money += cost 538 | showMsgbox(`${owner.name}感谢${person.name}在${place.name}消费$${cost}`) 539 | checkBankrupt() 540 | } 541 | gameSequence(s) 542 | } else if (place.owner === person.name) { // 升级房子 // - 涉及异步 543 | if (place.state === 3) { 544 | gameSequence(s) 545 | } else { 546 | if(person.control){ // 玩家控制 547 | showDialog("upgrade", person.money > place.value * .5) 548 | } else { // NPC行为 549 | dialogClicked("upgrade", (person.money - place.value / 2) > 2000) // 大于3000块保底才升级 550 | } 551 | } 552 | } else if (place.state === "goodEvent") { // 捡到钱 553 | let randomMoney = 500 * generateNum(0, 7) 554 | person.money += randomMoney 555 | showMsgbox(`恭喜你捡到了$${randomMoney}`) 556 | gameSequence(s) 557 | } else if (place.state === "badEvent") { // 交税 558 | let randomMoney = 300 * generateNum(0, 7) 559 | person.money -= randomMoney 560 | showMsgbox(`你需要向税务局缴纳税收$${randomMoney}`) 561 | checkBankrupt() 562 | gameSequence(s) 563 | } else if (place.state === "jail") { 564 | person.stop = generateNum(1, 3) 565 | showMsgbox(`偷税漏税被抓,关押${person.stop}天`) 566 | gameSequence(s) 567 | } else if (place.state === "casino") { 568 | let num = generateNum(1, 6) 569 | rollDice(num) 570 | setTimeout(() => { 571 | let casinoMoney = num * 500 572 | person.money += casinoMoney 573 | showMsgbox(`恭喜你获得了$${casinoMoney}`) 574 | updateInfo() 575 | gameSequence(s) 576 | }, v * 2) 577 | // toggleDice(true) 578 | } else if (place.state === "surprise") { // 机会命运 // - 涉及异步 579 | var event = generateNum(0, 31) 580 | person.money += fates[event].value 581 | // 坐牢事件 582 | if (fates[event].stop){ 583 | setTimeout(function(){ 584 | person.position = 11 585 | person.stop = fates[event].stop 586 | places[11].node.append(person.node) 587 | checkBankrupt() 588 | gameSequence(s) 589 | },v * 1.5) 590 | } else { 591 | checkBankrupt() 592 | gameSequence(s) 593 | } 594 | showMsgbox(fates[event].text) 595 | } else if (place.state === "airport") { // 飞机 // - 涉及异步 596 | let des = place.name === "白云机场" ? "英国" : "中国" 597 | showMsgbox(`你花费$800搭乘飞机前往${des}`) 598 | setTimeout(() => { 599 | person.position = 30 - person.position 600 | places[person.position].node.append(person.node) 601 | checkBankrupt() 602 | gameSequence(s) 603 | },v * 1.5) 604 | person.money -= 800 605 | } else if (place.state === "trip") { // 旅游度假 606 | person.stop = generateNum(1, 3) 607 | person.money -= person.stop * 1000 608 | showMsgbox(`${person.name}花费${person.stop * 1000}享受旅游度假${person.stop}天`) 609 | checkBankrupt() 610 | gameSequence(s) 611 | } 612 | updateInfo() 613 | },v * (num + 0.9)) 614 | } 615 | 616 | function dialogClicked(type, action) { // 购买或取消 617 | let place = places[person.position] 618 | if (!action) { // 关闭对话框: 通过action模拟NPC购买与否 619 | closeDialog() 620 | gameSequence(s) 621 | return 622 | } 623 | if (type === "purchase") { // 购买 624 | place.owner = person.name // 房产证署名 625 | person.money -= place.value // 交钱 626 | let color = colorScheme[person.name] 627 | buyPlace(place.node, color) // 显示地皮归属 628 | showMsgbox(`恭喜你获得了${place.name}`) 629 | gameSequence(s) 630 | } else { // 升级 631 | let upgradeMap = ["一座小房子", "一套大别墅", "一栋大酒店"] 632 | person.money -= place.value / 2 633 | place.state ++ 634 | showMsgbox(`恭喜你在${place.name}建了${upgradeMap[place.state - 1]}`) 635 | // 造房动画效果 636 | upgradeHouse(place.node, place.state - 1) 637 | } 638 | closeDialog() 639 | updateInfo() 640 | } 641 | 642 | function generateNum(min, max) { // 生成随机数 643 | return Math.floor(Math.random() * (max - min)) + min 644 | } 645 | 646 | // 判断相关 647 | // 判断轮到的下个玩家是否处在停止状态 648 | function checkPlayerState(index) { 649 | let player = players[index] 650 | if (player.stop) { // 停止状态 651 | if (player.position === 11) { 652 | showMsgbox(`${player.name}还有${player.stop}天可以出狱`) 653 | } else { 654 | showMsgbox(`${player.name}离难得的假期结束还有${player.stop}天`) 655 | } 656 | player.stop -- 657 | return false 658 | } else if (player.state === "bankrupt") { 659 | return false 660 | } else { 661 | if (!player.control) { // NPC行动的地方 662 | setTimeout(() => { 663 | game() 664 | },v*2) 665 | } else { // 解锁骰子,玩家行动 666 | toggleDice(true) 667 | } 668 | // 轮到下一玩家 669 | s = index 670 | updatePlayer(player.name) 671 | return true 672 | } 673 | } 674 | // 判断胜利条件 675 | function checkFinish(){ 676 | let count = 0 677 | let winner 678 | players.forEach(player => { // 数还有多少人处于活跃状态 679 | if (player.state === "active") { 680 | count ++ 681 | winner = player 682 | } 683 | }) 684 | if (count === 1) { // 只有一个人活跃的话 685 | setTimeout(() => { 686 | alert(`${winner.name}赢啦!恭喜你成为最有钱的人!`) 687 | location.reload() 688 | }, v * 2) 689 | } 690 | } 691 | // 判断破产 692 | function checkBankrupt() { 693 | if (person.money < 0) { // 当前玩家的钱变成负值了 694 | setTimeout(() => { 695 | person.stop = 0 696 | person.state = "bankrupt" 697 | alert(`很遗憾,${person.name}破产了,所有地产将充公处理。`) 698 | updateBankrupt(person.node, players.indexOf(person)) 699 | places.forEach(place => { // 地产充公 700 | if (place.owner === person.name) { 701 | place.owner = "" 702 | place.node.style.boxShadow = "1px 1px 1px inset #454545, 1px -1px 1px inset #454545, -1px 1px 1px inset #454545, -1px -1px 1px inset #454545" 703 | } 704 | }) 705 | checkFinish() // 每当有人破产就判断是否结束 706 | }, v / 2) 707 | } 708 | } -------------------------------------------------------------------------------- /src/js/data.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @Author: Human Sean 3 | * @Email: humansean@qq.com 4 | * @Date: 2020-03-16 10:58:11 5 | * @LastEditTime: 2020-04-09 20:44:06 6 | * @Description: 所有的数据存放,包括角色棋子、棋格以及机会命运 7 | */ 8 | // 定义角色 9 | var players = [] 10 | function CreatePlayer(name, index, money, state, stop, control, node) { // 创建角色 11 | this.name = name // 名字 12 | this.index = index // 顺序 13 | this.money = money // 金钱 14 | this.state = state // 状态:活跃或破产 15 | this.stop = stop // 停止天数 16 | this.control = control // 是否玩家控制 17 | this.node = node // 对应DOM棋子 18 | this.position = 0 // 当前位置 19 | players.push(this) 20 | } 21 | // 棋格数据 22 | var places = [] 23 | function CreateBox(name, value, state, owner, index) { // 创建棋格 24 | this.name = name // 地名 25 | this.value = value // 价值 26 | this.state = state // 状态:特殊事件 / 普通地产的等级 27 | this.owner = owner // 有无地主 / 特殊棋格 28 | this.node = document.querySelectorAll('.map>div')[index] // 对应DOM 注:此处的index是乱序的,为了达到棋格顺时针排列的效果 29 | this.node.firstElementChild.append(name) // 顺手写入地名 30 | places.push(this) 31 | } 32 | new CreateBox("起点", 2000, "goodEvent", "sean", 18) 33 | new CreateBox("中国", 5000, 0, "", 19) 34 | new CreateBox("越南", 1000, 0, "", 20) 35 | new CreateBox("韩国", 1300, 0, "", 21) 36 | new CreateBox("机会", 1000, "surprise", "sean", 22) 37 | new CreateBox("日本", 3000, 0, "", 23) 38 | new CreateBox("俄罗斯", 4000, 0, "", 24) 39 | new CreateBox("白云机场", 1000, "airport", "sean", 25) 40 | new CreateBox("交所得税", 1000, "badEvent", "sean", 26) 41 | new CreateBox("命运", 1000, "surprise", "sean", 27) 42 | new CreateBox("埃及", 1600, 0, "", 28) 43 | new CreateBox("监狱", 0, "jail", "sean", 29) 44 | new CreateBox("澳大利亚", 2400, 0, "", 17) 45 | new CreateBox("新西兰", 1800, 0, "", 15) 46 | new CreateBox("南极洲", 20000, 0, "", 13) 47 | new CreateBox("赌场", 1000, "casino", "sean", 11) 48 | new CreateBox("机会", 1000, "surprise", "sean", 10) 49 | new CreateBox("捡到钱", 1000, "goodEvent", "sean", 9) 50 | new CreateBox("巴西", 2000, 0, "", 8) 51 | new CreateBox("阿根廷", 2200, 0, "", 7) 52 | new CreateBox("墨西哥", 2400, 0, "", 6) 53 | new CreateBox("美国", 4500, 0, "", 5) 54 | new CreateBox("意大利", 3000, 0, "", 4) 55 | new CreateBox("伦敦机场", 1000, "airport", "sean", 3) 56 | new CreateBox("英国", 3600, 0, "", 2) 57 | new CreateBox("命运", 1000, "surprise", "sean", 1) 58 | new CreateBox("阿尔卑斯山", 1000, "trip", "sean", 0) 59 | new CreateBox("德国", 3400, 0, "", 12) 60 | new CreateBox("法国", 3200, 0, "", 14) 61 | new CreateBox("西班牙", 2800, 0, "", 16) 62 | // 机会命运 63 | var fates = [] 64 | function CreateFate(text, value, stop) { // 创建机会命运 65 | this.text = text // 对应说明 66 | this.value = value // 金钱变动值 67 | this.stop = stop // 是否需要坐牢 68 | fates.push(this) 69 | } 70 | new CreateFate("扶老奶奶过马路的事迹被大家知道了,村委会颁发$1000奖金", 1000, 0) 71 | new CreateFate("中了彩票,获得头奖$5000", 5000, 0) 72 | new CreateFate("在街边被劫匪抢劫,为了保住性命,失去$3000", -3000, 0) 73 | new CreateFate("喝了一杯一点点,花费$30", -30, 0) 74 | new CreateFate("路边捡到$500", 500, 0) 75 | new CreateFate("吃鱼卡到鱼刺,去医院花了$800", -800, 0) 76 | new CreateFate("钱包落在出租车里,丢失$1000", -1000, 0) 77 | new CreateFate("空闲时间去兼职家教,收获$2000", 2000, 0) 78 | new CreateFate("扶老奶奶过马路摔了一跤,买药花了$100", -100, 0) 79 | new CreateFate("手机突然坏了,换了部最新款iPhone,花费$1300", -1300, 0) 80 | new CreateFate("吃羊肉火锅,花费$500", -500, 0) 81 | new CreateFate("去日本看樱花,花费$2000", -2000, 0) 82 | new CreateFate("什么也没有发生,除了钱包少了$800", -800, 0) 83 | new CreateFate("什么也没有发生, 除了钱包多了$1000", 1000, 0) 84 | new CreateFate("在广交会做翻译,获得$1000", 1000, 0) 85 | new CreateFate("在校门口发传单,得到$100", 100, 0) 86 | new CreateFate("获得三好学生奖学金,奖金$3000", 3000, 0) 87 | new CreateFate("抢了个微信红包,获得$1", 1, 0) 88 | new CreateFate("梦见得到$3000奖金,醒来决定花$50去拜神", -50, 0) 89 | new CreateFate("获得了$3000奖金!赶紧花$500去还愿", 2500, 0) 90 | new CreateFate("卖闲置赚了$100", 100, 0) 91 | new CreateFate("什么也没有发生", 0, 0) 92 | new CreateFate("看电影花费了$100", -100, 0) 93 | new CreateFate("还花呗欠款$999", -999, 0) 94 | new CreateFate("一年一度的双十一到了,剁手花了$2000", -2000, 0) 95 | new CreateFate("突然很渴想买瓶矿泉水,花费$5", -5, 0) 96 | new CreateFate("去工地搬砖赚了$500", 500, 0) 97 | new CreateFate("偷税漏税罚款$1000,拘留1日", -1000, 1) 98 | new CreateFate("超速行驶被罚款$2000,拘留2天", -2000, 2) 99 | new CreateFate("被查水表发现有违建,罚款$1000并拘留3日", -1000, 3) 100 | new CreateFate("考试作弊被拘留5日", 0, 5) -------------------------------------------------------------------------------- /src/js/dom-binding.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @Author: Human Sean 3 | * @Email: humansean@qq.com 4 | * @Date: 2020-04-09 14:26:45 5 | * @LastEditTime: 2020-04-11 17:46:01 6 | * @Description: 一切跟DOM有关的操作 7 | */ 8 | // 快捷编号 9 | var map = document.querySelector('.map') 10 | var dice = document.querySelector(".dice") 11 | var choosebox = document.querySelector(".choosebox") 12 | var choosechr = document.querySelector(".choosechr") 13 | var title = document.querySelector(".title") 14 | var info = document.querySelector('.info') 15 | var dialog = document.querySelector(".dialog") 16 | var infobox = document.querySelector(".infobox") 17 | var msgbox = document.querySelector(".msgbox") 18 | // 创建升级造房动画 19 | function construct() { 20 | let construct = document.createElement('div') 21 | construct.className = 'construct' 22 | for (let i = 0; i < 5; i++) { 23 | const img = document.createElement('img') 24 | img.src = `img/c${i + 1}.png` 25 | construct.append(img) 26 | } 27 | return construct 28 | } 29 | // 创建升级的房子 30 | function buidings(index) { 31 | let img = document.createElement('img') 32 | img.src = `img/l${index + 1}.png` 33 | img.className = 'house' 34 | return img 35 | } 36 | // 写入地图棋格 37 | for (let i = 0; i < 30; i++) { 38 | let box = document.createElement('div') 39 | let h3 = document.createElement('h3') 40 | box.className = 'box' 41 | box.append(h3) 42 | map.prepend(box) 43 | } 44 | // 绑定选择 45 | Array.from(document.querySelectorAll('.choosebox li')).forEach((node, index) => { 46 | node.addEventListener('click', () => { 47 | chooseNumber(index) 48 | }) 49 | }) 50 | // 更改选择配置时的DOM显示 51 | function writeSetting(title, startNum, num) { 52 | choosebox.firstElementChild.innerHTML = title 53 | Array.from(choosebox.lastElementChild.children).forEach((node, index) => { 54 | node.innerHTML = startNum + index 55 | switch (num) { 56 | case 3: 57 | finishChooseNumber() 58 | break 59 | case 2: 60 | if (index > 1) { 61 | disableBox(node) 62 | } 63 | break 64 | case 1: 65 | if (index > 2) { 66 | disableBox(node) 67 | } 68 | break 69 | case 0: 70 | if (index < 1) { 71 | disableBox(node) 72 | } 73 | break 74 | } 75 | }) 76 | } 77 | // 禁用选框,避免人数总和大于四 78 | function disableBox(node) { 79 | node.style.pointerEvents = "none" 80 | node.style.background = "grey" 81 | } 82 | // 结束人数选择,开启角色选择,并画上地图 83 | function finishChooseNumber() { 84 | choosebox.style.display = "none" 85 | choosechr.style.display = "block" 86 | } 87 | // 创造复用的箭头 88 | let arrow = document.createElement('div') 89 | arrow.className = 'arrow' 90 | let img = document.createElement('img') 91 | img.src = "img/arrow.png" 92 | arrow.append(img) 93 | // 选择角色 94 | Array.from(choosechr.lastElementChild.children).forEach(item => { 95 | item.firstElementChild.addEventListener('mouseover', function(){ // 下标箭头 96 | item.appendChild(arrow) 97 | }) 98 | item.firstElementChild.addEventListener('click', () => { // 绑定角色 99 | // 处理选中效果 100 | item.firstElementChild.style.border = "1px solid #666" 101 | let index = document.createElement('div') 102 | index.innerHTML = `${players.length + 1}` 103 | index.className = 'index' 104 | item.appendChild(index) 105 | item.removeChild(arrow) 106 | item.style.pointerEvents = "none" 107 | // 创建角色对应棋子 108 | let name = item.children[1].innerHTML 109 | let node = document.createElement('img') 110 | node.className = 'chr' 111 | node.src = `img/${name}.png` 112 | places[0].node.append(node) 113 | // 处理角色逻辑 114 | binding(node, name) 115 | }) 116 | }) 117 | // 开始游戏 118 | function gameStart() { 119 | choosechr.parentElement.style.display = "none" 120 | title.style.visibility = "visible" 121 | updatePlayer(players[s].name) 122 | writeInfo() 123 | placeInfo() 124 | person = players[0] 125 | } 126 | // # 界面显示相关 127 | 128 | // 掷骰区 129 | dice.addEventListener("click", () => { 130 | game() 131 | }) 132 | 133 | function rollDice(num) { // 掷骰子 134 | let bg = generateNum(1, 2) 135 | dice.style.background = `url(img/s${bg}.jpg)` 136 | setTimeout(function(){ 137 | dice.style.background = `url(img/${num}.jpg)` 138 | }, 300) 139 | toggleDice(false) 140 | } 141 | 142 | function toggleDice(state) { 143 | if (state) { 144 | dice.style.pointerEvents = "auto" 145 | } else { 146 | dice.style.pointerEvents = "none" 147 | } 148 | } 149 | 150 | // 游戏信息区 151 | 152 | // 当前行动玩家 153 | function updatePlayer(name) { 154 | title.innerHTML = name 155 | title.style.background = colorScheme[name] 156 | } 157 | // 当前回合数 158 | function updateRound() { 159 | let num = +document.querySelector('.big-box span b').innerHTML + 1 160 | document.querySelector('.big-box span b').innerHTML = num 161 | // if (num % 7 === 0) { // 每周新闻 // - 也许能插入随机的机会命运 162 | 163 | // } 164 | // if (num % 30 === 0) { // 发工资啦 165 | // let salary = 5000 * num / 30 166 | // players.forEach(player => { 167 | // player.money += salary 168 | // }) 169 | // updateInfo() 170 | // setTimeout(() => { 171 | // showMsgbox(`又到了每月的发薪日啦!每位玩家获得$${salary}`) 172 | // }, v * .5) 173 | // } 174 | } 175 | // 显示玩家信息 176 | function writeInfo() { 177 | let num = playerNumber + npcNumber 178 | for (let i = 0; i < num; i++) { 179 | let node = document.createElement('div') 180 | let h2 = document.createElement('h2') 181 | let h3 = document.createElement('h3') 182 | h3.innerHTML = `$${players[i].money}` 183 | h2.innerHTML = players[i].name 184 | h2.style.background = colorScheme[players[i].name] 185 | node.append(h3) 186 | node.append(h2) 187 | info.append(node) 188 | } 189 | } 190 | // 实时显示金钱 191 | function updateInfo() { 192 | let num = playerNumber + npcNumber 193 | for (let i = 0; i < num; i++) { 194 | info.children[i].firstElementChild.innerHTML = "$" + players[i].money 195 | } 196 | } 197 | // 判断后把角色挪走 198 | function updateBankrupt(node, index) { 199 | info.children[index].firstElementChild.style.display = "none" 200 | info.children[index].append(node) 201 | } 202 | 203 | // 提前隐藏区 204 | // 显示地皮归属 205 | function buyPlace(node, color) { 206 | node.style.boxShadow = `3px 3px 3px inset ${color},3px -3px 3px inset ${color},-3px 3px 3px inset ${color}, -3px -3px 3px inset ${color}` 207 | } 208 | // 显示造房动画 209 | function upgradeHouse(node, state) { 210 | let upgrade = construct() 211 | node.prepend(upgrade) 212 | setTimeout(() => { 213 | node.removeChild(upgrade) 214 | node.append(buidings(state)) 215 | gameSequence(s) 216 | }, 2000) 217 | } 218 | // 显示地产信息 219 | function placeInfo() { 220 | places.forEach(place => { 221 | place.node.addEventListener('mouseover', () => { 222 | if (place.state >= 0) { 223 | infobox.style.display = "block" 224 | infobox.firstElementChild.innerHTML = place.name 225 | infobox.lastElementChild.children[0].innerHTML = `地主:${place.owner}` 226 | infobox.lastElementChild.children[1].innerHTML = `价格:${place.value}` 227 | if (place.owner) { 228 | let state = 5 / (place.state * 3 + 1) 229 | let cost = place.value / (state > .5 ? Math.ceil(state) : state) 230 | infobox.lastElementChild.children[2].innerHTML = `住宿:${cost}` 231 | } else { 232 | infobox.lastElementChild.children[2].innerHTML = "" 233 | } 234 | } else { 235 | return 236 | } 237 | }) 238 | place.node.addEventListener('mouseout', () => { 239 | infobox.style.display = "none" 240 | }) 241 | }) 242 | } 243 | // 显示消息框 244 | function showMsgbox(msg){ 245 | msgbox.style.display = "block" 246 | msgbox.innerHTML = msg 247 | setTimeout(() => { 248 | msgbox.style.display = "none" 249 | },v * 1.6) 250 | } 251 | // 显示购买框 252 | function showDialog(type, allowButton) { 253 | dialog.style.display = 'block' 254 | let title, msg 255 | let {name, value, state} = places[person.position] 256 | if (type === "purchase") { 257 | title = "购买地产" 258 | msg = `请问你要花费$${value * (state + 1)}来购买${name}吗?` 259 | } else { 260 | title = "升级地产" 261 | msg = `请问你要花费$${value / 2}来升级${name}吗?` 262 | } 263 | dialog.children[1].innerHTML = title 264 | dialog.firstElementChild.innerHTML = msg 265 | if (allowButton) { 266 | dialog.children[2].style.pointerEvents = "auto" 267 | dialog.children[2].style.background = "#f2f2f2" 268 | } else { 269 | dialog.children[2].style.pointerEvents = "none" 270 | dialog.children[2].style.background = "#454545" 271 | } 272 | dialog.children[2].onclick = () => { // 确定按钮 273 | dialogClicked(type , true) 274 | } 275 | } 276 | dialog.children[3].addEventListener('click', () => { // 取消按钮 277 | dialogClicked("", false) 278 | }) 279 | // 关闭购买框 280 | function closeDialog() { 281 | dialog.style.display = "none" 282 | } 283 | 284 | 285 | // 设置区域 286 | document.querySelectorAll('.big-box button')[0].addEventListener('click', function() { // 开启指南 287 | if (this.innerHTML === "规则介绍") { 288 | this.innerHTML = "返回" 289 | document.querySelector('.instruction').style.height = "100%" 290 | } else { 291 | this.innerHTML = "规则介绍" 292 | document.querySelector('.instruction').style.height = "0" 293 | } 294 | }) 295 | document.querySelectorAll('.big-box button')[1].addEventListener('click', function() { // 设置速度 296 | let text = v > 600 ? '正常' : '加快' 297 | this.innerHTML = `${text}速度` 298 | v = 1300 - v 299 | }) 300 | document.querySelectorAll('.big-box button')[2].addEventListener('click', function() { // 托管 301 | if (this.innerHTML === "开启托管") { 302 | this.innerHTML = "取消托管" 303 | players.forEach(player => { 304 | if (player.control) { 305 | player.control = "" 306 | } 307 | }) 308 | } else { 309 | this.innerHTML = "开启托管" 310 | players.forEach(player => { 311 | if (player.control === "") { 312 | player.control = 1 313 | } 314 | }) 315 | } 316 | 317 | }) 318 | 319 | // 预加载图片 320 | window.addEventListener('load', () => { 321 | let images = [] 322 | let src = [ 323 | "img/arrow.png", "img/batman.png", "img/superman.png", "img/green lantern.png", "img/robin.png", "img/catwoman.png", "img/harley quinn.png", "img/joker.png", 324 | "img/1.jpg", "img/2.jpg", "img/3.jpg", "img/4.jpg", "img/5.jpg", "img/6.jpg", "img/s1.jpg", "img/s2.jpg", 325 | "img/c1.png", "img/c2.png", "img/c3.png", "img/c4.png", "img/c5.png", "img/l1.png", "img/l2.png", "img/l3.png" 326 | ] 327 | src.forEach((src, index) => { 328 | images[index] = new Image() 329 | images[index].src = src 330 | }) 331 | }) -------------------------------------------------------------------------------- /src/js/initializing.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @Author: Human Sean 3 | * @Email: humansean@qq.com 4 | * @Date: 2020-03-16 10:58:11 5 | * @LastEditTime: 2020-04-09 21:28:45 6 | * @Description: 完成游戏开局前的初始化 7 | */ 8 | var s = 0 // 初始化玩家顺序 / sequence 9 | var playerNumber = 0 // 玩家数量 10 | var npcNumber = 0 // npc数量 11 | var startMoney = 0 // 初始化金钱 12 | var v = 800 // 初始速度 13 | var person // 初始化当前玩家 14 | var colorScheme = { // 不同角色对应颜色方案 15 | "Joker": "#5E45AB", 16 | "Batman": "#121212", 17 | "Superman": "#274D7A", 18 | "Catwoman": "#B04E58", 19 | "Harley Quinn": "pink", 20 | "Robin": "#FA2A14", 21 | "Green Lantern": "#5FAE2E" 22 | } 23 | 24 | function chooseNumber(num) { // 选择配置 25 | if (!startMoney) { // 选择起始金钱 26 | writeSetting("玩家人数", 1) 27 | startMoney = num * 5000 + 10000 28 | } else if (!playerNumber) { // 选择玩家数量 29 | writeSetting("电脑人数", 0, num) 30 | playerNumber = +num + 1 31 | } else { // 选择npc数量 32 | npcNumber = +num 33 | finishChooseNumber() 34 | } 35 | } 36 | function binding(node, name){ // 角色选择 37 | let control = players.length < playerNumber ? 1 : 0 // 玩家还是电脑控制 38 | new CreatePlayer(name, players.length, startMoney, "active", 0, control, node) // 创建一个人物 39 | if (players.length == (playerNumber + npcNumber)) { // 游戏开局 40 | gameStart() 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/js/monopoly.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @Author: Human Sean 3 | * @Email: humansean@qq.com 4 | * @Date: 2020-03-16 10:58:11 5 | * @LastEditTime: 2020-04-09 21:32:19 6 | * @Description: 大富翁的核心逻辑处理 7 | */ 8 | // 轮骰顺序 9 | function gameSequence(index){ 10 | if (index === (playerNumber + npcNumber) - 1) { // 从最后一位玩家到第一位玩家 11 | index = 0 12 | updateRound() 13 | } else { // 下一位玩家 14 | index ++ 15 | } 16 | 17 | setTimeout(() => { 18 | if (!checkPlayerState(index)) { // 检查下一位玩家状态:false的话就继续轮骰 19 | gameSequence(index) 20 | } 21 | }, v) 22 | 23 | } 24 | 25 | function playerMove(index) { // 角色移动一步 26 | if (person.position === 29) { 27 | person.position = -1 28 | places[0].node.append(players[index].node) 29 | updateInfo() 30 | players[index].money += 1000 31 | } 32 | person.position ++ 33 | places[person.position].node.append(players[index].node) 34 | } 35 | 36 | function game(){ // 掷筛到动作完成 37 | //骰子点数显示 38 | let num = generateNum(1, 6) 39 | rollDice(num) 40 | //绑定对应角色 41 | person = players[s] 42 | let move = setInterval(() => { // 角色按速度间隔向下一个棋格移动 43 | playerMove(s) 44 | }, v) 45 | 46 | setTimeout(() => { // 停下后触发棋格事件 47 | clearInterval(move) // 停止移动 48 | let place = places[person.position] 49 | // 买地产 // - 涉及异步 50 | if (!place.owner) { // 该地产没有地主 51 | if(person.control){ // 玩家角色才出现选择框 52 | showDialog("purchase", person.money > place.value) 53 | } else { // NPC行为,买了后还有3000保底才决定买 54 | setTimeout(() => dialogClicked("purchase", (person.money - place.value) > 3000), v / 3) 55 | } 56 | } else if (place.owner && place.owner !== person.name && place.owner != "sean") { // 住房:存在地主且不属于本人或特殊区域 57 | let owner = players.find(player => player.name === place.owner) // 找到主人 58 | if(owner.stop){ // 主人不在家 59 | showMsgbox("房子主人不在,免费过夜1晚!") 60 | } else{ // 付地租 61 | let state = 5 / (place.state * 3 + 1) // 5 / (1 4 7 10) 62 | let cost = place.value / (state > .5 ? Math.ceil(state) : state) // 根据地产等级计算房租 63 | person.money -= cost 64 | owner.money += cost 65 | showMsgbox(`${owner.name}感谢${person.name}在${place.name}消费$${cost}`) 66 | checkBankrupt() 67 | } 68 | gameSequence(s) 69 | } else if (place.owner === person.name) { // 升级房子 // - 涉及异步 70 | if (place.state === 3) { 71 | gameSequence(s) 72 | } else { 73 | if(person.control){ // 玩家控制 74 | showDialog("upgrade", person.money > place.value * .5) 75 | } else { // NPC行为 76 | dialogClicked("upgrade", (person.money - place.value / 2) > 2000) // 大于3000块保底才升级 77 | } 78 | } 79 | } else if (place.state === "goodEvent") { // 捡到钱 80 | let randomMoney = 500 * generateNum(0, 7) 81 | person.money += randomMoney 82 | showMsgbox(`恭喜你捡到了$${randomMoney}`) 83 | gameSequence(s) 84 | } else if (place.state === "badEvent") { // 交税 85 | let randomMoney = 300 * generateNum(0, 7) 86 | person.money -= randomMoney 87 | showMsgbox(`你需要向税务局缴纳税收$${randomMoney}`) 88 | checkBankrupt() 89 | gameSequence(s) 90 | } else if (place.state === "jail") { 91 | person.stop = generateNum(1, 3) 92 | showMsgbox(`偷税漏税被抓,关押${person.stop}天`) 93 | gameSequence(s) 94 | } else if (place.state === "casino") { 95 | let num = generateNum(1, 6) 96 | rollDice(num) 97 | setTimeout(() => { 98 | let casinoMoney = num * 500 99 | person.money += casinoMoney 100 | showMsgbox(`恭喜你获得了$${casinoMoney}`) 101 | updateInfo() 102 | gameSequence(s) 103 | }, v * 2) 104 | // toggleDice(true) 105 | } else if (place.state === "surprise") { // 机会命运 // - 涉及异步 106 | var event = generateNum(0, 31) 107 | person.money += fates[event].value 108 | // 坐牢事件 109 | if (fates[event].stop){ 110 | setTimeout(function(){ 111 | person.position = 11 112 | person.stop = fates[event].stop 113 | places[11].node.append(person.node) 114 | checkBankrupt() 115 | gameSequence(s) 116 | },v * 1.5) 117 | } else { 118 | checkBankrupt() 119 | gameSequence(s) 120 | } 121 | showMsgbox(fates[event].text) 122 | } else if (place.state === "airport") { // 飞机 // - 涉及异步 123 | let des = place.name === "白云机场" ? "英国" : "中国" 124 | showMsgbox(`你花费$800搭乘飞机前往${des}`) 125 | setTimeout(() => { 126 | person.position = 30 - person.position 127 | places[person.position].node.append(person.node) 128 | checkBankrupt() 129 | gameSequence(s) 130 | },v * 1.5) 131 | person.money -= 800 132 | } else if (place.state === "trip") { // 旅游度假 133 | person.stop = generateNum(1, 3) 134 | person.money -= person.stop * 1000 135 | showMsgbox(`${person.name}花费${person.stop * 1000}享受旅游度假${person.stop}天`) 136 | checkBankrupt() 137 | gameSequence(s) 138 | } 139 | updateInfo() 140 | },v * (num + 0.9)) 141 | } 142 | 143 | function dialogClicked(type, action) { // 购买或取消 144 | let place = places[person.position] 145 | if (!action) { // 关闭对话框: 通过action模拟NPC购买与否 146 | closeDialog() 147 | gameSequence(s) 148 | return 149 | } 150 | if (type === "purchase") { // 购买 151 | place.owner = person.name // 房产证署名 152 | person.money -= place.value // 交钱 153 | let color = colorScheme[person.name] 154 | buyPlace(place.node, color) // 显示地皮归属 155 | showMsgbox(`恭喜你获得了${place.name}`) 156 | gameSequence(s) 157 | } else { // 升级 158 | let upgradeMap = ["一座小房子", "一套大别墅", "一栋大酒店"] 159 | person.money -= place.value / 2 160 | place.state ++ 161 | showMsgbox(`恭喜你在${place.name}建了${upgradeMap[place.state - 1]}`) 162 | // 造房动画效果 163 | upgradeHouse(place.node, place.state - 1) 164 | } 165 | closeDialog() 166 | updateInfo() 167 | } 168 | 169 | function generateNum(min, max) { // 生成随机数 170 | return Math.floor(Math.random() * (max - min)) + min 171 | } 172 | 173 | // 判断相关 174 | // 判断轮到的下个玩家是否处在停止状态 175 | function checkPlayerState(index) { 176 | let player = players[index] 177 | if (player.stop) { // 停止状态 178 | if (player.position === 11) { 179 | showMsgbox(`${player.name}还有${player.stop}天可以出狱`) 180 | } else { 181 | showMsgbox(`${player.name}离难得的假期结束还有${player.stop}天`) 182 | } 183 | player.stop -- 184 | return false 185 | } else if (player.state === "bankrupt") { 186 | return false 187 | } else { 188 | if (!player.control) { // NPC行动的地方 189 | setTimeout(() => { 190 | game() 191 | },v*2) 192 | } else { // 解锁骰子,玩家行动 193 | toggleDice(true) 194 | } 195 | // 轮到下一玩家 196 | s = index 197 | updatePlayer(player.name) 198 | return true 199 | } 200 | } 201 | // 判断胜利条件 202 | function checkFinish(){ 203 | let count = 0 204 | let winner 205 | players.forEach(player => { // 数还有多少人处于活跃状态 206 | if (player.state === "active") { 207 | count ++ 208 | winner = player 209 | } 210 | }) 211 | if (count === 1) { // 只有一个人活跃的话 212 | setTimeout(() => { 213 | alert(`${winner.name}赢啦!恭喜你成为最有钱的人!`) 214 | location.reload() 215 | }, v * 2) 216 | } 217 | } 218 | // 判断破产 219 | function checkBankrupt() { 220 | if (person.money < 0) { // 当前玩家的钱变成负值了 221 | setTimeout(() => { 222 | person.stop = 0 223 | person.state = "bankrupt" 224 | alert(`很遗憾,${person.name}破产了,所有地产将充公处理。`) 225 | updateBankrupt(person.node, players.indexOf(person)) 226 | places.forEach(place => { // 地产充公 227 | if (place.owner === person.name) { 228 | place.owner = "" 229 | place.node.style.boxShadow = "1px 1px 1px inset #454545, 1px -1px 1px inset #454545, -1px 1px 1px inset #454545, -1px -1px 1px inset #454545" 230 | } 231 | }) 232 | checkFinish() // 每当有人破产就判断是否结束 233 | }, v / 2) 234 | } 235 | } -------------------------------------------------------------------------------- /webpack.config.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @Author: Human Sean 3 | * @Email: humansean@qq.com 4 | * @Date: 2020-04-11 16:18:03 5 | * @LastEditTime: 2020-04-11 17:03:04 6 | * @Description: 7 | */ 8 | const path = require('path') 9 | 10 | module.exports = { 11 | mode: "production", 12 | entry: "./src/index.js", 13 | output: { 14 | path: path.resolve(__dirname, "public"), 15 | filename: "index.js" 16 | }, 17 | } --------------------------------------------------------------------------------