Magic_GameClient/sqr/User/GameClass/OctreeClass/OctreeClass.nut

358 lines
14 KiB
Plaintext

/*
文件名:OctreeClass.nut
路径:User/GameClass/OctreeClass/OctreeClass.nut
创建日期:2024-05-18 08:19
文件用途:
*/
class AABB {
minX = null;
minY = null;
minZ = null;
maxX = null;
maxY = null;
maxZ = null;
ObjectIndex = null;
constructor(...) {
minX = vargv[0];
minY = vargv[1];
minZ = vargv[2];
maxX = vargv[3];
maxY = vargv[4];
maxZ = vargv[5];
if (vargv.len() > 6) ObjectIndex = vargv[6];
}
}
class OctreeNode {
static m_maxObjects = 8;
static m_maxDepth = 8;
m_bounds = null;
m_isLeaf = true;
m_depth = 0;
m_objects = null;
m_children = null;
constructor(bounds) {
m_bounds = bounds;
m_depth = 0;
m_objects = [];
m_children = [null, null, null, null, null, null, null, null];
}
// function insert(aabb) {
// if (!m_isLeaf) {
// local index = getIndex(aabb);
// if (index != -1) {
// m_children[index].insert(aabb);
// return;
// }
// }
// m_objects.append(aabb);
// if (m_objects.len() > m_maxObjects && m_depth< m_maxDepth) {
// if (m_isLeaf) {
// split();
// }
// foreach(obj in m_objects) {
// local index = getIndex(obj);
// if (index != -1) {
// m_children[index].insert(obj);
// }
// }
// m_objects.clear();
// }
// }
function insert(aabb) {
if (!this.m_isLeaf) {
local index = this.getIndex(aabb);
if (index != -1 && this.m_children[index]) {
this.m_children[index].insert(aabb);
return;
}
}
if (this.m_objects.len() > this.m_maxObjects && this.m_depth< this.m_maxDepth) {
if (this.m_isLeaf) {
this.split();
}
foreach(obj in this.m_objects) {
local index = this.getIndex(obj);
if (index != -1) {
this.m_children[index].insert(obj);
}
}
this.m_objects.clear();
}
if (this.m_isLeaf) {
this.m_objects.append(aabb);
}
}
function clear() {
for (local i = 0; i< m_children.len(); i++) {
if (m_children[i] != null) {
m_children[i].clear();
m_children[i] = null;
}
}
/*
foreach(child in m_children) {
if (child != null) {
child.clear();
// delete m_children.child;
child = null;
}
}
*/
m_objects.clear();
}
function retrieve(aabb) {
local collidingObjects = [];
local index = getIndex(aabb);
if (index != -1 && !m_isLeaf) {
local tmp = m_children[index].retrieve(aabb);
collidingObjects.extend(tmp);
}
collidingObjects.extend(m_objects);
return collidingObjects;
}
//判断该点是否在给定参数的立方体内
function pointIsInCubeArea(px, py, pz, startX, startY, startZ, endX, endY, endZ) {
local cubeCenterX = (startX + endX) / 2;
local cubeXLen = abs(startX - endX) / 2;
local cubeCenterY = (startY + endY) / 2;
local cubeYLen = abs(startY - endY) / 2;
local cubeCenterZ = (startZ + endZ) / 2;
local cubeZLen = abs(startZ - endZ) / 2;
if (abs(px - cubeCenterX) <= cubeXLen && abs(py - cubeCenterY) <= cubeYLen && abs(pz - cubeCenterZ) <= cubeZLen)
return true;
return false;
}
//立方体与立方体之间碰撞 暂未测试
function CubeAndCubeCollection(c1StartX, c1StartY, c1StartZ, c1EndX, c1EndY, c1EndZ, c2StartX, c2StartY, c2StartZ, c2EndX, c2EndY, c2EndZ) {
if (pointIsInCubeArea(c1StartX, c1StartY, c1StartZ, c2StartX, c2StartY, c2StartZ, c2EndX, c2EndY, c2EndZ))
return true;
if (pointIsInCubeArea(c1EndX, c1StartY, c1StartZ, c2StartX, c2StartY, c2StartZ, c2EndX, c2EndY, c2EndZ))
return true;
if (pointIsInCubeArea(c1StartX, c1EndY, c1StartZ, c2StartX, c2StartY, c2StartZ, c2EndX, c2EndY, c2EndZ))
return true;
if (pointIsInCubeArea(c1EndX, c1EndY, c1StartZ, c2StartX, c2StartY, c2StartZ, c2EndX, c2EndY, c2EndZ))
return true;
if (pointIsInCubeArea(c1StartX, c1StartY, c1EndZ, c2StartX, c2StartY, c2StartZ, c2EndX, c2EndY, c2EndZ))
return true;
if (pointIsInCubeArea(c1EndX, c1StartY, c1EndZ, c2StartX, c2StartY, c2StartZ, c2EndX, c2EndY, c2EndZ))
return true;
if (pointIsInCubeArea(c1StartX, c1EndY, c1EndZ, c2StartX, c2StartY, c2StartZ, c2EndX, c2EndY, c2EndZ))
return true;
if (pointIsInCubeArea(c1EndX, c1EndY, c1EndZ, c2StartX, c2StartY, c2StartZ, c2EndX, c2EndY, c2EndZ))
return true;
if (pointIsInCubeArea(c2StartX, c2StartY, c2StartZ, c1StartX, c1StartY, c1StartZ, c1EndX, c1EndY, c1EndZ))
return true;
if (pointIsInCubeArea(c2EndX, c2StartY, c2StartZ, c1StartX, c1StartY, c1StartZ, c1EndX, c1EndY, c1EndZ))
return true;
if (pointIsInCubeArea(c2StartX, c2EndY, c2StartZ, c1StartX, c1StartY, c1StartZ, c1EndX, c1EndY, c1EndZ))
return true;
if (pointIsInCubeArea(c2EndX, c2EndY, c2StartZ, c1StartX, c1StartY, c1StartZ, c1EndX, c1EndY, c1EndZ))
return true;
if (pointIsInCubeArea(c2StartX, c2StartY, c2EndZ, c1StartX, c1StartY, c1StartZ, c1EndX, c1EndY, c1EndZ))
return true;
if (pointIsInCubeArea(c2EndX, c2StartY, c2EndZ, c1StartX, c1StartY, c1StartZ, c1EndX, c1EndY, c1EndZ))
return true;
if (pointIsInCubeArea(c2StartX, c2EndY, c2EndZ, c1StartX, c1StartY, c1StartZ, c1EndX, c1EndY, c1EndZ))
return true;
if (pointIsInCubeArea(c2EndX, c2EndY, c2EndZ, c1StartX, c1StartY, c1StartZ, c1EndX, c1EndY, c1EndZ))
return true;
if (pointIsInCubeArea((c1StartX + c1EndX) / 2, c1StartY, c1StartZ, c2StartX, c2StartY, c2StartZ, c2EndX, c2EndY, c2EndZ))
return true;
if (pointIsInCubeArea((c1StartX + c1EndX) / 2, c1EndY, c1StartZ, c2StartX, c2StartY, c2StartZ, c2EndX, c2EndY, c2EndZ))
return true;
if (pointIsInCubeArea((c1StartX + c1EndX) / 2, c1StartY, c1EndZ, c2StartX, c2StartY, c2StartZ, c2EndX, c2EndY, c2EndZ))
return true;
if (pointIsInCubeArea((c1StartX + c1EndX) / 2, c1EndY, c1EndZ, c2StartX, c2StartY, c2StartZ, c2EndX, c2EndY, c2EndZ))
return true;
if (pointIsInCubeArea(c1StartX, (c1StartY + c1EndY) / 2, c1StartZ, c2StartX, c2StartY, c2StartZ, c2EndX, c2EndY, c2EndZ))
return true;
if (pointIsInCubeArea(c1StartX, (c1StartY + c1EndY) / 2, c1EndZ, c2StartX, c2StartY, c2StartZ, c2EndX, c2EndY, c2EndZ))
return true;
if (pointIsInCubeArea(c1EndX, (c1StartY + c1EndY) / 2, c1StartZ, c2StartX, c2StartY, c2StartZ, c2EndX, c2EndY, c2EndZ))
return true;
if (pointIsInCubeArea(c1EndX, (c1StartY + c1EndY) / 2, c1EndZ, c2StartX, c2StartY, c2StartZ, c2EndX, c2EndY, c2EndZ))
return true;
if (pointIsInCubeArea(c1StartX, c1StartY, (c1StartZ + c1EndZ) / 2, c2StartX, c2StartY, c2StartZ, c2EndX, c2EndY, c2EndZ))
return true;
if (pointIsInCubeArea(c1StartX, c1EndY, (c1StartZ + c1EndZ) / 2, c2StartX, c2StartY, c2StartZ, c2EndX, c2EndY, c2EndZ))
return true;
if (pointIsInCubeArea(c1EndX, c1StartY, (c1StartZ + c1EndZ) / 2, c2StartX, c2StartY, c2StartZ, c2EndX, c2EndY, c2EndZ))
return true;
if (pointIsInCubeArea(c1EndX, c1EndY, (c1StartZ + c1EndZ) / 2, c2StartX, c2StartY, c2StartZ, c2EndX, c2EndY, c2EndZ))
return true;
if (pointIsInCubeArea((c2StartX + c2EndX) / 2, c2StartY, c2StartZ, c1StartX, c1StartY, c1StartZ, c1EndX, c1EndY, c1EndZ))
return true;
if (pointIsInCubeArea((c2StartX + c2EndX) / 2, c2EndY, c2StartZ, c1StartX, c1StartY, c1StartZ, c1EndX, c1EndY, c1EndZ))
return true;
if (pointIsInCubeArea((c2StartX + c2EndX) / 2, c2StartY, c2EndZ, c1StartX, c1StartY, c1StartZ, c1EndX, c1EndY, c1EndZ))
return true;
if (pointIsInCubeArea((c2StartX + c2EndX) / 2, c2EndY, c2EndZ, c1StartX, c1StartY, c1StartZ, c1EndX, c1EndY, c1EndZ))
return true;
if (pointIsInCubeArea(c2StartX, (c2StartY + c2EndY) / 2, c2StartZ, c1StartX, c1StartY, c1StartZ, c1EndX, c1EndY, c1EndZ))
return true;
if (pointIsInCubeArea(c2StartX, (c2StartY + c2EndY) / 2, c2EndZ, c1StartX, c1StartY, c1StartZ, c1EndX, c1EndY, c1EndZ))
return true;
if (pointIsInCubeArea(c2EndX, (c2StartY + c2EndY) / 2, c2StartZ, c1StartX, c1StartY, c1StartZ, c1EndX, c1EndY, c1EndZ))
return true;
if (pointIsInCubeArea(c2EndX, (c2StartY + c2EndY) / 2, c2EndZ, c1StartX, c1StartY, c1StartZ, c1EndX, c1EndY, c1EndZ))
return true;
if (pointIsInCubeArea(c2StartX, c2StartY, (c2StartZ + c2EndZ) / 2, c1StartX, c1StartY, c1StartZ, c1EndX, c1EndY, c1EndZ))
return true;
if (pointIsInCubeArea(c2StartX, c2EndY, (c2StartZ + c2EndZ) / 2, c1StartX, c1StartY, c1StartZ, c1EndX, c1EndY, c1EndZ))
return true;
if (pointIsInCubeArea(c2EndX, c2StartY, (c2StartZ + c2EndZ) / 2, c1StartX, c1StartY, c1StartZ, c1EndX, c1EndY, c1EndZ))
return true;
if (pointIsInCubeArea(c2EndX, c2EndY, (c2StartZ + c2EndZ) / 2, c1StartX, c1StartY, c1StartZ, c1EndX, c1EndY, c1EndZ))
return true;
if (pointIsInCubeArea((c1StartX + c1EndX) / 2, (c1StartY + c1EndY) / 2, (c1StartZ + c1EndZ) / 2, c2StartX, c2StartY, c2StartZ, c2EndX, c2EndY, c2EndZ))
return true;
if (pointIsInCubeArea((c2StartX + c2EndX) / 2, (c2StartY + c2EndY) / 2, (c2StartZ + c2EndZ) / 2, c1StartX, c1StartY, c1StartZ, c1EndX, c1EndY, c1EndZ))
return true;
return false;
}
function checkCollision(aabb1, aabb2) {
return CubeAndCubeCollection(aabb1.minX, aabb1.minY, aabb1.minZ, aabb1.maxX, aabb1.maxY, aabb1.maxZ, aabb2.minX, aabb2.minY, aabb2.minZ, aabb2.maxX, aabb2.maxY, aabb2.maxZ);
}
function checkCollisionWithNode(aabb) {
local collidingObjects = [];
foreach(obj in m_objects) {
if (checkCollision(obj, aabb)) {
collidingObjects.append(obj);
}
}
if (!m_isLeaf) {
foreach(child in m_children) {
if (child != null) {
local tmp = child.checkCollisionWithNode(aabb);
collidingObjects.extend(tmp);
}
}
}
return collidingObjects;
}
function split() {
local minX = m_bounds.minX;
local maxX = m_bounds.maxX;
local minY = m_bounds.minY;
local maxY = m_bounds.maxY;
local minZ = m_bounds.minZ;
local maxZ = m_bounds.maxZ;
local midX = (minX + maxX) / 2;
local midY = (minY + maxY) / 2;
local midZ = (minZ + maxZ) / 2;
local objectbuf = m_bounds.Object;
m_children[0] = OctreeNode(AABB(minX, minY, minZ, midX, midY, midZ, objectbuf));
m_children[1] = OctreeNode(AABB(midX, minY, minZ, maxX, midY, midZ, objectbuf));
m_children[2] = OctreeNode(AABB(minX, midY, minZ, midX, maxY, midZ, objectbuf));
m_children[3] = OctreeNode(AABB(midX, midY, minZ, maxX, maxY, midZ, objectbuf));
m_children[4] = OctreeNode(AABB(minX, minY, midZ, midX, midY, maxZ, objectbuf));
m_children[5] = OctreeNode(AABB(midX, minY, midZ, maxX, midY, maxZ, objectbuf));
m_children[6] = OctreeNode(AABB(minX, midY, midZ, midX, maxY, maxZ, objectbuf));
m_children[7] = OctreeNode(AABB(midX, midY, midZ, maxX, maxY, maxZ, objectbuf));
m_isLeaf = false;
}
function getIndex(aabb) {
local midX = (m_bounds.minX + m_bounds.maxX) / 2;
local midY = (m_bounds.minY + m_bounds.maxY) / 2;
local midZ = (m_bounds.minZ + m_bounds.maxZ) / 2;
local top = aabb.minY > midY;
local bottom = aabb.maxY< midY;
local north = aabb.minZ > midZ;
local south = aabb.maxZ< midZ;
local east = aabb.minX > midX;
local west = aabb.maxX< midX;
if (top) {
if (east) return 0;
if (west) return 1;
return -1;
}
if (bottom) {
if (east) return 2;
if (west) return 3;
return -1;
}
if (north) {
if (east) return 4;
if (west) return 5;
return -1;
}
if (south) {
if (east) return 6;
if (west) return 7;
return -1;
}
return -1;
}
}
// local octree = OctreeNode(AABB(0, 0, 0, 100, 100, 100));
// octree.clear();
// local aabb1 = AABB(10, 10, 10, 20, 20, 20);
// local aabb2 = AABB(30, 30, 30, 40, 40, 40);
// local aabb3 = AABB(50, 50, 50, 60, 60, 60);
// octree.insert(aabb1);
// octree.insert(aabb2);
// octree.insert(aabb3);
// local testAABB = AABB(15, 15, 15, 35, 35, 35);
// local collidingObjects = octree.checkCollisionWithNode(testAABB);
// print(collidingObjects.len());
// Util.PrintTable(collidingObjects);
// foreach(obj in collidingObjects) {
// print("Colliding object: (" + obj.minX + ", " + obj.minY + ", " + obj.minZ + ") - (" +
// obj.maxX + ", " + obj.maxY + ", " + obj.maxZ + ")");
// }