快过年,各大游戏中都陆续添加了打年兽的休闲玩法。之前学习了css的3D相关知识,一直想实践一下,这次就使用css加上js实现3D版打年兽小游戏。
效果演示游戏玩法说明将main层div作为3D容器,ground层div作为地面,通过X,Y坐标旋转调整地面的默认角度`transform: rotateY(30deg) rotateX(60deg);`,同时将ground层设置成3D容器,为后面在地面上添加年兽准备。代码如下。
页面元素:
<div class="main">
<div class="ground">
</div>
</div>
样式布局:
.main{
width:400px;height:400px;
margin:0px auto;
perspective-origin: 50% 200px;
perspective: 2000px;
transform-style: preserve-3d;
backface-visibility: hidden;
}
.main .ground{
width:100%;height:100%;
transform: rotateY(30deg) rotateX(60deg);
background: rgb(7, 255, 138);
position: relative;
perspective-origin: 50% 100px;
perspective: 1000px;
transform-style: preserve-3d;
backface-visibility: hidden;
}
设计3D相机效果
我们知道3D坐标分为X、Y、Z三个方向,X轴为水平方向,Y轴为竖直方向,Z轴为垂直与屏幕方向。要实现上图中的效果,保持Z轴不变,只改变X、Y轴旋转角度即可。
具体操作逻辑为监听鼠标点击后的移动事件,通过计算当前鼠标位置相对于鼠标刚点击时的位置X、Y轴像素偏移量动态调整、Y轴的旋转角度,代码如下。
document.addEventListener("mousedown",function(e){
click = true;
sp = {x:e.clientX,y:e.clientY}
});
document.addEventListener("mousemove",function(e){
if(!click){
return;
}
var ydeg = (deg.y (e.clientX - sp.x)/10);
var xdeg = (deg.x - (e.clientY - sp.y)/10);
$('.ground').css({transform:'rotateY(' ydeg 'deg) rotateX(' xdeg 'deg)'})
deg = {x:xdeg,y:ydeg};
sp = {x:e.clientX,y:e.clientY}
});
document.addEventListener("mouseup",function(e){
click = false;
})
设计地洞效果
通过白色背景线条在水平和竖直方向将地面分成4X4棋盘,每一片代表一个地洞,代码如下。
var topVal = 100;
for (var i = 0; i < 4; i ) {
var div = document.createElement("div");
div.style.top = topVal "px";
div.style.left = "0px";
div.style.width = '100%';
div.style.height = '2px';
$('.ground').append(div)
topVal = 100;
}
var leftVal = 100;
for (var i = 0; i < 4; i ) {
var div = document.createElement("div");
div.style.left = leftVal "px";
div.style.top = "0px";
div.style.width = '2px';
div.style.height = '100%';
$('.ground').append(div)
leftVal = 100;
}
设计年兽
在第一个地洞的位置画一个3D盒子作为年兽身体,长80px,宽30px,高30px,离地面高度为10px,代码如下。
页面元素
<div class="main">
<div class="ground">
<div class="nian body front"></div>
<div class="nian body left"></div>
<div class="nian body back"></div>
<div class="nian body right"></div>
<div class="nian body top"></div>
<div class="nian body bottom"></div>
</div>
</div>
style样式
.main .ground > .body{
top:0px;
left:35px;
background: rgb(243, 253, 255);
height: 80px;
width: 80px;
}
.main .ground > .front{
width: 30px;
transform: translateZ(40px);
}
.main .ground > .left{
width:30px;
transform: translateZ(40px) rotateY(90deg);
transform-origin: left center;
}
.main .ground > .back{
width: 30px;
transform: translateZ(10px) rotateY(180deg);
}
.main .ground > .right{
width: 30px;
transform:translateZ(40px) rotateY(-90deg);
transform-origin: right;
}
.main .ground > .top{
height: 30px;
width: 30px;
transform: translateZ(40px) rotateX(-90deg);
transform-origin: top center;
}
.main .ground > .bottom{
height: 30px;
width: 30px;
top:50px;
transform: translateZ(40px) rotateX(90deg);
transform-origin: bottom center;
}
然后一次画出年兽的头部、脚步3D盒子,效果如下,代码见底部完整代码。
设计年兽出现效果`transVal`对象存储了年兽每个部位的最终tansform变换值,用来提供jQuery展示动画;年兽出现位置随机,通过随机函数生成年兽最终的位置,通过top、left样式属性定位,通过Jquery的animate函数动态调整translateZ的值,形成年兽重地下钻出来的效果。
设置定时器,到期自动执行游戏主体函数,游戏主体函数逻辑在下面的内容介绍。
var transVal = {
front:{
translateZ:{val:40,un:'px'}
},
left:{
translateZ:{val:40,un:'px'},
rotateY:{val:90,un:'deg'}
},
right:{
translateZ:{val:40,un:'px'},
rotateY:{val:-90,un:'deg'}
},
back:{
translateZ:{val:10,un:'px'},
rotateY:{val:180,un:'deg'}
},
top:{
translateZ:{val:40,un:'px'},
rotateX:{val:-90,un:'deg'}
},
bottom:{
translateZ:{val:40,un:'px'},
rotateX:{val:90,un:'deg'}
},
'head-front':{
translateZ:{val:80,un:'px'}
},
'head-left':{
translateZ:{val:80,un:'px'},
rotateY:{val:90,un:'deg'}
},
'head-right':{
translateZ:{val:80,un:'px'},
rotateY:{val:-90,un:'deg'}
},
'head-back':{
translateZ:{val:41,un:'px'},
rotateY:{val:180,un:'deg'}
},
'head-top':{
translateZ:{val:80,un:'px'},
rotateX:{val:-90,un:'deg'}
},
'head-bottom':{
translateZ:{val:65,un:'px'},
rotateX:{val:-90,un:'deg'}
},
'foot-front':{
translateZ:{val:10,un:'px'}
},
'foot-left':{
translateZ:{val:10,un:'px'},
rotateY:{val:90,un:'deg'}
},
'foot-right':{
translateZ:{val:10,un:'px'},
rotateY:{val:-90,un:'deg'}
},
'foot-back':{
translateZ:{val:0,un:'px'},
rotateY:{val:180,un:'deg'}
},
'foot-top':{
translateZ:{val:10,un:'px'},
rotateX:{val:-90,un:'deg'}
},
'foot-bottom':{
translateZ:{val:10,un:'px'},
rotateX:{val:90,un:'deg'}
}
}
function showNianshou() {
$('.nian').show()
if(!start){
return;
}
var topNum = parseInt(Math.random()*4)
var leftNum = parseInt(Math.random()*4)
$('.body').css({top:topNum*100 'px',left:leftNum*100 35 'px'})
$('.head').css({top:topNum*100 60 'px',left:leftNum*100 30 'px'})
$('.head-bottom').css({top:topNum*100 60 'px',left:leftNum*100 27 'px'})
$('.foot1').css({top:topNum*100 'px',left:leftNum*100 35 'px'})
$('.foot2').css({top:topNum*100 'px',left:leftNum*100 55 'px'})
$('.foot3').css({top:topNum*100 75 'px',left:leftNum*100 35 'px'})
$('.foot4').css({top:topNum*100 75 'px',left:leftNum*100 55 'px'})
$('.nian').animate({opacity:1},{
step:function(now,fix){
var obj = transVal[$(this).attr('class').split(' ')[2]]
if(obj){
var s = ' '
for (var v in obj){
if(v.indexOf('translate') >= 0){
s = v '(' (obj[v].val - 80 now * 80) obj[v].un ') '
}else{
s = v '(' obj[v].val obj[v].un ') '
}
}
$(this).css({transform:s})
}
},
duration:timer
},'linear')
setTimeout(function(){
hiding = false
setTimeout(function(){clickFun(undefined,true)},timer)
},timer)
}
设计年兽消失效果
同上通过Jquery的animate函数动态调整translateZ的值,形成年兽钻回地下果,代码如下。
function hideNianshou(){
$('.nian').animate({opacity:0},{
step:function(now,fix){
var obj = transVal[$(this).attr('class').split(' ')[2]]
if(obj){
var s = ' '
for (var v in obj){
if(v.indexOf('translate') >= 0){
s = v '(' (obj[v].val - 80 now * 80) obj[v].un ') '
}else{
s = v '(' obj[v].val obj[v].un ') '
}
}
$(this).css({transform:s})
}
},
duration:timer
},'linear');
}
设计年兽打中效果
同上通过Jquery的animate函数动态调整translateZ的值,形成年兽被打死的效果,码如下。
function deadNianshou(){
$('.nian').animate({opacity:0},{
step:function(now,fix){
$(this).css({transform:'translateZ(' now * 40 'px)'})
},
duration:timer
},'linear');
}
设计打击效果
锤子素材
页面中添加锤子元素,同时给main层添加鼠标移动监听,调整锤子的位置使其跟随鼠标的光标移动。
<img id="chui" src="${rc.contextPath}/static/image/chuizi.png" width="50" style="position: absolute;">
在移动锤子的位置时判断锤子是否正在执行打击动画,正在执行时锤子的位置不变,动画执行完,再次跟随鼠标光标移动。
$('.main')[0].addEventListener('mousemove',function(e){
if(!hiting){
$('#chui').css({left:e.clientX-5 'px',top:e.clientY - 55'px'})
}
})
给ground层添加点击时间监听,执行锤子的打击动画
$('.ground')[0].addEventListener('click',function(e){
$('#chui').addClass("hit");
hiting = true
setTimeout(function(){
hiting = false
$('#chui').removeClass("hit');
},300)
})
打击动画通过`keyframes `实现。
.hit{
animation: hit ease 0.3s;
}
@keyframes hit {
0%{
transform: rotate(0deg) ;
}
80%{
transform: rotate(30deg) translateX(50px) translateY(-100px);
}
100%{
transform: rotate(0deg);
}
}
游戏主体函数设计
给年兽添加点击事件,当年兽被点击后执行游戏主体函数。
$('.nian').on('click',clickFun);
游戏主题函数两个参数,第一个为点击时间Event,第二个参数为是否自动执行自动则为true手动点击为undefinded.
通过hiding值防止主体函数并发执行导致游戏画面不可控。
主体函数被自动执行则说明,点击得慢了,此时执行年兽消失函数,执行点击失败后逻辑,重新执行年兽出现函数。
主体函数因年兽被点击后执行,则说明打到了年兽,此时计算成功次数并判断是否提升游戏速度,每成功击中5次提升一次速度,重新执行年兽出现函数。
function clickFun(e,auto){
if(e){
e.stopPropagation();
}
if(hiding){
return;
}
hiding = true
if(auto){
hideNianshou()
setTimeout(function(){
dealAfterFail();
showNianshou()
},timer)
}else{
$('#chui').addClass("hit");
hiting = true
setTimeout(function(){
hiting = false
$('#chui').removeClass("hit");
sucTimes
if(sucTimes%5==0){
showMsg('速度加快了')
timer -= 100
}
if(timer < 400){
timer = 400
}
deadNianshou();
setTimeout(function(){
showMsg('成功打到' sucTimes '只年兽')
showNianshou()
},timer)
},300)
}
}
设计打击年兽失败后函数
累加失败次数,当失败次数达到3时,游戏结束,弹出游戏结束消息。
function dealAfterFail(){
failTimes
if(failTimes == 3){
showMsg('GAME OVER,成功打到' sucTimes '只年兽');
start = false
}
}
游戏弹出消息设计
页面添加div设置其位于页面右上角,默认隐藏,提供`showMsg`函数动态修改div文字内容,2秒后自动消失。
<div class="msg">速度加快了</div>
.msg{
display: none;
width:300px;
height:50px;
line-height: 50px;
text-align: center;
color: #CC2222;
position: absolute;
right: 10px;
top:10px;
background: rgba(255,255,255,.8);
border-radius: 5px;
}
.msg:after{
content: ' ';
clear: both;
}
function showMsg(msg){
$('.msg').html(msg);
$('.msg').show();
setTimeout(function(){$('.msg').hide();},2000)
}
设计开始菜单
页面添加列表元素,添加点击时间。
<ul class="hover">
<li onclick="reStart()">开始</li>
</ul>
ul{
display: block;
position: absolute;
top:10px;
left:10px;
width: 200px;
background: rgba(255,255,255,.3);
}
li{
display: block;
list-style: none;
width:100px;
height: 30px;
text-align: center;
line-height: 30px;
color: #fff;
background: rgba(255,0,0,.7);
border-radius: 2px;
margin:10px auto;
cursor: pointer;
}
li:hover{
background: rgba(255,0,0,1);
transform: scale(1.1);
}
年兽默认隐藏。
$('.nian').hide()
点击开始后,重置游戏参数,执行年兽消失函数,执行年兽出现函数。
function reStart(){
start = true
sucTimes = 0
failTimes = 0
timer = 800
hideNianshou()
setTimeout(showNianshou,timer)
}
完整代码
3D兽小游戏源码:https://gitee.com/tech-famer/farmer-game-nianshou
Copyright © 2024 妖气游戏网 www.17u1u.com All Rights Reserved