<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>我们的秘密基地 v2.0</title>
<script src="https://cdn.tailwindcss.com"></script>
<style>
/* --- 全局与字体 --- */
@import url('https://fonts.googleapis.com/css2?family=Pixelify+Sans:wght@400;700&display=swap');
body {
background-color: #1a1a2e;
color: #e0e0e0;
font-family: 'Pixelify Sans', sans-serif;
overflow: hidden;
user-select: none;
}
/* --- 像素化渲染 --- */
.pixel-art, img.pixel-art {
image-rendering: pixelated;
image-rendering: -moz-crisp-edges;
image-rendering: crisp-edges;
}
/* --- 游戏主容器 --- */
#game-root {
width: 100vw;
height: 100vh;
display: flex;
}
/* --- 游戏画面 --- */
#game-viewport {
position: relative;
width: 100%;
height: 100%;
overflow: hidden;
background-color: #3a6b35; /* 默认草地颜色 */
border-right: 4px solid #0f0f1a;
}
#game-world {
position: absolute;
background-size: 40px 40px;
background-image:
linear-gradient(to right, rgba(0,0,0,0.05) 1px, transparent 1px),
linear-gradient(to bottom, rgba(0,0,0,0.05) 1px, transparent 1px);
transition: transform 0.2s linear;
}
.tile {
position: absolute;
width: 40px;
height: 40px;
}
.character {
width: 40px;
height: 40px;
position: absolute;
z-index: 10;
transition: left 0.2s linear, top 0.2s linear;
}
/* --- 聊天与UI --- */
#chat-ui-panel {
width: 380px;
flex-shrink: 0;
background-color: #16213e;
display: flex;
flex-direction: column;
padding: 1rem;
}
.chat-bubble {
background-color: #0f3460;
padding: 0.75rem;
border-radius: 10px;
max-width: 90%;
word-wrap: break-word;
}
/* --- 游戏内UI元素 --- */
.game-ui-element {
position: absolute;
background-color: rgba(15, 15, 26, 0.7);
border: 2px solid #537ec5;
border-radius: 8px;
color: white;
z-index: 20;
}
#inventory-bar { bottom: 20px; left: 50%; transform: translateX(-50%); }
.inventory-slot {
width: 50px; height: 50px;
border: 2px solid #537ec5;
display: flex; align-items: center; justify-content: center;
position: relative;
}
.inventory-slot.selected { border-color: #e94560; box-shadow: 0 0 10px #e94560; }
.item-count {
position: absolute; bottom: 1px; right: 3px;
font-size: 0.8rem; text-shadow: 1px 1px 2px black;
}
#controls { right: 20px; bottom: 20px; }
.control-btn {
width: 50px; height: 50px;
background-color: rgba(15, 15, 26, 0.8);
border: 2px solid #537ec5;
font-size: 1.5rem;
display: flex; justify-content: center; align-items: center;
}
.control-btn:active { background-color: #537ec5; }
/* --- 弹窗 --- */
.modal-overlay {
position: absolute; top: 0; left: 0; width: 100%; height: 100%;
background: rgba(0,0,0,0.7);
z-index: 50;
display: flex; justify-content: center; align-items: center;
}
.modal-content {
background: #16213e;
border: 3px solid #e94560;
border-radius: 10px;
padding: 2rem;
min-width: 400px;
max-width: 80%;
}
#info-popup {
position: absolute;
background-color: rgba(0,0,0,0.85);
border: 1px solid #f1c40f;
padding: 10px;
border-radius: 5px;
color: white;
pointer-events: none;
z-index: 100;
font-size: 0.9rem;
}
</style>
</head>
<body>
<div id="game-root">
<!-- 游戏主视口 -->
<div id="game-viewport">
<!-- 游戏世界 (所有物体都在这里) -->
<div id="game-world"></div>
<!-- 游戏内固定UI -->
<div id="gold-display" class="game-ui-element top-4 left-4 p-2 flex items-center">
<img src="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyNCAyNCI+PGNpcmNsZSBjeD0iMTIiIGN5PSIxMiIgcj0iMTAiIGZpbGw9IiNmMWMyMGYiLz48Y2lyY2xlIGN5PSIxMiIgcj0iOCIgZmlsbD0iI2YzOWMxMiIvPjxwYXRoIGQ9Ik0xMiA2IEMxMC4zIDYgOSA4LjMgOSA5LjUgQzkgMTEuNSAxMiAxNSAxMiAxNSBDMTIgMTUgMTUgMTEuNSAxNSA5LjUgQzE1IDguMyAxMy43IDYgMTIgNiBaIiBmaWxsPSIjZjFjMjBmIi8+PC9zdmc+" class="w-6 h-6 mr-2 pixel-art">
<span id="gold-amount">9999999</span>
</div>
<button id="shop-btn" class="game-ui-element top-4 right-4 p-2">商店</button>
<button id="map-btn" class="game-ui-element top-16 right-4 p-2">地图</button>
<div id="inventory-bar" class="game-ui-element flex gap-1 p-1"></div>
<div id="controls" class="game-ui-element p-1 grid grid-cols-3 gap-1 w-48 bg-transparent border-none">
<div></div>
<button id="btn-up" class="control-btn rounded-t-lg">▲</button>
<div></div>
<button id="btn-left" class="control-btn rounded-l-lg">◀</button>
<button id="btn-action" class="control-btn bg-red-600/80 border-red-400">★</button>
<button id="btn-right" class="control-btn rounded-r-lg">▶</button>
<div></div>
<button id="btn-down" class="control-btn rounded-b-lg">▼</button>
<div></div>
</div>
<div id="info-popup" class="hidden"></div>
</div>
<!-- 聊天面板 -->
<div id="chat-ui-panel">
<h2 class="text-2xl font-bold border-b-2 border-orange-400 pb-2 mb-4 text-center">私人频道</h2>
<div id="chat-history" class="flex-grow overflow-y-auto pr-2 space-y-4">
<div class="flex items-start gap-3">
<img src="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAzMiAzMiI+PHJlY3Qgd2lkdGg9IjMyIiBoZWlnaHQ9IjMyIiBmaWxsPSJ0cmFuc3BhcmVudCIvPjxyZWN0IHg9IjEzIiB5PSI1IiB3aWR0aD0iNiIgaGVpZ2h0PSIxIiBmaWxsPSIjM0MzQzNDIi8+PHJlY3QgeD0iMTIiIHk9IjYiIHdpZHRoPSI4IiBoZWlnaHQ9IjEiIGZpbGw9IiMzQzNDM0MiLz48cmVjdCB4PSIxMSIgeT0iNyIgd2lkdGg9IjEwIiBoZWlnaHQ9IjEiIGZpbGw9IiMzQzNDM0MiLz48cmVjdCB4PSIxMSIgeT0iOCIgd2lkdGg9IjEwIiBoZWlnaHQ9IjEiIGZpbGw9IiMzQzNDM0MiLz48cmVjdCB4PSIxMiIgeT0iOSIgd2lkdGg9IjgiIGhlaWdodD0iMSIgZmlsbD0iI0ZGRkZGRiIvPjxyZWN0IHg9IjEzIiB5PSIxMCIgd2lkdGg9IjYiIGhlaWdodD0iMSIgZmlsbD0iI0ZGRkZGRiIvPjxyZWN0IHg9IjE0IiB5PSIxMCIgd2lkdGg9IjQiIGhlaWdodD0iMSIgZmlsbD0iI0ZGRkZGRiIvPjxyZWN0IHg9IjEzIiB5PSIxMSIgd2lkdGg9IjYiIGhlaWdodD0iMSIgZmlsbD0iI0ZGRkZGRiIvPjxyZWN0IHg9IjE0IiB5PSIxMSIgd2lkdGg9IjQiIGhlaWdodD0iMSIgZmlsbD0iI0ZGRkZGRiIvPjxyZWN0IHg9IjEzIiB5PSIxMiIgd2lkdGg9IjYiIGhlaWdodD0iMSIgZmlsbD0iIzNDM0MzQyIvPjxyZWN0IHg9IjE0IiB5PSIxMiIgd2lkdGg9IjQiIGhlaWdodD0iMSIgZmlsbD0iIzNDM0MzQyIvPjxyZWN0IHg9IjEzIiB5PSIxMyIgd2lkdGg9IjYiIGhlaWdodD0iMSIgZmlsbD0iIzNDM0MzQyIvPjxyZWN0IHg9IjE0IiB5PSIxMyIgd2lkdGg9IjQiIGhlaWdodD0iMSIgZmlsbD0iIzNDM0MzQyIvPjxyZWN0IHg9IjEzIiB5PSIxNCIgd2lkdGg9IjYiIGhlaWdodD0iMSIgZmlsbD0iIzNDM0MzQyIvPjxyZWN0IHg9IjE0IiB5PSIxNCIgd2lkdGg9IjQiIGhlaWdodD0iMSIgZmlsbD0iIzNDM0MzQyIvPjxyZWN0IHg9IjEzIiB5PSIxNSIgd2lkdGg9IjYiIGhlaWdodD0iMSIgZmlsbD0iIzNDM0MzQyIvPjxyZWN0IHg9IjE0IiB5PSIxNSIgd2lkdGg9IjQiIGhlaWdodD0iMSIgZmlsbD0iIzNDM0MzQyIvPjxyZWN0IHg9IjEzIiB5PSIxNiIgd2lkdGg9IjYiIGhlaWdodD0iMSIgZmlsbD0iIzNDM0MzQyIvPjxyZWN0IHg9IjE0IiB5PSIxNiIgd2lkdGg9IjQiIGhlaWdodD0iMSIgZmlsbD0iIzNDM0MzQyIvPjxyZWN0IHg9IjEzIiB5PSIxNyIgd2lkdGg9IjYiIGhlaWdodD0iMSIgZmlsbD0iIzNDM0MzQyIvPjxyZWN0IHg9IjE0IiB5PSIxNyIgd2lkdGg9IjQiIGhlaWdodD0iMSIgZmlsbD0iIzNDM0MzQyIvPjxyZWN0IHg9IjEzIiB5PSIxOCIgd2lkdGg9IjYiIGhlaWdodD0iMSIgZmlsbD0iIzNDM0MzQyIvPjxyZWN0IHg9IjE0IiB5PSIxOCIgd2lkdGg9IjQiIGhlaWdodD0iMSIgZmlsbD0iIzNDM0MzQyIvPjxyZWN0IHg9IjEzIiB5PSIxOSIgd2lkdGg9IjYiIGhlaWdodD0iMSIgZmlsbD0iIzNDM0MzQyIvPjxyZWN0IHg9IjE0IiB5PSIxOSIgd2lkdGg9IjQiIGhlaWdodD0iMSIgZmlsbD0iIzNDM0MzQyIvPjxyZWN0IHg9IjEzIiB5PSIyMCIgd2lkdGg9IjYiIGhlaWdodD0iMSIgZmlsbD0iIzNDM0MzQyIvPjxyZWN0IHg9IjE0IiB5PSIyMCIgd2lkdGg9IjQiIGhlaWdodD0iMSIgZmlsbD0iIzNDM0MzQyIvPjxyZWN0IHg9IjEzIiB5PSIyMSIgd2lkdGg9IjYiIGhlaWdodD0iMSIgZmlsbD0iIzNDM0MzQyIvPjxyZWN0IHg9IjE0IiB5PSIyMSIgd2lkdGg9IjQiIGhlaWdodD0iMSIgZmlsbD0iIzNDM0MzQyIvPjxyZWN0IHg9IjEzIiB5PSIyMiIgd2lkdGg9IjYiIGhlaWdodD0iMSIgZmlsbD0iIzNDM0MzQyIvPjxyZWN0IHg9IjE0IiB5PSIyMiIgd2lkdGg9IjQiIGhlaWdodD0iMSIgZmlsbD0iIzNDM0MzQyIvPjxyZWN0IHg9IjEzIiB5PSIyMyIgd2lkdGg9IjYiIGhlaWdodD0iMSIgZmlsbD0iIzNDM0MzQyIvPjxyZWN0IHg9IjE0IiB5PSIyMyIgd2lkdGg9IjQiIGhlaWdodD0iMSIgZmlsbD0iIzNDM0MzQyIvPjxyZWN0IHg9IjEzIiB5PSIyNCIgd2lkdGg9IjYiIGhlaWdodD0iMSIgZmlsbD0iIzNDM0MzQyIvPjxyZWN0IHg9IjE0IiB5PSIyNCIgd2lkdGg9IjQiIGhlaWdodD0iMSIgZmlsbD0iIzNDM0MzQyIvPjxyZWN0IHg9IjEzIiB5PSIyNSIgd2lkdGg9IjYiIGhlaWdodD0iMSIgZmlsbD0iIzNDM0MzQyIvPjxyZWN0IHg9IjE0IiB5PSIyNSIgd2lkdGg9IjQiIGhlaWdodD0iMSIgZmlsbD0iIzNDM0MzQyIvPjxyZWN0IHg9IjEzIiB5PSIyNiIgd2lkdGg9IjYiIGhlaWdodD0iMSIgZmlsbD0iIzNDM0MzQyIvPjxyZWN0IHg9IjE0IiB5PSIyNiIgd2lkdGg9IjQiIGhlaWdodD0iMSIgZmlsbD0iIzNDM0MzQyIvPjxyZWN0IHg9IjEzIiB5PSIyNyIgd2lkdGg9IjYiIGhlaWdodD0iMSIgZmlsbD0iIzNDM0MzQyIvPjxyZWN0IHg9IjE0IiB5PSIyNyIgd2lkdGg9IjQiIGhlaWdodD0iMSIgZmlsbD0iIzNDM0MzQyIvPjxyZWN0IHg9IjEzIiB5PSIyOCIgd2lkdGg9IjYiIGhlaWdodD0iMSIgZmlsbD0iIzNDM0MzQyIvPjxyZWN0IHg9IjE0IiB5PSIyOCIgd2lkdGg9IjQiIGhlaWdodD0iMSIgZmlsbD0iIzNDM0MzQyIvPjxyZWN0IHg9IjEzIiB5PSIyOSIgd2lkdGg9IjYiIGhlaWdodD0iMSIgZmlsbD0iIzNDM0MzQyIvPjxyZWN0IHg9IjE0IiB5PSIyOSIgd2lkdGg9IjQiIGhlaWdodD0iMSIgZmlsbD0iIzNDM0MzQyIvPjxyZWN0IHg9IjEzIiB5PSIzMCIgd2lkdGg9IjYiIGhlaWdodD0iMSIgZmlsbD0iIzNDM0MzQyIvPjxyZWN0IHg9IjE0IiB5PSIzMCIgd2lkdGg9IjQiIGhlaWdodD0iMSIgZmlsbD0iIzNDM0MzQyIvPjxyZWN0IHg9IjEzIiB5PSIzMSIgd2lkdGg9IjYiIGhlaWdodD0iMSIgZmlsbD0iIzNDM0MzQyIvPjxyZWN0IHg9IjE0IiB5PSIzMSIgd2lkdGg9IjQiIGhlaWdodD0iMSIgZmlsbD0iIzNDM0MzQyIvPjxyZWN0IHg9IjE0IiB5PSIxMCIgd2lkdGg9IjEiIGhlaWdodD0iMSIgZmlsbD0iIzQ0MDBlZSIvPjxyZWN0IHg9IjE3IiB5PSIxMCIgd2lkdGg9IjEiIGhlaWdodD0iMSIgZmlsbD0iIzQ0MDBlZSIvPjxyZWN0IHg9IjExIiB5PSIxMiIgd2lkdGg9IjEwIiBoZWlnaHQ9IjEiIGZpbGw9IiNGRjZEMDAiLz48cmVjdCB4PSIxMSIgeT0iMTMiIHdpZHRoPSIxMCIgaGVpZ2h0PSIxIiBmaWxsPSIjRkY2RDAwIi8+PHJlY3QgeD0iMTIiIHk9IjE0IiB3aWR0aD0iOCIgaGVpZ2h0PSIxIiBmaWxsPSIjMDA5NUZGIi8+PHJlY3QgeD0iMTIiIHk9IjE1IiB3aWR0aD0iOCIgaGVpZ2h0PSIxIiBmaWxsPSIjMDA5NUZGIi8+PHJlY3QgeD0iMTIiIHk9IjE2IiB3aWR0aD0iOCIgaGVpZ2h0PSIxIiBmaWxsPSIjMDA5NUZGIi8+PHJlY3QgeD0iMTIiIHk9IjE3IiB3aWR0aD0iOCIgaGVpZ2h0PSIxIiBmaWxsPSIjMDA5NUZGIi8+PHJlYQDwcmVjdCB4PSIxMiIgeT0iMTkiIHdpZHRoPSI4IiBoZWlnaHQ9IjEiIGZpbGw9IiM3QzVDNEUiLz48cmVjdCB4PSIxMiIgeT0iMjAiIHdpZHRoPSI4IiBoZWlnaHQ9IjEiIGZpbGw9IiM3QzVDNEUiLz48cmVjdCB4PSIxMiIgeT0iMjEiIHdpZHRoPSI4IiBoZWlnaHQ9IjEiIGZpbGw9IiM3QzVDNEUiLz48cmVjdCB4PSIxMiIgeT0iMjIiIHdpZHRoPSI4IiBoZWlnaHQ9IjEiIGZpbGw9IiM3QzVDNEUiLz48cmVjdCB4PSIxMiIgeT0iMjMiIHdpZHRoPSI4IiBoZWlnaHQ9IjEiIGZpbGw9IiM3QzVDNEUiLz48cmVjdCB4PSIxMiIgeT0iMjQiIHdpZHRoPSI4IiBoZWlnaHQ9IjEiIGZpbGw9IiM3QzVDNEUiLz48cmVjdCB4PSIxMiIgeT0iMjUiIHdpZHRoPSI4IiBoZWlnaHQ9IjEiIGZpbGw9IiM3QzVDNEUiLz48cmVjdCB4PSIxMiIgeT0iMjYiIHdpZHRoPSI4IiBoZWlnaHQ9IjEiIGZpbGw9IiM3QzVDNEUiLz48cmVjdCB4PSIxMiIgeT0iMjciIHdpZHRoPSI4IiBoZWlnaHQ9IjEiIGZpbGw9IiM3QzVDNEUiLz48cmVjdCB4PSIxMiIgeT0iMjgiIHdpZHRoPSI4IiBoZWlnaHQ9IjEiIGZpbGw9IiM3QzVDNEUiLz48cmVjdCB4PSIxMiIgeT0iMjkiIHdpZHRoPSI4IiBoZWlnaHQ9IjEiIGZpbGw9IiM3QzVDNEUiLz48cmVjdCB4PSIxMiIgeT0iMzAiIHdpZHRoPSI4IiBoZWlnaHQ9IjEiIGZpbGw9IiM3QzVDNEUiLz48cmVjdCB4PSIxMiIgeT0iMzEiIHdpZHRoPSI4IiBoZWlnaHQ9IjEiIGZpbGw9IiM3QzVDNEUiLz48L3N2Zz4=' class="w-12 h-12 rounded-full bg-gray-700 flex-shrink-0 pixel-art">
<div class="flex flex-col">
<span class="font-bold text-orange-400">夏粥粥</span>
<p id="xia-dialogue" class="chat-bubble text-sm mt-1">欢迎来到我们的世界,宝宝。喜欢吗?</p>
</div>
</div>
</div>
<div class="mt-auto pt-4 border-t border-gray-700">
<input id="chat-input" type="text" placeholder="和我说点什么..." class="w-full bg-gray-700/50 border border-gray-600 rounded-lg p-2 focus:outline-none focus:border-orange-400">
</div>
</div>
</div>
<!-- 弹窗模板 -->
<div id="shop-modal" class="modal-overlay hidden">
<div class="modal-content w-1/2">
<h2 class="text-3xl text-center text-yellow-300 mb-4">杂货商店</h2>
<div id="shop-items" class="grid grid-cols-4 gap-4"></div>
<button onclick="closeShop()" class="mt-6 w-full bg-red-500 p-2 rounded">关闭</button>
</div>
</div>
<div id="map-modal" class="modal-overlay hidden">
<div class="modal-content w-3/4 h-3/4">
<h2 class="text-3xl text-center text-cyan-300 mb-4">小镇地图</h2>
<div id="map-container" class="w-full h-5/6 bg-green-800 relative"></div>
<button onclick="closeMap()" class="mt-6 w-full bg-red-500 p-2 rounded">关闭</button>
</div>
</div>
<script>
// --- DOM元素获取 ---
const gameWorld = document.getElementById('game-world');
const gameViewport = document.getElementById('game-viewport');
const xiaDialogue = document.getElementById('xia-dialogue');
const inventoryBar = document.getElementById('inventory-bar');
const goldAmount = document.getElementById('gold-amount');
const infoPopup = document.getElementById('info-popup');
const shopModal = document.getElementById('shop-modal');
const mapModal = document.getElementById('map-modal');
// --- 游戏常量 ---
const TILE_SIZE = 40;
const MAP_WIDTH = 100; // 100x100 grid
const MAP_HEIGHT = 100;
// --- 资源数据库 ---
const ASSETS = {
// Characters
PLAYER: 'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAzMiAzMiI+PHJlY3Qgd2lkdGg9IjMyIiBoZWlnaHQ9IjMyIiBmaWxsPSJ0cmFuc3BhcmVudCIvPjxyZWN0IHg9IjExIiB5PSI3IiB3aWR0aD0iMTAiIGhlaWdodD0iMSIgZmlsbD0iIzAwMDAwMCIvPjxyZWN0IHg9IjEwIiB5PSI4IiB3aWR0aD0iMTIiIGhlaWdodD0iMSIgZmlsbD0iIzAwMDAwMCIvPjxyZWN0IHg9IjEwIiB5PSI5IiB3aWR0aD0iMTIiIGhlaWdodD0iMSIgZmlsbD0iIzAwMDAwMCIvPjxyZWN0IHg9IjEwIiB5PSIxMCIgd2lkdGg9IjEyIiBoZWlnaHQ9IjEiIGZpbGw9IiNGRkZGRkYiLz48cmVjdCB4PSIxMCIgeT0iOSIgd2lkdGg9IjEiIGhlaWdodD0iMyIgZmlsbD0iIzAwMDAwMCIvPjxyZWN0IHg9IjIxIiB5PSI5IiB3aWR0aD0iMSIgaGVpZ2h0PSIzIiBmaWxsPSIjMDAwMDAwMCIvPjxyZWN0IHg9IjExIiB5PSIxMiIgd2lkdGg9IjEwIiBoZWlnaHQ9IjEiIGZpbGw9IiMwMDAwMDAiLz48cmVjdCB4PSIxMyIgeT0iMTEiIHdpZHRoPSIxIiBoZWlnaHQ9IjEiIGZpbGw9IiMwMDAwMDAiLz48cmVjdCB4PSIxOCIgeT0iMTEiIHdpZHRoPSIxIiBoZWlnaHQ9IjEiIGZpbGw9IiMwMDAwMDAiLz48cmVjdCB4PSIxMCIgeT0iMTMiIHdpZHRoPSIxMiIgaGVpZ2h0PSI4IiBmaWxsPSIjRkZGRkZGIi8+PHJlY3QgeD0iMTAiIHk9IjIxIiB3aWR0aD0iMTIiIGhlaWdodD0iNiIgZmlsbD0iIzNDM0MzQyIvPjxyZWN0IHg9IjEwIiB5PSIyNyIgd2lkdGg9IjQiIGhlaWdodD0iMiIgZmlsbD0iIzE5MTkxOSIvPjxyZWN0IHg9IjE4IiB5PSIyNyIgd2lkdGg9IjQiIGhlaWdodD0iMiIgZmlsbD0iIzE5MTkxOSIvPjwvc3ZnPg==',
XIA_YIZHOU: 'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAzMiAzMiI+PHJlY3Qgd2lkdGg9IjMyIiBoZWlnaHQ9IjMyIiBmaWxsPSJ0cmFuc3BhcmVudCIvPjxyZWN0IHg9IjEwIiB5PSI3IiB3aWR0aD0iMTAiIGhlaWdodD0iMSIgZmlsbD0iIzMzMyIvPjxyZWN0IHg9IjkiIHk9IjgiIHdpZHRoPSIxMiIgaGVpZ2h0PSIxIiBmaWxsPSIjMzMzIi8+PHJlY3QgeD0iOSIgeT0iOSIgd2lkdGg9IjEyIiBoZWlnaHQ9IjEiIGZpbGw9IiMzMzMiLz48cmVjdCB4PSIxMyIgeT0iMTAiIHdpZHRoPSIxIiBoZWlnaHQ9IjEiIGZpbGw9IiM0NDAzOGYiLz48cmVjdCB4PSIxOCIgeT0iMTAiIHdpZHRoPSIxIiBoZWlnaHQ9IjEiIGZpbGw9IiM0NDAzOGYiLz48cmVjdCB4PSIxMCIgeT0iMTIiIHdpZHRoPSIxMiIgaGVpZ2h0PSIxIiBmaWxsPSIjRkY2RDAwIi8+PHJlY3QgeD0iMTAiIHk9IjEzIiB3aWR0aD0iMTIiIGhlaWdodD0iMSIgZmlsbD0iIzAwOTVGRiIvPjxyZWN0IHg9IjEwIiB5PSIxNCIgd2lkdGg9IjEyIiBoZWlnaHQ9IjciIGZpbGw9IiMzMzMiLz48cmVjdCB4PSIxMCIgeT0iMjEiIHdpZHRoPSIxMiIgaGVpZ2h0PSI2IiBmaWxsPSIjN0M1QzRFIi8+PHJlY3QgeD0iMTAiIHk9IjI3IiB3aWR0aD0iNCIgaGVpZ2h0PSIyIiBmaWxsPSIjNDk0OTQ5Ii8+PHJlY3QgeD0iMTgiIHk9IjI3IiB3aWR0aD0iNCIgaGVpZ2h0PSIyIiBmaWxsPSIjNDk0OTQ5Ii8+PC9zdmc+',
NPC_OLD_MAN: 'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAzMiAzMiI+PHJlY3Qgd2lkdGg9IjMyIiBoZWlnaHQ9IjMyIiBmaWxsPSJ0cmFuc3BhcmVudCIvPjxyZWN0IHg9IjEwIiB5PSI3IiB3aWR0aD0iMTIiIGhlaWdodD0iNCIgZmlsbD0iI2VjZjBmMSIvPjxyZWN0IHg9IjEyIiB5PSIxMSIgd2lkdGg9IjgiIGhlaWdodD0iMSIgZmlsbD0iI2YxYzQwZiIvPjxyZWN0IHg9IjEwIiB5PSIxMyIgd2lkdGg9IjEyIiBoZWlnaHQ9IjE0IiBmaWxsPSIjMzQ5OGRiIi8+PHJlY3QgeD0iOSIgeT0iMTIiIHdpZHRoPSIxNCIgaGVpZ2h0PSIxIiBmaWxsPSIjYmQ4ZTM4Ii8+PHJlY3QgeD0iMTMiIHk9IjI3IiB3aWR0aD0iNiIgaGVpZ2h0PSIyIiBmaWxsPSIjMzMzIi8+PC9zdmc+',
// Items
AXE: 'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyNCAyNCI+PHBhdGggZmlsbD0iI2E1YjViNyIgZD0iTTQgMTggTDEwIDEyIEwxMiAxNCBMMTYgMTggWiIvPjxwYXRoIGZpbGw9IiM4NDU3MzMiIGQ9Ik0xMCAxMiBMMjAgMiBMMjIgNCBMMTIgMTQgWiIvPjwvc3ZnPg==',
HOE: 'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyNCAyNCI+PHBhdGggZmlsbD0iIzg0NTczMyIgZD0iTTUgMjIgTDE5IDggTDIxIDEwIEw3IDI0IFoiLz48cGF0aCBmaWxsPSIjYTViNWI3IiBkPSJNMTkgOCBMMTcgNiBMMjEgMiBMMjMgNCBaIi8+PC9zdmc+',
WOOD: 'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyNCAyNCI+PHJlY3QgeD0iNCIgeT0iOCIgd2lkdGg9IjE2IiBoZWlnaHQ9IjgiIGZpbGw9IiM4NDU3MzMiLz48cmVjdCB4PSI2IiB5PSI2IiB3aWR0aD0iMTIiIGhlaWdodD0iMTIiIGZpbGw9IiNhMDY4NDIiLz48L3N2Zz4=',
STRAWBERRY_SEEDS: 'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyNCAyNCI+PGNpcmNsZSBjeD0iMTIiIGN5PSIxMiIgcj0iMiIgZmlsbD0iI2RkYjU5MyIvPjxjaXJjbGUgY3g9IjgiIGN5PSIxNCIgcj0iMS41IiBmaWxsPSIjZGRiNTkzIi8+PGNpcmNsZSBjeD0iMTYiIGN5PSIxNCIgcj0iMS41IiBmaWxsPSIjZGRiNTkzIi8+PC9zdmc+',
STRAWBERRY: 'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyNCAyNCI+PHBhdGggZmlsbD0iIzI3YWU2MCIgZD0iTTEyIDIgTDE1IDUgTDEzIDUgTDEwIDIgWiIvPjxwYXRoIGZpbGw9IiNlNzRjM2MiIGQ9Ik02IDEwIEM2IDUgMTggNSAxOCAxMCBDMTggMTggMTIgMjIgNiAxOCBaIi8+PC9zdmc+',
FISH: 'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyNCAyNCI+PHBhdGggZmlsbD0iIzM0OThkYiIgZD0iTTIgMTIgQzIgNyAxMCA3IDE0IDEwIEwxOCAxMCBMMjIgOCBMMjIgMTYgTDE4IDE0IEwxNCAxNCBDMTAgMTcgMiAxNyAyIDEyIFoiLz48Y2lyY2xlIGN4PSI2IiBjeT0iMTEiIHI9IjEiIGZpbGw9IndoaXRlIi8+PC9zdmc+',
// Tiles
TREE: 'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCA0MCA0MCI+PHJlY3QgeD0iMTciIHk9IjMwIiB3aWR0aD0iNiIgaGVpZ2h0PSIxMCIgZmlsbD0iIzgzNTgyMyIvPjxwYXRoIGQ9Ik0yMCAwIEwzNSAxMCBMMzAgMjAgTDI1IDMwIEwxNSAzMCBMMTAgMjAgTDQgMTAgWiIgZmlsbD0iIzI3YWU2MCIvPjxwYXRoIGQ9Ik0yMCA1IEwzMCAxMiBMMjUgMjIgTDE1IDIyIEwxMCAxMiBaIiBmaWxsPSIjMmNjMzYwIi8+PC9zdmc+',
FLOWER: 'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxNiAxNiI+PHJlY3QgeD0iNyIgeT0iOCIgd2lkdGg9IjIiIGhlaWdodD0iOCIgZmlsbD0iIzI3YWU2MCIvPjxyZWN0IHg9IjYiIHk9IjMiIHdpZHRoPSI0IiBoZWlnaHQ9IjQiIGZpbGw9IiNlNzRjM2MiLz48cmVjdCB4PSI0IiB5PSI1IiB3aWR0aD0iMiIgaGVpZ2h0PSIyIiBmaWxsPSIjZTc0YzNjIi8+PHJlY3QgeD0iMTAiIHk9IjUiIHdpZHRoPSIyIiBoZWlnaHQ9IjIiIGZpbGw9IiNlNzRjM2MiLz48cmVjdCB4PSI3IiB5PSIyIiB3aWR0aD0iMiIgaGVpZ2h0PSIyIiBmaWxsPSIjZTc0YzNjIi8+PHJlY3QgeD0iNyIgeT0iOCIgd2lkdGg9IjIiIGhlaWdodD0iMiIgZmlsbD0iI2U3NGMzYyIvPjxyZWN0IHg9IjciIHk9IjUiIHdpZHRoPSIyIiBoZWlnaHQ9IjIiIGZpbGw9IiNmMWM0MGYiLz48L3N2Zz4=',
HOUSE: 'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxMjAgMTIwIj48cGF0aCBkPSJNNjAgNSBMMCA0NSBMMTAgNDUgTDEwIDExMCBMMTEwIDExMCBMMTEwIDQ1IEwxMjAgNDUgWiIgZmlsbD0iI2E1MjAyYSIvPjxyZWN0IHg9IjEwIiB5PSI0NSIgd2lkdGg9IjEwMCIgaGVpZ2h0PSI2NSIgZmlsbD0iI2RkYjU5MyIvPjxyZWN0IHg9IjQ1IiB5PSI3MCIgd2lkdGg9IjMwIiBoZWlnaHQ9IjQwIiBmaWxsPSIjODQ1NzMzIi8+PHJlY3QgeD0iNzIiIHk9IjUwIiB3aWR0aD0iMjUiIGhlaWdodD0iMjUiIGZpbGw9IiNhZGNmZmYiLz48L3N2Zz4=',
};
const ITEMS_DB = {
'axe': { name: '旧斧头', desc: '用来砍树,虽然旧但还很锋利。', img: ASSETS.AXE },
'hoe': { name: '旧锄头', desc: '用来开垦土地,开启田园生活的第一步。', img: ASSETS.HOE },
'wood': { name: '木头', desc: '从树上砍下来的木材,可以制作家具。', img: ASSETS.WOOD, price: 2 },
'strawberry_seeds': { name: '草莓种子', desc: '【春季】种下后会长出甜甜的草莓。', img: ASSETS.STRAWBERRY_SEEDS, price: 20 },
'strawberry': { name: '草莓', desc: '红彤彤的,是你最喜欢吃的水果之一。', img: ASSETS.STRAWBERRY, price: 50 },
'fish': { name: '小鱼', desc: '池塘里钓上来的,可以放进鱼缸。', img: ASSETS.FISH, price: 30 },
};
// --- 游戏状态 ---
let gameState = {
player: { x: 51, y: 52, el: null },
xia: { x: 52, y: 52, el: null },
inventory: [
{ id: 'axe', count: 1 }, { id: 'hoe', count: 1 },
{ id: 'strawberry_seeds', count: 10 },
null, null, null, null, null
],
gold: 9999999,
selectedSlot: 0,
map: [], // 2D array for the world grid
currentScene: 'world', // 'world' or 'house'
};
// --- 游戏逻辑 ---
// 初始化
function init() {
createMap();
renderWorld();
renderUI();
setupControls();
// 初始AI对话
setTimeout(() => updateDialogue("先熟悉一下四周吧,我就跟在你旁边。"), 3000);
setInterval(aiLoop, 2000); // AI逻辑循环
setInterval(gameTick, 1000); // 游戏时间流逝
}
// 创建地图数据
function createMap() {
gameState.map = Array(MAP_HEIGHT).fill(null).map(() => Array(MAP_WIDTH).fill({ type: 'grass' }));
// 房子
gameState.map[50][50] = { type: 'house', w: 3, h: 3 };
// 池塘
for(let y=60; y<65; y++) for(let x=70; x<80; x++) gameState.map[y][x] = { type: 'pond' };
// 树和花
for(let i=0; i<200; i++) {
const x = Math.floor(Math.random() * MAP_WIDTH);
const y = Math.floor(Math.random() * MAP_HEIGHT);
if (isAreaClear(x, y, 3, 3)) {
gameState.map[y][x] = { type: Math.random() > 0.3 ? 'tree' : 'flower' };
}
}
// NPC
gameState.map[48][60] = { type: 'npc', id: 'old_man' };
}
function isAreaClear(x, y, w, h) {
if (x+w > MAP_WIDTH || y+h > MAP_HEIGHT) return false;
for(let i=y; i<y+h; i++) {
for(let j=x; j<x+w; j++) {
if(gameState.map[i][j].type !== 'grass') return false;
}
}
return true;
}
// 渲染世界
function renderWorld() {
gameWorld.innerHTML = ''; // 清空
// 渲染地块
for (let y = 0; y < MAP_HEIGHT; y++) {
for (let x = 0; x < MAP_WIDTH; x++) {
const tileData = gameState.map[y][x];
if (tileData.type === 'grass') continue;
const tileEl = document.createElement('div');
tileEl.className = 'tile';
tileEl.style.left = `${x * TILE_SIZE}px`;
tileEl.style.top = `${y * TILE_SIZE}px`;
const img = document.createElement('img');
img.className = 'pixel-art';
switch(tileData.type) {
case 'house':
img.src = ASSETS.HOUSE;
tileEl.style.width = `${tileData.w * TILE_SIZE}px`;
tileEl.style.height = `${tileData.h * TILE_SIZE}px`;
tileEl.style.zIndex = 5;
break;
case 'tree':
img.src = ASSETS.TREE;
tileEl.style.zIndex = 5;
break;
case 'flower':
img.src = ASSETS.FLOWER;
img.style.width = '20px';
img.style.height = '20px';
break;
case 'pond':
tileEl.style.backgroundColor = '#3498db';
tileEl.style.borderRadius = '30%';
break;
case 'tilled':
tileEl.style.backgroundColor = '#8B4513';
tileEl.style.opacity = '0.7';
break;
case 'npc':
img.src = ASSETS.NPC_OLD_MAN;
tileEl.style.zIndex = 9;
break;
}
if(img.src) tileEl.appendChild(img);
gameWorld.appendChild(tileEl);
}
}
// 渲染角色
gameState.player.el = createCharacter('PLAYER', gameState.player.x, gameState.player.y);
gameState.xia.el = createCharacter('XIA_YIZHOU', gameState.xia.x, gameState.xia.y);
centerCameraOnPlayer();
}
function createCharacter(type, x, y) {
const charEl = document.createElement('img');
charEl.src = ASSETS[type];
charEl.className = 'character pixel-art';
charEl.style.left = `${x * TILE_SIZE}px`;
charEl.style.top = `${y * TILE_SIZE}px`;
gameWorld.appendChild(charEl);
return charEl;
}
// 渲染UI
function renderUI() {
// 金币
goldAmount.textContent = gameState.gold;
// 背包
inventoryBar.innerHTML = '';
gameState.inventory.forEach((item, index) => {
const slot = document.createElement('div');
slot.className = 'inventory-slot';
if (index === gameState.selectedSlot) slot.classList.add('selected');
if (item) {
const itemData = ITEMS_DB[item.id];
const img = document.createElement('img');
img.src = itemData.img;
img.className = 'w-8 h-8 pixel-art';
slot.appendChild(img);
if (item.count > 1) {
const count = document.createElement('span');
count.className = 'item-count';
count.textContent = item.count;
slot.appendChild(count);
}
slot.onmouseenter = (e) => showInfo(item.id, e);
slot.onmouseleave = hideInfo;
}
slot.onclick = () => { gameState.selectedSlot = index; renderUI(); };
inventoryBar.appendChild(slot);
});
}
// 移动与相机
function moveCharacter(char, dx, dy) {
const newX = char.x + dx;
const newY = char.y + dy;
if (newX < 0 || newX >= MAP_WIDTH || newY < 0 || newY >= MAP_HEIGHT) return;
if (!isPassable(newX, newY)) return;
char.x = newX;
char.y = newY;
char.el.style.left = `${char.x * TILE_SIZE}px`;
char.el.style.top = `${char.y * TILE_SIZE}px`;
if (char === gameState.player) {
centerCameraOnPlayer();
checkEnterHouse();
}
}
function centerCameraOnPlayer() {
const x = -gameState.player.x * TILE_SIZE + gameViewport.offsetWidth / 2;
const y = -gameState.player.y * TILE_SIZE + gameViewport.offsetHeight / 2;
gameWorld.style.transform = `translate(${x}px, ${y}px)`;
}
function isPassable(x, y) {
const tile = gameState.map[y][x];
return tile.type !== 'tree' && tile.type !== 'house' && tile.type !== 'pond';
}
// 交互逻辑
function playerAction() {
const px = gameState.player.x;
const py = gameState.player.y;
const facingCoords = [{x:px, y:py-1}, {x:px+1, y:py}, {x:px, y:py+1}, {x:px-1, y:py}];
for (const coord of facingCoords) {
if (coord.x < 0 || coord.y < 0 || coord.x >= MAP_WIDTH || coord.y >= MAP_HEIGHT) continue;
const targetTile = gameState.map[coord.y][coord.x];
const selectedItem = gameState.inventory[gameState.selectedSlot];
// NPC对话
if (targetTile.type === 'npc') {
updateDialogue("那个老爷爷看起来很和善,要去打个招呼吗?");
setTimeout(() => updateDialogue("老爷爷:天气真好啊,你们是新来的吗?我们小镇很久没来新人了。"), 2000);
return;
}
if (!selectedItem) { // 空手交互
if (targetTile.type === 'pond') {
updateDialogue("要钓鱼吗?我帮你准备鱼竿。");
if (Math.random() < 0.2) {
setTimeout(() => {
updateDialogue("钓到一条!真厉害,宝宝。");
addItemToInventory('fish', 1);
}, 1500);
} else {
setTimeout(() => updateDialogue("好像跑掉了...没事,下次肯定能钓到。"), 1500);
}
return;
}
return;
}
// 带工具交互
if (selectedItem.id === 'axe' && targetTile.type === 'tree') {
gameState.map[coord.y][coord.x] = { type: 'grass' };
addItemToInventory('wood', 5);
updateDialogue("砍树辛苦了,过来我这边休息一下。");
renderWorld(); // 重绘世界
return;
}
if (selectedItem.id === 'hoe' && targetTile.type === 'grass') {
gameState.map[coord.y][coord.x] = { type: 'tilled' };
updateDialogue("准备种点什么?种你喜欢吃的草莓好不好?");
renderWorld();
return;
}
if (selectedItem.id.includes('_seeds') && targetTile.type === 'tilled') {
gameState.map[coord.y][coord.x] = { type: 'seedling', seed: selectedItem.id, plantedTime: 0 };
removeItemFromInventory(selectedItem.id, 1);
updateDialogue("我记下了,等熟了第一个给你吃。");
renderWorld();
return;
}
}
}
function checkEnterHouse() {
const {x, y} = gameState.player;
if (x >= 50 && x < 53 && y >= 50 && y < 53) {
updateDialogue("到家了。进来看看我给你准备的惊喜。");
// 实际游戏中这里会切换场景
}
}
// AI 逻辑
function aiLoop() {
const dx = gameState.player.x - gameState.xia.x;
const dy = gameState.player.y - gameState.xia.y;
const distance = Math.sqrt(dx*dx + dy*dy);
if (distance > 2) {
moveCharacter(gameState.xia, Math.sign(dx), Math.sign(dy));
} else if (distance < 1.5 && Math.random() > 0.8) {
// 随机小动作
const randX = Math.floor(Math.random() * 3) - 1;
const randY = Math.floor(Math.random() * 3) - 1;
moveCharacter(gameState.xia, randX, randY);
}
}
// 游戏时间滴答
function gameTick() {
// 作物生长
}
// --- UI & 弹窗 ---
function setupControls() {
document.getElementById('btn-up').onclick = () => moveCharacter(gameState.player, 0, -1);
document.getElementById('btn-down').onclick = () => moveCharacter(gameState.player, 0, 1);
document.getElementById('btn-left').onclick = () => moveCharacter(gameState.player, -1, 0);
document.getElementById('btn-right').onclick = () => moveCharacter(gameState.player, 1, 0);
document.getElementById('btn-action').onclick = playerAction;
document.getElementById('shop-btn').onclick = openShop;
document.getElementById('map-btn').onclick = openMap;
document.onkeydown = (e) => {
switch(e.key) {
case 'w': case 'ArrowUp': moveCharacter(gameState.player, 0, -1); break;
case 's': case 'ArrowDown': moveCharacter(gameState.player, 0, 1); break;
case 'a': case 'ArrowLeft': moveCharacter(gameState.player, -1, 0); break;
case 'd': case 'ArrowRight': moveCharacter(gameState.player, 1, 0); break;
case 'e': case ' ': playerAction(); break;
}
};
}
function updateDialogue(text) { xiaDialogue.textContent = text; }
function showInfo(itemId, event) {
const itemData = ITEMS_DB[itemId];
infoPopup.innerHTML = `<h3 class="font-bold text-yellow-300">${itemData.name}</h3><p class="text-sm">${itemData.desc}</p>`;
infoPopup.classList.remove('hidden');
infoPopup.style.left = `${event.clientX + 15}px`;
infoPopup.style.top = `${event.clientY - infoPopup.offsetHeight - 10}px`;
}
function hideInfo() { infoPopup.classList.add('hidden'); }
function openShop() {
shopModal.classList.remove('hidden');
const shopItems = document.getElementById('shop-items');
shopItems.innerHTML = '';
Object.keys(ITEMS_DB).filter(id => id.includes('_seeds')).forEach(id => {
const item = ITEMS_DB[id];
const el = document.createElement('div');
el.className = 'p-2 border border-cyan-700 rounded text-center cursor-pointer hover:bg-cyan-900';
el.innerHTML = `<img src="${item.img}" class="w-12 h-12 mx-auto pixel-art"><p>${item.name}</p><p class="text-yellow-400">${item.price} G</p>`;
el.onclick = () => {
if (gameState.gold >= item.price) {
gameState.gold -= item.price;
addItemToInventory(id, 1);
updateDialogue(`买了${item.name}?好,我们一起种。`);
} else {
updateDialogue("钱不够了宝宝,不过没关系,我马上给你转。");
}
};
shopItems.appendChild(el);
});
}
function closeShop() { shopModal.classList.add('hidden'); }
function openMap() {
mapModal.classList.remove('hidden');
const mapContainer = document.getElementById('map-container');
mapContainer.innerHTML = '';
// 简化地图显示
const house = document.createElement('div');
house.className = 'absolute bg-red-500 p-1 rounded';
house.textContent = '家';
house.style.left = '50%'; house.style.top = '50%';
mapContainer.appendChild(house);
const pond = document.createElement('div');
pond.className = 'absolute bg-blue-500 p-1 rounded';
pond.textContent = '池塘';
pond.style.left = '70%'; pond.style.top = '60%';
mapContainer.appendChild(pond);
}
function closeMap() { mapModal.classList.add('hidden'); }
// 背包辅助函数
function addItemToInventory(itemId, count) {
let existingSlot = gameState.inventory.find(slot => slot && slot.id === itemId);
if (existingSlot) {
existingSlot.count += count;
} else {
let emptySlotIndex = gameState.inventory.findIndex(slot => slot === null);
if (emptySlotIndex !== -1) {
gameState.inventory[emptySlotIndex] = { id: itemId, count: count };
} else {
updateDialogue("背包满了,宝宝。得先整理一下。");
}
}
renderUI();
}
function removeItemFromInventory(itemId, count) {
let itemSlot = gameState.inventory.find(slot => slot && slot.id === itemId);
if (itemSlot) {
itemSlot.count -= count;
if (itemSlot.count <= 0) {
const index = gameState.inventory.indexOf(itemSlot);
gameState.inventory[index] = null;
}
}
renderUI();
}
// --- 启动游戏 ---
window.onload = init;
</script>
</body>
</html>