This commit is contained in:
2024-07-17 16:14:14 +08:00
commit 2ef3bcf322
1817 changed files with 63826 additions and 0 deletions

View File

@@ -0,0 +1,36 @@
/*
* @Author: dgflash
* @Date: 2022-02-12 11:02:21
* @LastEditors: dgflash
* @LastEditTime: 2022-08-04 15:20:55
*/
import { instantiate, Prefab } from "cc";
import { oops } from "../../../../extensions/oops-plugin-framework/assets/core/Oops";
import { ecs } from "../../../../extensions/oops-plugin-framework/assets/libs/ecs/ECS";
import { MapModelComp } from "./model/MapModelComp";
import { MapViewComp } from "./view/MapViewComp";
/** 游戏地图 */
@ecs.register(`GameMap`)
export class GameMap extends ecs.Entity {
MapModel!: MapModelComp;
MapView!: MapViewComp;
protected init(): void {
this.addComponents<ecs.Comp>(
MapModelComp);
}
/** 加载地图显示资源 */
load() {
oops.res.load(this.MapModel.resPrefab, Prefab, (err: Error | null, res: Prefab) => {
if (err) {
console.error(err);
}
var map = instantiate(res);
map.parent = oops.game.root;
this.add(map.getChildByName("map").getComponent(MapViewComp));
});
}
}

View File

@@ -0,0 +1,9 @@
{
"ver": "4.0.23",
"importer": "typescript",
"imported": true,
"uuid": "d15fc8d4-c897-4a5c-a97c-b65114b41a69",
"files": [],
"subMetas": {},
"userData": {}
}

View File

@@ -0,0 +1,12 @@
{
"ver": "1.2.0",
"importer": "directory",
"imported": true,
"uuid": "8c68118e-d594-4966-8748-7bbf4ee62ee1",
"files": [],
"subMetas": {},
"userData": {
"compressionType": {},
"isRemoteBundle": {}
}
}

View File

@@ -0,0 +1,42 @@
/*
* @Author: dgflash
* @Date: 2022-08-04 15:08:34
* @LastEditors: dgflash
* @LastEditTime: 2022-08-04 15:23:20
*/
import { ecs } from "../../../../../extensions/oops-plugin-framework/assets/libs/ecs/ECS";
@ecs.register('MapModel')
export class MapModelComp extends ecs.Comp {
/** 初始地图编号 */
id: number = 1;
/** 地图数据配置 */
resConfigMap: string = "config/map/map";
/** 地图转场点数据配置 */
resDeliveryMap: string = "config/map/map_delivery";
/** 地图显示预制 */
resPrefab: string = "game/map/map_rpg";
/** 地图内容资源 */
getResContentMiniMap(mapName: string): string {
return `content/map/${mapName}/${mapName}/miniMap/texture`;
};
/** 地图瓦片资源 */
getResContentSlices(bgName: string, key: string): string {
return `content/map/${bgName}/${bgName}/slices/${key}/texture`;
};
/** 地图数据资源 */
getResContentData(mapName: string): string {
return `content/map/${mapName}/${mapName}`;
};
reset() {
}
}

View File

@@ -0,0 +1,9 @@
{
"ver": "4.0.23",
"importer": "typescript",
"imported": true,
"uuid": "2f2380b0-3fa7-48ee-8e30-24e5d718f91e",
"files": [],
"subMetas": {},
"userData": {}
}

View File

@@ -0,0 +1,12 @@
{
"ver": "1.2.0",
"importer": "directory",
"imported": true,
"uuid": "22e4e848-ae40-4493-ba1f-bf4cd25ec4ed",
"files": [],
"subMetas": {},
"userData": {
"compressionType": {},
"isRemoteBundle": {}
}
}

View File

@@ -0,0 +1,71 @@
import { v3, Vec3, _decorator } from "cc";
import { ecs } from "../../../../../extensions/oops-plugin-framework/assets/libs/ecs/ECS";
import { CCComp } from "../../../../../extensions/oops-plugin-framework/assets/module/common/CCComp";
import { smc } from "../../common/SingletonModuleComp";
import { Role } from "../../role/Role";
// import MapRoadUtils from "./map/road/MapRoadUtils";
import { MapViewScene } from "./MapViewScene";
const { ccclass, property } = _decorator;
@ccclass('MapViewComp')
@ecs.register('MapView', false)
export class MapViewComp extends CCComp {
scene: MapViewScene = null!;
/** 是否正在转场 */
/** 当前地图数据 */
current_map: any;
/** 转场碰撞点对象集合 */
reset(): void {
}
start() {
this.scene = this.getComponent(MapViewScene);
this.addHero();
}
/** 转场 */
private mapLoaded() {
}
/** 添加玩家 */
private addHero(pos?: Vec3) {
if (pos == null) {
this.scene.node.active = true
smc.own = ecs.getEntity<Role>(Role);
smc.own.load(this.aStarToVec3("0,0"), true);
// smc.own.loadJoystick();
// 测试玩家
var test = ecs.getEntity<Role>(Role);
test.load(this.aStarToVec3("-300,0"), false);
var test2 = ecs.getEntity<Role>(Role);
test2.load(this.aStarToVec3("-300,300"), false);
}
else {
this.scene.setPlayer(pos);
}
}
private aStarToVec3(str: string) {
let array = str.split(",");
let x = parseInt(array[0]);
let y = parseInt(array[1]);
// let p = MapRoadUtils.instance.getPixelByDerect(x, y);
return v3(x, y);
}
}

View File

@@ -0,0 +1,9 @@
{
"ver": "4.0.23",
"importer": "typescript",
"imported": true,
"uuid": "b9f0df21-67f9-460a-8306-caf12042a78f",
"files": [],
"subMetas": {},
"userData": {}
}

View File

@@ -0,0 +1,94 @@
import { Camera, CCBoolean, Component, EventTouch, Node, screen, Size, Texture2D, UITransform, Vec2, Vec3, view, _decorator } from "cc";
import { oops } from "../../../../../extensions/oops-plugin-framework/assets/core/Oops";
import MapData from "./map/base/MapData";
import { MapLoadModel } from "./map/base/MapLoadModel";
import MapParams from "./map/base/MapParams";
import Charactor from "./map/charactor/Charactor";
import EntityLayer from "./map/layer/EntityLayer";
import MapLayer from "./map/layer/MapLayer";
import IRoadSeeker from "./map/road/IRoadSeeker";
import RoadNode from "./map/road/RoadNode";
const { ccclass, property } = _decorator;
/**
* 地图场景逻辑
* 1、地图摄像机跟随角色位置移动
*/
@ccclass('MapViewScene')
export class MapViewScene extends Component {
@property(Camera)
public camera: Camera | null = null;
@property(Node)
public layer: Node | null = null;
@property(MapLayer)
public mapLayer: MapLayer | null = null;
@property(Node)
public floorLayer: Node | null = null;
@property(EntityLayer)
public entityLayer: EntityLayer | null = null;
@property(CCBoolean)
public isFollowPlayer: boolean = true;
/** 2D转3D位置比例值 */
ratio: Vec2 = new Vec2();
private _roadDic: { [key: string]: RoadNode } = {};
private _roadSeeker!: IRoadSeeker;
private _mapParams: MapParams | null = null;
private player: Charactor | null = null; // 主角玩家
private targetPos: Vec3 = new Vec3(); // 摄像机位置
private winSize!: Size; // 屏幕尺寸
private screenCenter: Vec3 = new Vec3(); // 屏幕中心位置
private boundary: Vec2 = new Vec2(); // 边界位置
setPlayer(value: Charactor | Vec3) {
if (value instanceof Charactor) {
this.enabled = true;
this.player = value;
}
else {
this.player!.pos = value;
}
}
onLoad() {
this.enabled = false;
}
start() {
}
private reset() {
this.floorLayer!.removeAllChildren(); // 清除地面显示对象
this.entityLayer!.clear(); // 清除游戏实体对象
this.mapLayer!.clear(); // 清除地图瓦片显示对象
this._roadDic = {};
}
public init(mapData: MapData, bgTex: Texture2D, mapLoadModel: MapLoadModel = 1) {
}
update(dt: number) {
}
}

View File

@@ -0,0 +1,11 @@
{
"ver": "4.0.23",
"importer": "typescript",
"imported": true,
"uuid": "a31682ea-e44b-4122-b411-6761895ab6b0",
"files": [],
"subMetas": {},
"userData": {
"simulateGlobals": []
}
}

View File

@@ -0,0 +1,12 @@
{
"ver": "1.2.0",
"importer": "directory",
"imported": true,
"uuid": "316746b3-9791-4e17-a00c-f3a9be70e380",
"files": [],
"subMetas": {},
"userData": {
"compressionType": {},
"isRemoteBundle": {}
}
}

View File

@@ -0,0 +1,12 @@
{
"ver": "1.2.0",
"importer": "directory",
"imported": true,
"uuid": "b0f6dc85-a76e-4bdf-a11c-d1b518f80db5",
"files": [],
"subMetas": {},
"userData": {
"compressionType": {},
"isRemoteBundle": {}
}
}

View File

@@ -0,0 +1,16 @@
import { MapType } from "./MapType";
export default class MapData {
public name: string = "";
public bgName: string = "";
public type: MapType = MapType.angle45;
public mapWidth: number = 0;
public mapHeight: number = 0;
public nodeWidth: number = 0;
public nodeHeight: number = 0;
public roadDataArr: number[][] = [];
//public row:number = 0;
//public col:number = 0;
public mapItems: object[] = [];
}

View File

@@ -0,0 +1,11 @@
{
"ver": "4.0.23",
"importer": "typescript",
"imported": true,
"uuid": "a0091b9b-c39d-45b0-bcec-3f5a5c6258bf",
"files": [],
"subMetas": {},
"userData": {
"simulateGlobals": []
}
}

View File

@@ -0,0 +1,14 @@
/**
* 地图加载模式
*/
export enum MapLoadModel {
/**
* 单张地图加载
*/
single = 0,
/**
* 分切片加载
*/
slices = 1,
}

View File

@@ -0,0 +1,11 @@
{
"ver": "4.0.23",
"importer": "typescript",
"imported": true,
"uuid": "2f328b5a-8e30-4411-a6d1-997689a315a7",
"files": [],
"subMetas": {},
"userData": {
"simulateGlobals": []
}
}

View File

@@ -0,0 +1,74 @@
import { MapType } from "./MapType";
import { MapLoadModel } from "./MapLoadModel";
import { Texture2D } from "cc";
/**
* 地图参数
*/
export default class MapParams {
/**
* 地图名称
*/
public name: string = "";
/**
* 底图资源名称
*/
public bgName: string = "";
/**
* 地图类型
*/
public mapType: MapType = MapType.angle45;
/**
* 地图宽
*/
public mapWidth: number = 750;
/**
* 地图高
*/
public mapHeight: number = 1600;
/**
* 地图单元格宽
*/
public ceilWidth: number = 75;
/**
* 地图单元格高
*/
public ceilHeight: number = 75;
/**
* 地图视野宽
*/
public viewWidth: number = 750;
/**
* 地图视野高
*/
public viewHeight: number = 1334;
/**
* 地图切片宽
*/
public sliceWidth: number = 256;
/**
* 地图切片高
*/
public sliceHeight: number = 256;
/**
* 底图加载模式,是单张还是切片加载
*/
public mapLoadModel: MapLoadModel = MapLoadModel.single;
/**
* 地图底图
*/
public bgTex: Texture2D | null = null;
}

View File

@@ -0,0 +1,11 @@
{
"ver": "4.0.23",
"importer": "typescript",
"imported": true,
"uuid": "6b00edff-eb4a-4dcb-af47-ad707888c9b8",
"files": [],
"subMetas": {},
"userData": {
"simulateGlobals": []
}
}

View File

@@ -0,0 +1,6 @@
export enum MapType {
angle45 = 0,
angle90 = 1,
honeycomb = 2,
}

View File

@@ -0,0 +1,11 @@
{
"ver": "4.0.23",
"importer": "typescript",
"imported": true,
"uuid": "967a1a19-a1dd-4241-81d7-a92f041c19e9",
"files": [],
"subMetas": {},
"userData": {
"simulateGlobals": []
}
}

View File

@@ -0,0 +1,12 @@
{
"ver": "1.2.0",
"importer": "directory",
"imported": true,
"uuid": "f58752f0-7320-4a2f-b7a3-d4d59e42c1f6",
"files": [],
"subMetas": {},
"userData": {
"compressionType": {},
"isRemoteBundle": {}
}
}

View File

