import { _decorator, Vec3, randomRangeInt, path, IVec3Like, math, v3, randomRange, Line, find } from 'cc'; import { KeyAnyType } from '../data/game-type'; const { ccclass, property, executeInEditMode } = _decorator; export namespace NavSystem { export type NavPointType = { x: number, y: number, z: number, id: number, radius: number, } let data: KeyAnyType; export function Init (_data: any) { data = _data; } export function nodePosition (nodeID: number) { return data.nodes[nodeID]; } export function randomPoint (size = 0.5) { const randomNode = randomRangeInt(0, data.count); const node = data.nodes[randomNode]; const radius = node.radius - size; const position = v3(node.x + randomRange(-radius, radius), node.y, node.z + randomRange(-radius, radius)); return { closestNavigationPon: randomNode, position: position }; } export function randomPaths (paths: Array, position: Vec3, count: number, nearest: number = -1): NavPointType[] { paths.length = 0; if (nearest === -1) { // find nearest point. nearest = findNearestPoint(position); } if (nearest === -1) { return []; } // search path. calculateRandomPaths(paths, nearest, count); return paths; } export function randomFirePath (paths: Array, node: number) { paths.length = 0; const length = randomRangeInt(5, 11); const nodeData = data.nodes[node]; for (let i = 0; i < length; i++) { let point = v3( nodeData.x + randomRange(-nodeData.radius, nodeData.radius), nodeData.y, nodeData.z + randomRange(-nodeData.radius, nodeData.radius) ) paths[i] = { x: point.x, y: point.y, z: point.z, id: nodeData.id, radius: nodeData.radius }; } return paths; } export function findNearest (position: Vec3): number { const length = data.nodes.length; let minlength = Number.MAX_VALUE; let index = -1; for (let i = 0; i < length; i++) { const node = data.nodes[i]; const curLen = Vec3.distance(position, node); if (curLen < minlength) { index = i; minlength = curLen; } } if (index === -1) { throw new Error(`'can not find target node.`); } return index; } function findNearestPoint (position: Vec3): number { if (data == undefined) { console.warn(' Navigation data not init.'); return 0; } return findNearest(position); /* let closestNavigationPon = -1; const x = Math.floor(position.x/data.blockX); const y = Math.floor(position.y/data.blockY); const z = Math.floor(position.z/data.blockZ); const key = `${x},${y},${z}`; const blockNodes = data.nodeMap[key]; if(blockNodes === undefined) { console.warn(`Can not find block:${key}, position:${position}`) return -1; } let minDistance = Number.MAX_VALUE; //console.log(blockNodes); for (let i = 0; i < blockNodes.length; i++) { const nodeID = blockNodes[i] const nodePosition = data.nodes[nodeID]; const currentDistance = Vec3.distance(position, nodePosition); if(currentDistance < minDistance) { closestNavigationPon = nodeID; } } return closestNavigationPon; */ } function calculateRandomPaths (paths: Array, start: number, count: number) { if (data == undefined) { console.warn(' Navigation data not init.'); return 0; } paths[0] = data.nodes[start]; //console.log('start node:', start, paths[0]); let currentNode = start; for (let i = 1; i < count; i++) { // random children. const links = data.links[currentNode]; const randomLinkIndex = randomRangeInt(0, links.length); currentNode = links[randomLinkIndex] paths[i] = (data.nodes[currentNode]); //console.log('point_', currentNode, links, randomLinkIndex, paths[i]); } } type PathPoint = { node: number, g: number, h: number, f: number, parent: PathPoint | undefined } export function findPaths (paths: Array, start: Vec3, startNearest: number = -1, end: Vec3): NavPointType[] { paths.length = 0; // open table. let openTable: PathPoint[] = []; // close table. let closeTable: PathPoint[] = []; if (startNearest === -1) { // find nearest point. startNearest = findNearestPoint(start); openTable.push({ node: startNearest, g: 0, h: 0, f: 0, parent: undefined }); } // find nearest end point. const endNearest = findNearestPoint(end); //console.log('endNearest id', endNearest); // check start equal end. if (startNearest === endNearest) { paths.push(data.nodes[startNearest]); return paths; } const findMinCostPoint = function (): number { if (openTable.length <= 0) return -1; let cost = Number.MAX_VALUE; let minNode = -1; for (let i = 0; i < openTable.length; i++) { const current = openTable[i]; if (current.f < cost) { minNode = i; cost = current.f; } } return minNode; } const checkInOpenTable = function (node: number) { for (let openTableI = 0; openTableI < openTable.length; openTableI++) { if (openTable[openTableI].node === node) return true; } return false; } const checkInCloseTable = function (node: number) { for (let closeTableI = 0; closeTableI < closeTable.length; closeTableI++) { if (closeTable[closeTableI].node === node) return true; } return false; } const pushOpenTable = function (node: number, parent: PathPoint) { const nodeData = data.nodes[node]; // find target. if (nodeData.id == endNearest) { //console.log('find target.', nodeData.id, ' target id:', endNearest); return { node, g: 0, h: 0, f: 0, parent }; } //console.log(start, nodeData); const g = Vec3.distance(start, nodeData); const h = Vec3.distance(nodeData, end); const f = g + h; //console.log('distances start:', distanceStart, 'distances target:', distanceTarget, 'f:', f); openTable.push({ node, f, g, h, parent }); return undefined } const searchNeighbor = function (parent: PathPoint) { const links = data.links[parent.node]; //console.log('node:', node, 'neighbor links', links); for (let i = 0; i < links.length; i++) { const linkNode = links[i]; // find in close table. // console.log('neighbor:', links[i], 'close table:', closeTable, 'state:', inCloseTable); if (checkInCloseTable(linkNode)) continue; // find in open table. if (checkInOpenTable(linkNode)) continue; // push in open table. const findPathPoint = pushOpenTable(linkNode, parent); if (findPathPoint) return findPathPoint; } return false; } const find = function () { // find min cost point. const minNodeIndex = findMinCostPoint(); if (minNodeIndex == -1) { //console.log('can not find target.'); return null; } //console.log('open table:', openTable, 'minNode:', minNode); // open table. const minNode = openTable[minNodeIndex]; // remove open table. openTable.splice(minNodeIndex, 1); // insert close table. closeTable.push(minNode); // search neighbors. const findPathPoint = searchNeighbor(minNode); if (findPathPoint) { //console.log('find node target:', findPathPoint); return findPathPoint; } return undefined; } const calculateParent = function (targetNode: PathPoint) { const parent = targetNode.parent; if (parent == undefined) return; const node = data.nodes[parent.node]; paths.push(node); calculateParent(parent); } let index = -1; let max = 112; let findTargetPoint: PathPoint | undefined | null; while (true) { index++; //console.log('index:', index, 'close table count:', closeTable.length, 'open table count:', openTable.length); if (index > max) break; findTargetPoint = find(); if (findTargetPoint !== undefined) break; } //calculate paths if (findTargetPoint) { //console.log('find target point:', findTargetPoint); // push end node. paths.push(data.nodes[endNearest]); // get end to start list. calculateParent(findTargetPoint); paths.reverse(); } return paths; } }