vue3版本网页小游戏_vue写个小游戏

// 前置点击如果槽位满了还没有消除完
fullFun()

// 关卡的消除
let tempList = fixFun(k, onekSub, onek, oneiSub)

// 消除动作 和 添加爆炸效果
if (footerList.value.length > 2) {
isNotClick.value = true
const { list, flag } = eliminationFunction(footerList.value)
footerList.value = list;
if (flag) {
footerList.value = addBoomFunction(footerList.value);
}
setTimeout(() => {
const { list, flag } = eliminationFunction(footerList.value)
footerList.value = list;
isNotClick.value = false
}, 1000);

// 进入下一关
nextFun(tempList)

}
// 挑战失败
failFun(tempList)

console.log(footerList, tempList, “tempList”);
}
// full
function fullFun() {
if (footerList.value.length === 7) {
ElMessage.closeAll();

ElMessageBox.alert("挑战失败,点击确定返回!", "Warning", {
  confirmButtonText: "确定",
  type: "warning",
  showClose: false,
}).then(() => {
  location.reload();
});
return false;

}
}
// fix
function fixFun(k: number, onekSub: number, onek: number, oneiSub: Array) {
const { value } = totalList;

let tempList = JSON.parse(JSON.stringify(value));

for (let i = 0; i < tempList.length; i++) {
const one = tempList[k].one;
for (let j = 0; j < one.length; j++) {
const oneSub = one[onek];
for (let k = 0; k < oneSub.oneSub.length; k++) {
if (onekSub === k) {
const footItem = oneSub.oneSub.splice(onekSub);
break;
}
}
}
}
footerList.value.push(oneiSub);
totalList.value = tempList;
return tempList
}
//fail
function failFun(tempList: any[]) {
setTimeout(() => {
if (footerList.value.length > 0 && !jugeList(tempList)) {
ElMessage.closeAll();

  ElMessageBox.alert("挑战失败,点击确定返回!", "Warning", {
    confirmButtonText: "确定",
    type: "warning",
    showClose: false,
  }).then(() => {
    location.reload();
  });
  return false;
}

}, 1002)
}
// next
function nextFun(tempList: any[]) {
setTimeout(() => {
if (!footerList.value.length && !jugeList(tempList)) {
// debugger
ElMessage.closeAll();
ElMessage.success(“恭喜您,挑战成功!进入下一关”);
store.step++;
const inStep: string = “list” + (store.step + 1);
totalList.value = JSON.parse(JSON.stringify(data))[inStep];
footerList.value = [];
}
}, 1001)
}
// 判断是否过关
function jugeList(list: any[]) {
let temp: any = [];
list?.forEach((oeni: { one: any }) => {
oeni?.one?.forEach((sub: { oneSub: any }) => {
temp = […temp, …sub.oneSub];
});
});
return temp.length;
}

// 消除函数
function eliminationFunction(list: any[]) {
let flag: boolean = false;
for (let k = 0; k < list.length - 2; k++) {
const temp = list;
const arr = temp.slice(k, k + 3);
console.log(k, arr);
if (arr[0] === arr[1] && arr[1] === arr[2] && arr[0] === arr[2]) {
list.splice(k + 2);
list.splice(k + 1);
list.splice(k, 1);
flag = true
break;
}
}

return { list, flag };
}

// 实现爆炸💥效果
function addBoomFunction(list: any[]) {
const temp = JSON.parse(JSON.stringify([…list, …[‘boom’, ‘boom’, ‘boom’]]))
return temp;
}

.el-row {
// margin-top: 3rem;
height: 28%;
}

.fz {
font-size: 3rem;
border: 1px solid #dfe5f9;
// box-shadow: 2px 2px 10px #f3f6fe;

background: #f3f6fe;
border-radius: 5px;
}

.pic-list {
position: relative;
width: 100%;
height: 100%;

&-item {
position: absolute;
left: 10vw;
cursor: pointer;
transition: all 0.3s;

&:nth-child(1n) {
  top: calc(var(--i) * 1.5rem);
}

&.true {
  box-shadow: 0 -55px 0 0 #dfe5f9 inset;
}

// &:nth-child(even) {
//   top: 2rem;
// }

}
}

