three实仙三维有声仙侠国风网页游戏代码
代码语言:html
所属分类:其他
代码由glm-5.3-flash ai生成,可能有错误,仅供参考:点击查看提示词
代码描述:仙侠3d国风网游
代码标签: three 三维 有声 仙侠 国风 网页 游戏 代码
下面为部分代码预览,完整代码请点击下载或在bfwstudio webide中打开
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no, viewport-fit=cover">
<meta name="theme-color" content="#0c1310">
<title>斩魔行 · 水墨仙侠</title>
<style>
/* ============ 全局:水墨宣纸色系 ============ */
:root{
--ink:#232b25; --ink2:#46524a; --paper:#ece4d0; --paper2:#d9cdaf;
--verm:#c0362c; --verm2:#8c1f16; --gold:#d9b45c; --jade:#7fc7ae; --skyc:#0c1310;
}
*{margin:0;padding:0;box-sizing:border-box;-webkit-tap-highlight-color:transparent}
html,body{width:100%;height:100%;overflow:hidden;background:var(--skyc);
touch-action:none;user-select:none;-webkit-user-select:none;overscroll-behavior:none}
body{font-family:"Kaiti SC","STKaiti","KaiTi","BiauKai","Noto Serif SC","Songti SC","SimSun",serif;color:var(--ink)}
#app{position:fixed;inset:0;background:radial-gradient(ellipse at 50% 32%,#17251f 0%,#0b1210 72%)}
canvas{position:absolute;inset:0;width:100%;height:100%;display:block}
.hide{display:none!important}
.hide0{opacity:0!important}
/* ============ 后期叠加层(暗角 / 色差 / 红屏 / 白闪) ============ */
#fxV{position:absolute;inset:0;pointer-events:none;z-index:5;
background:radial-gradient(ellipse at 50% 46%,transparent 50%,rgba(8,12,10,.46) 100%)}
#fxCA{position:absolute;inset:0;pointer-events:none;z-index:5;
box-shadow:inset 3px 0 8px rgba(255,40,60,.07),inset -3px 0 8px rgba(40,180,255,.07)}
#fxR{position:absolute;inset:0;pointer-events:none;z-index:6;opacity:0;transition:opacity .4s;
background:radial-gradient(ellipse at center,transparent 34%,rgba(158,22,10,.55) 100%)}
#fxR.on{opacity:.55;animation:redPulse 1.1s ease-in-out infinite}
@keyframes redPulse{0%,100%{opacity:.35}50%{opacity:.72}}
#fxF{position:absolute;inset:0;pointer-events:none;z-index:6;opacity:0;transition:opacity .28s;background:#fff}
/* ============ 飘字层 ============ */
#dmgLayer{position:absolute;inset:0;overflow:hidden;pointer-events:none;z-index:7}
.dmg{position:absolute;left:0;top:0;font-weight:700;font-size:3.4vmin;color:#fffdf2;
text-shadow:0 0 3px rgba(0,0,0,.9),1px 1px 0 #14231c,-1px -1px 0 #14231c;
will-change:transform,opacity;white-space:nowrap}
.dmg.crit{color:var(--gold);font-size:5.2vmin}
.dmg.hurt{color:#ff7462}
.dmg.heal{color:#9fe6a8}
.dmg.mp{color:var(--gold);font-size:2.8vmin}
/* ============ HUD ============ */
#hud{position:absolute;inset:0;pointer-events:none;z-index:10}
#stat{position:absolute;left:calc(12px + env(safe-area-inset-left));top:calc(10px + env(safe-area-inset-top));
width:min(42vmin,250px)}
#hpbar{position:relative;height:3.2vmin;min-height:17px;overflow:hidden;
border:2px solid rgba(18,24,18,.92);background:rgba(236,228,208,.22);
border-radius:46% 10% 42% 12%/58% 26% 46% 30%}
#hpfill{position:absolute;left:0;top:0;bottom:0;width:100%;
background:linear-gradient(180deg,#d84b3a 0%,#a32418 55%,#7e1a12 100%);transition:width .15s}
#hpfill::after{content:"";position:absolute;inset:0;
background:repeating-linear-gradient(115deg,rgba(255,255,255,.10) 0 6px,transparent 6px 13px)}
#hptxt{position:absolute;right:1.2vmin;top:50%;transform:translateY(-52%);
font-size:2.2vmin;color:#fdf3e0;text-shadow:0 1px 2px #40100a;z-index:2}
#mpbar{position:relative;height:1.9vmin;min-height:10px;margin-top:1.1vmin;overflow:hidden;
border:2px solid rgba(18,24,18,.92);background:rgba(236,228,208,.18);
border-radius:8px 40% 8px 40%/50%}
#mpfill{position:absolute;left:0;top:0;bottom:0;width:100%;
background:linear-gradient(180deg,#e8d28e,#b8913e);transition:width .15s}
#comboEl{position:absolute;left:calc(14px + env(safe-area-inset-left));top:calc(10vmin + env(safe-area-inset-top));
font-size:4.2vmin;color:#f2e6c8;letter-spacing:.3vmin;opacity:0;transition:opacity .25s;
text-shadow:0 0 8px rgba(192,54,44,.95),1px 1px 0 #20120e}
#comboEl.show{opacity:1}
/* 竖排书法侧诗 */
#sidePoem{position:absolute;right:calc(8px + env(safe-area-inset-right));top:15%;
writing-mode:vertical-rl;font-size:2.7vmin;letter-spacing:.9vmin;line-height:2;
color:rgba(236,228,208,.30);text-shadow:0 0 6px rgba(0,0,0,.5)}
body.touch #sidePoem{display:none}
/* Boss 长血条 */
#bosswrap{position:absolute;left:50%;top:calc(2vmin + env(safe-area-inset-top));
transform:translateX(-50%);width:min(66vmin,540px);text-align:center}
#bossname{font-size:3.4vmin;color:#f0d9c0;letter-spacing:.8vmin;text-shadow:0 2px 4px #000;margin-bottom:.6vmin}
#bossbar{height:2.5vmin;min-height:13px;overflow:hidden;border:2px solid rgba(18,14,10,.92);
background:rgba(30,20,16,.55);border-radius:40% 8% 40% 8%/60% 30% 60% 30%}
#bossfill{height:100%;width:100%;background:linear-gradient(180deg,#e0563f,#7e1410);transition:width .18s}
#bossfill.p2{background:linear-gradient(180deg,#ff8340,#c02218)}
/* 波次横幅 */
#banner{position:absolute;left:0;right:0;top:33%;text-align:center;font-size:6.2vmin;
letter-spacing:1.6vmin;color:#ece4d0;opacity:0;transition:opacity .5s;z-index:15;
text-shadow:0 0 18px rgba(0,0,0,.85),0 2px 0 #1c2420}
/* 角落按钮 */
#muteBtn{position:absolute;right:calc(10px + env(safe-area-inset-right));top:calc(10px + env(safe-area-inset-top));
width:8vmin;height:8vmin;min-width:40px;min-height:40px;border-radius:50%;pointer-events:auto;
border:2px solid rgba(236,228,208,.5);background:rgba(20,28,24,.55);color:#ece4d0;
font-family:inherit;font-size:3.4vmin;cursor:pointer;z-index:25}
#skipBtn{position:absolute;right:calc(10px + env(safe-area-inset-right));top:calc(11vmin + env(safe-area-inset-top));
pointer-events:auto;font-family:inherit;font-size:2.8vmin;letter-spacing:.3vmin;color:#f2e6c8;cursor:pointer;
background:rgba(20,28,24,.6);border:1px solid rgba(236,228,208,.45);border-radius:6px;
padding:1vmin 2.2vmin;z-index:25}
/* 键位提示(仅桌面) */
#hint{position:absolute;left:calc(12px + env(safe-area-inset-left));bottom:calc(10px + env(safe-area-inset-bottom));
font-size:2.4vmin;color:rgba(236,228,208,.55);letter-spacing:.2vmin;
background:rgba(16,22,18,.45);border:1px solid rgba(236,228,208,.18);border-radius:6px;padding:1vmin 1.8vmin}
body.touch #hint{display:none}
/* 虚拟摇杆 */
#joy{position:absolute;width:24vmin;height:24vmin;border-radius:50%;display:none;pointer-events:none;z-index:11;
border:2px solid rgba(236,228,208,.35);background:rgba(236,228,208,.08)}
#joyKnob{position:absolute;left:50%;top:50%;width:10vmin;height:10vmin;margin:-5vmin;border-radius:50%;
background:radial-gradient(circle at 35% 30%,rgba(236,228,208,.95),rgba(236,228,208,.4));
border:2px solid rgba(30,36,30,.7)}
/* 技能按钮(触屏) */
#skillbar{position:absolute;display:none;
right:calc(8px + env(safe-area-inset-right));bottom:calc(10px + env(safe-area-inset-bottom));
width:34vmin;height:30vmin;pointer-events:none;z-index:12}
body.touch #skillbar{display:block}
.skill{position:absolute;pointer-events:auto;width:11.5vmin;height:11.5vmin;min-width:52px;min-height:52px;
border-radius:50%;border:3px solid rgba(24,30,24,.85);color:#20261f;font-family:inherit;cursor:pointer;
background:radial-gradient(circle at 35% 30%,#f3ecd9,#cfc4a6);overflow:hidden;
box-shadow:0 2px 10px rgba(0,0,0,.5),inset 0 0 12px rgba(120,90,40,.25)}
.skill span{position:relative;z-index:2;font-size:4.4vmin;text-shadow:0 0 2px #fff}
.skill i{position:absolute;inset:0;border-radius:50%;z-index:1;font-style:normal;
background:conic-gradient(rgba(10,14,10,.62) var(--p,0deg),transparent 0deg)}
.skill:active{transform:scale(.93)}
.skill.nomp span{color:#8a8574}
.s-atk{width:15vmin;height:15vmin;min-width:64px;min-height:64px;right:0;bottom:0;
background:radial-gradient(circle at 35% 30%,#e8d0ba,#b0503c);color:#fff7e8}
.s-atk span{font-size:5.8vmin}
.s-hvy{right:16.5vmin;bottom:.5vmin}
.s-dge{right:1.5vmin;bottom:16.5vmin}
.s-spl{right:16.5vmin;bottom:16.5vmin}
/* ============ 卷轴对话框 ============ */
#dialog{position:absolute;left:50%;bottom:calc(5vmin + env(safe-area-inset-bottom));
transform:translateX(-50%);width:min(86vw,620px);pointer-events:auto;z-index:20;cursor:pointer;
background:linear-gradient(180deg,rgba(242,235,216,.97),rgba(224,214,188,.97));
border:2px solid #2a3128;border-radius:6px;padding:4.2vmin 4vmin 4.6vmin;
box-shadow:0 6px 26px rgba(0,0,0,.55)}
#dialog::before,#dialog::after{content:"";position:absolute;left:-2.5%;right:-2.5%;height:2.4vmin;
background:linear-gradient(180deg,#5a4a33,#2e251a);border-radius:2vmin;box-shadow:0 2px 6px rgba(0,0,0,.5)}
#dialog::before{top:-1.2vmin}
#dialog::after{bottom:-1.2vmin}
#dlgName{position:absolute;top:-2.6vmin;left:3vmin;background:var(--verm);color:#f7ecd9;
padding:.5vmin 1.8vmin;font-size:3vmin;letter-spacing:.4vmin;border-radius:4px;
box-shadow:inset 0 0 0 2px rgba(255,235,200,.28),0 2px 6px rgba(0,0,0,.4)}
#dlgText{font-size:3.8vmin;line-height:1.75;min-height:12vmin;color:#241f16;letter-spacing:.18vmin}
#dlgNext{position:absolute;right:2.6vmin;bottom:1vmin;font-size:2.8vmin;color:#6b5b3e;animation:blink 1s infinite}
@keyframes blink{0%,100%{opacity:.2}50%{opacity:1}}
/* ============ 开始 / 结算 ============ */
#startScr{position:absolute;inset:0;z-index:30;display:flex;flex-direction:column;align-items:center;
justify-content:center;gap:2.6vmin;background:radial-gradient(ellipse at 50% 30%,#16241e 0%,#0a110e 74%)}
#inkRing{position:absolute;width:52vmin;height:52vmin;border-radius:50%;pointer-events:none;
border:2px solid rgba(236,228,208,.13);box-shadow:0 0 60px rgba(127,199,174,.12) inset}
#titleZh{font-size:15vmin;color:#ece4d0;font-weight:700;letter-spacing:2.2vmin;text-indent:2.2vmin;
text-shadow:0 0 26px rgba(127,199,174,.4),0 4px 0 #1a221d}
#titleSub{font-size:3.2vmin;color:#9fb3a6;letter-spacing:1vmin}
#cdnNote{font-size:2.6vmin;color:#7f938a;min-height:4vmin}
.seal-btn{pointer-events:auto;font-family:inherit;font-size:4.4vmin;letter-spacing:1vmin;text-indent:1vmin;
color:#f7ecd9;cursor:pointer;background:linear-gradient(180deg,#c0362c,#8c1f16);
border:2px solid #5f150e;border-radius:10px;padding:1.6vmin 6.5vmin;
box-shadow:inset 0 0 0 2px rgba(255,235,200,.25),0 4px 16px rgba(0,0,0,.55)}
.seal-btn:active{transform:scale(.95)}
#startHint{font-size:2.3vmin;color:#6f8177}
#endScr{position:absolute;inset:0;z-index:29;display:flex;flex-direction:column;align-items:center;
justify-content:center;gap:2.2vmin;background:rgba(6,10,8,.74)}
#endTitle{font-size:14vmin;color:#ece4d0;letter-spacing:2vmin;text-indent:2vmin;
text-shadow:0 0 24px rgba(217,180,92,.5),0 3px 0 #1a221d}
#endTitle.lose{color:#c66a5c;text-shadow:0 0 24px rgba(150,40,30,.6),0 3px 0 #1a1210}
#endQuote{font-size:3.2vmin;color:#c9d6c9;letter-spacing:.3vmin}
#endStats{font-size:3vmin;color:#9fb3a6;text-align:center;line-height:1.9}
/* Toast */
#toast{position:absolute;left:50%;bottom:calc(14vmin + env(safe-area-inset-bottom));transform:translateX(-50%);
max-width:88vw;font-size:2.8vmin;color:#f2e6c8;background:rgba(18,24,20,.85);
border:1px solid rgba(236,228,208,.35);border-radius:8px;padding:1.6vmin 3vmin;z-index:40;
text-align:center;transition:opacity .4s}
/* 竖屏适配 */
@media (orientation:portrait){
#dialog{bottom:40vmin;width:92vw}
#stat{width:38vmin}
#skillbar{transform:scale(.94);transform-origin:bottom right}
#bosswrap{width:76vmin}
}
</style>
</head>
<body>
<div id="app">
<canvas id="c3d"></canvas>
<canvas id="c2d" class="hide"></canvas>
<div id="fxV"></div><div id="fxCA"></div><div id="fxR"></div><div id="fxF"></div>
<div id="dmgLayer"></div>
<div id="hud" class="hide">
<div id="stat">
<div id="hpbar"><div id="hpfill"></div><div id="hptxt">100</div></div>
<div id="mpbar"><div id="mpfill"></div></div>
</div>
<div id="comboEl"></div>
<div id="sidePoem">御剑乘风来<br>除魔天地间</div>
<div id="bosswrap" class="hide">
<div id="bossname">魔尊 · 赤渊</div>
<div id="bossbar"><div id="bossfill"></div></div>
</div>
<div id="banner"></div>
<button id="muteBtn">音</button>
<button id="skipBtn" class="hide">跳过剧情 ›</button>
<div id="hint">W A S D 移动 · J 连斩 · K 蓄力重斩 · L 天雷符 · 空格 翻滚 · 鼠标 转向 · M 静音</div>
<div id="joy"><div id="joyKnob"></div></div>
<div id="skillbar">
<button class="skill s-atk" id="btnL"><span>斩</span><i class="cd"></i></button>
<button class="skill s-hvy" id="btnH"><span>重</span><i class="cd"></i></button>
<button class="skill s-dge" id="btnD"><span>翻</span><i class="cd"></i></button>
<button class="skill s-spl" id="btnS"><span>诀</span><i class="cd"></i></button>
</div>
</div>
<div id="dialog" class="hide">
<div id="dlgName">师尊</div>
<div id="dlgText"></div>
<div id="dlgNext">▼</div>
</div>
<div id="startScr">
<div id="inkRing"></div>
<div id="titleZh">斩魔行</div>
<div id="titleSub">水墨仙侠 · 御剑除魔</div>
<div id="cdnNote">正在召引 three.js ……</div>
<button id="startBtn" class="seal-btn hide">入 局</button>
<div id="startHint">点击「入局」解锁音效 · 手机建议横屏体验</div>
</div>
<div id="endScr" class="hide">
<div id="endTitle">胜</div>
<div id="endQuote"></div>
<div id="endStats"></div>
<button id="restartBtn" class="seal-btn">再 战</button>
</div>
<div id="toast" class="hide"></div>
</div>
<script type="importmap">
{ "imports": { "three": "https://unpkg.com/three@0.160.0/build/three.module.js" } }
</script>
<script type="module">
/* ================================================================
* 《斩魔行》—— 单文件国风仙侠俯视角 3D 动作游戏
* 模块:Config / Audio / Input / UI / Story / Combat / Player /
* Enemy / Boss / Director / Renderer3D / Renderer2D / Game
* ================================================================ */
/* ---------------- 基础工具 ---------------- */
const $ = s => document.querySelector(s);
const TAU = Math.PI * 2;
const clamp = (v, a, b) => v < a ? a : v > b ? b : v;
const lerp = (a, b, t) => a + (b - a) * t;
const rand = (a, b) => a + Math.random() * (b - a);
const elerp = (a, b, t) => a + (b - a) * (1 - Math.exp(-t)); // 指数平滑(帧率无关)
const angDiff = (a, b) => { let d = (b - a) % TAU; if (d > Math.PI) d -= TAU; if (d < -Math.PI) d += TAU; return d; };
const dist2 = (x1, z1, x2, z2) => (x1 - x2) * (x1 - x2) + (z1 - z2) * (z1 - z2);
// 扇形判定:目标点是否在 (x,z) 朝向 face、半径 range、张角 arc 的扇形内
function inSector(px, pz, x, z, face, range, arc) {
const dx = px - x, dz = pz - z, d = Math.hypot(dx, dz);
if (d > range) return false;
if (d < 0.35) return true;
return Math.abs(angDiff(face, Math.atan2(dx, dz))) <= arc / 2;
}
// 把实体限制在圆形演武场内
function clampArena(o) {
const R = CONFIG.arena.radius - (o.r || 0.5);
const len = Math.hypot(o.x, o.z);
if (len > R) { o.x = o.x / len * R; o.z = o.z / len * R; return true; }
return false;
}
const IS_TOUCH = (window.matchMedia && matchMedia('(pointer:coarse)').matches) || 'ontouchstart' in window;
if (.........完整代码请登录后点击上方下载按钮下载查看















网友评论0