HTML实现类星露谷小游戏

🎮 核心游戏系统

1. 完整的农场操作

  • 🔨 锄头:开垦草地变成可耕种的土地
  • 💧 水壶:给作物浇水,促进生长
  • 🪓 斧头:砍伐树木,获得金币
  • ⛏️ 镐子:开采矿石,获得资源

2. 多样化的作物

  • 🥕 防风草(4天成熟,售价35金)
  • 🥔 土豆(6天成熟,售价80金)
  • 🍅 番茄(8天成熟,售价120金)
  • 🌽 玉米(10天成熟,售价150金)
  • 🍓 草莓(12天成熟,售价220金)

3. 完整的时间与季节系统

  • 每天从6:00到23:00(23点强制睡觉)
  • 四季变化(春→夏→秋→冬)
  • 天气系统(晴天、雨天、暴风雨)
  • 昼夜效果变化

🎯 游戏特色

  • 精美像素风格界面:温暖的渐变色彩和流畅动画
  • 作物生长系统:每天浇水后作物会成长,显示生长阶段
  • 体力系统:工作消耗体力,睡觉恢复
  • 商店系统:购买种子,扩大种植规模
  • 存档/读档:使用localStorage保存游戏进度
  • 通知系统:实时显示操作反馈
  • 浮动文字效果:显示获得的资源和金币
  • 快捷按键
    • 1-4:切换工具
    • Q/E:切换种子

📊 统计与进度

  • 金币数统计
  • 总收获数统计
  • 总收入统计
  • 天数和季节显示

代码直接放在下面,开盖即食:

html 复制代码
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>田园生活 - 农场模拟</title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
 
