This commit is contained in:
2026-04-10 20:17:38 +08:00
parent 95d5fe6780
commit dc93ca2e8d
40 changed files with 681 additions and 27 deletions

593
sinner-gallery.html Normal file
View File

@@ -0,0 +1,593 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>罪人立绘排列</title>
<link href="https://fonts.googleapis.com/css2?family=Noto+Serif+SC:wght@400;700&display=swap" rel="stylesheet">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
<style>
/* 继承index.html的样式并添加展示页面特定样式 */
:root {
--primary-color: #ff4d4d;
--secondary-color: #ffd700;
--bg-color: #121212;
--text-color: #e0e0e0;
--panel-bg: #1e1e1e;
}
body {
font-family: 'Noto Serif SC', serif;
background-color: var(--bg-color);
color: var(--text-color);
margin: 0;
padding: 0;
min-height: 100vh;
display: flex;
flex-direction: column;
overflow-x: hidden;
user-select: none;
}
.page-header {
padding: 20px;
display: flex;
justify-content: space-between;
align-items: center;
background-color: rgba(30, 30, 30, 0.8);
border-bottom: 1px solid var(--secondary-color);
}
.page-title {
font-size: 1.8rem;
color: var(--secondary-color);
margin: 0;
}
.back-btn {
background: linear-gradient(135deg, #2a2a2a 0%, #1a1a1a 100%);
border: 2px solid var(--secondary-color);
color: var(--secondary-color);
padding: 0.5rem 1.5rem;
font-family: 'Noto Serif SC', serif;
font-weight: bold;
cursor: pointer;
transition: all 0.3s ease;
clip-path: polygon(10% 0, 100% 0, 100% 90%, 90% 100%, 0 100%, 0 10%);
}
.back-btn:hover {
background: var(--secondary-color);
color: #000;
}
.gallery-container {
flex: 1;
padding: 20px;
display: flex;
flex-direction: column;
align-items: center;
}
.sinner-cards {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));
gap: 20px;
width: 100%;
max-width: 1200px;
margin-top: 20px;
}
.sinner-card {
background-color: rgba(30, 30, 30, 0.8);
border: 2px solid rgba(255, 215, 0, 0.3);
border-radius: 10px;
overflow: hidden;
transition: all 0.3s ease;
cursor: pointer;
position: relative;
}
.sinner-card:hover {
transform: translateY(-5px);
border-color: var(--secondary-color);
box-shadow: 0 10px 20px rgba(0, 0, 0, 0.5);
}
.sinner-card-img {
width: 100%;
height: 300px;
object-fit: contain;
background-color: rgba(0, 0, 0, 0.3);
padding: 10px;
}
.sinner-card-info {
padding: 15px;
text-align: center;
}
.sinner-name {
font-size: 1.2rem;
color: var(--secondary-color);
margin: 0;
}
.sinner-source {
font-size: 0.9rem;
color: var(--text-color);
margin-top: 5px;
}
/* 罪人立绘排序界面 */
.sorting-container {
display: none;
flex-direction: column;
width: 100%;
height: 100%;
padding: 20px;
}
.sorting-container.active {
display: flex;
}
.sorting-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 20px;
}
.sorting-title {
font-size: 1.5rem;
color: var(--secondary-color);
}
.sorting-content {
display: flex;
flex: 1;
gap: 20px;
overflow: hidden;
}
.sorting-left {
flex: 2;
display: flex;
flex-direction: column;
gap: 20px;
overflow-y: auto;
}
.sorting-right {
flex: 1;
background-color: rgba(30, 30, 30, 0.8);
border: 2px solid rgba(255, 215, 0, 0.3);
border-radius: 10px;
display: flex;
flex-direction: column;
overflow: hidden;
}
.sorting-right-header {
padding: 15px;
border-bottom: 1px solid rgba(255, 215, 0, 0.3);
text-align: center;
color: var(--secondary-color);
font-size: 1.2rem;
}
.sorting-right-content {
flex: 1;
display: flex;
justify-content: center;
align-items: center;
padding: 20px;
overflow: auto;
}
.sorting-right-image {
max-width: 100%;
max-height: 100%;
object-fit: contain;
}
.sorting-categories {
display: flex;
flex-direction: column;
gap: 15px;
}
.sorting-category {
background-color: rgba(30, 30, 30, 0.8);
border: 2px solid rgba(255, 215, 0, 0.3);
border-radius: 10px;
padding: 15px;
min-height: 150px;
transition: all 0.3s ease;
}
.sorting-category.drag-over {
border-color: var(--secondary-color);
background-color: rgba(255, 215, 0, 0.1);
}
.sorting-category-title {
font-size: 1.2rem;
color: var(--secondary-color);
margin-bottom: 10px;
text-align: center;
}
.sorting-category-content {
display: flex;
flex-wrap: wrap;
gap: 10px;
}
.sorting-images {
display: flex;
flex-wrap: wrap;
gap: 10px;
padding: 15px;
background-color: rgba(30, 30, 30, 0.5);
border-radius: 10px;
}
.sorting-image {
width: 80px;
height: 80px;
object-fit: cover;
border: 2px solid rgba(255, 215, 0, 0.3);
border-radius: 5px;
cursor: grab;
transition: all 0.3s ease;
}
.sorting-image:hover {
border-color: var(--secondary-color);
transform: scale(1.05);
}
.sorting-image:active {
cursor: grabbing;
}
.sorting-image.dragging {
opacity: 0.5;
}
.sorting-image-small {
width: 80px;
height: 80px;
object-fit: cover;
border: 2px solid rgba(255, 215, 0, 0.3);
border-radius: 5px;
cursor: pointer;
transition: all 0.3s ease;
}
.sorting-image-small:hover {
border-color: var(--secondary-color);
transform: scale(1.05);
}
/* 响应式设计 */
@media (max-width: 768px) {
.sinner-cards {
grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
}
.sinner-card-img {
height: 200px;
}
.sorting-content {
flex-direction: column;
}
.sorting-left {
flex: 1;
}
.sorting-right {
height: 300px;
}
}
</style>
</head>
<body>
<div class="page-header">
<h1 class="page-title">罪人立绘排列</h1>
<button class="back-btn" onclick="window.location.href='index.html'">
<i class="fas fa-arrow-left"></i> 返回
</button>
</div>
<div class="gallery-container">
<div class="sinner-cards" id="sinner-cards">
<!-- 罪人卡片将通过JavaScript动态生成 -->
</div>
</div>
<!-- 罪人立绘排序界面 -->
<div class="sorting-container" id="sorting-container">
<div class="sorting-header">
<h2 class="sorting-title" id="sorting-title">罪人立绘排序</h2>
<button class="back-btn" onclick="closeSorting()">
<i class="fas fa-arrow-left"></i> 返回
</button>
</div>
<div class="sorting-content">
<div class="sorting-left">
<div class="sorting-categories">
<div class="sorting-category" data-category="夯">
<div class="sorting-category-title"></div>
<div class="sorting-category-content"></div>
</div>
<div class="sorting-category" data-category="顶级">
<div class="sorting-category-title">顶级</div>
<div class="sorting-category-content"></div>
</div>
<div class="sorting-category" data-category="人上人">
<div class="sorting-category-title">人上人</div>
<div class="sorting-category-content"></div>
</div>
<div class="sorting-category" data-category="npc">
<div class="sorting-category-title">NPC</div>
<div class="sorting-category-content"></div>
</div>
</div>
<div class="sorting-images" id="sorting-images">
<!-- 罪人立绘将通过JavaScript动态生成 -->
</div>
</div>
<div class="sorting-right">
<div class="sorting-right-header">立绘预览</div>
<div class="sorting-right-content">
<img src="" alt="" class="sorting-right-image" id="sorting-right-image">
</div>
</div>
</div>
</div>
<script>
// 罪人数据与matching-game.html保持一致
const gameData = [
{ id: 1, sinner: "李箱", source: "《李箱》", imgName: "yisang", egoImgName: "yi_sang_ego" },
{ id: 2, sinner: "浮士德", source: "《浮士德》", imgName: "faust", egoImgName: "faust_ego" },
{ id: 3, sinner: "堂吉诃德", source: "《堂吉诃德》", imgName: "don_quixote", egoImgName: "don_quixote_ego" },
{ id: 4, sinner: "良秀", source: "《地狱变》", imgName: "yoshihide", egoImgName: "yoshihide_ego" },
{ id: 5, sinner: "默尔索", source: "《局外人》", imgName: "meursault", egoImgName: "meursault_ego" },
{ id: 6, sinner: "鸿璐", source: "《红楼梦》", imgName: "honglu", egoImgName: "honglu_ego" },
{ id: 7, sinner: "希斯克利夫", source: "《呼啸山庄》", imgName: "heathcliff", egoImgName: "heathcliff_ego" },
{ id: 8, sinner: "以实玛利", source: "《白鲸》", imgName: "ishmael", egoImgName: "ishmael_ego" },
{ id: 9, sinner: "罗佳", source: "《罪与罚》", imgName: "rodya", egoImgName: "rodya_ego" },
{ id: 11, sinner: "辛克莱", source: "《德米安》", imgName: "sinclair", egoImgName: "sinclair_ego" },
{ id: 12, sinner: "奥提斯", source: "《奥德修斯》", imgName: "outis", egoImgName: "outis_ego" },
{ id: 13, sinner: "格里高尔", source: "《变形记》", imgName: "gregor", egoImgName: "gregor_ego" },
];
// 初始化页面
function initPage() {
// 生成罪人卡片
generateSinnerCards();
}
// 生成罪人卡片
function generateSinnerCards() {
const sinnerCards = document.getElementById('sinner-cards');
sinnerCards.innerHTML = '';
gameData.forEach(sinner => {
const card = document.createElement('div');
card.className = 'sinner-card';
card.dataset.id = sinner.id;
const img = document.createElement('img');
img.src = `images/sinners/${sinner.imgName}.png`;
img.alt = sinner.sinner;
img.className = 'sinner-card-img';
// 如果图片加载失败,显示默认图标
img.onerror = function() {
this.style.display = 'none';
const icon = document.createElement('i');
icon.className = 'fas fa-user';
icon.style.fontSize = '100px';
icon.style.color = 'var(--secondary-color)';
this.parentNode.insertBefore(icon, this);
};
const info = document.createElement('div');
info.className = 'sinner-card-info';
const name = document.createElement('h3');
name.className = 'sinner-name';
name.textContent = sinner.sinner;
const source = document.createElement('div');
source.className = 'sinner-source';
source.textContent = sinner.source;
info.appendChild(name);
info.appendChild(source);
card.appendChild(img);
card.appendChild(info);
// 添加点击事件,打开立绘排序界面
card.addEventListener('click', () => openSorting(sinner));
sinnerCards.appendChild(card);
});
}
// 打开立绘排序界面
function openSorting(sinner) {
const sortingContainer = document.getElementById('sorting-container');
const sortingTitle = document.getElementById('sorting-title');
const sortingImages = document.getElementById('sorting-images');
// 隐藏罪人卡片,显示排序界面
document.querySelector('.gallery-container').style.display = 'none';
sortingContainer.classList.add('active');
// 设置标题
sortingTitle.textContent = `${sinner.sinner} 立绘排序`;
// 清空之前的立绘
sortingImages.innerHTML = '';
// 清空分类中的立绘
document.querySelectorAll('.sorting-category-content').forEach(content => {
content.innerHTML = '';
});
// 加载罪人的所有人格立绘
loadSinnerPersonalities(sinner);
}
// 加载罪人的所有人格立绘
async function loadSinnerPersonalities(sinner) {
const sortingImages = document.getElementById('sorting-images');
try {
// 加载 JSON 索引文件
const response = await fetch('images/sinner_images.json');
const sinnerData = await response.json();
// 查找当前罪人的图片数据
const currentSinner = sinnerData.find(item => item.name === sinner.imgName);
if (currentSinner && currentSinner.images && currentSinner.images.length > 0) {
// 为每个人格立绘创建可拖动的图片元素
currentSinner.images.forEach((personality, index) => {
const img = document.createElement('img');
img.src = personality.path;
img.alt = personality.name;
img.className = 'sorting-image';
img.dataset.id = index + 1;
img.dataset.name = personality.name;
img.draggable = true;
// 如果图片加载失败,显示默认图标
img.onerror = function() {
this.style.display = 'none';
const icon = document.createElement('i');
icon.className = 'fas fa-user';
icon.style.fontSize = '80px';
icon.style.color = 'var(--secondary-color)';
this.parentNode.insertBefore(icon, this);
};
// 添加拖动事件
img.addEventListener('dragstart', handleDragStart);
img.addEventListener('dragend', handleDragEnd);
// 添加点击事件,在右侧显示完整图片
img.addEventListener('click', () => showFullImage(personality.path));
sortingImages.appendChild(img);
});
} else {
// 如果没有找到图片,显示提示信息
const errorMsg = document.createElement('div');
errorMsg.className = 'error-message';
errorMsg.textContent = `未找到 ${sinner.sinner} 的立绘图片`;
sortingImages.appendChild(errorMsg);
}
} catch (error) {
console.error('加载立绘失败:', error);
// 显示错误提示
const errorMsg = document.createElement('div');
errorMsg.className = 'error-message';
errorMsg.textContent = '无法加载立绘,请检查图片路径';
sortingImages.appendChild(errorMsg);
}
}
// 显示完整图片
function showFullImage(imgSrc) {
const fullImage = document.getElementById('sorting-right-image');
fullImage.src = imgSrc;
}
// 处理拖动开始
function handleDragStart(e) {
this.classList.add('dragging');
e.dataTransfer.setData('text/plain', this.dataset.id);
e.dataTransfer.effectAllowed = 'move';
}
// 处理拖动结束
function handleDragEnd(e) {
this.classList.remove('dragging');
}
// 为分类区域添加拖放事件
document.querySelectorAll('.sorting-category').forEach(category => {
category.addEventListener('dragover', handleDragOver);
category.addEventListener('dragleave', handleDragLeave);
category.addEventListener('drop', handleDrop);
});
// 处理拖动悬停
function handleDragOver(e) {
e.preventDefault();
e.dataTransfer.dropEffect = 'move';
this.classList.add('drag-over');
}
// 处理拖动离开
function handleDragLeave(e) {
this.classList.remove('drag-over');
}
// 处理放置
function handleDrop(e) {
e.preventDefault();
this.classList.remove('drag-over');
const id = e.dataTransfer.getData('text/plain');
const draggedElement = document.querySelector(`.sorting-image[data-id="${id}"]`);
if (draggedElement) {
// 将图片从原位置移动到新位置
const categoryContent = this.querySelector('.sorting-category-content');
// 创建一个新图片元素
const newImg = document.createElement('img');
newImg.src = draggedElement.src;
newImg.alt = draggedElement.alt;
newImg.className = 'sorting-image-small';
newImg.dataset.id = draggedElement.dataset.id;
newImg.dataset.name = draggedElement.dataset.name;
// 添加点击事件,在右侧显示完整图片
newImg.addEventListener('click', () => showFullImage(draggedElement.src));
// 将新图片添加到分类中
categoryContent.appendChild(newImg);
// 从原位置移除图片
draggedElement.remove();
}
}
// 关闭排序界面
function closeSorting() {
const sortingContainer = document.getElementById('sorting-container');
// 显示罪人卡片,隐藏排序界面
document.querySelector('.gallery-container').style.display = 'flex';
sortingContainer.classList.remove('active');
}
// 初始化页面
initPage();
</script>
</body>
</html>