年後復工,寫了一個方格遊戲練練手。
最開始想的遊戲名字是雪人回家,找不到合適的雪人頭像,就簡單的稱呼爲方格遊戲吧,哈哈。
項目地址(打開就能玩)
http://mumuqiuer.gitee.io/snowman/
目前沒有移動版本,只能在PC上玩。
遊戲說明:
使用鍵盤上下左右四個箭頭按鍵移動小女孩,在倒計時結束前到達小房子的位置即遊戲挑戰成功。
每次限制移動一格,紅綠方格代表正負分值,走過的方格不再積分。
倒計時,系統設置時間爲30秒,可以自行修改時間,調節遊戲難度。
遊戲比的是限定時間內的得分高低。當然,遊戲時間結束了還沒回家,就是0分。哈哈。
遊戲覆盤功能,棋盤不變,可以重走一遍。戰績記錄每次重玩的得分,快來和小夥伴一較高低!
不想玩本局了,還可以再來一局,棋盤則會重新生成,每格分數隨機。
遊戲實現思路
h5+vue+js實現
移動原理是css的位置偏移 translate(x,y)
難點
1、獲取當前移動到達的目標格的分值。
初始化一個方格字典數組。在棋盤創建時,同步更新字典中記錄的對應方格分值。每次移動累積偏移量,都去遍歷字典數組,通過比較偏移量,確定目標方格,從而獲取目標方格的分值。
2、遊戲覆盤。
確保方格顯示的分值不變,上次走過並置爲0的方格需要復原。在棋盤數組中,記錄兩個分值,一個是隨機出的方格分值 score ,一個是修改過的分值 usedScore 。score 在一局遊戲中始終不變,usedScore 的值動態改變,記錄失效後的分值0。棋盤的顯示,usedScore 爲0就顯示 usedScore,否則顯示 score 。
遊戲源碼分享
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1.0">
<meta http-equiv="x-ua-compatible" content="IE=edge">
<title>方格遊戲</title>
<link rel="shortcut icon" href="favicon.ico">
<meta name="keywords" content="方格遊戲">
<meta name="description" content="方格遊戲">
<script src="vue.js"></script>
<style>
body{
width: 100%;
height:100%;
margin:0;
background: #fff;
overflow: hidden;
box-sizing: border-box;
}
div.container{
width: 100%;
display: flex;
justify-content: center;
margin-top:80px;
text-align: center;
}
div.container div.chess{
width:700px;
height:700px;
display: flex;
justify-content: flex-start;
flex-wrap: wrap;
box-sizing: border-box;
margin:0 20px;
}
div.container div.score{
width:300px;
margin:0 20px;
border:1px solid #999;
background: #999;
}
/*遊戲計時器*/
div.head{
width:100%;
height:64px;
box-sizing: border-box;
text-align: center;
position: fixed;
top: 0;
background: #999;
padding:12px;
}
div.head span,div.score span{
font-size: 24px;
font-weight: bold;
color:red;
padding:0 4px
}
/*雪人*/
div.snowman{
width:80px;
height:80px;
margin:10px;
text-align: center;
background: url("head.jpg") no-repeat;
cursor: pointer;
z-index: 2;
}
div.chess-grid{
width:100px;
height:100px;
line-height:100px;
box-sizing: border-box;
text-align: center;
border:1px solid #ccc;
color: #fff;
}
/*雪人的家*/
div.home{
width:100px;
height:80px;
margin:12px 7px;
background: url("home.jpg") no-repeat;
}
/*控制器*/
div.control{
width:100%;
height:60px;
line-height:60px;
text-align: center;
display: flex;
justify-content: center;
position: fixed;
bottom: 0;
background: #999;
}
div.btn{
width:200px;
height:40px;
line-height: 40px;
box-sizing: border-box;
border:1px solid #ccc;
margin:10px;
color: #fff;
cursor: pointer;
}
div.auto{
background: green;
}
div.refresh{
background: red;
}
div.game_start_btn{
margin:0 auto;
}
</style>
</head>
<body>
<div id="root">
<div class="head" v-show="!showControl">
<div v-show="!showTime" class="game_start_btn btn" @click="game_start">開始遊戲</div>
<div v-show="showTime">倒計時<span>{{gameTime}}</span>秒 </div>
</div>
<div class="container">
<div class="chess">
<div class="chess-grid"><div class="snowman" :style="moveStyle" title="按鍵盤方向鍵移動我哦"></div></div>
<div class="chess-grid" v-for="(item,index) in chess" :key="index" :style="{background:item.background}">{{item.usedScore == 0 ? item.usedScore : item.score}}分</div>
<div class="chess-grid"><div class="home"></div></div>
</div>
<div class="score">
<p>倒計時設置(10 ~ 60s):<input type="number" v-model="userSetGameTime" min="10" max="60"/></p>
<hr>
<p>戰績</p>
<div v-for="(score,index) in gameScores" :key="index">第{{index+1}}戰得分<span>{{score}}</span>分</div>
</div>
</div>
<div class="control" v-show="showControl">
<div class="btn auto" @click="game_review">本局覆盤</div>
<div class="btn refresh" @click="game_update">再來一局</div>
</div>
</div>
<script>
new Vue({
el: "#root",
data: {
showControl:false,//是否顯示本局覆盤、再來一局
showTime:false,//是否顯示倒計時 不顯示倒計時的時候會顯示開始遊戲按鈕
is_get_home:false,
gameTime:30,//系統設置的遊戲時間 30秒一局遊戲
userSetGameTime:30,//用戶設置的遊戲時間
gameScores:[],//單機多人遊戲 遊戲覆盤,存儲歷史得分
currentScore:0,//當前一局遊戲的得分
moveDown:0,
moveRitht:0,
chess:[],//存儲隨機的分數和背景色數組
moveStyle:{transform:"translate(0,0)"},//偏移樣式
dictionary:[//棋盤各塊偏移量對照字典 最後一格爲終點格
{"score":0," i":0, "r":100, "d":0},
{"score":0, "i":1, "r":200, "d":0},
{"score":0,"i":2, "r":300, "d":0},
{"score":0,"i":3, "r":400, "d":0},
{"score":0,"i":4, "r":500, "d":0},
{"score":0,"i":5, "r":600, "d":0},
{"score":0,"i":6, "r":0, "d":100},
{"score":0,"i":7, "r":100, "d":100},
{"score":0,"i":8, "r":200, "d":100},
{"score":0,"i":9, "r":300, "d":100},
{"score":0,"i":10, "r":400, "d":100},
{"score":0,"i":11, "r":500, "d":100},
{"score":0,"i":12, "r":600, "d":100},
{"score":0,"i":13, "r":0, "d":200},
{"score":0,"i":14, "r":100, "d":200},
{"score":0,"i":15, "r":200, "d":200},
{"score":0,"i":16, "r":300, "d":200},
{"score":0,"i":17, "r":400, "d":200},
{"score":0,"i":18, "r":500, "d":200},
{"score":0,"i":19, "r":600, "d":200},
{"score":0,"i":20, "r":0, "d":300},
{"score":0,"i":21, "r":100, "d":300},
{"score":0,"i":22, "r":200, "d":300},
{"score":0,"i":23, "r":300, "d":300},
{"score":0,"i":24, "r":400, "d":300},
{"score":0,"i":25, "r":500, "d":300},
{"score":0,"i":26, "r":600, "d":300},
{"score":0,"i":27, "r":0, "d":400},
{"score":0,"i":28, "r":100, "d":400},
{"score":0,"i":29, "r":200, "d":400},
{"score":0,"i":30, "r":300, "d":400},
{"score":0,"i":31, "r":400, "d":400},
{"score":0,"i":32, "r":500, "d":400},
{"score":0,"i":33, "r":600, "d":400},
{"score":0,"i":34, "r":0, "d":500},
{"score":0,"i":35, "r":100, "d":500},
{"score":0,"i":36, "r":200, "d":500},
{"score":0,"i":37, "r":300, "d":500},
{"score":0,"i":38, "r":400, "d":500},
{"score":0,"i":39, "r":500, "d":500},
{"score":0,"i":40, "r":600, "d":500},
{"score":0,"i":41, "r":0, "d":600},
{"score":0,"i":42, "r":100, "d":600},
{"score":0,"i":43, "r":200, "d":600},
{"score":0,"i":44, "r":300, "d":600},
{"score":0,"i":45, "r":400, "d":600},
{"score":0,"i":46, "r":500, "d":600},
{"score":0,"i":47, "r":600, "d":600}
]
},
methods: {
//生成隨機分數棋格
createChess:function(){
//7*7方格,掐頭去尾,需要生成47個隨機數。
var score;
var bgColor;
for(var i=0;i<47;i++){
// 按奇數偶數對應正負分值
if(i%2 ==0){
//正數 加分
score =Math.round(Math.random()*10)+2;
bgColor="#16a05d";
}else{
//負數 減分
score =-Math.round(Math.random()*6)-1;
bgColor="#e21918";
}
this.chess.push({
"score":score,
"usedScore":100,//隨便指定一個現今規則不可能有的一個分數即可
"background":bgColor
});
//同步更新對照字典,存儲分值。
this.dictionary[i].score = score;
}
},
//鍵盤事件 四個箭頭按鍵,控制上下左右四個方向的移動。
letMove:function(e){
e||event;
//當遊戲倒計時顯示時,即遊戲還未結束,才能觸發鍵盤事件,開始移動。
if(this.showTime){
switch(e.keyCode){
case 39:
//向右移動
this.moveRitht +=100;
break;
case 40:
//向下移動
this.moveDown +=100;
break;
case 37:
//向左移動
this.moveRitht -=100;
break;
case 38:
//向上移動
this.moveDown -=100;
break;
default:
return;
}
//判斷界限值 不能超出棋盤活動
this.moveRitht < 0 ? this.moveRitht = 0 : this.moveRitht;
this.moveRitht > 600 ? this.moveRitht = 600 : this.moveRitht;
this.moveDown < 0 ? this.moveDown = 0 : this.moveDown;
this.moveDown > 600 ? this.moveDown = 600 : this.moveDown;
this.moveStyle.transform = "translate("+this.moveRitht+"px,"+this.moveDown+"px)";
//根據偏移的位置,統計得分。
this.countScore(this.moveRitht,this.moveDown);
}
},
//計算得分
countScore:function(r,d){
//遍歷偏移量字典,根據當前所在的位置,獲取對應的分值。
//偏移量字典(len=48)比棋格(len=47)多了一個終點的位置信息。
if(!(r == 600 && d == 600)){
//不在家,賦值false 防止回家後再離開的情形
this.is_get_home = false;
for(var i=0;i<48;i++){
if(r == this.dictionary[i].r && d == this.dictionary[i].d){
if(this.chess[i].usedScore !=0){
this.currentScore += this.dictionary[i].score;
//分數一次性有效 走過的分數變爲0.
//爲了覆盤,不直接改變分數,新分數存儲到 usedScore
this.chess[i].usedScore = 0;
}
}
}
}else{
//雪人到家
this.is_get_home = true;
}
},
//計時器,每次時間-1,時間單位秒。
timer:function(){
this.gameTime -= 1
},
//用戶點擊遊戲開始 創建定時器 顯示倒計時
game_start:function(){
if(this.gameTime != this.userSetGameTime){
//系統設置的遊戲時長和用戶設置的遊戲時長衝突,則使用用戶設置的時長
this.gameTime = this.userSetGameTime;
}
this.showTime=true;
timer1=setInterval(this.timer, 1000);
},
game_review:function(){
this.parameter_reset();
this.resetUsedScore();
},
//恢復棋盤 使用過的分數初始化
resetUsedScore:function(){
var len = 47;
while(len--){
this.chess[len].usedScore = 100;
}
},
//本局重玩,只需要重置參數。
parameter_reset:function(){
this.showControl=false;
this.is_get_home = false;
this.showTime=false;//先不顯示倒計時,顯示開始遊戲按鈕。
this.moveRitht=0;
this.moveDown=0;
this.moveStyle.transform = "translate(0,0)";
this.currentScore=0;
},
//頁面初始化 遊戲重新開始
game_update:function(){
this.parameter_reset();
this.gameScores=[];
this.chess=[];
this.createChess();
}
},
watch:{
//監測遊戲時間
gameTime(){
if(this.gameTime == 0){
clearInterval(timer1);
this.showControl=true;
this.showTime=false;//倒計時結束,關閉倒計時結果顯示
if(this.is_get_home){
//遊戲結束:倒計時結束,雪人進入小屋。當前得分計入。
this.gameScores.push(this.currentScore);
}else{
//遊戲失敗: 倒計時結束,但雪人未進入小屋。本局得分爲0。
this.currentScore=0;
this.gameScores.push(0);
}
}
}
},
created(){
//註冊鍵盤事件
var _this = this;
document.addEventListener("keydown", _this.letMove);
},
mounted(){
this.game_update();
}
})
</script>
</body>
</html>