add 添加 4 种道具

This commit is contained in:
yupi 2022-09-17 12:09:46 +08:00
parent 200b2a47d0
commit 9b8077c536
8 changed files with 189 additions and 66 deletions

View File

@ -3,20 +3,6 @@
<div class="content">
<router-view />
</div>
<div class="footer">
鱼了个鱼 ©2022 by
<a href="https://github.com/liyupi" target="_blank" style="color: #fff">
程序员鱼皮
</a>
|
<a
href="https://github.com/liyupi/yulegeyu"
target="_blank"
style="color: #fff"
>
代码开源
</a>
</div>
</div>
</template>
<script setup lang="ts"></script>
@ -27,15 +13,4 @@
min-height: 100vh;
background-size: 100% 100%;
}
.footer {
background: rgba(0, 0, 0, 0.6);
color: #fff;
padding: 12px;
text-align: center;
position: fixed;
bottom: 0;
left: 0;
right: 0;
}
</style>

View File

@ -24,6 +24,7 @@ const useGame = () => {
const currSlotNum = ref(0);
// 保存所有块(包括随机块)
const allBlocks: BlockType[] = [];
const blockData: Record<number, BlockType> = {};
// 总块数
@ -43,6 +44,9 @@ const useGame = () => {
// 保存整个 "棋盘" 的每个格子状态(下标为格子起始点横纵坐标)
let chessBoard: ChessBoardUnitType[][] = [];
// 操作历史(存储点击的块)
let opHistory: BlockType[] = [];
/**
*
* @param width
@ -80,9 +84,12 @@ const useGame = () => {
console.log("块数单位", blockNumUnit);
// 随机生成的总块数
const totalRandomBlockNum = gameConfig.randomBlocks.reduce((pre, curr) => {
return pre + curr;
}, 0);
const totalRandomBlockNum = gameConfig.randomBlocks.reduce(
(pre: number, curr: number) => {
return pre + curr;
},
0
);
console.log("随机生成的总块数", totalRandomBlockNum);
// 需要的最小块数
@ -112,7 +119,6 @@ const useGame = () => {
const randomAnimalBlocks = _.shuffle(animalBlocks);
// 初始化
const allBlocks: BlockType[] = [];
for (let i = 0; i < totalBlockNum; i++) {
const newBlock = {
id: i,
@ -130,7 +136,7 @@ const useGame = () => {
// 3. 计算随机生成的块
const randomBlocks: BlockType[][] = [];
gameConfig.randomBlocks.forEach((randomBlock, idx) => {
gameConfig.randomBlocks.forEach((randomBlock: number, idx: number) => {
randomBlocks[idx] = [];
for (let i = 0; i < randomBlock; i++) {
randomBlocks[idx].push(allBlocks[pos]);
@ -271,15 +277,15 @@ const useGame = () => {
/**
*
* @param block
* @param e
* @param randomIdx >= 0
* @param force
*/
const doClickBlock = (block: BlockType, e: Event, randomIdx = -1) => {
const doClickBlock = (block: BlockType, randomIdx = -1, force = false) => {
// 已经输了 / 已经被点击 / 有上层块,不能再点击
if (
currSlotNum.value >= gameConfig.slotNum ||
block.status !== 0 ||
block.lowerThanBlocks.length > 0
(block.lowerThanBlocks.length > 0 && !force)
) {
return;
}
@ -293,9 +299,8 @@ const useGame = () => {
randomBlocksVal.value[randomIdx].length
);
} else {
// 删除节点
// @ts-ignore
e.target.remove();
// 非随机区才可撤回
opHistory.push(block);
// 移除覆盖关系
block.higherThanBlocks.forEach((higherThanBlock) => {
_.remove(higherThanBlock.lowerThanBlocks, (lowerThanBlock) => {
@ -333,6 +338,8 @@ const useGame = () => {
slotBlock.status = 2;
// 已消除块数 +1
clearBlockNum++;
// 清除操作记录,防止撤回
opHistory = [];
return;
}
newSlotAreaVal[tempSlotNum++] = slotBlock;
@ -364,6 +371,93 @@ const useGame = () => {
gameStatus.value = 1;
};
// region 技能
/**
*
*
* @desc
*/
const doShuffle = () => {
// 遍历所有未消除的块
const originBlocks = allBlocks.filter((block) => block.status === 0);
const newBlockTypes = _.shuffle(originBlocks.map((block) => block.type));
let pos = 0;
originBlocks.forEach((block) => {
block.type = newBlockTypes[pos++];
});
levelBlocksVal.value = [...levelBlocksVal.value];
};
/**
*
*
* @desc
*/
const doBroke = () => {
// 类型,块列表映射
const typeBlockMap: Record<string, BlockType[]> = {};
const blocks = levelBlocksVal.value.filter((block) => block.status === 0);
// 遍历所有未消除的层级块
for (let i = 0; i < blocks.length; i++) {
const block = blocks[i];
if (!typeBlockMap[block.type]) {
typeBlockMap[block.type] = [];
}
typeBlockMap[block.type].push(block);
// 有能消除的一组块
if (typeBlockMap[block.type].length >= gameConfig.composeNum) {
typeBlockMap[block.type].forEach((clickBlock) => {
doClickBlock(clickBlock, -1, true);
});
console.log("doBroke", typeBlockMap[block.type]);
break;
}
}
};
/**
*
*
* @desc 退
*/
const doRevert = () => {
if (opHistory.length < 1) {
return;
}
opHistory[opHistory.length - 1].status = 0;
// @ts-ignore
slotAreaVal.value[currSlotNum.value - 1] = null;
};
/**
*
*/
const doRemove = () => {
// 移除第一个块
const block = slotAreaVal.value[0];
if (!block) {
return;
}
// 槽移除块
for (let i = 0; i < slotAreaVal.value.length - 1; i++) {
slotAreaVal.value[i] = slotAreaVal.value[i - 1];
}
// @ts-ignore
slotAreaVal.value[slotAreaVal.value.length - 1] = null;
// 改变新块的坐标
block.x = Math.floor(Math.random() * (boxWidthNum - 2));
block.y = boxHeightNum - 2;
block.status = 0;
// 移除的是随机块的元素,移到层级区域
if (block.level < 1) {
block.level = 10000;
levelBlocksVal.value.push(block);
}
};
// endregion
return {
gameStatus,
levelBlocksVal,
@ -371,8 +465,14 @@ const useGame = () => {
slotAreaVal,
widthUnit,
heightUnit,
currSlotNum,
opHistory,
doClickBlock,
doStart,
doShuffle,
doBroke,
doRemove,
doRevert,
};
};

View File

@ -23,7 +23,7 @@ const animals = [
"🐂",
];
export const defaultGameConfig: GameConfig = {
export const defaultGameConfig: GameConfigType = {
// 槽容量
slotNum: 7,
// 需要多少个一样块的才能合成
@ -45,7 +45,7 @@ export const defaultGameConfig: GameConfig = {
/**
*
*/
export const easyGameConfig: GameConfig = {
export const easyGameConfig: GameConfigType = {
// 槽容量
slotNum: 7,
// 需要多少个一样块的才能合成
@ -67,7 +67,7 @@ export const easyGameConfig: GameConfig = {
/**
*
*/
export const middleGameConfig: GameConfig = {
export const middleGameConfig: GameConfigType = {
// 槽容量
slotNum: 7,
// 需要多少个一样块的才能合成
@ -89,7 +89,7 @@ export const middleGameConfig: GameConfig = {
/**
*
*/
export const hardGameConfig: GameConfig = {
export const hardGameConfig: GameConfigType = {
// 槽容量
slotNum: 7,
// 需要多少个一样块的才能合成
@ -111,7 +111,7 @@ export const hardGameConfig: GameConfig = {
/**
*
*/
export const lunaticGameConfig: GameConfig = {
export const lunaticGameConfig: GameConfigType = {
// 槽容量
slotNum: 7,
// 需要多少个一样块的才能合成

View File

@ -24,10 +24,10 @@ export const useGlobalStore = defineStore("global", {
},
},
actions: {
setGameConfig(gameConfig: GameConfig) {
setGameConfig(gameConfig: GameConfigType) {
this.gameConfig = gameConfig;
},
setCustomConfig(customConfig: GameConfig) {
setCustomConfig(customConfig: GameConfigType) {
this.customConfig = customConfig;
},
reset() {

14
src/core/type.d.ts vendored
View File

@ -24,9 +24,9 @@ interface ChessBoardUnitType {
}
/**
*
*
*/
interface GameConfig {
interface GameConfigType {
// 槽容量
slotNum: number;
// 需要多少个一样块的才能合成
@ -48,3 +48,13 @@ interface GameConfig {
// 最下层块数最小值(已废弃)
// minBottomBlockNum: 20,
}
/**
*
*/
interface SkillType {
name: string;
desc: string;
icon: string;
action: function;
}

View File

@ -53,9 +53,9 @@ import { defaultGameConfig } from "../core/gameConfig";
const formRef = ref<FormInstance>();
const router = useRouter();
const { setGameConfig, setCustomConfig } = useGlobalStore();
const config = reactive<GameConfig>({ ...defaultGameConfig });
const config = reactive<GameConfigType>({ ...defaultGameConfig });
const handleFinish = (values: GameConfig) => {
const handleFinish = (values: GameConfigType) => {
setGameConfig(config);
setCustomConfig(config);
router.push("/game");

View File

@ -5,25 +5,25 @@
<!-- 胜利 -->
<div v-if="gameStatus === 3" style="text-align: center">
<h2>恭喜你赢啦🎉</h2>
<img src="../assets/kunkun.png" />
<img alt="程序员鱼皮" src="../assets/kunkun.png" />
</div>
<!-- 分层选块 -->
<div class="level-board">
<div
v-for="(block, idx) in levelBlocksVal"
v-show="gameStatus > 0"
:key="idx"
class="block level-block"
:class="{ disabled: block.lowerThanBlocks.length > 0 }"
:data-id="block.id"
:style="{
zIndex: 100 + block.level,
left: block.x * widthUnit + 'px',
top: block.y * heightUnit + 'px',
}"
@click="(e) => doClickBlock(block, e)"
>
{{ block.type }}
<div v-show="gameStatus > 0" class="level-board">
<div v-for="(block, idx) in levelBlocksVal" :key="idx">
<div
v-if="block.status === 0"
class="block level-block"
:class="{ disabled: block.lowerThanBlocks.length > 0 }"
:data-id="block.id"
:style="{
zIndex: 100 + block.level,
left: block.x * widthUnit + 'px',
top: block.y * heightUnit + 'px',
}"
@click="() => doClickBlock(block)"
>
{{ block.type }}
</div>
</div>
</div>
<!-- 随机选块 -->
@ -35,11 +35,13 @@
>
<div
v-if="randomBlock.length > 0"
:data-id="randomBlock[0].id"
class="block"
@click="(e) => doClickBlock(randomBlock[0], e, index)"
@click="() => doClickBlock(randomBlock[0], index)"
>
{{ randomBlock[0].type }}
</div>
<!-- 隐藏 -->
<div
v-for="num in Math.max(randomBlock.length - 1, 0)"
:key="num"
@ -57,6 +59,13 @@
{{ slotBlock?.type }}
</div>
</div>
<!-- 技能 -->
<a-space style="margin-top: 16px">
<a-button size="small" @click="doRevert">撤回</a-button>
<a-button size="small" @click="doRemove">移出</a-button>
<a-button size="small" @click="doShuffle">洗牌</a-button>
<a-button size="small" @click="doBroke">破坏</a-button>
</a-space>
</a-row>
</div>
</template>
@ -77,6 +86,10 @@ const {
heightUnit,
doClickBlock,
doStart,
doShuffle,
doBroke,
doRemove,
doRevert,
} = useGame();
/**

View File

@ -39,6 +39,20 @@
代码完全开源欢迎 star
</div>
</a>
<div class="footer">
鱼了个鱼 ©2022 by
<a href="https://github.com/liyupi" target="_blank" style="color: #fff">
程序员鱼皮
</a>
|
<a
href="https://github.com/liyupi/yulegeyu"
target="_blank"
style="color: #fff"
>
代码开源
</a>
</div>
</div>
</template>
@ -57,7 +71,7 @@ const router = useRouter();
const { setGameConfig } = useGlobalStore();
const toGamePage = (config?: GameConfig) => {
const toGamePage = (config?: GameConfigType) => {
if (config) {
setGameConfig(config);
router.push("/game");
@ -71,4 +85,15 @@ const toGamePage = (config?: GameConfig) => {
#indexPage {
text-align: center;
}
.footer {
background: rgba(0, 0, 0, 0.6);
color: #fff;
padding: 12px;
text-align: center;
position: fixed;
bottom: 0;
left: 0;
right: 0;
}
</style>