@@ -0,0 +1,146 @@
import { Component, game, Vec3, _decorator } from 'cc';
import { MapViewScene } from '../../MapViewScene';
import RoadNode from '../road/RoadNode';
import { RoadType } from '../road/RoadType';
import { ICharactorClip } from './ICharactorClip';
const { ccclass, property } = _decorator;
export enum CharactorState {
Idle = 0,
Run = 1
}
export enum CharactorDirection {
none = -1,
bottom = 0,
left_bottom = 1,
left = 2,
left_up = 3,
up = 4,
right_up = 5,
right = 6,
right_bottom = 7
}
/**
* 场景角色
*/
@ccclass('Charactor')
export default class Charactor extends Component {
/** 优化后的路点移动 */
static WalkRoadNode: string = "WalkRoadNode";
/** 移动到新的一个格子路点 */
static NextRoadNode: string = "NextRoadNode";
private _direction: CharactorDirection = CharactorDirection.bottom;
public get direction(): CharactorDirection {
return this._direction;
}
public set direction(value: CharactorDirection) {
this._direction = value;
// this.clip.setDirection(value);
}
private _state: CharactorState = 0;
public get state(): CharactorState {
return this._state;
}
public set state(value: CharactorState) {
this._state = value;
// this.clip.setState(value);
}
private _alpha: number = 1;
public get alpha(): number {
return this._alpha;
}
public set alpha(value: number) {
this._alpha = value;
// this.clip.setAlpha(value);
}
private _zIndex: number = 0;
/** 深度排序 */
public get zIndex(): number {
return this._zIndex;
}
private _pos!: Vec3;
/** 玩家地图上的位置 */
public get pos(): Vec3 {
return this._pos;
}
public set pos(value: Vec3) {
this._pos = value;
// this.clip.setPos(value);
}
public sceneMap: MapViewScene = null!;
public clip!: ICharactorClip;
public moving: boolean = false;
public joystic: boolean = false;
public joystic_dir: Vec3 = new Vec3();
public moveSpeed: number = 200;
/**
* 玩家当前所站在的地图节点
*/
private _currentNode!: RoadNode;
private _moveAngle: number = 0;
private _roadNodeArr: RoadNode[] = [];
private _nodeIndex: number = 0;
start() {
this.direction = CharactorDirection.bottom;
this.state = CharactorState.Idle;
}
update(dt: number) {
}
joystick(dir: Vec3) {
if (this.moving) {
this.moving = false;
this._roadNodeArr.splice(0, this._roadNodeArr.length);
}
if (dir.strictEquals(Vec3.ZERO)) {
this.joystic = false;
this.state = CharactorState.Idle;
}
else {
this.joystic = true;
this.state = CharactorState.Run;
}
this.joystic_dir.set(dir);
}
public updateZIndex() {
this._zIndex = this.sceneMap.mapLayer!.height - this._pos.y;
}
private walk() {
if (this._nodeIndex < this._roadNodeArr.length - 1) {
this._nodeIndex++;
// 移动一个路点事件
this.node.emit(Charactor.WalkRoadNode, this._roadNodeArr[this._nodeIndex]);
}
}
public move() {
this.joystic = false;
this.moving = true;
this.state = CharactorState.Run;
}
public stop() {
this.moving = false;
this.state = CharactorState.Idle;
}
}

View File

@@ -0,0 +1,11 @@
{
"ver": "4.0.23",
"importer": "typescript",
"imported": true,
"uuid": "cbc1684f-2e32-4088-a784-3c147c9b6f31",
"files": [],
"subMetas": {},
"userData": {
"simulateGlobals": []
}
}

View File

@@ -0,0 +1,10 @@
import { EventTouch, Vec3 } from "cc";
import { CharactorDirection, CharactorState } from "./Charactor";
export interface ICharactorClip {
setDirection(value: CharactorDirection): void;
setState(value: CharactorState): void;
setAlpha(value: number): void;
setPos(value: Vec3): void;
checkTouch(event: EventTouch): boolean;
}

View File

@@ -0,0 +1,9 @@
{
"ver": "4.0.23",
"importer": "typescript",
"imported": true,
"uuid": "977105e0-d01b-402a-b649-080e33733218",
"files": [],
"subMetas": {},
"userData": {}
}

View File

@@ -0,0 +1,230 @@
import { CCBoolean, CCFloat, CCInteger, Component, Rect, Size, Sprite, SpriteFrame, Texture2D, UITransform, Vec2, _decorator } from 'cc';
const { ccclass, property } = _decorator;
/**
* 动画播放器
* @author 落日故人 QQ 583051842
*
*/
@ccclass('MovieClip')
export default class MovieClip extends Component {
/** Sprite渲染器 */
protected m_sprite: Sprite | null = null;;
/** 动画计时间隔 每隔0.1s更新一帧 */
protected timer: number = 0.1;
/** 播放 时间 间隔 */
@property({ type: CCFloat })
public interval: number = 0.1;
/** 贴图文件名 */
@property({ type: Texture2D })
public texture: Texture2D | null = null;
/** 播放次数 */
@property({ type: CCInteger })
public playTimes: number = 0;
@property({ type: CCInteger })
public row: number = 4;
/** 图片切割成几列 */
@property({ type: CCInteger })
public col: number = 4;
@property({ type: CCInteger })
public rowIndex: number = 0;
@property(CCBoolean)
public isAll: boolean = false;
@property(CCBoolean)
public autoPlayOnLoad: boolean = true;
/** 播放完自动销毁 */
@property(CCBoolean)
public autoDestroy: boolean = false;
@property(CCFloat)
public begin: number = 0;
@property(CCFloat)
public end: number = 0;
/** 动画帧数 */
public totalFrame: number = 8;
/** 当前帧数 */
public currentFrame: number = 0;
/** 当前播放了第几次 */
private currentTimes: number = 0;
/** 影片是否在跑动中 */
public running: boolean = true;
//private _direction:number = 1;
private _playIndex: number = 0;
private _pieceWidth: number = 0;
private _pieceHeight: number = 0;
private _bitmapArr: SpriteFrame[][] = [];
onLoad() {
//this. m_clips = new SpriteFrame[this.row][this.col];
//Texture2D tex = Resources.Load<Texture2D>("Image/Avatar/" + m_sprite_name);
//this.begin = 0;
if (this.end == 0) {
this.end = this.col;
}
this.rowIndex = this.clamp(this.rowIndex, 0, this.row - 1);
this._pieceWidth = this.texture!.width / this.col;
this._pieceHeight = this.texture!.height / this.row;
this.m_sprite = this.getComponent(Sprite);
if (!this.m_sprite) {
this.m_sprite = this.addComponent(Sprite);
}
for (var i = 0; i < this.row; i++) {
this._bitmapArr[i] = [];
for (var j = 0; j < this.col; j++) {
var spriteFrame: SpriteFrame = new SpriteFrame();
spriteFrame.texture = this.texture!;
spriteFrame.rect = new Rect(j * this._pieceWidth, i * this._pieceHeight, this._pieceWidth, this._pieceHeight);
spriteFrame.rotated = false;
spriteFrame.offset = new Vec2(0, 0);
spriteFrame.originalSize = new Size(this._pieceWidth, this._pieceHeight);
this._bitmapArr[i][j] = spriteFrame;
}
}
this.m_sprite!.spriteFrame = this._bitmapArr[this.rowIndex][0];
this.m_sprite!.spriteFrame.width
var uiTransform = this.getComponent(UITransform);
if (uiTransform) {
uiTransform.width = this._pieceWidth;
uiTransform.height = this._pieceHeight;
}
this.timer = 0;
this.running = this.autoPlayOnLoad;
}
update(dt: number) {
if (!this.running)
return;
if (this.playTimes != 0 && this.currentTimes == this.playTimes) {
this.running = false;
return;
}
this.timer -= dt;
if (this.timer <= 0) {
this.timer = this.interval;
this.currentFrame = this.currentFrame % this.col;
this.playAction();
this.currentFrame++;
if (this.currentFrame == this.col) {
if (this.isAll) {
this.rowIndex++;
if (this.rowIndex == this.row) {
this.currentTimes++;
this.node.emit("completeTimes");
if (this.playTimes != 0 && this.currentTimes == this.playTimes) {
this.node.emit("complete");
if (this.autoDestroy) {
this.node.destroy();
}
}
}
this.rowIndex %= this.row;
}
else {
this.currentTimes++;
this.node.emit("completeTimes");
if (this.playTimes != 0 && this.currentTimes == this.playTimes) {
this.node.emit("complete");
if (this.autoDestroy) {
this.node.destroy();
}
}
}
}
}
}
private playAction() {
this.rowIndex = this.clamp(this.rowIndex, 0, this.row - 1);
this._playIndex = this._playIndex % (this.end - this.begin) + this.begin;
this.m_sprite!.spriteFrame = this._bitmapArr[this.rowIndex][this._playIndex];
//this.m_sprite.spriteFrame.setRect(this.rect);
this._playIndex++;
}
/** 播放影片 */
public play() {
this.running = true;
}
/** 停止播放影片 */
public stop() {
this.running = false;
}
/**
* 跳帧播放
* @param frame 帧
*/
public gotoAndPlay(frame: number) {
this.running = true;
this._playIndex = frame;
this._playIndex = this.clamp(this._playIndex, 0, this.col - 1);
}
/**
* 跳帧停止
* @param frame 帧
*/
public gotoAndStop(frame: number) {
this.running = false;
this._playIndex = frame;
this._playIndex = this.clamp(this._playIndex, 0, this.col - 1);
this.m_sprite!.spriteFrame = this._bitmapArr[this.rowIndex][this._playIndex];
}
public clamp(value: number, minLimit: number, maxLimit: number) {
if (value < minLimit) {
return minLimit;
}
if (value > maxLimit) {
return maxLimit;
}
return value;
}
}

View File

@@ -0,0 +1,11 @@
{
"ver": "4.0.23",
"importer": "typescript",
"imported": true,
"uuid": "cb924b7b-003d-4995-a223-f41612b1d87c",
"files": [],
"subMetas": {},
"userData": {
"simulateGlobals": []
}
}

View File

@@ -0,0 +1,12 @@
{
"ver": "1.2.0",
"importer": "directory",
"imported": true,
"uuid": "7c59804e-f894-4753-97cb-ffe0d43e52d6",
"files": [],
"subMetas": {},
"userData": {
"compressionType": {},
"isRemoteBundle": {}
}
}

View File

@@ -0,0 +1,39 @@
/*
* @Author: dgflash
* @Date: 2022-08-04 15:22:33
* @LastEditors: dgflash
* @LastEditTime: 2023-05-12 18:04:45
*/
import { Component, Node, _decorator } from 'cc';
import { Timer } from '../../../../../../../extensions/oops-plugin-framework/assets/core/common/timer/Timer';
import Charactor from '../charactor/Charactor';
const { ccclass, property } = _decorator;
/**
* 物体层
* 注:
* 1、这里的深度排序如果有性能问题可考虑修改为非每帧排序
* 2、如果全3D世界显示角色相关显示对象则不需要2D深度排序只引用2D地图上的位置信息
*/
@ccclass('EntityLayer')
export default class EntityLayer extends Component {
private timer: Timer = new Timer(0.2);
update(dt: number) {
if (this.timer.update(dt))
this.node.children.sort(this.zIndexSort);
}
private zIndexSort(a: Node, b: Node) {
let a_zIndex = a.getComponent(Charactor)!.zIndex;
let b_zIndex = b.getComponent(Charactor)!.zIndex;
return a_zIndex - b_zIndex;
}
public clear() {
this.node.children.forEach(n => {
});
}
}

View File

@@ -0,0 +1,11 @@
{
"ver": "4.0.23",
"importer": "typescript",
"imported": true,
"uuid": "6639aca8-e031-4a65-8094-d8e059cf26fe",
"files": [],
"subMetas": {},
"userData": {
"simulateGlobals": []
}
}

View File

@@ -0,0 +1,134 @@
import { Component, Layers, Node, Sprite, SpriteFrame, Texture2D, UITransform, Vec3, _decorator } from 'cc';
import { oops } from '../../../../../../../extensions/oops-plugin-framework/assets/core/Oops';
import { LayerUtil } from '../../../../../../../extensions/oops-plugin-framework/assets/core/utils/LayerUtil';
import { smc } from '../../../../common/SingletonModuleComp';
import { MapLoadModel } from '../base/MapLoadModel';
import MapParams from '../base/MapParams';
const { ccclass, property } = _decorator;
/**
* 地图层
* @author 落日故人 QQ 583051842
*
*/
@ccclass('MapLayer')
export default class MapLayer extends Component {
/** 切割小图片集 */
private _sliceImgDic: { [key: string]: Sprite | null } = {};
private _mapParams: MapParams | null = null;
@property(Sprite)
private bgImg: Sprite | null = null;
public init(mapParams: MapParams): void {
this._mapParams = mapParams;
if (!this.bgImg) {
var bgNode: Node = new Node();
this.node.addChild(bgNode);
bgNode.layer = Layers.Enum.UI_2D;
this.bgImg = bgNode.addComponent(Sprite);
this.bgImg.sizeMode = Sprite.SizeMode.RAW;
bgNode.getComponent(UITransform)!.anchorX = 0;
bgNode.getComponent(UITransform)!.anchorY = 0;
}
var spriteFrame: SpriteFrame = new SpriteFrame();
spriteFrame.texture = this._mapParams.bgTex!;
this.bgImg.spriteFrame = spriteFrame;
//如果是马赛克小地图,则需要把小地图缩放成原始地图一样大小
if (mapParams.mapLoadModel == MapLoadModel.slices) {
this.bgImg.getComponent(UITransform)!.width = mapParams.mapWidth;
this.bgImg.getComponent(UITransform)!.height = mapParams.mapHeight;
}
this.getComponent(UITransform)!.width = this.width;
this.getComponent(UITransform)!.height = this.height;
}
/**
* 根据视图区域加载小地图
* @param px 滚动视图左上角的x坐标
* @param py 滚动视图左上角的y坐标
*
*/
public loadSliceImage(px: number, py: number): void {
// var iy1: number = Math.floor(py / this._mapParams!.sliceHeight);
// var iy2: number = Math.floor((py + this._mapParams!.viewHeight) / this._mapParams!.sliceHeight);
// var jx1: number = Math.floor(px / this._mapParams!.sliceWidth);
// var jx2: number = Math.floor((px + this._mapParams!.viewWidth) / this._mapParams!.sliceWidth);
// var key: string;
// for (var i: number = iy1; i <= iy2; i++) {
// for (var j: number = jx1; j <= jx2; j++) {
// key = (i + 1) + "_" + (j + 1); // 图片的索引是从1开始的所以要加1
// if (!this._sliceImgDic[key]) {
// let bitmap: Sprite = this.getSliceSprite(key)
// this._sliceImgDic[key] = bitmap;
// this.node.addChild(bitmap.node);
// bitmap.node.position = new Vec3(j * this._mapParams!.sliceWidth, i * this._mapParams!.sliceHeight, 0)
// // var path: string = `maps/${this._mapParams!.bgName}/${this._mapParams!.bgName}/slices/${key}/texture`;
// // oops.res.load("remote", path, Texture2D, (error: Error | null, tex: Texture2D) => {
// var path: string = smc.map.MapModel.getResContentSlices(this._mapParams!.bgName, key);
// oops.res.load(path, Texture2D, (error: Error | null, tex: Texture2D) => {
// if (error) {
// console.error(error);
// }
// var spriteFrame: SpriteFrame = new SpriteFrame();
// spriteFrame.texture = tex;
// bitmap.spriteFrame = spriteFrame;
// });
// }
// }
// }
}
private getSliceSprite(name: string) {
var node: Node = new Node(name);
node.layer = LayerUtil.MAP.mask; // Layers.Enum.UI_2D;
var sprite: Sprite = node.addComponent(Sprite);
sprite.sizeMode = Sprite.SizeMode.RAW;
node.getComponent(UITransform)!.anchorX = 0;
node.getComponent(UITransform)!.anchorY = 0;
return sprite;
}
public clear(): void {
this.bgImg!.spriteFrame = null;
for (var key in this._sliceImgDic) {
var sprite: Sprite | null = this._sliceImgDic[key];
sprite && sprite.node.destroy();
this._sliceImgDic[key] = null;
delete this._sliceImgDic[key];
}
}
public get bgImage(): Sprite {
return this.bgImg!;
}
public get width(): number {
if (this.bgImg) {
return this.bgImg.getComponent(UITransform)!.width;
}
return this._mapParams!.viewWidth;
}
public get height(): number {
if (this.bgImg) {
return this.bgImg.getComponent(UITransform)!.height;
}
return this._mapParams!.viewHeight;
}
}

