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"> <div class="content">
<router-view /> <router-view />
</div> </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> </div>
</template> </template>
<script setup lang="ts"></script> <script setup lang="ts"></script>
@ -27,15 +13,4 @@
min-height: 100vh; min-height: 100vh;
background-size: 100% 100%; 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> </style>

View File

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

View File

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

View File

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

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

@ -24,9 +24,9 @@ interface ChessBoardUnitType {
} }
/** /**
* *
*/ */
interface GameConfig { interface GameConfigType {
// 槽容量 // 槽容量
slotNum: number; slotNum: number;
// 需要多少个一样块的才能合成 // 需要多少个一样块的才能合成
@ -48,3 +48,13 @@ interface GameConfig {
// 最下层块数最小值(已废弃) // 最下层块数最小值(已废弃)
// minBottomBlockNum: 20, // 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 formRef = ref<FormInstance>();
const router = useRouter(); const router = useRouter();
const { setGameConfig, setCustomConfig } = useGlobalStore(); const { setGameConfig, setCustomConfig } = useGlobalStore();
const config = reactive<GameConfig>({ ...defaultGameConfig }); const config = reactive<GameConfigType>({ ...defaultGameConfig });
const handleFinish = (values: GameConfig) => { const handleFinish = (values: GameConfigType) => {
setGameConfig(config); setGameConfig(config);
setCustomConfig(config); setCustomConfig(config);
router.push("/game"); router.push("/game");

View File

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

View File

@ -39,6 +39,20 @@
代码完全开源欢迎 star 代码完全开源欢迎 star
</div> </div>
</a> </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> </div>
</template> </template>
@ -57,7 +71,7 @@ const router = useRouter();
const { setGameConfig } = useGlobalStore(); const { setGameConfig } = useGlobalStore();
const toGamePage = (config?: GameConfig) => { const toGamePage = (config?: GameConfigType) => {
if (config) { if (config) {
setGameConfig(config); setGameConfig(config);
router.push("/game"); router.push("/game");
@ -71,4 +85,15 @@ const toGamePage = (config?: GameConfig) => {
#indexPage { #indexPage {
text-align: center; 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> </style>