版權說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權,請進行舉報或認領
文檔簡介
第利用js+canvas實現(xiàn)掃雷游戲本文實例為大家分享了用js+canvas實現(xiàn)掃雷游戲的具體代碼,供大家參考,具體內(nèi)容如下
記錄js學習后制作的第一關小游戲。
這里的代碼還不夠精簡,許多地方偷懶沒有封裝,邏輯也有許多可以優(yōu)化。
body
勝利條件,找出所有地雷并標記
formaction="javaScript:createContent()"
divid="message"地雷數(shù)量必須小于地圖大小xy的平方/div
br/
地圖大小xy:inputid="xyNum"type="number"required="true"name="points"min="1"max="50"
/
booNum:inputid="booNum"type="number"required="true"name="points"min="1"max="2500"/
inputtype="submit"value="OK":/
br/1.輸入寬度br/2.輸入地雷數(shù)(地雷數(shù)小于寬*寬)br/3.單擊確定
br/
鼠標右鍵:br/
第一次:標記您的猜測br/
第二次:取消標簽br/
/form
divid='game'
/div
scriptsrc="./js/MarkObs.js"/script
scriptsrc="./js/Isboo.js"/script
scriptsrc="./js/lei.js"/script
script
letxy=document.getElementById('xyNum');
letboo=document.getElementById('booNum');
letmeg=document.getElementById("message");
letdiv=document.getElementById('game');
//獲取輸入的寬高和地雷數(shù)
createContent=function(){
//console.log(xy.value);
//console.log(boo.value);
letxyNum=xy.value;
letbooNum=boo.value;
//console.log(Math.pow(xyNum,2));
//判斷輸入是否合法
if(Math.pow(xyNum,2)boo.value){
meg.style.display='block';
}
else{//繪制地圖
div.innerHTML='';//清除上次div里的地圖
letgame=newGame('game',xyNum,booNum);
}
}
/script
/body
lei.js
/*一個自定義原型數(shù)組方法
可以放到html里
二維數(shù)組查找
arr:要找數(shù)組第一第二項找到返回下標,沒有返回-1
PS:只要this數(shù)組和arr數(shù)組第一第二項的值相等,即為找到。
Atotype.myindexOf=function(arr){
for(leti=0;ithis.length;i++){
if((this[i][0]==arr[0])(this[i][1]==arr[1])){
returni;
}
}
return-1;
初始化地雷圖
id:傳入繪制地圖的容器id
xyNum:長||寬的格子數(shù)(地圖固定正方形)
booNum:地雷數(shù)
classGame{
constructor(id,xyNum,booNum){
this.xyNum=xyNum;
this.booNum=booNum;
this.id=id;
this.booArrs=[];//保存雷的位置
this.boox=-1;//地雷在x軸第幾個塊
this.booy=-1;//地雷在x軸第幾個塊
this.numArrs=[];//保存提醒數(shù)字的位置以及數(shù)字
this.num=0;//保存找到的提醒數(shù)字的個數(shù)
this.markArrs=[];//保存標記位置的數(shù)組
//單個塊的寬高
this.divw=20;
//初始化畫布
this.initCanvas(xyNum);
//初始化地雷位置(地雷用-1代替,圖片繪制麻煩)
this.initBooxy(xyNum,booNum);
//初始化遮擋物
this.initObs(xyNum);
//判斷是否勝利
this.win();
}
/*初始化畫布(包括網(wǎng)格)
xyNum:傳入需要繪制的寬格子數(shù)
*/
initCanvas(xyNum){
this.canvas=document.createElement('canvas');
this.ctx=this.canvas.getContext('2d');
//1為border
this.canvas.width=(this.divw+1)*xyNum;
this.canvas.height=(this.divw+1)*xyNum;
//繪制網(wǎng)格坐標
//獲取canvas的寬高;
letw=this.canvas.width;
leth=this.canvas.height;
//繪制水平線
for(leti=1;ih/21;i++){
this.ctx.beginPath();
this.ctx.lineTo(0,
21*i)//起點
this.ctx.lineTo(w,21*i);//重點
this.ctx.stroke();
}
//h繪制垂直線
for(leti=1;iw/21;i++){
this.ctx.beginPath();
this.ctx.lineTo(21*i,0)//起點
this.ctx.lineTo(21*i,h);//重點
this.ctx.stroke();
}
//ctx.stroke();
//放入容器
this.div=document.getElementById(this.id);
this.div.appendChild(this.canvas);
//綁定點擊事件!!!
this.canvas.addEventListener('mousedown',this.mouseDown.bind(this))//!!!!注意需要更改this指向,用bind
//清除鼠標右鍵的默認事件“contextmenu“
this.canvas.addEventListener("contextmenu",function(event){
event.preventDefault()
})
}
/*初始化地雷(包括提醒數(shù)字)
xyNum:傳入地圖的寬的格子數(shù)
booNum:傳入地雷數(shù)
*/
initBooxy(xyNum,booNum){
//隨機地雷位置并保存起來
for(leti=0;ibooNum;i++){
//x,y為地雷所在格子坐標,從0開始
this.boox=parseInt(Math.random()*xyNum);
this.booy=parseInt(Math.random()*xyNum);
//避免雷的位置重復
while(this.booArrs.myindexOf([this.boox,this.booy])!=-1){
this.boox=parseInt(Math.random()*xyNum);
this.booy=parseInt(Math.random()*xyNum);
}
this.booArrs.push([this.boox,this.booy])//!!!保存地雷的位置
console.log(i,'x:'+this.boox,'y:'+this.booy);
//繪制地雷
this.ctx.beginPath();//不清楚可不可以刪
this.ctx.rect(this.boox*21,this.booy*21,20,20);
this.ctx.fillStyle='red';
this.ctx.fill();
}
//繪制地雷位置周圍提醒數(shù)字
//這里的邏輯可以優(yōu)化,不提前繪制數(shù)字,在點擊清除障礙物后再判斷繪制。
/*
想法一:在每個雷周圍添加數(shù)字1,如果在多個雷交集處累加
想法二:所有塊依次判斷周圍是否有雷,有幾個雷,就fillText()多少
想法三:(一二結合)先找每個雷,該雷周圍的8個塊依次判斷周圍有幾個雷
*/
//這里為法二
for(leti=0;ixyNum;i++){
for(letj=0;jxyNum;j++){
letnum=0;//提醒數(shù)字,每次重置為0
if(this.booArrs.myindexOf([i-1,j-1])!=-1){
num++;
}
if(this.booArrs.myindexOf([i-1,j])!=-1){
num++;
}
if(this.booArrs.myindexOf([i-1,j+1])!=-1){
num++;
}
if(this.booArrs.myindexOf([i,j-1])!=-1){
num++;
}
if(this.booArrs.myindexOf([i,j+1])!=-1){
num++;
}
if(this.booArrs.myindexOf([i+1,j-1])!=-1){
num++;
}
if(this.booArrs.myindexOf([i+1,j])!=-1){
num++;
}
if(this.booArrs.myindexOf([i+1,j+1])!=-1){
num++;
}
//繪制提醒數(shù)字
if(num!=0(this.booArrs.myindexOf([i,j])==-1)){//(this.booArrs.myindexOf([i,j])==-1)地雷不標注提示數(shù)字若。要標注需要+1(本身)
this.ctx.font='18pxfasdg'
this.ctx.fillStyle='#000'
this.ctx.fillText(num,i*(this.divw+1)+2,(j+1)*(this.divw+1)-2);//加1和j+1為測試結果,-+2是為了文本在格子里居中//y為文本中線坐標
this.numArrs.push([i,j,num]);//i,j為提醒數(shù)字的塊坐標,num為裝數(shù)組里的值(myindexOf來判斷)
}
//this.NUM=num;
}
}
}
/*初始化遮擋物
xyNum:傳入地圖的寬的格子數(shù)
*/
initObs(xyNum){
for(leti=0;ixyNum;i++){
for(letj=0;jxyNum;j++){
this.ctx.beginPath();
this.ctx.rect(i*21,j*21,20,20);
//this.ctx.fillStyle='rgb(155,25,205,0.7)';//設置障礙物透明度可以方便查看雷的位置
this.ctx.fillStyle='rgb(155,25,205,1)';//正常游戲時透明度為'1‘
this.ctx.fill();
}
}
/*點擊事件在initCanvas中綁定*/
mouseDown(){
//這里使用preventDefault,默認事件被沒有消除,是因為觸發(fā)鼠標右鍵的默認事件的事件類型不是mousedown,是contextmenu
//event.preventDefault();//ie9以下不兼容
this.clix=Math.floor(event.layerX/(this.divw+1));//this.divw為20是塊的寬
this.cliy=Math.floor(event.layerY/(this.divw+1));
//鼠標左鍵
if(event.button==0){
this.clearObs(this.clix,this.cliy);
}
//鼠標右鍵
elseif(event.button==2){
this.markObs(this.clix,this.cliy);
}
/*掃雷*/
//這里的代碼可以封裝一下為了方便此處沒有封裝
clearObs(x,y){
//console.log(x,y);點擊坐標
this.ctx.clearRect(x*21,y*21,20,20);//清除指定塊
//點擊到標記,點擊到提醒數(shù)字,點擊到地雷,點擊到空白,
if(this.markArrs.myindexOf([x,y])!=-1){
//點擊到標記,重新覆蓋
this.ctx.rect(x*21,y*21,20,20);
this.ctx.fillStyle='rgb(155,25,205,1)';
this.ctx.fill();
this.ctx.beginPath();
this.ctx.fillStyle='red';
this.ctx.fillText('',x*(this.divw+1)+2,(y+1)*(this.divw+1)-2);
this.ctx.fill();
}
elseif(this.numArrs.myindexOf([x,y])!=-1){//點擊到提醒數(shù)字
letindex=this.numArrs.myindexOf([x,y]);//下標
letnum=this.numArrs[index][2];//提醒數(shù)字
this.ctx.fillText(num,x*(this.divw+1)+2,(y+1)*(this.divw+1)-2);//加1和j+1為測試結果,-+2是為了文本在格子里居中//y為文本中線坐標
this.num++;
}
elseif(this.booArrs.myindexOf([x,y])!=-1){//,點擊到地雷,全部繪制
console.log(this.booArrs.myindexOf([x,y]));
//繪制全圖
//繪制提醒數(shù)字
for(leti=0;ithis.xyNum;i++){
for(letj=0;jthis.xyNum;j++){
letnum=0;//提醒數(shù)字,每次重置為0
//if(booArrs.indexof([i-1,j-1])!=-1){//數(shù)組是對象這樣永遠-1
this.ctx.clearRect(i*21,j*21,20,20);
if(this.booArrs.myindexOf([i-1,j-1])!=-1){
num++;
}
if(this.booArrs.myindexOf([i-1,j])!=-1){
num++;
}
if(this.booArrs.myindexOf([i-1,j+1])!=-1){
num++;
}
if(this.booArrs.myindexOf([i,j-1])!=-1){
num++;
}
if(this.booArrs.myindexOf([i,j+1])!=-1){
num++;
}
if(this.booArrs.myindexOf([i+1,j-1])!=-1){
num++;
}
if(this.booArrs.myindexOf([i+1,j])!=-1){
num++;
}
if(this.booArrs.myindexOf([i+1,j+1])!=-1){
num++;
}
//繪制提醒數(shù)字
if(num!=0(this.booArrs.myindexOf([i,j])==-1)){//(this.booArrs.myindexOf([i,j])==-1)地雷不標注提示數(shù)字若要標注需要+1(本身)
this.ctx.font='18pxfasdg'
this.ctx.fillStyle='#000'
this.ctx.fillText(num,i*(this.divw+1)+2,(j+1)*(this.divw+1)-2);//加1和j+1為測試結果,-+2是為了文本在格子里居中//y為文本中線坐標
this.numArrs.push([i,j,num]);//i,j為提醒數(shù)字的塊坐標,num為裝數(shù)組里的值(myindexOf來判斷)
}
//this.NUM=num;
}
}
//繪制地雷
for(leti=0;ithis.booArrs.length;i++){
this.ctx.fillStyle='red';
this.ctx.rect(this.booArrs[i][0]*21,this.booArrs[i][1]*21,20,20);
this.ctx.fill();
}
this.ctx.clearRect((this.xyNum-1)*21,(this.xyNum-1)*21,20,20);//每次最后一個都會變紅,不知道原因,此處專門刪除。
alert('你驚動了雷雷');
}
else{
this.isboo(this.ctx,x,y,this.booArrs,this.numArrs,this.markArrs,this.xyNum);
}
win(){//標記數(shù)組==地雷數(shù)組
this.tim=setInterval(()={
if(this.booArrs.length==this.markArrs.length){
for(leti=0;ithis.booNum;i++){
if(true==this.booArrs.some(()={
returnthis.markArrs.myindexOf(this.booArrs[i])!=-1;
})){
this.booNum--;
}
if(this.booNum==0){
clearInterval(this.tim);
alert('youarewin');
}
}
}
},10)
isboo(ctx,x,y,booArrs,numArrs,markArrs,xyNum){
newIsboo(ctx,x,y,booArrs,numArrs,markArrs,xyNum);
/*標記
*/
markObs(x,y){
console.log(x,y);
newMarkObs(this.ctx,x,y,this.booArrs,this.divw,this.markArrs);
}
isboo.js
Atotype.myindexOf=function(arr){
for(leti=0;ithis.length;i++){
if((this[i][0]==arr[0])(this[i][1]==arr[1])){
returni;
}
}
return-1;
這里解決點擊到空白格子時,把周圍的空白格一起顯示。此處的邏輯可以再優(yōu)化.
ctx:布局
x,點擊位置
y,點擊位置
booArrs:炸彈的位置數(shù)組
numArrs:提示數(shù)的位置
markArrs:標記的位置
classIsboo{
constructor(ctx,x,y,booArrs,numArrs,markArrs,xyNum){
this.x=x;
this.y=y;
//判斷有沒有提醒數(shù)字
this.isbool(ctx,x,y,booArrs,numArrs,markArrs,xyNum);
this.isboor(ctx,x,y,booArrs,numArrs,markArrs,xyNum);
this.isboot(ctx,x,y,booArrs,numArrs,markArrs,xyNum);
this.isboob(ctx,x,y,booArrs,numArrs,markArrs,xyNum);
}
isbool(ctx,x,y,booArrs,numArrs,markArrs,xyNum){
if((numArrs.myindexOf([x,y])==-1)(xxyNum)(markArrs.myindexOf([x,y])==-1)){
ctx.clearRect(x*21,y*21,20,20);
x+=1;
this.isbool(ctx,x,y,booArrs,numArrs,markArrs,xyNum);
//this.isboor(ctx,x,y,booArrs,numArrs,markArrs,xyNum);
this.isboot(ctx,x,y,booArrs,numArrs,markArrs,xyNum);
this.isboob(ctx,x,y,booArrs,numArrs,markArrs,xyNum);
}else{
return;
}
}
isboor(ctx,x,y,booArrs,numArrs,markArrs,xyNum){
if((numArrs.myindexOf([x,y])==-1)(x=0)(markArrs.myindexOf([x,y])==-1)){
ctx.clearRect(x*21,y*21,20,20);
x-=1;
//this.isbool(ctx,x,y,booArrs,numArrs,markArrs,xyNum);
this.isboor(ctx,x,y,booArrs,numArrs,markArrs,xyNum);
this.isboot(ctx,x,y,booArrs,numArrs,markArrs,xyNum);
this.isboob(ctx,x,y,booArrs,numArrs,markArrs,xyNum);
}else{
return;
}
}
isboot(ctx,x,y,booArrs,numArrs,markArrs,xyNum){
if((numArrs.myindexOf([x,y])==-1)(yxyNum)(markArrs.myindexOf([x,y])==-1)){
ctx.clearRect(x*21,y*21,20,20);
y+=1;
//this.isbool(ctx,x,y,booArrs,numArrs,markArrs,xyNum);
//this.isboor(ctx,x,y,booArrs,numArrs,markArrs,xyNum);
this.isboot(ctx,x,y,booArrs,numArrs,markArrs,xyNum);
//this.isboob(ctx,x,y,booArrs,numArrs,markArrs,xyNum);
}else{
return;
}
}
isboob(ctx,x,y,booArrs,numArrs,markArrs,xyNum){
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
- 4. 未經(jīng)權益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負責。
- 6. 下載文件中如有侵權或不適當內(nèi)容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 2026安徽馬鞍山公共交通集團有限責任公司招聘3人備考題庫及1套參考答案詳解
- 2026江蘇省疾病預防控制中(江蘇省預防醫(yī)學科學院)博士專項招聘3人備考題庫及完整答案詳解
- 2026四川成都市華西醫(yī)院可視化診療與人工智能實驗室招聘2人備考題庫及完整答案詳解一套
- 2026廣東東莞市大灣區(qū)大學專職心理咨詢師招聘1人備考題庫完整答案詳解
- 農(nóng)村人居環(huán)境整治設施管理使用協(xié)議
- 誠信經(jīng)營示范店責任承諾書6篇
- 企業(yè)活動組織策劃標準化模板
- XX校區(qū)2025年秋季學期食品安全與營養(yǎng)健康工作報告
- 銷售業(yè)務合同審核與風險評估工具
- 那片草原的美麗與神奇寫景散文11篇
- 國家基層高血壓防治管理指南 2025版圖文解讀
- 小學數(shù)學長度單位換算練習200題及答案
- 機器人工程技術人員筆試試題及答案
- GB/T 18344-2025汽車維護、檢測、診斷技術規(guī)范
- crm系統(tǒng)使用管理辦法
- 肝癌晚期護理常規(guī)課件
- 神經(jīng)外科VTE的預防及護理
- 清潔驗證完整版本
- 2023年山東省中考英語二輪復習專題++時態(tài)+語態(tài)
- 車間新增設備管理制度
- 前沿財務知識培訓課件
評論
0/150
提交評論