View File

@@ -0,0 +1,11 @@
{
"ver": "4.0.23",
"importer": "typescript",
"imported": true,
"uuid": "753fb70a-638e-44d4-b736-f8696df44858",
"files": [],
"subMetas": {},
"userData": {
"simulateGlobals": []
}
}

View File

@@ -0,0 +1,12 @@
{
"ver": "1.2.0",
"importer": "directory",
"imported": true,
"uuid": "76609af6-ff56-411b-a2e5-b6a6027fb037",
"files": [],
"subMetas": {},
"userData": {
"compressionType": {},
"isRemoteBundle": {}
}
}

View File

@@ -0,0 +1,613 @@
import RoadNode from "./RoadNode";
import IRoadSeeker from "./IRoadSeeker";
import BinaryTreeNode from "./BinaryTreeNode";
/**
* A*寻路算法
* @author 落日故人 QQ 583051842
*
*/
export default class AStarRoadSeeker implements IRoadSeeker {
/**
* 横向移动一个格子的代价
*/
private COST_STRAIGHT: number = 10;
/**
* 斜向移动一个格子的代价
*/
private COST_DIAGONAL: number = 14;
/**
* 最大搜寻步骤数,超过这个值时表示找不到目标
*/
private maxStep: number = 15000;
/**
* 开启列表
*/
private _openlist: Array<RoadNode>;
/**
*关闭列表
*/
private _closelist: Array<RoadNode>;
/**
* 二叉堆存储结构
*/
private _binaryTreeNode: BinaryTreeNode = new BinaryTreeNode();
/**
*开始节点
*/
private _startNode: RoadNode;
/**
*当前检索节点
*/
private _currentNode: RoadNode;
/**
*目标节点
*/
private _targetNode: RoadNode;
/**
*地图路点数据
*/
private _roadNodes: { [key: number]: RoadNode };
/**
*用于检索一个节点周围8个点的向量数组
*/
private _round: number[][] = [[0, -1], [1, -1], [1, 0], [1, 1], [0, 1], [-1, 1], [-1, 0], [-1, -1]]
private handle: number = -1;
/**
* 是否优化路径
*/
private optimize: boolean = true;
public constructor(roadNodes: { [key: string]: RoadNode }) {
this._roadNodes = roadNodes;
}
/**
*寻路入口方法
* @param startNode
* @param targetNode
* @return
*
*/
public seekPath(startNode: RoadNode, targetNode: RoadNode): Array<RoadNode> {
this._startNode = startNode;
this._currentNode = startNode;
this._targetNode = targetNode;
if (!this._startNode || !this._targetNode)
return [];
if (this._targetNode.value == 1) {
console.log("目标不可达到:");
return [];
}
this._startNode.g = 0; //重置起始节点的g值
this._startNode.resetTree(); //清除起始节点原有的二叉堆关联关系
this._binaryTreeNode.refleshTag(); //刷新二叉堆tag用于后面判断是不是属于当前次的寻路
//this._binaryTreeNode.addTreeNode(this._startNode); //把起始节点设置为二叉堆结构的根节点
var step: number = 0;
while (true) {
if (step > this.maxStep) {
// console.log("没找到目标计算步骤为:", step);
return [];
}
step++;
this.searchRoundNodes(this._currentNode);
if (this._binaryTreeNode.isTreeNull()) //二叉堆树里已经没有任何可搜寻的点了,则寻路结束,每找到目标
{
// console.log("没找到目标计算步骤为:", step);
return [];
}
this._currentNode = this._binaryTreeNode.getMin_F_Node();
if (this._currentNode == this._targetNode) {
// console.log("找到目标计算步骤为:", step);
return this.getPath();
}
else {
this._binaryTreeNode.setRoadNodeInCloseList(this._currentNode);//打入关闭列表标记
}
}
return [];
}
/**
*寻路入口方法 如果没有寻到目标,则返回离目标最近的路径
* @param startNode
* @param targetNode
* @return
*
*/
public seekPath2(startNode: RoadNode, targetNode: RoadNode): Array<RoadNode> {
this._startNode = startNode;
this._currentNode = startNode;
this._targetNode = targetNode;
if (!this._startNode || !this._targetNode)
return [];
var newMaxStep: number = this.maxStep;
if (!this.isPassNode(this._targetNode)) {
//如果不能直达目标,最大寻路步骤 = 为两点间的预估距离的2倍
newMaxStep = (Math.abs(this._targetNode.cx - this._startNode.cx) + Math.abs(this._targetNode.cy - this._startNode.cy)) * 2;
if (newMaxStep > this.maxStep) {
newMaxStep = this.maxStep;
}
}
this._startNode.g = 0; //重置起始节点的g值
this._startNode.resetTree(); //清除起始节点原有的二叉堆关联关系
this._binaryTreeNode.refleshTag(); //刷新二叉堆tag用于后面判断是不是属于当前次的寻路
//this._binaryTreeNode.addTreeNode(this._startNode); //把起始节点设置为二叉堆结构的根节点
var step: number = 0;
var closestNode: RoadNode = null; //距离目标最近的路点
while (true) {
if (step > newMaxStep) {
// console.log("没找到目标计算步骤为:", step);
return this.seekPath(startNode, closestNode);
}
step++;
this.searchRoundNodes(this._currentNode);
if (this._binaryTreeNode.isTreeNull()) //二叉堆树里已经没有任何可搜寻的点了,则寻路结束,没找到目标
{
// console.log("没找到目标计算步骤为:", step);
return this.seekPath(startNode, closestNode);
}
this._currentNode = this._binaryTreeNode.getMin_F_Node();
if (closestNode == null) {
closestNode = this._currentNode;
}
else {
if (this._currentNode.h < closestNode.h) {
closestNode = this._currentNode;
}
}
if (this._currentNode == this._targetNode) {
// console.log("找到目标计算步骤为:", step);
return this.getPath();
}
else {
this._binaryTreeNode.setRoadNodeInCloseList(this._currentNode);//打入关闭列表标记
}
}
return this.seekPath(startNode, closestNode);
}
/**
* 对路节点进行排序
* @param node1
* @param node2
*/
private sortNode(node1: RoadNode, node2: RoadNode) {
if (node1.f < node2.f) {
return -1;
}
else if (node1.f > node2.f) {
return 1;
}
return 0;
}
/**
* 获得最终寻路到的所有路点
* @return
*
*/
private getPath(): Array<RoadNode> {
var nodeArr: Array<RoadNode> = [];
var node: RoadNode = this._targetNode;
while (node != this._startNode) {
nodeArr.unshift(node);
node = node.parent;
}
nodeArr.unshift(this._startNode);
if (!this.optimize) {
return nodeArr;
}
//第一阶段优化: 对横,竖,正斜进行优化
//把多个节点连在一起的,横向或者斜向的一连串点,除两边的点保留
for (var i: number = 1; i < nodeArr.length - 1; i++) {
var preNode: RoadNode = nodeArr[i - 1] as RoadNode;
var midNode: RoadNode = nodeArr[i] as RoadNode;
var nextNode: RoadNode = nodeArr[i + 1] as RoadNode;
var bool1: Boolean = midNode.cx == preNode.cx && midNode.cx == nextNode.cx;
var bool2: Boolean = midNode.cy == preNode.cy && midNode.cy == nextNode.cy;
var bool3: Boolean = ((midNode.cx - preNode.cx) / (midNode.cy - preNode.cy)) * ((nextNode.cx - midNode.cx) / (nextNode.cy - midNode.cy)) == 1
if (bool1 || bool2 || bool3) {
nodeArr.splice(i, 1)
i--;
}
}
//return nodeArr;
//第二阶段优化:对不在横,竖,正斜的格子进行优化
for (var i: number = 0; i < nodeArr.length - 2; i++) {
var startNode: RoadNode = nodeArr[i] as RoadNode;
var optimizeNode: RoadNode = null;
//优先从尾部对比,如果能直达就把中间多余的路点删掉
for (var j: number = nodeArr.length - 1; j > i + 1; j--) {
var targetNode: RoadNode = nodeArr[j] as RoadNode;
//在第一阶段优已经优化过横,竖,正斜了,所以再出现是肯定不能优化的,可以忽略
if (startNode.cx == targetNode.cx || startNode.cy == targetNode.cy || Math.abs(targetNode.cx - startNode.cx) == Math.abs(targetNode.cy - startNode.cy)) {
continue;
}
if (this.isArriveBetweenTwoNodes(startNode, targetNode)) {
optimizeNode = targetNode;
break;
}
}
if (optimizeNode) {
var optimizeLen: number = j - i - 1;
nodeArr.splice(i + 1, optimizeLen);
}
}
return nodeArr;
}
/**
* 两点之间是否可到达
*/
private isArriveBetweenTwoNodes(startNode: RoadNode, targetNode: RoadNode): boolean {
if (startNode == targetNode) {
return false;
}
var disX: number = Math.abs(targetNode.cx - startNode.cx);
var disY: number = Math.abs(targetNode.cy - startNode.cy);
var dirX = 0;
if (targetNode.cx > startNode.cx) {
dirX = 1;
}
else if (targetNode.cx < startNode.cx) {
dirX = -1;
}
var dirY = 0;
if (targetNode.cy > startNode.cy) {
dirY = 1;
}
else if (targetNode.cy < startNode.cy) {
dirY = -1;
}
var rx: number = 0;
var ry: number = 0;
var intNum: number = 0;
var decimal: number = 0;
if (disX > disY) {
var rate: number = disY / disX;
for (var i = 0; i < disX; i++) {
ry = startNode.cy + i * dirY * rate;
intNum = Math.floor(ry);
decimal = ry % 1;
var cx1: number = startNode.cx + i * dirX;
var cy1: number = decimal <= 0.5 ? intNum : intNum + 1;
ry = startNode.cy + (i + 1) * dirY * rate;
intNum = Math.floor(ry);
decimal = ry % 1;
var cx2: number = startNode.cx + (i + 1) * dirX;
var cy2: number = decimal <= 0.5 ? intNum : intNum + 1;
var node1: RoadNode = this._roadNodes[cx1 + "_" + cy1] as RoadNode;
var node2: RoadNode = this._roadNodes[cx2 + "_" + cy2] as RoadNode;
//cc.log(i + " :: " + node1.cy," yy ",startNode.cy + i * rate,ry % 1);
if (!this.isCrossAtAdjacentNodes(node1, node2)) {
return false;
}
}
} else {
var rate: number = disX / disY;
for (var i = 0; i < disY; i++) {
rx = i * dirX * rate;
intNum = dirX > 0 ? Math.floor(startNode.cx + rx) : Math.ceil(startNode.cx + rx);
decimal = Math.abs(rx % 1);
var cx1: number = decimal <= 0.5 ? intNum : intNum + 1 * dirX;
var cy1: number = startNode.cy + i * dirY;
rx = (i + 1) * dirX * rate;
intNum = dirX > 0 ? Math.floor(startNode.cx + rx) : Math.ceil(startNode.cx + rx);
decimal = Math.abs(rx % 1);
var cx2: number = decimal <= 0.5 ? intNum : intNum + 1 * dirX;
var cy2: number = startNode.cy + (i + 1) * dirY;
var node1: RoadNode = this._roadNodes[cx1 + "_" + cy1] as RoadNode;
var node2: RoadNode = this._roadNodes[cx2 + "_" + cy2] as RoadNode;
if (!this.isCrossAtAdjacentNodes(node1, node2)) {
return false;
}
}
}
return true;
}
/**
* 判断两个相邻的点是否可通过
* @param node1
* @param node2
*/
private isCrossAtAdjacentNodes(node1: RoadNode, node2: RoadNode): boolean {
if (node1 == node2) {
return false;
}
//两个点只要有一个点不能通过就不能通过
if (!this.isPassNode(node1) || !this.isPassNode(node2)) {
return false;
}
var dirX = node2.cx - node1.cx;
var dirY = node2.cy - node1.cy
//如果不是相邻的两个点 则不能通过
if (Math.abs(dirX) > 1 || Math.abs(dirY) > 1) {
return false;
}
//如果相邻的点是在同一行,或者同一列,则判定为可通过
if ((node1.cx == node2.cx) || (node1.cy == node2.cy)) {
return true;
}
//只剩对角情况了
if (
this.isPassNode(this._roadNodes[node1.cx + "_" + (node1.cy + dirY)]) &&
this.isPassNode(this._roadNodes[(node1.cx + dirX) + "_" + node1.cy])
) {
return true;
}
return false;
}
/**
* 是否是可通过的点
* @param node
*/
private isPassNode(node: RoadNode): boolean {
if (!node || node.value == 1) {
return false;
}
return true;
}
/**
*测试寻路步骤
* @param startNode
* @param targetNode
* @return
*
*/
public testSeekPathStep(startNode: RoadNode, targetNode: RoadNode, callback: Function, target: any, time: number = 100): void {
this._startNode = startNode;
this._currentNode = startNode;
this._targetNode = targetNode;
if (this._targetNode.value == 1)
return;
this._startNode.g = 0; //重置起始节点的g值
this._startNode.resetTree(); //清除起始节点原有的二叉堆关联关系
this._binaryTreeNode.refleshTag(); //刷新二叉堆tag用于后面判断是不是属于当前次的寻路
//this._binaryTreeNode.addTreeNode(this._startNode); //把起始节点设置为二叉堆结构的根节点
this._closelist = [];
var step: number = 0;
clearInterval(this.handle);
this.handle = setInterval(() => {
if (step > this.maxStep) {
// console.log("没找到目标计算步骤为:", step);
clearInterval(this.handle);
return;
}
step++;
this.searchRoundNodes(this._currentNode);
if (this._binaryTreeNode.isTreeNull()) //二叉堆树里已经没有任何可搜寻的点了,则寻路结束,每找到目标
{
// console.log("没找到目标计算步骤为:", step);
clearInterval(this.handle);
return;
}
this._currentNode = this._binaryTreeNode.getMin_F_Node();
if (this._currentNode == this._targetNode) {
// console.log("找到目标计算步骤为:", step);
clearInterval(this.handle);
this._openlist = this._binaryTreeNode.getOpenList();
callback.apply(target, [this._startNode, this._targetNode, this._currentNode, this._openlist, this._closelist, this.getPath()]);
}
else {
this._binaryTreeNode.setRoadNodeInCloseList(this._currentNode);//打入关闭列表标记
this._openlist = this._binaryTreeNode.getOpenList();
this._closelist.push(this._currentNode);
callback.apply(target, [this._startNode, this._targetNode, this._currentNode, this._openlist, this._closelist, null]);
}
}, time);
}
/**
*查找一个节点周围可通过的点
* @param node
* @return
*
*/
private searchRoundNodes(node: RoadNode): void {
for (var i: number = 0; i < this._round.length; i++) {
var cx: number = node.cx + this._round[i][0];
var cy: number = node.cy + this._round[i][1];
var node2: RoadNode = this._roadNodes[cx + "_" + cy] as RoadNode
if (node2 != null && node2 != this._startNode && node2.value != 1 && !this.isInCloseList(node2) && !this.inInCorner(node2)) {
this.setNodeF(node2);
}
}
}
/**
*设置节点的F值
* @param node
*
*/
public setNodeF(node: RoadNode): void {
var g: number;
if (node.cx == this._currentNode.cx || node.cy == this._currentNode.cy) {
g = this._currentNode.g + this.COST_STRAIGHT;
}
else {
g = this._currentNode.g + this.COST_DIAGONAL;
}
if (this.isInOpenList(node)) {
if (g < node.g) {
node.g = g;
node.parent = this._currentNode;
node.h = (Math.abs(this._targetNode.cx - node.cx) + Math.abs(this._targetNode.cy - node.cy)) * this.COST_STRAIGHT;
node.f = node.g + node.h;
//节点的g值已经改变把节点先从二堆叉树结构中删除再重新添加进二堆叉树
this._binaryTreeNode.removeTreeNode(node);
this._binaryTreeNode.addTreeNode(node);
}
}
else {
node.g = g;
this._binaryTreeNode.setRoadNodeInOpenList(node);//给节点打入开放列表的标志
node.resetTree();
node.parent = this._currentNode;
node.h = (Math.abs(this._targetNode.cx - node.cx) + Math.abs(this._targetNode.cy - node.cy)) * this.COST_STRAIGHT;
node.f = node.g + node.h;
this._binaryTreeNode.addTreeNode(node);
}
}
/**
*节点是否在开启列表
* @param node
* @return
*/
private isInOpenList(node: RoadNode): Boolean {
return this._binaryTreeNode.isInOpenList(node);
}
/**
* 节点是否在关闭列表
* @param node
* @returns
*/
private isInCloseList(node: RoadNode): Boolean {
return this._binaryTreeNode.isInCloseList(node);
}
/**
*节点是否在拐角处
* @return
*
*/
private inInCorner(node: RoadNode): Boolean {
if (node.cx == this._currentNode.cx || node.cy == this._currentNode.cy) {
return false;
}
var node1: RoadNode = this._roadNodes[this._currentNode.cx + "_" + node.cy] as RoadNode;
var node2: RoadNode = this._roadNodes[node.cx + "_" + this._currentNode.cy] as RoadNode;
if (this.isPassNode(node1) && this.isPassNode(node2)) {
return false;
}
return true;
}
public dispose(): void {
this._roadNodes = null;
this._round = null;
}
}