body {
font-family: 'Courier New', monospace;
background: linear-gradient(180deg, #87CEEB 0%, #98D8C8 100%);
overflow: hidden;
height: 100vh;
}
 
.game-container {
display: flex;
flex-direction: column;
height: 100vh;
}
 
.hud {
display: flex;
justify-content: space-between;
align-items: center;
padding: 15px 30px;
background: linear-gradient(180deg, rgba(101, 67, 33, 0.95) 0%, rgba(139, 90, 43, 0.95) 100%);
border-bottom: 4px solid #654321;
box-shadow: 0 4px 10px rgba(0,0,0,0.3);
z-index: 100;
}
 
.hud-item {
display: flex;
align-items: center;
gap: 10px;
font-size: 1.2rem;
color: #FFE4B5;
text-shadow: 2px 2px 4px rgba(0,0,0,0.5);
}
 
.hud-icon {
font-size: 1.8rem;
}
 
.main-area {
flex: 1;
display: flex;
position: relative;
overflow: hidden;
}
 
.game-world {
flex: 1;
position: relative;
background: linear-gradient(180deg, #7CFC00 0%, #228B22 100%);
overflow: hidden;
}
 
.farm-grid {
display: grid;
grid-template-columns: repeat(12, 64px);
grid-template-rows: repeat(8, 64px);
gap: 2px;
padding: 20px;
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}
 
.tile {
width: 64px;
height: 64px;
display: flex;
align-items: center;
justify-content: center;
font-size: 2.5rem;
cursor: pointer;
transition: all 0.2s ease;
border-radius: 8px;
position: relative;
}
 
.tile:hover {
transform: scale(1.1);
z-index: 10;
}
 
.tile-grass {
background: linear-gradient(135deg, #228B22 0%, #32CD32 100%);
}
 
.tile-tilled {
background: linear-gradient(135deg, #8B4513 0%, #A0522D 100%);
}
 
.tile-watered {
background: linear-gradient(135deg, #654321 0%, #8B4513 100%);
}
 
.tile-rock {
background: linear-gradient(135deg, #696969 0%, #808080 100%);
}
 
.tile-tree {
background: linear-gradient(135deg, #228B22 0%, #32CD32 100%);
}
 
.crop-stage {
position: absolute;
font-size: 2rem;
}
 
.growth-indicator {
position: absolute;
bottom: 5px;
right: 5px;
font-size: 0.7rem;
background: rgba(0,0,0,0.6);
color: white;
padding: 2px 6px;
border-radius: 10px;
}
 
.sidebar {
width: 280px;
background: linear-gradient(180deg, rgba(101, 67, 33, 0.9) 0%, rgba(139, 90, 43, 0.9) 100%);
padding: 20px;
border-left: 4px solid #654321;
box-shadow: -4px 0 10px rgba(0,0,0,0.3);
z-index: 50;
}
 
.tools-section {
margin-bottom: 30px;
}
 
.section-title {
color: #FFE4B5;
font-size: 1.3rem;
margin-bottom: 15px;
text-align: center;
text-shadow: 2px 2px 4px rgba(0,0,0,0.5);
border-bottom: 2px solid #FFE4B5;
padding-bottom: 8px;
}
 
.tools-grid {
display: grid;
grid-template-columns: repeat(4, 1fr);
gap: 10px;
}
 
.tool {
width: 55px;
height: 55px;
background: linear-gradient(135deg, #D2691E 0%, #CD853F 100%);
border: 3px solid #8B4513;
border-radius: 10px;
display: flex;
align-items: center;
justify-content: center;
font-size: 2rem;
cursor: pointer;
transition: all 0.2s ease;
}
 
.tool:hover {
transform: scale(1.1);
box-shadow: 0 0 15px rgba(255, 228, 181, 0.6);
}
 
.tool.active {
background: linear-gradient(135deg, #FFD700 0%, #FFA500 100%);
border-color: #FF8C00;
transform: scale(1.15);
box-shadow: 0 0 20px rgba(255, 215, 0, 0.8);
}
 
.inventory-section {
margin-bottom: 30px;
}
 
.inventory-grid {
display: grid;
grid-template-columns: repeat(4, 1fr);
gap: 8px;
}
 
.inventory-slot {
width: 55px;
height: 55px;
background: linear-gradient(135deg, #F5DEB3 0%, #DEB887 100%);
border: 2px solid #8B4513;
border-radius: 8px;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
cursor: pointer;
transition: all 0.2s ease;
position: relative;
}
 
.inventory-slot:hover {
transform: scale(1.1);
}
 
.inventory-slot.selected {
border-color: #FFD700;
box-shadow: 0 0 15px rgba(255, 215, 0, 0.8);
}
 
.slot-icon {
font-size: 1.8rem;
}
 
.slot-count {
position: absolute;
bottom: 2px;
right: 4px;
font-size: 0.75rem;
font-weight: bold;
color: #000;
text-shadow: 1px 1px 0 #fff;
}
 
.shop-section {
margin-bottom: 20px;
}
 
.shop-item {
display: flex;
align-items: center;
justify-content: space-between;
background: rgba(139, 90, 43, 0.8);
padding: 10px 15px;
border-radius: 8px;
margin-bottom: 10px;
cursor: pointer;
transition: all 0.2s ease;
border: 2px solid transparent;
}
 
.shop-item:hover {
border-color: #FFD700;
transform: translateX(5px);
}
 
.shop-item-left {
display: flex;
align-items: center;
gap: 10px;
color: #FFE4B5;
}
 
.shop-item-icon {
font-size: 1.8rem;
}
 
.shop-item-price {
color: #FFD700;
font-weight: bold;
font-size: 1.1rem;
}
 
.controls-section {
background: rgba(0, 0, 0, 0.2);
padding: 15px;
border-radius: 10px;
}
 
.control-info {
color: #FFE4B5;
font-size: 0.9rem;
margin-bottom: 8px;
display: flex;
justify-content: space-between;
}
 
.btn {
width: 100%;
padding: 12px;
margin-top: 10px;
border: none;
border-radius: 8px;
font-family: 'Courier New', monospace;
font-size: 1rem;
font-weight: bold;
cursor: pointer;
transition: all 0.3s ease;
}
 
.btn-primary {
background: linear-gradient(135deg, #4CAF50 0%, #45a049 100%);
color: white;
}
 
.btn-primary:hover {
transform: translateY(-2px);
box-shadow: 0 5px 15px rgba(76, 175, 80, 0.4);
}
 
.btn-secondary {
background: linear-gradient(135deg, #2196F3 0%, #1976D2 100%);
color: white;
}
 
.btn-secondary:hover {
transform: translateY(-2px);
box-shadow: 0 5px 15px rgba(33, 150, 243, 0.4);
}
 
.notifications {
position: absolute;
top: 20px;
left: 50%;
transform: translateX(-50%);
z-index: 200;
display: flex;
flex-direction: column;
gap: 10px;
}
 
.notification {
background: rgba(0, 0, 0, 0.8);
color: #FFE4B5;
padding: 12px 25px;
border-radius: 10px;
font-size: 1rem;
animation: slideDown 0.3s ease, fadeOut 0.3s ease 2.7s;
border: 2px solid #FFD700;
}
 
@keyframes slideDown {
from { transform: translateY(-20px); opacity: 0; }
to { transform: translateY(0); opacity: 1; }
}
 
@keyframes fadeOut {
from { opacity: 1; }
to { opacity: 0; }
}
 
.day-overlay {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
pointer-events: none;
transition: background 1s ease;
}
 
.weather-effect {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
pointer-events: none;
overflow: hidden;
}
 
.raindrop {
position: absolute;
width: 2px;
height: 20px;
background: linear-gradient(180deg, transparent, rgba(174, 194, 224, 0.8));
animation: rain 0.5s linear infinite;
}
 
@keyframes rain {
from { transform: translateY(-20px); }
to { transform: translateY(100vh); }
}
 
.modal {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: rgba(0, 0, 0, 0.7);
display: none;
align-items: center;
justify-content: center;
z-index: 1000;
}
 
.modal.active {
display: flex;
}
 
.modal-content {
background: linear-gradient(135deg, #8B4513 0%, #A0522D 100%);
padding: 40px;
border-radius: 20px;
border: 4px solid #FFD700;
text-align: center;
max-width: 500px;
box-shadow: 0 20px 50px rgba(0, 0, 0, 0.5);
}
 
.modal-title {
font-size: 2rem;
color: #FFD700;
margin-bottom: 20px;
text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.5);
}
 
.modal-stats {
color: #FFE4B5;
font-size: 1.2rem;
margin: 20px 0;
line-height: 2;
}
 
.floating-text {
position: absolute;
pointer-events: none;
font-size: 1.2rem;
font-weight: bold;
color: #FFD700;
text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.8);
animation: floatUp 1s ease-out forwards;
z-index: 150;
}
 
@keyframes floatUp {
from {
opacity: 1;
transform: translateY(0);
}
to {
opacity: 0;
transform: translateY(-50px);
}
}
 
.tooltip {
position: fixed;
background: rgba(0, 0, 0, 0.9);
color: #FFE4B5;
padding: 8px 12px;
border-radius: 6px;
font-size: 0.9rem;
pointer-events: none;
z-index: 500;
border: 2px solid #FFD700;
}
</style>
</head>
<body>
<div class="game-container">
<div class="hud">
<div class="hud-item">
<span class="hud-icon">💰</span>
<span id="gold-display">500</span>
</div>
<div class="hud-item">
<span class="hud-icon">📅</span>
<span id="date-display">春季 1日</span>
</div>
<div class="hud-item">
<span class="hud-icon">☀️</span>
<span id="time-display">6:00</span>
</div>
<div class="hud-item">
<span class="hud-icon">🌱</span>
<span id="season-display">春季</span>
</div>
<div class="hud-item">
<span class="hud-icon">⚡</span>
<span id="energy-display">100/100</span>
</div>
</div>
 
<div class="main-area">
<div class="game-world">
<div class="day-overlay" id="day-overlay"></div>
<div class="weather-effect" id="weather-effect"></div>
<div class="notifications" id="notifications"></div>
<div class="farm-grid" id="farm-grid"></div>
</div>
 
<div class="sidebar">
<div class="tools-section">
<h3 class="section-title">🔧 工具</h3>
<div class="tools-grid">
<div class="tool active" data-tool="hoe" onclick="selectTool('hoe')" title="锄头 - 耕地">🔨</div>
<div class="tool" data-tool="watering-can" onclick="selectTool('watering-can')" title="水壶 - 浇水">💧</div>
<div class="tool" data-tool="axe" onclick="selectTool('axe')" title="斧头 - 砍树">🪓</div>
<div class="tool" data-tool="pickaxe" onclick="selectTool('pickaxe')" title="镐子 - 挖矿">⛏️</div>
</div>
</div>
 
<div class="inventory-section">
<h3 class="section-title">🎒 物品栏</h3>
<div class="inventory-grid" id="inventory-grid"></div>
</div>
 
<div class="shop-section">
<h3 class="section-title">🏪 商店</h3>
<div class="shop-item" onclick="buySeed('parsnip')">
<div class="shop-item-left">
<span class="shop-item-icon">🥕</span>
<span>防风草种子</span>
</div>
<span class="shop-item-price">20💰</span>
</div>
<div class="shop-item" onclick="buySeed('potato')">
<div class="shop-item-left">
<span class="shop-item-icon">🥔</span>
<span>土豆种子</span>
</div>
<span class="shop-item-price">50💰</span>
</div>
<div class="shop-item" onclick="buySeed('tomato')">
<div class="shop-item-left">
<span class="shop-item-icon">🍅</span>
<span>番茄种子</span>
</div>
<span class="shop-item-price">80💰</span>
</div>
<div class="shop-item" onclick="buySeed('corn')">
<div class="shop-item-left">
<span class="shop-item-icon">🌽</span>
<span>玉米种子</span>
</div>
<span class="shop-item-price">100💰</span>
</div>
<div class="shop-item" onclick="buySeed('strawberry')">
<div class="shop-item-left">
<span class="shop-item-icon">🍓</span>
<span>草莓种子</span>
</div>
<span class="shop-item-price">150💰</span>
</div>
</div>
 
<div class="controls-section">
<h3 class="section-title">📖 操作</h3>
<div class="control-info">
<span>左键点击</span>
<span>使用工具/交互</span>
</div>
<div class="control-info">
<span>1-4</span>
<span>切换工具</span>
</div>
<div class="control-info">
<span>Q/E</span>
<span>切换种子</span>
</div>
<button class="btn btn-primary" onclick="sleep()">🛏️ 睡觉</button>
<button class="btn btn-secondary" onclick="saveGame()">💾 保存</button>
</div>
</div>
</div>
 
<div class="modal" id="game-modal">
<div class="modal-content">
<h2 class="modal-title" id="modal-title">🎉 新的一天!</h2>
<div class="modal-stats" id="modal-stats"></div>
<button class="btn btn-primary" onclick="closeModal()">开始!</button>
</div>
</div>
</div>
 
<script>
let gameState = {
gold: 500,
day: 1,
season: 'spring',
time: 360,
energy: 100,
maxEnergy: 100,
weather: 'sunny',
selectedTool: 'hoe',
selectedSeed: null,
inventory: {
'parsnip_seed': 5,
'potato_seed': 3
},
farm: [],
totalHarvested: 0,
totalGoldEarned: 0
};
 
const crops = {
parsnip: {
name: '防风草',
icon: '🥕',
seedPrice: 20,
sellPrice: 35,
growTime: 4,
stages: ['🌱', '🌿', '🌿', '🥕']
},
potato: {
name: '土豆',
icon: '🥔',
seedPrice: 50,
sellPrice: 80,
growTime: 6,
stages: ['🌱', '🌿', '🌿', '🌿', '🥔', '🥔']
},
tomato: {
name: '番茄',
icon: '🍅',
seedPrice: 80,
sellPrice: 120,
growTime: 8,
stages: ['🌱', '🌿', '🌿', '🌿', '🌿', '🍅', '🍅', '🍅']
},
corn: {
name: '玉米',
icon: '🌽',
seedPrice: 100,
sellPrice: 150,
growTime: 10,
stages: ['🌱', '🌿', '🌿', '🌿', '🌿', '🌿', '🌽', '🌽', '🌽', '🌽']
},
strawberry: {
name: '草莓',
icon: '🍓',
seedPrice: 150,
sellPrice: 220,
growTime: 12,
stages: ['🌱', '🌿', '🌿', '🌿', '🌿', '🌿', '🌿', '🍓', '🍓', '🍓', '🍓', '🍓']
}
};
 
const seasons = ['spring', 'summer', 'autumn', 'winter'];
const seasonNames = {
spring: '春季',
summer: '夏季',
autumn: '秋季',
winter: '冬季'
};
 
const weatherTypes = ['sunny', 'sunny', 'sunny', 'rainy', 'stormy'];
 
function initGame() {
generateFarm();
renderFarm();
renderInventory();
updateHUD();
showNotification('欢迎来到田园生活!开始你的农场之旅吧!');
}
 
function generateFarm() {
gameState.farm = [];
for (let y = 0; y < 8; y++) {
for (let x = 0; x < 12; x++) {
let tile = {
x, y,
type: 'grass',
crop: null,
watered: false,
growthStage: 0
};
 
const rand = Math.random();
if (rand < 0.08) {
tile.type = 'rock';
} else if (rand < 0.15) {
tile.type = 'tree';
}
 
gameState.farm.push(tile);
}
}
}
 
function renderFarm() {
const grid = document.getElementById('farm-grid');
grid.innerHTML = '';
 
gameState.farm.forEach((tile, index) => {
const tileEl = document.createElement('div');
tileEl.className = `tile tile-${tile.type}${tile.watered ? ' tile-watered' : ''}`;
tileEl.dataset.index = index;
 
if (tile.type === 'rock') {
tileEl.textContent = '🪨';
} else if (tile.type === 'tree') {
tileEl.textContent = '🌲';
} else if (tile.crop) {
const cropData = crops[tile.crop];
const stage = Math.min(tile.growthStage, cropData.stages.length - 1);
tileEl.innerHTML = `
<span class="crop-stage">${cropData.stages[stage]}</span>
${tile.growthStage < cropData.growTime ? `<span class="growth-indicator">${tile.growthStage}/${cropData.growTime}</span>` : ''}
`;
}
 
tileEl.onclick = (e) => interactWithTile(index, e);
grid.appendChild(tileEl);
});
}
 
function renderInventory() {
const grid = document.getElementById('inventory-grid');
grid.innerHTML = '';
 
const seeds = Object.entries(gameState.inventory).filter(([id]) => id.endsWith('_seed'));
for (let i = 0; i < 12; i++) {
const slot = document.createElement('div');
slot.className = 'inventory-slot';
 
if (i < seeds.length) {
const [seedId, count] = seeds[i];
const cropType = seedId.replace('_seed', '');
const cropData = crops[cropType];
 
slot.innerHTML = `
<span class="slot-icon">${cropData.icon}</span>
<span class="slot-count">${count}</span>
`;
 
if (gameState.selectedSeed === cropType) {
slot.classList.add('selected');
}
 
slot.onclick = () => selectSeed(cropType);
slot.title = cropData.name + '种子';
}
 
grid.appendChild(slot);
}
}
 
function updateHUD() {
document.getElementById('gold-display').textContent = gameState.gold;
document.getElementById('date-display').textContent = `${seasonNames[gameState.season]} ${gameState.day}日`;
document.getElementById('season-display').textContent = seasonNames[gameState.season];
 
const hours = Math.floor(gameState.time / 60);
const minutes = gameState.time % 60;
document.getElementById('time-display').textContent = `${hours.toString().padStart(2, '0')}:${minutes.toString().padStart(2, '0')}`;
 
document.getElementById('energy-display').textContent = `${gameState.energy}/${gameState.maxEnergy}`;
 
updateDayLight();
}
 
function updateDayLight() {
const overlay = document.getElementById('day-overlay');
let opacity = 0;
if (gameState.time < 360) opacity = 0.4;
else if (gameState.time < 420) opacity = 0.2;
else if (gameState.time > 1080) opacity = 0.5;
else if (gameState.time > 1020) opacity = 0.3;
overlay.style.background = `rgba(25, 25, 50, ${opacity})`;
}
 
function selectTool(tool) {
gameState.selectedTool = tool;
gameState.selectedSeed = null;
document.querySelectorAll('.tool').forEach(t => t.classList.remove('active'));
document.querySelector(`[data-tool="${tool}"]`).classList.add('active');
renderInventory();
}
 
function selectSeed(seedType) {
gameState.selectedSeed = seedType;
gameState.selectedTool = null;
document.querySelectorAll('.tool').forEach(t => t.classList.remove('active'));
renderInventory();
}
 
function interactWithTile(index, event) {
const tile = gameState.farm[index];
 
if (gameState.energy <= 0) {
showNotification('⚠️ 体力不足!去睡觉吧!');
return;
}
 
switch (gameState.selectedTool) {
case 'hoe':
if (tile.type === 'grass') {
tile.type = 'tilled';
gameState.energy -= 3;
showNotification('🔨 耕地成功!');
createFloatingText(event, '+耕地');
}
break;
 
case 'watering-can':
if ((tile.type === 'tilled' || tile.crop) && !tile.watered) {
tile.watered = true;
gameState.energy -= 2;
showNotification('💧 浇水成功!');
createFloatingText(event, '+浇水');
}
break;
 
case 'axe':
if (tile.type === 'tree') {
tile.type = 'grass';
gameState.energy -= 10;
gameState.gold += 20;
showNotification('🪓 砍树获得 20 金币!');
createFloatingText(event, '+20💰');
}
break;
 
case 'pickaxe':
if (tile.type === 'rock') {
tile.type = 'grass';
gameState.energy -= 8;
gameState.gold += 15;
showNotification('⛏️ 挖矿获得 15 金币!');
createFloatingText(event, '+15💰');
}
break;
}
 
if (gameState.selectedSeed && tile.type === 'tilled' && !tile.crop) {
const seedId = gameState.selectedSeed + '_seed';
if (gameState.inventory[seedId] > 0) {
tile.crop = gameState.selectedSeed;
tile.growthStage = 0;
gameState.inventory[seedId]--;
gameState.energy -= 2;
showNotification(`🌱 种植了 ${crops[gameState.selectedSeed].name}!`);
createFloatingText(event, '+种植');
} else {
showNotification('⚠️ 没有足够的种子!');
}
}
 
if (tile.crop) {
const cropData = crops[tile.crop];
if (tile.growthStage >= cropData.growTime) {
const sellPrice = cropData.sellPrice;
gameState.gold += sellPrice;
gameState.totalGoldEarned += sellPrice;
gameState.totalHarvested++;
tile.crop = null;
tile.growthStage = 0;
tile.watered = false;
tile.type = 'tilled';
gameState.energy -= 3;
showNotification(`🎉 收获了 ${cropData.name}!获得 ${sellPrice} 金币!`);
createFloatingText(event, `+${sellPrice}💰`);
}
}
 
renderFarm();
renderInventory();
updateHUD();
}
 
function buySeed(cropType) {
const cropData = crops[cropType];
if (gameState.gold >= cropData.seedPrice) {
gameState.gold -= cropData.seedPrice;
const seedId = cropType + '_seed';
gameState.inventory[seedId] = (gameState.inventory[seedId] || 0) + 1;
showNotification(`✅ 购买了 ${cropData.name} 种子!`);
renderInventory();
updateHUD();
} else {
showNotification('⚠️ 金币不足!');
}
}
 
function sleep() {
advanceDay();
}
 
function advanceDay() {
gameState.day++;
gameState.time = 360;
gameState.energy = gameState.maxEnergy;
 
if (gameState.day > 28) {
gameState.day = 1;
const seasonIndex = seasons.indexOf(gameState.season);
gameState.season = seasons[(seasonIndex + 1) % 4];
showNotification(`🌿 ${seasonNames[gameState.season]}来了!`);
}
 
gameState.weather = weatherTypes[Math.floor(Math.random() * weatherTypes.length)];
updateWeather();
 
gameState.farm.forEach(tile => {
if (tile.crop && tile.watered) {
tile.growthStage++;
}
if (gameState.weather === 'rainy' || gameState.weather === 'stormy') {
if (tile.type === 'tilled' || tile.crop) {
tile.watered = true;
}
} else {
tile.watered = false;
}
});
 
showModal();
 
renderFarm();
updateHUD();
}
 
function updateWeather() {
const weatherEl = document.getElementById('weather-effect');
weatherEl.innerHTML = '';
if (gameState.weather === 'rainy' || gameState.weather === 'stormy') {
for (let i = 0; i < 100; i++) {
const drop = document.createElement('div');
drop.className = 'raindrop';
drop.style.left = Math.random() * 100 + '%';
drop.style.animationDelay = Math.random() * 0.5 + 's';
weatherEl.appendChild(drop);
}
}
}
 
function showModal() {
const modal = document.getElementById('game-modal');
document.getElementById('modal-title').textContent = `🌅 ${seasonNames[gameState.season]} ${gameState.day}日`;
document.getElementById('modal-stats').innerHTML = `
<p>天气: ${gameState.weather === 'sunny' ? '☀️ 晴天' : gameState.weather === 'rainy' ? '🌧️ 雨天' : '⛈️ 暴风雨'}</p>
<p>总收获: ${gameState.totalHarvested}</p>
<p>总收入: ${gameState.totalGoldEarned}💰</p>
`;
modal.classList.add('active');
}
 
function closeModal() {
document.getElementById('game-modal').classList.remove('active');
}
 
function showNotification(message) {
const container = document.getElementById('notifications');
const notification = document.createElement('div');
notification.className = 'notification';
notification.textContent = message;
container.appendChild(notification);
setTimeout(() => notification.remove(), 3000);
}
 
function createFloatingText(event, text) {
const floater = document.createElement('div');
floater.className = 'floating-text';
floater.textContent = text;
floater.style.left = event.clientX + 'px';
floater.style.top = event.clientY + 'px';
document.body.appendChild(floater);
setTimeout(() => floater.remove(), 1000);
}
 
function saveGame() {
localStorage.setItem('stardewGame', JSON.stringify(gameState));
showNotification('💾 游戏已保存!');
}
 
function loadGame() {
const saved = localStorage.getItem('stardewGame');
if (saved) {
gameState = JSON.parse(saved);
return true;
}
return false;
}
 
function timeAdvance() {
if (!document.getElementById('game-modal').classList.contains('active')) {
gameState.time += 10;
if (gameState.time >= 1380) {
showNotification('💤 太晚了!强制睡觉!');
advanceDay();
}
updateHUD();
}
}
 
document.addEventListener('keydown', (e) => {
const tools = ['hoe', 'watering-can', 'axe', 'pickaxe'];
const num = parseInt(e.key);
if (num >= 1 && num <= 4) {
selectTool(tools[num - 1]);
}
if (e.key.toLowerCase() === 'q' || e.key.toLowerCase() === 'e') {
const seeds = Object.keys(gameState.inventory).filter(id => id.endsWith('_seed') && gameState.inventory[id] > 0);
if (seeds.length > 0) {
let currentIndex = seeds.indexOf(gameState.selectedSeed + '_seed');
if (e.key.toLowerCase() === 'q') {
currentIndex = currentIndex <= 0 ? seeds.length - 1 : currentIndex - 1;
} else {
currentIndex = (currentIndex + 1) % seeds.length;
}
selectSeed(seeds[currentIndex].replace('_seed', ''));
}
}
});
 
if (loadGame()) {
showNotification('📂 已加载存档!');
}
initGame();
 
setInterval(timeAdvance, 5000);
</script>
</body>
</html>
相关推荐
Solis程序员2 小时前
拿捏登录安全:RS256 + 双令牌,把非法请求拦在 Redis 白名单门外
java·安全·缓存·面试·bootstrap·html
cq林志炫2 小时前
fastadmin 如何限制访问public\assets\libs目录下面的所有html文件
html·php·fastadmin
x***r15115 小时前
Another-Redis-Desktop-Manager.1.3.7安装步骤详解(附Redis可视化连接与Key管理教程)
前端·bootstrap·html
biubiubiu_LYQ18 小时前
入门开发者基础篇之CSS浮动布局:一文吃透浮动底层逻辑
前端·css
ZC跨境爬虫1 天前
跟着 MDN 学CSS day_45:媒体查询入门指南——从语法到移动优先实践
前端·css·ui·html·tensorflow·媒体
ZC跨境爬虫1 天前
跟着 MDN 学CSS day_47:(移动优先实战——从手机到宽屏的响应式进化)
前端·css·html·tensorflow·媒体
ZC跨境爬虫1 天前
跟着 MDN 学CSS day_46:(响应式实战——用媒体查询打造双列布局)
前端·css·ui·html·tensorflow·媒体
shuoshuohaohao1 天前
《CSS》
前端·css
用户059540174461 天前
Redis持久化踩坑实录:RDB+AOF混合持久化,竟会悄无声息丢数据?我用pytest+Docker复现了30次故障场景
前端·css