.sheep-main {
flex: 1;

&-wrap {
height: calc(100% - 80px);
}
}

.sheep-footer {
height: 80px;
width: 100%;
// border: 2px solid #298df9;
border: 2px solid #778899;
background: #010206;

.sheep-footer-items {
height: 80px;
width: calc(100% / 7);
margin-left: 8px;
display: flex;
align-items: center;
justify-content: center;

.boom-class {
  font-size: 3rem;
  animation: myMove 3s ease-in-out infinite;
}

@keyframes myMove {
  0% {
    opacity: 1;
  }

  100% {
    opacity: 0;
  }
}

// border-right: 1px solid #dfe5f9;

}
}


## 3.核心逻辑分步骤详解



> 
> import { ref, type Ref } from "vue";
> 
> 
> import { ElMessage, ElMessageBox } from "element-plus";
> 
> 
> import { useSheepStore } from "@/stores/sheep";
> 
> 
> // 关卡数据
> 
> 
> import data from "./data.json";
> 
> 
> // 颜色
> 
> 
> import constants from "./constants";
> 
> 
> // pinia 控制关卡
> 
> 
> const store = useSheepStore();
> 
> 
> 


首先引入data.json数据是渲染中间的页面内容,即是:


![](https://img-blog.csdnimg.cn/cac29ea1764545a09200c0b322076923.png)


中间的就叫卡片区域吧,卡片分为半个遮挡和整个遮挡,在data数据里面配置:



> 
> "full": true
> 
> 
> 


 默认是半个遮挡,配置了"full": true就表示这块的卡片是全遮挡的效果:



> 
> :style="!onei.full ? `--i:${onekSub}` : `--i:0`"
> 
> 
> :class="onei.full && onei.oneSub.length > 1 ? 'true' : ''" :key="'i' + onekSub"
> 
> 
> 


css: 使用了var的变量形式,来控制是否需要top下移,&.true来控制是否有下一级的卡片的样式



> 
> &:nth-child(1n) {
> 
> 
> top: calc(var(--i) \* 1.5rem);
> 
> 
> }
> 
> 
> 
> &.true {
> 
> 
>         box-shadow: 0 -55px 0 0 #dfe5f9 inset;
> 
> 
> }
> 
> 
> 


data.json里面的数据oneSub的选值范围是:0-10


这和dom渲染层的息息相关:卡片使用的是简单的icon也可以是其他类型的元素,你觉得好看即可。



            <el-icon class="fz" v-if="oneiSub === 0">
              <StarFilled :color="colors[0]" />
            </el-icon>
            <el-icon class="fz" v-if="oneiSub === 1">
              <Aim :color="colors[1]" />
            </el-icon>
            <el-icon class="fz" v-if="oneiSub === 2">
              <Grid :color="colors[2]" />
            </el-icon>
            <el-icon class="fz" v-if="oneiSub === 3">
              <HelpFilled :color="colors[3]" />
            </el-icon>
            <el-icon class="fz" v-if="oneiSub === 4">
              <Star :color="colors[4]" />
            </el-icon>
            <el-icon class="fz" v-if="oneiSub === 5">
              <Menu :color="colors[5]" />
            </el-icon>
            <el-icon class="fz" v-if="oneiSub === 6">
              <Camera :color="colors[6]" />
            </el-icon>
            <el-icon class="fz" v-if="oneiSub === 7">
              <Bicycle :color="colors[7]" />
            </el-icon>
            <el-icon class="fz" v-if="oneiSub === 8">
              <IceTea :color="colors[8]" />
            </el-icon>
            <el-icon class="fz" v-if="oneiSub === 9">
              <ColdDrink :color="colors[9]" />
            </el-icon>
            <el-icon class="fz" v-if="oneiSub === 10">
              <CoffeeCup :color="colors[10]" />
            </el-icon>

这里只提供11中卡片的效果,可以扩展添加,需要修改代码。


接下来是:



> 
> // 七个槽位
> 
> 
> // const footerList = ref([0, 1, 2, 3, 4, 5, 6]);
> 
> 
> const footerList: Ref<Array<any> | [any]> = ref([]);
> 
> 
> 
> const colors = ref(constants.colors);
> 
> 
> 
> // 关卡响应式
> 
> 
> const totalList: Ref<Array<any> | [any]> = ref([]);
> 
> 
> totalList.value = data["list1"]; // 默认第一关
> 
> 
> 
> // 控制动画效果结束才能点击
> 
> 
> const isNotClick = ref(false);
> 
> 
> 
> 


7个槽位在底部需要变化展示,做成响应式。totalList是动态变化的卡片数据集。totalList.value = data["list1"] ,默认第一关。爆炸💥的电话效果有延迟,需要控制在结束之后才能进行卡片的点击。


然后就是核心的卡片点击事件,需要做哪些逻辑控制呢?先看源代码,已经提前做了备注:



// 点击控制事件
function handleClick(
i: number,
k: number,
onei: { oneSub: string | Array },
onek: number,
oneiSub: Array,
onekSub: number
) {
console.log(i, k, onei, onek, oneiSub, onekSub, “测试”);
if (isNotClick.value) {
return false;
}
// 内层不能点击
if (onekSub !== onei.oneSub.length - 1) {
return false;
}

// 前置点击如果槽位满了还没有消除完
fullFun()

// 关卡的消除
let tempList = fixFun(k, onekSub, onek, oneiSub)

// 消除动作 和 添加爆炸效果
if (footerList.value.length > 2) {
isNotClick.value = true
const { list, flag } = eliminationFunction(footerList.value)
footerList.value = list;
if (flag) {
footerList.value = addBoomFunction(footerList.value);
}
setTimeout(() => {
const { list, flag } = eliminationFunction(footerList.value)
footerList.value = list;
isNotClick.value = false
}, 1000);

// 进入下一关
nextFun(tempList)

}
// 挑战失败
failFun(tempList)

console.log(footerList, tempList, “tempList”);
}


首先是函数的签名,接受最上层级的i对象,k索引,然后是中层的onei对象,onek索引,最后是父级的oneiSub对象,onekSub索引。判断条件需要前置,判断能否点击isNotClick,内层不能点击



> 
> if (isNotClick.value) {
> 
> 
>         return false;
> 
> 
> }
> 
> 
> 


// 前置点击如果槽位满了还没有消除完


fullFun()函数判断如果槽位满了还没有消除完,就是挑战失败



function fullFun() {
if (footerList.value.length === 7) {
ElMessage.closeAll();

ElMessageBox.alert("挑战失败,点击确定返回!", "Warning", {
  confirmButtonText: "确定",
  type: "warning",
  showClose: false,
}).then(() => {
  location.reload();
});
return false;

}
}


如何添加爆炸💥效果:


思路是在三个相同消除之后添加,添加在totalList数据之中 ,效果展示完成之后立即进行totalList数据重置操作。



// 关卡的消除
let tempList = fixFun(k, onekSub, onek, oneiSub)

// 消除动作 和 添加爆炸效果
if (footerList.value.length > 2) {
isNotClick.value = true
const { list, flag } = eliminationFunction(footerList.value)
footerList.value = list;
if (flag) {
footerList.value = addBoomFunction(footerList.value);
}
setTimeout(() => {
const { list, flag } = eliminationFunction(footerList.value)
footerList.value = list;
isNotClick.value = false
}, 1000);

// 进入下一关
nextFun(tempList)

}


css 添加的方法:



.boom-class {
  font-size: 3rem;
  animation: myMove 3s ease-in-out infinite;
}

@keyframes myMove {
  0% {
    opacity: 1;
  }

  100% {
    opacity: 0;
  }
}

消除函数eliminationFunction逻辑的控制,flag用来进行是否成功消除:



// 消除函数
function eliminationFunction(list: any[]) {
let flag: boolean = false;
for (let k = 0; k < list.length - 2; k++) {
const temp = list;
const arr = temp.slice(k, k + 3);
console.log(k, arr);
if (arr[0] === arr[1] && arr[1] === arr[2] && arr[0] === arr[2]) {
list.splice(k + 2);
list.splice(k + 1);
list.splice(k, 1);
flag = true
break;
}
}

return { list, flag };
}


添加addBoomFunction爆炸函数:



// 实现爆炸💥效果
function addBoomFunction(list: any[]) {
const temp = JSON.parse(JSON.stringify([…list, …[‘boom’, ‘boom’, ‘boom’]]))
return temp;
}


挑战失败如何判断呢?



//fail
function failFun(tempList: any[]) {
setTimeout(() => {
if (footerList.value.length > 0 && !jugeList(tempList)) {
ElMessage.closeAll();

  ElMessageBox.alert("挑战失败,点击确定返回!", "Warning", {
    confirmButtonText: "确定",
    type: "warning",
    showClose: false,
  }).then(() => {
    location.reload();
  });
  return false;
}

}, 1002)
}


jugeList函数是对目前存在的卡片集合进行长度判断,如何卡片不存在,但是槽位的数据不为空的情况下,说明没有消除完,就判断要重新开始挑战: 



// 判断是否过关
function jugeList(list: any[]) {
let temp: any = [];
list?.forEach((oeni: { one: any }) => {
oeni?.one?.forEach((sub: { oneSub: any }) => {
temp = […temp, …sub.oneSub];
});
});

最后

ion failFun(tempList: any[]) {
setTimeout(() => {
if (footerList.value.length > 0 && !jugeList(tempList)) {
ElMessage.closeAll();

  ElMessageBox.alert("挑战失败,点击确定返回!", "Warning", {
    confirmButtonText: "确定",
    type: "warning",
    showClose: false,
  }).then(() => {
    location.reload();
  });
  return false;
}

}, 1002)
}


jugeList函数是对目前存在的卡片集合进行长度判断,如何卡片不存在,但是槽位的数据不为空的情况下,说明没有消除完,就判断要重新开始挑战: 



// 判断是否过关
function jugeList(list: any[]) {
let temp: any = [];
list?.forEach((oeni: { one: any }) => {
oeni?.one?.forEach((sub: { oneSub: any }) => {
temp = […temp, …sub.oneSub];
});
});

最后

  • 17
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,我可以给你提供一个简单的示例:猜数字小游戏。 1. 在Vue3中创建一个新的组件,名为`GuessNumberGame`。 2. 在组件中定义一个响应式数据`guessNumber`,用于存储玩家猜的数字。 ``` <template> <div> <h1>猜数字小游戏</h1> <p>猜一个1到100的数字:</p> <input v-model="guessNumber" type="number" /> <button @click="checkGuess">猜!</button> <p v-if="message">{{message}}</p> </div> </template> <script> import { ref } from 'vue'; export default { setup() { const guessNumber = ref(null); const message = ref(''); const checkGuess = () => { // 随机生成一个1到100的整数 const randomNumber = Math.floor(Math.random() * 100) + 1; if (guessNumber.value === randomNumber) { message.value = '恭喜你,猜对了!'; } else if (guessNumber.value < randomNumber) { message.value = '你猜小了,请再试一次。'; } else { message.value = '你猜大了,请再试一次。'; } }; return { guessNumber, message, checkGuess }; } }; </script> ``` 3. 在模板中添加一个输入框和一个按钮,用于让玩家输入猜测的数字,并调用`checkGuess`方法进行验证。 4. 在`checkGuess`方法中,先生成一个1到100的随机整数作为答案,然后与玩家猜测的数字进行比较,根据比较结果更新`message`的值,提示玩家猜对了还是猜错了。 5. 最后,将`guessNumber`和`message`添加到`setup`函数的返回值中,以便在模板中使用。 这是一个简单的Vue3小游戏示例,你可以根据自己的需求进行修改和扩展。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值