View File

@@ -0,0 +1,11 @@
{
"ver": "4.0.23",
"importer": "typescript",
"imported": true,
"uuid": "a3a19dc4-7645-485a-80e0-b49fdb062b00",
"files": [],
"subMetas": {},
"userData": {
"simulateGlobals": []
}
}

View File

@@ -0,0 +1,836 @@
import BinaryTreeNode from "./BinaryTreeNode";
import IRoadSeeker from "./IRoadSeeker";
import RoadNode from "./RoadNode";
/**
* 六边形 A*寻路算法
* @author 落日故人 QQ 583051842
*
*/
export default class AstarHoneycombRoadSeeker implements IRoadSeeker {
/**
* 横向移动一个格子的代价
*/
private COST_STRAIGHT: number = 10;
/**
* 斜向移动一个格子的代价
*/
private COST_DIAGONAL: number = 10;
/**
* 最大搜寻步骤数,超过这个值时表示找不到目标
*/
private maxStep: number = 15000;
/**
* 开启列表
*/
private _openlist: Array<RoadNode>;
/**
*关闭列表
*/
private _closelist: Array<RoadNode>;
/**
* 二叉堆存储结构
*/
private _binaryTreeNode: BinaryTreeNode = new BinaryTreeNode();
/**
*开始节点
*/
private _startNode: RoadNode;
/**
*当前检索节点
*/
private _currentNode: RoadNode;
/**
*目标节点
*/
private _targetNode: RoadNode;
/**
*地图路点数据
*/
private _roadNodes: { [key: number]: RoadNode };
/**
*用于检索一个节点周围6个点的向量数组 格子列数为偶数时使用
*/
private _round1: number[][] = [[0, -1], [1, -1], [1, 0], [0, 1], [-1, 0], [-1, -1]];
/**
*用于检索一个节点周围6个点的向量数组 格子列数为奇数时使用
*/
private _round2: number[][] = [[0, -1], [1, 0], [1, 1], [0, 1], [-1, 1], [-1, 0]];
private handle: number = -1;
/**
* 是否优化路径
*/
private optimize: boolean = true;
public constructor(roadNodes: { [key: string]: RoadNode }) {
this._roadNodes = roadNodes;
}
/**
*寻路入口方法
* @param startNode
* @param targetNode
* @return
*
*/
public seekPath(startNode: RoadNode, targetNode: RoadNode): Array<RoadNode> {
this._startNode = startNode;
this._currentNode = startNode;
this._targetNode = targetNode;
if (!this._startNode || !this._targetNode)
return [];
if (this._targetNode.value == 1) {
console.log("目标不可达到:");
return [];
}
this._startNode.g = 0; //重置起始节点的g值
this._startNode.resetTree(); //清除起始节点原有的二叉堆关联关系
this._binaryTreeNode.refleshTag(); //刷新二叉堆tag用于后面判断是不是属于当前次的寻路
//this._binaryTreeNode.addTreeNode(this._startNode); //把起始节点设置为二叉堆结构的根节点
var step: number = 0;
while (true) {
if (step > this.maxStep) {
console.log("没找到目标计算步骤为:", step);
return [];
}
step++;
this.searchRoundNodes(this._currentNode);
if (this._binaryTreeNode.isTreeNull()) //二叉堆树里已经没有任何可搜寻的点了,则寻路结束,每找到目标
{
console.log("没找到目标计算步骤为:", step);
return [];
}
this._currentNode = this._binaryTreeNode.getMin_F_Node();
if (this._currentNode == this._targetNode) {
console.log("找到目标计算步骤为:", step);
return this.getPath();
}
else {
this._binaryTreeNode.setRoadNodeInCloseList(this._currentNode);//打入关闭列表标记
}
}
return [];
}
/**
*寻路入口方法 如果没有寻到目标,则返回离目标最近的路径
* @param startNode
* @param targetNode
* @return
*
*/
public seekPath2(startNode: RoadNode, targetNode: RoadNode): Array<RoadNode> {
this._startNode = startNode;
this._currentNode = startNode;
this._targetNode = targetNode;
if (!this._startNode || !this._targetNode)
return [];
var newMaxStep: number = this.maxStep;
if (!this.isPassNode(this._targetNode)) {
//如果不能直达目标,最大寻路步骤 = 为两点间的预估距离的2倍
newMaxStep = (Math.abs(this._targetNode.cx - this._startNode.cx) + Math.abs(this._targetNode.cy - this._startNode.cy)) * 2;
if (newMaxStep > this.maxStep) {
newMaxStep = this.maxStep;
}
}
this._startNode.g = 0; //重置起始节点的g值
this._startNode.resetTree(); //清除起始节点原有的二叉堆关联关系
this._binaryTreeNode.refleshTag(); //刷新二叉堆tag用于后面判断是不是属于当前次的寻路
//this._binaryTreeNode.addTreeNode(this._startNode); //把起始节点设置为二叉堆结构的根节点
var step: number = 0;
var closestNode: RoadNode = null; //距离目标最近的路点
while (true) {
if (step > newMaxStep) {
console.log("没找到目标计算步骤为:", step);
return this.seekPath(startNode, closestNode);
}
step++;
this.searchRoundNodes(this._currentNode);
if (this._binaryTreeNode.isTreeNull()) { //二叉堆树里已经没有任何可搜寻的点了,则寻路结束,没找到目标
console.log("没找到目标计算步骤为:", step);
return this.seekPath(startNode, closestNode);
}
this._currentNode = this._binaryTreeNode.getMin_F_Node();
if (closestNode == null) {
closestNode = this._currentNode;
}
else {
if (this._currentNode.h < closestNode.h) {
closestNode = this._currentNode;
}
}
if (this._currentNode == this._targetNode) {
console.log("找到目标计算步骤为:", step);
return this.getPath();
}
else {
this._binaryTreeNode.setRoadNodeInCloseList(this._currentNode);//打入关闭列表标记
}
}
return this.seekPath(startNode, closestNode);
}
/**
* 对路节点进行排序
* @param node1
* @param node2
*/
private sortNode(node1: RoadNode, node2: RoadNode) {
if (node1.f < node2.f) {
return -1;
}
else if (node1.f > node2.f) {
return 1;
}
return 0;
}
/*private getPath():Array<RoadNode>
{
var nodeArr:Array<RoadNode> = [];
var node:RoadNode = this._targetNode;
while(node != this._startNode)
{
nodeArr.unshift(node);
node = node.parent;
}
nodeArr.unshift(this._startNode);
if(!this.optimize)
{
return nodeArr;
}
//把多个节点连在一起的,横向或者斜向的一连串点,除两边的点保留
var preNode:RoadNode;
var midNode:RoadNode;
var nextNode:RoadNode;
for(var i:number = 1 ; i < nodeArr.length - 1 ; i++)
{
preNode = nodeArr[i - 1] as RoadNode;
midNode = nodeArr[i] as RoadNode;
nextNode = nodeArr[i + 1] as RoadNode;
var bool:Boolean = false;
var otherNode:RoadNode = null;
if(Math.abs(nextNode.cx - preNode.cx) == 2 && preNode.cy == nextNode.cy)
{
if(midNode.cx % 2 == 0)
{
if(midNode.cy == preNode.cy)
{
otherNode = this._roadNodes[midNode.cx + "_" + (midNode.cy + 1)] as RoadNode
}else
{
otherNode = this._roadNodes[midNode.cx + "_" + (midNode.cy - 1)] as RoadNode
}
}else
{
if(midNode.cy == preNode.cy)
{
otherNode = this._roadNodes[midNode.cx + "_" + (midNode.cy - 1)] as RoadNode
}else
{
otherNode = this._roadNodes[midNode.cx + "_" + (midNode.cy + 1)] as RoadNode
}
}
}
if(otherNode)
bool = otherNode.value != 1 ? true : false;
if(bool)
{
nodeArr.splice(i,1)
i--;
}
}
for(i = 1 ; i < nodeArr.length - 1 ; i++)
{
preNode = nodeArr[i - 1] as RoadNode;
midNode = nodeArr[i] as RoadNode;
nextNode = nodeArr[i + 1] as RoadNode;
var bool1:Boolean = midNode.cx == preNode.cx && midNode.cx == nextNode.cx;
var bool2:Boolean = (midNode.cy == preNode.cy && midNode.cy == nextNode.cy) && ((preNode.cx % 2 == midNode.cx % 2 && midNode.cx % 2 == nextNode.cx % 2) );
var bool3:Boolean = preNode.cy - Math.floor(preNode.cx / 2) == midNode.cy - Math.floor(midNode.cx / 2) && midNode.cy - Math.floor(midNode.cx / 2) == nextNode.cy - Math.floor(nextNode.cx / 2);
var bool4:Boolean = preNode.cy + Math.ceil(preNode.cx / 2) == midNode.cy + Math.ceil(midNode.cx / 2) && midNode.cy + Math.ceil(midNode.cx / 2) == nextNode.cy + Math.ceil(nextNode.cx / 2);
if(bool1 || bool2 || bool3 || bool4)
{
nodeArr.splice(i,1)
i--;
}
}
return nodeArr
}*/
/**
*获得最终寻路到的所有路点
* @return
*
*/
private getPath(): Array<RoadNode> {
var nodeArr: Array<RoadNode> = [];
var node: RoadNode = this._targetNode;
while (node != this._startNode) {
nodeArr.unshift(node);
node = node.parent;
}
nodeArr.unshift(this._startNode);
if (!this.optimize) {
return nodeArr;
}
//把多个节点连在一起的,横向或者斜向的一连串点,除两边的点保留
var preNode: RoadNode;
var midNode: RoadNode;
var nextNode: RoadNode;
var preHpos: HoneyPoint;
var midHpos: HoneyPoint;
var nextHpos: HoneyPoint;
//var hround:number[][] = [[-1,-1],[-1,0],[0,1],[1,1],[1,0],[0,-1]];
//var hround2:number[][] = [[-2,-1],[-1,1],[1,2],[2,1],[1,-1],[-1,-2]];
//第一阶段优化: 对横,竖,正斜进行优化
for (i = 1; i < nodeArr.length - 1; i++) {
preNode = nodeArr[i - 1] as RoadNode;
midNode = nodeArr[i] as RoadNode;
nextNode = nodeArr[i + 1] as RoadNode;
preHpos = this.getHoneyPoint(preNode);
midHpos = this.getHoneyPoint(midNode);
nextHpos = this.getHoneyPoint(nextNode);
var bool1: Boolean = midNode.cx == preNode.cx && midNode.cx == nextNode.cx;
var bool2: Boolean = (midNode.cy == preNode.cy && midNode.cy == nextNode.cy) && ((preNode.cx % 2 == midNode.cx % 2 && midNode.cx % 2 == nextNode.cx % 2));
var bool3: Boolean = preHpos.hx == midHpos.hx && midHpos.hx == nextHpos.hx;
var bool4: Boolean = preHpos.hy == midHpos.hy && midHpos.hy == nextHpos.hy;
if (bool1 || bool2 || bool3 || bool4) {
nodeArr.splice(i, 1)
i--;
}
}
//第二阶段优化:对不在横,竖,正斜的格子进行优化
for (var i: number = 0; i < nodeArr.length - 2; i++) {
var startNode: RoadNode = nodeArr[i] as RoadNode;
var optimizeNode: RoadNode = null;
//优先从尾部对比,如果能直达就把中间多余的路点删掉
for (var j: number = nodeArr.length - 1; j > i + 1; j--) {
var targetNode: RoadNode = nodeArr[j] as RoadNode;
if (this.isArriveBetweenTwoNodes(this.getHoneyPoint(startNode), this.getHoneyPoint(targetNode))) {
optimizeNode = targetNode;
break;
}
}
if (optimizeNode) {
var optimizeLen: number = j - i - 1;
nodeArr.splice(i + 1, optimizeLen);
}
}
return nodeArr
}
/**
* 两点之间是否可到达
*/
private isArriveBetweenTwoNodes(startPoint: HoneyPoint, targetPoint: HoneyPoint): boolean {
if (startPoint.hx == targetPoint.hx && startPoint.hy == targetPoint.hy) {
return false;
}
var disX: number = Math.abs(targetPoint.hx - startPoint.hx);
var disY: number = Math.abs(targetPoint.hy - startPoint.hy);
var dirX = 0;
if (targetPoint.hx > startPoint.hx) {
dirX = 1;
}
else if (targetPoint.hx < startPoint.hx) {
dirX = -1;
}
var dirY = 0;
if (targetPoint.hy > startPoint.hy) {
dirY = 1;
}
else if (targetPoint.hy < startPoint.hy) {
dirY = -1;
}
var rx: number = 0;
var ry: number = 0;
var intNum: number = 0;
var decimal: number = 0;
if (disX > disY) {
var rate: number = disY / disX;
for (var i = 0; i < disX; i += 2) {
ry = i * dirY * rate;
intNum = dirY > 0 ? Math.floor(startPoint.hy + ry) : Math.ceil(startPoint.hy + ry);
decimal = Math.abs(ry % 1);
var hpoint1: HoneyPoint = new HoneyPoint();
hpoint1.hx = startPoint.hx + i * dirX;
hpoint1.hy = decimal <= 0.5 ? intNum : intNum + 1 * dirY;
//cc.log(i + " :: " ,hpoint1.hx, hpoint1.hy," yy ",startPoint.hy + i * dirY * rate,ry % 1,rate,intNum,decimal,dirY,ry);
ry = (i + 1) * dirY * rate;
intNum = dirY > 0 ? Math.floor(startPoint.hy + ry) : Math.ceil(startPoint.hy + ry);
decimal = Math.abs(ry % 1);
var hpoint2: HoneyPoint = new HoneyPoint();
hpoint2.hx = startPoint.hx + (i + 1) * dirX;
hpoint2.hy = decimal <= 0.5 ? intNum : intNum + 1 * dirY;
ry = (i + 2) * dirY * rate;
intNum = dirY > 0 ? Math.floor(startPoint.hy + ry) : Math.ceil(startPoint.hy + ry);
decimal = Math.abs(ry % 1);
var hpoint3: HoneyPoint = new HoneyPoint();
hpoint3.hx = startPoint.hx + (i + 2) * dirX;
hpoint3.hy = decimal <= 0.5 ? intNum : intNum + 1 * dirY;
if (!this.isCrossAtAdjacentNodes(startPoint, targetPoint, hpoint1, hpoint2, hpoint3)) {
return false;
}
}
}
else {
var rate: number = disX / disY;
for (var i = 0; i < disY; i += 2) {
rx = i * dirX * rate;
intNum = dirX > 0 ? Math.floor(startPoint.hx + rx) : Math.ceil(startPoint.hx + rx);
decimal = Math.abs(rx % 1);
var hpoint1: HoneyPoint = new HoneyPoint();
hpoint1.hx = decimal <= 0.5 ? intNum : intNum + 1 * dirX;
hpoint1.hy = startPoint.hy + i * dirY;
rx = (i + 1) * dirX * rate;
intNum = dirX > 0 ? Math.floor(startPoint.hx + rx) : Math.ceil(startPoint.hx + rx);
decimal = Math.abs(rx % 1);
var hpoint2: HoneyPoint = new HoneyPoint();
hpoint2.hx = decimal <= 0.5 ? intNum : intNum + 1 * dirX;
hpoint2.hy = startPoint.hy + (i + 1) * dirY;
rx = (i + 2) * dirX * rate;
intNum = dirX > 0 ? Math.floor(startPoint.hx + rx) : Math.ceil(startPoint.hx + rx);
decimal = Math.abs(rx % 1);
var hpoint3: HoneyPoint = new HoneyPoint();
hpoint3.hx = decimal <= 0.5 ? intNum : intNum + 1 * dirX;
hpoint3.hy = startPoint.hy + (i + 2) * dirY;
if (!this.isCrossAtAdjacentNodes(startPoint, targetPoint, hpoint1, hpoint2, hpoint3)) {
return false;
}
}
}
return true;
}
/**
* 判断三个相邻的点是否可通过
* @param node1
* @param node2
*/
private isCrossAtAdjacentNodes(startPoint: HoneyPoint, targetPoint: HoneyPoint, hpoint1: HoneyPoint, hpoint2: HoneyPoint, hpoint3: HoneyPoint): boolean {
var node1: RoadNode = this.getNodeByHoneyPoint(hpoint1.hx, hpoint1.hy);
var node2: RoadNode = this.getNodeByHoneyPoint(hpoint2.hx, hpoint2.hy);
var node3: RoadNode = this.getNodeByHoneyPoint(hpoint3.hx, hpoint3.hy); // 节点3主要用做路径方向的判断
if (node1 == node2) {
return false;
}
//前两个点只要有一个点不能通过就不能通过节点3只做方向向导不用考虑是否可通过和是否存在
if (!this.isPassNode(node1) || !this.isPassNode(node2)) {
return false;
}
var dirX1: number = hpoint1.hx - hpoint2.hx;
var dirY1: number = hpoint1.hy - hpoint2.hy;
var dirX2: number = hpoint3.hx - hpoint2.hx;
var dirY2: number = hpoint3.hy - hpoint2.hy;
//hround:number[][] = [[-1,-1],[-1,0],[0,1],[1,1],[1,0],[0,-1]]; //相邻点向量
//[-1,1] [1,-1] //特殊相邻点向量
//如果不是相邻的两个点 则不能通过
if ((Math.abs(dirX1) > 1 || Math.abs(dirY1) > 1) || (Math.abs(dirX2) > 1 || Math.abs(dirY2) > 1)) {
return false;
}
//特殊相邻点 特殊对待
if (dirX1 == -dirY1) { //如果第一个点和第二个点是特殊相邻点
if (dirX1 == -1) {
if (!this.isPassNode(this.getNodeByHoneyPoint(hpoint2.hx - 1, hpoint2.hy)) || !this.isPassNode(this.getNodeByHoneyPoint(hpoint2.hx, hpoint2.hy + 1))) {
return false;
}
}
else {
if (!this.isPassNode(this.getNodeByHoneyPoint(hpoint2.hx + 1, hpoint2.hy)) || !this.isPassNode(this.getNodeByHoneyPoint(hpoint2.hx, hpoint2.hy - 1))) {
return false;
}
}
}
//第一个点和第二个点已经可通过,如果第二个点是终点,那么可直达
if (hpoint2.hx == targetPoint.hx && hpoint2.hy == targetPoint.hy) {
return true;
}
//特殊相邻点 特殊对待
if (dirX2 == -dirY2) { //如果第二个点和第三个点是特殊相邻点
if (dirX2 == -1) {
if (!this.isPassNode(this.getNodeByHoneyPoint(hpoint2.hx - 1, hpoint2.hy)) || !this.isPassNode(this.getNodeByHoneyPoint(hpoint2.hx, hpoint2.hy + 1))) {
return false;
}
}
else {
if (!this.isPassNode(this.getNodeByHoneyPoint(hpoint2.hx + 1, hpoint2.hy)) || !this.isPassNode(this.getNodeByHoneyPoint(hpoint2.hx, hpoint2.hy - 1))) {
return false;
}
}
}
//如果相邻的点和目标点在同一直线
if (hpoint1.hx == hpoint2.hx && hpoint2.hx == hpoint3.hx) {
return true;
}
//var hround2:number[][] = [[-2,-1],[-1,1],[1,2],[2,1],[1,-1],[-1,-2]];
if (this.isPassNode(this.getNodeByHoneyPoint(hpoint2.hx + (dirX1 + dirX2), hpoint2.hy + (dirY1 + dirY2)))) {
return true;
}
return false;
}
/**
* 获得六边形格子坐标(以正斜角和反斜角为标准的坐标)
* @param node
*/
public getHoneyPoint(node: RoadNode): HoneyPoint {
var hx: number = node.cy + Math.ceil(node.cx / 2); //设置反斜角为x坐标
var hy: number = node.cy - Math.floor(node.cx / 2); //设置正斜角为y坐标
return new HoneyPoint(hx, hy);
}
public getNodeByHoneyPoint(hx: number, hy: number): RoadNode {
var cx: number = hx - hy; //研究出来的
var cy: number = Math.floor((hx - hy) / 2) + hy; //研究出来的
return this._roadNodes[cx + "_" + cy] as RoadNode;
}
/**
* 获得一个点周围指定方向相邻的一个点
* @param node 制定的点
* @param roundIndex 0是下然后顺时针5右下
*/
public getRoundNodeByIndex(node: RoadNode, roundIndex: number): RoadNode {
if (!node) {
return null;
}
roundIndex = roundIndex % 6;
var round: number[][];
node.cx % 2 == 0 ? round = this._round1 : round = this._round2;
var cx: number = node.cx + round[roundIndex][0];
var cy: number = node.cy + round[roundIndex][1];
return this._roadNodes[cx + "_" + cy] as RoadNode;
}
/**
* 获得一个点周围所有的相邻点
* @param node
*/
public getRoundNodes(node: RoadNode): RoadNode[] {
var round: number[][];
node.cx % 2 == 0 ? round = this._round1 : round = this._round2;
var nodeArr: RoadNode[] = [];
for (var i: number = 0; i < round.length; i++) {
var cx: number = node.cx + round[i][0];
var cy: number = node.cy + round[i][1];
var node2: RoadNode = this._roadNodes[cx + "_" + cy] as RoadNode;
nodeArr.push(node2);
}
return nodeArr;
}
/**
* 是否是可通过的点
* @param node
*/
private isPassNode(node: RoadNode): boolean {
if (!node || node.value == 1) {
return false;
}
return true;
}
/**
*测试寻路步骤
* @param startNode
* @param targetNode
* @return
*
*/
public testSeekPathStep(startNode: RoadNode, targetNode: RoadNode, callback: Function, target: any, time: number = 100): void {
this._startNode = startNode;
this._currentNode = startNode;
this._targetNode = targetNode;
if (this._targetNode.value == 1)
return;
this._startNode.g = 0; //重置起始节点的g值
this._startNode.resetTree(); //清除起始节点原有的二叉堆关联关系
this._binaryTreeNode.refleshTag(); //刷新二叉堆tag用于后面判断是不是属于当前次的寻路
//this._binaryTreeNode.addTreeNode(this._startNode); //把起始节点设置为二叉堆结构的根节点
this._closelist = [];
var step: number = 0;
clearInterval(this.handle);
this.handle = setInterval(() => {
if (step > this.maxStep) {
console.log("没找到目标计算步骤为:", step);
clearInterval(this.handle);
return;
}
step++;
this.searchRoundNodes(this._currentNode);
if (this._binaryTreeNode.isTreeNull()) //二叉堆树里已经没有任何可搜寻的点了,则寻路结束,每找到目标
{
console.log("没找到目标计算步骤为:", step);
clearInterval(this.handle);
return;
}
this._currentNode = this._binaryTreeNode.getMin_F_Node();
if (this._currentNode == this._targetNode) {
console.log("找到目标计算步骤为:", step);
clearInterval(this.handle);
this._openlist = this._binaryTreeNode.getOpenList();
callback.apply(target, [this._startNode, this._targetNode, this._currentNode, this._openlist, this._closelist, this.getPath()]);
} else {
this._binaryTreeNode.setRoadNodeInCloseList(this._currentNode);//打入关闭列表标记
this._openlist = this._binaryTreeNode.getOpenList();
this._closelist.push(this._currentNode);
callback.apply(target, [this._startNode, this._targetNode, this._currentNode, this._openlist, this._closelist, null]);
}
}, time);
}
/**
*查找一个节点周围可通过的点
* @param node
* @return
*
*/
private searchRoundNodes(node: RoadNode): void {
var round: number[][];
node.cx % 2 == 0 ? round = this._round1 : round = this._round2;
for (var i: number = 0; i < round.length; i++) {
var cx: number = node.cx + round[i][0];
var cy: number = node.cy + round[i][1];
var node2: RoadNode = this._roadNodes[cx + "_" + cy] as RoadNode;
if (node2 != null && node2 != this._startNode && node2.value != 1 && !this.isInCloseList(node2)) {
this.setNodeF(node2);
}
}
}
/**
*设置节点的F值
* @param node
*
*/
public setNodeF(node: RoadNode): void {
var g: number;
if (node.cx == this._currentNode.cx || node.cy == this._currentNode.cy) {
g = this._currentNode.g + this.COST_STRAIGHT;
} else {
g = this._currentNode.g + this.COST_DIAGONAL;
}
if (this.isInOpenList(node)) {
if (g < node.g) {
node.g = g;
node.parent = this._currentNode;
node.h = (Math.abs(this._targetNode.cx - node.cx) + Math.abs(this._targetNode.cy - node.cy)) * this.COST_STRAIGHT;
node.f = node.g + node.h;
//节点的g值已经改变把节点先从二堆叉树结构中删除再重新添加进二堆叉树
this._binaryTreeNode.removeTreeNode(node);
this._binaryTreeNode.addTreeNode(node);
}
} else {
node.g = g;
this._binaryTreeNode.setRoadNodeInOpenList(node);//给节点打入开放列表的标志
node.resetTree();
node.parent = this._currentNode;
node.h = (Math.abs(this._targetNode.cx - node.cx) + Math.abs(this._targetNode.cy - node.cy)) * this.COST_STRAIGHT;
node.f = node.g + node.h;
this._binaryTreeNode.addTreeNode(node);
}
}
/**
*节点是否在开启列表
* @param node
* @return
*
*/
private isInOpenList(node: RoadNode): Boolean {
return this._binaryTreeNode.isInOpenList(node);
}
/**
* 节点是否在关闭列表
* @param node
* @returns
*/
private isInCloseList(node: RoadNode): Boolean {
return this._binaryTreeNode.isInCloseList(node);
}
public dispose(): void {
this._roadNodes = null;
this._round1 = null;
this._round2 = null;
}
}
/**
* 六边形格子坐标(以正斜角和反斜角为标准的坐标)
*/
class HoneyPoint {
public hx: number = 0;
public hy: number = 0;
constructor(x: number = 0, y: number = 0) {
this.hx = x;
this.hy = y;
}
}

