first commit

This commit is contained in:
2026-04-10 16:37:45 +08:00
commit 95d5fe6780
22 changed files with 1058 additions and 0 deletions

5
.idea/.gitignore generated vendored Normal file
View File

@@ -0,0 +1,5 @@
# 默认忽略的文件
/shelf/
/workspace.xml
# 基于编辑器的 HTTP 客户端请求
/httpRequests/

10
.idea/084PlayHtml.iml generated Normal file
View File

@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="PYTHON_MODULE" version="4">
<component name="NewModuleRootManager">
<content url="file://$MODULE_DIR$">
<excludeFolder url="file://$MODULE_DIR$/.venv" />
</content>
<orderEntry type="jdk" jdkName="uv (084PlayHtml)" jdkType="Python SDK" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>

View File

@@ -0,0 +1,12 @@
<component name="InspectionProjectProfileManager">
<profile version="1.0">
<option name="myName" value="Project Default" />
<inspection_tool class="PyUnresolvedReferencesInspection" enabled="true" level="WARNING" enabled_by_default="true">
<option name="ignoredIdentifiers">
<list>
<option value="requests.models.Response.__getitem__" />
</list>
</option>
</inspection_tool>
</profile>
</component>

View File

@@ -0,0 +1,6 @@
<component name="InspectionProjectProfileManager">
<settings>
<option name="USE_PROJECT_PROFILE" value="false" />
<version value="1.0" />
</settings>
</component>

7
.idea/misc.xml generated Normal file
View File

@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="Black">
<option name="sdkName" value="uv (084PlayHtml)" />
</component>
<component name="ProjectRootManager" version="2" project-jdk-name="uv (084PlayHtml)" project-jdk-type="Python SDK" />
</project>

8
.idea/modules.xml generated Normal file
View File

@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/.idea/084PlayHtml.iml" filepath="$PROJECT_DIR$/.idea/084PlayHtml.iml" />
</modules>
</component>
</project>

6
.idea/vcs.xml generated Normal file
View File

@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="$PROJECT_DIR$" vcs="Git" />
</component>
</project>

Binary file not shown.

After

Width:  |  Height:  |  Size: 157 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 59 KiB

BIN
image/sinners/奥提斯.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 67 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 72 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 89 KiB

BIN
image/sinners/浮士德.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 78 KiB

BIN
image/sinners/罗佳.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 97 KiB

BIN
image/sinners/良秀.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 74 KiB

BIN
image/sinners/辛克莱.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 84 KiB

BIN
image/sinners/鸿璐.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 88 KiB

BIN
image/sinners/默尔索.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 55 KiB

0
index.css Normal file
View File

200
index.html Normal file
View File

