mirror of
https://github.com/genxium/DelayNoMore
synced 2026-04-02 11:23:15 +00:00
Initial commit.
This commit is contained in:
471
frontend/assets/scripts/BasePlayer.js
Normal file
471
frontend/assets/scripts/BasePlayer.js
Normal file
@@ -0,0 +1,471 @@
|
||||
module.export = cc.Class({
|
||||
extends: cc.Component,
|
||||
|
||||
properties: {
|
||||
animComp: {
|
||||
type: cc.Animation,
|
||||
default: null,
|
||||
},
|
||||
baseSpeed: {
|
||||
type: cc.Float,
|
||||
default: 300,
|
||||
},
|
||||
speed: {
|
||||
type: cc.Float,
|
||||
default: 300
|
||||
},
|
||||
lastMovedAt: {
|
||||
type: cc.Float,
|
||||
default: 0 // In "GMT milliseconds"
|
||||
},
|
||||
eps: {
|
||||
default: 0.10,
|
||||
type: cc.Float
|
||||
},
|
||||
magicLeanLowerBound: {
|
||||
default: 0.414, // Tangent of (PI/8).
|
||||
type: cc.Float
|
||||
},
|
||||
magicLeanUpperBound: {
|
||||
default: 2.414, // Tangent of (3*PI/8).
|
||||
type: cc.Float
|
||||
},
|
||||
},
|
||||
|
||||
// LIFE-CYCLE CALLBACKS:
|
||||
start() {
|
||||
const self = this;
|
||||
self.contactedControlledPlayers = [];
|
||||
self.contactedNPCPlayers = [];
|
||||
self.coveringShelterZReducers = [];
|
||||
|
||||
self.computedNewDifferentPosLocalToParentWithinCurrentFrame = null;
|
||||
self.actionMangerSingleton = new cc.ActionManager();
|
||||
self.scheduledDirection = {
|
||||
dx: 0,
|
||||
dy: 0
|
||||
};
|
||||
|
||||
self.activeDirection = {
|
||||
dx: 0,
|
||||
dy: 0
|
||||
};
|
||||
},
|
||||
|
||||
onLoad() {
|
||||
const self = this;
|
||||
self.clips = {
|
||||
'01': 'Top',
|
||||
'0-1': 'Bottom',
|
||||
'-20': 'Left',
|
||||
'20': 'Right',
|
||||
'-21': 'TopLeft',
|
||||
'21': 'TopRight',
|
||||
'-2-1': 'BottomLeft',
|
||||
'2-1': 'BottomRight'
|
||||
};
|
||||
const canvasNode = self.mapNode.parent;
|
||||
self.contactedBarriers = [];
|
||||
const joystickInputControllerScriptIns = canvasNode.getComponent("TouchEventsManager");
|
||||
self.ctrl = joystickInputControllerScriptIns;
|
||||
self.animComp = self.node.getComponent(cc.Animation);
|
||||
self.animComp.play();
|
||||
},
|
||||
|
||||
scheduleNewDirection(newScheduledDirection, forceAnimSwitch) {
|
||||
if (!newScheduledDirection) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (forceAnimSwitch || null == this.scheduledDirection || (newScheduledDirection.dx != this.scheduledDirection.dx || newScheduledDirection.dy != this.scheduledDirection.dy)) {
|
||||
this.scheduledDirection = newScheduledDirection;
|
||||
const clipKey = newScheduledDirection.dx.toString() + newScheduledDirection.dy.toString();
|
||||
const clips = (this.attacked ? this.attackedClips : this.clips);
|
||||
let clip = clips[clipKey];
|
||||
if (!clip) {
|
||||
// Keep playing the current anim.
|
||||
if (0 !== newScheduledDirection.dx || 0 !== newScheduledDirection.dy) {
|
||||
cc.warn('Clip for clipKey === ' + clipKey + ' is invalid: ' + clip + '.');
|
||||
}
|
||||
} else {
|
||||
this.animComp.play(clip);
|
||||
if (this.attacked) {
|
||||
cc.log(`Attacked, switching to play clipKey = ${clipKey}, clip == ${clip}, this.activeDirection == ${JSON.stringify(this.activeDirection)}, this.scheduledDirection == ${JSON.stringify(this.scheduledDirection)}.`);
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
_addCoveringShelterZReducer(comp) {
|
||||
const self = this;
|
||||
for (let coveringShelterZReducer of self.coveringShelterZReducers) {
|
||||
if (coveringShelterZReducer._id == comp._id) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
self.coveringShelterZReducers.push(comp);
|
||||
return true;
|
||||
},
|
||||
|
||||
_removeCoveringShelterZReducer(comp) {
|
||||
const self = this;
|
||||
self.coveringShelterZReducers = self.coveringShelterZReducers.filter((coveringShelterZReducer) => {
|
||||
return coveringShelterZReducer._id != comp._id;
|
||||
});
|
||||
return true;
|
||||
},
|
||||
|
||||
_addContactedBarrier(collider) {
|
||||
const self = this;
|
||||
if (!self.contactedBarriers) {
|
||||
cc.log("self.contactedBarriers is null or undefined" + self.contactedBarriers)
|
||||
}
|
||||
for (let contactedBarrier of self.contactedBarriers) {
|
||||
if (contactedBarrier._id == collider._id) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
self.contactedBarriers.push(collider);
|
||||
return true;
|
||||
},
|
||||
|
||||
_removeContactedBarrier(collider) {
|
||||
const self = this;
|
||||
self.contactedBarriers = self.contactedBarriers.filter((contactedBarrier) => {
|
||||
return contactedBarrier._id != collider._id;
|
||||
});
|
||||
return true;
|
||||
},
|
||||
|
||||
_addContactedControlledPlayers(comp) {
|
||||
const self = this;
|
||||
for (let aComp of self.contactedControlledPlayers) {
|
||||
if (aComp.uuid == comp.uuid) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
self.contactedControlledPlayers.push(comp);
|
||||
return true;
|
||||
},
|
||||
|
||||
_removeContactedControlledPlayer(comp) {
|
||||
const self = this;
|
||||
self.contactedControlledPlayers = self.contactedControlledPlayers.filter((aComp) => {
|
||||
return aComp.uuid != comp.uuid;
|
||||
});
|
||||
return true;
|
||||
},
|
||||
|
||||
_addContactedNPCPlayers(comp) {
|
||||
const self = this;
|
||||
for (let aComp of self.contactedNPCPlayers) {
|
||||
if (aComp.uuid == comp.uuid) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
self.contactedNPCPlayers.push(comp);
|
||||
return true;
|
||||
},
|
||||
|
||||
_removeContactedNPCPlayer(comp) {
|
||||
const self = this;
|
||||
self.contactedNPCPlayers = self.contactedNPCPlayers.filter((aComp) => {
|
||||
return aComp.uuid != comp.uuid;
|
||||
});
|
||||
return true;
|
||||
},
|
||||
|
||||
_canMoveBy(vecToMoveBy) {
|
||||
const self = this;
|
||||
const computedNewDifferentPosLocalToParentWithinCurrentFrame = self.node.position.add(vecToMoveBy);
|
||||
self.computedNewDifferentPosLocalToParentWithinCurrentFrame = computedNewDifferentPosLocalToParentWithinCurrentFrame;
|
||||
|
||||
if (tileCollisionManager.isOutOfMapNode(self.mapNode, computedNewDifferentPosLocalToParentWithinCurrentFrame)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const currentSelfColliderCircle = self.node.getComponent(cc.CircleCollider);
|
||||
let nextSelfColliderCircle = null;
|
||||
if (0 < self.contactedBarriers.length) {
|
||||
/* To avoid unexpected buckling. */
|
||||
const mutatedVecToMoveBy = vecToMoveBy.mul(5); // To help it escape the engaged `contactedBarriers`.
|
||||
nextSelfColliderCircle = {
|
||||
position: self.node.position.add(mutatedVecToMoveBy).add(currentSelfColliderCircle.offset),
|
||||
radius: currentSelfColliderCircle.radius,
|
||||
};
|
||||
} else {
|
||||
nextSelfColliderCircle = {
|
||||
position: computedNewDifferentPosLocalToParentWithinCurrentFrame.add(currentSelfColliderCircle.offset),
|
||||
radius: currentSelfColliderCircle.radius,
|
||||
};
|
||||
}
|
||||
|
||||
for (let contactedBarrier of self.contactedBarriers) {
|
||||
let contactedBarrierPolygonLocalToParentWithinCurrentFrame = [];
|
||||
for (let p of contactedBarrier.points) {
|
||||
contactedBarrierPolygonLocalToParentWithinCurrentFrame.push(contactedBarrier.node.position.add(p));
|
||||
}
|
||||
if (cc.Intersection.pointInPolygon(nextSelfColliderCircle.position, contactedBarrierPolygonLocalToParentWithinCurrentFrame)) {
|
||||
// Make sure that the player is "leaving" the PolygonCollider.
|
||||
return false;
|
||||
}
|
||||
if (cc.Intersection.polygonCircle(contactedBarrierPolygonLocalToParentWithinCurrentFrame, nextSelfColliderCircle)) {
|
||||
if (null == self.firstContactedEdge) {
|
||||
return false;
|
||||
}
|
||||
if (null != self.firstContactedEdge && self.firstContactedEdge.associatedBarrier != contactedBarrier) {
|
||||
const res = self._calculateTangentialMovementAttrs(nextSelfColliderCircle, contactedBarrier);
|
||||
if (null == res.contactedEdge) {
|
||||
// Otherwise, the current movement is going to transit smoothly onto the next PolygonCollider.
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
/*
|
||||
* In a subclass, use
|
||||
*
|
||||
* _canMoveBy(vecToMoveBy) {
|
||||
* BasePlayer.prototype._canMoveBy.call(this, vecToMoveBy);
|
||||
* // Customized codes.
|
||||
* }
|
||||
*
|
||||
* Reference http://www.cocos2d-x.org/docs/creator/manual/en/scripting/reference/class.html#override
|
||||
*/
|
||||
},
|
||||
|
||||
_calculateTangentialMovementAttrs(currentSelfColliderCircle, contactedBarrier) {
|
||||
/*
|
||||
* Theoretically when the `contactedBarrier` is a convex polygon and the `PlayerCollider` is a circle, there can be only 1 `contactedEdge` for each `contactedBarrier`. Except only for around the corner.
|
||||
*
|
||||
* We should avoid the possibility of players hitting the "corners of convex polygons" by map design wherever & whenever possible.
|
||||
*
|
||||
*/
|
||||
const self = this;
|
||||
const sDir = self.activeDirection;
|
||||
const currentSelfColliderCircleCentrePos = (currentSelfColliderCircle.position ? currentSelfColliderCircle.position : self.node.position.add(currentSelfColliderCircle.offset));
|
||||
const currentSelfColliderCircleRadius = currentSelfColliderCircle.radius;
|
||||
let contactedEdgeCandidateList = [];
|
||||
let skinDepthThreshold = 0.45*currentSelfColliderCircleRadius;
|
||||
for (let i = 0; i < contactedBarrier.points.length; ++i) {
|
||||
const stPoint = contactedBarrier.points[i].add(contactedBarrier.offset).add(contactedBarrier.node.position);
|
||||
const edPoint = (i == contactedBarrier.points.length - 1 ? contactedBarrier.points[0].add(contactedBarrier.offset).add(contactedBarrier.node.position) : contactedBarrier.points[1 + i].add(contactedBarrier.offset).add(contactedBarrier.node.position));
|
||||
const tmpVSt = stPoint.sub(currentSelfColliderCircleCentrePos);
|
||||
const tmpVEd = edPoint.sub(currentSelfColliderCircleCentrePos);
|
||||
const crossProdScalar = tmpVSt.cross(tmpVEd);
|
||||
if (0 < crossProdScalar) {
|
||||
// If moving parallel along `st <-> ed`, the trajectory of `currentSelfColliderCircleCentrePos` will cut inside the polygon.
|
||||
continue;
|
||||
}
|
||||
const dis = cc.Intersection.pointLineDistance(currentSelfColliderCircleCentrePos, stPoint, edPoint, true);
|
||||
if (dis > currentSelfColliderCircleRadius) continue;
|
||||
if (dis < skinDepthThreshold) continue;
|
||||
contactedEdgeCandidateList.push({
|
||||
st: stPoint,
|
||||
ed: edPoint,
|
||||
associatedBarrier: contactedBarrier,
|
||||
});
|
||||
}
|
||||
let contactedEdge = null;
|
||||
let contactedEdgeDir = null;
|
||||
let largestInnerProdAbs = Number.MIN_VALUE;
|
||||
|
||||
if (0 < contactedEdgeCandidateList.length) {
|
||||
const sDirMag = Math.sqrt(sDir.dx * sDir.dx + sDir.dy * sDir.dy);
|
||||
for (let contactedEdgeCandidate of contactedEdgeCandidateList) {
|
||||
const tmp = contactedEdgeCandidate.ed.sub(contactedEdgeCandidate.st);
|
||||
const contactedEdgeDirCandidate = {
|
||||
dx: tmp.x,
|
||||
dy: tmp.y,
|
||||
};
|
||||
const contactedEdgeDirCandidateMag = Math.sqrt(contactedEdgeDirCandidate.dx * contactedEdgeDirCandidate.dx + contactedEdgeDirCandidate.dy * contactedEdgeDirCandidate.dy);
|
||||
const innerDotProd = (sDir.dx * contactedEdgeDirCandidate.dx + sDir.dy * contactedEdgeDirCandidate.dy)/(sDirMag * contactedEdgeDirCandidateMag);
|
||||
const innerDotProdThresholdMag = 0.7;
|
||||
if ((0 > innerDotProd && innerDotProd > -innerDotProdThresholdMag) || (0 < innerDotProd && innerDotProd < innerDotProdThresholdMag)) {
|
||||
// Intentionally left blank, in this case the player is trying to escape from the `contactedEdge`.
|
||||
continue;
|
||||
} else if (innerDotProd > 0) {
|
||||
const abs = Math.abs(innerDotProd);
|
||||
if (abs > largestInnerProdAbs) {
|
||||
contactedEdgeDir = contactedEdgeDirCandidate;
|
||||
contactedEdge = contactedEdgeCandidate;
|
||||
}
|
||||
} else {
|
||||
const abs = Math.abs(innerDotProd);
|
||||
if (abs > largestInnerProdAbs) {
|
||||
contactedEdgeDir = {
|
||||
dx: -contactedEdgeDirCandidate.dx,
|
||||
dy: -contactedEdgeDirCandidate.dy,
|
||||
};
|
||||
contactedEdge = contactedEdgeCandidate;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return {
|
||||
contactedEdgeDir: contactedEdgeDir,
|
||||
contactedEdge: contactedEdge,
|
||||
};
|
||||
},
|
||||
|
||||
_calculateVecToMoveByWithChosenDir(elapsedTime, sDir) {
|
||||
if (0 == sDir.dx && 0 == sDir.dy) {
|
||||
return cc.v2();
|
||||
}
|
||||
const self = this;
|
||||
const distanceToMove = (self.speed * elapsedTime);
|
||||
const denominator = Math.sqrt(sDir.dx * sDir.dx + sDir.dy * sDir.dy);
|
||||
const unitProjDx = (sDir.dx / denominator);
|
||||
const unitProjDy = (sDir.dy / denominator);
|
||||
return cc.v2(
|
||||
distanceToMove * unitProjDx,
|
||||
distanceToMove * unitProjDy,
|
||||
);
|
||||
},
|
||||
|
||||
_calculateVecToMoveBy(elapsedTime) {
|
||||
const self = this;
|
||||
// Note that `sDir` used in this method MUST BE a copy in RAM.
|
||||
let sDir = {
|
||||
dx: self.activeDirection.dx,
|
||||
dy: self.activeDirection.dy,
|
||||
};
|
||||
|
||||
if (0 == sDir.dx && 0 == sDir.dy) {
|
||||
return cc.v2();
|
||||
}
|
||||
|
||||
self.firstContactedEdge = null; // Reset everytime (temporary algorithm design, might change later).
|
||||
if (0 < self.contactedBarriers.length) {
|
||||
/*
|
||||
* Hardcoded to take care of only the 1st `contactedEdge` of the 1st `contactedBarrier` for now. Each `contactedBarrier` must be "counterclockwisely convex polygonal", otherwise sliding doesn't work!
|
||||
*
|
||||
*/
|
||||
const contactedBarrier = self.contactedBarriers[0];
|
||||
const currentSelfColliderCircle = self.node.getComponent(cc.CircleCollider);
|
||||
const res = self._calculateTangentialMovementAttrs(currentSelfColliderCircle, contactedBarrier);
|
||||
if (res.contactedEdge) {
|
||||
self.firstContactedEdge = res.contactedEdge;
|
||||
sDir = res.contactedEdgeDir;
|
||||
}
|
||||
}
|
||||
return self._calculateVecToMoveByWithChosenDir(elapsedTime, sDir);
|
||||
},
|
||||
|
||||
update(dt) {
|
||||
const self = this;
|
||||
const vecToMoveBy = self._calculateVecToMoveBy(dt);
|
||||
// console.log("activeDirection=", self.activeDirection, "vecToMoveBy=", vecToMoveBy, ", computedNewDifferentPosLocalToParentWithinCurrentFrame=", self.computedNewDifferentPosLocalToParentWithinCurrentFrame);
|
||||
if (self._canMoveBy(vecToMoveBy)) {
|
||||
self.node.position = self.computedNewDifferentPosLocalToParentWithinCurrentFrame;
|
||||
}
|
||||
},
|
||||
|
||||
lateUpdate(dt) {
|
||||
const self = this;
|
||||
self.activeDirection.dx = self.scheduledDirection.dx;
|
||||
self.activeDirection.dy = self.scheduledDirection.dy;
|
||||
const now = new Date().getTime();
|
||||
self.lastMovedAt = now;
|
||||
},
|
||||
|
||||
onCollisionEnter(other, self) {
|
||||
const playerScriptIns = self.node.getComponent("SelfPlayer");
|
||||
switch (other.node.name) {
|
||||
case "NPCPlayer":
|
||||
if ("NPCPlayer" != self.node.name) {
|
||||
other.node.getComponent('NPCPlayer').showProfileTrigger();
|
||||
}
|
||||
playerScriptIns._addContactedNPCPlayers(other);
|
||||
break;
|
||||
case "PolygonBoundaryBarrier":
|
||||
playerScriptIns._addContactedBarrier(other);
|
||||
break;
|
||||
case "PolygonBoundaryShelter":
|
||||
break;
|
||||
case "PolygonBoundaryShelterZReducer":
|
||||
playerScriptIns._addCoveringShelterZReducer(other);
|
||||
if (1 == playerScriptIns.coveringShelterZReducers.length) {
|
||||
setLocalZOrder(self.node, 2);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
},
|
||||
|
||||
onCollisionStay(other, self) {
|
||||
// TBD.
|
||||
},
|
||||
|
||||
onCollisionExit(other, self) {
|
||||
const playerScriptIns = self.getComponent("SelfPlayer");
|
||||
switch (other.node.name) {
|
||||
case "NPCPlayer":
|
||||
other.node.getComponent('NPCPlayer').hideProfileTrigger();
|
||||
playerScriptIns._removeContactedNPCPlayer(other);
|
||||
break;
|
||||
case "PolygonBoundaryBarrier":
|
||||
playerScriptIns._removeContactedBarrier(other);
|
||||
break;
|
||||
case "PolygonBoundaryShelter":
|
||||
break;
|
||||
case "PolygonBoundaryShelterZReducer":
|
||||
playerScriptIns._removeCoveringShelterZReducer(other);
|
||||
if (0 == playerScriptIns.coveringShelterZReducers.length) {
|
||||
setLocalZOrder(self.node, 5);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
},
|
||||
|
||||
_generateRandomDirection() {
|
||||
return ALL_DISCRETE_DIRECTIONS_CLOCKWISE[Math.floor(Math.random() * ALL_DISCRETE_DIRECTIONS_CLOCKWISE.length)];
|
||||
},
|
||||
|
||||
_generateRandomDirectionExcluding(toExcludeDx, toExcludeDy) {
|
||||
let randomDirectionList = [];
|
||||
let exactIdx = null;
|
||||
for (let ii = 0; ii < ALL_DISCRETE_DIRECTIONS_CLOCKWISE.length; ++ii) {
|
||||
if (toExcludeDx != ALL_DISCRETE_DIRECTIONS_CLOCKWISE[ii].dx || toExcludeDy != ALL_DISCRETE_DIRECTIONS_CLOCKWISE[ii].dy) continue;
|
||||
exactIdx = ii;
|
||||
break;
|
||||
}
|
||||
if (null == exactIdx) {
|
||||
return this._generateRandomDirection();
|
||||
}
|
||||
|
||||
for (let ii = 0; ii < ALL_DISCRETE_DIRECTIONS_CLOCKWISE.length; ++ii) {
|
||||
if (ii == exactIdx || ((ii - 1) % ALL_DISCRETE_DIRECTIONS_CLOCKWISE.length) == exactIdx || ((ii + 1) % ALL_DISCRETE_DIRECTIONS_CLOCKWISE.length) == exactIdx) continue;
|
||||
randomDirectionList.push(ALL_DISCRETE_DIRECTIONS_CLOCKWISE[ii]);
|
||||
}
|
||||
return randomDirectionList[Math.floor(Math.random() * randomDirectionList.length)]
|
||||
},
|
||||
|
||||
updateSpeed(proposedSpeed) {
|
||||
if (0 == proposedSpeed && 0 < this.speed) {
|
||||
this.startFrozenDisplay();
|
||||
}
|
||||
if (0 < proposedSpeed && 0 == this.speed) {
|
||||
this.stopFrozenDisplay();
|
||||
}
|
||||
this.speed = proposedSpeed;
|
||||
},
|
||||
|
||||
startFrozenDisplay() {
|
||||
const self = this;
|
||||
self.attacked = true;
|
||||
self.scheduleNewDirection(self.scheduledDirection, true);
|
||||
},
|
||||
|
||||
stopFrozenDisplay() {
|
||||
const self = this;
|
||||
self.attacked = false;
|
||||
self.scheduleNewDirection(self.scheduledDirection, true);
|
||||
},
|
||||
});
|
||||
9
frontend/assets/scripts/BasePlayer.js.meta
Normal file
9
frontend/assets/scripts/BasePlayer.js.meta
Normal file
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"ver": "1.0.5",
|
||||
"uuid": "2fa4ffbb-5654-4c7a-b7f3-a27d1303b019",
|
||||
"isPlugin": false,
|
||||
"loadPluginInWeb": true,
|
||||
"loadPluginInNative": true,
|
||||
"loadPluginInEditor": false,
|
||||
"subMetas": {}
|
||||
}
|
||||
201
frontend/assets/scripts/Bullet.js
Normal file
201
frontend/assets/scripts/Bullet.js
Normal file
@@ -0,0 +1,201 @@
|
||||
module.export = cc.Class({
|
||||
extends: cc.Component,
|
||||
|
||||
properties: {
|
||||
localIdInBattle: {
|
||||
default: null,
|
||||
},
|
||||
linearSpeed: {
|
||||
default: 0.0,
|
||||
},
|
||||
},
|
||||
|
||||
ctor() {
|
||||
this.ctrl = null;
|
||||
this.activeDirection = null;
|
||||
},
|
||||
|
||||
onLoad() {
|
||||
},
|
||||
|
||||
_calculateVecToMoveByWithChosenDir(elapsedTime, sDir) {
|
||||
if (0 == sDir.dx && 0 == sDir.dy) {
|
||||
return cc.v2();
|
||||
}
|
||||
const self = this;
|
||||
const distanceToMove = (self.linearSpeed * elapsedTime);
|
||||
const denominator = Math.sqrt(sDir.dx * sDir.dx + sDir.dy * sDir.dy);
|
||||
const unitProjDx = (sDir.dx / denominator);
|
||||
const unitProjDy = (sDir.dy / denominator);
|
||||
return cc.v2(
|
||||
distanceToMove * unitProjDx,
|
||||
distanceToMove * unitProjDy,
|
||||
);
|
||||
},
|
||||
|
||||
_calculateVecToMoveBy(elapsedTime) {
|
||||
const self = this;
|
||||
if (null == self.activeDirection) {
|
||||
return null;
|
||||
}
|
||||
// Note that `sDir` used in this method MUST BE a copy in RAM.
|
||||
let sDir = {
|
||||
dx: self.activeDirection.dx,
|
||||
dy: self.activeDirection.dy,
|
||||
};
|
||||
|
||||
if (0 == sDir.dx && 0 == sDir.dy) {
|
||||
return cc.v2();
|
||||
}
|
||||
|
||||
return self._calculateVecToMoveByWithChosenDir(elapsedTime, sDir);
|
||||
},
|
||||
|
||||
_canMoveBy(vecToMoveBy) {
|
||||
return true;
|
||||
},
|
||||
|
||||
update(dt) {
|
||||
// Used only for EXTRAPOLATING the position of this bullet. The position might be corrected within `setData` as well.
|
||||
const self = this;
|
||||
if (null != self.bulletMaxDist) {
|
||||
const dxMoved = self.node.position.x - self.startAtPoint.x;
|
||||
const dyMoved = self.node.position.y - self.startAtPoint.y;
|
||||
const distanceMoved = Math.sqrt(dxMoved * dxMoved + dyMoved * dyMoved)
|
||||
self.node.opacity = 255*(1 - distanceMoved/self.bulletMaxDist);
|
||||
}
|
||||
|
||||
const vecToMoveBy = self._calculateVecToMoveBy(dt);
|
||||
if (null == vecToMoveBy) {
|
||||
return;
|
||||
}
|
||||
if (self._canMoveBy(vecToMoveBy)) {
|
||||
self.node.position = self.node.position.add(vecToMoveBy);
|
||||
}
|
||||
},
|
||||
|
||||
_calculateAngle(dx, dy) {
|
||||
if (dx == 0) {
|
||||
if (dy > 0) {
|
||||
return 90;
|
||||
}
|
||||
if (dy < 0) {
|
||||
return -90;
|
||||
}
|
||||
}
|
||||
|
||||
if (dx > 0) {
|
||||
if (dy == 0) {
|
||||
return 0;
|
||||
}
|
||||
if (dy > 0) {
|
||||
return 45;
|
||||
}
|
||||
if (dy < 0) {
|
||||
return -45;
|
||||
}
|
||||
}
|
||||
|
||||
if (dx < 0) {
|
||||
if (dy == 0) {
|
||||
return 180;
|
||||
}
|
||||
if (dy > 0) {
|
||||
return 135;
|
||||
}
|
||||
if (dy < 0) {
|
||||
return -135;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
},
|
||||
|
||||
setData(bulletLocalIdInBattle, bulletInfo, dtFromMapUpdate) {
|
||||
const targetNode = this.node;
|
||||
|
||||
if (true == bulletInfo.removed) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (null == bulletInfo.startAtPoint || null == bulletInfo.endAtPoint) {
|
||||
console.error(`Init bullet direction error, startAtPoint:${bulletInfo.startAtPoint}, endAtPoint:${bulletInfo.endAtPoint}`);
|
||||
return false;
|
||||
}
|
||||
|
||||
this.localIdInBattle = bulletLocalIdInBattle;
|
||||
this.linearSpeed = bulletInfo.linearSpeed * 1000000000; // The `bullet.LinearSpeed` on server-side is denoted in pts/nanoseconds.
|
||||
|
||||
const dx = bulletInfo.endAtPoint.x - bulletInfo.startAtPoint.x;
|
||||
const dy = bulletInfo.endAtPoint.y - bulletInfo.startAtPoint.y;
|
||||
|
||||
const discretizedDir = this.ctrl.discretizeDirection(dx, dy, this.ctrl.joyStickEps);
|
||||
const baseAngle = 0;
|
||||
const angleToRotate = baseAngle - this._calculateAngle(discretizedDir.dx, discretizedDir.dy);
|
||||
if (null == angleToRotate) {
|
||||
return false;
|
||||
}
|
||||
set2dRotation(targetNode, angleToRotate);
|
||||
|
||||
const newPos = cc.v2(
|
||||
bulletInfo.x,
|
||||
bulletInfo.y
|
||||
);
|
||||
|
||||
if (null == this.activeDirection) {
|
||||
// Initialization.
|
||||
this.startAtPoint = bulletInfo.startAtPoint;
|
||||
this.endAtPoint = bulletInfo.endAtPoint;
|
||||
this.bulletMaxDist = 600.0; // Hardcoded temporarily, matching that in "<backend>/models/room.go". -- YFLu, 2019-09-05.
|
||||
targetNode.setPosition(newPos);
|
||||
this.activeDirection = {
|
||||
dx: 0,
|
||||
dy: 0,
|
||||
};
|
||||
return true;
|
||||
}
|
||||
|
||||
const oldPos = cc.v2(
|
||||
targetNode.x,
|
||||
targetNode.y,
|
||||
);
|
||||
const toMoveByVec = newPos.sub(oldPos);
|
||||
const toMoveByVecMag = toMoveByVec.mag();
|
||||
const toTeleportDisThreshold = (this.linearSpeed * dtFromMapUpdate * 100);
|
||||
const notToMoveDisThreshold = (this.linearSpeed * dtFromMapUpdate * 0.5);
|
||||
if (toMoveByVecMag < notToMoveDisThreshold) {
|
||||
// To stop extrapolated moving.
|
||||
this.activeDirection = {
|
||||
dx: 0,
|
||||
dy: 0,
|
||||
};
|
||||
} else {
|
||||
if (toMoveByVecMag > toTeleportDisThreshold) {
|
||||
console.log("Bullet ", bulletLocalIdInBattle, " is teleporting! Having toMoveByVecMag == ", toMoveByVecMag, ", toTeleportDisThreshold == ", toTeleportDisThreshold);
|
||||
// To stop extrapolated moving.
|
||||
this.activeDirection = {
|
||||
dx: 0,
|
||||
dy: 0
|
||||
};
|
||||
// Deliberately NOT using `cc.Action`. -- YFLu, 2019-09-04
|
||||
targetNode.setPosition(newPos);
|
||||
} else {
|
||||
// The common case which is suitable for interpolation.
|
||||
const normalizedDir = {
|
||||
dx: toMoveByVec.x / toMoveByVecMag,
|
||||
dy: toMoveByVec.y / toMoveByVecMag,
|
||||
};
|
||||
if (isNaN(normalizedDir.dx) || isNaN(normalizedDir.dy)) {
|
||||
this.activeDirection = {
|
||||
dx: 0,
|
||||
dy: 0,
|
||||
};
|
||||
} else {
|
||||
this.activeDirection = normalizedDir;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
},
|
||||
});
|
||||
9
frontend/assets/scripts/Bullet.js.meta
Normal file
9
frontend/assets/scripts/Bullet.js.meta
Normal file
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"ver": "1.0.5",
|
||||
"uuid": "ea965d25-ec82-478c-bdb2-9ac07981ab0e",
|
||||
"isPlugin": false,
|
||||
"loadPluginInWeb": true,
|
||||
"loadPluginInNative": true,
|
||||
"loadPluginInEditor": false,
|
||||
"subMetas": {}
|
||||
}
|
||||
31
frontend/assets/scripts/CameraTracker.js
Normal file
31
frontend/assets/scripts/CameraTracker.js
Normal file
@@ -0,0 +1,31 @@
|
||||
cc.Class({
|
||||
extends: cc.Component,
|
||||
|
||||
properties: {
|
||||
mapNode: {
|
||||
type: cc.Node,
|
||||
default: null
|
||||
},
|
||||
|
||||
},
|
||||
|
||||
onLoad () {
|
||||
this.mainCamera = this.mapNode.parent.getChildByName("Main Camera").getComponent(cc.Camera);
|
||||
this.mapScriptIns = this.mapNode.getComponent("Map");
|
||||
},
|
||||
|
||||
start() {},
|
||||
|
||||
update(dt) {
|
||||
const self = this;
|
||||
if (!self.mainCamera) return;
|
||||
if (!self.mapScriptIns) return;
|
||||
if (!self.mapScriptIns.selfPlayerInfo) return;
|
||||
if (!self.mapScriptIns.playerRichInfoDict) return;
|
||||
const selfPlayerRichInfo = self.mapScriptIns.playerRichInfoDict[self.mapScriptIns.selfPlayerInfo.id];
|
||||
if (!selfPlayerRichInfo) return;
|
||||
const selfPlayerNode = selfPlayerRichInfo.node;
|
||||
if (!selfPlayerNode) return;
|
||||
self.mainCamera.node.setPosition(selfPlayerNode.position);
|
||||
}
|
||||
});
|
||||
9
frontend/assets/scripts/CameraTracker.js.meta
Normal file
9
frontend/assets/scripts/CameraTracker.js.meta
Normal file
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"ver": "1.0.5",
|
||||
"uuid": "78830fc7-4e25-49a1-a7fc-9f9d3883f278",
|
||||
"isPlugin": false,
|
||||
"loadPluginInWeb": true,
|
||||
"loadPluginInNative": true,
|
||||
"loadPluginInEditor": false,
|
||||
"subMetas": {}
|
||||
}
|
||||
16
frontend/assets/scripts/Canvas.js
Normal file
16
frontend/assets/scripts/Canvas.js
Normal file
@@ -0,0 +1,16 @@
|
||||
cc.Class({
|
||||
extends: cc.Component,
|
||||
|
||||
properties: {
|
||||
map: {
|
||||
type: cc.Node,
|
||||
default: null
|
||||
}
|
||||
},
|
||||
|
||||
// LIFE-CYCLE CALLBACKS:
|
||||
|
||||
onLoad() {
|
||||
|
||||
}
|
||||
});
|
||||
9
frontend/assets/scripts/Canvas.js.meta
Normal file
9
frontend/assets/scripts/Canvas.js.meta
Normal file
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"ver": "1.0.5",
|
||||
"uuid": "8ac0809b-f98d-4cff-a66c-3bd9e218ecd6",
|
||||
"isPlugin": false,
|
||||
"loadPluginInWeb": true,
|
||||
"loadPluginInNative": true,
|
||||
"loadPluginInEditor": false,
|
||||
"subMetas": {}
|
||||
}
|
||||
29
frontend/assets/scripts/ConfirmLogout.js
Normal file
29
frontend/assets/scripts/ConfirmLogout.js
Normal file
@@ -0,0 +1,29 @@
|
||||
cc.Class({
|
||||
extends: cc.Component,
|
||||
|
||||
properties: {
|
||||
mapNode: {
|
||||
type: cc.Node,
|
||||
default: null,
|
||||
}
|
||||
},
|
||||
|
||||
onButtonClick(event, customData) {
|
||||
const mapScriptIns = this.mapNode.getComponent('Map');
|
||||
switch (customData) {
|
||||
case 'confirm':
|
||||
mapScriptIns.logout.bind(mapScriptIns)(true, false);
|
||||
break;
|
||||
case 'cancel':
|
||||
mapScriptIns.onLogoutConfirmationDismissed.bind(mapScriptIns)();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
},
|
||||
// LIFE-CYCLE CALLBACKS:
|
||||
|
||||
onLoad() {
|
||||
|
||||
}
|
||||
});
|
||||
9
frontend/assets/scripts/ConfirmLogout.js.meta
Normal file
9
frontend/assets/scripts/ConfirmLogout.js.meta
Normal file
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"ver": "1.0.5",
|
||||
"uuid": "e16000cb-4e57-44be-a791-e26298b480bb",
|
||||
"isPlugin": false,
|
||||
"loadPluginInWeb": true,
|
||||
"loadPluginInNative": true,
|
||||
"loadPluginInEditor": false,
|
||||
"subMetas": {}
|
||||
}
|
||||
32
frontend/assets/scripts/CountdownToBeginGame.js
Normal file
32
frontend/assets/scripts/CountdownToBeginGame.js
Normal file
@@ -0,0 +1,32 @@
|
||||
cc.Class({
|
||||
extends: cc.Component,
|
||||
|
||||
properties: {
|
||||
countdownSeconds : {
|
||||
type: cc.Label,
|
||||
default: null
|
||||
},
|
||||
},
|
||||
|
||||
// LIFE-CYCLE CALLBACKS:
|
||||
onLoad() {
|
||||
},
|
||||
|
||||
setData() {
|
||||
this.startedMillis = Date.now();
|
||||
this.durationMillis = 3000;
|
||||
},
|
||||
|
||||
update() {
|
||||
const currentGMTMillis = Date.now();
|
||||
const elapsedMillis = currentGMTMillis - this.startedMillis;
|
||||
let remainingMillis = this.durationMillis - elapsedMillis;
|
||||
if (remainingMillis <= 0) {
|
||||
remainingMillis = 0;
|
||||
}
|
||||
let remaingHint = "" + Math.round(remainingMillis / 1000 );
|
||||
if (remaingHint != this.countdownSeconds.string) {
|
||||
this.countdownSeconds.string = remaingHint;
|
||||
}
|
||||
}
|
||||
});
|
||||
9
frontend/assets/scripts/CountdownToBeginGame.js.meta
Normal file
9
frontend/assets/scripts/CountdownToBeginGame.js.meta
Normal file
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"ver": "1.0.5",
|
||||
"uuid": "6a3d663a-2a2d-418a-a015-48a211770465",
|
||||
"isPlugin": false,
|
||||
"loadPluginInWeb": true,
|
||||
"loadPluginInNative": true,
|
||||
"loadPluginInEditor": false,
|
||||
"subMetas": {}
|
||||
}
|
||||
146
frontend/assets/scripts/FindingPlayer.js
Normal file
146
frontend/assets/scripts/FindingPlayer.js
Normal file
@@ -0,0 +1,146 @@
|
||||
cc.Class({
|
||||
extends: cc.Component,
|
||||
|
||||
properties: {
|
||||
firstPlayerInfoNode: {
|
||||
type: cc.Node,
|
||||
default: null
|
||||
},
|
||||
secondPlayerInfoNode: {
|
||||
type: cc.Node,
|
||||
default: null
|
||||
},
|
||||
findingAnimNode: {
|
||||
type: cc.Node,
|
||||
default: null
|
||||
},
|
||||
myAvatarNode: {
|
||||
type: cc.Node,
|
||||
default: null
|
||||
},
|
||||
exitBtnNode: {
|
||||
type: cc.Node,
|
||||
default: null
|
||||
}
|
||||
},
|
||||
|
||||
// LIFE-CYCLE CALLBACKS:
|
||||
onLoad() {
|
||||
// WARNING: 不能保证在ws连接成功并且拿到boundRoomId后才运行到此处。
|
||||
if (cc.sys.platform == cc.sys.WECHAT_GAME) {
|
||||
const boundRoomId = window.getBoundRoomIdFromPersistentStorage();
|
||||
const wxToShareMessage = {
|
||||
title: '夺宝大作战',
|
||||
imageUrl: 'https://mmocgame.qpic.cn/wechatgame/ibxA6JVNslX02zq6aAWCZiaWTXLYGorrVgUszo3WH1oL1CFDcFU7VKPRXPFiadxagMR/0',
|
||||
imageUrlId: 'FiLZpa5FT5GgEeEagzGBsA',
|
||||
query: 'expectedRoomId=' + boundRoomId,
|
||||
};
|
||||
console.warn("The boundRoomId for sharing: ", boundRoomId, " wxToShareMessage ", wxToShareMessage);
|
||||
wx.showShareMenu();
|
||||
wx.onShareAppMessage(() => (wxToShareMessage));
|
||||
}
|
||||
},
|
||||
|
||||
init() {
|
||||
if (null != this.firstPlayerInfoNode) {
|
||||
this.firstPlayerInfoNode.active = false;
|
||||
}
|
||||
if (null != this.secondPlayerInfoNode) {
|
||||
this.secondPlayerInfoNode.active = false;
|
||||
}
|
||||
this.playersInfoNode = {};
|
||||
Object.assign(this.playersInfoNode, {
|
||||
1: this.firstPlayerInfoNode
|
||||
});
|
||||
Object.assign(this.playersInfoNode, {
|
||||
2: this.secondPlayerInfoNode
|
||||
});
|
||||
|
||||
if (null != this.findingAnimNode) {
|
||||
this.findingAnimNode.active = true;
|
||||
}
|
||||
|
||||
window.firstPlayerInfoNode = this.firstPlayerInfoNode;
|
||||
},
|
||||
|
||||
hideExitButton() {
|
||||
if (null == this.exitBtnNode != null) {
|
||||
return;
|
||||
}
|
||||
this.exitBtnNode.active = false;
|
||||
},
|
||||
|
||||
exitBtnOnClick(evt) {
|
||||
window.clearBoundRoomIdInBothVolatileAndPersistentStorage();
|
||||
window.closeWSConnection();
|
||||
if (cc.sys.platform == cc.sys.WECHAT_GAME) {
|
||||
cc.director.loadScene('wechatGameLogin');
|
||||
} else {
|
||||
cc.director.loadScene('login');
|
||||
}
|
||||
},
|
||||
|
||||
updatePlayersInfo(playerMetas) {
|
||||
if (null == playerMetas) return;
|
||||
for (let i in playerMetas) {
|
||||
const playerMeta = playerMetas[i];
|
||||
const playerInfoNode = this.playersInfoNode[playerMeta.joinIndex];
|
||||
if (null == playerInfoNode) {
|
||||
cc.error("There's no playerInfoNode for joinIndex == ", joinIndex, ", as `this.playerInfoNode` is currently ", this.playersInfoNode);
|
||||
}
|
||||
playerInfoNode.active = true;
|
||||
if (2 == playerMeta.joinIndex) {
|
||||
if (null != this.findingAnimNode) {
|
||||
this.findingAnimNode.active = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//显示自己的头像名称以及他人的头像名称
|
||||
for (let i in playerMetas) {
|
||||
const playerMeta = playerMetas[i];
|
||||
console.log("Showing playerMeta:", playerMeta);
|
||||
const playerInfoNode = this.playersInfoNode[playerMeta.joinIndex];
|
||||
|
||||
(() => { //远程加载头像
|
||||
let remoteUrl = playerMeta.avatar;
|
||||
if (remoteUrl == null || remoteUrl == '') {
|
||||
cc.log(`No avatar to show for :`);
|
||||
cc.log(playerMeta);
|
||||
remoteUrl = 'http://wx.qlogo.cn/mmopen/PiajxSqBRaEJUWib5D85KXWHumaxhU4E9XOn9bUpCNKF3F4ibfOj8JYHCiaoosvoXCkTmOQE1r2AKKs8ObMaz76EdA/0'
|
||||
}
|
||||
cc.loader.load({
|
||||
url: remoteUrl,
|
||||
type: 'jpg'
|
||||
}, function(err, texture) {
|
||||
if (null != err ) {
|
||||
console.error(err);
|
||||
} else {
|
||||
if (null == texture) {
|
||||
return;
|
||||
}
|
||||
const sf = new cc.SpriteFrame();
|
||||
sf.setTexture(texture);
|
||||
playerInfoNode.getChildByName('avatarMask').getChildByName('avatar').getComponent(cc.Sprite).spriteFrame = sf;
|
||||
}
|
||||
});
|
||||
})();
|
||||
|
||||
function isEmptyString(str) {
|
||||
return str == null || str == ''
|
||||
}
|
||||
|
||||
const nameNode = playerInfoNode.getChildByName("name");
|
||||
const nameToDisplay = (() => {
|
||||
if (!isEmptyString(playerMeta.displayName)) {
|
||||
return playerMeta.displayName
|
||||
} else if (!isEmptyString(playerMeta.name)) {
|
||||
return playerMeta.name
|
||||
} else {
|
||||
return ""
|
||||
}
|
||||
})();
|
||||
nameNode.getComponent(cc.Label).string = nameToDisplay;
|
||||
}
|
||||
},
|
||||
});
|
||||
9
frontend/assets/scripts/FindingPlayer.js.meta
Normal file
9
frontend/assets/scripts/FindingPlayer.js.meta
Normal file
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"ver": "1.0.5",
|
||||
"uuid": "ecdd3aad-b601-4f8d-85a1-69d9d270a806",
|
||||
"isPlugin": false,
|
||||
"loadPluginInWeb": true,
|
||||
"loadPluginInNative": true,
|
||||
"loadPluginInEditor": false,
|
||||
"subMetas": {}
|
||||
}
|
||||
24
frontend/assets/scripts/GameRule.js
Normal file
24
frontend/assets/scripts/GameRule.js
Normal file
@@ -0,0 +1,24 @@
|
||||
cc.Class({
|
||||
extends: cc.Component,
|
||||
|
||||
properties: {
|
||||
modeButton: {
|
||||
type: cc.Button,
|
||||
default: null
|
||||
},
|
||||
mapNode: {
|
||||
type: cc.Node,
|
||||
default: null
|
||||
},
|
||||
},
|
||||
|
||||
// LIFE-CYCLE CALLBACKS:
|
||||
onLoad() {
|
||||
const modeBtnClickEventHandler = new cc.Component.EventHandler();
|
||||
modeBtnClickEventHandler.target = this.mapNode;
|
||||
modeBtnClickEventHandler.component = "Map";
|
||||
modeBtnClickEventHandler.handler = "onGameRule1v1ModeClicked";
|
||||
this.modeButton.clickEvents.push(modeBtnClickEventHandler);
|
||||
}
|
||||
|
||||
});
|
||||
9
frontend/assets/scripts/GameRule.js.meta
Normal file
9
frontend/assets/scripts/GameRule.js.meta
Normal file
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"ver": "1.0.5",
|
||||
"uuid": "dd92b295-cbc1-4963-bbaa-de27a8359099",
|
||||
"isPlugin": false,
|
||||
"loadPluginInWeb": true,
|
||||
"loadPluginInNative": true,
|
||||
"loadPluginInEditor": false,
|
||||
"subMetas": {}
|
||||
}
|
||||
243
frontend/assets/scripts/Heap.js
Normal file
243
frontend/assets/scripts/Heap.js
Normal file
@@ -0,0 +1,243 @@
|
||||
/**
|
||||
* Creates a binary heap.
|
||||
*
|
||||
* @constructor
|
||||
* @param {function} customCompare An optional custom node comparison
|
||||
* function.
|
||||
*/
|
||||
var BinaryHeap = function (customCompare) {
|
||||
/**
|
||||
* The backing data of the heap.
|
||||
* @type {Object[]}
|
||||
* @private
|
||||
*/
|
||||
this.list = [];
|
||||
|
||||
if (customCompare) {
|
||||
this.compare = customCompare;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Builds a heap with the provided keys and values, this will discard the
|
||||
* heap's current data.
|
||||
*
|
||||
* @param {Array} keys An array of keys.
|
||||
* @param {Array} values An array of values. This must be the same size as the
|
||||
* key array.
|
||||
*/
|
||||
BinaryHeap.prototype.buildHeap = function (keys, values) {
|
||||
if (typeof values !== 'undefined' && values.length !== keys.length) {
|
||||
throw new Error('Key array must be the same length as value array');
|
||||
}
|
||||
|
||||
var nodeArray = [];
|
||||
|
||||
for (var i = 0; i < keys.length; i++) {
|
||||
nodeArray.push(new Node(keys[i], values ? values[i] : undefined));
|
||||
}
|
||||
|
||||
buildHeapFromNodeArray(this, nodeArray);
|
||||
};
|
||||
|
||||
/**
|
||||
* Clears the heap's data, making it an empty heap.
|
||||
*/
|
||||
BinaryHeap.prototype.clear = function () {
|
||||
this.list.length = 0;
|
||||
};
|
||||
|
||||
/**
|
||||
* Extracts and returns the minimum node from the heap.
|
||||
*
|
||||
* @return {Node} node The heap's minimum node or undefined if the heap is
|
||||
* empty.
|
||||
*/
|
||||
BinaryHeap.prototype.extractMinimum = function () {
|
||||
if (!this.list.length) {
|
||||
return undefined;
|
||||
}
|
||||
if (this.list.length === 1) {
|
||||
return this.list.shift();
|
||||
}
|
||||
var min = this.list[0];
|
||||
this.list[0] = this.list.pop();
|
||||
heapify(this, 0);
|
||||
return min;
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns the minimum node from the heap.
|
||||
*
|
||||
* @return {Node} node The heap's minimum node or undefined if the heap is
|
||||
* empty.
|
||||
*/
|
||||
BinaryHeap.prototype.findMinimum = function () {
|
||||
return this.isEmpty() ? undefined : this.list[0];
|
||||
};
|
||||
|
||||
/**
|
||||
* Inserts a new key-value pair into the heap.
|
||||
*
|
||||
* @param {Object} key The key to insert.
|
||||
* @param {Object} value The value to insert.
|
||||
* @return {Node} node The inserted node.
|
||||
*/
|
||||
BinaryHeap.prototype.insert = function (key, value) {
|
||||
var i = this.list.length;
|
||||
var node = new Node(key, value);
|
||||
this.list.push(node);
|
||||
var parent = getParent(i);
|
||||
while (typeof parent !== 'undefined' &&
|
||||
this.compare(this.list[i], this.list[parent]) < 0) {
|
||||
swap(this.list, i, parent);
|
||||
i = parent;
|
||||
parent = getParent(i);
|
||||
}
|
||||
return node;
|
||||
};
|
||||
|
||||
/**
|
||||
* @return {boolean} Whether the heap is empty.
|
||||
*/
|
||||
BinaryHeap.prototype.isEmpty = function () {
|
||||
return !this.list.length;
|
||||
};
|
||||
|
||||
/**
|
||||
* @return {number} The size of the heap.
|
||||
*/
|
||||
BinaryHeap.prototype.size = function () {
|
||||
return this.list.length;
|
||||
};
|
||||
|
||||
/**
|
||||
* Joins another heap to this one.
|
||||
*
|
||||
* @param {BinaryHeap} otherHeap The other heap.
|
||||
*/
|
||||
BinaryHeap.prototype.union = function (otherHeap) {
|
||||
var array = this.list.concat(otherHeap.list);
|
||||
buildHeapFromNodeArray(this, array);
|
||||
};
|
||||
|
||||
/**
|
||||
* Compares two nodes with each other.
|
||||
*
|
||||
* @private
|
||||
* @param {Object} a The first key to compare.
|
||||
* @param {Object} b The second key to compare.
|
||||
* @return -1, 0 or 1 if a < b, a == b or a > b respectively.
|
||||
*/
|
||||
BinaryHeap.prototype.compare = function (a, b) {
|
||||
if (a.key > b.key) {
|
||||
return 1;
|
||||
}
|
||||
if (a.key < b.key) {
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
};
|
||||
|
||||
/**
|
||||
* Heapifies a node.
|
||||
*
|
||||
* @private
|
||||
* @param {BinaryHeap} heap The heap containing the node to heapify.
|
||||
* @param {number} i The index of the node to heapify.
|
||||
*/
|
||||
function heapify(heap, i) {
|
||||
var l = getLeft(i);
|
||||
var r = getRight(i);
|
||||
var smallest = i;
|
||||
if (l < heap.list.length &&
|
||||
heap.compare(heap.list[l], heap.list[i]) < 0) {
|
||||
smallest = l;
|
||||
}
|
||||
if (r < heap.list.length &&
|
||||
heap.compare(heap.list[r], heap.list[smallest]) < 0) {
|
||||
smallest = r;
|
||||
}
|
||||
if (smallest !== i) {
|
||||
swap(heap.list, i, smallest);
|
||||
heapify(heap, smallest);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds a heap from a node array, this will discard the heap's current data.
|
||||
*
|
||||
* @private
|
||||
* @param {BinaryHeap} heap The heap to override.
|
||||
* @param {Node[]} nodeArray The array of nodes for the new heap.
|
||||
*/
|
||||
function buildHeapFromNodeArray(heap, nodeArray) {
|
||||
heap.list = nodeArray;
|
||||
for (var i = Math.floor(heap.list.length / 2); i >= 0; i--) {
|
||||
heapify(heap, i);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Swaps two values in an array.
|
||||
*
|
||||
* @private
|
||||
* @param {Array} array The array to swap on.
|
||||
* @param {number} a The index of the first element.
|
||||
* @param {number} b The index of the second element.
|
||||
*/
|
||||
function swap(array, a, b) {
|
||||
var temp = array[a];
|
||||
array[a] = array[b];
|
||||
array[b] = temp;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the index of a node's parent.
|
||||
*
|
||||
* @private
|
||||
* @param {number} i The index of the node to get the parent of.
|
||||
* @return {number} The index of the node's parent.
|
||||
*/
|
||||
function getParent(i) {
|
||||
if (i === 0) {
|
||||
return undefined;
|
||||
}
|
||||
return Math.floor((i - 1) / 2);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the index of a node's left child.
|
||||
*
|
||||
* @private
|
||||
* @param {number} i The index of the node to get the left child of.
|
||||
* @return {number} The index of the node's left child.
|
||||
*/
|
||||
function getLeft(i) {
|
||||
return 2 * i + 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the index of a node's right child.
|
||||
*
|
||||
* @private
|
||||
* @param {number} i The index of the node to get the right child of.
|
||||
* @return {number} The index of the node's right child.
|
||||
*/
|
||||
function getRight(i) {
|
||||
return 2 * i + 2;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a node.
|
||||
*
|
||||
* @constructor
|
||||
* @param {Object} key The key of the new node.
|
||||
* @param {Object} value The value of the new node.
|
||||
*/
|
||||
function Node(key, value) {
|
||||
this.key = key;
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
module.exports = BinaryHeap;
|
||||
9
frontend/assets/scripts/Heap.js.meta
Normal file
9
frontend/assets/scripts/Heap.js.meta
Normal file
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"ver": "1.0.5",
|
||||
"uuid": "247b7613-6c6e-4f01-b1d6-5f8f041b5688",
|
||||
"isPlugin": false,
|
||||
"loadPluginInWeb": true,
|
||||
"loadPluginInNative": true,
|
||||
"loadPluginInEditor": false,
|
||||
"subMetas": {}
|
||||
}
|
||||
69
frontend/assets/scripts/KeyboardControls.js
Normal file
69
frontend/assets/scripts/KeyboardControls.js
Normal file
@@ -0,0 +1,69 @@
|
||||
cc.Class({
|
||||
extends: cc.Component,
|
||||
|
||||
properties: {},
|
||||
|
||||
setInputControls: function() {
|
||||
const self = this;
|
||||
// add keyboard event listener
|
||||
// When there is a key being pressed down, judge if it's the designated directional button and set up acceleration in the corresponding direction
|
||||
cc.systemEvent.on(cc.SystemEvent.EventType.KEY_DOWN, function(event) {
|
||||
switch (event.keyCode) {
|
||||
case cc.macro.KEY.w:
|
||||
self.activeDirection.dPjY = +1.0;
|
||||
break;
|
||||
case cc.macro.KEY.s:
|
||||
self.activeDirection.dPjY = -1.0;
|
||||
break;
|
||||
case cc.macro.KEY.a:
|
||||
self.activeDirection.dPjX = -2.0;
|
||||
break;
|
||||
case cc.macro.KEY.d:
|
||||
self.activeDirection.dPjX = +2.0;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}, self.node);
|
||||
|
||||
// when releasing the button, stop acceleration in this direction
|
||||
cc.systemEvent.on(cc.SystemEvent.EventType.KEY_UP, function(event) {
|
||||
switch (event.keyCode) {
|
||||
case cc.macro.KEY.w:
|
||||
if (+1.0 == self.activeDirection.dPjY) {
|
||||
self.activeDirection.dPjY = 0.0;
|
||||
}
|
||||
break;
|
||||
case cc.macro.KEY.s:
|
||||
if (-1.0 == self.activeDirection.dPjY) {
|
||||
self.activeDirection.dPjY = 0.0;
|
||||
}
|
||||
break;
|
||||
case cc.macro.KEY.a:
|
||||
if (-2.0 == self.activeDirection.dPjX) {
|
||||
self.activeDirection.dPjX = 0.0;
|
||||
}
|
||||
break;
|
||||
case cc.macro.KEY.d:
|
||||
if (+2.0 == self.activeDirection.dPjX) {
|
||||
self.activeDirection.dPjX = 0.0;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}, self.node);
|
||||
},
|
||||
|
||||
// LIFE-CYCLE CALLBACKS:
|
||||
|
||||
onLoad() {
|
||||
// Properties deliberately hidden from GUI panel.
|
||||
this.activeDirection = {
|
||||
dPjY: 0.0,
|
||||
dPjX: 0.0
|
||||
};
|
||||
this.setInputControls();
|
||||
}
|
||||
});
|
||||
|
||||
9
frontend/assets/scripts/KeyboardControls.js.meta
Normal file
9
frontend/assets/scripts/KeyboardControls.js.meta
Normal file
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"ver": "1.0.5",
|
||||
"uuid": "4561a173-bfd2-4f64-b7ba-888cce0e4d9d",
|
||||
"isPlugin": false,
|
||||
"loadPluginInWeb": true,
|
||||
"loadPluginInNative": true,
|
||||
"loadPluginInEditor": false,
|
||||
"subMetas": {}
|
||||
}
|
||||
555
frontend/assets/scripts/Login.js
Normal file
555
frontend/assets/scripts/Login.js
Normal file
@@ -0,0 +1,555 @@
|
||||
const i18n = require('LanguageData');
|
||||
i18n.init(window.language); // languageID should be equal to the one we input in New Language ID input field
|
||||
cc.Class({
|
||||
extends: cc.Component,
|
||||
|
||||
properties: {
|
||||
cavasNode: {
|
||||
default: null,
|
||||
type: cc.Node
|
||||
},
|
||||
backgroundNode: {
|
||||
default: null,
|
||||
type: cc.Node
|
||||
},
|
||||
interactiveControls: {
|
||||
default: null,
|
||||
type: cc.Node
|
||||
},
|
||||
phoneLabel: {
|
||||
default: null,
|
||||
type: cc.Node
|
||||
},
|
||||
smsLoginCaptchaLabel: {
|
||||
default: null,
|
||||
type: cc.Node
|
||||
},
|
||||
phoneCountryCodeInput: {
|
||||
default: null,
|
||||
type: cc.Node
|
||||
},
|
||||
phoneNumberInput: {
|
||||
type: cc.Node,
|
||||
default: null
|
||||
},
|
||||
phoneNumberTips: {
|
||||
type: cc.Node,
|
||||
default: null
|
||||
},
|
||||
smsLoginCaptchaInput: {
|
||||
type: cc.Node,
|
||||
default: null
|
||||
},
|
||||
smsLoginCaptchaButton: {
|
||||
type: cc.Node,
|
||||
default: null
|
||||
},
|
||||
captchaTips: {
|
||||
type: cc.Node,
|
||||
default: null
|
||||
},
|
||||
loginButton: {
|
||||
type: cc.Node,
|
||||
default: null
|
||||
},
|
||||
smsWaitCountdownPrefab: {
|
||||
default: null,
|
||||
type: cc.Prefab
|
||||
},
|
||||
loadingPrefab: {
|
||||
default: null,
|
||||
type: cc.Prefab
|
||||
},
|
||||
wechatLoginTips: {
|
||||
default: null,
|
||||
type: cc.Label,
|
||||
},
|
||||
},
|
||||
|
||||
// LIFE-CYCLE CALLBACKS:
|
||||
|
||||
onLoad() {
|
||||
|
||||
//kobako: 腾讯统计代码
|
||||
//WARN: 打包到微信小游戏的时候会导致出错
|
||||
/*
|
||||
(function() {
|
||||
var mta = document.createElement("script");
|
||||
mta.src = "//pingjs.qq.com/h5/stats.js?v2.0.4";
|
||||
mta.setAttribute("name", "MTAH5");
|
||||
mta.setAttribute("sid", "500674632");
|
||||
var s = document.getElementsByTagName("script")[0];
|
||||
s.parentNode.insertBefore(mta, s);
|
||||
})();
|
||||
*/
|
||||
|
||||
window.atFirstLocationHref = window.location.href.split('#')[0];
|
||||
const self = this;
|
||||
self.getRetCodeList();
|
||||
self.getRegexList();
|
||||
|
||||
const isUsingX5BlinkKernelOrWebkitWeChatKernel = window.isUsingX5BlinkKernelOrWebkitWeChatKernel();
|
||||
//const isUsingX5BlinkKernelOrWebkitWeChatKernel = true;
|
||||
if (!CC_DEBUG) {
|
||||
self.phoneNumberTips.active = !isUsingX5BlinkKernelOrWebkitWeChatKernel;
|
||||
self.smsLoginCaptchaButton.active = !isUsingX5BlinkKernelOrWebkitWeChatKernel;
|
||||
|
||||
self.captchaTips.active = !isUsingX5BlinkKernelOrWebkitWeChatKernel;
|
||||
self.phoneCountryCodeInput.active = !isUsingX5BlinkKernelOrWebkitWeChatKernel;
|
||||
self.phoneNumberInput.active = !isUsingX5BlinkKernelOrWebkitWeChatKernel;
|
||||
self.smsLoginCaptchaInput.active = !isUsingX5BlinkKernelOrWebkitWeChatKernel;
|
||||
|
||||
self.phoneLabel.active = !isUsingX5BlinkKernelOrWebkitWeChatKernel;
|
||||
self.smsLoginCaptchaLabel.active = !isUsingX5BlinkKernelOrWebkitWeChatKernel;
|
||||
|
||||
self.loginButton.active = !isUsingX5BlinkKernelOrWebkitWeChatKernel;
|
||||
}
|
||||
self.checkPhoneNumber = self.checkPhoneNumber.bind(self);
|
||||
self.checkIntAuthTokenExpire = self.checkIntAuthTokenExpire.bind(self);
|
||||
self.checkCaptcha = self.checkCaptcha.bind(self);
|
||||
self.onSMSCaptchaGetButtonClicked = self.onSMSCaptchaGetButtonClicked.bind(self);
|
||||
self.smsLoginCaptchaButton.on('click', self.onSMSCaptchaGetButtonClicked);
|
||||
|
||||
self.loadingNode = cc.instantiate(this.loadingPrefab);
|
||||
self.smsGetCaptchaNode = self.smsLoginCaptchaButton.getChildByName('smsGetCaptcha');
|
||||
self.smsWaitCountdownNode = cc.instantiate(self.smsWaitCountdownPrefab);
|
||||
|
||||
const qDict = window.getQueryParamDict();
|
||||
if (null != qDict && qDict["expectedRoomId"]) {
|
||||
window.clearBoundRoomIdInBothVolatileAndPersistentStorage();
|
||||
}
|
||||
|
||||
cc.loader.loadRes("pbfiles/room_downsync_frame", function(err, textAsset /* cc.TextAsset */ ) {
|
||||
if (err) {
|
||||
cc.error(err.message || err);
|
||||
return;
|
||||
}
|
||||
if (false == (cc.sys.platform == cc.sys.WECHAT_GAME)) {
|
||||
// Otherwise, `window.RoomDownsyncFrame` is already assigned.
|
||||
let protoRoot = new protobuf.Root;
|
||||
window.protobuf.parse(textAsset.text, protoRoot);
|
||||
window.RoomDownsyncFrame = protoRoot.lookupType("treasurehunterx.RoomDownsyncFrame");
|
||||
window.BattleColliderInfo = protoRoot.lookupType("treasurehunterx.BattleColliderInfo");
|
||||
window.WsReq = protoRoot.lookupType("treasurehunterx.WsReq");
|
||||
window.WsResp = protoRoot.lookupType("treasurehunterx.WsResp");
|
||||
}
|
||||
self.checkIntAuthTokenExpire().then(
|
||||
() => {
|
||||
const intAuthToken = JSON.parse(cc.sys.localStorage.getItem('selfPlayer')).intAuthToken;
|
||||
self.useTokenLogin(intAuthToken);
|
||||
},
|
||||
() => {
|
||||
window.clearBoundRoomIdInBothVolatileAndPersistentStorage();
|
||||
if ( (CC_DEBUG || isUsingX5BlinkKernelOrWebkitWeChatKernel) ) {
|
||||
if (null != qDict && qDict["code"]) {
|
||||
const code = qDict["code"];
|
||||
console.log("Got the wx authcode: ", code, "while at full url: " + window.location.href);
|
||||
self.useWXCodeLogin(code);
|
||||
} else {
|
||||
if (isUsingX5BlinkKernelOrWebkitWeChatKernel) {
|
||||
self.getWechatCode(null);
|
||||
} else {
|
||||
// Deliberately left blank.
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
||||
});
|
||||
},
|
||||
|
||||
getRetCodeList() {
|
||||
const self = this;
|
||||
self.retCodeDict = constants.RET_CODE;
|
||||
},
|
||||
|
||||
getRegexList() {
|
||||
const self = this;
|
||||
self.regexList = {
|
||||
EMAIL: /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/,
|
||||
PHONE: /^\+?[0-9]{8,14}$/,
|
||||
STREET_META: /^.{5,100}$/,
|
||||
LNG_LAT_TEXT: /^[0-9]+(\.[0-9]{4,6})$/,
|
||||
SEO_KEYWORD: /^.{2,50}$/,
|
||||
PASSWORD: /^.{6,50}$/,
|
||||
SMS_CAPTCHA_CODE: /^[0-9]{4}$/,
|
||||
ADMIN_HANDLE: /^.{4,50}$/,
|
||||
};
|
||||
},
|
||||
|
||||
onSMSCaptchaGetButtonClicked(evt) {
|
||||
var timerEnable = true;
|
||||
const self = this;
|
||||
if (!self.checkPhoneNumber('getCaptcha')) {
|
||||
return;
|
||||
}
|
||||
NetworkUtils.ajax({
|
||||
url: backendAddress.PROTOCOL + '://' + backendAddress.HOST + ':' + backendAddress.PORT + constants.ROUTE_PATH.API + constants.ROUTE_PATH.PLAYER +
|
||||
constants.ROUTE_PATH.VERSION + constants.ROUTE_PATH.SMS_CAPTCHA + constants.ROUTE_PATH.GET,
|
||||
type: 'GET',
|
||||
data: {
|
||||
phoneCountryCode: self.phoneCountryCodeInput.getComponent(cc.EditBox).string,
|
||||
phoneNum: self.phoneNumberInput.getComponent(cc.EditBox).string
|
||||
},
|
||||
success: function(res) {
|
||||
switch (res.ret) {
|
||||
case self.retCodeDict.OK:
|
||||
self.phoneNumberTips.getComponent(cc.Label).string = '';
|
||||
self.captchaTips.getComponent(cc.Label).string = '';
|
||||
break;
|
||||
case self.retCodeDict.DUPLICATED:
|
||||
self.phoneNumberTips.getComponent(cc.Label).string = constants.ALERT.TIP_LABEL.LOG_OUT;
|
||||
break;
|
||||
case self.retCodeDict.INCORRECT_PHONE_COUNTRY_CODE_OR_NUMBER:
|
||||
self.captchaTips.getComponent(cc.Label).string = i18n.t("login.tips.PHONE_ERR");
|
||||
break;
|
||||
case self.retCodeDict.IS_TEST_ACC:
|
||||
self.smsLoginCaptchaInput.getComponent(cc.EditBox).string = res.smsLoginCaptcha;
|
||||
self.captchaTips.getComponent(cc.Label).string = i18n.t("login.tips.TEST_USER");
|
||||
timerEnable = false;
|
||||
// clearInterval(self.countdownTimer);
|
||||
break;
|
||||
case self.retCodeDict.SMS_CAPTCHA_REQUESTED_TOO_FREQUENTLY:
|
||||
self.captchaTips.getComponent(cc.Label).string = i18n.t("login.tips.SMS_CAPTCHA_FREEQUENT_REQUIRE");
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (timerEnable)
|
||||
self.countdownTime(self);
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
countdownTime(self) {
|
||||
self.smsLoginCaptchaButton.off('click', self.onSMSCaptchaGetButtonClicked);
|
||||
self.smsLoginCaptchaButton.removeChild(self.smsGetCaptchaNode);
|
||||
self.smsWaitCountdownNode.parent = self.smsLoginCaptchaButton;
|
||||
var total = 20; // Magic number
|
||||
self.countdownTimer = setInterval(function() {
|
||||
if (total === 0) {
|
||||
self.smsWaitCountdownNode.parent.removeChild(self.smsWaitCountdownNode);
|
||||
self.smsGetCaptchaNode.parent = self.smsLoginCaptchaButton;
|
||||
self.smsWaitCountdownNode.getChildByName('WaitTimeLabel').getComponent(cc.Label).string = 20;
|
||||
self.smsLoginCaptchaButton.on('click', self.onSMSCaptchaGetButtonClicked);
|
||||
clearInterval(self.countdownTimer);
|
||||
} else {
|
||||
total--;
|
||||
self.smsWaitCountdownNode.getChildByName('WaitTimeLabel').getComponent(cc.Label).string = total;
|
||||
}
|
||||
}, 1000)
|
||||
|
||||
},
|
||||
|
||||
checkIntAuthTokenExpire() {
|
||||
return new Promise((resolve, reject) => {
|
||||
if (!cc.sys.localStorage.getItem('selfPlayer')) {
|
||||
reject();
|
||||
return;
|
||||
}
|
||||
const selfPlayer = JSON.parse(cc.sys.localStorage.getItem('selfPlayer'));
|
||||
(selfPlayer.intAuthToken && new Date().getTime() < selfPlayer.expiresAt) ? resolve() : reject();
|
||||
})
|
||||
},
|
||||
|
||||
checkPhoneNumber(type) {
|
||||
const self = this;
|
||||
const phoneNumberRegexp = self.regexList.PHONE;
|
||||
var phoneNumberString = self.phoneNumberInput.getComponent(cc.EditBox).string;
|
||||
if (phoneNumberString) {
|
||||
return true;
|
||||
if (!phoneNumberRegexp.test(phoneNumberString)) {
|
||||
self.captchaTips.getComponent(cc.Label).string = i18n.t("login.tips.PHONE_ERR");
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
if (type === 'getCaptcha' || type === 'login') {
|
||||
self.captchaTips.getComponent(cc.Label).string = i18n.t("login.tips.PHONE_ERR");
|
||||
}
|
||||
return false;
|
||||
}
|
||||
},
|
||||
|
||||
checkCaptcha(type) {
|
||||
const self = this;
|
||||
const captchaRegexp = self.regexList.SMS_CAPTCHA_CODE;
|
||||
var captchaString = self.smsLoginCaptchaInput.getComponent(cc.EditBox).string;
|
||||
|
||||
if (captchaString) {
|
||||
if (self.smsLoginCaptchaInput.getComponent(cc.EditBox).string.length !== 4 || (!captchaRegexp.test(captchaString))) {
|
||||
self.captchaTips.getComponent(cc.Label).string = i18n.t("login.tips.CAPTCHA_ERR");
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
if ('login' == type) {
|
||||
self.captchaTips.getComponent(cc.Label).string = i18n.t("login.tips.CAPTCHA_ERR");
|
||||
}
|
||||
return false;
|
||||
}
|
||||
},
|
||||
|
||||
useTokenLogin(_intAuthToken) {
|
||||
var self = this;
|
||||
NetworkUtils.ajax({
|
||||
url: backendAddress.PROTOCOL + '://' + backendAddress.HOST + ':' + backendAddress.PORT + constants.ROUTE_PATH.API + constants.ROUTE_PATH.PLAYER + constants.ROUTE_PATH.VERSION + constants.ROUTE_PATH.INT_AUTH_TOKEN + constants.ROUTE_PATH.LOGIN,
|
||||
type: "POST",
|
||||
data: {
|
||||
intAuthToken: _intAuthToken
|
||||
},
|
||||
success: function(resp) {
|
||||
self.onLoggedIn(resp);
|
||||
},
|
||||
error: function(xhr, status, errMsg) {
|
||||
console.log("Login attempt `useTokenLogin` failed, about to execute `clearBoundRoomIdInBothVolatileAndPersistentStorage`.");
|
||||
window.clearBoundRoomIdInBothVolatileAndPersistentStorage()
|
||||
},
|
||||
timeout: function() {
|
||||
self.enableInteractiveControls(true);
|
||||
},
|
||||
});
|
||||
},
|
||||
|
||||
enableInteractiveControls(enabled) {
|
||||
this.smsLoginCaptchaButton.getComponent(cc.Button).interactable = enabled;
|
||||
this.loginButton.getComponent(cc.Button).interactable = enabled;
|
||||
this.phoneCountryCodeInput.getComponent(cc.EditBox).enabled = enabled;
|
||||
this.phoneNumberInput.getComponent(cc.EditBox).enabled = enabled;
|
||||
this.smsLoginCaptchaInput.getComponent(cc.EditBox).enabled = enabled;
|
||||
if (enabled) {
|
||||
setVisible(this.interactiveControls);
|
||||
} else {
|
||||
setInvisible(this.interactiveControls);
|
||||
}
|
||||
},
|
||||
|
||||
onLoginButtonClicked(evt) {
|
||||
const self = this;
|
||||
if (!self.checkPhoneNumber('login') || !self.checkCaptcha('login')) {
|
||||
return;
|
||||
}
|
||||
self.loginParams = {
|
||||
phoneCountryCode: self.phoneCountryCodeInput.getComponent(cc.EditBox).string,
|
||||
phoneNum: self.phoneNumberInput.getComponent(cc.EditBox).string,
|
||||
smsLoginCaptcha: self.smsLoginCaptchaInput.getComponent(cc.EditBox).string
|
||||
};
|
||||
self.enableInteractiveControls(false);
|
||||
|
||||
NetworkUtils.ajax({
|
||||
url: backendAddress.PROTOCOL + '://' + backendAddress.HOST + ':' + backendAddress.PORT + constants.ROUTE_PATH.API + constants.ROUTE_PATH.PLAYER +
|
||||
constants.ROUTE_PATH.VERSION + constants.ROUTE_PATH.SMS_CAPTCHA + constants.ROUTE_PATH.LOGIN,
|
||||
type: "POST",
|
||||
data: self.loginParams,
|
||||
success: function(resp) {
|
||||
self.onLoggedIn(resp);
|
||||
},
|
||||
error: function(xhr, status, errMsg) {
|
||||
console.log("Login attempt `onLoginButtonClicked` failed, about to execute `clearBoundRoomIdInBothVolatileAndPersistentStorage`.");
|
||||
window.clearBoundRoomIdInBothVolatileAndPersistentStorage()
|
||||
},
|
||||
timeout: function() {
|
||||
self.enableInteractiveControls(true);
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
onWechatLoggedIn(res) {
|
||||
const self = this;
|
||||
if (res.ret === self.retCodeDict.OK) {
|
||||
self.enableInteractiveControls(false);
|
||||
const date = Number(res.expiresAt);
|
||||
const selfPlayer = {
|
||||
expiresAt: date,
|
||||
playerId: res.playerId,
|
||||
intAuthToken: res.intAuthToken,
|
||||
displayName: res.displayName,
|
||||
avatar: res.avatar,
|
||||
}
|
||||
cc.sys.localStorage.setItem('selfPlayer', JSON.stringify(selfPlayer));
|
||||
|
||||
const qDict = window.getQueryParamDict();
|
||||
const expectedRoomId = qDict["expectedRoomId"];
|
||||
if (null != expectedRoomId) {
|
||||
console.log("onWechatLoggedIn using expectedRoomId == " + expectedRoomId);
|
||||
window.clearBoundRoomIdInBothVolatileAndPersistentStorage();
|
||||
}
|
||||
// To remove "code=XXX" in "query string".
|
||||
window.history.replaceState(qDict, null, window.location.pathname);
|
||||
self.useTokenLogin(res.intAuthToken);
|
||||
} else {
|
||||
cc.sys.localStorage.removeItem("selfPlayer");
|
||||
window.clearBoundRoomIdInBothVolatileAndPersistentStorage();
|
||||
self.wechatLoginTips.string = constants.ALERT.TIP_LABEL.WECHAT_LOGIN_FAILS + ", errorCode = " + res.ret;
|
||||
// To remove "code=XXX" in "query string".
|
||||
window.history.replaceState({}, null, window.location.pathname);
|
||||
}
|
||||
},
|
||||
|
||||
onLoggedIn(res) {
|
||||
const self = this;
|
||||
cc.log(`OnLoggedIn ${JSON.stringify(res)}.`)
|
||||
if (res.ret === self.retCodeDict.OK) {
|
||||
if(window.isUsingX5BlinkKernelOrWebkitWeChatKernel()) {
|
||||
window.initWxSdk = self.initWxSdk.bind(self);
|
||||
window.initWxSdk();
|
||||
}
|
||||
self.enableInteractiveControls(false);
|
||||
const date = Number(res.expiresAt);
|
||||
const selfPlayer = {
|
||||
expiresAt: date,
|
||||
playerId: res.playerId,
|
||||
intAuthToken: res.intAuthToken,
|
||||
avatar: res.avatar,
|
||||
displayName: res.displayName,
|
||||
name: res.name,
|
||||
}
|
||||
cc.sys.localStorage.setItem('selfPlayer', JSON.stringify(selfPlayer));
|
||||
console.log("cc.sys.localStorage.selfPlayer = ", cc.sys.localStorage.getItem('selfPlayer'));
|
||||
if (self.countdownTimer) {
|
||||
clearInterval(self.countdownTimer);
|
||||
}
|
||||
const inputControls = self.backgroundNode.getChildByName("InteractiveControls");
|
||||
self.backgroundNode.removeChild(inputControls);
|
||||
safelyAddChild(self.backgroundNode, self.loadingNode);
|
||||
self.loadingNode.getChildByName('loadingSprite').runAction(
|
||||
cc.repeatForever(cc.rotateBy(1.0, 360))
|
||||
);
|
||||
cc.director.loadScene('default_map');
|
||||
} else {
|
||||
cc.sys.localStorage.removeItem("selfPlayer");
|
||||
window.clearBoundRoomIdInBothVolatileAndPersistentStorage();
|
||||
self.enableInteractiveControls(true);
|
||||
switch (res.ret) {
|
||||
case self.retCodeDict.DUPLICATED:
|
||||
this.phoneNumberTips.getComponent(cc.Label).string = constants.ALERT.TIP_LABEL.LOG_OUT;
|
||||
break;
|
||||
case this.retCodeDict.TOKEN_EXPIRED:
|
||||
this.captchaTips.getComponent(cc.Label).string = constants.ALERT.TIP_LABEL.TOKEN_EXPIRED;
|
||||
break;
|
||||
case this.retCodeDict.SMS_CAPTCHA_NOT_MATCH:
|
||||
self.captchaTips.getComponent(cc.Label).string = i18n.t("login.tips.SMS_CAPTCHA_NOT_MATCH");
|
||||
break;
|
||||
case this.retCodeDict.INCORRECT_CAPTCHA:
|
||||
self.captchaTips.getComponent(cc.Label).string = i18n.t("login.tips.SMS_CAPTCHA_NOT_MATCH");
|
||||
break;
|
||||
case this.retCodeDict.SMS_CAPTCHA_CODE_NOT_EXISTING:
|
||||
self.captchaTips.getComponent(cc.Label).string = i18n.t("login.tips.SMS_CAPTCHA_NOT_MATCH");
|
||||
break;
|
||||
case this.retCodeDict.INCORRECT_PHONE_NUMBER:
|
||||
self.captchaTips.getComponent(cc.Label).string = i18n.t("login.tips.INCORRECT_PHONE_NUMBER");
|
||||
break;
|
||||
case this.retCodeDict.INVALID_REQUEST_PARAM:
|
||||
self.captchaTips.getComponent(cc.Label).string = i18n.t("login.tips.INCORRECT_PHONE_NUMBER");
|
||||
break;
|
||||
case this.retCodeDict.INCORRECT_PHONE_COUNTRY_CODE:
|
||||
this.captchaTips.getComponent(cc.Label).string = constants.ALERT.TIP_LABEL.INCORRECT_PHONE_COUNTRY_CODE;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
useWXCodeLogin(_code) {
|
||||
const self = this;
|
||||
NetworkUtils.ajax({
|
||||
url: backendAddress.PROTOCOL + '://' + backendAddress.HOST + ':' + backendAddress.PORT + constants.ROUTE_PATH.API + constants.ROUTE_PATH.PLAYER + constants.ROUTE_PATH.VERSION + constants.ROUTE_PATH.WECHAT + constants.ROUTE_PATH.LOGIN,
|
||||
type: "POST",
|
||||
data: {
|
||||
code: _code
|
||||
},
|
||||
success: function(res) {
|
||||
self.onWechatLoggedIn(res);
|
||||
},
|
||||
error: function(xhr, status, errMsg) {
|
||||
console.log("Login attempt `useWXCodeLogin` failed, about to execute `clearBoundRoomIdInBothVolatileAndPersistentStorage`.");
|
||||
cc.sys.localStorage.removeItem("selfPlayer");
|
||||
window.clearBoundRoomIdInBothVolatileAndPersistentStorage();
|
||||
self.wechatLoginTips.string = constants.ALERT.TIP_LABEL.WECHAT_LOGIN_FAILS + ", errorMsg =" + errMsg;
|
||||
window.history.replaceState({}, null, window.location.pathname);
|
||||
},
|
||||
});
|
||||
},
|
||||
|
||||
getWechatCode(evt) {
|
||||
let self = this;
|
||||
self.wechatLoginTips.string = "";
|
||||
const wechatServerEndpoint = wechatAddress.PROTOCOL + "://" + wechatAddress.HOST + ((null != wechatAddress.PORT && "" != wechatAddress.PORT.trim()) ? (":" + wechatAddress.PORT) : "");
|
||||
const url = wechatServerEndpoint + constants.WECHAT.AUTHORIZE_PATH + "?" + wechatAddress.APPID_LITERAL + "&" + constants.WECHAT.REDIRECT_RUI_KEY + NetworkUtils.encode(window.location.href) + "&" + constants.WECHAT.RESPONSE_TYPE + "&" + constants.WECHAT.SCOPE + constants.WECHAT.FIN;
|
||||
console.log("To visit wechat auth addr: " + url);
|
||||
window.location.href = url;
|
||||
},
|
||||
|
||||
initWxSdk() {
|
||||
const selfPlayer = JSON.parse(cc.sys.localStorage.getItem('selfPlayer'));
|
||||
const origUrl = window.location.protocol + "//" + window.location.host + window.location.pathname;
|
||||
/*
|
||||
* The `shareLink` must
|
||||
* - have its 2nd-order-domain registered as trusted 2nd-order under the targetd `res.jsConfig.app_id`, and
|
||||
* - extracted from current window.location.href.
|
||||
*/
|
||||
const shareLink = origUrl;
|
||||
const updateAppMsgShareDataObj = {
|
||||
type: 'link', // 分享类型,music、video或link,不填默认为link
|
||||
dataUrl: '', // 如果type是music或video,则要提供数据链接,默认为空
|
||||
title: document.title, // 分享标题
|
||||
desc: 'Let\'s play together!', // 分享描述
|
||||
link: shareLink + (cc.sys.localStorage.getItem('boundRoomId') ? "" : ("?expectedRoomId=" + cc.sys.localStorage.getItem('boundRoomId'))),
|
||||
imgUrl: origUrl + "/favicon.ico", // 分享图标
|
||||
success: function() {
|
||||
// 设置成功
|
||||
}
|
||||
};
|
||||
const menuShareTimelineObj = {
|
||||
title: document.title, // 分享标题
|
||||
link: shareLink + (cc.sys.localStorage.getItem('boundRoomId') ? "" : ("?expectedRoomId=" + cc.sys.localStorage.getItem('boundRoomId'))),
|
||||
imgUrl: origUrl + "/favicon.ico", // 分享图标
|
||||
success: function() {}
|
||||
};
|
||||
|
||||
const wxConfigUrl = (window.isUsingWebkitWechatKernel() ? window.atFirstLocationHref : window.location.href);
|
||||
//接入微信登录接口
|
||||
NetworkUtils.ajax({
|
||||
"url": backendAddress.PROTOCOL + '://' + backendAddress.HOST + ':' + backendAddress.PORT + constants.ROUTE_PATH.API + constants.ROUTE_PATH.PLAYER + constants.ROUTE_PATH.VERSION + constants.ROUTE_PATH.WECHAT + constants.ROUTE_PATH.JSCONFIG,
|
||||
type: "POST",
|
||||
data: {
|
||||
"url": wxConfigUrl,
|
||||
"intAuthToken": selfPlayer.intAuthToken,
|
||||
},
|
||||
success: function(res) {
|
||||
if (constants.RET_CODE.OK != res.ret) {
|
||||
console.log("cannot get the wsConfig. retCode == " + res.ret);
|
||||
return;
|
||||
}
|
||||
const jsConfig = res.jsConfig;
|
||||
console.log(updateAppMsgShareDataObj);
|
||||
const configData = {
|
||||
debug: CC_DEBUG, // 开启调试模式,调用的所有api的返回值会在客户端alert出来,若要查看传入的参数,可以在pc端打开,参数信息会通过log打出,仅在pc端时才会打印。
|
||||
appId: jsConfig.app_id, // 必填,公众号的唯一标识
|
||||
timestamp: jsConfig.timestamp.toString(), // 必填,生成签名的时间戳
|
||||
nonceStr: jsConfig.nonce_str, // 必填,生成签名的随机串
|
||||
jsApiList: ['onMenuShareAppMessage', 'onMenuShareTimeline'],
|
||||
signature: jsConfig.signature, // 必填,签名
|
||||
};
|
||||
console.log("config url: " + wxConfigUrl);
|
||||
console.log("wx.config: ");
|
||||
console.log(configData);
|
||||
wx.config(configData);
|
||||
console.log("Current window.location.href: " + window.location.href);
|
||||
wx.ready(function() {
|
||||
console.log("Here is wx.ready.")
|
||||
wx.onMenuShareAppMessage(updateAppMsgShareDataObj);
|
||||
wx.onMenuShareTimeline(menuShareTimelineObj);
|
||||
});
|
||||
wx.error(function(res) {
|
||||
console.error("wx config fails and error is " + JSON.stringify(res));
|
||||
});
|
||||
},
|
||||
error: function(xhr, status, errMsg) {
|
||||
console.log("cannot get the wsConfig. errMsg == " + errMsg);
|
||||
},
|
||||
});
|
||||
},
|
||||
});
|
||||
9
frontend/assets/scripts/Login.js.meta
Normal file
9
frontend/assets/scripts/Login.js.meta
Normal file
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"ver": "1.0.5",
|
||||
"uuid": "12a3d94d-56bd-42d2-8a2e-da1d27168980",
|
||||
"isPlugin": false,
|
||||
"loadPluginInWeb": true,
|
||||
"loadPluginInNative": true,
|
||||
"loadPluginInEditor": false,
|
||||
"subMetas": {}
|
||||
}
|
||||
1011
frontend/assets/scripts/Map.js
Normal file
1011
frontend/assets/scripts/Map.js
Normal file
File diff suppressed because it is too large
Load Diff
9
frontend/assets/scripts/Map.js.meta
Normal file
9
frontend/assets/scripts/Map.js.meta
Normal file
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"ver": "1.0.5",
|
||||
"uuid": "41d304ce-6a68-4d2d-92ab-5219de6e8638",
|
||||
"isPlugin": false,
|
||||
"loadPluginInWeb": true,
|
||||
"loadPluginInNative": true,
|
||||
"loadPluginInEditor": false,
|
||||
"subMetas": {}
|
||||
}
|
||||
66
frontend/assets/scripts/MusicEffectManager.js
Normal file
66
frontend/assets/scripts/MusicEffectManager.js
Normal file
@@ -0,0 +1,66 @@
|
||||
cc.Class({
|
||||
extends: cc.Component,
|
||||
|
||||
properties: {
|
||||
BGMEffect: {
|
||||
type: cc.AudioClip,
|
||||
default: null
|
||||
},
|
||||
crashedByTrapBullet: {
|
||||
type: cc.AudioClip,
|
||||
default: null
|
||||
},
|
||||
highScoreTreasurePicked: {
|
||||
type: cc.AudioClip,
|
||||
default: null
|
||||
},
|
||||
treasurePicked: {
|
||||
type: cc.AudioClip,
|
||||
default: null
|
||||
},
|
||||
countDown10SecToEnd: {
|
||||
type: cc.AudioClip,
|
||||
default: null
|
||||
},
|
||||
mapNode: {
|
||||
type: cc.Node,
|
||||
default: null
|
||||
},
|
||||
},
|
||||
|
||||
// LIFE-CYCLE CALLBACKS:
|
||||
|
||||
onLoad() {
|
||||
cc.audioEngine.setEffectsVolume(1);
|
||||
cc.audioEngine.setMusicVolume(0.5);
|
||||
},
|
||||
stopAllMusic() {
|
||||
cc.audioEngine.stopAll();
|
||||
},
|
||||
playBGM() {
|
||||
if(this.BGMEffect) {
|
||||
cc.audioEngine.playMusic(this.BGMEffect, true);
|
||||
}
|
||||
},
|
||||
playCrashedByTrapBullet() {
|
||||
if(this.crashedByTrapBullet) {
|
||||
cc.audioEngine.playEffect(this.crashedByTrapBullet, false);
|
||||
}
|
||||
},
|
||||
playHighScoreTreasurePicked() {
|
||||
if(this.highScoreTreasurePicked) {
|
||||
cc.audioEngine.playEffect(this.highScoreTreasurePicked, false);
|
||||
}
|
||||
},
|
||||
playTreasurePicked() {
|
||||
if(this.treasurePicked) {
|
||||
cc.audioEngine.playEffect(this.treasurePicked, false);
|
||||
}
|
||||
},
|
||||
playCountDown10SecToEnd() {
|
||||
if(this.countDown10SecToEnd) {
|
||||
cc.audioEngine.playEffect(this.countDown10SecToEnd, false);
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
9
frontend/assets/scripts/MusicEffectManager.js.meta
Normal file
9
frontend/assets/scripts/MusicEffectManager.js.meta
Normal file
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"ver": "1.0.5",
|
||||
"uuid": "09e1bfed-132e-4ada-a68f-229a870db69e",
|
||||
"isPlugin": false,
|
||||
"loadPluginInWeb": true,
|
||||
"loadPluginInNative": true,
|
||||
"loadPluginInEditor": false,
|
||||
"subMetas": {}
|
||||
}
|
||||
337
frontend/assets/scripts/NPCPlayer.js
Normal file
337
frontend/assets/scripts/NPCPlayer.js
Normal file
@@ -0,0 +1,337 @@
|
||||
const COLLISION_WITH_PLAYER_STATE = {
|
||||
WALKING_COLLIDABLE: 0,
|
||||
STILL_NEAR_SELF_PLAYER_ONLY_PLAYING_ANIM: 1,
|
||||
STILL_NEAR_SELF_PLAYER_ONLY_PLAYED_ANIM: 2,
|
||||
STILL_NEAR_OTHER_PLAYER_ONLY_PLAYING_ANIM: 3,
|
||||
STILL_NEAR_OTHER_PLAYER_ONLY_PLAYED_ANIM: 4,
|
||||
STILL_NEAR_SELF_PLAYER_NEAR_OTHER_PLAYER_PLAYING_ANIM: 5,
|
||||
STILL_NEAR_SELF_PLAYER_NEAR_OTHER_PLAYER_PLAYED_ANIM: 6,
|
||||
WALKING_COLLIDABLE_WITH_SELF_PLAYER_BUT_NOT_OTHER_PLAYER: 7,
|
||||
STILL_NEAR_NOBODY_PLAYING_ANIM: 8,
|
||||
};
|
||||
|
||||
const STILL_NEAR_SELF_PLAYER_STATE_SET = new Set();
|
||||
STILL_NEAR_SELF_PLAYER_STATE_SET.add(COLLISION_WITH_PLAYER_STATE.STILL_NEAR_SELF_PLAYER_ONLY_PLAYING_ANIM);
|
||||
STILL_NEAR_SELF_PLAYER_STATE_SET.add(COLLISION_WITH_PLAYER_STATE.STILL_NEAR_SELF_PLAYER_ONLY_PLAYED_ANIM);
|
||||
STILL_NEAR_SELF_PLAYER_STATE_SET.add(COLLISION_WITH_PLAYER_STATE.STILL_NEAR_SELF_PLAYER_NEAR_OTHER_PLAYER_PLAYING_ANIM);
|
||||
STILL_NEAR_SELF_PLAYER_STATE_SET.add(COLLISION_WITH_PLAYER_STATE.STILL_NEAR_SELF_PLAYER_NEAR_OTHER_PLAYER_PLAYED_ANIM);
|
||||
|
||||
const STILL_NEAR_OTHER_PLAYER_STATE_SET = new Set();
|
||||
STILL_NEAR_OTHER_PLAYER_STATE_SET.add(COLLISION_WITH_PLAYER_STATE.STILL_NEAR_OTHER_PLAYER_ONLY_PLAYING_ANIM);
|
||||
STILL_NEAR_OTHER_PLAYER_STATE_SET.add(COLLISION_WITH_PLAYER_STATE.STILL_NEAR_OTHER_PLAYER_ONLY_PLAYED_ANIM);
|
||||
STILL_NEAR_OTHER_PLAYER_STATE_SET.add(COLLISION_WITH_PLAYER_STATE.STILL_NEAR_SELF_PLAYER_NEAR_OTHER_PLAYER_PLAYING_ANIM);
|
||||
STILL_NEAR_OTHER_PLAYER_STATE_SET.add(COLLISION_WITH_PLAYER_STATE.STILL_NEAR_SELF_PLAYER_NEAR_OTHER_PLAYER_PLAYED_ANIM);
|
||||
|
||||
const STILL_SHOULD_NOT_PLAY_STUNNED_ANIM_SET = new Set();
|
||||
STILL_SHOULD_NOT_PLAY_STUNNED_ANIM_SET.add(COLLISION_WITH_PLAYER_STATE.STILL_NEAR_SELF_PLAYER_ONLY_PLAYING_ANIM);
|
||||
STILL_SHOULD_NOT_PLAY_STUNNED_ANIM_SET.add(COLLISION_WITH_PLAYER_STATE.STILL_NEAR_SELF_PLAYER_ONLY_PLAYED_ANIM);
|
||||
STILL_SHOULD_NOT_PLAY_STUNNED_ANIM_SET.add(COLLISION_WITH_PLAYER_STATE.STILL_NEAR_OTHER_PLAYER_ONLY_PLAYING_ANIM);
|
||||
STILL_SHOULD_NOT_PLAY_STUNNED_ANIM_SET.add(COLLISION_WITH_PLAYER_STATE.STILL_NEAR_OTHER_PLAYER_ONLY_PLAYED_ANIM);
|
||||
STILL_SHOULD_NOT_PLAY_STUNNED_ANIM_SET.add(COLLISION_WITH_PLAYER_STATE.STILL_NEAR_SELF_PLAYER_NEAR_OTHER_PLAYER_PLAYING_ANIM);
|
||||
STILL_SHOULD_NOT_PLAY_STUNNED_ANIM_SET.add(COLLISION_WITH_PLAYER_STATE.STILL_NEAR_SELF_PLAYER_NEAR_OTHER_PLAYER_PLAYED_ANIM);
|
||||
STILL_SHOULD_NOT_PLAY_STUNNED_ANIM_SET.add(COLLISION_WITH_PLAYER_STATE.STILL_NEAR_NOBODY_PLAYING_ANIM);
|
||||
|
||||
function transitWalkingConditionallyCollidableToUnconditionallyCollidable(currentCollisionWithPlayerState) {
|
||||
switch (currentCollisionWithPlayerState) {
|
||||
case COLLISION_WITH_PLAYER_STATE.WALKING_COLLIDABLE_WITH_SELF_PLAYER_BUT_NOT_OTHER_PLAYER:
|
||||
return COLLISION_WITH_PLAYER_STATE.WALKING_COLLIDABLE;
|
||||
}
|
||||
|
||||
return currentCollisionWithPlayerState;
|
||||
}
|
||||
|
||||
function transitUponSelfPlayerLeftProximityArea(currentCollisionWithPlayerState) {
|
||||
switch (currentCollisionWithPlayerState) {
|
||||
case COLLISION_WITH_PLAYER_STATE.STILL_NEAR_SELF_PLAYER_ONLY_PLAYING_ANIM:
|
||||
return COLLISION_WITH_PLAYER_STATE.STILL_NEAR_NOBODY_PLAYING_ANIM;
|
||||
|
||||
case COLLISION_WITH_PLAYER_STATE.STILL_NEAR_SELF_PLAYER_ONLY_PLAYED_ANIM:
|
||||
return COLLISION_WITH_PLAYER_STATE.WALKING_COLLIDABLE;
|
||||
|
||||
case COLLISION_WITH_PLAYER_STATE.STILL_NEAR_SELF_PLAYER_NEAR_OTHER_PLAYER_PLAYING_ANIM:
|
||||
return COLLISION_WITH_PLAYER_STATE.STILL_NEAR_OTHER_PLAYER_ONLY_PLAYING_ANIM;
|
||||
|
||||
case COLLISION_WITH_PLAYER_STATE.STILL_NEAR_SELF_PLAYER_NEAR_OTHER_PLAYER_PLAYED_ANIM:
|
||||
return COLLISION_WITH_PLAYER_STATE.WALKING_COLLIDABLE_WITH_SELF_PLAYER_BUT_NOT_OTHER_PLAYER;
|
||||
}
|
||||
return currentCollisionWithPlayerState;
|
||||
}
|
||||
|
||||
function transitDueToNoBodyInProximityArea(currentCollisionWithPlayerState) {
|
||||
switch (currentCollisionWithPlayerState) {
|
||||
case COLLISION_WITH_PLAYER_STATE.STILL_NEAR_SELF_PLAYER_ONLY_PLAYING_ANIM:
|
||||
case COLLISION_WITH_PLAYER_STATE.STILL_NEAR_OTHER_PLAYER_ONLY_PLAYING_ANIM:
|
||||
case COLLISION_WITH_PLAYER_STATE.STILL_NEAR_SELF_PLAYER_NEAR_OTHER_PLAYER_PLAYING_ANIM:
|
||||
return COLLISION_WITH_PLAYER_STATE.STILL_NEAR_NOBODY_PLAYING_ANIM;
|
||||
|
||||
case COLLISION_WITH_PLAYER_STATE.STILL_NEAR_SELF_PLAYER_ONLY_PLAYED_ANIM:
|
||||
case COLLISION_WITH_PLAYER_STATE.STILL_NEAR_OTHER_PLAYER_ONLY_PLAYED_ANIM:
|
||||
case COLLISION_WITH_PLAYER_STATE.STILL_NEAR_SELF_PLAYER_NEAR_OTHER_PLAYER_PLAYED_ANIM:
|
||||
return COLLISION_WITH_PLAYER_STATE.WALKING_COLLIDABLE_WITH_SELF_PLAYER_BUT_NOT_OTHER_PLAYER;
|
||||
}
|
||||
return currentCollisionWithPlayerState;
|
||||
}
|
||||
|
||||
function transitToPlayingStunnedAnim(currentCollisionWithPlayerState, dueToSelfPlayer, dueToOtherPlayer) {
|
||||
if (dueToSelfPlayer) {
|
||||
switch (currentCollisionWithPlayerState) {
|
||||
case COLLISION_WITH_PLAYER_STATE.WALKING_COLLIDABLE:
|
||||
case COLLISION_WITH_PLAYER_STATE.WALKING_COLLIDABLE_WITH_SELF_PLAYER_BUT_NOT_OTHER_PLAYER:
|
||||
return COLLISION_WITH_PLAYER_STATE.STILL_NEAR_SELF_PLAYER_ONLY_PLAYING_ANIM;
|
||||
}
|
||||
}
|
||||
|
||||
if (dueToOtherPlayer) {
|
||||
switch (currentCollisionWithPlayerState) {
|
||||
case COLLISION_WITH_PLAYER_STATE.WALKING_COLLIDABLE:
|
||||
return COLLISION_WITH_PLAYER_STATE.STILL_NEAR_OTHER_PLAYER_ONLY_PLAYING_ANIM;
|
||||
}
|
||||
}
|
||||
// TODO: Any error to throw?
|
||||
return currentCollisionWithPlayerState;
|
||||
}
|
||||
|
||||
function transitDuringPlayingStunnedAnim(currentCollisionWithPlayerState, dueToSelfPlayerComesIntoProximity, dueToOtherPlayerComesIntoProximity) {
|
||||
if (dueToSelfPlayerComesIntoProximity) {
|
||||
switch (currentCollisionWithPlayerState) {
|
||||
case COLLISION_WITH_PLAYER_STATE.STILL_NEAR_OTHER_PLAYER_ONLY_PLAYING_ANIM:
|
||||
return COLLISION_WITH_PLAYER_STATE.STILL_NEAR_SELF_PLAYER_NEAR_OTHER_PLAYER_PLAYING_ANIM;
|
||||
|
||||
case COLLISION_WITH_PLAYER_STATE.STILL_NEAR_NOBODY_PLAYING_ANIM:
|
||||
return COLLISION_WITH_PLAYER_STATE.STILL_NEAR_SELF_PLAYER_ONLY_PLAYING_ANIM;
|
||||
}
|
||||
}
|
||||
|
||||
if (dueToOtherPlayerComesIntoProximity) {
|
||||
switch (currentCollisionWithPlayerState) {
|
||||
case COLLISION_WITH_PLAYER_STATE.STILL_NEAR_SELF_PLAYER_ONLY_PLAYING_ANIM:
|
||||
return COLLISION_WITH_PLAYER_STATE.STILL_NEAR_SELF_PLAYER_NEAR_OTHER_PLAYER_PLAYING_ANIM;
|
||||
|
||||
case COLLISION_WITH_PLAYER_STATE.STILL_NEAR_NOBODY_PLAYING_ANIM:
|
||||
return COLLISION_WITH_PLAYER_STATE.STILL_NEAR_OTHER_PLAYER_ONLY_PLAYING_ANIM;
|
||||
}
|
||||
}
|
||||
// TODO: Any error to throw?
|
||||
return currentCollisionWithPlayerState;
|
||||
}
|
||||
|
||||
function transitStunnedAnimPlayingToPlayed(currentCollisionWithPlayerState, forceNotCollidableWithOtherPlayer) {
|
||||
switch (currentCollisionWithPlayerState) {
|
||||
case COLLISION_WITH_PLAYER_STATE.STILL_NEAR_SELF_PLAYER_ONLY_PLAYING_ANIM:
|
||||
return COLLISION_WITH_PLAYER_STATE.STILL_NEAR_SELF_PLAYER_ONLY_PLAYED_ANIM;
|
||||
|
||||
case COLLISION_WITH_PLAYER_STATE.STILL_NEAR_OTHER_PLAYER_ONLY_PLAYING_ANIM:
|
||||
return COLLISION_WITH_PLAYER_STATE.STILL_NEAR_OTHER_PLAYER_ONLY_PLAYED_ANIM;
|
||||
|
||||
case COLLISION_WITH_PLAYER_STATE.STILL_NEAR_SELF_PLAYER_NEAR_OTHER_PLAYER_PLAYING_ANIM:
|
||||
return COLLISION_WITH_PLAYER_STATE.STILL_NEAR_SELF_PLAYER_NEAR_OTHER_PLAYER_PLAYED_ANIM;
|
||||
|
||||
case COLLISION_WITH_PLAYER_STATE.STILL_NEAR_NOBODY_PLAYING_ANIM:
|
||||
return (true == forceNotCollidableWithOtherPlayer ? COLLISION_WITH_PLAYER_STATE.WALKING_COLLIDABLE_WITH_SELF_PLAYER_BUT_NOT_OTHER_PLAYER : COLLISION_WITH_PLAYER_STATE.WALKING_COLLIDABLE);
|
||||
}
|
||||
// TODO: Any error to throw?
|
||||
return currentCollisionWithPlayerState;
|
||||
}
|
||||
|
||||
function transitStunnedAnimPlayedToWalking(currentCollisionWithPlayerState) {
|
||||
/*
|
||||
* Intentionally NOT transiting for
|
||||
*
|
||||
* - STILL_NEAR_SELF_PLAYER_NEAR_OTHER_PLAYER_PLAYED_ANIM, or
|
||||
* - STILL_NEAR_SELF_PLAYER_ONLY_PLAYED_ANIM,
|
||||
*
|
||||
* which should be transited upon leaving of "SelfPlayer".
|
||||
*/
|
||||
switch (currentCollisionWithPlayerState) {
|
||||
case COLLISION_WITH_PLAYER_STATE.STILL_NEAR_OTHER_PLAYER_ONLY_PLAYED_ANIM:
|
||||
return COLLISION_WITH_PLAYER_STATE.WALKING_COLLIDABLE_WITH_SELF_PLAYER_BUT_NOT_OTHER_PLAYER;
|
||||
}
|
||||
// TODO: Any error to throw?
|
||||
return currentCollisionWithPlayerState;
|
||||
}
|
||||
|
||||
const BasePlayer = require("./BasePlayer");
|
||||
|
||||
cc.Class({
|
||||
extends: BasePlayer,
|
||||
|
||||
// LIFE-CYCLE CALLBACKS:
|
||||
start() {
|
||||
BasePlayer.prototype.start.call(this);
|
||||
|
||||
this.scheduleNewDirection(this._generateRandomDirectionExcluding(0, 0));
|
||||
},
|
||||
|
||||
onLoad() {
|
||||
BasePlayer.prototype.onLoad.call(this);
|
||||
const self = this;
|
||||
|
||||
this.collisionWithPlayerState = COLLISION_WITH_PLAYER_STATE.WALKING_COLLIDABLE;
|
||||
|
||||
this.clips = {
|
||||
'01': 'FlatHeadSisterRunTop',
|
||||
'0-1': 'FlatHeadSisterRunBottom',
|
||||
'-20': 'FlatHeadSisterRunLeft',
|
||||
'20': 'FlatHeadSisterRunRight',
|
||||
'-21': 'FlatHeadSisterRunTopLeft',
|
||||
'21': 'FlatHeadSisterRunTopRight',
|
||||
'-2-1': 'FlatHeadSisterRunBottomLeft',
|
||||
'2-1': 'FlatHeadSisterRunBottomRight'
|
||||
};
|
||||
|
||||
|
||||
self.onStunnedAnimPlayedSafe = () => {
|
||||
const oldCollisionWithPlayerState = self.collisionWithPlayerState;
|
||||
self.collisionWithPlayerState = transitStunnedAnimPlayingToPlayed(this.collisionWithPlayerState, true);
|
||||
if (oldCollisionWithPlayerState == self.collisionWithPlayerState || !self.node) return;
|
||||
|
||||
// TODO: Be more specific with "toExcludeDx" and "toExcludeDy".
|
||||
self.scheduleNewDirection(self._generateRandomDirectionExcluding(0, 0));
|
||||
self.collisionWithPlayerState = transitStunnedAnimPlayedToWalking(self.collisionWithPlayerState);
|
||||
setTimeout(() => {
|
||||
self.collisionWithPlayerState = transitWalkingConditionallyCollidableToUnconditionallyCollidable(self.collisionWithPlayerState);
|
||||
}, 5000);
|
||||
};
|
||||
|
||||
self.onStunnedAnimPlayedSafeAction = cc.callFunc(self.onStunnedAnimPlayedSafe, self);
|
||||
|
||||
self.playStunnedAnim = () => {
|
||||
let colliededAction1 = cc.rotateTo(0.2, -15);
|
||||
let colliededAction2 = cc.rotateTo(0.3, 15);
|
||||
let colliededAction3 = cc.rotateTo(0.2, 0);
|
||||
|
||||
self.node.runAction(cc.sequence(
|
||||
cc.callFunc(() => {
|
||||
self.player.pause()
|
||||
}, self),
|
||||
colliededAction1,
|
||||
colliededAction2,
|
||||
colliededAction3,
|
||||
cc.callFunc(() => {
|
||||
self.player.resume()
|
||||
}, self),
|
||||
self.onStunnedAnimPlayedSafeAction
|
||||
));
|
||||
|
||||
// NOTE: Use <cc.Animation>.on('stop', self.onStunnedAnimPlayedSafe) if necessary.
|
||||
}
|
||||
},
|
||||
|
||||
_canMoveBy(vecToMoveBy) {
|
||||
if (COLLISION_WITH_PLAYER_STATE.WALKING_COLLIDABLE_WITH_SELF_PLAYER_BUT_NOT_OTHER_PLAYER != this.collisionWithPlayerState && COLLISION_WITH_PLAYER_STATE.WALKING_COLLIDABLE != this.collisionWithPlayerState) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const superRet = BasePlayer.prototype._canMoveBy.call(this, vecToMoveBy);
|
||||
const self = this;
|
||||
|
||||
const computedNewDifferentPosLocalToParentWithinCurrentFrame = self.node.position.add(vecToMoveBy);
|
||||
|
||||
const currentSelfColliderCircle = self.node.getComponent("cc.CircleCollider");
|
||||
let nextSelfColliderCircle = null;
|
||||
if (0 < self.contactedBarriers.length || 0 < self.contactedNPCPlayers.length || 0 < self.contactedControlledPlayers) {
|
||||
/* To avoid unexpected buckling. */
|
||||
const mutatedVecToMoveBy = vecToMoveBy.mul(2);
|
||||
nextSelfColliderCircle = {
|
||||
position: self.node.position.add(vecToMoveBy.mul(2)).add(currentSelfColliderCircle.offset),
|
||||
radius: currentSelfColliderCircle.radius,
|
||||
};
|
||||
} else {
|
||||
nextSelfColliderCircle = {
|
||||
position: computedNewDifferentPosLocalToParentWithinCurrentFrame.add(currentSelfColliderCircle.offset),
|
||||
radius: currentSelfColliderCircle.radius,
|
||||
};
|
||||
}
|
||||
|
||||
for (let aCircleCollider of self.contactedControlledPlayers) {
|
||||
let contactedCircleLocalToParentWithinCurrentFrame = {
|
||||
position: aCircleCollider.node.position.add(aCircleCollider.offset),
|
||||
radius: aCircleCollider.radius,
|
||||
};
|
||||
if (cc.Intersection.circleCircle(contactedCircleLocalToParentWithinCurrentFrame, nextSelfColliderCircle)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return superRet;
|
||||
},
|
||||
|
||||
update(dt) {
|
||||
const self = this;
|
||||
|
||||
BasePlayer.prototype.update.call(this, dt);
|
||||
|
||||
if (0 < self.contactedBarriers.length) {
|
||||
self.scheduleNewDirection(self._generateRandomDirectionExcluding(self.scheduledDirection.dx, self.scheduledDirection.dy));
|
||||
}
|
||||
|
||||
if (tileCollisionManager.isOutOfMapNode(self.mapNode, self.computedNewDifferentPosLocalToParentWithinCurrentFrame)) {
|
||||
self.scheduleNewDirection(self._generateRandomDirectionExcluding(self.scheduledDirection.dx, self.scheduledDirection.dy));
|
||||
}
|
||||
},
|
||||
|
||||
onCollisionEnter(other, self) {
|
||||
BasePlayer.prototype.onCollisionEnter.call(this, other, self);
|
||||
const playerScriptIns = self.getComponent(self.node.name);
|
||||
switch (other.node.name) {
|
||||
case "SelfPlayer":
|
||||
playerScriptIns._addContactedControlledPlayers(other);
|
||||
if (1 == playerScriptIns.contactedControlledPlayers.length) {
|
||||
// When "SelfPlayer" comes into proximity area.
|
||||
if (!STILL_SHOULD_NOT_PLAY_STUNNED_ANIM_SET.has(playerScriptIns.collisionWithPlayerState)) {
|
||||
playerScriptIns.collisionWithPlayerState = transitToPlayingStunnedAnim(playerScriptIns.collisionWithPlayerState, true, false);
|
||||
playerScriptIns.playStunnedAnim();
|
||||
} else {
|
||||
playerScriptIns.collisionWithPlayerState = transitDuringPlayingStunnedAnim(playerScriptIns.collisionWithPlayerState, true, false);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case "NPCPlayer":
|
||||
if (1 == playerScriptIns.contactedNPCPlayers.length) {
|
||||
// When one of the other "OtherPlayer"s comes into proximity area.
|
||||
if (!STILL_SHOULD_NOT_PLAY_STUNNED_ANIM_SET.has(playerScriptIns.collisionWithPlayerState)) {
|
||||
const oldState = playerScriptIns.collisionWithPlayerState;
|
||||
playerScriptIns.collisionWithPlayerState = transitToPlayingStunnedAnim(oldState, false, true);
|
||||
if (playerScriptIns.collisionWithPlayerState != oldState) {
|
||||
playerScriptIns.playStunnedAnim();
|
||||
}
|
||||
} else {
|
||||
playerScriptIns.collisionWithPlayerState = transitDuringPlayingStunnedAnim(playerScriptIns.collisionWithPlayerState, false, true);
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
},
|
||||
|
||||
onCollisionStay(other, self) {
|
||||
// TBD.
|
||||
},
|
||||
|
||||
onCollisionExit(other, self) {
|
||||
BasePlayer.prototype.onCollisionExit.call(this, other, self);
|
||||
const playerScriptIns = self.getComponent(self.node.name);
|
||||
switch (other.node.name) {
|
||||
case "SelfPlayer":
|
||||
playerScriptIns._removeContactedControlledPlayer(other);
|
||||
if (0 == playerScriptIns.contactedControlledPlayers.length) {
|
||||
// Special release step.
|
||||
if (STILL_NEAR_SELF_PLAYER_STATE_SET.has(playerScriptIns.collisionWithPlayerState)) {
|
||||
playerScriptIns.collisionWithPlayerState = transitUponSelfPlayerLeftProximityArea(playerScriptIns.collisionWithPlayerState);
|
||||
}
|
||||
}
|
||||
if (0 == playerScriptIns.contactedControlledPlayers.length && 0 == playerScriptIns.contactedNPCPlayers.length) {
|
||||
transitDueToNoBodyInProximityArea(playerScriptIns.collisionWithPlayerState);
|
||||
}
|
||||
break;
|
||||
case "NPCPlayer":
|
||||
if (0 == playerScriptIns.contactedControlledPlayers.length && 0 == playerScriptIns.contactedNPCPlayers.length) {
|
||||
transitDueToNoBodyInProximityArea(playerScriptIns.collisionWithPlayerState);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
},
|
||||
});
|
||||
9
frontend/assets/scripts/NPCPlayer.js.meta
Normal file
9
frontend/assets/scripts/NPCPlayer.js.meta
Normal file
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"ver": "1.0.5",
|
||||
"uuid": "17759956-1f8c-421f-bac2-7f4dd7ccdcda",
|
||||
"isPlugin": false,
|
||||
"loadPluginInWeb": true,
|
||||
"loadPluginInNative": true,
|
||||
"loadPluginInEditor": false,
|
||||
"subMetas": {}
|
||||
}
|
||||
53
frontend/assets/scripts/PlayersInfo.js
Normal file
53
frontend/assets/scripts/PlayersInfo.js
Normal file
@@ -0,0 +1,53 @@
|
||||
cc.Class({
|
||||
extends: cc.Component,
|
||||
|
||||
properties: {
|
||||
listNode: {
|
||||
type: cc.Node,
|
||||
default: null,
|
||||
}
|
||||
},
|
||||
|
||||
// LIFE-CYCLE CALLBACKS:
|
||||
updateData(playerMeta) {
|
||||
const joinIndex = playerMeta.joinIndex;
|
||||
const playerNode = this.listNode.getChildByName("player" + joinIndex);
|
||||
if (!playerNode) {
|
||||
return;
|
||||
}
|
||||
const playerNameLabelNode = playerNode.getChildByName("name");
|
||||
|
||||
function isEmptyString(str) {
|
||||
return str == null || str == ''
|
||||
}
|
||||
|
||||
const nameToDisplay = (() => {
|
||||
if (!isEmptyString(playerMeta.displayName)) {
|
||||
return playerMeta.displayName;
|
||||
} else if (!isEmptyString(playerMeta.name)) {
|
||||
return playerMeta.name;
|
||||
} else {
|
||||
return ""
|
||||
}
|
||||
})();
|
||||
|
||||
playerNameLabelNode.getComponent(cc.Label).string = nameToDisplay;
|
||||
|
||||
const score = (playerMeta.score ? playerMeta.score : 0);
|
||||
const playerScoreLabelNode = playerNode.getChildByName("score");
|
||||
playerScoreLabelNode.getComponent(cc.Label).string = score;
|
||||
},
|
||||
|
||||
onLoad() {},
|
||||
|
||||
clearInfo() {
|
||||
for (let i = 1; i < 3; i++) {
|
||||
const playerNode = this.listNode.getChildByName('player' + i);
|
||||
const playerScoreLabelNode = playerNode.getChildByName("score");
|
||||
const playerNameLabelNode = playerNode.getChildByName("name");
|
||||
playerScoreLabelNode.getComponent(cc.Label).string = '';
|
||||
playerNameLabelNode.getComponent(cc.Label).string = '';
|
||||
}
|
||||
},
|
||||
|
||||
});
|
||||
9
frontend/assets/scripts/PlayersInfo.js.meta
Normal file
9
frontend/assets/scripts/PlayersInfo.js.meta
Normal file
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"ver": "1.0.5",
|
||||
"uuid": "846cee45-4ca9-4383-8a74-c6a8f3c35617",
|
||||
"isPlugin": false,
|
||||
"loadPluginInWeb": true,
|
||||
"loadPluginInNative": true,
|
||||
"loadPluginInEditor": false,
|
||||
"subMetas": {}
|
||||
}
|
||||
13
frontend/assets/scripts/Pumpkin.js
Normal file
13
frontend/assets/scripts/Pumpkin.js
Normal file
@@ -0,0 +1,13 @@
|
||||
const Bullet = require("./Bullet");
|
||||
|
||||
cc.Class({
|
||||
extends: Bullet,
|
||||
// LIFE-CYCLE CALLBACKS:
|
||||
properties: {
|
||||
},
|
||||
|
||||
onLoad() {
|
||||
Bullet.prototype.onLoad.call(this);
|
||||
},
|
||||
|
||||
});
|
||||
9
frontend/assets/scripts/Pumpkin.js.meta
Normal file
9
frontend/assets/scripts/Pumpkin.js.meta
Normal file
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"ver": "1.0.5",
|
||||
"uuid": "c3bb6519-af90-4641-bb5e-5abbbcdfa6da",
|
||||
"isPlugin": false,
|
||||
"loadPluginInWeb": true,
|
||||
"loadPluginInNative": true,
|
||||
"loadPluginInEditor": false,
|
||||
"subMetas": {}
|
||||
}
|
||||
163
frontend/assets/scripts/ResultPanel.js
Normal file
163
frontend/assets/scripts/ResultPanel.js
Normal file
@@ -0,0 +1,163 @@
|
||||
const i18n = require('LanguageData');
|
||||
i18n.init(window.language); // languageID should be equal to the one we input in New Language ID input field
|
||||
cc.Class({
|
||||
extends: cc.Component,
|
||||
properties: {
|
||||
onCloseDelegate: {
|
||||
type: cc.Object,
|
||||
default: null
|
||||
},
|
||||
onAgainClicked: {
|
||||
type: cc.Object,
|
||||
default: null
|
||||
},
|
||||
myAvatarNode: {
|
||||
type: cc.Node,
|
||||
default: null,
|
||||
},
|
||||
myNameNode: {
|
||||
type: cc.Node,
|
||||
default: null,
|
||||
},
|
||||
rankingNodes: {
|
||||
type: [cc.Node],
|
||||
default: [],
|
||||
},
|
||||
winNode: {
|
||||
type: cc.Node,
|
||||
default: null,
|
||||
},
|
||||
},
|
||||
|
||||
// LIFE-CYCLE CALLBACKS:
|
||||
onLoad() {
|
||||
},
|
||||
|
||||
againBtnOnClick(evt) {
|
||||
this.onClose();
|
||||
if (!this.onAgainClicked) return;
|
||||
this.onAgainClicked();
|
||||
},
|
||||
|
||||
homeBtnOnClick(evt) {
|
||||
this.onClose();
|
||||
window.clearLocalStorageAndBackToLoginScene();
|
||||
},
|
||||
|
||||
showPlayerInfo(playerRichInfoDict) {
|
||||
this.showRanking(playerRichInfoDict);
|
||||
this.showMyAvatar();
|
||||
this.showMyName();
|
||||
},
|
||||
|
||||
showMyName() {
|
||||
const selfPlayerInfo = JSON.parse(cc.sys.localStorage.getItem('selfPlayer'));
|
||||
let name = 'No name';
|
||||
if (null == selfPlayerInfo.displayName || "" == selfPlayerInfo.displayName) {
|
||||
name = selfPlayerInfo.name;
|
||||
} else {
|
||||
name = selfPlayerInfo.displayName;
|
||||
}
|
||||
if (!this.myNameNode) return;
|
||||
const myNameNodeLabel = this.myNameNode.getComponent(cc.Label);
|
||||
if (!myNameNodeLabel || null == name) return;
|
||||
myNameNodeLabel.string = name;
|
||||
},
|
||||
|
||||
showRanking(playerRichInfoDict) {
|
||||
const self = this;
|
||||
const sortablePlayers = [];
|
||||
|
||||
for (let playerId in playerRichInfoDict) {
|
||||
const p = playerRichInfoDict[playerId];
|
||||
p.id = playerId;
|
||||
if (null == p.score) {
|
||||
p.score = playerRichInfoDict[playerId].score;
|
||||
}
|
||||
if (null == p.score) {
|
||||
p.score = 0;
|
||||
}
|
||||
sortablePlayers.push(p);
|
||||
}
|
||||
const sortedPlayers = sortablePlayers.sort((a, b) => {
|
||||
if (a.score != b.score) {
|
||||
return (b.score - a.score);
|
||||
} else {
|
||||
return (a.id > b.id);
|
||||
}
|
||||
});
|
||||
|
||||
const selfPlayerInfo = JSON.parse(cc.sys.localStorage.getItem('selfPlayer'));
|
||||
for (let k in sortedPlayers) {
|
||||
const p = sortedPlayers[k];
|
||||
const nameToDisplay = (() => {
|
||||
function isEmptyString(str) {
|
||||
return str == null || str == '';
|
||||
}
|
||||
if (!isEmptyString(p.displayName)) {
|
||||
return p.displayName;
|
||||
} else if (!isEmptyString(p.name)) {
|
||||
return p.name;
|
||||
} else {
|
||||
return "";
|
||||
}
|
||||
})();
|
||||
|
||||
if (selfPlayerInfo.playerId == p.id) {
|
||||
const rank = k + 1;
|
||||
if (1 != rank && null != self.winNode) {
|
||||
self.winNode.active = false;
|
||||
}
|
||||
}
|
||||
|
||||
self.rankingNodes[k].getChildByName('name').getComponent(cc.Label).string = nameToDisplay;
|
||||
self.rankingNodes[k].getChildByName('score').getComponent(cc.Label).string = playerRichInfoDict[p.id].score;
|
||||
}
|
||||
},
|
||||
|
||||
showMyAvatar() {
|
||||
const self = this;
|
||||
const selfPlayerInfo = JSON.parse(cc.sys.localStorage.getItem('selfPlayer'));
|
||||
let remoteUrl = selfPlayerInfo.avatar;
|
||||
if (remoteUrl == null || remoteUrl == '') {
|
||||
cc.log(`No avatar to show for myself, check storage.`);
|
||||
return;
|
||||
} else {
|
||||
cc.loader.load({
|
||||
url: remoteUrl,
|
||||
type: 'jpg'
|
||||
}, function(err, texture) {
|
||||
if (err != null || texture == null) {
|
||||
console.log(err);
|
||||
} else {
|
||||
const sf = new cc.SpriteFrame();
|
||||
sf.setTexture(texture);
|
||||
self.myAvatarNode.getComponent(cc.Sprite).spriteFrame = sf;
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
showRibbon(winnerInfo, ribbonNode) {
|
||||
const selfPlayerInfo = JSON.parse(cc.sys.localStorage.getItem('selfPlayer'));
|
||||
const texture = (selfPlayerInfo.playerId == winnerInfo.id) ? "textures/resultPanel/WinRibbon" : "textures/resultPanel/loseRibbon";
|
||||
cc.loader.loadRes(texture, cc.SpriteFrame, function(err, spriteFrame) {
|
||||
if (err) {
|
||||
console.log(err);
|
||||
return;
|
||||
}
|
||||
ribbonNode.getComponent(cc.Sprite).spriteFrame = spriteFrame;
|
||||
});
|
||||
|
||||
},
|
||||
|
||||
onClose(evt) {
|
||||
if (this.node.parent) {
|
||||
this.node.parent.removeChild(this.node);
|
||||
}
|
||||
if (!this.onCloseDelegate) {
|
||||
return;
|
||||
}
|
||||
this.onCloseDelegate();
|
||||
}
|
||||
});
|
||||
9
frontend/assets/scripts/ResultPanel.js.meta
Normal file
9
frontend/assets/scripts/ResultPanel.js.meta
Normal file
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"ver": "1.0.5",
|
||||
"uuid": "5ae774fb-4f9c-445d-a057-5d32522b975d",
|
||||
"isPlugin": false,
|
||||
"loadPluginInWeb": true,
|
||||
"loadPluginInNative": true,
|
||||
"loadPluginInEditor": false,
|
||||
"subMetas": {}
|
||||
}
|
||||
49
frontend/assets/scripts/SelfPlayer.js
Normal file
49
frontend/assets/scripts/SelfPlayer.js
Normal file
@@ -0,0 +1,49 @@
|
||||
const BasePlayer = require("./BasePlayer");
|
||||
|
||||
cc.Class({
|
||||
extends: BasePlayer,
|
||||
// LIFE-CYCLE CALLBACKS:
|
||||
properties: {
|
||||
arrowTipNode: {
|
||||
type: cc.Node,
|
||||
default: null
|
||||
}
|
||||
},
|
||||
start() {
|
||||
BasePlayer.prototype.start.call(this);
|
||||
},
|
||||
|
||||
onLoad() {
|
||||
BasePlayer.prototype.onLoad.call(this);
|
||||
this.attackedClips = {
|
||||
'01': 'attackedLeft',
|
||||
'0-1': 'attackedRight',
|
||||
'-20': 'attackedLeft',
|
||||
'20': 'attackedRight',
|
||||
'-21': 'attackedLeft',
|
||||
'21': 'attackedRight',
|
||||
'-2-1': 'attackedLeft',
|
||||
'2-1': 'attackedRight'
|
||||
};
|
||||
this.arrowTipNode.active = false;
|
||||
},
|
||||
|
||||
showArrowTipNode() {
|
||||
const self = this;
|
||||
if (null == self.arrowTipNode) {
|
||||
return;
|
||||
}
|
||||
self.arrowTipNode.active = true;
|
||||
window.setTimeout(function(){
|
||||
if (null == self.arrowTipNode) {
|
||||
return;
|
||||
}
|
||||
self.arrowTipNode.active = false;
|
||||
}, 3000)
|
||||
},
|
||||
|
||||
update(dt) {
|
||||
BasePlayer.prototype.update.call(this, dt);
|
||||
},
|
||||
|
||||
});
|
||||
9
frontend/assets/scripts/SelfPlayer.js.meta
Normal file
9
frontend/assets/scripts/SelfPlayer.js.meta
Normal file
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"ver": "1.0.5",
|
||||
"uuid": "b74b0e58-0ea6-4546-8e0e-919445657f24",
|
||||
"isPlugin": false,
|
||||
"loadPluginInWeb": true,
|
||||
"loadPluginInNative": true,
|
||||
"loadPluginInEditor": false,
|
||||
"subMetas": {}
|
||||
}
|
||||
26
frontend/assets/scripts/SimplePressToGoDialog.js
Normal file
26
frontend/assets/scripts/SimplePressToGoDialog.js
Normal file
@@ -0,0 +1,26 @@
|
||||
cc.Class({
|
||||
extends: cc.Component,
|
||||
properties: {
|
||||
|
||||
},
|
||||
|
||||
start() {
|
||||
|
||||
},
|
||||
|
||||
onLoad() {
|
||||
},
|
||||
|
||||
update(dt) {
|
||||
},
|
||||
|
||||
dismissDialog(postDismissalByYes, evt) {
|
||||
const self = this;
|
||||
const target = evt.target;
|
||||
self.node.parent.removeChild(self.node);
|
||||
if ("Yes" == target._name) {
|
||||
// This is a dirty hack!
|
||||
postDismissalByYes();
|
||||
}
|
||||
}
|
||||
});
|
||||
9
frontend/assets/scripts/SimplePressToGoDialog.js.meta
Normal file
9
frontend/assets/scripts/SimplePressToGoDialog.js.meta
Normal file
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"ver": "1.0.5",
|
||||
"uuid": "27562abf-fe68-427f-b598-b8e53aca6e87",
|
||||
"isPlugin": false,
|
||||
"loadPluginInWeb": true,
|
||||
"loadPluginInNative": true,
|
||||
"loadPluginInEditor": false,
|
||||
"subMetas": {}
|
||||
}
|
||||
784
frontend/assets/scripts/TileCollisionManagerSingleton.js
Normal file
784
frontend/assets/scripts/TileCollisionManagerSingleton.js
Normal file
@@ -0,0 +1,784 @@
|
||||
"use strict";
|
||||
|
||||
window.ALL_DISCRETE_DIRECTIONS_CLOCKWISE = [{
|
||||
dx: 0,
|
||||
dy: 1
|
||||
}, {
|
||||
dx: 2,
|
||||
dy: 1
|
||||
}, {
|
||||
dx: 2,
|
||||
dy: 0
|
||||
}, {
|
||||
dx: 2,
|
||||
dy: -1
|
||||
}, {
|
||||
dx: 0,
|
||||
dy: -1
|
||||
}, {
|
||||
dx: -2,
|
||||
dy: -1
|
||||
}, {
|
||||
dx: -2,
|
||||
dy: 0
|
||||
}, {
|
||||
dx: -2,
|
||||
dy: 1
|
||||
}];
|
||||
|
||||
function TileCollisionManager() { }
|
||||
|
||||
TileCollisionManager.prototype._continuousFromCentreOfDiscreteTile = function (tiledMapNode, tiledMapIns, layerIns, discretePosX, discretePosY) {
|
||||
var mapOrientation = tiledMapIns.getMapOrientation();
|
||||
var mapTileRectilinearSize = tiledMapIns.getTileSize();
|
||||
var mapAnchorOffset = cc.v2(0, 0);
|
||||
var tileSize = {
|
||||
width: 0,
|
||||
height: 0
|
||||
};
|
||||
var layerOffset = cc.v2(0, 0);
|
||||
|
||||
switch (mapOrientation) {
|
||||
case cc.TiledMap.Orientation.ORTHO:
|
||||
return null;
|
||||
|
||||
case cc.TiledMap.Orientation.ISO:
|
||||
var tileSizeUnifiedLength = Math.sqrt(mapTileRectilinearSize.width * mapTileRectilinearSize.width / 4 + mapTileRectilinearSize.height * mapTileRectilinearSize.height / 4);
|
||||
tileSize = {
|
||||
width: tileSizeUnifiedLength,
|
||||
height: tileSizeUnifiedLength
|
||||
};
|
||||
var cosineThetaRadian = mapTileRectilinearSize.width / 2 / tileSizeUnifiedLength;
|
||||
var sineThetaRadian = mapTileRectilinearSize.height / 2 / tileSizeUnifiedLength;
|
||||
mapAnchorOffset = cc.v2(
|
||||
tiledMapNode.getContentSize().width * (0.5 - tiledMapNode.getAnchorPoint().x),
|
||||
tiledMapNode.getContentSize().height * (1 - tiledMapNode.getAnchorPoint().y)
|
||||
);
|
||||
layerOffset = cc.v2(0, 0);
|
||||
var transMat = [
|
||||
[cosineThetaRadian, -cosineThetaRadian],
|
||||
[-sineThetaRadian, -sineThetaRadian]
|
||||
];
|
||||
var tmpContinuousX = (parseFloat(discretePosX) + 0.5) * tileSizeUnifiedLength;
|
||||
var tmpContinuousY = (parseFloat(discretePosY) + 0.5) * tileSizeUnifiedLength;
|
||||
var dContinuousXWrtMapNode = transMat[0][0] * tmpContinuousX + transMat[0][1] * tmpContinuousY;
|
||||
var dContinuousYWrtMapNode = transMat[1][0] * tmpContinuousX + transMat[1][1] * tmpContinuousY;
|
||||
return cc.v2(dContinuousXWrtMapNode, dContinuousYWrtMapNode).add(mapAnchorOffset);
|
||||
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
TileCollisionManager.prototype._continuousToDiscrete = function (tiledMapNode, tiledMapIns, continuousNewPosLocalToMap, continuousOldPosLocalToMap) {
|
||||
/*
|
||||
* References
|
||||
* - http://cocos2d-x.org/docs/api-ref/creator/v1.5/classes/TiledMap.html
|
||||
* - http://cocos2d-x.org/docs/api-ref/creator/v1.5/classes/TiledLayer.html
|
||||
* - http://docs.mapeditor.org/en/stable/reference/tmx-map-format/?highlight=orientation#map
|
||||
*/
|
||||
var mapOrientation = tiledMapIns.getMapOrientation();
|
||||
var mapTileRectilinearSize = tiledMapIns.getTileSize();
|
||||
var mapAnchorOffset = {
|
||||
x: 0,
|
||||
y: 0
|
||||
};
|
||||
var tileSize = {
|
||||
width: 0,
|
||||
height: 0
|
||||
};
|
||||
var layerOffset = {
|
||||
x: 0,
|
||||
y: 0
|
||||
};
|
||||
var convertedContinuousOldXInTileCoordinates = null;
|
||||
var convertedContinuousOldYInTileCoordinates = null;
|
||||
var convertedContinuousNewXInTileCoordinates = null;
|
||||
var convertedContinuousNewYInTileCoordinates = null;
|
||||
var oldWholeMultipleX = 0;
|
||||
var oldWholeMultipleY = 0;
|
||||
var newWholeMultipleX = 0;
|
||||
var newWholeMultipleY = 0;
|
||||
var discretePosX = 0;
|
||||
var discretePosY = 0;
|
||||
var exactBorderX = 0;
|
||||
var exactBorderY = 0; // These tmp variables are NOT NECESSARILY useful.
|
||||
|
||||
var oldTmpX = 0;
|
||||
var oldTmpY = 0;
|
||||
var newTmpX = 0;
|
||||
var newTmpY = 0;
|
||||
|
||||
switch (mapOrientation) {
|
||||
case cc.TiledMap.Orientation.ORTHO:
|
||||
mapAnchorOffset = {
|
||||
x: -(tiledMapNode.getContentSize().width * tiledMapNode.getAnchorPoint().x),
|
||||
y: tiledMapNode.getContentSize().height * (1 - tiledMapNode.getAnchorPoint().y)
|
||||
};
|
||||
layerOffset = {
|
||||
x: 0,
|
||||
y: 0
|
||||
};
|
||||
tileSize = mapTileRectilinearSize;
|
||||
convertedContinuousOldXInTileCoordinates = continuousOldPosLocalToMap.x - layerOffset.x - mapAnchorOffset.x;
|
||||
convertedContinuousOldYInTileCoordinates = mapAnchorOffset.y - (continuousOldPosLocalToMap.y - layerOffset.y);
|
||||
convertedContinuousNewXInTileCoordinates = continuousNewPosLocalToMap.x - layerOffset.x - mapAnchorOffset.x;
|
||||
convertedContinuousNewYInTileCoordinates = mapAnchorOffset.y - (continuousNewPosLocalToMap.y - layerOffset.y);
|
||||
break;
|
||||
|
||||
case cc.TiledMap.Orientation.ISO:
|
||||
var tileSizeUnifiedLength = Math.sqrt(mapTileRectilinearSize.width * mapTileRectilinearSize.width / 4 + mapTileRectilinearSize.height * mapTileRectilinearSize.height / 4);
|
||||
tileSize = {
|
||||
width: tileSizeUnifiedLength,
|
||||
height: tileSizeUnifiedLength
|
||||
};
|
||||
var cosineThetaRadian = mapTileRectilinearSize.width / 2 / tileSizeUnifiedLength;
|
||||
var sineThetaRadian = mapTileRectilinearSize.height / 2 / tileSizeUnifiedLength;
|
||||
mapAnchorOffset = {
|
||||
x: tiledMapNode.getContentSize().width * (0.5 - tiledMapNode.getAnchorPoint().x),
|
||||
y: tiledMapNode.getContentSize().height * (1 - tiledMapNode.getAnchorPoint().y)
|
||||
};
|
||||
layerOffset = {
|
||||
x: 0,
|
||||
y: 0
|
||||
};
|
||||
oldTmpX = continuousOldPosLocalToMap.x - layerOffset.x - mapAnchorOffset.x;
|
||||
oldTmpY = continuousOldPosLocalToMap.y - layerOffset.y - mapAnchorOffset.y;
|
||||
newTmpX = continuousNewPosLocalToMap.x - layerOffset.x - mapAnchorOffset.x;
|
||||
newTmpY = continuousNewPosLocalToMap.y - layerOffset.y - mapAnchorOffset.y;
|
||||
var transMat = [[1 / (2 * cosineThetaRadian), -1 / (2 * sineThetaRadian)], [-1 / (2 * cosineThetaRadian), -1 / (2 * sineThetaRadian)]];
|
||||
convertedContinuousOldXInTileCoordinates = transMat[0][0] * oldTmpX + transMat[0][1] * oldTmpY;
|
||||
convertedContinuousOldYInTileCoordinates = transMat[1][0] * oldTmpX + transMat[1][1] * oldTmpY;
|
||||
convertedContinuousNewXInTileCoordinates = transMat[0][0] * newTmpX + transMat[0][1] * newTmpY;
|
||||
convertedContinuousNewYInTileCoordinates = transMat[1][0] * newTmpX + transMat[1][1] * newTmpY;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (null == convertedContinuousOldXInTileCoordinates || null == convertedContinuousOldYInTileCoordinates || null == convertedContinuousNewXInTileCoordinates || null == convertedContinuousNewYInTileCoordinates) {
|
||||
return null;
|
||||
}
|
||||
|
||||
oldWholeMultipleX = Math.floor(convertedContinuousOldXInTileCoordinates / tileSize.width);
|
||||
oldWholeMultipleY = Math.floor(convertedContinuousOldYInTileCoordinates / tileSize.height);
|
||||
newWholeMultipleX = Math.floor(convertedContinuousNewXInTileCoordinates / tileSize.width);
|
||||
newWholeMultipleY = Math.floor(convertedContinuousNewYInTileCoordinates / tileSize.height); // Mind that the calculation of `exactBorderY` is different for `convertedContinuousOldYInTileCoordinates <> convertedContinuousNewYInTileCoordinates`.
|
||||
|
||||
if (convertedContinuousOldYInTileCoordinates < convertedContinuousNewYInTileCoordinates) {
|
||||
exactBorderY = newWholeMultipleY * tileSize.height;
|
||||
|
||||
if (convertedContinuousNewYInTileCoordinates > exactBorderY && convertedContinuousOldYInTileCoordinates <= exactBorderY) {
|
||||
// Will try to cross the border if (newWholeMultipleY != oldWholeMultipleY).
|
||||
discretePosY = newWholeMultipleY;
|
||||
} else {
|
||||
discretePosY = oldWholeMultipleY;
|
||||
}
|
||||
} else if (convertedContinuousOldYInTileCoordinates > convertedContinuousNewYInTileCoordinates) {
|
||||
exactBorderY = oldWholeMultipleY * tileSize.height;
|
||||
|
||||
if (convertedContinuousNewYInTileCoordinates < exactBorderY && convertedContinuousOldYInTileCoordinates >= exactBorderY) {
|
||||
// Will try to cross the border if (newWholeMultipleY != oldWholeMultipleY).
|
||||
discretePosY = newWholeMultipleY;
|
||||
} else {
|
||||
discretePosY = oldWholeMultipleY;
|
||||
}
|
||||
} else {
|
||||
discretePosY = oldWholeMultipleY;
|
||||
} // Mind that the calculation of `exactBorderX` is different for `convertedContinuousOldXInTileCoordinates <> convertedContinuousNewXInTileCoordinates`.
|
||||
|
||||
|
||||
if (convertedContinuousOldXInTileCoordinates < convertedContinuousNewXInTileCoordinates) {
|
||||
exactBorderX = newWholeMultipleX * tileSize.width;
|
||||
|
||||
if (convertedContinuousNewXInTileCoordinates > exactBorderX && convertedContinuousOldXInTileCoordinates <= exactBorderX) {
|
||||
// Will cross the border if (newWholeMultipleX != oldWholeMultipleX).
|
||||
discretePosX = newWholeMultipleX;
|
||||
} else {
|
||||
discretePosX = oldWholeMultipleX;
|
||||
}
|
||||
} else if (convertedContinuousOldXInTileCoordinates > convertedContinuousNewXInTileCoordinates) {
|
||||
exactBorderX = oldWholeMultipleX * tileSize.width;
|
||||
|
||||
if (convertedContinuousNewXInTileCoordinates < exactBorderX && convertedContinuousOldXInTileCoordinates >= exactBorderX) {
|
||||
// Will cross the border if (newWholeMultipleX != oldWholeMultipleX).
|
||||
discretePosX = newWholeMultipleX;
|
||||
} else {
|
||||
discretePosX = oldWholeMultipleX;
|
||||
}
|
||||
} else {
|
||||
discretePosX = oldWholeMultipleX;
|
||||
}
|
||||
|
||||
return {
|
||||
x: discretePosX,
|
||||
y: discretePosY
|
||||
};
|
||||
};
|
||||
|
||||
TileCollisionManager.prototype.continuousMapNodeVecToContinuousObjLayerVec = function (withTiledMapNode, continuousMapNodeVec) {
|
||||
var tiledMapIns = withTiledMapNode.getComponent(cc.TiledMap);
|
||||
|
||||
var mapOrientation = tiledMapIns.getMapOrientation();
|
||||
var mapTileRectilinearSize = tiledMapIns.getTileSize();
|
||||
|
||||
switch (mapOrientation) {
|
||||
case cc.TiledMap.Orientation.ORTHO:
|
||||
// TODO
|
||||
return null;
|
||||
|
||||
case cc.TiledMap.Orientation.ISO:
|
||||
var tileSizeUnifiedLength = Math.sqrt(mapTileRectilinearSize.width * mapTileRectilinearSize.width * 0.25 + mapTileRectilinearSize.height * mapTileRectilinearSize.height * 0.25);
|
||||
var isometricObjectLayerPointOffsetScaleFactor = (tileSizeUnifiedLength / mapTileRectilinearSize.height);
|
||||
var inverseIsometricObjectLayerPointOffsetScaleFactor = 1 / isometricObjectLayerPointOffsetScaleFactor;
|
||||
|
||||
var cosineThetaRadian = (mapTileRectilinearSize.width * 0.5) / tileSizeUnifiedLength;
|
||||
var sineThetaRadian = (mapTileRectilinearSize.height * 0.5) / tileSizeUnifiedLength;
|
||||
|
||||
var inverseTransMat = [
|
||||
[inverseIsometricObjectLayerPointOffsetScaleFactor * 0.5 * (1 / cosineThetaRadian), - inverseIsometricObjectLayerPointOffsetScaleFactor * 0.5 * (1 / sineThetaRadian)],
|
||||
[- inverseIsometricObjectLayerPointOffsetScaleFactor * 0.5 * (1 / cosineThetaRadian), - inverseIsometricObjectLayerPointOffsetScaleFactor * 0.5 * (1 / sineThetaRadian)]
|
||||
];
|
||||
var convertedVecX = inverseTransMat[0][0] * continuousMapNodeVec.x + inverseTransMat[0][1] * continuousMapNodeVec.y;
|
||||
var convertedVecY = inverseTransMat[1][0] * continuousMapNodeVec.x + inverseTransMat[1][1] * continuousMapNodeVec.y;
|
||||
|
||||
return cc.v2(convertedVecX, convertedVecY);
|
||||
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
TileCollisionManager.prototype.continuousObjLayerVecToContinuousMapNodeVec = function (withTiledMapNode, continuousObjLayerVec) {
|
||||
var tiledMapIns = withTiledMapNode.getComponent(cc.TiledMap);
|
||||
|
||||
var mapOrientation = tiledMapIns.getMapOrientation();
|
||||
var mapTileRectilinearSize = tiledMapIns.getTileSize();
|
||||
|
||||
switch (mapOrientation) {
|
||||
case cc.TiledMap.Orientation.ORTHO:
|
||||
// TODO
|
||||
return null;
|
||||
|
||||
case cc.TiledMap.Orientation.ISO:
|
||||
var tileSizeUnifiedLength = Math.sqrt(mapTileRectilinearSize.width * mapTileRectilinearSize.width * 0.25 + mapTileRectilinearSize.height * mapTileRectilinearSize.height * 0.25);
|
||||
var isometricObjectLayerPointOffsetScaleFactor = (tileSizeUnifiedLength / mapTileRectilinearSize.height);
|
||||
|
||||
var cosineThetaRadian = (mapTileRectilinearSize.width * 0.5) / tileSizeUnifiedLength;
|
||||
var sineThetaRadian = (mapTileRectilinearSize.height * 0.5) / tileSizeUnifiedLength;
|
||||
|
||||
var transMat = [
|
||||
[isometricObjectLayerPointOffsetScaleFactor * cosineThetaRadian, - isometricObjectLayerPointOffsetScaleFactor * cosineThetaRadian],
|
||||
[- isometricObjectLayerPointOffsetScaleFactor * sineThetaRadian, - isometricObjectLayerPointOffsetScaleFactor * sineThetaRadian]
|
||||
];
|
||||
var convertedVecX = transMat[0][0] * continuousObjLayerVec.x + transMat[0][1] * continuousObjLayerVec.y;
|
||||
var convertedVecY = transMat[1][0] * continuousObjLayerVec.x + transMat[1][1] * continuousObjLayerVec.y;
|
||||
|
||||
return cc.v2(convertedVecX, convertedVecY);
|
||||
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
TileCollisionManager.prototype.continuousObjLayerOffsetToContinuousMapNodePos = function (withTiledMapNode, continuousObjLayerOffset) {
|
||||
var tiledMapIns = withTiledMapNode.getComponent(cc.TiledMap);
|
||||
|
||||
var mapOrientation = tiledMapIns.getMapOrientation();
|
||||
|
||||
switch (mapOrientation) {
|
||||
case cc.TiledMap.Orientation.ORTHO:
|
||||
// TODO
|
||||
return null;
|
||||
|
||||
case cc.TiledMap.Orientation.ISO:
|
||||
const calibratedVec = continuousObjLayerOffset; // TODO: Respect the real offsets!
|
||||
|
||||
// The immediately following statement takes a magic assumption that the anchor of `withTiledMapNode` is (0.5, 0.5) which is NOT NECESSARILY true.
|
||||
const layerOffset = cc.v2(0, +(withTiledMapNode.getContentSize().height * 0.5));
|
||||
|
||||
return layerOffset.add(this.continuousObjLayerVecToContinuousMapNodeVec(withTiledMapNode, calibratedVec));
|
||||
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
TileCollisionManager.prototype.continuousMapNodePosToContinuousObjLayerOffset = function (withTiledMapNode, continuousMapNodePos) {
|
||||
var tiledMapIns = withTiledMapNode.getComponent(cc.TiledMap);
|
||||
|
||||
var mapOrientation = tiledMapIns.getMapOrientation();
|
||||
var mapTileRectilinearSize = tiledMapIns.getTileSize();
|
||||
|
||||
switch (mapOrientation) {
|
||||
case cc.TiledMap.Orientation.ORTHO:
|
||||
// TODO
|
||||
return null;
|
||||
|
||||
case cc.TiledMap.Orientation.ISO:
|
||||
// The immediately following statement takes a magic assumption that the anchor of `withTiledMapNode` is (0.5, 0.5) which is NOT NECESSARILY true.
|
||||
var layerOffset = cc.v2(0, +(withTiledMapNode.getContentSize().height * 0.5));
|
||||
var calibratedVec = continuousMapNodePos.sub(layerOffset); // TODO: Respect the real offsets!
|
||||
return this.continuousMapNodeVecToContinuousObjLayerVec(withTiledMapNode, calibratedVec);
|
||||
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Note that `TileCollisionManager.extractBoundaryObjects` returns everything with coordinates local to `withTiledMapNode`!
|
||||
*/
|
||||
window.battleEntityTypeNameToGlobalGid = {};
|
||||
TileCollisionManager.prototype.extractBoundaryObjects = function (withTiledMapNode) {
|
||||
let toRet = {
|
||||
barriers: [],
|
||||
shelters: [],
|
||||
shelterChainTails: [],
|
||||
shelterChainHeads: [],
|
||||
sheltersZReducer: [],
|
||||
frameAnimations: [],
|
||||
grandBoundaries: [],
|
||||
};
|
||||
const tiledMapIns = withTiledMapNode.getComponent(cc.TiledMap); // This is a magic name.
|
||||
const mapTileSize = tiledMapIns.getTileSize();
|
||||
const mapOrientation = tiledMapIns.getMapOrientation();
|
||||
|
||||
/*
|
||||
* Copies from https://github.com/cocos-creator/engine/blob/master/cocos2d/tilemap/CCTiledMap.js as a hack to parse advanced <tile> info
|
||||
* of a TSX file. [BEGINS]
|
||||
*/
|
||||
const file = tiledMapIns._tmxFile;
|
||||
const texValues = file.textures;
|
||||
const texKeys = file.textureNames;
|
||||
const textures = {};
|
||||
for (let texIdx = 0; texIdx < texValues.length; ++texIdx) {
|
||||
textures[texKeys[texIdx]] = texValues[texIdx];
|
||||
}
|
||||
|
||||
const tsxFileNames = file.tsxFileNames;
|
||||
const tsxFiles = file.tsxFiles;
|
||||
let tsxMap = {};
|
||||
for (let tsxFilenameIdx = 0; tsxFilenameIdx < tsxFileNames.length; ++tsxFilenameIdx) {
|
||||
if (0 >= tsxFileNames[tsxFilenameIdx].length) continue;
|
||||
tsxMap[tsxFileNames[tsxFilenameIdx]] = tsxFiles[tsxFilenameIdx].text;
|
||||
}
|
||||
|
||||
const mapInfo = new cc.TMXMapInfo(file.tmxXmlStr, tsxMap, textures);
|
||||
const tileSets = mapInfo.getTilesets();
|
||||
/*
|
||||
* Copies from https://github.com/cocos-creator/engine/blob/master/cocos2d/tilemap/CCTiledMap.js as a hack to parse advanced <tile> info
|
||||
* of a TSX file. [ENDS]
|
||||
*/
|
||||
let gidBoundariesMap = {};
|
||||
const tilesElListUnderTilesets = {};
|
||||
for (let tsxFilenameIdx = 0; tsxFilenameIdx < tsxFileNames.length; ++tsxFilenameIdx) {
|
||||
const tsxOrientation = tileSets[tsxFilenameIdx].orientation;
|
||||
if (cc.TiledMap.Orientation.ORTHO == tsxOrientation) {
|
||||
cc.error("Error at tileset %s: We proceed with ONLY tilesets in ORTHO orientation for all map orientations by now.", tsxFileNames[tsxFilenameIdx]);
|
||||
continue;
|
||||
};
|
||||
|
||||
const tsxXMLStr = tsxMap[tsxFileNames[tsxFilenameIdx]];
|
||||
const selTileset = mapInfo._parser._parseXML(tsxXMLStr).documentElement;
|
||||
const firstGid = (parseInt(selTileset.getAttribute('firstgid')) || tileSets[tsxFilenameIdx].firstGid || 0);
|
||||
const currentTiles = selTileset.getElementsByTagName('tile');
|
||||
if (!currentTiles) continue;
|
||||
tilesElListUnderTilesets[tsxFileNames[tsxFilenameIdx]] = currentTiles;
|
||||
|
||||
for (let tileIdx = 0; tileIdx < currentTiles.length; ++tileIdx) {
|
||||
const currentTile = currentTiles[tileIdx];
|
||||
const parentGid = parseInt(firstGid) + parseInt(currentTile.getAttribute('id') || 0);
|
||||
let childrenOfCurrentTile = null;
|
||||
if (cc.sys.isNative) {
|
||||
childrenOfCurrentTile = currentTile.getElementsByTagName("objectgroup");
|
||||
} else if (cc.sys.platform == cc.sys.WECHAT_GAME) {
|
||||
childrenOfCurrentTile = currentTile.childNodes;
|
||||
} else {
|
||||
childrenOfCurrentTile = currentTile.children;
|
||||
}
|
||||
for (let childIdx = 0; childIdx < childrenOfCurrentTile.length; ++childIdx) {
|
||||
const ch = childrenOfCurrentTile[childIdx];
|
||||
if ('objectgroup' != ch.nodeName) continue;
|
||||
var currentObjectGroupUnderTile = mapInfo._parseObjectGroup(ch);
|
||||
gidBoundariesMap[parentGid] = {
|
||||
barriers: [],
|
||||
shelters: [],
|
||||
sheltersZReducer: [],
|
||||
};
|
||||
for (let oidx = 0; oidx < currentObjectGroupUnderTile._objects.length; ++oidx) {
|
||||
const oo = currentObjectGroupUnderTile._objects[oidx];
|
||||
const polylinePoints = oo.polylinePoints;
|
||||
if (null == polylinePoints) continue;
|
||||
const boundaryType = oo.boundary_type;
|
||||
switch (boundaryType) {
|
||||
case "LowScoreTreasure":
|
||||
case "HighScoreTreasure":
|
||||
case "GuardTower":
|
||||
const spriteFrameInfoForGid = getOrCreateSpriteFrameForGid(parentGid, mapInfo, tilesElListUnderTilesets);
|
||||
if (null != spriteFrameInfoForGid) {
|
||||
window.battleEntityTypeNameToGlobalGid[boundaryType] = parentGid;
|
||||
}
|
||||
break;
|
||||
case "barrier":
|
||||
let brToPushTmp = [];
|
||||
for (let bidx = 0; bidx < polylinePoints.length; ++bidx) {
|
||||
brToPushTmp.push(cc.v2(oo.x, oo.y).add(polylinePoints[bidx]));
|
||||
}
|
||||
brToPushTmp.boundaryType = boundaryType;
|
||||
gidBoundariesMap[parentGid].barriers.push(brToPushTmp);
|
||||
break;
|
||||
case "shelter":
|
||||
let shToPushTmp = [];
|
||||
for (let shidx = 0; shidx < polylinePoints.length; ++shidx) {
|
||||
shToPushTmp.push(cc.v2(oo.x, oo.y).add(polylinePoints[shidx]));
|
||||
}
|
||||
shToPushTmp.boundaryType = boundaryType;
|
||||
gidBoundariesMap[parentGid].shelters.push(shToPushTmp);
|
||||
break;
|
||||
case "shelter_z_reducer":
|
||||
let shzrToPushTmp = [];
|
||||
for (let shzridx = 0; shzridx < polylinePoints.length; ++shzridx) {
|
||||
shzrToPushTmp.push(cc.v2(oo.x, oo.y).add(polylinePoints[shzridx]));
|
||||
}
|
||||
shzrToPushTmp.boundaryType = boundaryType;
|
||||
gidBoundariesMap[parentGid].sheltersZReducer.push(shzrToPushTmp);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Reference http://docs.cocos.com/creator/api/en/classes/TiledMap.html.
|
||||
let allObjectGroups = tiledMapIns.getObjectGroups();
|
||||
|
||||
for (var i = 0; i < allObjectGroups.length; ++i) {
|
||||
// Reference http://docs.cocos.com/creator/api/en/classes/TiledObjectGroup.html.
|
||||
var objectGroup = allObjectGroups[i];
|
||||
if ("frame_anim" != objectGroup.getProperty("type")) continue;
|
||||
var allObjects = objectGroup.getObjects();
|
||||
for (var j = 0; j < allObjects.length; ++j) {
|
||||
var object = allObjects[j];
|
||||
var gid = object.gid;
|
||||
if (!gid || gid <= 0) {
|
||||
continue;
|
||||
}
|
||||
var animationClipInfoForGid = getOrCreateAnimationClipForGid(gid, mapInfo, tilesElListUnderTilesets);
|
||||
if (!animationClipInfoForGid) continue;
|
||||
toRet.frameAnimations.push({
|
||||
posInMapNode: this.continuousObjLayerOffsetToContinuousMapNodePos(withTiledMapNode, object.offset),
|
||||
origSize: animationClipInfoForGid.origSize,
|
||||
sizeInMapNode: cc.size(object.width, object.height),
|
||||
animationClip: animationClipInfoForGid.animationClip
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
for (let i = 0; i < allObjectGroups.length; ++i) {
|
||||
var objectGroup = allObjectGroups[i];
|
||||
if ("barrier_and_shelter" != objectGroup.getProperty("type")) continue;
|
||||
var allObjects = objectGroup.getObjects();
|
||||
for (let j = 0; j < allObjects.length; ++j) {
|
||||
let object = allObjects[j];
|
||||
let gid = object.gid;
|
||||
if (0 < gid) {
|
||||
continue;
|
||||
}
|
||||
const polylinePoints = object.polylinePoints;
|
||||
if (null == polylinePoints) {
|
||||
continue
|
||||
}
|
||||
for (let k = 0; k < polylinePoints.length; ++k) {
|
||||
/* Since CocosCreatorv2.1.3, the Y-coord of object polylines DIRECTLY DRAWN ON tmx with ISOMETRIC ORIENTATION is inverted. -- YFLu, 2019-11-01. */
|
||||
polylinePoints[k].y = -polylinePoints[k].y;
|
||||
}
|
||||
const boundaryType = object.boundary_type;
|
||||
switch (boundaryType) {
|
||||
case "barrier":
|
||||
let toPushBarriers = [];
|
||||
for (let k = 0; k < polylinePoints.length; ++k) {
|
||||
const tmp = object.offset.add(polylinePoints[k]);
|
||||
toPushBarriers.push(this.continuousObjLayerOffsetToContinuousMapNodePos(withTiledMapNode, tmp));
|
||||
}
|
||||
if (null != object.debug_mark) {
|
||||
console.log("Transformed ", polylinePoints, ", to ", toPushBarriers);
|
||||
}
|
||||
toPushBarriers.boundaryType = boundaryType;
|
||||
toRet.barriers.push(toPushBarriers);
|
||||
break;
|
||||
case "shelter":
|
||||
let toPushShelters = [];
|
||||
for (let kk = 0; kk < polylinePoints.length; ++kk) {
|
||||
toPushShelters.push(this.continuousObjLayerOffsetToContinuousMapNodePos(withTiledMapNode, object.offset.add(polylinePoints[kk])));
|
||||
}
|
||||
toPushShelters.boundaryType = boundaryType;
|
||||
toRet.shelters.push(toPushShelters);
|
||||
break;
|
||||
case "shelter_z_reducer":
|
||||
let toPushSheltersZReducer = [];
|
||||
for (let kkk = 0; kkk < polylinePoints.length; ++kkk) {
|
||||
toPushSheltersZReducer.push(this.continuousObjLayerOffsetToContinuousMapNodePos(withTiledMapNode, object.offset.add(polylinePoints[kkk])));
|
||||
}
|
||||
toPushSheltersZReducer.boundaryType = boundaryType;
|
||||
toRet.sheltersZReducer.push(toPushSheltersZReducer);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const allLayers = tiledMapIns.getLayers();
|
||||
|
||||
let layerDOMTrees = [];
|
||||
const mapDomTree = mapInfo._parser._parseXML(tiledMapIns.tmxAsset.tmxXmlStr).documentElement;
|
||||
const mapDOMAllChildren = (cc.sys.platform == cc.sys.WECHAT_GAME ? mapDomTree.childNodes : mapDomTree.children);
|
||||
for (let mdtIdx = 0; mdtIdx < mapDOMAllChildren.length; ++mdtIdx) {
|
||||
const tmpCh = mapDOMAllChildren[mdtIdx];
|
||||
if (mapInfo._shouldIgnoreNode(tmpCh)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (tmpCh.nodeName != 'layer') {
|
||||
continue;
|
||||
}
|
||||
layerDOMTrees.push(tmpCh);
|
||||
}
|
||||
|
||||
for (let j = 0; j < allLayers.length; ++j) {
|
||||
// TODO: Respect layer offset!
|
||||
const currentTileLayer = allLayers[j];
|
||||
const currentTileset = currentTileLayer.getTileSet();
|
||||
|
||||
if (!currentTileset) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const currentLayerSize = currentTileLayer.getLayerSize();
|
||||
|
||||
const currentLayerTileSize = currentTileset._tileSize;
|
||||
const firstGidInCurrentTileset = currentTileset.firstGid;
|
||||
|
||||
for (let discreteXInLayer = 0; discreteXInLayer < currentLayerSize.width; ++discreteXInLayer) {
|
||||
for (let discreteYInLayer = 0; discreteYInLayer < currentLayerSize.height; ++discreteYInLayer) {
|
||||
const currentGid = currentTileLayer.getTileGIDAt(discreteXInLayer, discreteYInLayer);
|
||||
if (0 >= currentGid) continue;
|
||||
const gidBoundaries = gidBoundariesMap[currentGid];
|
||||
if (!gidBoundaries) continue;
|
||||
switch (mapOrientation) {
|
||||
case cc.TiledMap.Orientation.ORTHO:
|
||||
// TODO
|
||||
return toRet;
|
||||
|
||||
case cc.TiledMap.Orientation.ISO:
|
||||
const centreOfAnchorTileInMapNode = this._continuousFromCentreOfDiscreteTile(withTiledMapNode, tiledMapIns, currentTileLayer, discreteXInLayer, discreteYInLayer);
|
||||
const topLeftOfWholeTsxTileInMapNode = centreOfAnchorTileInMapNode.add(cc.v2(-0.5 * mapTileSize.width, currentLayerTileSize.height - 0.5 * mapTileSize.height));
|
||||
for (let bidx = 0; bidx < gidBoundaries.barriers.length; ++bidx) {
|
||||
const theBarrier = gidBoundaries.barriers[bidx]; // An array of cc.v2 points.
|
||||
let brToPushTmp = [];
|
||||
for (let tbidx = 0; tbidx < theBarrier.length; ++tbidx) {
|
||||
brToPushTmp.push(topLeftOfWholeTsxTileInMapNode.add(cc.v2(theBarrier[tbidx].x, -theBarrier[tbidx].y /* Mind the reverse y-axis here. */)));
|
||||
}
|
||||
toRet.barriers.push(brToPushTmp);
|
||||
}
|
||||
for (let shidx = 0; shidx < gidBoundaries.shelters.length; ++shzridx) {
|
||||
const theShelter = gidBoundaries.shelters[shidx]; // An array of cc.v2 points.
|
||||
let shToPushTmp = [];
|
||||
for (let tshidx = 0; tshidx < theShelter.length; ++tshidx) {
|
||||
shToPushTmp.push(topLeftOfWholeTsxTileInMapNode.add(cc.v2(theShelter[tshidx].x, -theShelter[tshidx].y)));
|
||||
}
|
||||
toRet.shelters.push(shToPushTmp);
|
||||
}
|
||||
for (let shzridx = 0; shzridx < gidBoundaries.sheltersZReducer.length; ++shzridx) {
|
||||
const theShelter = gidBoundaries.sheltersZReducer[shzridx]; // An array of cc.v2 points.
|
||||
let shzrToPushTmp = [];
|
||||
for (let tshzridx = 0; tshzridx < theShelter.length; ++tshzridx) {
|
||||
shzrToPushTmp.push(topLeftOfWholeTsxTileInMapNode.add(cc.v2(theShelter[tshzridx].x, -theShelter[tshzridx].y)));
|
||||
}
|
||||
toRet.sheltersZReducer.push(shzrToPushTmp);
|
||||
}
|
||||
|
||||
continue;
|
||||
|
||||
default:
|
||||
return toRet;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return toRet;
|
||||
}
|
||||
|
||||
TileCollisionManager.prototype.isOutOfMapNode = function (tiledMapNode, continuousPosLocalToMap) {
|
||||
var tiledMapIns = tiledMapNode.getComponent(cc.TiledMap); // This is a magic name.
|
||||
|
||||
var mapOrientation = tiledMapIns.getMapOrientation();
|
||||
var mapTileRectilinearSize = tiledMapIns.getTileSize();
|
||||
|
||||
var mapContentSize = cc.size(tiledMapIns.getTileSize().width * tiledMapIns.getMapSize().width, tiledMapIns.getTileSize().height * tiledMapIns.getMapSize().height);
|
||||
|
||||
switch (mapOrientation) {
|
||||
case cc.TiledMap.Orientation.ORTHO:
|
||||
// TODO
|
||||
return true;
|
||||
|
||||
case cc.TiledMap.Orientation.ISO:
|
||||
var continuousObjLayerOffset = this.continuousMapNodePosToContinuousObjLayerOffset(tiledMapNode, continuousPosLocalToMap);
|
||||
return 0 > continuousObjLayerOffset.x || 0 > continuousObjLayerOffset.y || mapContentSize.width < continuousObjLayerOffset.x || mapContentSize.height < continuousObjLayerOffset.y;
|
||||
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
TileCollisionManager.prototype.initMapNodeByTiledBoundaries = function(mapScriptIns, mapNode, extractedBoundaryObjs) {
|
||||
const tiledMapIns = mapNode.getComponent(cc.TiledMap);
|
||||
if (extractedBoundaryObjs.grandBoundaries) {
|
||||
window.grandBoundary = [];
|
||||
for (let boundaryObj of extractedBoundaryObjs.grandBoundaries) {
|
||||
for (let p of boundaryObj) {
|
||||
if (CC_DEBUG) {
|
||||
const labelNode = new cc.Node();
|
||||
labelNode.setPosition(p);
|
||||
const label = labelNode.addComponent(cc.Label);
|
||||
label.string = "GB_(" + p.x.toFixed(2) + ", " + p.y.toFixed(2) + ")";
|
||||
safelyAddChild(mapNode, labelNode);
|
||||
setLocalZOrder(labelNode, 999);
|
||||
}
|
||||
window.grandBoundary.push(p);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
mapScriptIns.dictOfTiledFrameAnimationList = {};
|
||||
for (let frameAnim of extractedBoundaryObjs.frameAnimations) {
|
||||
if (!frameAnim.type) {
|
||||
cc.warn("should bind a type to the frameAnim object layer");
|
||||
continue
|
||||
}
|
||||
const tiledMapIns = mapScriptIns.node.getComponent(cc.TiledMap);
|
||||
let frameAnimInType = mapScriptIns.dictOfTiledFrameAnimationList[frameAnim.type];
|
||||
if (!frameAnimInType) {
|
||||
mapScriptIns.dictOfTiledFrameAnimationList[frameAnim.type] = [];
|
||||
frameAnimInType = mapScriptIns.dictOfTiledFrameAnimationList[frameAnim.type];
|
||||
}
|
||||
const animNode = cc.instantiate(mapScriptIns.tiledAnimPrefab);
|
||||
const anim = animNode.getComponent(cc.Animation);
|
||||
animNode.setPosition(frameAnim.posInMapNode);
|
||||
animNode.width = frameAnim.sizeInMapNode.width;
|
||||
animNode.height = frameAnim.sizeInMapNode.height;
|
||||
animNode.setScale(frameAnim.sizeInMapNode.width / frameAnim.origSize.width, frameAnim.sizeInMapNode.height / frameAnim.origSize.height);
|
||||
animNode.opacity = 0;
|
||||
animNode.setAnchorPoint(cc.v2(0.5, 0)); // A special requirement for "image-type Tiled object" by "CocosCreator v2.0.1".
|
||||
safelyAddChild(mapScriptIns.node, animNode);
|
||||
setLocalZOrder(animNode, 5);
|
||||
anim.addClip(frameAnim.animationClip, "default");
|
||||
anim.play("default");
|
||||
frameAnimInType.push(animNode);
|
||||
}
|
||||
|
||||
for (let boundaryObj of extractedBoundaryObjs.shelterChainTails) {
|
||||
const newShelter = cc.instantiate(mapScriptIns.polygonBoundaryShelterPrefab);
|
||||
const newBoundaryOffsetInMapNode = cc.v2(boundaryObj[0].x, boundaryObj[0].y);
|
||||
newShelter.setPosition(newBoundaryOffsetInMapNode);
|
||||
newShelter.setAnchorPoint(cc.v2(0, 0));
|
||||
const newShelterColliderIns = newShelter.getComponent(cc.PolygonCollider);
|
||||
newShelterColliderIns.points = [];
|
||||
for (let p of boundaryObj) {
|
||||
newShelterColliderIns.points.push(p.sub(newBoundaryOffsetInMapNode));
|
||||
}
|
||||
newShelter.pTiledLayer = boundaryObj.pTiledLayer;
|
||||
newShelter.tileDiscretePos = boundaryObj.tileDiscretePos;
|
||||
if (null != boundaryObj.imageObject) {
|
||||
newShelter.imageObject = boundaryObj.imageObject;
|
||||
newShelter.tailOrHead = "tail";
|
||||
window.addToGlobalShelterChainVerticeMap(newShelter.imageObject.imageObjectNode); // Deliberately NOT adding at the "traversal of shelterChainHeads".
|
||||
}
|
||||
newShelter.boundaryObj = boundaryObj;
|
||||
mapScriptIns.node.addChild(newShelter);
|
||||
}
|
||||
|
||||
for (let boundaryObj of extractedBoundaryObjs.shelterChainHeads) {
|
||||
const newShelter = cc.instantiate(mapScriptIns.polygonBoundaryShelterPrefab);
|
||||
const newBoundaryOffsetInMapNode = cc.v2(boundaryObj[0].x, boundaryObj[0].y);
|
||||
newShelter.setPosition(newBoundaryOffsetInMapNode);
|
||||
newShelter.setAnchorPoint(cc.v2(0, 0));
|
||||
const newShelterColliderIns = newShelter.getComponent(cc.PolygonCollider);
|
||||
newShelterColliderIns.points = [];
|
||||
for (let p of boundaryObj) {
|
||||
newShelterColliderIns.points.push(p.sub(newBoundaryOffsetInMapNode));
|
||||
}
|
||||
newShelter.pTiledLayer = boundaryObj.pTiledLayer;
|
||||
newShelter.tileDiscretePos = boundaryObj.tileDiscretePos;
|
||||
if (null != boundaryObj.imageObject) {
|
||||
newShelter.imageObject = boundaryObj.imageObject;
|
||||
newShelter.tailOrHead = "head";
|
||||
}
|
||||
newShelter.boundaryObj = boundaryObj;
|
||||
mapScriptIns.node.addChild(newShelter);
|
||||
}
|
||||
|
||||
mapScriptIns.barrierColliders = [];
|
||||
for (let boundaryObj of extractedBoundaryObjs.barriers) {
|
||||
const newBarrier = cc.instantiate(mapScriptIns.polygonBoundaryBarrierPrefab);
|
||||
const newBoundaryOffsetInMapNode = cc.v2(boundaryObj[0].x, boundaryObj[0].y);
|
||||
newBarrier.setPosition(newBoundaryOffsetInMapNode);
|
||||
newBarrier.setAnchorPoint(cc.v2(0, 0));
|
||||
const newBarrierColliderIns = newBarrier.getComponent(cc.PolygonCollider);
|
||||
newBarrierColliderIns.points = [];
|
||||
for (let p of boundaryObj) {
|
||||
newBarrierColliderIns.points.push(p.sub(newBoundaryOffsetInMapNode));
|
||||
}
|
||||
mapScriptIns.barrierColliders.push(newBarrierColliderIns);
|
||||
mapScriptIns.node.addChild(newBarrier);
|
||||
}
|
||||
|
||||
for (let boundaryObj of extractedBoundaryObjs.sheltersZReducer) {
|
||||
const newShelter = cc.instantiate(mapScriptIns.polygonBoundaryShelterZReducerPrefab);
|
||||
const newBoundaryOffsetInMapNode = cc.v2(boundaryObj[0].x, boundaryObj[0].y);
|
||||
newShelter.setPosition(newBoundaryOffsetInMapNode);
|
||||
newShelter.setAnchorPoint(cc.v2(0, 0));
|
||||
const newShelterColliderIns = newShelter.getComponent(cc.PolygonCollider);
|
||||
newShelterColliderIns.points = [];
|
||||
for (let p of boundaryObj) {
|
||||
newShelterColliderIns.points.push(p.sub(newBoundaryOffsetInMapNode));
|
||||
}
|
||||
mapScriptIns.node.addChild(newShelter);
|
||||
}
|
||||
|
||||
const allLayers = tiledMapIns.getLayers();
|
||||
for (let layer of allLayers) {
|
||||
const layerType = layer.getProperty("type");
|
||||
switch (layerType) {
|
||||
case "barrier_and_shelter":
|
||||
setLocalZOrder(layer.node, 3);
|
||||
break;
|
||||
case "shelter_preview":
|
||||
layer.node.opacity = 100;
|
||||
setLocalZOrder(layer.node, 500);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
const allObjectGroups = tiledMapIns.getObjectGroups();
|
||||
for (let objectGroup of allObjectGroups) {
|
||||
const objectGroupType = objectGroup.getProperty("type");
|
||||
switch (objectGroupType) {
|
||||
case "barrier_and_shelter":
|
||||
setLocalZOrder(objectGroup.node, 3);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
window.tileCollisionManager = new TileCollisionManager();
|
||||
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"ver": "1.0.5",
|
||||
"uuid": "91a92fb7-f06a-4b7e-8438-eb743ee49e4e",
|
||||
"isPlugin": false,
|
||||
"loadPluginInWeb": true,
|
||||
"loadPluginInNative": true,
|
||||
"loadPluginInEditor": false,
|
||||
"subMetas": {}
|
||||
}
|
||||
387
frontend/assets/scripts/TouchEventsManager.js
Normal file
387
frontend/assets/scripts/TouchEventsManager.js
Normal file
@@ -0,0 +1,387 @@
|
||||
window.DIRECTION_DECODER = [
|
||||
[0, 0],
|
||||
[0, +1],
|
||||
[0, -1],
|
||||
[+2, 0],
|
||||
[-2, 0],
|
||||
[+2, +1],
|
||||
[-2, -1],
|
||||
[+2, -1],
|
||||
[-2, +1],
|
||||
[+2, 0],
|
||||
[-2, 0],
|
||||
[0, +1],
|
||||
[0, -1],
|
||||
];
|
||||
|
||||
cc.Class({
|
||||
extends: cc.Component,
|
||||
properties: {
|
||||
// For joystick begins.
|
||||
translationListenerNode: {
|
||||
default: null,
|
||||
type: cc.Node
|
||||
},
|
||||
zoomingListenerNode: {
|
||||
default: null,
|
||||
type: cc.Node
|
||||
},
|
||||
stickhead: {
|
||||
default: null,
|
||||
type: cc.Node
|
||||
},
|
||||
base: {
|
||||
default: null,
|
||||
type: cc.Node
|
||||
},
|
||||
joyStickEps: {
|
||||
default: 0.10,
|
||||
type: cc.Float
|
||||
},
|
||||
magicLeanLowerBound: {
|
||||
default: 0.414, // Tangent of (PI/8).
|
||||
type: cc.Float
|
||||
},
|
||||
magicLeanUpperBound: {
|
||||
default: 2.414, // Tangent of (3*PI/8).
|
||||
type: cc.Float
|
||||
},
|
||||
// For joystick ends.
|
||||
linearScaleFacBase: {
|
||||
default: 1.00,
|
||||
type: cc.Float
|
||||
},
|
||||
minScale: {
|
||||
default: 1.00,
|
||||
type: cc.Float
|
||||
},
|
||||
maxScale: {
|
||||
default: 2.50,
|
||||
type: cc.Float
|
||||
},
|
||||
maxMovingBufferLength: {
|
||||
default: 1,
|
||||
type: cc.Integer
|
||||
},
|
||||
zoomingScaleFacBase: {
|
||||
default: 0.10,
|
||||
type: cc.Float
|
||||
},
|
||||
zoomingSpeedBase: {
|
||||
default: 4.0,
|
||||
type: cc.Float
|
||||
},
|
||||
linearSpeedBase: {
|
||||
default: 320.0,
|
||||
type: cc.Float
|
||||
},
|
||||
canvasNode: {
|
||||
default: null,
|
||||
type: cc.Node
|
||||
},
|
||||
mapNode: {
|
||||
default: null,
|
||||
type: cc.Node
|
||||
},
|
||||
linearMovingEps: {
|
||||
default: 0.10,
|
||||
type: cc.Float
|
||||
},
|
||||
scaleByEps: {
|
||||
default: 0.0375,
|
||||
type: cc.Float
|
||||
},
|
||||
},
|
||||
|
||||
start() {},
|
||||
|
||||
onLoad() {
|
||||
this.cachedStickHeadPosition = cc.v2(0.0, 0.0);
|
||||
this.canvasNode = this.mapNode.parent;
|
||||
this.mainCameraNode = this.canvasNode.getChildByName("Main Camera"); // Cannot drag and assign the `mainCameraNode` from CocosCreator EDITOR directly, otherwise it'll cause an infinite loading time, till v2.1.0.
|
||||
this.mainCamera = this.mainCameraNode.getComponent(cc.Camera);
|
||||
this.activeDirection = {
|
||||
dx: 0.0,
|
||||
dy: 0.0
|
||||
};
|
||||
this.maxHeadDistance = (0.5 * this.base.width);
|
||||
|
||||
this._initTouchEvent();
|
||||
this._cachedMapNodePosTarget = [];
|
||||
this._cachedZoomRawTarget = null;
|
||||
|
||||
this.mapScriptIns = this.mapNode.getComponent("Map");
|
||||
this.initialized = true;
|
||||
},
|
||||
|
||||
justifyMapNodePosAndScale(linearSpeedBase, zoomingSpeedBase) {
|
||||
const self = this;
|
||||
if (false == self.mapScriptIns._inputControlEnabled) return;
|
||||
if (null != self._cachedMapNodePosTarget) {
|
||||
while (self.maxMovingBufferLength < self._cachedMapNodePosTarget.length) {
|
||||
self._cachedMapNodePosTarget.shift();
|
||||
}
|
||||
if (0 < self._cachedMapNodePosTarget.length && 0 == self.mapNode.getNumberOfRunningActions()) {
|
||||
const nextMapNodePosTarget = self._cachedMapNodePosTarget.shift();
|
||||
const linearSpeed = linearSpeedBase;
|
||||
const finalDiffVec = nextMapNodePosTarget.pos.sub(self.mapNode.position);
|
||||
const finalDiffVecMag = finalDiffVec.mag();
|
||||
if (self.linearMovingEps > finalDiffVecMag) {
|
||||
// Jittering.
|
||||
// cc.log("Map node moving by finalDiffVecMag == %s is just jittering.", finalDiffVecMag);
|
||||
return;
|
||||
}
|
||||
const durationSeconds = finalDiffVecMag / linearSpeed;
|
||||
cc.log("Map node moving to %o in %s/%s == %s seconds.", nextMapNodePosTarget.pos, finalDiffVecMag, linearSpeed, durationSeconds);
|
||||
const bufferedTargetPos = cc.v2(nextMapNodePosTarget.pos.x, nextMapNodePosTarget.pos.y);
|
||||
self.mapNode.runAction(cc.sequence(
|
||||
cc.moveTo(durationSeconds, bufferedTargetPos),
|
||||
cc.callFunc(() => {
|
||||
if (self._isMapOverMoved(self.mapNode.position)) {
|
||||
self.mapNode.setPosition(bufferedTargetPos);
|
||||
}
|
||||
}, self)
|
||||
));
|
||||
}
|
||||
}
|
||||
if (null != self._cachedZoomRawTarget && false == self._cachedZoomRawTarget.processed) {
|
||||
cc.log(`Processing self._cachedZoomRawTarget == ${self._cachedZoomRawTarget}`);
|
||||
self._cachedZoomRawTarget.processed = true;
|
||||
self.mapNode.setScale(self._cachedZoomRawTarget.scale);
|
||||
}
|
||||
},
|
||||
|
||||
_initTouchEvent() {
|
||||
const self = this;
|
||||
const translationListenerNode = (self.translationListenerNode ? self.translationListenerNode : self.mapNode);
|
||||
const zoomingListenerNode = (self.zoomingListenerNode ? self.zoomingListenerNode : self.mapNode);
|
||||
|
||||
translationListenerNode.on(cc.Node.EventType.TOUCH_START, function(event) {
|
||||
self._touchStartEvent(event);
|
||||
});
|
||||
translationListenerNode.on(cc.Node.EventType.TOUCH_MOVE, function(event) {
|
||||
self._translationEvent(event);
|
||||
});
|
||||
translationListenerNode.on(cc.Node.EventType.TOUCH_END, function(event) {
|
||||
self._touchEndEvent(event);
|
||||
});
|
||||
translationListenerNode.on(cc.Node.EventType.TOUCH_CANCEL, function(event) {
|
||||
self._touchEndEvent(event);
|
||||
});
|
||||
translationListenerNode.inTouchPoints = new Map();
|
||||
|
||||
zoomingListenerNode.on(cc.Node.EventType.TOUCH_START, function(event) {
|
||||
self._touchStartEvent(event);
|
||||
});
|
||||
zoomingListenerNode.on(cc.Node.EventType.TOUCH_MOVE, function(event) {
|
||||
self._zoomingEvent(event);
|
||||
});
|
||||
zoomingListenerNode.on(cc.Node.EventType.TOUCH_END, function(event) {
|
||||
self._touchEndEvent(event);
|
||||
});
|
||||
zoomingListenerNode.on(cc.Node.EventType.TOUCH_CANCEL, function(event) {
|
||||
self._touchEndEvent(event);
|
||||
});
|
||||
zoomingListenerNode.inTouchPoints = new Map();
|
||||
},
|
||||
|
||||
_isMapOverMoved(mapTargetPos) {
|
||||
const virtualPlayerPos = cc.v2(-mapTargetPos.x, -mapTargetPos.y);
|
||||
return tileCollisionManager.isOutOfMapNode(this.mapNode, virtualPlayerPos);
|
||||
},
|
||||
|
||||
_touchStartEvent(event) {
|
||||
const theListenerNode = event.target;
|
||||
for (let touch of event._touches) {
|
||||
theListenerNode.inTouchPoints.set(touch._id, touch);
|
||||
}
|
||||
},
|
||||
|
||||
_translationEvent(event) {
|
||||
if (ALL_MAP_STATES.VISUAL != this.mapScriptIns.state) {
|
||||
return;
|
||||
}
|
||||
const theListenerNode = event.target;
|
||||
const linearScaleFacBase = this.linearScaleFacBase; // Not used yet.
|
||||
if (1 != theListenerNode.inTouchPoints.size) {
|
||||
return;
|
||||
}
|
||||
if (!theListenerNode.inTouchPoints.has(event.currentTouch._id)) {
|
||||
return;
|
||||
}
|
||||
const diffVec = event.currentTouch._point.sub(event.currentTouch._startPoint);
|
||||
const distance = diffVec.mag();
|
||||
const overMoved = (distance > this.maxHeadDistance);
|
||||
if (overMoved) {
|
||||
const ratio = (this.maxHeadDistance / distance);
|
||||
this.cachedStickHeadPosition = diffVec.mul(ratio);
|
||||
} else {
|
||||
const ratio = (distance / this.maxHeadDistance);
|
||||
this.cachedStickHeadPosition = diffVec.mul(ratio);
|
||||
}
|
||||
},
|
||||
|
||||
_zoomingEvent(event) {
|
||||
if (ALL_MAP_STATES.VISUAL != this.mapScriptIns.state) {
|
||||
return;
|
||||
}
|
||||
const theListenerNode = event.target;
|
||||
if (2 != theListenerNode.inTouchPoints.size) {
|
||||
return;
|
||||
}
|
||||
if (2 == event._touches.length) {
|
||||
const firstTouch = event._touches[0];
|
||||
const secondTouch = event._touches[1];
|
||||
|
||||
const startMagnitude = firstTouch._startPoint.sub(secondTouch._startPoint).mag();
|
||||
const currentMagnitude = firstTouch._point.sub(secondTouch._point).mag();
|
||||
|
||||
let scaleBy = (currentMagnitude / startMagnitude);
|
||||
scaleBy = 1 + (scaleBy - 1) * this.zoomingScaleFacBase;
|
||||
if (1 < scaleBy && Math.abs(scaleBy - 1) < this.scaleByEps) {
|
||||
// Jitterring.
|
||||
cc.log(`ScaleBy == ${scaleBy} is just jittering.`);
|
||||
return;
|
||||
}
|
||||
if (1 > scaleBy && Math.abs(scaleBy - 1) < 0.5 * this.scaleByEps) {
|
||||
// Jitterring.
|
||||
cc.log(`ScaleBy == ${scaleBy} is just jittering.`);
|
||||
return;
|
||||
}
|
||||
if (!this.mainCamera) return;
|
||||
const targetScale = this.mainCamera.zoomRatio * scaleBy;
|
||||
if (this.minScale > targetScale || targetScale > this.maxScale) {
|
||||
return;
|
||||
}
|
||||
this.mainCamera.zoomRatio = targetScale;
|
||||
for (let child of this.mainCameraNode.children) {
|
||||
child.setScale(1/targetScale);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
_touchEndEvent(event) {
|
||||
const theListenerNode = event.target;
|
||||
do {
|
||||
if (!theListenerNode.inTouchPoints.has(event.currentTouch._id)) {
|
||||
break;
|
||||
}
|
||||
const diffVec = event.currentTouch._point.sub(event.currentTouch._startPoint);
|
||||
const diffVecMag = diffVec.mag();
|
||||
if (this.linearMovingEps <= diffVecMag) {
|
||||
break;
|
||||
}
|
||||
// Only triggers map-state-switch when `diffVecMag` is sufficiently small.
|
||||
|
||||
if (ALL_MAP_STATES.VISUAL != this.mapScriptIns.state) {
|
||||
break;
|
||||
}
|
||||
|
||||
// TODO: Handle single-finger-click event.
|
||||
} while (false);
|
||||
this.cachedStickHeadPosition = cc.v2(0.0, 0.0);
|
||||
for (let touch of event._touches) {
|
||||
if (touch) {
|
||||
theListenerNode.inTouchPoints.delete(touch._id);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
_touchCancelEvent(event) {},
|
||||
|
||||
update(dt) {
|
||||
if (this.inMultiTouch) return;
|
||||
if (true != this.initialized) return;
|
||||
this.stickhead.setPosition(this.cachedStickHeadPosition);
|
||||
},
|
||||
|
||||
discretizeDirection(continuousDx, continuousDy, eps) {
|
||||
let ret = {
|
||||
dx: 0,
|
||||
dy: 0,
|
||||
encodedIdx: 0
|
||||
};
|
||||
if (Math.abs(continuousDx) < eps && Math.abs(continuousDy) < eps) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (Math.abs(continuousDx) < eps) {
|
||||
ret.dx = 0;
|
||||
if (0 < continuousDy) {
|
||||
ret.dy = +1; // up
|
||||
ret.encodedIdx = 1;
|
||||
} else {
|
||||
ret.dy = -1; // down
|
||||
ret.encodedIdx = 2;
|
||||
}
|
||||
} else if (Math.abs(continuousDy) < eps) {
|
||||
ret.dy = 0;
|
||||
if (0 < continuousDx) {
|
||||
ret.dx = +2; // right
|
||||
ret.encodedIdx = 3;
|
||||
} else {
|
||||
ret.dx = -2; // left
|
||||
ret.encodedIdx = 4;
|
||||
}
|
||||
} else {
|
||||
const criticalRatio = continuousDy / continuousDx;
|
||||
if (criticalRatio > this.magicLeanLowerBound && criticalRatio < this.magicLeanUpperBound) {
|
||||
if (0 < continuousDx) {
|
||||
ret.dx = +2;
|
||||
ret.dy = +1;
|
||||
ret.encodedIdx = 5;
|
||||
} else {
|
||||
ret.dx = -2;
|
||||
ret.dy = -1;
|
||||
ret.encodedIdx = 6;
|
||||
}
|
||||
} else if (criticalRatio > -this.magicLeanUpperBound && criticalRatio < -this.magicLeanLowerBound) {
|
||||
if (0 < continuousDx) {
|
||||
ret.dx = +2;
|
||||
ret.dy = -1;
|
||||
ret.encodedIdx = 7;
|
||||
} else {
|
||||
ret.dx = -2;
|
||||
ret.dy = +1;
|
||||
ret.encodedIdx = 8;
|
||||
}
|
||||
} else {
|
||||
if (Math.abs(criticalRatio) < 1) {
|
||||
ret.dy = 0;
|
||||
if (0 < continuousDx) {
|
||||
ret.dx = +2;
|
||||
ret.encodedIdx = 9;
|
||||
} else {
|
||||
ret.dx = -2;
|
||||
ret.encodedIdx = 10;
|
||||
}
|
||||
} else {
|
||||
ret.dx = 0;
|
||||
if (0 < continuousDy) {
|
||||
ret.dy = +1;
|
||||
ret.encodedIdx = 11;
|
||||
} else {
|
||||
ret.dy = -1;
|
||||
ret.encodedIdx = 12;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
},
|
||||
|
||||
decodeDirection(encodedDirection) {
|
||||
const mapped = window.DIRECTION_DECODER[encodedDirection];
|
||||
if (null == mapped) {
|
||||
console.error("Unexpected encodedDirection = ", encodedDirection);
|
||||
}
|
||||
return {
|
||||
dx: mapped[0],
|
||||
dy: mapped[1]
|
||||
}
|
||||
},
|
||||
|
||||
getDiscretizedDirection() {
|
||||
return this.discretizeDirection(this.cachedStickHeadPosition.x, this.cachedStickHeadPosition.y, this.joyStickEps);
|
||||
}
|
||||
});
|
||||
9
frontend/assets/scripts/TouchEventsManager.js.meta
Normal file
9
frontend/assets/scripts/TouchEventsManager.js.meta
Normal file
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"ver": "1.0.5",
|
||||
"uuid": "d34e3738-8dde-4da9-8b60-f25b4bf50493",
|
||||
"isPlugin": false,
|
||||
"loadPluginInWeb": true,
|
||||
"loadPluginInNative": true,
|
||||
"loadPluginInEditor": false,
|
||||
"subMetas": {}
|
||||
}
|
||||
26
frontend/assets/scripts/Treasure.js
Normal file
26
frontend/assets/scripts/Treasure.js
Normal file
@@ -0,0 +1,26 @@
|
||||
window.LOW_SCORE_TREASURE_TYPE = 1;
|
||||
window.HIGH_SCORE_TREASURE_TYPE = 2;
|
||||
|
||||
window.LOW_SCORE_TREASURE_SCORE = 100;
|
||||
window.HIGH_SCORE_TREASURE_SCORE = 200;
|
||||
|
||||
cc.Class({
|
||||
extends: cc.Component,
|
||||
|
||||
properties: {
|
||||
},
|
||||
|
||||
setData (treasureInfo) {
|
||||
const self = this;
|
||||
this.score = treasureInfo.score;
|
||||
this.type = treasureInfo.type;
|
||||
|
||||
this.treasureInfo = treasureInfo;
|
||||
|
||||
const spriteComponent = this.node.getComponent(cc.Sprite);
|
||||
const targetGid = (window.LOW_SCORE_TREASURE_TYPE == treasureInfo.type ? window.battleEntityTypeNameToGlobalGid["LowScoreTreasure"] : window.battleEntityTypeNameToGlobalGid["HighScoreTreasure"])
|
||||
spriteComponent.spriteFrame = window.getOrCreateSpriteFrameForGid(targetGid).spriteFrame;
|
||||
},
|
||||
|
||||
start() {},
|
||||
})
|
||||
9
frontend/assets/scripts/Treasure.js.meta
Normal file
9
frontend/assets/scripts/Treasure.js.meta
Normal file
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"ver": "1.0.5",
|
||||
"uuid": "5eea6ce5-0343-4776-80a4-fccd69bd099b",
|
||||
"isPlugin": false,
|
||||
"loadPluginInWeb": true,
|
||||
"loadPluginInNative": true,
|
||||
"loadPluginInEditor": false,
|
||||
"subMetas": {}
|
||||
}
|
||||
84
frontend/assets/scripts/TreasurePickedUpAnim.js
Normal file
84
frontend/assets/scripts/TreasurePickedUpAnim.js
Normal file
@@ -0,0 +1,84 @@
|
||||
cc.Class({
|
||||
extends: cc.Component,
|
||||
|
||||
properties: {
|
||||
pickedUpAnimNode: {
|
||||
type: cc.Node,
|
||||
default: null
|
||||
},
|
||||
durationMillis: {
|
||||
default: 0
|
||||
},
|
||||
binglingAnimNode: {
|
||||
type: cc.Node,
|
||||
default: null
|
||||
},
|
||||
binglingAnimDurationMillis: {
|
||||
default: 0
|
||||
},
|
||||
scoreLabelNode: {
|
||||
type: cc.Node,
|
||||
default: null
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
|
||||
setData (treasureInfo) {
|
||||
const self = this;
|
||||
this.score = treasureInfo.score ? treasureInfo.score : 100 ;
|
||||
this.type = treasureInfo.type ? treasureInfo.type : 1;
|
||||
this.scoreLabelNode.getComponent(cc.Label).string = this.score;
|
||||
const spriteComponent = this.pickedUpAnimNode.getComponent(cc.Sprite);
|
||||
//hardcode treasurePNG's path.
|
||||
cc.loader.loadRes("textures/treasures/"+ this.type, cc.SpriteFrame, function (err, frame) {
|
||||
if(err){
|
||||
cc.warn(err);
|
||||
return;
|
||||
}
|
||||
spriteComponent.spriteFrame = frame;
|
||||
})
|
||||
},
|
||||
|
||||
// LIFE-CYCLE CALLBACKS:
|
||||
update (dt) {
|
||||
const changingNode = this.pickedUpAnimNode;
|
||||
const elapsedMillis = Date.now() - this.startedAtMillis;
|
||||
if(elapsedMillis >= this.binglingAnimDurationMillis && null != this.binglingAnimNode && true == this.binglingAnimNode.active) {
|
||||
this.binglingAnimNode.active = false;
|
||||
this.startedAtMillis = Date.now();
|
||||
}
|
||||
if(this.binglingAnimNode.active)
|
||||
return;
|
||||
if (elapsedMillis > this.durationMillis) {
|
||||
this.node.destroy();
|
||||
return;
|
||||
}
|
||||
if (elapsedMillis <= this.firstDurationMillis) {
|
||||
let posDiff = cc.v2(0, dt * this.yIncreaseSpeed);
|
||||
changingNode.setPosition(changingNode.position.add(posDiff));
|
||||
this.scoreLabelNode.setPosition(this.scoreLabelNode.position.add(posDiff));
|
||||
changingNode.scale += (this.scaleIncreaseSpeed*dt);
|
||||
} else {
|
||||
let posDiff = cc.v2(dt * this.xIncreaseSpeed , ( -1 *dt * this.yDecreaseSpeed));
|
||||
changingNode.setPosition(changingNode.position.add(posDiff));
|
||||
this.scoreLabelNode.setPosition(this.scoreLabelNode.position.add(posDiff));
|
||||
changingNode.opacity -= dt * this.opacityDegradeSpeed;
|
||||
this.scoreLabelNode.opacity -= dt * this.opacityDegradeSpeed;
|
||||
}
|
||||
},
|
||||
|
||||
onLoad() {
|
||||
this.pickedUpAnimNode.scale = 0;
|
||||
this.startedAtMillis = Date.now();
|
||||
|
||||
this.firstDurationMillis = (0.8*this.durationMillis);
|
||||
this.yIncreaseSpeed = (200 *1000/this.firstDurationMillis);
|
||||
this.scaleIncreaseSpeed = (2 * 1000/this.firstDurationMillis);
|
||||
|
||||
this.scondDurationMillis = (0.2 * this.durationMillis );
|
||||
this.opacityDegradeSpeed = (255*1000/this.scondDurationMillis);
|
||||
this.yDecreaseSpeed = (30*1000/this.scondDurationMillis);
|
||||
this.xIncreaseSpeed = (20*1000/this.scondDurationMillis);
|
||||
}
|
||||
});
|
||||
9
frontend/assets/scripts/TreasurePickedUpAnim.js.meta
Normal file
9
frontend/assets/scripts/TreasurePickedUpAnim.js.meta
Normal file
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"ver": "1.0.5",
|
||||
"uuid": "697ef72c-27ee-4184-9ae3-885808d58153",
|
||||
"isPlugin": false,
|
||||
"loadPluginInWeb": true,
|
||||
"loadPluginInNative": true,
|
||||
"loadPluginInEditor": false,
|
||||
"subMetas": {}
|
||||
}
|
||||
28
frontend/assets/scripts/Type2NPCPlayer.js
Normal file
28
frontend/assets/scripts/Type2NPCPlayer.js
Normal file
@@ -0,0 +1,28 @@
|
||||
const BasePlayer = require("./BasePlayer");
|
||||
|
||||
cc.Class({
|
||||
extends: BasePlayer,
|
||||
|
||||
// LIFE-CYCLE CALLBACKS:
|
||||
start() {
|
||||
BasePlayer.prototype.start.call(this);
|
||||
},
|
||||
|
||||
onLoad() {
|
||||
BasePlayer.prototype.onLoad.call(this);
|
||||
this.clips = {
|
||||
'01': 'FlatHeadSisterRunTop',
|
||||
'0-1': 'FlatHeadSisterRunBottom',
|
||||
'-20': 'FlatHeadSisterRunLeft',
|
||||
'20': 'FlatHeadSisterRunRight',
|
||||
'-21': 'FlatHeadSisterRunTopLeft',
|
||||
'21': 'FlatHeadSisterRunTopRight',
|
||||
'-2-1': 'FlatHeadSisterRunBottomLeft',
|
||||
'2-1': 'FlatHeadSisterRunBottomRight'
|
||||
};
|
||||
},
|
||||
|
||||
update(dt) {
|
||||
},
|
||||
|
||||
});
|
||||
9
frontend/assets/scripts/Type2NPCPlayer.js.meta
Normal file
9
frontend/assets/scripts/Type2NPCPlayer.js.meta
Normal file
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"ver": "1.0.5",
|
||||
"uuid": "233a1795-0de3-4d7c-9ce6-c5736ade723f",
|
||||
"isPlugin": false,
|
||||
"loadPluginInWeb": true,
|
||||
"loadPluginInNative": true,
|
||||
"loadPluginInEditor": false,
|
||||
"subMetas": {}
|
||||
}
|
||||
628
frontend/assets/scripts/WechatGameLogin.js
Normal file
628
frontend/assets/scripts/WechatGameLogin.js
Normal file
@@ -0,0 +1,628 @@
|
||||
const i18n = require('LanguageData');
|
||||
i18n.init(window.language); // languageID should be equal to the one we input in New Language ID input field
|
||||
|
||||
const WECHAT_ON_HIDE_TARGET_ACTION = {
|
||||
SHARE_CHAT_MESSAGE: 8,
|
||||
CLOSE: 3,
|
||||
};
|
||||
|
||||
const pbStructRoot = require('./modules/room_downsync_frame_proto_bundle.forcemsg.js');
|
||||
window.RoomDownsyncFrame = pbStructRoot.treasurehunterx.RoomDownsyncFrame;
|
||||
window.BattleColliderInfo = pbStructRoot.treasurehunterx.BattleColliderInfo;
|
||||
|
||||
cc.Class({
|
||||
extends: cc.Component,
|
||||
|
||||
properties: {
|
||||
cavasNode: {
|
||||
default: null,
|
||||
type: cc.Node
|
||||
},
|
||||
backgroundNode: {
|
||||
default: null,
|
||||
type: cc.Node
|
||||
},
|
||||
loadingPrefab: {
|
||||
default: null,
|
||||
type: cc.Prefab
|
||||
},
|
||||
tipsLabel: {
|
||||
default: null,
|
||||
type: cc.Label,
|
||||
},
|
||||
|
||||
downloadProgress: {
|
||||
default: null,
|
||||
type: cc.ProgressBar,
|
||||
},
|
||||
writtenBytes: {
|
||||
default: null,
|
||||
type: cc.Label,
|
||||
},
|
||||
expectedToWriteBytes: {
|
||||
default: null,
|
||||
type: cc.Label,
|
||||
},
|
||||
|
||||
handlerProgress: {
|
||||
default: null,
|
||||
type: cc.ProgressBar,
|
||||
},
|
||||
handledUrlsCount: {
|
||||
default: null,
|
||||
type: cc.Label,
|
||||
},
|
||||
toHandledUrlsCount: {
|
||||
default: null,
|
||||
type: cc.Label,
|
||||
},
|
||||
},
|
||||
|
||||
|
||||
// LIFE-CYCLE CALLBACKS:
|
||||
onLoad() {
|
||||
wx.onShow((res) => {
|
||||
console.log("+++++ wx onShow(), onShow.res ", res);
|
||||
window.expectedRoomId = res.query.expectedRoomId;
|
||||
});
|
||||
wx.onHide((res) => {
|
||||
// Reference https://developers.weixin.qq.com/minigame/dev/api/wx.exitMiniProgram.html.
|
||||
console.log("+++++ wx onHide(), onHide.res: ", res);
|
||||
if (
|
||||
WECHAT_ON_HIDE_TARGET_ACTION == res.targetAction
|
||||
||
|
||||
"back" == res.mode // After "WeChat v7.0.4 on iOS"
|
||||
||
|
||||
"close" == res.mode
|
||||
) {
|
||||
window.clearLocalStorageAndBackToLoginScene();
|
||||
} else {
|
||||
// Deliberately left blank.
|
||||
}
|
||||
});
|
||||
|
||||
const self = this;
|
||||
self.getRetCodeList();
|
||||
self.getRegexList();
|
||||
|
||||
self.showTips(i18n.t("login.tips.AUTO_LOGIN_1"));
|
||||
self.checkIntAuthTokenExpire().then(
|
||||
() => {
|
||||
self.showTips(i18n.t("login.tips.AUTO_LOGIN_2"));
|
||||
const intAuthToken = JSON.parse(cc.sys.localStorage.getItem('selfPlayer')).intAuthToken;
|
||||
self.useTokenLogin(intAuthToken);
|
||||
},
|
||||
() => {
|
||||
// 调用wx.login然后请求登录。
|
||||
wx.authorize({
|
||||
scope: "scope.userInfo",
|
||||
success() {
|
||||
self.showTips(i18n.t("login.tips.WECHAT_AUTHORIZED_AND_INT_AUTH_TOKEN_LOGGING_IN"));
|
||||
wx.login({
|
||||
success(res) {
|
||||
console.log("wx login success, res: ", res);
|
||||
const code = res.code;
|
||||
|
||||
wx.getUserInfo({
|
||||
success(res) {
|
||||
const userInfo = res.userInfo;
|
||||
console.log("Get user info ok: ", userInfo);
|
||||
self.useWxCodeMiniGameLogin(code, userInfo);
|
||||
},
|
||||
fail(err) {
|
||||
console.error(i18n.t("login.tips.AUTO_LOGIN_FAILED_WILL_USE_MANUAL_LOGIN"), err);
|
||||
self.showTips(i18n.t("login.tips.AUTO_LOGIN_FAILED_WILL_USE_MANUAL_LOGIN"));
|
||||
self.createAuthorizeThenLoginButton();
|
||||
},
|
||||
})
|
||||
},
|
||||
fail(err) {
|
||||
if (err) {
|
||||
console.error(i18n.t("login.tips.AUTO_LOGIN_FAILED_WILL_USE_MANUAL_LOGIN"), err);
|
||||
self.showTips(i18n.t("login.tips.AUTO_LOGIN_FAILED_WILL_USE_MANUAL_LOGIN"));
|
||||
self.createAuthorizeThenLoginButton();
|
||||
}
|
||||
},
|
||||
});
|
||||
},
|
||||
fail(err) {
|
||||
console.error(i18n.t("login.tips.AUTO_LOGIN_FAILED_WILL_USE_MANUAL_LOGIN"), err);
|
||||
self.showTips(i18n.t("login.tips.AUTO_LOGIN_FAILED_WILL_USE_MANUAL_LOGIN"));
|
||||
self.createAuthorizeThenLoginButton();
|
||||
}
|
||||
})
|
||||
}
|
||||
);
|
||||
},
|
||||
|
||||
createAuthorizeThenLoginButton(tips) {
|
||||
const self = this;
|
||||
|
||||
let sysInfo = wx.getSystemInfoSync();
|
||||
//获取微信界面大小
|
||||
let width = sysInfo.screenWidth;
|
||||
let height = sysInfo.screenHeight;
|
||||
|
||||
let button = wx.createUserInfoButton({
|
||||
type: 'text',
|
||||
text: '',
|
||||
style: {
|
||||
left: 0,
|
||||
top: 0,
|
||||
width: width,
|
||||
height: height,
|
||||
backgroundColor: '#00000000', //最后两位为透明度
|
||||
color: '#ffffff',
|
||||
fontSize: 20,
|
||||
textAlign: "center",
|
||||
lineHeight: height,
|
||||
},
|
||||
});
|
||||
button.onTap((res) => {
|
||||
console.log(res);
|
||||
if (null != res.userInfo) {
|
||||
const userInfo = res.userInfo;
|
||||
self.showTips(i18n.t("login.tips.WECHAT_AUTHORIZED_AND_INT_AUTH_TOKEN_LOGGING_IN"));
|
||||
|
||||
wx.login({
|
||||
success(res) {
|
||||
console.log('wx.login success, res:', res);
|
||||
const code = res.code;
|
||||
self.useWxCodeMiniGameLogin(code, userInfo);
|
||||
button.destroy();
|
||||
},
|
||||
fail(err) {
|
||||
console.err(i18n.t("login.tips.AUTO_LOGIN_FAILED_WILL_USE_MANUAL_LOGIN"), err);
|
||||
self.showTips(i18n.t("login.tips.AUTO_LOGIN_FAILED_WILL_USE_MANUAL_LOGIN"));
|
||||
},
|
||||
});
|
||||
} else {
|
||||
self.showTips(i18n.t("login.tips.PLEASE_AUTHORIZE_WECHAT_LOGIN_FIRST"));
|
||||
}
|
||||
})
|
||||
|
||||
},
|
||||
|
||||
onDestroy() {
|
||||
console.log("+++++++ WechatGameLogin onDestroy()");
|
||||
},
|
||||
|
||||
showTips(text) {
|
||||
if (this.tipsLabel != null) {
|
||||
this.tipsLabel.string = text;
|
||||
} else {
|
||||
console.log('Login scene showTips failed')
|
||||
}
|
||||
},
|
||||
|
||||
getRetCodeList() {
|
||||
const self = this;
|
||||
self.retCodeDict = constants.RET_CODE;
|
||||
},
|
||||
|
||||
getRegexList() {
|
||||
const self = this;
|
||||
self.regexList = {
|
||||
EMAIL: /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/,
|
||||
PHONE: /^\+?[0-9]{8,14}$/,
|
||||
STREET_META: /^.{5,100}$/,
|
||||
LNG_LAT_TEXT: /^[0-9]+(\.[0-9]{4,6})$/,
|
||||
SEO_KEYWORD: /^.{2,50}$/,
|
||||
PASSWORD: /^.{6,50}$/,
|
||||
SMS_CAPTCHA_CODE: /^[0-9]{4}$/,
|
||||
ADMIN_HANDLE: /^.{4,50}$/,
|
||||
};
|
||||
},
|
||||
|
||||
onSMSCaptchaGetButtonClicked(evt) {
|
||||
var timerEnable = true;
|
||||
const self = this;
|
||||
if (!self.checkPhoneNumber('getCaptcha')) {
|
||||
return;
|
||||
}
|
||||
NetworkUtils.ajax({
|
||||
url: backendAddress.PROTOCOL + '://' + backendAddress.HOST + ':' + backendAddress.PORT + constants.ROUTE_PATH.API + constants.ROUTE_PATH.PLAYER +
|
||||
constants.ROUTE_PATH.VERSION + constants.ROUTE_PATH.SMS_CAPTCHA + constants.ROUTE_PATH.GET,
|
||||
type: 'GET',
|
||||
data: {
|
||||
phoneCountryCode: self.phoneCountryCodeInput.getComponent(cc.EditBox).string,
|
||||
phoneNum: self.phoneNumberInput.getComponent(cc.EditBox).string
|
||||
},
|
||||
success: function(res) {
|
||||
switch (res.ret) {
|
||||
case constants.RET_CODE.OK:
|
||||
self.phoneNumberTips.getComponent(cc.Label).string = '';
|
||||
self.captchaTips.getComponent(cc.Label).string = '';
|
||||
break;
|
||||
case constants.RET_CODE.DUPLICATED:
|
||||
self.captchaTips.getComponent(cc.Label).string = i18n.t("login.tips.DUPLICATED");
|
||||
break;
|
||||
case constants.RET_CODE.INCORRECT_PHONE_COUNTRY_CODE:
|
||||
case constants.RET_CODE.INCORRECT_PHONE_NUMBER:
|
||||
self.captchaTips.getComponent(cc.Label).string = i18n.t("login.tips.PHONE_ERR");
|
||||
break;
|
||||
case constants.RET_CODE.IS_TEST_ACC:
|
||||
self.smsLoginCaptchaInput.getComponent(cc.EditBox).string = res.smsLoginCaptcha;
|
||||
self.captchaTips.getComponent(cc.Label).string = i18n.t("login.tips.TEST_USER");
|
||||
timerEnable = false;
|
||||
// clearInterval(self.countdownTimer);
|
||||
break;
|
||||
case constants.RET_CODE.SMS_CAPTCHA_REQUESTED_TOO_FREQUENTLY:
|
||||
self.captchaTips.getComponent(cc.Label).string = i18n.t("login.tips.SMS_CAPTCHA_FREEQUENT_REQUIRE");
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (timerEnable)
|
||||
self.countdownTime(self);
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
countdownTime(self) {
|
||||
self.smsLoginCaptchaButton.off('click', self.onSMSCaptchaGetButtonClicked);
|
||||
self.smsLoginCaptchaButton.removeChild(self.smsGetCaptchaNode);
|
||||
self.smsWaitCountdownNode.parent = self.smsLoginCaptchaButton;
|
||||
var total = 20; // Magic number
|
||||
self.countdownTimer = setInterval(function() {
|
||||
if (total === 0) {
|
||||
self.smsWaitCountdownNode.parent.removeChild(self.smsWaitCountdownNode);
|
||||
self.smsGetCaptchaNode.parent = self.smsLoginCaptchaButton;
|
||||
self.smsWaitCountdownNode.getChildByName('WaitTimeLabel').getComponent(cc.Label).string = 20;
|
||||
self.smsLoginCaptchaButton.on('click', self.onSMSCaptchaGetButtonClicked);
|
||||
clearInterval(self.countdownTimer);
|
||||
} else {
|
||||
total--;
|
||||
self.smsWaitCountdownNode.getChildByName('WaitTimeLabel').getComponent(cc.Label).string = total;
|
||||
}
|
||||
}, 1000)
|
||||
|
||||
},
|
||||
|
||||
checkIntAuthTokenExpire() {
|
||||
return new Promise((resolve, reject) => {
|
||||
if (!cc.sys.localStorage.getItem("selfPlayer")) {
|
||||
reject();
|
||||
return;
|
||||
}
|
||||
const selfPlayer = JSON.parse(cc.sys.localStorage.getItem('selfPlayer'));
|
||||
(selfPlayer.intAuthToken && new Date().getTime() < selfPlayer.expiresAt) ? resolve() : reject();
|
||||
})
|
||||
},
|
||||
|
||||
checkPhoneNumber(type) {
|
||||
const self = this;
|
||||
const phoneNumberRegexp = self.regexList.PHONE;
|
||||
var phoneNumberString = self.phoneNumberInput.getComponent(cc.EditBox).string;
|
||||
if (phoneNumberString) {
|
||||
return true;
|
||||
if (!phoneNumberRegexp.test(phoneNumberString)) {
|
||||
self.captchaTips.getComponent(cc.Label).string = i18n.t("login.tips.PHONE_ERR");
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
if (type === 'getCaptcha' || type === 'login') {
|
||||
self.captchaTips.getComponent(cc.Label).string = i18n.t("login.tips.PHONE_ERR");
|
||||
}
|
||||
return false;
|
||||
}
|
||||
},
|
||||
|
||||
checkCaptcha(type) {
|
||||
const self = this;
|
||||
const captchaRegexp = self.regexList.SMS_CAPTCHA_CODE;
|
||||
var captchaString = self.smsLoginCaptchaInput.getComponent(cc.EditBox).string;
|
||||
|
||||
if (captchaString) {
|
||||
if (self.smsLoginCaptchaInput.getComponent(cc.EditBox).string.length !== 4 || (!captchaRegexp.test(captchaString))) {
|
||||
self.captchaTips.getComponent(cc.Label).string = i18n.t("login.tips.CAPTCHA_ERR");
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
if (type === 'login') {
|
||||
self.captchaTips.getComponent(cc.Label).string = i18n.t("login.tips.CAPTCHA_ERR");
|
||||
}
|
||||
return false;
|
||||
}
|
||||
},
|
||||
|
||||
useTokenLogin(_intAuthToken) {
|
||||
var self = this;
|
||||
NetworkUtils.ajax({
|
||||
url: backendAddress.PROTOCOL + '://' + backendAddress.HOST + ':' + backendAddress.PORT + constants.ROUTE_PATH.API + constants.ROUTE_PATH.PLAYER + constants.ROUTE_PATH.VERSION + constants.ROUTE_PATH.INT_AUTH_TOKEN + constants.ROUTE_PATH.LOGIN,
|
||||
type: "POST",
|
||||
data: {
|
||||
intAuthToken: _intAuthToken
|
||||
},
|
||||
success: function(resp) {
|
||||
self.onLoggedIn(resp);
|
||||
},
|
||||
error: function(xhr, status, errMsg) {
|
||||
console.log("Login attempt `useTokenLogin` failed, about to execute `clearBoundRoomIdInBothVolatileAndPersistentStorage`.");
|
||||
window.clearBoundRoomIdInBothVolatileAndPersistentStorage()
|
||||
|
||||
self.showTips(i18n.t("login.tips.AUTO_LOGIN_FAILED_WILL_USE_MANUAL_LOGIN"));
|
||||
self.createAuthorizeThenLoginButton();
|
||||
},
|
||||
timeout: function() {
|
||||
self.enableInteractiveControls(true);
|
||||
},
|
||||
});
|
||||
},
|
||||
|
||||
enableInteractiveControls(enabled) {},
|
||||
|
||||
onLoginButtonClicked(evt) {
|
||||
const self = this;
|
||||
if (!self.checkPhoneNumber('login') || !self.checkCaptcha('login')) {
|
||||
return;
|
||||
}
|
||||
self.loginParams = {
|
||||
phoneCountryCode: self.phoneCountryCodeInput.getComponent(cc.EditBox).string,
|
||||
phoneNum: self.phoneNumberInput.getComponent(cc.EditBox).string,
|
||||
smsLoginCaptcha: self.smsLoginCaptchaInput.getComponent(cc.EditBox).string
|
||||
};
|
||||
self.enableInteractiveControls(false);
|
||||
|
||||
NetworkUtils.ajax({
|
||||
url: backendAddress.PROTOCOL + '://' + backendAddress.HOST + ':' + backendAddress.PORT + constants.ROUTE_PATH.API + constants.ROUTE_PATH.PLAYER +
|
||||
constants.ROUTE_PATH.VERSION + constants.ROUTE_PATH.SMS_CAPTCHA + constants.ROUTE_PATH.LOGIN,
|
||||
type: "POST",
|
||||
data: self.loginParams,
|
||||
success: function(resp) {
|
||||
self.onLoggedIn(resp);
|
||||
},
|
||||
error: function(xhr, status, errMsg) {
|
||||
console.log("Login attempt `onLoginButtonClicked` failed, about to execute `clearBoundRoomIdInBothVolatileAndPersistentStorage`.");
|
||||
window.clearBoundRoomIdInBothVolatileAndPersistentStorage()
|
||||
},
|
||||
timeout: function() {
|
||||
self.enableInteractiveControls(true);
|
||||
}
|
||||
});
|
||||
},
|
||||
onWechatLoggedIn(res) {
|
||||
const self = this;
|
||||
if (constants.RET_CODE.OK == res.ret) {
|
||||
//根据服务器返回信息设置selfPlayer
|
||||
self.enableInteractiveControls(false);
|
||||
const date = Number(res.expiresAt);
|
||||
const selfPlayer = {
|
||||
expiresAt: date,
|
||||
playerId: res.playerId,
|
||||
intAuthToken: res.intAuthToken,
|
||||
displayName: res.displayName,
|
||||
avatar: res.avatar,
|
||||
}
|
||||
cc.sys.localStorage.setItem('selfPlayer', JSON.stringify(selfPlayer));
|
||||
|
||||
self.useTokenLogin(res.intAuthToken);
|
||||
} else {
|
||||
cc.sys.localStorage.removeItem("selfPlayer");
|
||||
window.clearBoundRoomIdInBothVolatileAndPersistentStorage();
|
||||
|
||||
self.showTips(i18n.t("login.tips.WECHAT_LOGIN_FAILED_TAP_SCREEN_TO_RETRY") + ", errorCode = " + res.ret);
|
||||
self.createAuthorizeThenLoginButton();
|
||||
}
|
||||
},
|
||||
|
||||
onLoggedIn(res) {
|
||||
const self = this;
|
||||
console.log("OnLoggedIn: ", res);
|
||||
if (constants.RET_CODE.OK == res.ret) {
|
||||
if (window.isUsingX5BlinkKernelOrWebkitWeChatKernel()) {
|
||||
window.initWxSdk = self.initWxSdk.bind(self);
|
||||
window.initWxSdk();
|
||||
}
|
||||
self.enableInteractiveControls(false);
|
||||
const date = Number(res.expiresAt);
|
||||
const selfPlayer = {
|
||||
expiresAt: date,
|
||||
playerId: res.playerId,
|
||||
intAuthToken: res.intAuthToken,
|
||||
avatar: res.avatar,
|
||||
displayName: res.displayName,
|
||||
name: res.name,
|
||||
}
|
||||
cc.sys.localStorage.setItem("selfPlayer", JSON.stringify(selfPlayer));
|
||||
console.log("cc.sys.localStorage.selfPlayer = ", cc.sys.localStorage.getItem("selfPlayer"));
|
||||
if (self.countdownTimer) {
|
||||
clearInterval(self.countdownTimer);
|
||||
}
|
||||
|
||||
cc.director.loadScene('default_map');
|
||||
} else {
|
||||
console.warn('onLoggedIn failed!')
|
||||
cc.sys.localStorage.removeItem("selfPlayer");
|
||||
window.clearBoundRoomIdInBothVolatileAndPersistentStorage();
|
||||
self.enableInteractiveControls(true);
|
||||
switch (res.ret) {
|
||||
case constants.RET_CODE.DUPLICATED:
|
||||
this.captchaTips.getComponent(cc.Label).string = i18n.t("login.tips.DUPLICATED");
|
||||
break;
|
||||
case constants.RET_CODE.TOKEN_EXPIRED:
|
||||
this.captchaTips.getComponent(cc.Label).string = i18n.t("login.tips.LOGIN_TOKEN_EXPIRED");
|
||||
break;
|
||||
case constants.RET_CODE.SMS_CAPTCHA_NOT_MATCH:
|
||||
self.captchaTips.getComponent(cc.Label).string = i18n.t("login.tips.SMS_CAPTCHA_NOT_MATCH");
|
||||
break;
|
||||
case constants.RET_CODE.INCORRECT_CAPTCHA:
|
||||
self.captchaTips.getComponent(cc.Label).string = i18n.t("login.tips.SMS_CAPTCHA_NOT_MATCH");
|
||||
break;
|
||||
case constants.RET_CODE.SMS_CAPTCHA_CODE_NOT_EXISTING:
|
||||
self.captchaTips.getComponent(cc.Label).string = i18n.t("login.tips.SMS_CAPTCHA_NOT_MATCH");
|
||||
break;
|
||||
case constants.RET_CODE.INCORRECT_PHONE_NUMBER:
|
||||
self.captchaTips.getComponent(cc.Label).string = i18n.t("login.tips.INCORRECT_PHONE_NUMBER");
|
||||
break;
|
||||
case constants.RET_CODE.INVALID_REQUEST_PARAM:
|
||||
self.captchaTips.getComponent(cc.Label).string = i18n.t("login.tips.INCORRECT_PHONE_NUMBER");
|
||||
break;
|
||||
case constants.RET_CODE.INCORRECT_PHONE_COUNTRY_CODE:
|
||||
case constants.RET_CODE.INCORRECT_PHONE_NUMBER:
|
||||
this.captchaTips.getComponent(cc.Label).string = i18n.t("login.tips.INCORRECT_PHONE_NUMBER");
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
self.showTips(i18n.t("login.tips.AUTO_LOGIN_FAILED_WILL_USE_MANUAL_LOGIN"));
|
||||
self.createAuthorizeThenLoginButton();
|
||||
}
|
||||
},
|
||||
|
||||
useWXCodeLogin(_code) {
|
||||
const self = this;
|
||||
NetworkUtils.ajax({
|
||||
url: backendAddress.PROTOCOL + '://' + backendAddress.HOST + ':' + backendAddress.PORT + constants.ROUTE_PATH.API + constants.ROUTE_PATH.PLAYER + constants.ROUTE_PATH.VERSION + constants.ROUTE_PATH.WECHAT + constants.ROUTE_PATH.LOGIN,
|
||||
type: "POST",
|
||||
data: {
|
||||
code: _code
|
||||
},
|
||||
success: function(res) {
|
||||
self.onWechatLoggedIn(res);
|
||||
},
|
||||
error: function(xhr, status, errMsg) {
|
||||
console.log("Login attempt `onLoginButtonClicked` failed, about to execute `clearBoundRoomIdInBothVolatileAndPersistentStorage`.");
|
||||
cc.sys.localStorage.removeItem("selfPlayer");
|
||||
window.clearBoundRoomIdInBothVolatileAndPersistentStorage();
|
||||
self.showTips(i18n.t("login.tips.WECHAT_LOGIN_FAILED_TAP_SCREEN_TO_RETRY") + ", errorMsg =" + errMsg);
|
||||
},
|
||||
timeout: function() {
|
||||
console.log("Login attempt `onLoginButtonClicked` timed out, about to execute `clearBoundRoomIdInBothVolatileAndPersistentStorage`.");
|
||||
cc.sys.localStorage.removeItem("selfPlayer");
|
||||
window.clearBoundRoomIdInBothVolatileAndPersistentStorage();
|
||||
self.showTips(i18n.t("login.tips.WECHAT_LOGIN_FAILED_TAP_SCREEN_TO_RETRY") + ", errorMsg =" + errMsg);
|
||||
},
|
||||
});
|
||||
},
|
||||
|
||||
// 对比useWxCodeLogin函数只是请求了不同url
|
||||
useWxCodeMiniGameLogin(_code, _userInfo) {
|
||||
const self = this;
|
||||
NetworkUtils.ajax({
|
||||
url: backendAddress.PROTOCOL + '://' + backendAddress.HOST + ':' + backendAddress.PORT + constants.ROUTE_PATH.API + constants.ROUTE_PATH.PLAYER + constants.ROUTE_PATH.VERSION + constants.ROUTE_PATH.WECHATGAME + constants.ROUTE_PATH.LOGIN,
|
||||
type: "POST",
|
||||
data: {
|
||||
code: _code,
|
||||
avatarUrl: _userInfo.avatarUrl,
|
||||
nickName: _userInfo.nickName,
|
||||
},
|
||||
success: function(res) {
|
||||
self.onWechatLoggedIn(res);
|
||||
},
|
||||
error: function(xhr, status, errMsg) {
|
||||
console.log("Login attempt `onLoginButtonClicked` failed, about to execute `clearBoundRoomIdInBothVolatileAndPersistentStorage`.");
|
||||
cc.sys.localStorage.removeItem("selfPlayer");
|
||||
window.clearBoundRoomIdInBothVolatileAndPersistentStorage();
|
||||
self.showTips(i18n.t("login.tips.WECHAT_LOGIN_FAILED_TAP_SCREEN_TO_RETRY") + ", errorMsg =" + errMsg);
|
||||
self.createAuthorizeThenLoginButton();
|
||||
},
|
||||
timeout: function() {
|
||||
console.log("Login attempt `onLoginButtonClicked` failed, about to execute `clearBoundRoomIdInBothVolatileAndPersistentStorage`.");
|
||||
cc.sys.localStorage.removeItem("selfPlayer");
|
||||
window.clearBoundRoomIdInBothVolatileAndPersistentStorage();
|
||||
self.showTips(i18n.t("login.tips.WECHAT_LOGIN_FAILED_TAP_SCREEN_TO_RETRY"));
|
||||
self.createAuthorizeThenLoginButton();
|
||||
},
|
||||
});
|
||||
},
|
||||
|
||||
getWechatCode(evt) {
|
||||
let self = this;
|
||||
self.showTips("");
|
||||
const wechatServerEndpoint = wechatAddress.PROTOCOL + "://" + wechatAddress.HOST + ((null != wechatAddress.PORT && "" != wechatAddress.PORT.trim()) ? (":" + wechatAddress.PORT) : "");
|
||||
const url = wechatServerEndpoint + constants.WECHAT.AUTHORIZE_PATH + "?" + wechatAddress.APPID_LITERAL + "&" + constants.WECHAT.REDIRECT_RUI_KEY + NetworkUtils.encode(window.location.href) + "&" + constants.WECHAT.RESPONSE_TYPE + "&" + constants.WECHAT.SCOPE + constants.WECHAT.FIN;
|
||||
console.log("To visit wechat auth addr: ", url);
|
||||
window.location.href = url;
|
||||
},
|
||||
|
||||
initWxSdk() {
|
||||
const selfPlayer = JSON.parse(cc.sys.localStorage.getItem('selfPlayer'));
|
||||
const origUrl = window.location.protocol + "//" + window.location.host + window.location.pathname;
|
||||
/*
|
||||
* The `shareLink` must
|
||||
* - have its 2nd-order-domain registered as trusted 2nd-order under the targetd `res.jsConfig.app_id`, and
|
||||
* - extracted from current window.location.href.
|
||||
*/
|
||||
const shareLink = origUrl;
|
||||
const updateAppMsgShareDataObj = {
|
||||
type: 'link', // 分享类型,music、video或link,不填默认为link
|
||||
dataUrl: '', // 如果type是music或video,则要提供数据链接,默认为空
|
||||
title: document.title, // 分享标题
|
||||
desc: 'Let\'s play together!', // 分享描述
|
||||
link: shareLink + (cc.sys.localStorage.getItem('boundRoomId') ? "" : ("?expectedRoomId=" + cc.sys.localStorage.getItem('boundRoomId'))),
|
||||
imgUrl: origUrl + "/favicon.ico", // 分享图标
|
||||
success: function() {
|
||||
// 设置成功
|
||||
}
|
||||
};
|
||||
const menuShareTimelineObj = {
|
||||
title: document.title, // 分享标题
|
||||
link: shareLink + (cc.sys.localStorage.getItem('boundRoomId') ? "" : ("?expectedRoomId=" + cc.sys.localStorage.getItem('boundRoomId'))),
|
||||
imgUrl: origUrl + "/favicon.ico", // 分享图标
|
||||
success: function() {}
|
||||
};
|
||||
|
||||
const wxConfigUrl = (window.isUsingWebkitWechatKernel() ? window.atFirstLocationHref : window.location.href);
|
||||
|
||||
//接入微信登录接口
|
||||
NetworkUtils.ajax({
|
||||
"url": backendAddress.PROTOCOL + '://' + backendAddress.HOST + ':' + backendAddress.PORT + constants.ROUTE_PATH.API + constants.ROUTE_PATH.PLAYER + constants.ROUTE_PATH.VERSION + constants.ROUTE_PATH.WECHAT + constants.ROUTE_PATH.JSCONFIG,
|
||||
type: "POST",
|
||||
data: {
|
||||
"url": wxConfigUrl,
|
||||
"intAuthToken": selfPlayer.intAuthToken,
|
||||
},
|
||||
success: function(res) {
|
||||
if (constants.RET_CODE.OK != res.ret) {
|
||||
console.warn("Failed to get `wsConfig`: ", res);
|
||||
return;
|
||||
}
|
||||
const jsConfig = res.jsConfig;
|
||||
const configData = {
|
||||
debug: CC_DEBUG, // 开启调试模式,调用的所有api的返回值会在客户端alert出来,若要查看传入的参数,可以在pc端打开,参数信息会通过log打出,仅在pc端时才会打印。
|
||||
appId: jsConfig.app_id, // 必填,公众号的唯一标识
|
||||
timestamp: jsConfig.timestamp.toString(), // 必填,生成签名的时间戳
|
||||
nonceStr: jsConfig.nonce_str, // 必填,生成签名的随机串
|
||||
jsApiList: ['onMenuShareAppMessage', 'onMenuShareTimeline'],
|
||||
signature: jsConfig.signature, // 必填,签名
|
||||
};
|
||||
console.log("config url: ", wxConfigUrl);
|
||||
console.log("wx.config: ", configData);
|
||||
wx.config(configData);
|
||||
console.log("Current window.location.href: ", window.location.href);
|
||||
wx.ready(function() {
|
||||
console.log("Here is wx.ready.")
|
||||
wx.onMenuShareAppMessage(updateAppMsgShareDataObj);
|
||||
wx.onMenuShareTimeline(menuShareTimelineObj);
|
||||
});
|
||||
wx.error(function(res) {
|
||||
console.error("wx config fails and error is ", JSON.stringify(res));
|
||||
});
|
||||
},
|
||||
error: function(xhr, status, errMsg) {
|
||||
console.error("Failed to get `wsConfig`: ", errMsg);
|
||||
},
|
||||
});
|
||||
},
|
||||
|
||||
update(dt) {
|
||||
const self = this;
|
||||
if (null != wxDownloader && 0 < wxDownloader.totalBytesExpectedToWriteForAllTasks) {
|
||||
self.writtenBytes.string = wxDownloader.totalBytesWrittenForAllTasks;
|
||||
self.expectedToWriteBytes.string = wxDownloader.totalBytesExpectedToWriteForAllTasks;
|
||||
self.downloadProgress.progress = 1.0*wxDownloader.totalBytesWrittenForAllTasks/wxDownloader.totalBytesExpectedToWriteForAllTasks;
|
||||
}
|
||||
const totalUrlsToHandle = (wxDownloader.immediateHandleItemCount + wxDownloader.immediateReadFromLocalCount + wxDownloader.immediatePackDownloaderCount);
|
||||
const totalUrlsHandled = (wxDownloader.immediateHandleItemCompleteCount + wxDownloader.immediateReadFromLocalCompleteCount + wxDownloader.immediatePackDownloaderCompleteCount);
|
||||
if (null != wxDownloader && 0 < totalUrlsToHandle) {
|
||||
self.handledUrlsCount.string = totalUrlsHandled;
|
||||
self.toHandledUrlsCount.string = totalUrlsToHandle;
|
||||
self.handlerProgress.progress = 1.0*totalUrlsHandled/totalUrlsToHandle;
|
||||
}
|
||||
}
|
||||
});
|
||||
9
frontend/assets/scripts/WechatGameLogin.js.meta
Normal file
9
frontend/assets/scripts/WechatGameLogin.js.meta
Normal file
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"ver": "1.0.5",
|
||||
"uuid": "8264fb72-e348-45e4-9ab3-5bffb9a561ee",
|
||||
"isPlugin": false,
|
||||
"loadPluginInWeb": true,
|
||||
"loadPluginInNative": true,
|
||||
"loadPluginInEditor": false,
|
||||
"subMetas": {}
|
||||
}
|
||||
263
frontend/assets/scripts/WsSessionMgr.js
Normal file
263
frontend/assets/scripts/WsSessionMgr.js
Normal file
@@ -0,0 +1,263 @@
|
||||
window.UPSYNC_MSG_ACT_HB_PING = 1;
|
||||
window.UPSYNC_MSG_ACT_PLAYER_CMD = 2;
|
||||
window.UPSYNC_MSG_ACT_PLAYER_COLLIDER_ACK = 3;
|
||||
|
||||
window.DOWNSYNC_MSG_ACT_HB_REQ = 1;
|
||||
window.DOWNSYNC_MSG_ACT_INPUT_BATCH = 2;
|
||||
window.DOWNSYNC_MSG_ACT_ROOM_FRAME = 3;
|
||||
|
||||
window.sendSafely = function(msgStr) {
|
||||
/**
|
||||
* - "If the data can't be sent (for example, because it needs to be buffered but the buffer is full), the socket is closed automatically."
|
||||
*
|
||||
* from https://developer.mozilla.org/en-US/docs/Web/API/WebSocket/send.
|
||||
*/
|
||||
if (null == window.clientSession || window.clientSession.readyState != WebSocket.OPEN) return false;
|
||||
window.clientSession.send(msgStr);
|
||||
}
|
||||
|
||||
window.sendUint8AsBase64Safely = function(msgUint8Arr) {
|
||||
if (null == window.clientSession || window.clientSession.readyState != WebSocket.OPEN) return false;
|
||||
window.clientSession.send(_uint8ToBase64(msgUint8Arr));
|
||||
}
|
||||
|
||||
window.closeWSConnection = function() {
|
||||
if (null == window.clientSession || window.clientSession.readyState != WebSocket.OPEN) return;
|
||||
console.log(`Closing "window.clientSession" from the client-side.`);
|
||||
window.clientSession.close();
|
||||
}
|
||||
|
||||
window.getBoundRoomIdFromPersistentStorage = function() {
|
||||
const boundRoomIdExpiresAt = parseInt(cc.sys.localStorage.getItem("boundRoomIdExpiresAt"));
|
||||
if (!boundRoomIdExpiresAt || Date.now() >= boundRoomIdExpiresAt) {
|
||||
window.clearBoundRoomIdInBothVolatileAndPersistentStorage();
|
||||
return null;
|
||||
}
|
||||
return cc.sys.localStorage.getItem("boundRoomId");
|
||||
};
|
||||
|
||||
window.clearBoundRoomIdInBothVolatileAndPersistentStorage = function() {
|
||||
window.boundRoomId = null;
|
||||
cc.sys.localStorage.removeItem("boundRoomId");
|
||||
cc.sys.localStorage.removeItem("boundRoomIdExpiresAt");
|
||||
};
|
||||
|
||||
window.clearSelfPlayer = function() {
|
||||
cc.sys.localStorage.removeItem("selfPlayer");
|
||||
};
|
||||
|
||||
window.boundRoomId = getBoundRoomIdFromPersistentStorage();
|
||||
window.handleHbRequirements = function(resp) {
|
||||
if (constants.RET_CODE.OK != resp.ret) return;
|
||||
if (null == window.boundRoomId) {
|
||||
window.boundRoomId = resp.bciFrame.boundRoomId;
|
||||
cc.sys.localStorage.setItem('boundRoomId', window.boundRoomId);
|
||||
cc.sys.localStorage.setItem('boundRoomIdExpiresAt', Date.now() + 10 * 60 * 1000); // Temporarily hardcoded, for `boundRoomId` only.
|
||||
}
|
||||
|
||||
if (window.handleBattleColliderInfo) {
|
||||
window.handleBattleColliderInfo(resp.bciFrame);
|
||||
}
|
||||
};
|
||||
|
||||
function _uint8ToBase64(uint8Arr) {
|
||||
return window.btoa(uint8Arr);
|
||||
}
|
||||
|
||||
function _base64ToUint8Array(base64) {
|
||||
var origBytes = null;
|
||||
if (null != window.atob) {
|
||||
var origBinaryStr = window.atob(base64);
|
||||
var origLen = origBinaryStr.length;
|
||||
origBytes = new Uint8Array(origLen);
|
||||
for (var i = 0; i < origLen; i++) {
|
||||
origBytes[i] = origBinaryStr.charCodeAt(i);
|
||||
}
|
||||
return origBytes;
|
||||
} else if (cc.sys.platform == cc.sys.WECHAT_GAME) {
|
||||
return Buffer.from(base64, 'base64');
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
function _base64ToArrayBuffer(base64) {
|
||||
return _base64ToUint8Array(base64).buffer;
|
||||
}
|
||||
|
||||
window.getExpectedRoomIdSync = function() {
|
||||
if (cc.sys.platform == cc.sys.WECHAT_GAME) {
|
||||
return window.expectedRoomId;
|
||||
} else {
|
||||
const qDict = window.getQueryParamDict();
|
||||
if (qDict) {
|
||||
return qDict["expectedRoomId"];
|
||||
} else {
|
||||
if (window.history && window.history.state) {
|
||||
return window.history.state.expectedRoomId;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
};
|
||||
|
||||
window.unsetClientSessionCloseOrErrorFlag = function() {
|
||||
cc.sys.localStorage.removeItem("ClientSessionCloseOrErrorFlag");
|
||||
return;
|
||||
}
|
||||
|
||||
window.setClientSessionCloseOrErrorFlag = function() {
|
||||
const oldVal = cc.sys.localStorage.getItem("ClientSessionCloseOrErrorFlag");
|
||||
if (true == oldVal) return false;
|
||||
cc.sys.localStorage.setItem("ClientSessionCloseOrErrorFlag", true);
|
||||
return true;
|
||||
}
|
||||
|
||||
window.initPersistentSessionClient = function(onopenCb, expectedRoomId) {
|
||||
if (window.clientSession && window.clientSession.readyState == WebSocket.OPEN) {
|
||||
if (null != onopenCb) {
|
||||
onopenCb();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
const intAuthToken = cc.sys.localStorage.getItem("selfPlayer") ? JSON.parse(cc.sys.localStorage.getItem('selfPlayer')).intAuthToken : "";
|
||||
|
||||
let urlToConnect = backendAddress.PROTOCOL.replace('http', 'ws') + '://' + backendAddress.HOST + ":" + backendAddress.PORT + backendAddress.WS_PATH_PREFIX + "?intAuthToken=" + intAuthToken;
|
||||
|
||||
if (null != expectedRoomId) {
|
||||
console.log("initPersistentSessionClient with expectedRoomId == " + expectedRoomId);
|
||||
urlToConnect = urlToConnect + "&expectedRoomId=" + expectedRoomId;
|
||||
if (cc.sys.platform == cc.sys.WECHAT_GAME) {
|
||||
// This is a dirty hack. -- YFLu
|
||||
window.expectedRoomId = null;
|
||||
}
|
||||
} else {
|
||||
window.boundRoomId = getBoundRoomIdFromPersistentStorage();
|
||||
if (null != window.boundRoomId) {
|
||||
console.log("initPersistentSessionClient with boundRoomId == " + boundRoomId);
|
||||
urlToConnect = urlToConnect + "&boundRoomId=" + window.boundRoomId;
|
||||
}
|
||||
}
|
||||
|
||||
const currentHistoryState = window.history && window.history.state ? window.history.state : {};
|
||||
|
||||
if (cc.sys.platform != cc.sys.WECHAT_GAME) {
|
||||
window.history.replaceState(currentHistoryState, document.title, window.location.pathname);
|
||||
}
|
||||
|
||||
const clientSession = new WebSocket(urlToConnect);
|
||||
clientSession.binaryType = 'arraybuffer'; // Make 'event.data' of 'onmessage' an "ArrayBuffer" instead of a "Blob"
|
||||
|
||||
clientSession.onopen = function(event) {
|
||||
console.log("The WS clientSession is opened.");
|
||||
window.clientSession = clientSession;
|
||||
if (null == onopenCb) return;
|
||||
onopenCb();
|
||||
};
|
||||
|
||||
clientSession.onmessage = function(event) {
|
||||
if (null == event || null == event.data) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
const resp = window.WsResp.decode(new Uint8Array(event.data));
|
||||
switch (resp.act) {
|
||||
case window.DOWNSYNC_MSG_ACT_HB_REQ:
|
||||
window.handleHbRequirements(resp); // 获取boundRoomId并存储到localStorage
|
||||
break;
|
||||
case window.DOWNSYNC_MSG_ACT_ROOM_FRAME:
|
||||
if (window.handleRoomDownsyncFrame) {
|
||||
window.handleRoomDownsyncFrame(resp.rdf);
|
||||
}
|
||||
break;
|
||||
case window.DOWNSYNC_MSG_ACT_INPUT_BATCH:
|
||||
if (window.handleInputFrameDownsyncBatch) {
|
||||
window.handleInputFrameDownsyncBatch(resp.inputFrameDownsyncBatch);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
} catch (e) {
|
||||
console.error("Unexpected error when parsing data of:", event.data, e);
|
||||
}
|
||||
};
|
||||
|
||||
clientSession.onerror = function(event) {
|
||||
if (!window.setClientSessionCloseOrErrorFlag()) {
|
||||
return;
|
||||
}
|
||||
console.error("Error caught on the WS clientSession: ", event);
|
||||
if (window.clientSessionPingInterval) {
|
||||
clearInterval(window.clientSessionPingInterval);
|
||||
}
|
||||
if (window.handleClientSessionCloseOrError) {
|
||||
window.handleClientSessionCloseOrError();
|
||||
}
|
||||
window.unsetClientSessionCloseOrErrorFlag();
|
||||
};
|
||||
|
||||
clientSession.onclose = function(event) {
|
||||
if (!window.setClientSessionCloseOrErrorFlag()) {
|
||||
return;
|
||||
}
|
||||
console.warn("The WS clientSession is closed: ", event);
|
||||
if (window.clientSessionPingInterval) {
|
||||
clearInterval(window.clientSessionPingInterval);
|
||||
}
|
||||
if (false == event.wasClean) {
|
||||
// Chrome doesn't allow the use of "CustomCloseCode"s (yet) and will callback with a "WebsocketStdCloseCode 1006" and "false == event.wasClean" here. See https://tools.ietf.org/html/rfc6455#section-7.4 for more information.
|
||||
if (window.handleClientSessionCloseOrError) {
|
||||
window.handleClientSessionCloseOrError();
|
||||
}
|
||||
} else {
|
||||
switch (event.code) {
|
||||
case constants.RET_CODE.PLAYER_NOT_FOUND:
|
||||
case constants.RET_CODE.PLAYER_CHEATING:
|
||||
window.clearBoundRoomIdInBothVolatileAndPersistentStorage();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (window.handleClientSessionCloseOrError) {
|
||||
window.handleClientSessionCloseOrError();
|
||||
}
|
||||
}
|
||||
window.unsetClientSessionCloseOrErrorFlag();
|
||||
};
|
||||
};
|
||||
|
||||
window.clearLocalStorageAndBackToLoginScene = function(shouldRetainBoundRoomIdInBothVolatileAndPersistentStorage) {
|
||||
console.warn("+++++++ Calling `clearLocalStorageAndBackToLoginScene`");
|
||||
|
||||
if (window.mapIns && window.mapIns.musicEffectManagerScriptIns) {
|
||||
window.mapIns.musicEffectManagerScriptIns.stopAllMusic();
|
||||
}
|
||||
/**
|
||||
* Here I deliberately removed the callback in the "common `handleClientSessionCloseOrError` callback"
|
||||
* within which another invocation to `clearLocalStorageAndBackToLoginScene` will be made.
|
||||
*
|
||||
* It'll be re-assigned to the common one upon reentrance of `Map.onLoad`.
|
||||
*
|
||||
* -- YFLu 2019-04-06
|
||||
*/
|
||||
window.handleClientSessionCloseOrError = () => {
|
||||
console.warn("+++++++ Special handleClientSessionCloseOrError() assigned within `clearLocalStorageAndBackToLoginScene`");
|
||||
// TBD.
|
||||
window.handleClientSessionCloseOrError = null; // To ensure that it's called at most once.
|
||||
};
|
||||
window.closeWSConnection();
|
||||
window.clearSelfPlayer();
|
||||
if (true != shouldRetainBoundRoomIdInBothVolatileAndPersistentStorage) {
|
||||
window.clearBoundRoomIdInBothVolatileAndPersistentStorage();
|
||||
}
|
||||
if (cc.sys.platform == cc.sys.WECHAT_GAME) {
|
||||
cc.director.loadScene('wechatGameLogin');
|
||||
} else {
|
||||
cc.director.loadScene('login');
|
||||
}
|
||||
};
|
||||
|
||||
9
frontend/assets/scripts/WsSessionMgr.js.meta
Normal file
9
frontend/assets/scripts/WsSessionMgr.js.meta
Normal file
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"ver": "1.0.5",
|
||||
"uuid": "07a29622-1fef-4e3a-b892-7e203315ca91",
|
||||
"isPlugin": false,
|
||||
"loadPluginInWeb": true,
|
||||
"loadPluginInNative": true,
|
||||
"loadPluginInEditor": false,
|
||||
"subMetas": {}
|
||||
}
|
||||
7
frontend/assets/scripts/modules.meta
Normal file
7
frontend/assets/scripts/modules.meta
Normal file
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"ver": "1.0.1",
|
||||
"uuid": "40cf5957-2ccf-450f-b78e-6d65eb2fe420",
|
||||
"isSubpackage": false,
|
||||
"subpackageName": "",
|
||||
"subMetas": {}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"ver": "1.0.5",
|
||||
"uuid": "f9cd97f6-3533-4a27-afc8-cf302da003b2",
|
||||
"isPlugin": false,
|
||||
"loadPluginInWeb": true,
|
||||
"loadPluginInNative": true,
|
||||
"loadPluginInEditor": false,
|
||||
"subMetas": {}
|
||||
}
|
||||
1
frontend/assets/scripts/modules/protobuf.js.map
Normal file
1
frontend/assets/scripts/modules/protobuf.js.map
Normal file
File diff suppressed because one or more lines are too long
5
frontend/assets/scripts/modules/protobuf.js.map.meta
Normal file
5
frontend/assets/scripts/modules/protobuf.js.map.meta
Normal file
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"ver": "1.0.1",
|
||||
"uuid": "e646fbd9-7821-4567-9846-fb6e45aeb921",
|
||||
"subMetas": {}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"ver": "1.0.5",
|
||||
"uuid": "77ed160f-d4d5-4654-a502-66b008197da0",
|
||||
"isPlugin": false,
|
||||
"loadPluginInWeb": true,
|
||||
"loadPluginInNative": true,
|
||||
"loadPluginInEditor": false,
|
||||
"subMetas": {}
|
||||
}
|
||||
Reference in New Issue
Block a user