View File

@@ -0,0 +1,11 @@
{
"ver": "4.0.23",
"importer": "typescript",
"imported": true,
"uuid": "470f8a32-bf7c-4747-bd7d-07042bbc389e",
"files": [],
"subMetas": {},
"userData": {
"simulateGlobals": []
}
}

View File

@@ -0,0 +1,252 @@
import RoadNode from "./RoadNode";
/**
* 二堆叉结构存储
*/
export default class BinaryTreeNode {
/**
* 当前寻路标记,用于标记节点是否属于当前次寻路运算
*/
public seekTag: number = 0;
/**
* 开启列表根节点
*/
public openNode: RoadNode = null;
/**
* 计数当次寻路的运算代价(用于测试数据)
*/
public count: number = 0;
/**
* 刷新寻路tag标记用于标记当前是哪次的寻路
*/
public refleshTag() {
this.openNode = null;
this.count = 0;
this.seekTag++;
if (this.seekTag > 1000000000) {
this.seekTag = 0;
}
}
/**
* 二叉堆树是否为空,即没有任何节点加入
* @returns
*/
public isTreeNull() {
return this.openNode == null;
}
/**
* 把节点添加进二叉堆里
* @param roadNode 要添加的节点
* @param head 从哪个节点位置开始添加
* @returns
*/
public addTreeNode(roadNode: RoadNode, head: RoadNode = null) {
this.count++; //计数统计运算代价
if (head == null) {
if (this.openNode == null) //如果开启节点为空,则拿首次加二叉堆的节点作为开启节点
{
this.openNode = roadNode;
//console.log(this.count,"add root ",roadNode.f,roadNode.toString());
return;
} else //如果开启节点存在头节点为null,默认把开启节点用于头节点
{
head = this.openNode;
}
}
if (roadNode.f >= head.f) {
if (head.right == null) {
head.right = roadNode;
roadNode.treeParent = head;
//console.log(this.count,"add right ",roadNode.f,roadNode.toString());
} else {
this.addTreeNode(roadNode, head.right);
}
} else {
if (head.left == null) {
head.left = roadNode;
roadNode.treeParent = head;
//console.log(this.count,"add left ",roadNode.f,roadNode.toString());
} else {
this.addTreeNode(roadNode, head.left);
}
}
}
/**
* 删除树节点
* @param roadNode 要删除的节点
*/
public removeTreeNode(roadNode: RoadNode) {
this.count++; //计数统计运算代价
if (roadNode.treeParent == null && roadNode.left == null && roadNode.right == null) //节点不在树结构中
{
return;
}
if (roadNode.treeParent == null) //如果是根节点,优先把左子节点转换成根节点,左子节点不存在,则把右子节点转换成根节点
{
if (roadNode.left) {
this.openNode = roadNode.left;
roadNode.left.treeParent = null;
if (roadNode.right) {
roadNode.right.treeParent = null;
this.addTreeNode(roadNode.right, this.openNode);
}
} else if (roadNode.right) //如果没有左节点,只有右节点
{
this.openNode = roadNode.right;
roadNode.right.treeParent = null;
}
} else {
if (roadNode.treeParent.left == roadNode) //如果是左子节点
{
if (roadNode.right) {
roadNode.treeParent.left = roadNode.right;
roadNode.right.treeParent = roadNode.treeParent;
if (roadNode.left) {
roadNode.left.treeParent = null;
this.addTreeNode(roadNode.left, roadNode.right)
}
} else {
roadNode.treeParent.left = roadNode.left;
if (roadNode.left) {
roadNode.left.treeParent = roadNode.treeParent;
}
}
} else if (roadNode.treeParent.right == roadNode) //如果是右子节点
{
if (roadNode.left) {
roadNode.treeParent.right = roadNode.left;
roadNode.left.treeParent = roadNode.treeParent;
if (roadNode.right) {
roadNode.right.treeParent = null;
this.addTreeNode(roadNode.right, roadNode.left)
}
} else {
roadNode.treeParent.right = roadNode.right;
if (roadNode.right) {
roadNode.right.treeParent = roadNode.treeParent;
}
}
}
}
roadNode.resetTree();
}
/**
* 从二叉堆结构里快速查找除f值最小的路节点
* @param head 搜索的起始节点
* @returns
*/
public getMin_F_Node(head: RoadNode = null): RoadNode {
this.count++; //计数统计运算代价
if (head == null) {
if (this.openNode == null) {
return null;
} else {
head = this.openNode; //如果头节点为null并且开启节点不为空则头节点默认使用开启节点
}
}
if (head.left == null) {
var minNode: RoadNode = head;
if (head.treeParent == null) {
this.openNode = head.right;
if (this.openNode) {
this.openNode.treeParent = null;
}
} else {
head.treeParent.left = head.right;
if (head.right) {
head.right.treeParent = head.treeParent;
}
}
return minNode;
} else {
return this.getMin_F_Node(head.left);
}
}
/**
* 把节点加入开启列表,即打入开启列表标志
* @param node
*/
public setRoadNodeInOpenList(node: RoadNode) {
node.openTag = this.seekTag; //给节点打入开放列表的标志
node.closeTag = 0; //关闭列表标志关闭
}
/**
* 把节点加入关闭列表,即打入关闭列表标志
* @param node
*/
public setRoadNodeInCloseList(node: RoadNode) {
node.openTag = 0; //开放列表标志关闭
node.closeTag = this.seekTag; //给节点打入关闭列表的标志
}
/**
* 节点是否在开启列表
* @param node
* @returns
*/
public isInOpenList(node: RoadNode): Boolean {
return node.openTag == this.seekTag;
}
/**
* 节点是否在关闭列表
* @param node
* @returns
*/
public isInCloseList(node: RoadNode): Boolean {
return node.closeTag == this.seekTag;
}
public getOpenList(): RoadNode[] {
var openList: RoadNode[] = []
this.seachTree(this.openNode, openList);
return openList;
}
private seachTree(head: RoadNode, openList: RoadNode[]) {
if (head == null) {
return;
}
openList.push(head);
if (head.left) {
this.seachTree(head.left, openList);
}
if (head.right) {
this.seachTree(head.right, openList);
}
}
}