@@ -0,0 +1,200 @@
<!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>
/* --- 全局变量与基础样式 --- */
: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;
height: 100vh;
display: flex;
justify-content: center;
align-items: center;
overflow: hidden;
user-select: none;
}
/* --- 主菜单容器 --- */
.menu-container {
text-align: center;
z-index: 10;
width: 100%;
max-width: 800px;
padding: 20px;
box-sizing: border-box;
}
/* --- 标题样式 --- */
.menu-title {
font-size: 3.5rem;
margin-bottom: 3rem;
color: var(--secondary-color);
text-shadow: 0 0 10px rgba(255, 215, 0, 0.3), 2px 2px 4px rgba(0, 0, 0, 0.8);
font-weight: 700;
letter-spacing: 2px;
position: relative;
display: inline-block;
}
/* 标题下方的装饰线 */
.menu-title::after {
content: '';
position: absolute;
bottom: -10px;
left: 50%;
transform: translateX(-50%);
width: 60%;
height: 2px;
background: linear-gradient(90deg, transparent, var(--primary-color), transparent);
}
/* --- 按钮组样式 --- */
.menu-buttons {
display: flex;
gap: 3rem;
justify-content: center;
flex-wrap: wrap;
}
/* --- 按钮样式 --- */
.menu-btn {
background: linear-gradient(135deg, #2a2a2a 0%, #1a1a1a 100%);
border: 2px solid var(--secondary-color);
color: var(--secondary-color);
padding: 1.2rem 3rem;
font-size: 1.3rem;
font-family: 'Noto Serif SC', serif;
font-weight: bold;
cursor: pointer;
transition: all 0.3s ease;
position: relative;
overflow: hidden;
min-width: 250px;
/* 边狱公司风格的切角 */
clip-path: polygon(10% 0, 100% 0, 100% 90%, 90% 100%, 0 100%, 0 10%);
text-transform: uppercase;
}
/* 按钮悬停效果 */
.menu-btn:hover {
background: var(--secondary-color);
color: #000;
box-shadow: 0 0 20px rgba(255, 215, 0, 0.4);
transform: translateY(-2px);
}
/* 按钮点击效果 */
.menu-btn:active {
transform: translateY(1px);
}
/* 按钮内的图标 */
.menu-btn i {
margin-right: 10px;
}
/* 按钮光效动画 */
.menu-btn::before {
content: '';
position: absolute;
top: 0;
left: -100%;
width: 100%;
height: 100%;
background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.2), transparent);
transition: left 0.5s;
}
.menu-btn:hover::before {
left: 100%;
}
/* --- 背景装饰 --- */
.bg-decoration {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
z-index: 1;
overflow: hidden;
pointer-events: none;
}
/* 模拟背景中的光效 */
.bg-light {
position: absolute;
width: 300px;
height: 300px;
background: radial-gradient(circle, rgba(255, 77, 77, 0.1) 0%, transparent 70%);
border-radius: 50%;
animation: float 10s infinite ease-in-out;
}
.bg-light:nth-child(1) { top: 10%; left: 10%; animation-delay: 0s; }
.bg-light:nth-child(2) { bottom: 20%; right: 10%; animation-delay: 2s; background: radial-gradient(circle, rgba(255, 215, 0, 0.05) 0%, transparent 70%); }
.bg-light:nth-child(3) { top: 40%; left: 40%; animation-delay: 4s; width: 500px; height: 500px; opacity: 0.3; }
@keyframes float {
0%, 100% { transform: translate(0, 0); }
50% { transform: translate(20px, -20px); }
}
/* 响应式调整 */
@media (max-width: 768px) {
.menu-title {
font-size: 2.5rem;
}
.menu-buttons {
flex-direction: column;
align-items: center;
gap: 1.5rem;
}
.menu-btn {
width: 80%;
}
}
</style>
</head>
<body>
<!-- 背景装饰 -->
<div class="bg-decoration">
<div class="bg-light"></div>
<div class="bg-light"></div>
<div class="bg-light"></div>
</div>
<!-- 主菜单内容 -->
<div class="menu-container">
<h1 class="menu-title">边狱公司</h1>
<div class="menu-buttons">
<button class="menu-btn" onclick="window.location.href='matching-game.html'">
<i class="fas fa-link"></i> 罪人与原著
</button>
<button class="menu-btn" onclick="alert('即将进入:罪人立绘排列 (排序)')">
<i class="fas fa-sort-numeric-down"></i> 罪人立绘排列
</button>
</div>
</div>
</body>
</html>

798
matching-game.html Normal file
View File

