update
This commit is contained in:
@@ -1,151 +1,160 @@
|
||||
import { Node, Prefab, SpriteFrame, clamp } from 'cc'
|
||||
import Singleton from '../Base/Singleton'
|
||||
import { EntityTypeEnum, IBullet, IClientInput, InputTypeEnum, IRoom, IState, toFixed } from '../Common'
|
||||
import { ActorManager } from '../Entity/Actor/ActorManager'
|
||||
import { BulletManager } from '../Entity/Bullet/BulletManager'
|
||||
import { EventEnum } from '../Enum'
|
||||
import { JoyStickManager } from '../UI/JoyStickManager'
|
||||
import EventManager from './EventManager'
|
||||
import { Node, Prefab, SpriteFrame, clamp } from "cc";
|
||||
import Singleton from "../Base/Singleton";
|
||||
import { EntityTypeEnum, IBullet, IClientInput, InputTypeEnum, IRoom, IState, toFixed } from "../Common";
|
||||
import { ActorManager } from "../Entity/Actor/ActorManager";
|
||||
import { BulletManager } from "../Entity/Bullet/BulletManager";
|
||||
import { EventEnum } from "../Enum";
|
||||
import { JoyStickManager } from "../UI/JoyStickManager";
|
||||
import EventManager from "./EventManager";
|
||||
|
||||
const PLAYER_SPEED = 100;
|
||||
const BULLET_SPEED = 600;
|
||||
|
||||
const PLAYER_SPEED = 100
|
||||
const BULLET_SPEED = 600
|
||||
const WEAPON_DAMAGE = 5;
|
||||
|
||||
const WEAPON_DAMAGE = 5
|
||||
const PLAYER_RADIUS = 50;
|
||||
const BULLET_RADIUS = 10;
|
||||
|
||||
const PLAYER_RADIUS = 50
|
||||
const BULLET_RADIUS = 10
|
||||
|
||||
const mapW = 960
|
||||
const mapH = 640
|
||||
const mapW = 960;
|
||||
const mapH = 640;
|
||||
|
||||
export default class DataManager extends Singleton {
|
||||
static get Instance() {
|
||||
return super.GetInstance<DataManager>()
|
||||
return super.GetInstance<DataManager>();
|
||||
}
|
||||
|
||||
//登陆数据
|
||||
myPlayerId = 1
|
||||
myPlayerId = 1;
|
||||
|
||||
//大厅数据
|
||||
roomInfo: IRoom
|
||||
roomInfo: IRoom;
|
||||
|
||||
//游戏数据
|
||||
stage: Node
|
||||
jm: JoyStickManager
|
||||
prefabMap: Map<string, Prefab> = new Map()
|
||||
textureMap: Map<string, SpriteFrame[]> = new Map()
|
||||
actorMap: Map<number, ActorManager> = new Map()
|
||||
bulletMap: Map<number, BulletManager> = new Map()
|
||||
stage: Node;
|
||||
jm: JoyStickManager;
|
||||
prefabMap: Map<string, Prefab> = new Map();
|
||||
textureMap: Map<string, SpriteFrame[]> = new Map();
|
||||
actorMap: Map<number, ActorManager> = new Map();
|
||||
bulletMap: Map<number, BulletManager> = new Map();
|
||||
|
||||
reset() {
|
||||
this.stage = null
|
||||
this.jm = null
|
||||
this.actorMap.clear()
|
||||
this.bulletMap.clear()
|
||||
this.prefabMap.clear()
|
||||
this.textureMap.clear()
|
||||
this.frameId = 0;
|
||||
this.stage = null;
|
||||
this.jm = null;
|
||||
this.actorMap.clear();
|
||||
this.bulletMap.clear();
|
||||
this.prefabMap.clear();
|
||||
this.textureMap.clear();
|
||||
}
|
||||
|
||||
frameId = 0;
|
||||
lastState: IState;
|
||||
state: IState = {
|
||||
players: [{
|
||||
id: 2,
|
||||
nickname: "哈哈1",
|
||||
position: {
|
||||
x: -200,
|
||||
y: -200
|
||||
actors: [
|
||||
{
|
||||
id: 2,
|
||||
nickname: "哈哈1",
|
||||
position: {
|
||||
x: -200,
|
||||
y: -200,
|
||||
},
|
||||
direction: {
|
||||
x: 1,
|
||||
y: 0,
|
||||
},
|
||||
hp: 100,
|
||||
type: EntityTypeEnum.Actor1,
|
||||
weaponType: EntityTypeEnum.Weapon1,
|
||||
bulletType: EntityTypeEnum.Bullet1,
|
||||
},
|
||||
direction: {
|
||||
x: 1,
|
||||
y: 0
|
||||
{
|
||||
id: 1,
|
||||
nickname: "哈哈2",
|
||||
position: {
|
||||
x: 200,
|
||||
y: 200,
|
||||
},
|
||||
direction: {
|
||||
x: 0,
|
||||
y: -1,
|
||||
},
|
||||
hp: 100,
|
||||
type: EntityTypeEnum.Actor2,
|
||||
weaponType: EntityTypeEnum.Weapon2,
|
||||
bulletType: EntityTypeEnum.Bullet2,
|
||||
},
|
||||
hp: 100,
|
||||
type: EntityTypeEnum.Actor1,
|
||||
weaponType: EntityTypeEnum.Weapon1,
|
||||
bulletType: EntityTypeEnum.Bullet1,
|
||||
}, {
|
||||
id: 1,
|
||||
nickname: "哈哈2",
|
||||
position: {
|
||||
x: 200,
|
||||
y: 200
|
||||
},
|
||||
direction: {
|
||||
x: 0,
|
||||
y: -1
|
||||
},
|
||||
hp: 100,
|
||||
type: EntityTypeEnum.Actor2,
|
||||
weaponType: EntityTypeEnum.Weapon2,
|
||||
bulletType: EntityTypeEnum.Bullet2,
|
||||
}],
|
||||
],
|
||||
bullets: [],
|
||||
nextBulletId: 1
|
||||
}
|
||||
nextBulletId: 1,
|
||||
};
|
||||
|
||||
applyInput(input: IClientInput) {
|
||||
switch (input.type) {
|
||||
case InputTypeEnum.ActorMove: {
|
||||
const { direction: { x, y }, dt, id } = input
|
||||
const player = this.state.players.find(e => e.id === id)
|
||||
const {
|
||||
direction: { x, y },
|
||||
dt,
|
||||
id,
|
||||
} = input;
|
||||
const player = this.state.actors.find((e) => e.id === id);
|
||||
if (!player) {
|
||||
return
|
||||
return;
|
||||
}
|
||||
|
||||
player.position.x += toFixed(x * PLAYER_SPEED * dt)
|
||||
player.position.y += toFixed(y * PLAYER_SPEED * dt)
|
||||
player.position.x += toFixed(x * PLAYER_SPEED * dt);
|
||||
player.position.y += toFixed(y * PLAYER_SPEED * dt);
|
||||
|
||||
player.position.x = clamp(player.position.x, -mapW / 2, mapW / 2)
|
||||
player.position.y = clamp(player.position.y, -mapH / 2, mapH / 2)
|
||||
player.position.x = clamp(player.position.x, -mapW / 2, mapW / 2);
|
||||
player.position.y = clamp(player.position.y, -mapH / 2, mapH / 2);
|
||||
|
||||
player.direction = { x, y }
|
||||
break
|
||||
player.direction = { x, y };
|
||||
break;
|
||||
}
|
||||
case InputTypeEnum.WeaponShoot: {
|
||||
const { owner, position, direction } = input
|
||||
const { owner, position, direction } = input;
|
||||
const bullet: IBullet = {
|
||||
id: this.state.nextBulletId++,
|
||||
owner,
|
||||
position,
|
||||
direction,
|
||||
type: this.actorMap.get(owner).bulletType
|
||||
}
|
||||
this.state.bullets.push(bullet)
|
||||
type: this.actorMap.get(owner).bulletType,
|
||||
};
|
||||
this.state.bullets.push(bullet);
|
||||
|
||||
EventManager.Instance.emit(EventEnum.BulletBorn, owner)
|
||||
break
|
||||
EventManager.Instance.emit(EventEnum.BulletBorn, owner);
|
||||
break;
|
||||
}
|
||||
case InputTypeEnum.TimePast: {
|
||||
const { dt } = input
|
||||
const { bullets, players } = this.state
|
||||
const { dt } = input;
|
||||
const { bullets, actors } = this.state;
|
||||
|
||||
for (let i = bullets.length - 1; i >= 0; i--) {
|
||||
const bullet = bullets[i];
|
||||
for (let j = players.length - 1; j >= 0; j--) {
|
||||
const player = players[j];
|
||||
if (((player.position.x - bullet.position.x) ** 2 + (player.position.y - bullet.position.y) ** 2) < (PLAYER_RADIUS + BULLET_RADIUS) ** 2) {
|
||||
for (let j = actors.length - 1; j >= 0; j--) {
|
||||
const player = actors[j];
|
||||
if ((player.position.x - bullet.position.x) ** 2 + (player.position.y - bullet.position.y) ** 2 < (PLAYER_RADIUS + BULLET_RADIUS) ** 2) {
|
||||
EventManager.Instance.emit(EventEnum.ExplosionBorn, bullet.id, {
|
||||
x: toFixed((player.position.x + bullet.position.x) / 2),
|
||||
y: toFixed((player.position.y + bullet.position.y) / 2),
|
||||
})
|
||||
});
|
||||
|
||||
player.hp -= WEAPON_DAMAGE
|
||||
bullets.splice(i, 1)
|
||||
break
|
||||
player.hp -= WEAPON_DAMAGE;
|
||||
bullets.splice(i, 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (Math.abs(bullet.position.x) > mapW / 2 || Math.abs(bullet.position.y) > mapH / 2) {
|
||||
EventManager.Instance.emit(EventEnum.ExplosionBorn, bullet.id, {
|
||||
x: bullet.position.x,
|
||||
y: bullet.position.y,
|
||||
})
|
||||
bullets.splice(i, 1)
|
||||
});
|
||||
bullets.splice(i, 1);
|
||||
}
|
||||
}
|
||||
|
||||
for (const bullet of this.state.bullets) {
|
||||
bullet.position.x += toFixed(bullet.direction.x * BULLET_SPEED * dt)
|
||||
bullet.position.y += toFixed(bullet.direction.y * BULLET_SPEED * dt)
|
||||
bullet.position.x += toFixed(bullet.direction.x * BULLET_SPEED * dt);
|
||||
bullet.position.y += toFixed(bullet.direction.y * BULLET_SPEED * dt);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -1,5 +1,5 @@
|
||||
import Singleton from '../Base/Singleton'
|
||||
import { EventEnum } from '../Enum';
|
||||
import Singleton from "../Base/Singleton";
|
||||
import { EventEnum } from "../Enum";
|
||||
|
||||
interface IItem {
|
||||
cb: Function;
|
||||
@@ -23,7 +23,7 @@ export default class EventManager extends Singleton {
|
||||
|
||||
off(event: EventEnum, cb: Function, ctx: unknown) {
|
||||
if (this.map.has(event)) {
|
||||
const index = this.map.get(event).findIndex(i => cb === i.cb && i.ctx === ctx);
|
||||
const index = this.map.get(event).findIndex((i) => cb === i.cb && i.ctx === ctx);
|
||||
index > -1 && this.map.get(event).splice(index, 1);
|
||||
}
|
||||
}
|
||||
@@ -31,7 +31,7 @@ export default class EventManager extends Singleton {
|
||||
emit(event: EventEnum, ...params: unknown[]) {
|
||||
if (this.map.has(event)) {
|
||||
this.map.get(event).forEach(({ cb, ctx }) => {
|
||||
cb.apply(ctx, params)
|
||||
cb.apply(ctx, params);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@@ -1,8 +1,8 @@
|
||||
import Singleton from '../Base/Singleton'
|
||||
import { ApiMsgEnum, IModel } from '../Common';
|
||||
import { binaryEncode, binaryDecode } from '../Common/Binary';
|
||||
import Singleton from "../Base/Singleton";
|
||||
import { ApiMsgEnum, IModel } from "../Common";
|
||||
import { binaryEncode, binaryDecode } from "../Common/Binary";
|
||||
|
||||
const TIMEOUT = 5000
|
||||
const TIMEOUT = 5000;
|
||||
|
||||
interface IItem {
|
||||
cb: Function;
|
||||
@@ -12,109 +12,107 @@ interface IItem {
|
||||
export interface ICallApiRet<T> {
|
||||
success: boolean;
|
||||
error?: Error;
|
||||
res?: T
|
||||
res?: T;
|
||||
}
|
||||
|
||||
type aaa = keyof IModel
|
||||
export default class NetworkManager extends Singleton {
|
||||
static get Instance() {
|
||||
return super.GetInstance<NetworkManager>()
|
||||
return super.GetInstance<NetworkManager>();
|
||||
}
|
||||
|
||||
ws: WebSocket
|
||||
port = 8888
|
||||
maps: Map<ApiMsgEnum, Array<IItem>> = new Map()
|
||||
isConnected = false
|
||||
ws: WebSocket;
|
||||
port = 8888;
|
||||
maps: Map<ApiMsgEnum, Array<IItem>> = new Map();
|
||||
isConnected = false;
|
||||
|
||||
connect() {
|
||||
return new Promise((resolve, reject) => {
|
||||
if (this.isConnected) {
|
||||
resolve(true)
|
||||
return
|
||||
resolve(true);
|
||||
return;
|
||||
}
|
||||
this.ws = new WebSocket(`ws://localhost:${this.port}`)
|
||||
this.ws = new WebSocket(`ws://localhost:${this.port}`);
|
||||
//onmessage接受的数据类型,只有在后端返回字节数组的时候才有效果
|
||||
this.ws.binaryType = 'arraybuffer';
|
||||
this.ws.binaryType = "arraybuffer";
|
||||
|
||||
this.ws.onopen = () => {
|
||||
this.isConnected = true
|
||||
resolve(true)
|
||||
}
|
||||
this.isConnected = true;
|
||||
resolve(true);
|
||||
};
|
||||
|
||||
this.ws.onerror = (e) => {
|
||||
this.isConnected = false
|
||||
console.log(e)
|
||||
reject("ws onerror")
|
||||
}
|
||||
this.isConnected = false;
|
||||
console.log(e);
|
||||
reject("ws onerror");
|
||||
};
|
||||
|
||||
this.ws.onclose = () => {
|
||||
this.isConnected = false
|
||||
reject("ws onclose")
|
||||
}
|
||||
this.isConnected = false;
|
||||
reject("ws onclose");
|
||||
};
|
||||
|
||||
this.ws.onmessage = (e) => {
|
||||
try {
|
||||
const json = binaryDecode(e.data)
|
||||
const { name, data } = json
|
||||
const json = binaryDecode(e.data);
|
||||
const { name, data } = json;
|
||||
try {
|
||||
if (this.maps.has(name) && this.maps.get(name).length) {
|
||||
console.log(json);
|
||||
this.maps.get(name).forEach(({ cb, ctx }) => cb.call(ctx, data))
|
||||
this.maps.get(name).forEach(({ cb, ctx }) => cb.call(ctx, data));
|
||||
}
|
||||
} catch (error) {
|
||||
console.log("onmessage:", error)
|
||||
console.log("onmessage:", error);
|
||||
}
|
||||
} catch (error) {
|
||||
console.log('解析失败,不是合法的JSON格式', error)
|
||||
console.log("解析失败,不是合法的JSON格式", error);
|
||||
}
|
||||
}
|
||||
})
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
callApi<T extends keyof IModel['api']>(name: T, data: IModel['api'][T]['req']): Promise<ICallApiRet<IModel['api'][T]['res']>> {
|
||||
callApi<T extends keyof IModel["api"]>(name: T, data: IModel["api"][T]["req"]): Promise<ICallApiRet<IModel["api"][T]["res"]>> {
|
||||
return new Promise((resolve) => {
|
||||
try {
|
||||
// 超时处理
|
||||
const timer = setTimeout(() => {
|
||||
resolve({ success: false, error: new Error('timeout') })
|
||||
this.unlistenMsg(name as any, cb, null)
|
||||
}, TIMEOUT)
|
||||
resolve({ success: false, error: new Error("timeout") });
|
||||
this.unlistenMsg(name as any, cb, null);
|
||||
}, TIMEOUT);
|
||||
|
||||
// 回调处理
|
||||
const cb = (res) => {
|
||||
resolve(res)
|
||||
clearTimeout(timer)
|
||||
this.unlistenMsg(name as any, cb, null)
|
||||
}
|
||||
this.listenMsg(name as any, cb, null)
|
||||
resolve(res);
|
||||
clearTimeout(timer);
|
||||
this.unlistenMsg(name as any, cb, null);
|
||||
};
|
||||
this.listenMsg(name as any, cb, null);
|
||||
|
||||
this.sendMsg(name as any, data)
|
||||
this.sendMsg(name as any, data);
|
||||
} catch (error) {
|
||||
resolve({ success: false, error: error as Error })
|
||||
resolve({ success: false, error: error as Error });
|
||||
}
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
async sendMsg<T extends keyof IModel['msg']>(name: T, data: IModel['msg'][T]) {
|
||||
const view = binaryEncode(name, data)
|
||||
let delay = parseInt(new URLSearchParams(location.search).get('delay') || '0') || 0;
|
||||
await new Promise((r) => setTimeout(r, delay))
|
||||
this.ws.send(view.buffer)
|
||||
async sendMsg<T extends keyof IModel["msg"]>(name: T, data: IModel["msg"][T]) {
|
||||
const view = binaryEncode(name, data);
|
||||
let delay = parseInt(new URLSearchParams(location.search).get("delay") || "0") || 0;
|
||||
await new Promise((r) => setTimeout(r, delay));
|
||||
this.ws.send(view.buffer);
|
||||
}
|
||||
|
||||
listenMsg<T extends keyof IModel['msg']>(name: T, cb: (args: IModel['msg'][T]) => void, ctx: unknown) {
|
||||
listenMsg<T extends keyof IModel["msg"]>(name: T, cb: (args: IModel["msg"][T]) => void, ctx: unknown) {
|
||||
if (this.maps.has(name)) {
|
||||
this.maps.get(name).push({ ctx, cb })
|
||||
this.maps.get(name).push({ ctx, cb });
|
||||
} else {
|
||||
this.maps.set(name, [{ ctx, cb }])
|
||||
this.maps.set(name, [{ ctx, cb }]);
|
||||
}
|
||||
}
|
||||
|
||||
unlistenMsg<T extends keyof IModel['msg']>(name: T, cb: (args: IModel['msg'][T]) => void, ctx: unknown) {
|
||||
unlistenMsg<T extends keyof IModel["msg"]>(name: T, cb: (args: IModel["msg"][T]) => void, ctx: unknown) {
|
||||
if (this.maps.has(name)) {
|
||||
const items = this.maps.get(name)
|
||||
const index = items.findIndex(i => cb === i.cb && i.ctx === ctx);
|
||||
index > -1 && items.splice(index, 1)
|
||||
const items = this.maps.get(name);
|
||||
const index = items.findIndex((i) => cb === i.cb && i.ctx === ctx);
|
||||
index > -1 && items.splice(index, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -1,55 +1,55 @@
|
||||
import Singleton from '../Base/Singleton'
|
||||
import { instantiate, Node } from 'cc'
|
||||
import DataManager from './DataManager'
|
||||
import { EntityTypeEnum } from '../Common'
|
||||
import Singleton from "../Base/Singleton";
|
||||
import { instantiate, Node } from "cc";
|
||||
import DataManager from "./DataManager";
|
||||
import { EntityTypeEnum } from "../Common";
|
||||
|
||||
export default class ObjectPoolManager extends Singleton {
|
||||
static get Instance() {
|
||||
return super.GetInstance<ObjectPoolManager>()
|
||||
return super.GetInstance<ObjectPoolManager>();
|
||||
}
|
||||
|
||||
private objectPool: Node = null
|
||||
private map: Map<EntityTypeEnum, Node[]> = new Map()
|
||||
private objectPool: Node = null;
|
||||
private map: Map<EntityTypeEnum, Node[]> = new Map();
|
||||
|
||||
private getContainerName(objectName: EntityTypeEnum) {
|
||||
return objectName + 'Pool'
|
||||
return objectName + "Pool";
|
||||
}
|
||||
|
||||
reset() {
|
||||
this.objectPool = null
|
||||
this.map.clear()
|
||||
this.objectPool = null;
|
||||
this.map.clear();
|
||||
}
|
||||
|
||||
get(objectName: EntityTypeEnum) {
|
||||
if (this.objectPool === null) {
|
||||
this.objectPool = new Node("ObjectPool")
|
||||
this.objectPool.setParent(DataManager.Instance.stage)
|
||||
this.objectPool = new Node("ObjectPool");
|
||||
this.objectPool.setParent(DataManager.Instance.stage);
|
||||
}
|
||||
|
||||
if (!this.map.has(objectName)) {
|
||||
this.map.set(objectName, [])
|
||||
const container = new Node(this.getContainerName(objectName))
|
||||
container.setParent(this.objectPool)
|
||||
this.map.set(objectName, []);
|
||||
const container = new Node(this.getContainerName(objectName));
|
||||
container.setParent(this.objectPool);
|
||||
}
|
||||
|
||||
let node: Node
|
||||
const nodes = this.map.get(objectName)
|
||||
let node: Node;
|
||||
const nodes = this.map.get(objectName);
|
||||
|
||||
if (!nodes.length) {
|
||||
const prefab = DataManager.Instance.prefabMap.get(objectName)
|
||||
node = instantiate(prefab)
|
||||
node.name = objectName
|
||||
node.setParent(this.objectPool.getChildByName(this.getContainerName(objectName)))
|
||||
const prefab = DataManager.Instance.prefabMap.get(objectName);
|
||||
node = instantiate(prefab);
|
||||
node.name = objectName;
|
||||
node.setParent(this.objectPool.getChildByName(this.getContainerName(objectName)));
|
||||
} else {
|
||||
node = nodes.pop()
|
||||
node = nodes.pop();
|
||||
}
|
||||
node.active = true
|
||||
return node
|
||||
node.active = true;
|
||||
return node;
|
||||
}
|
||||
|
||||
ret(object: Node) {
|
||||
object.active = false
|
||||
const objectName = object.name as EntityTypeEnum
|
||||
this.map.get(objectName).push(object)
|
||||
object.active = false;
|
||||
const objectName = object.name as EntityTypeEnum;
|
||||
this.map.get(objectName).push(object);
|
||||
}
|
||||
}
|
||||
|
@@ -1,32 +1,32 @@
|
||||
import { _decorator, resources, Asset } from 'cc'
|
||||
import Singleton from '../Base/Singleton'
|
||||
import { _decorator, resources, Asset } from "cc";
|
||||
import Singleton from "../Base/Singleton";
|
||||
|
||||
export class ResourceManager extends Singleton {
|
||||
static get Instance() {
|
||||
return super.GetInstance<ResourceManager>()
|
||||
return super.GetInstance<ResourceManager>();
|
||||
}
|
||||
|
||||
loadRes<T extends Asset>(path: string, type: new (...args: any[]) => T) {
|
||||
return new Promise<T>((resolve, reject) => {
|
||||
resources.load(path, type, (err, res) => {
|
||||
if (err) {
|
||||
reject(err)
|
||||
return
|
||||
reject(err);
|
||||
return;
|
||||
}
|
||||
resolve(res)
|
||||
})
|
||||
})
|
||||
resolve(res);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
loadDir<T extends Asset>(path: string, type: new (...args: any[]) => T) {
|
||||
return new Promise<T[]>((resolve, reject) => {
|
||||
resources.loadDir(path, type, (err, res) => {
|
||||
if (err) {
|
||||
reject(err)
|
||||
return
|
||||
reject(err);
|
||||
return;
|
||||
}
|
||||
resolve(res)
|
||||
})
|
||||
})
|
||||
resolve(res);
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user