View File

@@ -0,0 +1,9 @@
{
"ver": "4.0.23",
"importer": "typescript",
"imported": true,
"uuid": "fbb8e89e-e776-48a5-bad2-bfbbd08cff18",
"files": [],
"subMetas": {},
"userData": {}
}

View File

@@ -0,0 +1,36 @@
import RoadNode from "./RoadNode";
/**
* 寻路接口
* @author 落日故人 QQ 583051842
*
*/
export default interface IRoadSeeker {
/**
*寻路入口方法
* @param startNode
* @param targetNode
* @return
*
*/
seekPath(startNode: RoadNode, targetNode: RoadNode): Array<RoadNode>;
/**
*寻路入口方法 如果没有寻到目标,则返回离目标最近的路径
* @param startNode
* @param targetNode
* @return
*
*/
seekPath2(startNode: RoadNode, targetNode: RoadNode): Array<RoadNode>;
/**
*测试寻路步骤
* @param startNode
* @param targetNode
* @return
*
*/
testSeekPathStep(startNode: RoadNode, targetNode: RoadNode, callback: Function, target: any, time: number): void;
}

View File

@@ -0,0 +1,11 @@
{
"ver": "4.0.23",
"importer": "typescript",
"imported": true,
"uuid": "e4f3fe84-cffc-40ca-ac1a-e0d853f234d8",
"files": [],
"subMetas": {},
"userData": {
"simulateGlobals": []
}
}

View File

