管道像素鸟
前言
本次要制作的游戏 —— 管道小鸟,直接上代码。
1、游戏界面
<template>
<!-- 管道小小鸟 -->
<view class="bird-game" @click="start">
<view class="bird-box u-rela">
<u-image src="/static/image/bird/bird-bg.png" width="100%" height="100%" :fade="false"></u-image>
<view class="bird-map">
<!-- 分数 -->
<view class="bird-number">{{number}}</view>
<!-- 开始游戏 -->
<view class="bird-start" v-if="!isStart">开始游戏</view>
<!-- 鸟 -->
<view class="bird hidden" :class="{'bird-move': !isStart}" :style="{'top':`${bird.top}rpx`, 'left':`${bird.left}rpx`, 'width': `${bird.width}rpx`, 'height': `${bird.height}rpx`}">
<u-image src="/static/image/bird/bird.gif" mode="widthFix"></u-image>
</view>
<!-- 管道 -->
<view class="bird-pipe" v-for="(item,index) in pipeList" :key="index" :style="{'right':`${item.pRight}rpx`, 'width': `${pipe.width}rpx`}">
<view class="bird-pipe-top" :style="{'top': `${item.pTop}rpx`}">
<u-image src="/static/image/bird/pipe_t.png" width="100%" mode="widthFix" :fade="false"></u-image>
</view>
<view class="bird-pipe-bottom" :style="{'bottom': `${item.pBottom}rpx`}">
<u-image src="/static/image/bird/pipe_b.png" width="100%" mode="widthFix" :fade="false"></u-image>
</view>
</view>
</view>
</view>
<!-- 地板 -->
<view class="land">
<view class="land-1"></view>
<view class="land-2"></view>
<view class="land-box" :class="{'land-move': !isEnd}"></view>
<view class="land-3"></view>
<view class="land-4"></view>
</view>
</view>
</template>
2、游戏样式
<style>
page{background-color: #DED895;}
</style>
<style lang="scss" scoped>
.bird-game{width: 100%;height: calc(100vh - 88rpx)}
.bird-box{
width: 100%;height: 64%;background-color: rgb(0,135,147);
.bird-map{
position: absolute;width: 100%;height: 100%;top: 0;right: 0;bottom: 0;left: 0;z-index: 2;overflow: hidden;
.bird{position: absolute;transition: transform .4s;}
.bird-number{position: absolute;font-size: 70rpx;color: #fff;font-weight: bold;left: 50%;transform: translateX(-50%);top: 60rpx;text-shadow: 8rpx 8rpx 4rpx rgba(0,0,0,1);z-index: 999;}
.bird-start{position: absolute;font-size: 80rpx;color: rgb(47,227,43);font-weight: bold;left: 50%;transform: translateX(-50%);top: 300rpx;text-shadow: 4rpx 4rpx 4rpx rgba(255,255,255,1);}
.bird-pipe{
position: absolute;top: 0;bottom: 0;
.bird-pipe-bottom,
.bird-pipe-top{position: absolute;width: 100%;}
}
}
}
// 小鸟上下摆动
.bird-move{animation: ani_bird .75s infinite cubic-bezier(0.215, 0.61, 0.355, 1);}
@keyframes ani_bird{
0%{transform: translateY(0);}
50%{transform: translateY(-20rpx);}
100%{transform: translateY(0);}
}
// 地面
.land{
.land-box{
width: 100%;height: 40rpx;background: linear-gradient(-45deg, #9BE557 25%, #73BF2E 0%, #73BF2E 50%, #9BE557 0%,#9BE557 75%, #73BF2E 0%,);background-size: 80rpx 80rpx;
background-position: 250% 0;
}
.land-1{width: 100%; height: 4rpx;background-color: #523546;}
.land-2{width: 100%; height: 4rpx;background-color: #DEF886;}
.land-3{width: 100%; height: 4rpx;background-color: #558121;}
.land-4{width: 100%; height: 4rpx;background-color: #E0B24E;}
}
.land-move{animation: ani_land 8.5s linear infinite;}
@keyframes ani_land{
0%{background-position: 250% 0;}
100%{background-position: 0 0;}
}
</style>
3、游戏逻辑
<script>
export default {
data() {
return {
isStart: false, // 游戏是否开始
isEnd: false, // 游戏是否结束
number: 0, // 分数
map:{ // 地图
width: 0,
height: 0,
},
bird:{ // 小鸟
width: 70,
height: 50,
left: 160,
top: 600,
speedStart: 1, // 初始速度
speedPlus: 0.2, // 加速度
speedMax: 10, // 上限速度
flyMaxHeight: 100, // 每点一次飞行的最大高度
flyStageHeight: 10, // 飞行的阶梯增加高度
flyRelaHeight: 0, // 当前飞行的相对高度,也就是飞行的那个过程,高度是多少,因为有时没到达顶部,玩家又点一次
flyDirect: null, // up上升,down下落
},
flyTimer: null,
pipe:{ // 管道
width: 90,
height: 728,
},
pipeVerticel: 200, // 上下管道之间的垂直距离
pipeDistance: 400, // 左右管道之间的水平距离
pipeList: [ // 存放管道数组
{pRight: -300, pTop: -400, pBottom: -400}
],
};
},
onLoad() {
setTimeout(()=>{
this.getMapEle();
},100);
},
onUnload() {
clearInterval(this.flyTimer);
},
methods:{
// 获取地图属性
getMapEle(){
this.$u.getRect('.bird-box').then(res => {
this.map.width = Math.floor(res.width) * 2;
this.map.height = Math.floor(res.height) * 2;
})
},
// 点击屏幕 游戏开始
start(){
if(this.isEnd){
uni.showToast({title: "游戏已结束",icon:'error'});
return;
}
if(this.flyTimer){
clearInterval(this.flyTimer);
this.flyTimer = null;
}
this.isStart = true;
this.bird.flyDirect = 'up';
this.flyTimer = setInterval(()=>{
this.birdFly();
this.pipeMove();
},20)
},
// 小鸟运动
birdFly(){
// 上升
if(this.bird.flyDirect == 'up'){
if(this.bird.flyRelaHeight <= this.bird.flyMaxHeight){
this.bird.top -= this.bird.flyStageHeight;
this.bird.flyRelaHeight += this.bird.flyStageHeight;
}else{
this.bird.flyDirect = 'down';
this.bird.flyRelaHeight = 0;
this.bird.speedStart = 1;
}
}
// 到达顶部
if(this.bird.top <= 0){
this.bird.top = 0;
this.die();
}
// 下降
if(this.bird.flyDirect == 'down'){
this.bird.top = this.bird.top + this.bird.speedStart * this.bird.speedStart;
if(this.bird.speedStart < this.bird.speedMax){
this.bird.speedStart += this.bird.speedPlus;
}
}
// 到达底边
if(this.bird.top >= this.map.height - this.bird.height){
this.bird.top = this.map.height - this.bird.height;
this.die();
}
},
// 管道移动 添加删除管道
pipeMove(){
// 如果数组中的最后一个到达右边的时候,增加一个
if(this.pipeList[this.pipeList.length - 1].pRight >= 0){
// 因为固定了上下管道距离,所以我们只要随机上下其中一个管道的距离值,再用整体高度-上下管道的距离-随机距离 = 另外一个管道的距离
let pipeRandom = this.$u.random(100, 600);
let obj = {
pRight: -(this.pipeList[this.pipeList.length - 1].pRight*1 + this.pipeDistance*1),
pTop: -pipeRandom,
pBottom: -(this.map.height*1 - pipeRandom*1 - this.pipeVerticel*1),
};
this.pipeList.push(obj);
}
// 如果第一个到达左边的时候,删除第一个
if(this.pipeList[0].pRight >= this.map.width){
this.pipeList.shift();
}
// 遍历管道移动
for(let i = 0; i < this.pipeList.length; i++){
let birdMouthRight = this.map.width - this.bird.width - this.bird.left; // 鸟嘴到右边的距离
// 判断是否碰撞管道 (注意:已经飞过的管道需要去除)
// 当没有飞过当前的管道
if(this.pipeList[i].pRight <= this.map.width - this.bird.left){
// 有咩有撞到上管道
if((this.pipeList[i].pRight + this.pipe.width) >= birdMouthRight && (this.pipe.height + this.pipeList[i].pTop) >= this.bird.top){
this.die();
return;
}
// 有咩有撞到下管道
if((this.pipeList[i].pRight + this.pipe.width) >= birdMouthRight && (this.pipe.height + this.pipeList[i].pBottom) >= (this.map.height - this.bird.height - this.bird.top)){
this.die();
return;
}
}
// 判断分数,也就是刚好飞过某一个管道
if(this.pipeList[i].pRight === 592){
this.number++;
}
this.pipeList[i].pRight += 4;
}
},
// 死亡
die(){
clearInterval(this.flyTimer)
this.isEnd = true;
uni.showModal({
content: "你死了",
showCancel: false,
success: res=>{
if (res.confirm) {
this.reset();
}
}
});
},
// 重新开始
reset(){
uni.redirectTo({
url: '/pages/games/bird'
})
},
}
}
</script>