diff --git a/src/App.vue b/src/App.vue index 2473673..8b442bb 100644 --- a/src/App.vue +++ b/src/App.vue @@ -3,20 +3,6 @@
- @@ -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; -} diff --git a/src/core/game.ts b/src/core/game.ts index e3f904c..df99183 100644 --- a/src/core/game.ts +++ b/src/core/game.ts @@ -24,6 +24,7 @@ const useGame = () => { const currSlotNum = ref(0); // 保存所有块(包括随机块) + const allBlocks: BlockType[] = []; const blockData: Record = {}; // 总块数 @@ -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 = {}; + 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, }; }; diff --git a/src/core/gameConfig.ts b/src/core/gameConfig.ts index 5c7ded1..c538b46 100644 --- a/src/core/gameConfig.ts +++ b/src/core/gameConfig.ts @@ -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, // 需要多少个一样块的才能合成 diff --git a/src/core/globalStore.ts b/src/core/globalStore.ts index 0f4f6d4..e2892cb 100644 --- a/src/core/globalStore.ts +++ b/src/core/globalStore.ts @@ -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() { diff --git a/src/core/type.d.ts b/src/core/type.d.ts index feccf2e..a8a6a19 100644 --- a/src/core/type.d.ts +++ b/src/core/type.d.ts @@ -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; +} diff --git a/src/pages/ConfigPage.vue b/src/pages/ConfigPage.vue index 115448f..23e11fc 100644 --- a/src/pages/ConfigPage.vue +++ b/src/pages/ConfigPage.vue @@ -53,9 +53,9 @@ import { defaultGameConfig } from "../core/gameConfig"; const formRef = ref(); const router = useRouter(); const { setGameConfig, setCustomConfig } = useGlobalStore(); -const config = reactive({ ...defaultGameConfig }); +const config = reactive({ ...defaultGameConfig }); -const handleFinish = (values: GameConfig) => { +const handleFinish = (values: GameConfigType) => { setGameConfig(config); setCustomConfig(config); router.push("/game"); diff --git a/src/pages/GamePage.vue b/src/pages/GamePage.vue index f969494..0deac2b 100644 --- a/src/pages/GamePage.vue +++ b/src/pages/GamePage.vue @@ -5,25 +5,25 @@

恭喜,你赢啦!🎉

- + 程序员鱼皮
-
-
- {{ block.type }} +
+
+
+ {{ block.type }} +
@@ -35,11 +35,13 @@ >
{{ randomBlock[0].type }}
+
+ + + 撤回 + 移出 + 洗牌 + 破坏 +
@@ -77,6 +86,10 @@ const { heightUnit, doClickBlock, doStart, + doShuffle, + doBroke, + doRemove, + doRevert, } = useGame(); /** diff --git a/src/pages/IndexPage.vue b/src/pages/IndexPage.vue index 1a14fb2..5f56168 100644 --- a/src/pages/IndexPage.vue +++ b/src/pages/IndexPage.vue @@ -39,6 +39,20 @@ 代码完全开源,欢迎 star
+ @@ -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; +}