@@ -0,0 +1,974 @@
import { MapType } from "../base/MapType";
import Point from "./Point";
import RoadNode from "./RoadNode";
export default class MapRoadUtils {
private static _instance: MapRoadUtils;
public static get instance(): MapRoadUtils {
if (this._instance == null) {
this._instance = new MapRoadUtils();
}
return this._instance;
}
/**
* 地图宽度
*/
private _mapWidth: number;
/**
*地图高度
*/
private _mapHeight: number;
/**
*地图一共分成几行
*/
private _row: number;
/**
*地图一共分成几列
*/
private _col: number;
/**
*地图路点单元格宽
*/
private _nodeWidth: number;
/**
*地图路点单元格高
*/
private _nodeHeight: number;
/**
*地图路点单元宽的一半
*/
private _halfNodeWidth: number;
/**
*地图路点单元高的一半
*/
private _halfNodeHeight: number;
private _mapType: number;
private _mapRoad: IMapRoad;
public updateMapInfo(mapWidth: number, mapHeight: number, nodeWidth: number, nodeHeight: number, mapType: MapType): void {
this._mapWidth = mapWidth;
this._mapHeight = mapHeight;
this._nodeWidth = nodeWidth;
this._nodeHeight = nodeHeight;
this._halfNodeWidth = Math.floor(this._nodeWidth / 2);
this._halfNodeHeight = Math.floor(this._nodeHeight / 2);
this._mapType = mapType;
switch (this._mapType) {
case MapType.angle45:
this._col = Math.ceil(mapWidth / this._nodeWidth);
this._row = Math.ceil(mapHeight / this._nodeHeight) * 2;
this._mapRoad = new MapRoad45Angle(this._row, this._col, this._nodeWidth, this._nodeHeight, this._halfNodeWidth, this._halfNodeHeight); break;
case MapType.angle90:
this._col = Math.ceil(mapWidth / this._nodeWidth);
this._row = Math.ceil(mapHeight / this._nodeHeight);
this._mapRoad = new MapRoad90Angle(this._row, this._col, this._nodeWidth, this._nodeHeight, this._halfNodeWidth, this._halfNodeHeight); break;
case MapType.honeycomb:
//this._nodeHeight = (this._nodeWidth / 2) * 1.732;
this._col = Math.ceil((this._mapWidth - this._nodeWidth / 4) / (this._nodeWidth / 4 * 6)) * 2;
this._row = Math.ceil((this._mapHeight - this._nodeHeight / 2) / this._nodeHeight);
this._mapRoad = new MapRoadHoneycomb(this._row, this._col, this._nodeWidth, this._nodeHeight, this._halfNodeWidth, this._halfNodeHeight); break;
}
// console.log("c r", this._col, this._row);
}
/**
*根据地图平面像素坐标获得路节点
* @param x
* @param y
* @return
*
*/
public getNodeByPixel(x: number, y: number): RoadNode {
if (this._mapRoad) {
return this._mapRoad.getNodeByPixel(x, y);
}
return new RoadNode();
}
/**
*根据路点平面坐标点获得路节点
* @param px
* @param py
* @return
*
*/
public getNodeByDerect(dx: number, dy: number): RoadNode {
if (this._mapRoad) {
return this._mapRoad.getNodeByDerect(dx, dy);
}
return new RoadNode();
}
/**
*根据路点场景世界坐标获得路节点
* @param wx
* @param wy
* @return
*
*/
public getNodeByWorldPoint(wx: number, wy: number): RoadNode {
if (this._mapRoad) {
return this._mapRoad.getNodeByWorldPoint(wx, wy);
}
return new RoadNode();
}
/**
*根据像素坐标得到场景世界坐标
* @param x
* @param y
* @return
*
*/
public getWorldPointByPixel(x: number, y: number): Point {
if (this._mapRoad) {
return this._mapRoad.getWorldPointByPixel(x, y);
}
return new Point();
}
/**
*根据世界坐标获得像素坐标
* @param cx
* @param cy
* @return
*
*/
public getPixelByWorldPoint(cx: number, cy: number): Point {
if (this._mapRoad) {
return this._mapRoad.getPixelByWorldPoint(cx, cy);
}
return new Point();
}
/**
*根据像素坐标获得网格平面坐标
* @param x
* @param y
* @return
*
*/
public getDerectByPixel(x: number, y: number): Point {
if (this._mapRoad) {
return this._mapRoad.getDerectByPixel(x, y);
}
return new Point();
}
/**
*根据世界坐标获得网格平面坐标
* @param cx
* @param cy
* @return
*
*/
public getDerectByWorldPoint(cx: number, cy: number): Point {
if (this._mapRoad) {
return this._mapRoad.getDerectByWorldPoint(cx, cy);
}
return new Point();
}
/**
*根据网格平面坐标获得世界坐标
* @param dx
* @param dy
* @return
*
*/
/* public getWorldPointByDerect(dx:number,dy:number):Point
{
var cx:number = (dy + dx) / 2;
var cy:number = (dy - dx) / 2 + col - 1;
return new Point(cx,cy);
}*/
public getPixelByDerect(dx: number, dy: number): Point {
if (this._mapRoad) {
return this._mapRoad.getPixelByDerect(dx, dy);
}
return new Point();
}
public get mapWidth(): number {
return this._mapWidth;
}
public get mapHeight(): number {
return this._mapHeight;
}
public get nodeWidth(): number {
return this._nodeWidth;
}
public get nodeHeight(): number {
return this._nodeHeight;
}
public get row(): number {
return this._row;
}
public get col(): number {
return this._col;
}
public get halfNodeWidth(): number {
return this._halfNodeWidth;
}
public get halfNodeHeight(): number {
return this._halfNodeHeight;
}
/**
*地图类型 0:斜45度等视角地图, 1:90度角平面地图
*/
public get mapType(): number {
return this._mapType;
}
}
/**
*地图路点处理接口
* @author Administrator
*
*/
interface IMapRoad {
/**
*根据地图平面像素坐标获得路节点
* @param x
* @param y
* @return
*
*/
getNodeByPixel(x: number, y: number): RoadNode;
/**
*根据路点平面坐标点获得路节点
* @param px
* @param py
* @return
*
*/
getNodeByDerect(dx: number, dy: number): RoadNode;
/**
*根据路点场景世界坐标获得路节点
* @param wx
* @param wy
* @return
*
*/
getNodeByWorldPoint(wx: number, wy: number): RoadNode;
/**
*根据像素坐标得到场景世界坐标
* @param x
* @param y
* @return
*
*/
getWorldPointByPixel(x: number, y: number): Point;
/**
*根据世界坐标获得像素坐标
* @param cx
* @param cy
* @return
*
*/
getPixelByWorldPoint(cx: number, cy: number): Point;
/**
*根据像素坐标获得网格平面坐标
* @param x
* @param y
* @return
*
*/
getDerectByPixel(x: number, y: number): Point;
/**
*根据世界坐标获得网格平面坐标
* @param cx
* @param cy
* @return
*
*/
getDerectByWorldPoint(cx: number, cy: number): Point;
/**
*根据网格平面坐标获得像素坐标
* @param dx
* @param dy
* @return
*
*/
getPixelByDerect(dx: number, dy: number): Point;
}
/**
*45度等视角地图路点处理接口实现
* @author Administrator
*
*/
class MapRoad45Angle implements IMapRoad {
/**
*地图一共分成几行
*/
private _row: number;
/**
*地图一共分成几列
*/
private _col: number;
/**
*地图路点单元格宽
*/
private _nodeWidth: number;
/**
*地图路点单元格高
*/
private _nodeHeight: number;
/**
*地图路点单元宽的一半
*/
private _halfNodeWidth: number;
/**
*地图路点单元高的一半
*/
private _halfNodeHeight: number;
public constructor(row: number, col: number, nodeWidth: number, nodeHeight: number, halfNodeWidth: number, halfNodeHeight: number) {
this._row = row;
this._col = col;
this._nodeWidth = nodeWidth;
this._nodeHeight = nodeHeight;
this._halfNodeWidth = halfNodeWidth;
this._halfNodeHeight = halfNodeHeight;
}
/**
*根据地图平面像素坐标获得路节点
* @param x
* @param y
* @return
*
*/
public getNodeByPixel(x: number, y: number): RoadNode {
var wPoint: Point = this.getWorldPointByPixel(x, y);
var fPoint: Point = this.getPixelByWorldPoint(wPoint.x, wPoint.y);
var dPoint: Point = this.getDerectByPixel(x, y);
var node: RoadNode = new RoadNode();
node.cx = wPoint.x;
node.cy = wPoint.y;
node.px = fPoint.x;
node.py = fPoint.y;
node.dx = dPoint.x;
node.dy = dPoint.y;
return node;
}
/**
*根据路点平面坐标点获得路节点
* @param px
* @param py
* @return
*
*/
public getNodeByDerect(dx: number, dy: number): RoadNode {
var fPoint: Point = this.getPixelByDerect(dx, dy);
var wPoint: Point = this.getWorldPointByPixel(fPoint.x, fPoint.y);
var node: RoadNode = new RoadNode();
node.cx = wPoint.x;
node.cy = wPoint.y;
node.px = fPoint.x;
node.py = fPoint.y;
node.dx = dx;
node.dy = dy;
return node;
}
/**
*根据路点场景世界坐标获得路节点
* @param wx
* @param wy
* @return
*
*/
public getNodeByWorldPoint(wx: number, wy: number): RoadNode {
var point: Point = this.getPixelByWorldPoint(wx, wy)
return this.getNodeByPixel(point.x, point.y);
}
/**
*根据像素坐标得到场景世界坐标
* @param x
* @param y
* @return
*
*/
public getWorldPointByPixel(x: number, y: number): Point {
var cx: number = Math.ceil(x / this._nodeWidth - 0.5 + y / this._nodeHeight) - 1;
var cy: number = (this._col - 1) - Math.ceil(x / this._nodeWidth - 0.5 - y / this._nodeHeight);
return new Point(cx, cy);
}
/**
*根据世界坐标获得像素坐标
* @param cx
* @param cy
* @return
*
*/
public getPixelByWorldPoint(cx: number, cy: number): Point {
var x: number = Math.floor((cx + 1 - (cy - (this._col - 1))) * this._halfNodeWidth);
var y: number = Math.floor((cx + 1 + (cy - (this._col - 1))) * this._halfNodeHeight);
return new Point(x, y);
}
/**
*根据像素坐标获得网格平面坐标
* @param x
* @param y
* @return
*
*/
public getDerectByPixel(x: number, y: number): Point {
var worldPoint: Point = this.getWorldPointByPixel(x, y);
var pixelPoint: Point = this.getPixelByWorldPoint(worldPoint.x, worldPoint.y);
var dx: number = Math.floor(pixelPoint.x / this._nodeWidth) - (pixelPoint.x % this._nodeWidth == 0 ? 1 : 0);
var dy: number = Math.floor(pixelPoint.y / this._halfNodeHeight) - 1;
return new Point(dx, dy);
}
/**
*根据世界坐标获得网格平面坐标
* @param cx
* @param cy
* @return
*
*/
public getDerectByWorldPoint(cx: number, cy: number): Point {
var dx: number = Math.floor((cx - (cy - (this._col - 1))) / 2);
var dy: number = cx + (cy - (this._col - 1));
return new Point(dx, dy);
}
/**
*根据网格平面坐标获得像素坐标
* @param dx
* @param dy
* @return
*
*/
public getPixelByDerect(dx: number, dy: number): Point {
var x: number = Math.floor((dx + dy % 2) * this._nodeWidth + (1 - dy % 2) * this._halfNodeWidth);
var y: number = Math.floor((dy + 1) * this._halfNodeHeight);
return new Point(x, y);
}
}
/**
*90度平面地图路点处理接口实现
* @author Administrator
*
*/
class MapRoad90Angle implements IMapRoad {
/**
*地图一共分成几行
*/
private _row: number;
/**
*地图一共分成几列
*/
private _col: number;
/**
*地图路点单元格宽
*/
private _nodeWidth: number;
/**
*地图路点单元格高
*/
private _nodeHeight: number;
/**
*地图路点单元宽的一半
*/
private _halfNodeWidth: number;
/**
*地图路点单元高的一半
*/
private _halfNodeHeight: number;
public constructor(row: number, col: number, nodeWidth: number, nodeHeight: number, halfNodeWidth: number, halfNodeHeight: number) {
this._row = row;
this._col = col;
this._nodeWidth = nodeWidth;
this._nodeHeight = nodeHeight;
this._halfNodeWidth = halfNodeWidth;
this._halfNodeHeight = halfNodeHeight;
}
/**
*根据地图平面像素坐标获得路节点
* @param x
* @param y
* @return
*
*/
public getNodeByPixel(x: number, y: number): RoadNode {
var wPoint: Point = this.getWorldPointByPixel(x, y);
var fPoint: Point = this.getPixelByWorldPoint(wPoint.x, wPoint.y);
var dPoint: Point = this.getDerectByPixel(x, y);
var node: RoadNode = new RoadNode();
node.cx = wPoint.x;
node.cy = wPoint.y;
node.px = fPoint.x;
node.py = fPoint.y;
node.dx = dPoint.x;
node.dy = dPoint.y;
return node;
}
/**
*根据路点平面坐标点获得路节点
* @param px
* @param py
* @return
*
*/
public getNodeByDerect(dx: number, dy: number): RoadNode {
var fPoint: Point = this.getPixelByDerect(dx, dy);
var wPoint: Point = this.getWorldPointByPixel(fPoint.x, fPoint.y);
var node: RoadNode = new RoadNode();
node.cx = wPoint.x;
node.cy = wPoint.y;
node.px = fPoint.x;
node.py = fPoint.y;
node.dx = dx;
node.dy = dy;
return node;
}
/**
*根据路点场景世界坐标获得路节点
* @param wx
* @param wy
* @return
*
*/
public getNodeByWorldPoint(wx: number, wy: number): RoadNode {
var point: Point = this.getPixelByWorldPoint(wx, wy)
return this.getNodeByPixel(point.x, point.y);
}
/**
*根据像素坐标得到场景世界坐标
* @param x
* @param y
* @return
*
*/
public getWorldPointByPixel(x: number, y: number): Point {
var cx: number = Math.floor(x / this._nodeWidth);
var cy: number = Math.floor(y / this._nodeHeight);
return new Point(cx, cy);
}
/**
*根据世界坐标获得像素坐标
* @param cx
* @param cy
* @return
*
*/
public getPixelByWorldPoint(cx: number, cy: number): Point {
var x: number = Math.floor((cx + 1) * this._nodeWidth - this._halfNodeWidth);
var y: number = Math.floor((cy + 1) * this._nodeHeight - this._halfNodeHeight);
return new Point(x, y);
}
/**
*根据像素坐标获得网格平面坐标
* @param x
* @param y
* @return
*
*/
public getDerectByPixel(x: number, y: number): Point {
var dx: number = Math.floor(x / this._nodeWidth);
var dy: number = Math.floor(y / this._nodeHeight);
return new Point(dx, dy);
}
/**
*根据世界坐标获得网格平面坐标 90度地图的世界坐标和网格坐标相同
* @param cx
* @param cy
* @return
*
*/
public getDerectByWorldPoint(cx: number, cy: number): Point {
return new Point(cx, cy);
}
/**
*根据网格平面坐标获得像素坐标
* @param dx
* @param dy
* @return
*
*/
public getPixelByDerect(dx: number, dy: number): Point {
var x: number = Math.floor((dx + 1) * this._nodeWidth - this._halfNodeWidth);
var y: number = Math.floor((dy + 1) * this._nodeHeight - this._halfNodeHeight);
return new Point(x, y);
}
}
/**
*蜂巢式(即正六边形)地图路点处理接口实现
* @author Administrator
*
*/
class MapRoadHoneycomb implements IMapRoad {
/**
*地图一共分成几行
*/
private _row: number;
/**
*地图一共分成几列
*/
private _col: number;
/**
*地图路点单元格宽
*/
private _nodeWidth: number;
/**
*地图路点单元格高
*/
private _nodeHeight: number;
/**
*地图路点单元宽的一半
*/
private _halfNodeWidth: number;
/**
*地图路点单元高的一半
*/
private _halfNodeHeight: number;
/**
* 六边形直径的4分之一
*/
private _nwDiv4: number;
/**
* 六边形直径的半径
*/
private _radius: number;
/**
* 六边形宽高的tan值正六边形为1.732
*/
private _proportion = 1.732;
/**
*蜂巢式(即正六边形)地图路点处理
* @param row
* @param col
* @param nodeWidth
* @param nodeHeight
* @param halfNodeWidth
* @param halfNodeHeight
*
*/
public constructor(row: number, col: number, nodeWidth: number, nodeHeight: number, halfNodeWidth: number, halfNodeHeight: number) {
this._row = row;
this._col = col;
this._nodeWidth = nodeWidth;
//this._nodeHeight = (this._nodeWidth / 2) * 1.732;
this._nodeHeight = nodeHeight;
this._halfNodeWidth = halfNodeWidth;
this._halfNodeHeight = halfNodeHeight;
this._nwDiv4 = this._nodeWidth / 4;
this._radius = this._nwDiv4 * 4;
this._proportion = this._nodeHeight * 2 / this._nodeWidth;
}
/**
*根据地图平面像素坐标获得路节点
* @param x
* @param y
* @return
*
*/
public getNodeByPixel(x: number, y: number): RoadNode {
var wPoint: Point = this.getWorldPointByPixel(x, y);
var fPoint: Point = this.getPixelByWorldPoint(wPoint.x, wPoint.y);
//var dPoint:Point = getDerectByPixel(x,y);
var node: RoadNode = new RoadNode();
node.cx = wPoint.x;
node.cy = wPoint.y;
node.px = fPoint.x;
node.py = fPoint.y;
node.dx = wPoint.x;
node.dy = wPoint.y;
return node;
}
/**
*根据路点平面坐标点获得路节点
* @param px
* @param py
* @return
*
*/
public getNodeByDerect(dx: number, dy: number): RoadNode {
var fPoint: Point = this.getPixelByDerect(dx, dy);
//var wPoint:Point = getWorldPointByPixel(fPoint.x,fPoint.y);
var node: RoadNode = new RoadNode();
node.cx = dx;
node.cy = dy;
node.px = fPoint.x;
node.py = fPoint.y;
node.dx = dx;
node.dy = dy;
return node;
}
/**
*根据路点场景世界坐标获得路节点
* @param wx
* @param wy
* @return
*
*/
public getNodeByWorldPoint(wx: number, wy: number): RoadNode {
var point: Point = this.getPixelByWorldPoint(wx, wy)
return this.getNodeByPixel(point.x, point.y);
}
/**
*根据像素坐标得到场景世界坐标
* @param x
* @param y
* @return
*
*/
public getWorldPointByPixel(x: number, y: number): Point {
var nwDiv4Index: number = Math.floor(x / this._nwDiv4); //六边形的外切矩形竖方向均等分成4分所有的六边形外切矩形连在一起形成一个个4分之一矩形宽的区域nwDiv4Index就是该区域的索引
var col: number = Math.floor(nwDiv4Index / 3); //取得临时六边形横轴的索引,根据不同的情况可能会变
var row: number; //六边形纵轴的索引
var cx: number;
var cy: number;
if ((nwDiv4Index - 1) % 6 == 0 || (nwDiv4Index - 2) % 6 == 0) {
row = Math.floor(y / this._nodeHeight);
cx = col;
cy = row;
}
else if ((nwDiv4Index - 4) % 6 == 0 || (nwDiv4Index - 5) % 6 == 0) {
if (y < this._nodeHeight / 2) {
row = -1;
} else {
row = Math.floor((y - this._nodeHeight / 2) / this._nodeHeight);
}
cx = col;
cy = row
}
else {
if (col % 2 == 0) {
//(x - 1,y - 1) (x - 1,y)
row = Math.floor(y / this._nodeHeight);
if (this.testPointInHoneycomb(col, row, x, y)) {
cx = col;
cy = row;
}
else if (this.testPointInHoneycomb(col - 1, row - 1, x, y)) {
cx = col - 1;
cy = row - 1;
}
else {
cx = col - 1;
cy = row;
}
}
else {
//(x - 1,y) (x - 1,y + 1)
if (y < this._nodeHeight / 2) {
row = -1;
} else {
row = Math.floor((y - this._nodeHeight / 2) / this._nodeHeight);
}
if (this.testPointInHoneycomb(col, row, x, y)) {
cx = col;
cy = row;
}
else if (this.testPointInHoneycomb(col - 1, row, x, y)) {
cx = col - 1;
cy = row;
}
else {
cx = col - 1;
cy = row + 1;
}
}
}
return new Point(cx, cy);
}
private testPointInHoneycomb(col: number, row: number, px: number, py: number): Boolean {
var a: number = this._nwDiv4 * 2;
var point: Point = this.getPixelByWorldPoint(col, row);
var absX: number = Math.abs(px - point.x);
var absY: number = Math.abs(py - point.y);
//return a-absX >= absY/(1.732);
return a - absX >= absY / this._proportion;
}
/**
*根据世界坐标获得像素坐标
* @param cx
* @param cy
* @return
*
*/
public getPixelByWorldPoint(cx: number, cy: number): Point {
var x: number = Math.floor((2 + 3 * cx) / 4 * this._nodeWidth);
var y: number = Math.floor((cy + 1 / 2 * (1 + (cx % 2))) * this._nodeHeight);
return new Point(x, y);
}
/**
*根据像素坐标获得网格平面坐标
* @param x
* @param y
* @return
*
*/
public getDerectByPixel(x: number, y: number): Point {
return this.getWorldPointByPixel(x, y);
}
/**
*根据世界坐标获得网格平面坐标 90度地图的世界坐标和网格坐标相同
* @param cx
* @param cy
* @return
*
*/
public getDerectByWorldPoint(cx: number, cy: number): Point {
return new Point(cx, cy);
}
/**
*根据网格平面坐标获得像素坐标
* @param dx
* @param dy
* @return
*
*/
public getPixelByDerect(dx: number, dy: number): Point {
var x: number = (2 + 3 * dx) / 4 * this._nodeWidth;
var y: number = (dy + 1 / 2 * (1 + (dx % 2))) * this._nodeHeight;
return new Point(x, y);
}
}

