[add] first

This commit is contained in:
2023-02-22 09:50:51 +08:00
commit 6260e95bc8
9053 changed files with 4492644 additions and 0 deletions
@@ -0,0 +1,22 @@
import { _decorator, Component, Node, Camera, v3, Color, renderer, debug, director } from 'cc';
import { EDITOR } from 'cc/env';
const { ccclass, property, executeInEditMode } = _decorator;
@ccclass('navigation_debugger')
@executeInEditMode
export class navigation_debugger extends Component {
start() {
}
update(deltaTime: number) {
if(EDITOR) this.editorUpdate();
}
editorUpdate() {
const render = director.root?.pipeline.geometryRenderer;
render?.addLine(v3(0, 0, 0), v3(3, 0, 3), Color.GREEN, false);
}
}
@@ -0,0 +1,9 @@
{
"ver": "4.0.23",
"importer": "typescript",
"imported": true,
"uuid": "8cffe35b-a6bd-4658-8562-5cb4bdc27bc5",
"files": [],
"subMetas": {},
"userData": {}
}
@@ -0,0 +1,113 @@
import { _decorator, Component, Node, Renderer, Line, v3, Vec2, Vec3, Graphics, gfx, debug, geometry, randomRangeInt, path, IVec3Like, math } from 'cc';
import { EDITOR } from 'cc/env';
import { DataNavigationInst } from '../data/data-core';
const { ccclass, property, executeInEditMode } = _decorator;
@ccclass('NavigationMap')
@executeInEditMode
export class NavigationMap extends Component {
points:Vec3[] = [];
__preload() {
//Navigation.init(this.node);
}
update(deltaTime: number) {
if (EDITOR) {
//this.updateEditModel();
}
}
updateEditModel() {
console.log('navigation edit');
this.linkChildNode(this.node);
}
linkChildNode(root:Node) {
const children = root.children;
for(let i = 0; i < children.length - 1; i++) {
const p0 = children[i];
const p1 = children[i + 1];
const pos0 = p0.position;
const pos1 = p1.position;
//let line = new geometry.Line(pos0.x, pos0.y, pos0.z, pos1.x, pos1.y, pos1.z);
//const l0 = p0.getComponent(Line);
//l0.positions[0] = pos0 as never;
//l0.positions[1] = pos1 as never;
}
}
}
/*
export class Navigation {
public static node:Node;
public static init(_node:Node) {
this.node = _node;
}
static calculateRandomPoint(curPos:Vec3) {
// find closet point.
var closet:Node | undefined = this.findChildren(this.node, curPos);
if (closet === undefined) {
console.error('closet not find', curPos, this.node);
return [];
}
// random target node.
const target:Node = this.randomChildren();
// go target node.
let paths:Vec3[] = [];
paths.push(curPos);
paths.push(closet.worldPosition);
this.findTargetNode(paths, closet, target);
return paths;
}
static findChildren(node:Node, curPos:Vec3) {
let minDistance = Number.MAX_VALUE;
const children = node.children;
let minNode:Node | undefined = undefined;
for(let i = 0; i < children.length; i++) {
const child = children[i];
if (node === child) continue;
const distance = Vec3.distance(curPos, child.worldPosition);
if (distance < minDistance) {
minNode = child;
minDistance = distance;
}
}
return minNode;
}
static randomChildren() {
const randomIndex = randomRangeInt(0, this.node.children.length);
return this.node.children[randomIndex];
}
static findTargetNode(paths:Vec3[], node:Node, target:Node) {
const children = node.parent?.children ?? undefined;
if (children === undefined) return;
for(let i = 0; i < children.length; i++) {
paths.push(children[i].worldPosition);
if (children[i] === node) {
break;
}
}
}
}
*/
@@ -0,0 +1,9 @@
{
"ver": "4.0.23",
"importer": "typescript",
"imported": true,
"uuid": "79294abb-dae0-4b09-b446-95ea5027d0e0",
"files": [],
"subMetas": {},
"userData": {}
}
@@ -0,0 +1,73 @@
import { _decorator, Component, Node, debug, Camera, Vec3, v3, PhysicsSystem, geometry, IVec3Like, math, url, CCFloat } from 'cc';
import { EDITOR } from 'cc/env';
import { DebugUtil } from '../../core/util/debug-util';
import { Gizmo, UtilVec3 } from '../../core/util/util';
const { ccclass, property, executeInEditMode } = _decorator;
@ccclass('NavigationPoint')
@executeInEditMode
export class NavigationPoint extends Component {
@property([Node])
linkNodes: Node[] = [];
@property([CCFloat])
weights: number[] = [];
@property
radius = 5;
@property
showRay = false
@property
segment = 20;
_rays: Array<Vec3> | undefined
onEnable () {
// Calculate radius
if (EDITOR) {
const segment = this.segment;
const ray = new geometry.Ray();
let minDistance = 200;
this._rays = Array(segment);
//Ray test
for (let i = 0; i < segment; i++) {
const angle = 360 / segment * i;
let direction = v3(0, this.node.worldPosition.y, -1);
Vec3.rotateY(direction, direction, this.node.worldPosition, math.toRadian(angle));
ray.o = this.node.worldPosition;
ray.d = direction.subtract(this.node.worldPosition);
this._rays[i] = direction;
if (PhysicsSystem.instance.raycastClosest(ray, undefined, 100)) {
const result = PhysicsSystem.instance.raycastClosestResult;
const hitPoint = result.hitPoint;
const currentDistance = Vec3.distance(this.node.worldPosition, hitPoint);
if (currentDistance < minDistance) {
minDistance = currentDistance;
}
}
}
this.radius = Number(minDistance.toFixed(3));
}
}
update (deltaTime: number) {
if (EDITOR) {
for (let i = 0; i < this.linkNodes.length; i++) {
Gizmo.drawLine(this.node.worldPosition, this.linkNodes[i].worldPosition);
}
Gizmo.drawCircle(this.node.position, this.radius);
if (this.showRay) {
for (let i = 0; i < this._rays!.length; i++) {
let target = v3(0, 0, 0);
UtilVec3.copy(target, this._rays![i]);
Gizmo.drawLine(this.node.worldPosition, target.add(this.node.worldPosition));
}
}
}
}
}
@@ -0,0 +1,9 @@
{
"ver": "4.0.23",
"importer": "typescript",
"imported": true,
"uuid": "54e2e98f-6d5c-485e-95b1-28e4623badf5",
"files": [],
"subMetas": {},
"userData": {}
}
@@ -0,0 +1,14 @@
import { _decorator, Component, Node } from 'cc';
const { ccclass, property } = _decorator;
@ccclass('NavigationPoints')
export class navigation_points extends Component {
start() {
}
update(deltaTime: number) {
}
}
@@ -0,0 +1,9 @@
{
"ver": "4.0.23",
"importer": "typescript",
"imported": true,
"uuid": "8f3997de-73e7-49f7-a604-c2684a225478",
"files": [],
"subMetas": {},
"userData": {}
}
@@ -0,0 +1,196 @@
import { _decorator, Component, Node, v3, Color, geometry, Vec3, PhysicsSystem, math, JsonAsset, IVec3Like, Input, input, EventKeyboard, KeyCode, color, game } from 'cc';
import { EDITOR } from 'cc/env';
import { JsonTool } from '../../core/io/json-tool';
import { Gizmo, UtilVec3 } from '../../core/util/util';
import { NavigationPoint } from './navigation-point';
import { NavSystem } from './navigation-system';
const { ccclass, property, executeInEditMode } = _decorator;
@ccclass('NavigationRegion')
@executeInEditMode
export class NavigationRegion extends Component {
@property
maxDistance = 15;
@property
height = 0.5;
@property
maxHeight = 3;
@property
slopHeight = 1;
@property
slopDistance = 7;
@property
mapBlockX = 15;
@property
mapBlockY = 3;
@property
mapBlockZ = 15;
@property
testPath = false;
@property(Node)
testNode:Node | undefined;
findPaths = Array<NavSystem.NavPointType>();
onEnable() {
if(EDITOR) {
this.refreshMapPoints();
}
}
refreshMapPoints() {
const children = this.node.children;
let data = {
blockX: this.mapBlockX,
blockY: this.mapBlockY,
blockZ: this.mapBlockZ,
count:children.length,
nodeMap:{},
nodes:[],
links:[],
weights:[]
};
for(let i = 0; i < children.length; i++) {
const child = children[i];
child.name = `point_${i}`;
const navigationPoint = child.getComponent(NavigationPoint);
if(!navigationPoint) {
child.addComponent(NavigationPoint);
}
const worldPosition = child.worldPosition;
const pos = {
x:Number(worldPosition.x.toFixed(3)),
y:Number(worldPosition.y.toFixed(3)),
z:Number(worldPosition.z.toFixed(3)),
id:child.getSiblingIndex(),
radius:navigationPoint?.radius,
};
const keyX = Math.floor(pos.x / this.mapBlockX);
const keyY = Math.floor(pos.y / this.mapBlockY);
const keyZ = Math.floor(pos.z / this.mapBlockZ);
const key = `${keyX},${keyY},${keyZ}`;
if(data.nodeMap[key] === undefined) data.nodeMap[key] = [];
data.nodeMap[key].push(child.getSiblingIndex());
data.nodes.push(pos);
const linkInfo = this.calculateCircleLink(child);
data.links.push(linkInfo.links);
data.weights.push(linkInfo.weights);
}
console.log(JsonTool.toJson(data));
if(this.testPath) {
NavSystem.Init(data);
// Test Random paths.
//this.testRandomPath();
// Test Find paths.
const times = 10000;
let time = game.totalTime;
for(let i = 0; i < times; i++) {
this.testFindPath();
}
console.log('run ', times, ' time:', game.totalTime - time, ' ms');
}
}
calculateCircleLink(node:Node):{ links:number[], weights:number[]} {
const children = this.node.children;
const origin = node.worldPosition;
const ray = new geometry.Ray();
ray.o = node.worldPosition;
const position = v3(0, 0, 0);
let link:Node[] = [];
let weights:number[] = [];
let linkIndex:number[] = [];
for(let i = 0; i < children.length; i++) {
const child = children[i];
if (child === node) continue;
UtilVec3.copy(position, child.worldPosition);
ray.d = position.subtract(origin).normalize();
const distance = Vec3.distance(origin, child.worldPosition);
if (distance > this.maxDistance) continue;
const heightDifference = Math.abs(origin.y - child.worldPosition.y);
if (heightDifference > this.maxHeight) continue;
if (heightDifference > this.slopHeight && distance > this.slopDistance) continue;
if (!PhysicsSystem.instance.raycastClosest(ray, undefined, distance)){
link.push(child);
linkIndex.push(child.getSiblingIndex());
weights.push(Number(distance.toFixed(3)));
}
}
const navigationPoint = node.getComponent(NavigationPoint);
navigationPoint!.linkNodes = link;
navigationPoint!.weights = weights;
return { links:linkIndex, weights:weights }
}
update(deltaTime:number) {
if(EDITOR) {
this.testFindPaths();
}
}
testFindPaths() {
if(this.findPaths.length <= 0) return;
let p0 = v3(0, 0, 0);
let p1 = v3(0, 0, 0);
//Gizmo.drawBox(p0, v3(10, 1, 10), Color.YELLOW);
Gizmo.drawBox(this.findPaths[0] as IVec3Like, Vec3.ONE, Color.WHITE);
for (let i = 1; i < this.findPaths.length; i++) {
const start = this.findPaths![i - 1] as IVec3Like;
const end = this.findPaths![i] as IVec3Like;
UtilVec3.copy(p0, start);
UtilVec3.copy(p1, end);
p0.y += 0.1;
p1.y += 0.1;
const isLast = i === (this.findPaths.length - 1);
if(isLast) {
Gizmo.drawBox(p1, Vec3.ONE, Color.RED);
}else{
Gizmo.drawCircle(p1, 1, Color.RED);
}
Gizmo.drawLine(p0, p1, Color.RED);
}
}
testRandomPath() {
// random point.
const point = NavSystem.randomPoint();
this.testNode?.setWorldPosition(point.position);
NavSystem.randomPaths(this.findPaths, this.testNode!.worldPosition, 20, point.closestNavigationPon);
}
testFindPath() {
// random start.
const start = NavSystem.randomPoint();
// random end.
const end = NavSystem.randomPoint();
NavSystem.findPaths(this.findPaths, start.position, -1, end.position);
//console.log('find paths:', this.findPaths);
}
}
@@ -0,0 +1,9 @@
{
"ver": "4.0.23",
"importer": "typescript",
"imported": true,
"uuid": "5a2dc65c-594f-488a-bbbd-25cb17685ec5",
"files": [],
"subMetas": {},
"userData": {}
}
@@ -0,0 +1,345 @@
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<NavPointType>, 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<NavPointType>, 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<IVec3Like>, 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<NavPointType>, 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;
}
}
@@ -0,0 +1,9 @@
{
"ver": "4.0.23",
"importer": "typescript",
"imported": true,
"uuid": "6d9ee84f-460a-4d9e-96ac-0c5be5893ac2",
"files": [],
"subMetas": {},
"userData": {}
}