年后复工,写了一个方格游戏练练手。
最开始想的游戏名字是雪人回家,找不到合适的雪人头像,就简单的称呼为方格游戏吧,哈哈。
项目地址(打开就能玩)
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>