Слияние кода завершено, страница обновится автоматически
<!DOCTYPE html>
<html>
<head>
<title>Bootstrap5 实例</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link href="static/bootstrap.min.css" rel="stylesheet">
<script src="static/bootstrap.bundle.min.js"></script>
<script src="static/jquery.min.js"></script>
<script src="static/three.min.js"></script>
<style>
body {
margin: 0;
overflow: hidden;
}
#three-container {
width: 100%;
height: 100%;
}
#toolbox {
position: absolute;
top: 10px;
left: 10px;
background-color: rgba(255, 255, 255, 0.1);
/* 半透明背景 */
padding: 10px;
border-radius: 5px;
z-index: 1000;
/* 确保覆盖在Three.js渲染内容之上 */
}
</style>
</head>
<body>
<div id="three-container"></div>
<div id="toolbox">
<div class="input-group mb-2">
<span id="show-time" class="btn btn-info" onclick="ht.show_tools()">0</span>
<span id="state-message" class="input-group-text"></span>
</div>
<div id="tools" style="display:none;">
<div class="input-group mb-1">
<button type="button" class="form-control btn btn-primary" onclick="ht.view(this)">前视图</button>
<button type="button" class="form-control btn btn-primary" onclick="ht.view(this)">后视图</button>
<button type="button" class="form-control btn btn-primary" onclick="ht.view(this)">左视图</button>
<button type="button" class="form-control btn btn-primary" onclick="ht.view(this)">右视图</button>
<button type="button" class="form-control btn btn-primary" onclick="ht.view(this)">俯视图</button>
<button type="button" class="form-control btn btn-primary" onclick="ht.view(this)">顺时针</button>
<button type="button" class="form-control btn btn-primary" onclick="ht.view(this)">逆时针</button>
</div>
<div class="input-group mb-1">
<span id="posColorList" class="badge bg-info" style="width: 35px;">0</span>
<button type="button" class="btn btn-primary" onclick="ht.go_step(this)">-</button>
<input class="form-control" type="range" id="myRange" onchange="ht.go_step(this)" value="0" min="0"
max="0" step="1">
<button type="button" class="btn btn-primary" onclick="ht.go_step(this)">+</button>
<button id="man-auto" type="button" class="btn btn-primary" onclick="ht.go_step(this)">》</button>
</div>
<textarea class="form-control" rows="3" id="sgftext"></textarea>
</div>
</div>
<script>
var health_alert = false;
function health() {
const now = new Date();
const minutes = now.getMinutes();
if (minutes === 0 || minutes === 30) {
if (health_alert) {
alert("游戏健康忠告:请注意休息,合理安排游戏时间。");
health_alert = false;
}
} else {
health_alert = true;
}
}
class simpleGo {
constructor() {
this.positions = ["a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s"];
this.newWeiQi([], {}, []);
this.goString = { string: [], empty: [] };
}
go_handler(item = "B[qd]") {
var position = item.slice(2, 4);
if (this.posColor.hasOwnProperty(position)) {
return false;
} else {
this.posColor[position] = [item[0]];
}
var del_pos = [];
var near_pos = this.near_positions(position);
for (var npn in near_pos) {
if (this.posColor.hasOwnProperty(near_pos[npn])) {
if (this.posColor[near_pos[npn]][0] != this.posColor[position][0]) {
this.goString = { 'string': [], 'empty': [] };
this.go_string(near_pos[npn]);
if (this.goString['empty'].length == 0) {
for (var spn in this.goString['string']) {
del_pos.includes(this.goString['string'][spn]) || del_pos.push(this.goString['string'][spn]);
}
}
}
}
}
if (del_pos.length == 0) {
this.goString = { 'string': [], 'empty': [] };
this.go_string(position);
if (this.goString['empty'].length == 0) {
delete this.posColor[position];
return false;
}
} else {
for (var d_p in del_pos) {
delete this.posColor[del_pos[d_p]];
}
}
this.sgf.push(item);
this.posColor[position].push(this.sgf.length)
this.posColorList.push(JSON.parse(JSON.stringify(this.posColor)));
return true;
}
go_string(position) {
this.goString['string'].push(position);
var nPos = this.near_positions(position);
for (var np in nPos) {
if (this.posColor.hasOwnProperty(nPos[np])) {
if (!this.goString['string'].includes(nPos[np]) && this.posColor[nPos[np]][0] == this.posColor[position][0]) {
this.go_string(nPos[np]);
}
} else {
this.goString['empty'].includes(nPos[np]) || this.goString['empty'].push(nPos[np]);
}
}
}
near_positions(position) {
var near_pos = [];
var row = this.near(position[0]);
var col = this.near(position[1]);
for (var r in row) {
near_pos.push(row[r] + position[1]);
}
for (var c in col) {
near_pos.push(position[0] + col[c]);
}
return near_pos;
}
near(char) {
switch (char) {
case "a":
return ["b"];
case "s":
return ["r"];
case "b": case "c": case "d": case "e": case "f": case "g":
case "h": case "i": case "j": case "k": case "l": case "m":
case "n": case "o": case "p": case "q": case "r":
default:
var pos = this.positions.indexOf(char);
return [this.positions[pos - 1], this.positions[pos + 1]];
}
}
newWeiQi(sgf, posColor, posColorList) {
this.sgf = sgf;
this.posColor = posColor;
this.posColorList = posColorList;
}
}
const sgo = new simpleGo();
const sgftext = `(;CA[UTF-8]AP[YuanYu]GM[1]FF[4]
SZ[19]
GN[2018腾讯世界人工智能围棋大赛决赛第1局 30日10:00]
DT[2018-07-30]
PB[Golaxy]BR[9d]
PW[FineArt]WR[9d]
KM[7.5]HA[0]RU[Chinese]RE[W+R]TM[3600]TC[10]TT[60]
;B[qd];W[pp];B[dd];W[dp];B[qn];W[qo];B[pn];W[np];B[pj];W[od];B[lc]
;W[me];B[lq];W[qe];B[fq];W[cc];B[qq];W[rn];B[cd];W[dc];B[ed];W[ec]
;B[rm];W[or];B[ro];W[rp];B[qp];W[po];B[sn];W[rq];B[fc];W[fb];B[cn]
;W[er];B[bc];W[bb];B[eb];W[db];B[gb];W[pd];B[eo];W[co];B[bn];W[fp]
;B[ep];W[eq];B[do];W[cq];B[fr];W[iq];B[hp];W[gq];B[gp];W[fo];B[fn]
;W[go];B[hn];W[gr];B[gn];W[fs];B[ei];W[bd];B[be];W[ac];B[cf];W[ih]
;B[qc];W[rf];B[pf];W[qh];B[ob];W[nb];B[oc];W[pc];B[pb];W[rd];B[nd]
;W[qb];B[oe];W[rc];B[nc];W[if];B[hg];W[ig];B[je];W[gi];B[fg];W[hf]
;B[fj];W[lg];B[lf];W[mg];B[kg];W[kh];B[mf];W[ff];B[gg];W[fd];B[gc]
;W[hd];B[fe];W[gd];B[ic];W[gj];B[kf];W[bg];B[cg];W[kj];B[bo];W[gk]
;B[fk];W[id];B[jc];W[eh];B[fh];W[fi];B[ej];W[fl];B[el];W[gl];B[lo]
;W[ae];B[bh];W[em];B[dl];W[km];B[ho];W[qk];B[ol];W[bf];B[ce];W[gf]
;B[ef];W[qj];B[hq];W[hr];B[pi];W[qi];B[lk];W[kk];B[lh];W[li];B[mh]
;W[ng];B[oo];W[pq];B[og];W[nh];B[mi];W[oh];B[qr];W[rr];B[mj];W[ph]
;B[lm];W[kl];B[jh];W[ki];B[bq];W[hh];B[eg];W[ll];B[ml];W[no];B[ln]
;W[nk];B[mk];W[nm];B[nn];W[mm];B[nl];W[mn];B[om];W[mo];B[jq];W[rl]
;B[ql];W[pl];B[qm];W[ir];B[jn];W[pk];B[rk];W[on];B[pm];W[rj];B[sl]
;W[cr];B[jg];W[ji];B[hl];W[il];B[hm];W[jp];B[kp];W[kn];B[ko];W[ik]
;B[cp];W[jr];B[jo];W[hc];B[hb];W[ea];B[af];W[ag];B[fq];W[br];B[ar]
;W[lr];B[mr];W[kq];B[mq];W[ad];B[ah];W[af];B[fm];W[sp];B[nn];W[op]
;B[dq];W[dr];B[jm];W[jl];B[ls];W[on];B[kr];W[nf];B[ne];W[ok];B[hk]
;W[hj];B[pg];W[jd])`
class extract_go_manual {
constructor() {
this.positions = ["a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s"];
this.combinedPattern = /[\u4e00-\u9fa5a-zA-Z0-9;\[\]\-: ]+/g;
}
handle(text) {
sgo.newWeiQi([], {}, []);
var results = text.match(this.combinedPattern) || [];
var format_content = results.join('').split(";");
for (var index in format_content) {
var item = format_content[index];
if (item.length == 5 && this.positions.includes(item[2]) && this.positions.includes(item[3])) {
sgo.go_handler(item);
}
}
}
}
const egm = new extract_go_manual();
class Three3D {
constructor() {
this.positions = ["a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s"];
this.scene = this.create_scene("LightBlue");
this.camera = this.create_camera([0, 0, 30]);
this.renderer = this.create_renderer();
let threeContainer = document.getElementById("three-container");
threeContainer.appendChild(this.renderer.domElement);
this.group1 = new THREE.Group();
this.scene.add(this.group1);
//this.group1.add(this.create_face([0, 0, -2e-5], [20, 20], "Yellow"));
this.group1.add(this.create_box([0, 0, -0.5 - 3e-3], [20, 20, 1], "Yellow"));
for (let i = 0; i < 19; i++) {
this.group1.add(this.create_face([i - 9, 0, -1e-3], [0.1, 18], "Black"));
this.group1.add(this.create_face([0, i - 9, -1e-3], [18, 0.1], "Black"));
}
let xingwei = [-6, 0, 6];
xingwei.forEach((row) => {
xingwei.forEach((col) => {
this.group1.add(this.create_torus([row, col, -0.03], [0.3, 0.05], "Black"));
});
});
//this.group1.add(this.create_box([0, -12, 0], [0.5, 0.5, 0.1], "Black"));
this.group1.add(this.create_box([-9.6, 9.6, 0], [0.5, 0.5, 0.01], "LightGreen"));
this.group2 = new THREE.Group();
this.scene.add(this.group2);
this.group2.add(this.create_box([0, 0, -1], [0.2, 0.2, 0.1], "LightGreen"));
//this.group2.add(this.lightPoint([30, 30, 30], "White", 5000, 1000));
this.group2.add(this.lightAmbient([30, 30, 30], "White", 100));
/*
this.group2.children[0].material.transparent = true;
this.group2.children[0].material.opacity = 0.01;
*/
this.group3 = new THREE.Group();
this.scene.add(this.group3);
this.scene.add(new THREE.AxesHelper(5));
this.setupClickListener(this.renderer.domElement, this);
}
lightDirectional(position = [0, 0, 0], color = "Gray", intensity = 1) {
// 创建方向光(可选,但推荐用于增强场景光照)
const directionalLight = new THREE.DirectionalLight(color, intensity);
directionalLight.position.set(position[0], position[1], position[2]); // 设置光的位置
directionalLight.castShadow = true; // 启用阴影投射
return directionalLight;
}
lightAmbient(position = [0, 0, 0], color = "Gray", intensity = 1) {
// 创建环境光
const ambientLight = new THREE.AmbientLight(color, intensity); // 灰色环境光,用于照亮整个场景
ambientLight.position.set(position[0], position[1], position[2]); // 设置光的位置
return ambientLight;
}
lightPoint(position = [0, 0, 0], color = "White", intensity = 1000, distance = 1000) {
let pointLight = new THREE.PointLight(color, intensity, distance); // 白色光,强度为1,距离为100
pointLight.position.set(position[0], position[1], position[2]); // 设置光的位置
pointLight.castShadow = true; // 启用阴影投射
// 设置阴影属性(可选,但推荐根据需要进行调整)
pointLight.shadow.mapSize.width = window.innerWidth; // 阴影映射的宽度
pointLight.shadow.mapSize.height = window.innerHeight; // 阴影映射的高度
pointLight.shadow.camera.near = 0.5; // 阴影相机的近裁剪面
pointLight.shadow.camera.far = 1000; // 阴影相机的远裁剪面
pointLight.shadow.camera.fov = 50; // 阴影相机的视场角
const pointLightHelper = new THREE.PointLightHelper(pointLight, 1); // 第二个参数是辅助对象的大小
this.scene.add(pointLightHelper);
return pointLight;
}
create_scene(color) {
let scene = new THREE.Scene();
scene.background = new THREE.Color(color);
return scene;
}
create_camera(position = [10, 10, 10], origin = [0, 0, 0]) {
let camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
camera.position.set(position[0], position[1], position[2]);
camera.lookAt(new THREE.Vector3(origin[0], origin[1], origin[2]));
return camera;
}
create_renderer() {
let renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.shadowMap.enabled = true;
renderer.shadowMap.type = THREE.PCFSoftShadowMap; // 可选:使用柔和阴影
return renderer;
}
create_material(imgData) {
if (imgData.split(";")[0] == "data:image/png") {
let textureLoader = new THREE.TextureLoader();
let texture = textureLoader.load(imgData);
let material = new THREE.MeshBasicMaterial({ map: texture });
return material;
} else {
let material = new THREE.MeshStandardMaterial({ color: imgData });
return material;
}
}
create_face(position = [0, 0, 0], size = [1, 1], imgData = "") {
let planeGeometry = new THREE.PlaneGeometry(size[0], size[1]);
let planeMaterial = this.create_material(imgData);
planeMaterial.side = THREE.DoubleSide;
let plane = new THREE.Mesh(planeGeometry, planeMaterial);
plane.position.set(position[0], position[1], position[2]);
plane.receiveShadow = true;
return plane;
}
create_box(position = [0, 0, 0], size = [1, 1, 1], color = "Black") {
var geometry = new THREE.BoxGeometry(size[0], size[1], size[2]);
var material = new THREE.MeshBasicMaterial({ color: color });
var cube = new THREE.Mesh(geometry, material);
cube.up.set([0, 0, 1]);
cube.position.set(position[0], position[1], position[2]);
//cube.rotation.x = Math.PI / 2;
return cube;
}
create_cylinder(position = [0, 0, 0], color = "Black") {
// 创建圆柱体几何体和材质
var geometry = new THREE.CylinderGeometry(0.2, 0.5, 0.1, 32); // 参数: 半径顶部, 半径底部, 高度, 径向分段数
//const material = new THREE.MeshLambertMaterial({ color: color, emissive: 0xff0000 }); // 白色带红色自发光
var material = new THREE.MeshStandardMaterial({
color: color,
transparent: true,
opacity: 0.95,
}); // 绿色材质
var cylinder = new THREE.Mesh(geometry, material);
cylinder.up.set([0, 0, 1]);
cylinder.position.set(position[0], position[1], position[2]);
cylinder.rotation.x = Math.PI / 2;
cylinder.receiveShadow = true;
return cylinder;
}
create_sphere(position = [0, 0, 0], color = "Black", radius = 0.5) {
// 创建球体几何体
var geometry = new THREE.SphereGeometry(radius, 32, 32); // 半径为1,宽度分段为32,高度分段为32
// 创建材质,并设置颜色和透明度
var material = new THREE.MeshStandardMaterial({
color: color,
transparent: true, // 允许透明
opacity: 0.7, // 透明度值(0.0 完全透明,1.0 完全不透明)
});
// 创建网格(球体)
var sphere = new THREE.Mesh(geometry, material);
sphere.position.set(position[0], position[1], position[2]);
sphere.castShadow = true;
return sphere;
}
create_ellipse(position = [0, 0, 0], color = "Black") {
const radiusX = 0.5;
const radiusY = 0.5;
const radiusZ = 0.1;
const widthSegments = 32;
const heightSegments = 32;
const phiSegments = 32;
const ellipsoidGeometry = this.createEllipsoidGeometry(radiusX, radiusY, radiusZ, widthSegments, heightSegments, phiSegments);
const material = new THREE.MeshBasicMaterial({
color: color,
//wireframe: true,
transparent: true,
opacity: 0.95,
});
const ellipsoid = new THREE.Mesh(ellipsoidGeometry, material);
ellipsoid.position.set(position[0], position[1], position[2]);
ellipsoid.castShadow = true;
return ellipsoid;
}
create_torus(position = [0, 0, 0], size = [1, 0.5], color = "Black") {
// 创建环形几何体
const radius = size[0]; // 环形的大圆半径
const tube = size[1]; // 环形的管道半径
const radialSegments = 16; // 环形圆周上的分段数
const tubularSegments = 100; // 管道圆周上的分段数
const torusGeometry = new THREE.TorusGeometry(radius, tube, radialSegments, tubularSegments);
// 创建材质, wireframe: true
const torusMaterial = new THREE.MeshBasicMaterial({ color: color });
// 创建网格
const torusMesh = new THREE.Mesh(torusGeometry, torusMaterial);
torusMesh.position.set(position[0], position[1], position[2]);
torusMesh.castShadow = true;
return torusMesh;
}
setupClickListener(element, someVariable) {
element.addEventListener('wheel', function (event) {
let delta = 0;
if (event.type === 'wheel') {
delta = -event.deltaY;
} else if (event.type === 'mousewheel') {
delta = event.wheelDelta;
}
let radius, theta, phi, x, y, z;
[radius, theta, phi] = someVariable.cartesianToSpherical(someVariable.camera.position.x, someVariable.camera.position.y, someVariable.camera.position.z);
[x, y, z] = someVariable.sphericalToCartesian(radius + delta / 100, theta, phi);
someVariable.camera.position.x = x;
someVariable.camera.position.y = y;
someVariable.camera.position.z = z;
someVariable.camera.lookAt(new THREE.Vector3(0, 0, 0));
});
element.addEventListener('mousedown', function (event) {
if (event.button == 0) {
this.painting = true;
someVariable.select(event.clientX, event.clientY);
} else if (event.button == 1) {
this.paintingM = true;
someVariable.basePosition = someVariable.rotate_basic(event);
}
});
element.addEventListener('mousemove', function (event) {
if (this.painting) {
console.log(event.button, event.clientX, event.clientY);
} else if (this.paintingM) {
someVariable.camera_rotate(event);
}
});
element.addEventListener('mouseup', function (event) {
if (this.painting) {
this.painting = false;
} else if (this.paintingM) {
this.paintingM = false;
}
});
}
select(clientX, clientY) {
let mouse = new THREE.Vector2();
mouse.x = (clientX / window.innerWidth) * 2 - 1;
mouse.y = -(clientY / window.innerHeight) * 2 + 1;
let raycaster = new THREE.Raycaster();
raycaster.setFromCamera(mouse, this.camera);
let intersects = raycaster.intersectObjects(this.group1.children, true);
if (intersects.length > 0) {
let intersect = intersects[0];
let position = this.coordinate_position(intersect.point.x + 10, 10 - intersect.point.y);
let [x, y] = this.position_coordinate(position);
//console.log(intersect.point, position, x, y)
let key, color = { "B": "Black", "W": "White" };
if (sgo.sgf.length = 0) {
key = "B";
} else if (sgo.sgf.length = 1) {
key = "W";
} else {
key = sgo.sgf[sgo.sgf.length - 2].slice(0, 1);
}
console.log(key, color[key])
this.group3.add(this.create_cylinder([x, y, 0.2], color[key]));
}
}
show(posColor) {
let x, y, color = { "B": "Black", "W": "FloralWhite" };
while (this.group3.children.length > 0) {
this.group3.remove(this.group3.children[0]);
}
for (let position in posColor) {
[x, y] = this.position_coordinate(position);
//console.log(position, sgo.posColor[position], color[sgo.posColor[position][0]]);
this.group3.add(this.create_cylinder([x, y, 0.03], color[posColor[position][0]]));
}
let position = sgo.sgf[Number(document.getElementById("myRange").value)].slice(2, 4);
let [lx, ly] = this.position_coordinate(position);
this.group2.children[0].position.set(lx, ly, 0.1);
}
changeGroupChildrenColor(group, newColor) {
group.children.forEach(child => {
if (child.isMesh) {
child.material.color.set(newColor);
} else if (child.children.length > 0) {
this.changeGroupChildrenColor(child, newColor);
}
});
}
rotate_basic(event) {
let [radius, theta, phi] = this.cartesianToSpherical(this.camera.position.x, this.camera.position.z, this.camera.position.y);
let basePosition = [event.clientX, event.clientY, radius, theta, phi];
return basePosition;
}
camera_rotate(event) {
const mouseX = event.clientX;
const mouseY = event.clientY;
var radius = this.basePosition[2];
var theta = this.minmax(mouseX - this.basePosition[0], -500, 500) / 500 * Math.PI + this.basePosition[3];
var phi = this.minmax(this.basePosition[1] - mouseY, -200, 200) / 200 * Math.PI / 2 + this.basePosition[4];
console.log(radius, theta, phi)
let [x, z, y] = this.sphericalToCartesian(radius, phi, theta);
this.camera.position.set(x, y, z);
this.camera.lookAt(new THREE.Vector3(0, 0, 0));
}
cartesianToSpherical(x, y, z) {
//r = sqrt(x^2 + y^2 + z^2), θ = arccos(z / r), φ = arctan2(y, x)
let radius, theta, phi;
radius = Math.sqrt(Math.pow(x, 2) + Math.pow(y, 2) + Math.pow(z, 2));
theta = Math.acos(z / radius);
phi = Math.atan2(y, x);
return [radius, theta, phi];
}
sphericalToCartesian(radius, theta, phi) {
//x=rsin(θ)cos(ϕ), y=rsin(θ)sin(ϕ), z=rcos(θ)
let x = radius * Math.sin(theta) * Math.cos(phi);
let y = radius * Math.sin(theta) * Math.sin(phi);
let z = radius * Math.cos(theta);
return [x, y, z];
}
coordinate_position(x, y) {
let row, col, grid = 1;
row = this.minmax(Math.floor((x - grid / 2) / grid), 0, 18);
col = this.minmax(Math.floor((y - grid / 2) / grid), 0, 18);
return this.positions[row] + this.positions[col];
}
minmax(coordinate, min, max) {
return Math.min(max, Math.max(min, coordinate));
}
position_coordinate(position) {
let row, col, x, y, grid = 1;
row = this.positions.indexOf(position.slice(0, 1));
col = this.positions.indexOf(position.slice(1, 2));
x = Math.floor(row * grid);
y = Math.floor(col * grid);
return [x - 9, 9 - y];
}
createEllipsoidGeometry(radiusX, radiusY, radiusZ, widthSegments, heightSegments, phiSegments) {
const vertices = [];
const indices = [];
const vertexTemplate = new THREE.Vector3();
const normalTemplate = new THREE.Vector3();
const xStep = Math.PI / widthSegments;
const yStep = Math.PI / heightSegments;
const zStep = Math.PI * 2 / phiSegments;
for (let y = 0; y <= heightSegments; y++) {
const theta = y * yStep;
const sinTheta = Math.sin(theta);
const cosTheta = Math.cos(theta);
for (let x = 0; x <= widthSegments; x++) {
const phi = x * xStep;
const sinPhi = Math.sin(phi);
const cosPhi = Math.cos(phi);
for (let z = 0; z < phiSegments; z++) {
const psi = z * zStep;
const sinPsi = Math.sin(psi);
const cosPsi = Math.cos(psi);
vertexTemplate.x = radiusX * (cosPhi * sinTheta * cosPsi - sinPhi * cosTheta * sinPsi);
vertexTemplate.y = radiusY * (sinPhi * sinTheta * cosPsi + cosPhi * cosTheta * sinPsi);
vertexTemplate.z = radiusZ * (cosTheta * cosPsi);
vertices.push(vertexTemplate.clone());
normalTemplate.copy(vertexTemplate).normalize();
if (x < widthSegments && y < heightSegments && z < phiSegments - 1) {
const a = (y * (widthSegments + 1) + x) * phiSegments + z;
const b = (y * (widthSegments + 1) + x) * phiSegments + (z + 1);
const c = ((y + 1) * (widthSegments + 1) + x) * phiSegments + (z + 1);
const d = ((y + 1) * (widthSegments + 1) + x) * phiSegments + z;
indices.push(a, b, d);
indices.push(b, c, d);
}
}
}
}
const geometry = new THREE.BufferGeometry();
geometry.setAttribute('position', new THREE.BufferAttribute(new Float32Array(vertices.flatMap(v => [v.x, v.y, v.z])), 3));
geometry.setIndex(indices);
geometry.computeVertexNormals();
return geometry;
}
}
const t3d = new Three3D();
class Animation {
constructor() {
this.startTime = null;
this.animationFrameId = null;
this.is1000ms = true;
this.is5s = 0;
this.start();
this.antiClockwise = 0;
this.isRotation = false;
}
start() {
if (this.animationFrameId == null) {
this.startTime = performance.now();
this.animate();
}
}
stop() {
if (this.animationFrameId !== null) {
cancelAnimationFrame(this.animationFrameId);
this.animationFrameId = null;
}
}
animate() {
const currentTime = performance.now();
const elapsedTime = currentTime - this.startTime;
if (currentTime % 1000 < 300) {
if (this.is1000ms) {
health();
$("#show-time").text(Number($("#show-time").text()) + 1);
if ($("#state-message").text() != "" && this.is5s < 5) {
this.is5s++;
} else if ($("#state-message").text() != "") {
$("#state-message").text("");
this.is5s = 0;
}
if (this.autoRun) {
if (Number(document.getElementById("myRange").value) < sgo.sgf.length - 1) {
document.getElementById("myRange").value = Math.min(sgo.sgf.length - 1, Number(document.getElementById("myRange").value) + 1);
document.getElementById("posColorList").textContent = document.getElementById("myRange").value;
t3d.show(sgo.posColorList[Number(document.getElementById("myRange").value)]);
} else {
this.autoRun = false;
}
}
}
this.is1000ms = false;
} else {
this.is1000ms = true;
}
if (this.isRotation) {
let clockValue = 0
if (this.antiClockwise == 1) {
clockValue = 0.005;
} else if (this.antiClockwise == 2) {
clockValue = -0.005;
}
t3d.group1.rotation.z += clockValue;
t3d.group2.rotation.z += clockValue;
t3d.group3.rotation.z += clockValue;
}
t3d.renderer.render(t3d.scene, t3d.camera);
this.animationFrameId = requestAnimationFrame(this.animate.bind(this));
}
}
const animation = new Animation();
class htmlClick {
constructor() {
document.getElementById("myRange").max = sgo.sgf.length - 1;
}
view(tt) {
let radius = 30, theta, phi, x, y, z;
radius = Math.sqrt(Math.pow(t3d.camera.position.x, 2) + Math.pow(t3d.camera.position.y, 2) + Math.pow(t3d.camera.position.z, 2));
t3d.camera.up.set(0, 0, 1);
animation.antiClockwise = 0;
animation.isRotation = false;
t3d.group1.rotation.z = 0;
t3d.group2.rotation.z = 0;
t3d.group3.rotation.z = 0;
switch ($(tt).text()) {
case "前视图":
phi = Math.PI / 6;
theta = 0;
break;
case "后视图":
phi = Math.PI / 6;
theta = Math.PI;
break;
case "左视图":
phi = Math.PI / 6;
theta = Math.PI * 1.5;
break;
case "右视图":
phi = Math.PI / 6;
theta = Math.PI / 2;
break;
case "俯视图":
t3d.camera.up.set(0, 1, 0);
phi = 0;
theta = 0;
break;
case "逆时针":
animation.antiClockwise = 1;
animation.isRotation = true;
return;
case "顺时针":
animation.antiClockwise = 2;
animation.isRotation = true;
return;
default:
console.log($(tt).val());
return;
}
[x, y, z] = this.sphericalToCartesian([radius, phi, theta]);
t3d.camera.position.set(x, y, z);
t3d.camera.lookAt(new THREE.Vector3(0, 0, 0));
}
go_step(tt) {
switch ($(tt).text()) {
case "-":
document.getElementById("myRange").value = Math.max(0, Number(document.getElementById("myRange").value) - 1);
//drawQipan.draw(sgo.posColorList[Number(document.getElementById("myRange").value)]);
break;
case "+":
document.getElementById("myRange").value = Math.min(sgo.sgf.length - 1, Number(document.getElementById("myRange").value) + 1);
//drawQipan.draw(sgo.posColorList[Number(document.getElementById("myRange").value)]);
break;
case "》":
//t3d.test();
if (document.getElementById("sgftext").value == "") {
egm.handle(sgftext)
} else {
egm.handle(document.getElementById("sgftext").value)
}
document.getElementById("myRange").max = sgo.sgf.length - 1;
document.getElementById("myRange").value = 0;
document.getElementById("posColorList").textContent = 0;
if (!animation.autoRun) { animation.autoRun = true; }
break;
default:
console.log(document.getElementById("myRange").value);
break;
}
document.getElementById("posColorList").textContent = document.getElementById("myRange").value;
t3d.show(sgo.posColorList[Number(document.getElementById("myRange").value)]);
}
show_tools() {
$("#tools").toggle();
$("#state-message").text("健康忠告:请注意休息,合理安排时间。");
}
sphericalToCartesian(spherical) {
let x = spherical[0] * Math.sin(spherical[1]) * Math.cos(spherical[2]);
let y = spherical[0] * Math.sin(spherical[1]) * Math.sin(spherical[2]);
let z = spherical[0] * Math.cos(spherical[1]);
return [x, y, z];
}
}
const ht = new htmlClick();
window.addEventListener('resize', () => {
t3d.camera.aspect = window.innerWidth / window.innerHeight;
t3d.camera.updateProjectionMatrix();
t3d.renderer.setSize(window.innerWidth, window.innerHeight);
});
</script>
</body>
</html>
Вы можете оставить комментарий после Вход в систему
Неприемлемый контент может быть отображен здесь и не будет показан на странице. Вы можете проверить и изменить его с помощью соответствующей функции редактирования.
Если вы подтверждаете, что содержание не содержит непристойной лексики/перенаправления на рекламу/насилия/вульгарной порнографии/нарушений/пиратства/ложного/незначительного или незаконного контента, связанного с национальными законами и предписаниями, вы можете нажать «Отправить» для подачи апелляции, и мы обработаем ее как можно скорее.
Опубликовать ( 0 )