@@ -0,0 +1,798 @@
<!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;
height: 100vh;
display: flex;
flex-direction: column;
overflow: hidden;
user-select: none;
}
.game-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);
}
.game-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;
}
.game-container {
flex: 1;
display: flex;
padding: 20px;
gap: 20px;
position: relative;
}
.sinner-column {
flex: 1;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
padding: 20px;
background-color: rgba(30, 30, 30, 0.5);
border-radius: 10px;
}
.column-title {
text-align: center;
font-size: 1.5rem;
color: var(--secondary-color);
margin-bottom: 20px;
text-shadow: 0 0 5px rgba(255, 215, 0, 0.3);
}
.sinner-card {
display: flex;
flex-direction: column;
align-items: center;
padding: 20px;
background-color: rgba(42, 42, 42, 0.8);
border: 2px solid var(--secondary-color);
border-radius: 10px;
max-width: 500px;
transition: all 0.3s ease;
}
.sinner-images-container {
display: flex;
justify-content: center;
gap: 20px;
margin-bottom: 20px;
}
.sinner-image-wrapper {
position: relative;
width: 200px;
height: 200px;
border-radius: 10px;
overflow: hidden;
border: 1px solid rgba(255, 215, 0, 0.3);
transition: all 0.3s ease;
cursor: pointer;
}
.sinner-image-wrapper:hover {
transform: scale(1.05);
border-color: var(--secondary-color);
}
.sinner-image {
width: 100%;
height: 100%;
object-fit: cover;
}
.ego-image-wrapper {
position: relative;
width: 200px;
height: 200px;
border-radius: 10px;
overflow: hidden;
border: 1px solid rgba(255, 215, 0, 0.3);
transition: all 0.3s ease;
cursor: pointer;
opacity: 0.5;
}
.ego-image-wrapper:hover {
opacity: 1;
transform: scale(1.05);
border-color: var(--secondary-color);
}
.ego-image {
width: 100%;
height: 100%;
object-fit: cover;
}
.image-label {
position: absolute;
bottom: 0;
left: 0;
right: 0;
background-color: rgba(0, 0, 0, 0.7);
color: var(--secondary-color);
text-align: center;
padding: 5px;
font-size: 0.9rem;
}
.hint-text {
font-size: 0.9rem;
color: var(--secondary-color);
margin-top: 10px;
opacity: 0.7;
}
.sources-column {
flex: 1;
display: flex;
flex-direction: column;
padding: 20px;
background-color: rgba(30, 30, 30, 0.5);
border-radius: 10px;
}
.source-item {
display: flex;
align-items: center;
padding: 15px;
margin-bottom: 10px;
background-color: rgba(42, 42, 42, 0.8);
border: 1px solid rgba(255, 215, 0, 0.3);
border-radius: 5px;
cursor: pointer;
transition: all 0.3s ease;
}
.source-item:hover {
background-color: rgba(255, 215, 0, 0.1);
border-color: var(--secondary-color);
}
.source-item.selected {
background-color: rgba(255, 77, 77, 0.2);
border-color: var(--primary-color);
box-shadow: 0 0 10px rgba(255, 77, 77, 0.3);
}
.source-item.matched {
background-color: rgba(255, 215, 0, 0.1);
border-color: var(--secondary-color);
opacity: 0.5;
pointer-events: none;
}
.source-text {
flex: 1;
font-size: 1.1rem;
}
.next-btn {
background: linear-gradient(135deg, #2a2a2a 0%, #1a1a1a 100%);
border: 2px solid var(--secondary-color);
color: var(--secondary-color);
padding: 0.8rem 2rem;
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%);
margin-top: 20px;
font-size: 1.1rem;
}
.next-btn:hover {
background: var(--secondary-color);
color: #000;
}
.next-btn:disabled {
opacity: 0.5;
cursor: not-allowed;
}
.message-display {
position: absolute;
bottom: 30px;
left: 50%;
transform: translateX(-50%);
background-color: rgba(30, 30, 30, 0.9);
padding: 10px 30px;
border-radius: 5px;
border: 1px solid var(--primary-color);
color: var(--text-color);
font-size: 1.2rem;
opacity: 0;
transition: opacity 0.5s ease;
z-index: 100;
}
.message-display.show {
opacity: 1;
}
.results-container {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: rgba(0, 0, 0, 0.9);
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
z-index: 1000;
opacity: 0;
visibility: hidden;
transition: all 0.5s ease;
overflow-y: auto;
}
.results-container.show {
opacity: 1;
visibility: visible;
}
.results-title {
font-size: 2.5rem;
color: var(--secondary-color);
margin-bottom: 30px;
text-shadow: 0 0 10px rgba(255, 215, 0, 0.3);
}
.results-list {
width: 80%;
max-width: 800px;
display: grid;
grid-template-columns: repeat(auto-fill, minmax(350px, 1fr));
gap: 20px;
margin-bottom: 30px;
}
.result-item {
display: flex;
align-items: center;
padding: 15px;
background-color: rgba(30, 30, 30, 0.8);
border: 1px solid rgba(255, 215, 0, 0.3);
border-radius: 10px;
transition: all 0.3s ease;
}
.result-item.correct {
border-color: var(--secondary-color);
box-shadow: 0 0 10px rgba(255, 215, 0, 0.2);
}
.result-item.incorrect {
border-color: var(--primary-color);
box-shadow: 0 0 10px rgba(255, 77, 77, 0.2);
}
.result-images {
display: flex;
flex-direction: column;
margin-right: 15px;
gap: 5px;
}
.result-image {
width: 60px;
height: 60px;
border-radius: 5px;
object-fit: cover;
}
.result-info {
flex: 1;
}
.result-sinner {
font-size: 1.1rem;
color: var(--text-color);
margin-bottom: 5px;
}
.result-source {
font-size: 0.9rem;
color: var(--secondary-color);
}
.result-status {
font-size: 1.2rem;
margin-left: 10px;
}
.correct-icon {
color: var(--secondary-color);
}
.incorrect-icon {
color: var(--primary-color);
}
.restart-btn {
background: linear-gradient(135deg, #2a2a2a 0%, #1a1a1a 100%);
border: 2px solid var(--secondary-color);
color: var(--secondary-color);
padding: 1rem 2rem;
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%);
font-size: 1.2rem;
margin-bottom: 30px;
}
.restart-btn:hover {
background: var(--secondary-color);
color: #000;
}
/* 响应式设计 */
@media (max-width: 768px) {
.game-container {
flex-direction: column;
overflow-y: auto;
}
.sinner-images-container {
flex-direction: column;
}
.sinner-image-wrapper, .ego-image-wrapper {
width: 150px;
height: 150px;
}
.results-list {
grid-template-columns: 1fr;
}
}
</style>
</head>
<body>
<div class="game-header">
<h1 class="game-title">罪人与原著</h1>
<button class="back-btn" onclick="window.location.href='index.html'">
<i class="fas fa-arrow-left"></i> 返回
</button>
</div>
<div class="game-container">
<div class="sinner-column">
<div class="column-title">罪人</div>
<div class="sinner-card" id="sinner-card">
<div class="sinner-images-container">
<div class="sinner-image-wrapper">
<img src="" alt="" class="sinner-image" id="sinner-image">
<div class="image-label">罪人立绘</div>
</div>
<div class="ego-image-wrapper">
<img src="" alt="" class="ego-image" id="ego-image">
<div class="image-label">初始Ego</div>
</div>
</div>
<div class="hint-text">点击图片查看提示</div>
</div>
<button class="next-btn" id="next-btn" disabled>下一个</button>
</div>
<div class="sources-column">
<div class="column-title">原著</div>
<div id="sources-list">
<!-- 原著列表将通过JavaScript动态生成 -->
</div>
</div>
<div class="message-display" id="message"></div>
</div>
<div class="results-container" id="results-container">
<div class="results-title">匹配结果</div>
<div class="results-list" id="results-list">
<!-- 结果列表将通过JavaScript动态生成 -->
</div>
<button class="restart-btn" onclick="restartGame()">重新开始</button>
</div>
<script>
// 游戏数据
const gameData = [
{ id: 1, sinner: "浮士德", source: "《浮士德》" },
{ id: 2, sinner: "但丁", source: "《神曲》" },
{ id: 3, sinner: "良秀", source: "《地狱变》" },
{ id: 4, sinner: "默尔索", source: "《局外人》" },
{ id: 5, sinner: "鸿璐", source: "《红楼梦》" },
{ id: 6, sinner: "希斯克利夫", source: "《呼啸山庄》" },
{ id: 7, sinner: "以实玛利", source: "《白鲸》" },
{ id: 8, sinner: "罗佳", source: "《罪与罚》" },
{ id: 9, sinner: "辛克莱", source: "《德米安》" },
{ id: 10, sinner: "奥提斯", source: "《奥提斯》" },
{ id: 11, sinner: "格里高尔", source: "《变形记》" },
{ id: 12, sinner: "堂吉诃德", source: "《堂吉诃德》" }
];
// 游戏状态
let currentSinnerIndex = 0;
let selectedSourceId = null;
let userAnswers = [];
let shuffledSinners = [];
let shuffledSources = [];
// 初始化游戏
function initGame() {
// 随机打乱罪人和原著顺序
shuffledSinners = shuffleArray([...gameData]);
shuffledSources = shuffleArray([...gameData]);
// 重置游戏状态
currentSinnerIndex = 0;
selectedSourceId = null;
userAnswers = [];
// 显示第一个罪人
displaySinner();
// 生成原著列表
generateSourcesList();
// 禁用"下一个"按钮
document.getElementById('next-btn').disabled = true;
}
// 显示当前罪人
function displaySinner() {
const sinner = shuffledSinners[currentSinnerIndex];
const sinnerImage = document.getElementById('sinner-image');
const egoImage = document.getElementById('ego-image');
const egoImageWrapper = document.querySelector('.ego-image-wrapper');
// 根据罪人名字构建图片路径假设图片在images目录下
// 使用罪人名字作为文件名,支持常见图片格式
const imageExtensions = ['.jpg', '.jpeg', '.png', '.gif', '.webp'];
let sinnerImageLoaded = false;
let egoImageLoaded = false;
// 尝试加载罪人立绘
for (const ext of imageExtensions) {
const imagePath = `images/sinners/${sinner.sinner}${ext}`;
sinnerImage.src = imagePath;
// 检查图片是否可以加载
sinnerImage.onload = function() {
if (!sinnerImageLoaded) {
sinnerImageLoaded = true;
sinnerImage.style.display = 'block';
}
};
sinnerImage.onerror = function() {
// 如果所有格式都尝试过且都失败,显示默认图标
if (!sinnerImageLoaded && ext === imageExtensions[imageExtensions.length - 1]) {
this.style.display = 'none';
const icon = document.createElement('i');
icon.className = 'fas fa-user';
icon.style.fontSize = '100px';
document.querySelector('.sinner-image-wrapper').appendChild(icon);
}
};
}
// 尝试加载Ego立绘
for (const ext of imageExtensions) {
const egoPath = `images/egos/${sinner.sinner}${ext}`;
egoImage.src = egoPath;
// 检查图片是否可以加载
egoImage.onload = function() {
if (!egoImageLoaded) {
egoImageLoaded = true;
egoImage.style.display = 'block';
}
};
egoImage.onerror = function() {
// 如果所有格式都尝试过且都失败,显示默认图标
if (!egoImageLoaded && ext === imageExtensions[imageExtensions.length - 1]) {
this.style.display = 'none';
const icon = document.createElement('i');
icon.className = 'fas fa-ghost';
icon.style.fontSize = '100px';
document.querySelector('.ego-image-wrapper').appendChild(icon);
}
};
}
// 重置Ego图片的透明度
egoImageWrapper.style.opacity = '0.5';
// 添加点击事件显示Ego立绘
egoImageWrapper.onclick = function() {
egoImageWrapper.style.opacity = egoImageWrapper.style.opacity === '0.5' ? '1' : '0.5';
};
}
// 生成原著列表
function generateSourcesList() {
const sourcesList = document.getElementById('sources-list');
sourcesList.innerHTML = '';
shuffledSources.forEach(source => {
const div = document.createElement('div');
div.className = 'source-item';
div.dataset.id = source.id;
const text = document.createElement('div');
text.className = 'source-text';
text.textContent = source.source;
div.appendChild(text);
div.addEventListener('click', handleSourceClick);
sourcesList.appendChild(div);
});
}
// 处理原著点击事件
function handleSourceClick(e) {
const sourceItem = e.currentTarget;
const sourceId = parseInt(sourceItem.dataset.id);
// 如果已经匹配过,不允许再次选择
if (sourceItem.classList.contains('matched')) {
return;
}
// 取消之前的选择
if (selectedSourceId !== null) {
document.querySelector(`.source-item[data-id="${selectedSourceId}"]`).classList.remove('selected');
}
// 标记当前选择
selectedSourceId = sourceId;
sourceItem.classList.add('selected');
// 启用"下一个"按钮
document.getElementById('next-btn').disabled = false;
}
// 下一个罪人
function nextSinner() {
// 记录用户答案
const currentSinner = shuffledSinners[currentSinnerIndex];
userAnswers.push({
sinnerId: currentSinner.id,
sinnerName: currentSinner.sinner,
selectedSourceId: selectedSourceId
});
// 标记已选择的原著为已匹配
document.querySelector(`.source-item[data-id="${selectedSourceId}"]`).classList.add('matched');
// 重置选择
selectedSourceId = null;
// 移动到下一个罪人
currentSinnerIndex++;
// 检查是否还有罪人需要匹配
if (currentSinnerIndex < shuffledSinners.length) {
displaySinner();
document.getElementById('next-btn').disabled = true;
} else {
// 所有罪人已匹配完成,显示结果
showResults();
}
}
// 显示结果
function showResults() {
const resultsContainer = document.getElementById('results-container');
const resultsList = document.getElementById('results-list');
// 清空结果列表
resultsList.innerHTML = '';
// 计算得分
let correctCount = 0;
// 显示每个罪人的匹配结果
userAnswers.forEach(answer => {
const sinner = gameData.find(s => s.id === answer.sinnerId);
const selectedSource = gameData.find(s => s.id === answer.selectedSourceId);
const isCorrect = answer.sinnerId === answer.selectedSourceId;
if (isCorrect) {
correctCount++;
}
const resultItem = document.createElement('div');
resultItem.className = `result-item ${isCorrect ? 'correct' : 'incorrect'}`;
// 添加罪人立绘和Ego立绘
const resultImages = document.createElement('div');
resultImages.className = 'result-images';
// 尝试加载罪人立绘
const imageExtensions = ['.jpg', '.jpeg', '.png', '.gif', '.webp'];
let sinnerImageFound = false;
for (const ext of imageExtensions) {
const testImage = new Image();
testImage.src = `images/sinners/${answer.sinnerName}${ext}`;
testImage.onload = function() {
if (!sinnerImageFound) {
sinnerImageFound = true;
const resultImage = document.createElement('img');
resultImage.src = `images/sinners/${answer.sinnerName}${ext}`;
resultImage.alt = answer.sinnerName;
resultImage.className = 'result-image';
resultImages.appendChild(resultImage);
}
};
if (sinnerImageFound) break;
}
// 尝试加载Ego立绘
let egoImageFound = false;
for (const ext of imageExtensions) {
const testImage = new Image();
testImage.src = `images/egos/${answer.sinnerName}${ext}`;
testImage.onload = function() {
if (!egoImageFound) {
egoImageFound = true;
const resultImage = document.createElement('img');
resultImage.src = `images/egos/${answer.sinnerName}${ext}`;
resultImage.alt = answer.sinnerName + ' Ego';
resultImage.className = 'result-image';
resultImages.appendChild(resultImage);
}
};
if (egoImageFound) break;
}
// 如果没有找到图片,显示默认图标
if (!sinnerImageFound) {
const icon = document.createElement('i');
icon.className = 'fas fa-user';
icon.style.fontSize = '30px';
resultImages.appendChild(icon);
}
if (!egoImageFound) {
const icon = document.createElement('i');
icon.className = 'fas fa-ghost';
icon.style.fontSize = '30px';
resultImages.appendChild(icon);
}
const resultInfo = document.createElement('div');
resultInfo.className = 'result-info';
const resultSinner = document.createElement('div');
resultSinner.className = 'result-sinner';
resultSinner.textContent = answer.sinnerName;
const resultSource = document.createElement('div');
resultSource.className = 'result-source';
resultSource.textContent = `匹配: ${selectedSource.source}`;
resultInfo.appendChild(resultSinner);
resultInfo.appendChild(resultSource);
const resultStatus = document.createElement('div');
resultStatus.className = 'result-status';
if (isCorrect) {
resultStatus.innerHTML = '<i class="fas fa-check correct-icon"></i>';
} else {
resultStatus.innerHTML = '<i class="fas fa-times incorrect-icon"></i>';
}
resultItem.appendChild(resultImages);
resultItem.appendChild(resultInfo);
resultItem.appendChild(resultStatus);
resultsList.appendChild(resultItem);
});
// 显示结果容器
resultsContainer.classList.add('show');
// 显示得分消息
showMessage(`匹配完成!正确率: ${Math.round((correctCount / userAnswers.length) * 100)}%`);
}
// 重新开始游戏
function restartGame() {
// 隐藏结果容器
document.getElementById('results-container').classList.remove('show');
// 重新初始化游戏
initGame();
}
// 显示消息
function showMessage(msg) {
const messageEl = document.getElementById('message');
messageEl.textContent = msg;
messageEl.classList.add('show');
setTimeout(() => {
messageEl.classList.remove('show');
}, 3000);
}
// 数组洗牌函数
function shuffleArray(array) {
for (let i = array.length - 1; i > 0; i--) {
const j = Math.floor(Math.random() * (i + 1));
[array[i], array[j]] = [array[j], array[i]];
}
return array;
}
// 绑定"下一个"按钮点击事件
document.getElementById('next-btn').addEventListener('click', nextSinner);
// 初始化游戏
initGame();
</script>
</body>
</html>

6
pyproject.toml Normal file
View File

@@ -0,0 +1,6 @@
[project]
name = "084playhtml"
version = "0.1.0"
description = "Add your description here"
requires-python = ">=3.12"
dependencies = []