Files
text-adventure-game/App.vue
Claude 16223c89a5 feat: 实现游戏核心系统和UI组件
核心系统:
- combatSystem: 战斗逻辑、伤害计算、战斗状态管理
- skillSystem: 技能系统、技能解锁、经验值、里程碑
- taskSystem: 任务系统、任务类型、任务执行和完成
- eventSystem: 事件系统、随机事件处理
- environmentSystem: 环境系统、时间流逝、区域效果
- levelingSystem: 升级系统、属性成长
- soundSystem: 音效系统

配置文件:
- enemies: 敌人配置、掉落表
- events: 事件配置、事件效果
- items: 物品配置、装备属性
- locations: 地点配置、探索事件
- skills: 技能配置、技能树

UI组件:
- CraftingDrawer: 制造界面
- InventoryDrawer: 背包界面
- 其他UI优化和动画

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-23 16:20:10 +08:00

428 lines
8.4 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<script setup>
import { onLaunch, onShow, onHide } from '@dcloudio/uni-app'
import { useGameStore } from '@/store/game.js'
import { usePlayerStore } from '@/store/player.js'
import {
saveGame,
loadGame,
resetGame as resetGameStorage,
hasSaveData
} from '@/utils/storage.js'
import {
startGameLoop,
stopGameLoop,
isGameLoopRunning,
calculateOfflineEarnings,
applyOfflineEarnings,
updateLastSaveTime,
refreshMarketPrices
} from '@/utils/gameLoop.js'
import { checkAndTriggerEvent } from '@/utils/eventSystem.js'
import { addItemToInventory } from '@/utils/itemSystem.js'
import { unlockSkill } from '@/utils/skillSystem.js'
// 记录应用隐藏时间(用于计算离线收益)
let appHideTime = Date.now()
onLaunch(() => {
try {
console.log('App Launch')
// 初始化Store
const gameStore = useGameStore()
const playerStore = usePlayerStore()
// 设置自动保存触发器
gameStore.triggerAutoSave = () => {
performAutoSave()
}
// 设置事件触发器
gameStore.triggerEvent = (type, context) => {
checkAndTriggerEvent(gameStore, playerStore, type, context)
}
// 加载存档
const loadResult = loadGame(gameStore, playerStore)
if (loadResult.success) {
// 存档加载成功
console.log('Save loaded, version:', loadResult.version)
// 添加欢迎日志
gameStore.addLog('欢迎回来!', 'info')
// 初始化市场价格(如果需要)
if (gameStore.gameTime.day !== gameStore.marketPrices.lastRefreshDay) {
refreshMarketPrices(gameStore)
}
} else if (loadResult.isNewGame) {
// 新游戏
console.log('Starting new game')
initializeNewGame(gameStore, playerStore)
} else {
// 加载失败,重置游戏
console.error('Load failed, resetting game')
resetGameStorage(gameStore, playerStore)
initializeNewGame(gameStore, playerStore)
}
// 启动游戏循环
startGameLoop(gameStore, playerStore)
// 更新保存时间
updateLastSaveTime()
} catch (error) {
console.error('App Launch failed:', error)
// 可以在这里显示友好的错误提示
}
})
onShow(() => {
console.log('App Show')
const gameStore = useGameStore()
const playerStore = usePlayerStore()
// 检查离线收益
checkOfflineEarnings(gameStore, playerStore)
// 确保游戏循环正在运行
if (!isGameLoopRunning()) {
startGameLoop(gameStore, playerStore)
}
})
onHide(() => {
console.log('App Hide')
const gameStore = useGameStore()
const playerStore = usePlayerStore()
// 记录隐藏时间
appHideTime = Date.now()
// 自动保存
performAutoSave()
// 停止游戏循环
stopGameLoop()
})
/**
* 初始化新游戏
* @param {Object} gameStore - 游戏Store
* @param {Object} playerStore - 玩家Store
*/
function initializeNewGame(gameStore, playerStore) {
// 重置所有数据
resetGameStorage(gameStore, playerStore)
// 给予初始货币
playerStore.currency.copper = 500 // 500铜币 = 5银币
// 给予初始物品
addItemToInventory(playerStore, 'wooden_stick', 1)
addItemToInventory(playerStore, 'bread', 5)
// 解锁木棍精通技能
unlockSkill(playerStore, 'stick_mastery')
// 添加欢迎日志
gameStore.addLog('欢迎来到荒野求生!', 'info')
gameStore.addLog('你在营地醒来,身边有一些铜币和物资...', 'story')
// 初始化市场价格
refreshMarketPrices(gameStore)
// 触发初始事件
checkAndTriggerEvent(gameStore, playerStore, 'enter', { locationId: 'camp' })
}
/**
* 检查并应用离线收益
* @param {Object} gameStore - 游戏Store
* @param {Object} playerStore - 玩家Store
*/
function checkOfflineEarnings(gameStore, playerStore) {
const now = Date.now()
const offlineSeconds = Math.floor((now - appHideTime) / 1000)
// 离线时间不足1分钟不计算收益
if (offlineSeconds < 60) {
return
}
// 计算离线收益
const earnings = calculateOfflineEarnings(
gameStore,
playerStore,
offlineSeconds
)
// 应用离线收益
if (earnings && (Object.keys(earnings.skillExp || {}).length > 0 || earnings.currency > 0)) {
applyOfflineEarnings(gameStore, playerStore, earnings)
gameStore.addLog(`离线 ${earnings.timeDisplay} 期间获得了收益`, 'info')
}
// 更新隐藏时间,避免重复计算
appHideTime = now
}
/**
* 执行自动保存
* @returns {boolean} 是否保存成功
*/
function performAutoSave() {
const gameStore = useGameStore()
const playerStore = usePlayerStore()
const success = saveGame(gameStore, playerStore)
if (success) {
console.log('Auto-save completed')
} else {
console.error('Auto-save failed')
}
return success
}
/**
* 手动保存游戏(暴露给全局)
* @returns {boolean}
*/
window.manualSave = function () {
return performAutoSave()
}
/**
* 获取存档信息(暴露给全局)
* @returns {Object|null}
*/
window.getSaveInfo = function () {
const gameStore = useGameStore()
const playerStore = usePlayerStore()
return {
gameTime: gameStore.gameTime,
playerLevel: playerStore.level.current,
location: playerStore.currentLocation,
hasSave: hasSaveData()
}
}
/**
* 解锁木棍精通技能(用于测试)
*/
window.unlockStickSkill = function () {
const playerStore = usePlayerStore()
unlockSkill(playerStore, 'stick_mastery')
return 'stick_mastery unlocked'
}
</script>
<style lang="scss">
/* 全局样式 */
@import '@/uni.scss';
page {
background-color: $bg-primary;
color: $text-primary;
font-size: 28rpx;
line-height: 1.6;
}
/* 滚动条样式 */
::-webkit-scrollbar {
width: 8rpx;
}
::-webkit-scrollbar-thumb {
background-color: $bg-tertiary;
border-radius: 4rpx;
}
/* ==================== 过渡动画 ==================== */
/* 淡入淡出 */
.fade-enter-active,
.fade-leave-active {
transition: opacity 0.3s ease;
}
.fade-enter-from,
.fade-leave-to {
opacity: 0;
}
/* 滑动进入 - 从右侧 */
.slide-right-enter-active,
.slide-right-leave-active {
transition: all 0.3s ease;
}
.slide-right-enter-from {
transform: translateX(100%);
opacity: 0;
}
.slide-right-leave-to {
transform: translateX(100%);
opacity: 0;
}
/* 滑动进入 - 从左侧 */
.slide-left-enter-active,
.slide-left-leave-active {
transition: all 0.3s ease;
}
.slide-left-enter-from {
transform: translateX(-100%);
opacity: 0;
}
.slide-left-leave-to {
transform: translateX(-100%);
opacity: 0;
}
/* 滑动进入 - 从下方 */
.slide-up-enter-active,
.slide-up-leave-active {
transition: all 0.3s ease;
}
.slide-up-enter-from {
transform: translateY(100%);
opacity: 0;
}
.slide-up-leave-to {
transform: translateY(100%);
opacity: 0;
}
/* 缩放动画 */
.scale-enter-active,
.scale-leave-active {
transition: all 0.2s ease;
}
.scale-enter-from,
.scale-leave-to {
transform: scale(0.9);
opacity: 0;
}
/* 弹跳动画 */
.bounce-enter-active {
animation: bounce-in 0.4s ease;
}
.bounce-leave-active {
animation: bounce-in 0.3s ease reverse;
}
@keyframes bounce-in {
0% {
transform: scale(0);
opacity: 0;
}
50% {
transform: scale(1.05);
}
100% {
transform: scale(1);
opacity: 1;
}
}
/* 闪烁动画 */
@keyframes flash {
0%, 100% { opacity: 1; }
50% { opacity: 0.5; }
}
.flash {
animation: flash 0.5s ease;
}
/* 脉冲动画 */
@keyframes pulse {
0%, 100% {
transform: scale(1);
opacity: 1;
}
50% {
transform: scale(1.05);
opacity: 0.8;
}
}
.pulse {
animation: pulse 1.5s ease infinite;
}
/* 摇晃动画 */
@keyframes shake {
0%, 100% { transform: translateX(0); }
25% { transform: translateX(-10rpx); }
75% { transform: translateX(10rpx); }
}
.shake {
animation: shake 0.3s ease;
}
/* 旋转加载 */
@keyframes spin {
from { transform: rotate(0deg); }
to { transform: rotate(360deg); }
}
.spin {
animation: spin 1s linear infinite;
}
/* 打字机效果 */
@keyframes typewriter {
from { width: 0; }
to { width: 100%; }
}
/* ==================== 工具类 ==================== */
/* 过渡效果 */
.transition-all {
transition: all 0.3s ease;
}
.transition-fast {
transition: all 0.15s ease;
}
.transition-slow {
transition: all 0.5s ease;
}
/* 悬停效果 */
.hover-scale {
transition: transform 0.2s ease;
}
.hover-scale:active {
transform: scale(0.95);
}
.hover-bright {
transition: filter 0.2s ease;
}
.hover-bright:active {
filter: brightness(1.2);
}
</style>