249 lines
5.5 KiB
TypeScript
249 lines
5.5 KiB
TypeScript
import BattleObj from "../object/BattleObj";
|
||
|
||
var assert = require('assert');
|
||
|
||
/* object 格式
|
||
obj = {
|
||
onlyid = onlyid,
|
||
x = x,
|
||
y = y,
|
||
dir = dir,
|
||
aoi_model = "w", // "w"、"m"、“wm "、"mw "
|
||
dst = 10, --观察半径
|
||
isplayer = false,
|
||
ismonster = false,
|
||
isnpc = false,
|
||
}
|
||
*/
|
||
|
||
export default class Aoi{
|
||
w:number;
|
||
h:number;
|
||
obj_list:any;
|
||
obj_list_x:any;
|
||
obj_list_y:any;
|
||
dst_max:number;
|
||
|
||
constructor() {
|
||
this.w = 300;
|
||
this.h = 300;
|
||
this.obj_list = {}
|
||
this.obj_list_x = {}
|
||
this.obj_list_y = {}
|
||
this.dst_max = 40 //最大观察半径
|
||
}
|
||
|
||
|
||
is_watcher(obj:any):boolean{
|
||
if (obj.aoi_model == "w" || obj.aoi_model == "wm" || obj.aoi_model == "mw") {
|
||
return true;
|
||
} else {
|
||
return false;
|
||
}
|
||
}
|
||
|
||
is_maker(obj:any):boolean{
|
||
if (obj.aoi_model == "m" || obj.aoi_model == "wm" || obj.aoi_model == "mw") {
|
||
return true;
|
||
} else {
|
||
return false;
|
||
}
|
||
}
|
||
|
||
dispatch_message(obj:any, func:any) {
|
||
assert(func);
|
||
if (this.is_maker(obj)) {
|
||
// 按照设置的最大视野范围遍历x轴
|
||
let tmps = obj.x - this.dst_max;
|
||
if (tmps <= 0) {
|
||
tmps = 1;
|
||
}
|
||
let tmpe = obj.x + this.dst_max;
|
||
if (tmpe > this.w) {
|
||
tmpe = this.w;
|
||
}
|
||
|
||
for (let i = tmps; i < tmpe; i++) {
|
||
if (i <= 0) {
|
||
break;
|
||
}
|
||
if (this.obj_list_x[i]) {
|
||
for (const k in this.obj_list_x[i]) {
|
||
if (this.obj_list_x[i].hasOwnProperty(k)) {
|
||
const v = this.obj_list_x[i][k];
|
||
if (v == null) continue;
|
||
// 是观察者,并且在他的视野范围内
|
||
if (this.is_watcher(v) && Math.abs(v.x - obj.x) <= this.dst_max && Math.abs(v.y - obj.y) <= this.dst_max && v != obj) {
|
||
// 执行更新回调
|
||
func(obj, v)
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
get_watcher(obj:any) {
|
||
let list:any = {};
|
||
let tmps = obj.x - this.dst_max;
|
||
if (tmps <= 0) {
|
||
tmps = 1;
|
||
}
|
||
|
||
let tmpe = obj.x + this.dst_max;
|
||
if (tmpe > this.w) {
|
||
tmpe = this.w;
|
||
}
|
||
|
||
for (let i = tmps; i <= tmpe; i++) {
|
||
if (i <= 0) {
|
||
break;
|
||
}
|
||
|
||
if (this.obj_list_x[i]) {
|
||
for (const k in this.obj_list_x[i]) {
|
||
if (this.obj_list_x[i].hasOwnProperty(k)) {
|
||
const v = this.obj_list_x[i][k];
|
||
if (v == null) continue;
|
||
if (this.is_watcher(v) && Math.abs(v.y - obj.y) <= this.dst_max && Math.abs(v.x - obj.x) <= this.dst_max && v != obj) {
|
||
list[k] = v;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
return list;
|
||
}
|
||
|
||
get_maker(obj:any, isproto?:any) {
|
||
let list:any = {};
|
||
let tmps = obj.x - this.dst_max;
|
||
if (tmps < 0) {
|
||
tmps = 0;
|
||
}
|
||
|
||
let tmpe = obj.x + this.dst_max;
|
||
if (tmpe > this.w) {
|
||
tmpe = this.w;
|
||
}
|
||
|
||
for (let i = tmps; i <= tmpe; i++) {
|
||
if (i < 0) {
|
||
break;
|
||
}
|
||
|
||
if (this.obj_list_x[i]) {
|
||
for (const k in this.obj_list_x[i]) {
|
||
if (this.obj_list_x[i].hasOwnProperty(k)) {
|
||
const v = this.obj_list_x[i][k];
|
||
if (v == null) continue;
|
||
if (this.is_maker(v) && Math.abs(v.y - obj.y) <= this.dst_max && Math.abs(v.x - obj.x) <= this.dst_max && v != obj) {
|
||
list[k] = v;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
return list;
|
||
}
|
||
|
||
init(width:any, height:any, maxdst:any) {
|
||
this.w = width == null ? this.w : width;
|
||
this.h = height == null ? this.h : height;
|
||
this.dst_max = maxdst == null ? this.dst_max : maxdst;
|
||
}
|
||
|
||
enter(obj:any, func:any) {
|
||
this.obj_list[obj.onlyid] = obj;
|
||
|
||
if (!this.obj_list_x[obj.x]) {
|
||
this.obj_list_x[obj.x] = {};
|
||
}
|
||
|
||
if (!this.obj_list_y[obj.y]) {
|
||
this.obj_list_y[obj.y] = {};
|
||
}
|
||
|
||
this.obj_list_x[obj.x][obj.onlyid] = obj;
|
||
this.obj_list_y[obj.y][obj.onlyid] = obj;
|
||
|
||
// 如果是maker模式, 广播给所有视野范围的带w模式的obj
|
||
this.dispatch_message(obj, func);
|
||
|
||
// 如果是watcher模式, 在进入之后返回视野上所有带m模式的obj
|
||
if (this.is_watcher(obj)) {
|
||
return this.get_maker(obj);
|
||
}
|
||
}
|
||
|
||
remove(obj:any, func:any) {
|
||
delete this.obj_list[obj.onlyid];
|
||
delete this.obj_list_x[obj.x][obj.onlyid];
|
||
delete this.obj_list_y[obj.y][obj.onlyid];
|
||
// 如果是m活着mw模式, 需要广播给其他所有视野范围的w
|
||
this.dispatch_message(obj, func)
|
||
}
|
||
// 需要计算更新之前和更新之后的交集作为广播集合
|
||
update(obj:any, x:any, y:any, updatefunc:any, enterfunc:any, exitfunc:any):BattleObj[]{
|
||
let bef_w_list = this.get_watcher(this.obj_list[obj.onlyid])
|
||
let bef_m_list = this.get_maker(this.obj_list[obj.onlyid])
|
||
|
||
delete this.obj_list_x[obj.x][obj.onlyid];
|
||
delete this.obj_list_y[obj.y][obj.onlyid];
|
||
|
||
obj.x = x;
|
||
obj.y = y;
|
||
if (!this.obj_list_x[obj.x]) {
|
||
this.obj_list_x[obj.x] = {};
|
||
}
|
||
|
||
if (!this.obj_list_y[obj.y]) {
|
||
this.obj_list_y[obj.y] = {};
|
||
}
|
||
|
||
this.obj_list[obj.onlyid] = obj;
|
||
this.obj_list_x[obj.x][obj.onlyid] = obj;
|
||
this.obj_list_y[obj.y][obj.onlyid] = obj;
|
||
|
||
let aft_w_list = this.get_watcher(obj);
|
||
let aft_m_list = this.get_maker(obj);
|
||
|
||
if (this.is_maker(obj)) {
|
||
for (const k in aft_w_list) {
|
||
if (aft_w_list.hasOwnProperty(k)) {
|
||
const v = aft_w_list[k];
|
||
if (bef_w_list[k]) {
|
||
updatefunc(obj, v); // 更新交集
|
||
} else {
|
||
enterfunc(obj, v); //新增进入视野
|
||
}
|
||
}
|
||
}
|
||
|
||
// 走出对方的视野了也通知对方做退出视野的相关操作
|
||
for (const k in bef_w_list) {
|
||
if (bef_w_list.hasOwnProperty(k)) {
|
||
const v = bef_w_list[k];
|
||
if (!aft_w_list[k]) {
|
||
exitfunc(obj, v);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
let list = [];
|
||
if (this.is_watcher(obj)) {
|
||
//找出新增的部分,需要更新到前端
|
||
for (const k in aft_m_list) {
|
||
if (aft_m_list.hasOwnProperty(k)) {
|
||
const v = aft_m_list[k];
|
||
if (!bef_m_list[k]) {
|
||
list.push(v);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
return list;
|
||
}
|
||
} |