View File

@@ -0,0 +1,11 @@
{
"ver": "4.0.23",
"importer": "typescript",
"imported": true,
"uuid": "38983af0-c3cc-42a2-bd83-49e6b001f888",
"files": [],
"subMetas": {},
"userData": {
"simulateGlobals": []
}
}

View File

@@ -0,0 +1,9 @@
export default class Point {
public x: number = 0;
public y: number = 0;
public constructor(x: number = 0, y: number = 0) {
this.x = x;
this.y = y;
}
}

View File

@@ -0,0 +1,11 @@
{
"ver": "4.0.23",
"importer": "typescript",
"imported": true,
"uuid": "520e470b-8810-4f2d-8444-cd2446965b49",
"files": [],
"subMetas": {},
"userData": {
"simulateGlobals": []
}
}

View File

@@ -0,0 +1,186 @@
export default class RoadNode {
private _px: number;//像素坐标x轴
private _py: number;//像素坐标y轴
private _cx: number;//世界坐标x轴
private _cy: number;//世界坐标y轴
private _dx: number;//直角坐标x轴
private _dy: number;//直角坐标y轴
private _value: number = 0;//节点的值
private _f: number = 0; //路点的f值
private _g: number = 0; //路点的g值
private _h: number = 0; //路点的h值
private _parent: RoadNode = null; //路点的父节点
//-------------二堆叉存储结构-----------------
private _treeParent: RoadNode = null; //二堆叉结构的父节点
private _left: RoadNode = null; //二堆叉结构的左子节点
private _right: RoadNode = null; //二堆叉结构的右子节点
private _openTag: number = 0; //是否在开启列表标记
private _closeTag: number = 0; //是否在关闭列表标记
/**
* 重置二叉堆存储信息
*/
public resetTree() {
this._treeParent = null;
this._left = null;
this._right = null;
}
public toString(): String {
return "路点像素坐标:(" + this._px + "," + this._py + "), " +
"路点世界坐标:(" + this._cx + "," + this._cy + "), " +
"路点平面直角坐标:(" + this._dx + "," + this._dy + ")";
}
public get px(): number {
return this._px;
}
public set px(value: number) {
this._px = value;
}
public get py(): number {
return this._py;
}
public set py(value: number) {
this._py = value;
}
public get cx(): number {
return this._cx;
}
public set cx(value: number) {
this._cx = value;
}
public get cy(): number {
return this._cy;
}
public set cy(value: number) {
this._cy = value;
}
public get dx(): number {
return this._dx;
}
public set dx(value: number) {
this._dx = value;
}
public get dy(): number {
return this._dy;
}
public set dy(value: number) {
this._dy = value;
}
public get value(): number {
return this._value;
}
public set value(val: number) {
this._value = val;
}
public get f(): number {
return this._f;
}
public set f(value: number) {
this._f = value;
}
public get g(): number {
return this._g;
}
public set g(value: number) {
this._g = value;
}
public get h(): number {
return this._h;
}
public set h(value: number) {
this._h = value;
}
public get parent(): RoadNode {
return this._parent;
}
public set parent(value: RoadNode) {
this._parent = value;
}
//-------------二堆叉存储结构-----------------
/**
* 二堆叉结构的父节点
*/
public get treeParent(): RoadNode {
return this._treeParent;
}
public set treeParent(value: RoadNode) {
this._treeParent = value;
}
/**
* 二堆叉结构的左子节点
*/
public get left(): RoadNode {
return this._left;
}
public set left(value: RoadNode) {
this._left = value;
}
/**
* 二堆叉结构的右子节点
*/
public get right(): RoadNode {
return this._right;
}
public set right(value: RoadNode) {
this._right = value;
}
/**
* 是否在开启列表标记
*/
public get openTag(): number {
return this._openTag;
}
public set openTag(value: number) {
this._openTag = value;
}
/**
* 是否在关闭列表标记
*/
public get closeTag(): number {
return this._closeTag;
}
public set closeTag(value: number) {
this._closeTag = value;
}
}

View File

@@ -0,0 +1,11 @@
{
"ver": "4.0.23",
"importer": "typescript",
"imported": true,
"uuid": "a55696bb-2934-4388-a1af-182ab13401ef",
"files": [],
"subMetas": {},
"userData": {
"simulateGlobals": []
}
}

View File

@@ -0,0 +1,18 @@
/*
* @Author: dgflash
* @Date: 2021-08-09 16:43:23
* @LastEditTime: 2021-08-09 18:32:54
* @LastEditors: Please set LastEditors
* @Description: 地形类型
* @FilePath: \Game\assets\script\core\libs\map\road\RoadType.ts
*/
export enum RoadType {
/** 标准路 */
Road = 0,
/** 障碍物 */
Obstacle = 1,
/** 班透明路 */
RoadTransparent = 2,
/** 隐藏点 */
Hidden = 3
}

View File

@@ -0,0 +1,9 @@
{
"ver": "4.0.23",
"importer": "typescript",
"imported": true,
"uuid": "524f315a-8ec1-44fd-95a9-555f0a57a113",
"files": [],
"subMetas": {},
"userData": {}
}