redraw textures and added new async task system
This commit is contained in:
parent
815422f8e4
commit
d1c3766c98
Binary file not shown.
Before Width: | Height: | Size: 692 B After Width: | Height: | Size: 1.5 KiB |
@ -68,10 +68,11 @@ function setupInGameSelector() {
|
|||||||
// npccc.moveTo(new Point2D(getTileAt(t.x, t.y, ChunkStorageTypes.TYPE_TERRAIN).worldPosition.getX(), getTileAt(t.x, t.y, ChunkStorageTypes.TYPE_TERRAIN).worldPosition.getY()));
|
// npccc.moveTo(new Point2D(getTileAt(t.x, t.y, ChunkStorageTypes.TYPE_TERRAIN).worldPosition.getX(), getTileAt(t.x, t.y, ChunkStorageTypes.TYPE_TERRAIN).worldPosition.getY()));
|
||||||
let tile = getNavigationGridTile(t.x, t.y);
|
let tile = getNavigationGridTile(t.x, t.y);
|
||||||
if(tile.isObstacle) return;
|
if(tile.isObstacle) return;
|
||||||
npccc.moveTo(new PointInt2D(tile.position.getX(), tile.position.getY()),
|
npccc.startTask(new PointInt2D(tile.position.getX(), tile.position.getY()));
|
||||||
(cb)=>{
|
// npccc.moveTo(new PointInt2D(tile.position.getX(), tile.position.getY()),
|
||||||
console.log(cb);
|
// (cb)=>{
|
||||||
});
|
// console.log(cb);
|
||||||
|
// });
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
447
src/Game/NPC/NPCBehavior/NPCBehavior.js
Normal file
447
src/Game/NPC/NPCBehavior/NPCBehavior.js
Normal file
@ -0,0 +1,447 @@
|
|||||||
|
import { PointInt2D } from "../../Utils/Math.utils";
|
||||||
|
// import { findPathOnNavigationGridIfExists } from "../../World/NavigationGrid/NavigationGrid";
|
||||||
|
import { NPCController } from "../NPCController/NPCController";
|
||||||
|
// import { NPCProto } from "../NPCProto/NPCProto";
|
||||||
|
|
||||||
|
async function NPCJobFunctor(props, action) {
|
||||||
|
return new NPCActionCallbackResult();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param {NPCActionCallbackResult} lastActionResult
|
||||||
|
*/
|
||||||
|
function NPCActionCallback(lastActionResult) {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param {NPCTaskCallbackResult} taskResult
|
||||||
|
*/
|
||||||
|
function NPCTaskCallback(taskResult) {}
|
||||||
|
|
||||||
|
export class NPCActionCallbackResult {
|
||||||
|
/**
|
||||||
|
* status of this action. -1 - error, 0 - waiting for execution, 1 - completed, 2 - can not be completed
|
||||||
|
*/
|
||||||
|
status = -1;
|
||||||
|
statusText = "";
|
||||||
|
/**
|
||||||
|
* @type {NPCAction}
|
||||||
|
*/
|
||||||
|
action = undefined;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* statuses: -1 - error, 0 - waiting for execution, 1 - completed, 2 - can not be completed
|
||||||
|
* @param {Number} status
|
||||||
|
* @param {String} text
|
||||||
|
* @param {NPCAction} action
|
||||||
|
*/
|
||||||
|
constructor(status, text = "", action = undefined) {
|
||||||
|
this.status = status;
|
||||||
|
this.statusText = text;
|
||||||
|
this.action = action;
|
||||||
|
}
|
||||||
|
|
||||||
|
clone() {
|
||||||
|
return new NPCActionCallbackResult(this.status, this.statusText, this.action);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class NPCTaskCallbackResult {
|
||||||
|
/**
|
||||||
|
* status of this task. -1 - error, 0 - completed, 1 - can not be completed, 2 - reset
|
||||||
|
*/
|
||||||
|
status = -1;
|
||||||
|
statusText = "";
|
||||||
|
/**
|
||||||
|
* @type {NPCActionCallbackResult}
|
||||||
|
*/
|
||||||
|
lastActionCallbackResult;
|
||||||
|
/**
|
||||||
|
* @type {NPCTask}
|
||||||
|
*/
|
||||||
|
task = undefined;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param {Number} status
|
||||||
|
* @param {String} statusText
|
||||||
|
* @param {NPCActionCallbackResult} lastActionCallbackResult
|
||||||
|
* @param {NPCTask} task
|
||||||
|
*/
|
||||||
|
constructor(status, statusText, lastActionCallbackResult, task) {
|
||||||
|
this.status = status;
|
||||||
|
this.statusText = statusText;
|
||||||
|
this.lastActionCallbackResult = lastActionCallbackResult;
|
||||||
|
this.task = task;
|
||||||
|
}
|
||||||
|
|
||||||
|
clone()
|
||||||
|
{
|
||||||
|
return new NPCTaskCallbackResult(this.status, this.statusText, this.lastActionCallbackResult, this.task);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* NPC Action is the smallest part of NPC's behavior.
|
||||||
|
* There are 2 types of actions:
|
||||||
|
* 0: move to tile
|
||||||
|
* 1: do something
|
||||||
|
*/
|
||||||
|
export class NPCAction {
|
||||||
|
//invalid action type by default
|
||||||
|
type = -1;
|
||||||
|
//target position
|
||||||
|
targetPosition = new PointInt2D();
|
||||||
|
/**
|
||||||
|
* target job function
|
||||||
|
* @type {NPCJobFunctor}
|
||||||
|
*/
|
||||||
|
targetJob;
|
||||||
|
/**
|
||||||
|
* these props will passed to job function on it's execution
|
||||||
|
*/
|
||||||
|
targetJobProps;
|
||||||
|
/**
|
||||||
|
* status of this action. -1 - error, 0 - waiting for execution, 1 - completed, 2 - can not be completed
|
||||||
|
*/
|
||||||
|
status = -1;
|
||||||
|
/**
|
||||||
|
* @type {NPCProto}
|
||||||
|
*/
|
||||||
|
owner = null;
|
||||||
|
/**
|
||||||
|
* will this task block chain of execution
|
||||||
|
*/
|
||||||
|
skipToNextIgnoringStatus = false;
|
||||||
|
|
||||||
|
usePause = false;
|
||||||
|
pauseTime = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* NPC Action is the smallest part of NPC's behavior.
|
||||||
|
* There are 2 types of actions:
|
||||||
|
* 0: move to tile
|
||||||
|
* 1: do something
|
||||||
|
* @param {Number} type
|
||||||
|
* @param {PointInt2D} pos
|
||||||
|
* @param {NPCJobFunctor} job
|
||||||
|
* @param {any} jobProps
|
||||||
|
* @param {NPCController} owner
|
||||||
|
* @param {Boolean} skipToNext
|
||||||
|
* @param {Boolean} usePause
|
||||||
|
* @param {Number} pauseTime
|
||||||
|
*/
|
||||||
|
constructor(type, pos, job, jobProps = {}, owner = null, skipToNext = false, usePause = false, pauseTime = 0) {
|
||||||
|
this.type = type;
|
||||||
|
this.targetPosition = pos;
|
||||||
|
this.targetJob = job;
|
||||||
|
this.targetJobProps = jobProps;
|
||||||
|
this.status = 0;
|
||||||
|
this.owner = owner;
|
||||||
|
this.skipToNextIgnoringStatus = skipToNext;
|
||||||
|
this.usePause = usePause;
|
||||||
|
this.pauseTime = pauseTime;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* NPC Task is a container with NPC Actions. It is like a timeline with frames (frames are NPC Actions)
|
||||||
|
*/
|
||||||
|
export class NPCTask {
|
||||||
|
/**
|
||||||
|
* @type {Array<NPCAction>}
|
||||||
|
*/
|
||||||
|
actionsContainer = [];
|
||||||
|
_currentIndex = 0;
|
||||||
|
_startIndex = 0;
|
||||||
|
/**
|
||||||
|
* @type {NPCController}
|
||||||
|
*/
|
||||||
|
owner = null;
|
||||||
|
//is task active and will execute actions
|
||||||
|
active = false;
|
||||||
|
//will task start again after completion
|
||||||
|
loop = false;
|
||||||
|
onPause = false;
|
||||||
|
|
||||||
|
_lastActionCompleted = false;
|
||||||
|
/**
|
||||||
|
* @type {NPCActionCallbackResult}
|
||||||
|
*/
|
||||||
|
_lastActionCallbackResult;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @type {NPCActionCallback}
|
||||||
|
*/
|
||||||
|
actionCallback;
|
||||||
|
/**
|
||||||
|
* @type {NPCTaskCallback}
|
||||||
|
*/
|
||||||
|
taskCallback;
|
||||||
|
|
||||||
|
_pauseTimeout;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {Array<NPCAction>} actions
|
||||||
|
* @param {NPCController} owner
|
||||||
|
* @param {boolean} loop
|
||||||
|
* @param {NPCActionCallback} actionCallback
|
||||||
|
* @param {NPCTaskCallback} taskCallback
|
||||||
|
*/
|
||||||
|
constructor(actions, owner = null, loop = false, actionCallback = undefined, taskCallback = undefined) {
|
||||||
|
this.actionsContainer = actions;
|
||||||
|
this.owner = owner;
|
||||||
|
this.loop = loop;
|
||||||
|
this.actionCallback = actionCallback;
|
||||||
|
this.taskCallback = taskCallback;
|
||||||
|
}
|
||||||
|
|
||||||
|
startTask() {
|
||||||
|
if (!this.owner || this._lastActionCompleted) return false;
|
||||||
|
this._currentIndex = this._startIndex;
|
||||||
|
this.active = true;
|
||||||
|
return this._pushNewAction();
|
||||||
|
}
|
||||||
|
|
||||||
|
resetTask() {
|
||||||
|
this.active = false;
|
||||||
|
this.onPause = false;
|
||||||
|
this._resetAllActions();
|
||||||
|
this._currentIndex = this._startIndex;
|
||||||
|
clearTimeout(this._pauseTimeout);
|
||||||
|
this.taskCallback(new NPCTaskCallbackResult(2, "reset", this._lastActionCallbackResult.clone(), this));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* set owner for all actions and this task
|
||||||
|
* @param {NPCController} owner
|
||||||
|
*/
|
||||||
|
setOwnerToAll(owner) {
|
||||||
|
this.owner = owner;
|
||||||
|
for (const action of this.actionsContainer) {
|
||||||
|
action.owner = owner;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
handleTaskTick(ticker) {
|
||||||
|
if (!this.active || this.onPause) return;
|
||||||
|
if (this._lastActionCompleted) {
|
||||||
|
this._lastActionCompleted = false;
|
||||||
|
this.actionCallback(this._lastActionCallbackResult.clone());
|
||||||
|
if (!this.active) return;
|
||||||
|
if (!this.actionsContainer[this._currentIndex].skipToNextIgnoringStatus) {
|
||||||
|
if (this._lastActionCallbackResult.status !== 1) {
|
||||||
|
this.taskCallback(new NPCTaskCallbackResult(1, "chain blocked by action status", this._lastActionCallbackResult.clone(), this));
|
||||||
|
this.resetTask();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//pay attention in timeout logic
|
||||||
|
if (this.actionsContainer[this._currentIndex].usePause) {
|
||||||
|
this.onPause = true;
|
||||||
|
clearTimeout(this._pauseTimeout);
|
||||||
|
let thisCopy = this;
|
||||||
|
this._pauseTimeout = setTimeout(() => {
|
||||||
|
thisCopy.onPause = false;
|
||||||
|
thisCopy._currentIndex++;
|
||||||
|
if (thisCopy._currentIndex >= thisCopy.actionsContainer.length) {
|
||||||
|
if (thisCopy.loop) {
|
||||||
|
thisCopy._currentIndex = thisCopy._startIndex;
|
||||||
|
thisCopy._resetAllActions();
|
||||||
|
thisCopy._pushNewAction();
|
||||||
|
} else thisCopy.active = false;
|
||||||
|
} else {
|
||||||
|
thisCopy._pushNewAction();
|
||||||
|
}
|
||||||
|
}, this.actionsContainer[this._currentIndex].pauseTime);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
//
|
||||||
|
this._currentIndex++;
|
||||||
|
if (this._currentIndex >= this.actionsContainer.length) {
|
||||||
|
if (this.loop) {
|
||||||
|
this._currentIndex = this._startIndex;
|
||||||
|
this._resetAllActions();
|
||||||
|
this._pushNewAction();
|
||||||
|
} else {
|
||||||
|
this.active = false;
|
||||||
|
this.taskCallback(new NPCTaskCallbackResult(0, "finished", this._lastActionCallbackResult.clone(), this));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
this._pushNewAction();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_pushNewAction() {
|
||||||
|
switch (this.actionsContainer[this._currentIndex].type) {
|
||||||
|
case 0:
|
||||||
|
this.owner.moveTo(this.actionsContainer[this._currentIndex].targetPosition, (r) => {
|
||||||
|
this._handleMovementResult(r);
|
||||||
|
});
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
this.actionsContainer[this._currentIndex].targetJob(this.actionsContainer[this._currentIndex].targetJobProps, this.actionsContainer[this._currentIndex]).then((r) => {
|
||||||
|
this._handleJobResult(r);
|
||||||
|
});
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
_resetAllActions() {
|
||||||
|
for (const action of this.actionsContainer) {
|
||||||
|
action.status = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {NPCActionCallbackResult} resultFromMoving
|
||||||
|
*/
|
||||||
|
_handleMovementResult(resultFromMoving) {
|
||||||
|
this.actionsContainer[this._currentIndex].status = resultFromMoving === 0 ? 1 : resultFromMoving === -1 ? -1 : 2;
|
||||||
|
this._lastActionCompleted = true;
|
||||||
|
this._lastActionCallbackResult = new NPCActionCallbackResult(resultFromMoving === 0 ? 1 : resultFromMoving === -1 ? -1 : 2, "", this.actionsContainer[this._currentIndex]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {NPCActionCallbackResult} resultFromJob
|
||||||
|
*/
|
||||||
|
_handleJobResult(resultFromJob) {
|
||||||
|
this._lastActionCallbackResult = resultFromJob;
|
||||||
|
this._lastActionCompleted = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {NPCTask} task
|
||||||
|
*/
|
||||||
|
function TaskChanger(task) {}
|
||||||
|
|
||||||
|
export class NPCBehaviorCallbackResult {
|
||||||
|
/**
|
||||||
|
* 0 - action callback
|
||||||
|
* 1 - task callback
|
||||||
|
* @type {Number}
|
||||||
|
*/
|
||||||
|
type;
|
||||||
|
/**
|
||||||
|
* status of the callback (see more in taskCallback or actionCallback)
|
||||||
|
* @type {Number}
|
||||||
|
*/
|
||||||
|
status;
|
||||||
|
/**
|
||||||
|
* @type {String}
|
||||||
|
*/
|
||||||
|
statusText;
|
||||||
|
/**
|
||||||
|
* @type {NPCTaskCallbackResult}
|
||||||
|
*/
|
||||||
|
taskCallbackResult;
|
||||||
|
/**
|
||||||
|
* @type {NPCActionCallbackResult}
|
||||||
|
*/
|
||||||
|
actionCallbackResult;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param {Number} type
|
||||||
|
* @param {Number} status
|
||||||
|
* @param {String} statusText
|
||||||
|
* @param {NPCTaskCallbackResult} taskCallbackResult
|
||||||
|
* @param {NPCActionCallbackResult} actionCallbackResult
|
||||||
|
*/
|
||||||
|
constructor(type, status, statusText, taskCallbackResult, actionCallbackResult) {
|
||||||
|
this.type = type;
|
||||||
|
this.status = status;
|
||||||
|
this.statusText = statusText;
|
||||||
|
this.taskCallbackResult = taskCallbackResult;
|
||||||
|
this.actionCallbackResult = actionCallbackResult;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class NPCBehavior {
|
||||||
|
/**
|
||||||
|
* @type {Map<String, NPCTask>}
|
||||||
|
*/
|
||||||
|
taskMap = new Map();
|
||||||
|
owner = undefined;
|
||||||
|
isTaskInProgress = false;
|
||||||
|
currentTask = "";
|
||||||
|
behaviorCallback = undefined;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {NPCController} owner
|
||||||
|
*/
|
||||||
|
constructor(owner, behaviorCallback) {
|
||||||
|
this.owner = owner;
|
||||||
|
this.behaviorCallback = behaviorCallback;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {String} key
|
||||||
|
* @param {NPCTask} task
|
||||||
|
*/
|
||||||
|
addTask(key, task) {
|
||||||
|
task.setOwnerToAll(this.owner);
|
||||||
|
task.actionCallback = this._handleActionCallback.bind(this);
|
||||||
|
task.taskCallback = this._handleTaskCallback.bind(this);
|
||||||
|
this.taskMap.set(key, task);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {String} key
|
||||||
|
*/
|
||||||
|
startTask(key) {
|
||||||
|
if (this.isTaskInProgress) return false;
|
||||||
|
if (this.taskMap.get(key).startTask()) {
|
||||||
|
this.currentTask = key;
|
||||||
|
this.isTaskInProgress = true;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
abortCurrentTask() {
|
||||||
|
if (this.taskMap.get(this.currentTask)?.resetTask()) {
|
||||||
|
this.isTaskInProgress = false;
|
||||||
|
this.currentTask = "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param {String} key
|
||||||
|
* @param {TaskChanger} changer
|
||||||
|
*/
|
||||||
|
changeTask(key, changer) {
|
||||||
|
changer(this.taskMap.get(key));
|
||||||
|
}
|
||||||
|
|
||||||
|
handleNPCBehaviorTick(ticker) {
|
||||||
|
this.taskMap.get(this.currentTask)?.handleTaskTick(ticker);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param {NPCTaskCallbackResult} result
|
||||||
|
*/
|
||||||
|
_handleTaskCallback(result) {
|
||||||
|
this.isTaskInProgress = false;
|
||||||
|
this.behaviorCallback(new NPCBehaviorCallbackResult(1, result.status, result.statusText, result.clone(), undefined));
|
||||||
|
console.log(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param {NPCActionCallbackResult} result
|
||||||
|
*/
|
||||||
|
_handleActionCallback(result) {
|
||||||
|
this.behaviorCallback(new NPCBehaviorCallbackResult(0, result.status, result.statusText, undefined, result.clone()));
|
||||||
|
console.log(result);
|
||||||
|
}
|
||||||
|
}
|
@ -2,12 +2,19 @@ import { GameObject } from "../../GameObject/GameObject";
|
|||||||
import { PointInt2D } from "../../Utils/Math.utils";
|
import { PointInt2D } from "../../Utils/Math.utils";
|
||||||
import { NavigationPath, PathFinder } from "../../Utils/PathFinding.utils";
|
import { NavigationPath, PathFinder } from "../../Utils/PathFinding.utils";
|
||||||
import { findPathOnNavigationGridIfExists } from "../../World/NavigationGrid/NavigationGrid";
|
import { findPathOnNavigationGridIfExists } from "../../World/NavigationGrid/NavigationGrid";
|
||||||
|
import { NPCAction, NPCActionCallbackResult, NPCBehavior, NPCTask } from "../NPCBehavior/NPCBehavior";
|
||||||
import { NPCProto } from "../NPCProto/NPCProto";
|
import { NPCProto } from "../NPCProto/NPCProto";
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param {Number} result
|
||||||
|
*/
|
||||||
|
function NavigationCallbackFunctor(result) {}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* NPCController defines NPC behavior. Many NPC can have same NPCController for the same behavior.
|
* NPCController defines NPC behavior. Many NPC can have same NPCController for the same behavior.
|
||||||
*/
|
*/
|
||||||
export class NPCController extends GameObject
|
export class NPCController extends GameObject {
|
||||||
{
|
|
||||||
/**
|
/**
|
||||||
* NPC controlled by this controller
|
* NPC controlled by this controller
|
||||||
* @type NPCProto
|
* @type NPCProto
|
||||||
@ -22,37 +29,63 @@ export class NPCController extends GameObject
|
|||||||
navigationFollowMidPoint = false;
|
navigationFollowMidPoint = false;
|
||||||
navigationCallback = () => {};
|
navigationCallback = () => {};
|
||||||
|
|
||||||
constructor(tickAble = true)
|
taskInstanceRef = new NPCTask(
|
||||||
{
|
[
|
||||||
|
new NPCAction(0, new PointInt2D(0, 0), undefined, undefined, undefined, false, true, 1000),
|
||||||
|
new NPCAction(
|
||||||
|
1,
|
||||||
|
undefined,
|
||||||
|
async (myOwner, action) => {
|
||||||
|
console.log(myOwner);
|
||||||
|
return new NPCActionCallbackResult(1, "", action);
|
||||||
|
},
|
||||||
|
"Привет!",
|
||||||
|
undefined,
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
0
|
||||||
|
),
|
||||||
|
],
|
||||||
|
undefined,
|
||||||
|
false
|
||||||
|
);
|
||||||
|
|
||||||
|
behavior = new NPCBehavior(this, () => {});
|
||||||
|
|
||||||
|
constructor(tickAble = true) {
|
||||||
super(tickAble);
|
super(tickAble);
|
||||||
|
this.behavior.addTask("MoveToCursor", this.taskInstanceRef);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* moves NPC to position
|
* moves NPC to position. callback contains result status: -1 - error happened; 0 - success; 1 - unreachable
|
||||||
* @param {PointInt2D} position
|
* @param {PointInt2D} position
|
||||||
* @param {Function} callback
|
* @param {NavigationCallbackFunctor} callback
|
||||||
*/
|
*/
|
||||||
moveTo(position, callback)
|
moveTo(position, callback) {
|
||||||
{
|
|
||||||
// let pf = new PathFinder();
|
// let pf = new PathFinder();
|
||||||
// let nPath = pf.findPathIfExist(new PointInt2D(this.controlledNPC.worldPosition.getX(), this.controlledNPC.worldPosition.getY()), position);
|
// let nPath = pf.findPathIfExist(new PointInt2D(this.controlledNPC.worldPosition.getX(), this.controlledNPC.worldPosition.getY()), position);
|
||||||
let nPath = findPathOnNavigationGridIfExists(new PointInt2D(this.controlledNPC.worldPosition.getX(), this.controlledNPC.worldPosition.getY()), position);
|
let nPath = findPathOnNavigationGridIfExists(
|
||||||
|
new PointInt2D(this.controlledNPC.worldPosition.getX(), this.controlledNPC.worldPosition.getY()),
|
||||||
|
position
|
||||||
|
);
|
||||||
nPath.then((r) => {
|
nPath.then((r) => {
|
||||||
if(r.error)
|
if (r.error) {
|
||||||
{
|
this.controlledNPC.isMoving = false;
|
||||||
callback("failed");
|
callback(-1); //error
|
||||||
return;
|
return;
|
||||||
}
|
} else if (r.state === 0) {
|
||||||
else if (r.result.path.length < 2)
|
this.controlledNPC.isMoving = false;
|
||||||
{
|
callback(1); //unreachable
|
||||||
callback("success");
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
this.navigationPathQueue = [];
|
||||||
for (let i = r.result.path.length - 1; i > 0; i--) {
|
for (let i = r.result.path.length - 1; i > 0; i--) {
|
||||||
this.navigationPathQueue.push(r.result.path[i]);
|
this.navigationPathQueue.push(r.result.path[i]);
|
||||||
}
|
}
|
||||||
this.navigationCallback = callback;
|
this.navigationCallback = callback;
|
||||||
this.navigationInProgress = true;
|
this.navigationInProgress = true;
|
||||||
|
this.controlledNPC.isMoving = true;
|
||||||
});
|
});
|
||||||
// console.log("boba");
|
// console.log("boba");
|
||||||
// console.log(nPath);
|
// console.log(nPath);
|
||||||
@ -60,42 +93,37 @@ export class NPCController extends GameObject
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @param {NavigationPath} pathToFollow
|
* @param {PointInt2D} pos
|
||||||
* @param {Function} callback
|
|
||||||
*/
|
*/
|
||||||
_moveByPath(pathToFollow, callback)
|
startTask(pos) {
|
||||||
{
|
this.behavior.abortCurrentTask();
|
||||||
|
this.behavior.changeTask("MoveToCursor", (task)=>{
|
||||||
|
task.actionsContainer[0].targetPosition = pos;
|
||||||
|
});
|
||||||
|
this.behavior.startTask("MoveToCursor");
|
||||||
}
|
}
|
||||||
|
|
||||||
tick(ticker)
|
tick(ticker) {
|
||||||
{
|
this.taskInstanceRef.handleTaskTick(ticker);
|
||||||
if(this.navigationInProgress)
|
if (this.navigationInProgress) {
|
||||||
{
|
if (!this.navigationFollowMidPoint) {
|
||||||
if(!this.navigationFollowMidPoint)
|
|
||||||
{
|
|
||||||
let target = this.navigationPathQueue.pop();
|
let target = this.navigationPathQueue.pop();
|
||||||
if(!target)
|
if (!target) {
|
||||||
{
|
|
||||||
this.navigationInProgress = false;
|
this.navigationInProgress = false;
|
||||||
this.navigationCallback("success");
|
this.controlledNPC.isMoving = false;
|
||||||
}
|
this.navigationCallback(0); //success
|
||||||
else
|
} else {
|
||||||
{
|
|
||||||
this.controlledNPC.worldPosition = target;
|
this.controlledNPC.worldPosition = target;
|
||||||
this.navigationFollowMidPoint = true;
|
this.navigationFollowMidPoint = true;
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
if (
|
if (
|
||||||
Math.abs(this.controlledNPC.drawObject.x - this.controlledNPC.worldPosition.getX()) < 0.5 &&
|
Math.abs(this.controlledNPC.drawObject.x - this.controlledNPC.worldPosition.getX()) < 0.5 &&
|
||||||
Math.abs(this.controlledNPC.drawObject.y - this.controlledNPC.worldPosition.getY()) < 0.5
|
Math.abs(this.controlledNPC.drawObject.y - this.controlledNPC.worldPosition.getY()) < 0.5
|
||||||
)
|
) {
|
||||||
{
|
|
||||||
this.navigationFollowMidPoint = false;
|
this.navigationFollowMidPoint = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
@ -2,6 +2,7 @@ import { Rectangle } from "../../../pixi/pixi.mjs";
|
|||||||
import { SceneObject } from "../../SceneObjects/SceneObject";
|
import { SceneObject } from "../../SceneObjects/SceneObject";
|
||||||
import { Point2D, interpolate } from "../../Utils/Math.utils";
|
import { Point2D, interpolate } from "../../Utils/Math.utils";
|
||||||
import { getSpriteFromAtlas } from "../../Utils/Sprites.utils";
|
import { getSpriteFromAtlas } from "../../Utils/Sprites.utils";
|
||||||
|
import { getNavigationGridTile } from "../../World/NavigationGrid/NavigationGrid";
|
||||||
import { NPCController } from "../NPCController/NPCController";
|
import { NPCController } from "../NPCController/NPCController";
|
||||||
|
|
||||||
export class NPCProto extends SceneObject
|
export class NPCProto extends SceneObject
|
||||||
@ -13,6 +14,7 @@ export class NPCProto extends SceneObject
|
|||||||
controller = null;
|
controller = null;
|
||||||
|
|
||||||
_positionInterpolationSpeed = 30;
|
_positionInterpolationSpeed = 30;
|
||||||
|
_basicPositionInterpolationSpeed = 30;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* path to NPC spritesheet
|
* path to NPC spritesheet
|
||||||
@ -24,6 +26,8 @@ export class NPCProto extends SceneObject
|
|||||||
*/
|
*/
|
||||||
frame = new Rectangle();
|
frame = new Rectangle();
|
||||||
|
|
||||||
|
isMoving = false;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* creates new NPC object
|
* creates new NPC object
|
||||||
* @param {Boolean} tickAble
|
* @param {Boolean} tickAble
|
||||||
@ -43,7 +47,15 @@ export class NPCProto extends SceneObject
|
|||||||
|
|
||||||
tick(ticker)
|
tick(ticker)
|
||||||
{
|
{
|
||||||
|
if(this.isMoving)
|
||||||
|
{
|
||||||
|
let gridTile = getNavigationGridTile(this.worldPosition.getX(), this.worldPosition.getY());
|
||||||
|
if(gridTile && !gridTile.isObstacle)
|
||||||
|
{
|
||||||
|
this._positionInterpolationSpeed = this._basicPositionInterpolationSpeed / gridTile.movementCost;
|
||||||
|
}
|
||||||
this._positionInterpolation(ticker.deltaMS / 1000 * this._positionInterpolationSpeed);
|
this._positionInterpolation(ticker.deltaMS / 1000 * this._positionInterpolationSpeed);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
_positionInterpolation(delta)
|
_positionInterpolation(delta)
|
||||||
|
@ -45,22 +45,22 @@ export class NavigationPath {
|
|||||||
|
|
||||||
export class NavigationResult {
|
export class NavigationResult {
|
||||||
/**
|
/**
|
||||||
* @type Boolean
|
* @type {Boolean}
|
||||||
*/
|
*/
|
||||||
error;
|
error;
|
||||||
/**
|
/**
|
||||||
* @type String
|
* @type {String}
|
||||||
*/
|
*/
|
||||||
errorText;
|
errorText;
|
||||||
/**
|
/**
|
||||||
* @type NavigationPath | undefined
|
* @type {NavigationPath | undefined}
|
||||||
*/
|
*/
|
||||||
result;
|
result;
|
||||||
/**
|
/**
|
||||||
* 0 - point is unreachable
|
* 0 - point is unreachable
|
||||||
* 1 - path found
|
* 1 - path found
|
||||||
* 2 - error
|
* 2 - error
|
||||||
* @type Int
|
* @type {Number}
|
||||||
*/
|
*/
|
||||||
state;
|
state;
|
||||||
|
|
||||||
@ -194,14 +194,14 @@ export class PathFinder {
|
|||||||
*/
|
*/
|
||||||
_reconstructPath(cameFrom, current) {
|
_reconstructPath(cameFrom, current) {
|
||||||
let totalPath = [current.position];
|
let totalPath = [current.position];
|
||||||
console.log(cameFrom);
|
// console.log(cameFrom);
|
||||||
let keys = [...cameFrom.keys()];
|
let keys = [...cameFrom.keys()];
|
||||||
while (keys.includes(current.id)) {
|
while (keys.includes(current.id)) {
|
||||||
if (current.id === cameFrom.get(current.id).id) break;
|
if (current.id === cameFrom.get(current.id).id) break;
|
||||||
current = cameFrom.get(current.id);
|
current = cameFrom.get(current.id);
|
||||||
totalPath.push(current.position);
|
totalPath.push(current.position);
|
||||||
}
|
}
|
||||||
return totalPath.reverse();
|
return totalPath;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -5,7 +5,7 @@ import { RGBColor, RGBCue } from "../Utils/DataTypes.utils";
|
|||||||
let timeElapsed = PRNG() * 37992648739;
|
let timeElapsed = PRNG() * 37992648739;
|
||||||
|
|
||||||
// ex: scaling = 10; 1 game minute = 6 real seconds;
|
// ex: scaling = 10; 1 game minute = 6 real seconds;
|
||||||
let timeScaling = 300.0;
|
let timeScaling = 100.0;
|
||||||
|
|
||||||
const gameSecondsInGameMinute = 60;
|
const gameSecondsInGameMinute = 60;
|
||||||
const gameMinutesInGameHour = 60;
|
const gameMinutesInGameHour = 60;
|
||||||
@ -14,7 +14,7 @@ const gameDaysInGameWeek = 7;
|
|||||||
const gameWeeksInGameMonth = 4;
|
const gameWeeksInGameMonth = 4;
|
||||||
const gameMonthsInGameYear = 12;
|
const gameMonthsInGameYear = 12;
|
||||||
|
|
||||||
let dayColor = new RGBColor(255, 255, 255);
|
// let dayColor = new RGBColor(255, 255, 255);
|
||||||
let currentColor = new RGBColor(0, 0, 0);
|
let currentColor = new RGBColor(0, 0, 0);
|
||||||
|
|
||||||
let dayColorsCue = new RGBCue(
|
let dayColorsCue = new RGBCue(
|
||||||
|
@ -131,7 +131,7 @@ async function _findPathAsync(start, goal)
|
|||||||
export async function findPathOnNavigationGridIfExists(start, goal) {
|
export async function findPathOnNavigationGridIfExists(start, goal) {
|
||||||
let r0 = await _findPathAsync(goal, start);
|
let r0 = await _findPathAsync(goal, start);
|
||||||
if(!r0.error){
|
if(!r0.error){
|
||||||
r0.result.path.reverse();
|
// r0.result.path.reverse();
|
||||||
return r0;
|
return r0;
|
||||||
}
|
}
|
||||||
let r1 = await _findPathAsync(start, goal);
|
let r1 = await _findPathAsync(start, goal);
|
||||||
|
@ -17,10 +17,10 @@ const WorldChunksStorage = new Map();
|
|||||||
|
|
||||||
/* #### REWRITE PART START ####*/
|
/* #### REWRITE PART START ####*/
|
||||||
const terrainSpriteList = {
|
const terrainSpriteList = {
|
||||||
0: { x: 21, y: 21 }, //water
|
0: { x: 20, y: 20 }, //water
|
||||||
1: { x: 2, y: 21 }, //sand
|
1: { x: 2, y: 20 }, //sand
|
||||||
2: { x: 2, y: 2 }, //grass
|
2: { x: 2, y: 2 }, //grass
|
||||||
3: { x: 21, y: 2 }, //stone
|
3: { x: 20, y: 2 }, //stone
|
||||||
};
|
};
|
||||||
const terrainTypeList = {
|
const terrainTypeList = {
|
||||||
0: "ter_water", //water
|
0: "ter_water", //water
|
||||||
@ -30,9 +30,9 @@ const terrainTypeList = {
|
|||||||
};
|
};
|
||||||
const terrainNavigationCostList = {
|
const terrainNavigationCostList = {
|
||||||
0: 100000000000, //water
|
0: 100000000000, //water
|
||||||
1: 3, //sand
|
1: 1.7, //sand
|
||||||
2: 2, //grass
|
2: 1, //grass
|
||||||
3: 1, //stone
|
3: 1.5, //stone
|
||||||
};
|
};
|
||||||
const grassVegetationSpriteList = {
|
const grassVegetationSpriteList = {
|
||||||
0: { x: 10, y: 11 },
|
0: { x: 10, y: 11 },
|
||||||
|
Loading…
x
Reference in New Issue
Block a user