可通过 URL 自定义 lag

This commit is contained in:
k8w 2021-12-03 14:19:09 +08:00
parent 5c588ea56e
commit 171c0264a2
6 changed files with 55 additions and 64 deletions

View File

@ -2,7 +2,6 @@ import 'k8w-extend-native';
import * as path from "path"; import * as path from "path";
import { WsConnection, WsServer } from "tsrpc"; import { WsConnection, WsServer } from "tsrpc";
import { Room } from './models/Room'; import { Room } from './models/Room';
import { gameConfig } from './shared/game/gameConfig';
import { serviceProto, ServiceType } from './shared/protocols/serviceProto'; import { serviceProto, ServiceType } from './shared/protocols/serviceProto';
// Create the Server // Create the Server
@ -19,19 +18,7 @@ server.flows.postDisconnectFlow.push(v => {
} }
return v; return v;
}) });
// 模拟网络延迟
if (gameConfig.networkLag) {
server.flows.preRecvDataFlow.push(async v => {
await new Promise(rs => { setTimeout(rs, gameConfig.networkLag) })
return v;
})
server.flows.preSendDataFlow.push(async v => {
await new Promise(rs => { setTimeout(rs, gameConfig.networkLag) })
return v;
})
}
export const roomInstance = new Room(server); export const roomInstance = new Room(server);

View File

@ -43,12 +43,14 @@ export class GameSystem {
else if (input.type === 'PlayerAttack') { else if (input.type === 'PlayerAttack') {
let player = this._state.players.find(v => v.id === input.playerId); let player = this._state.players.find(v => v.id === input.playerId);
if (player) { if (player) {
this._state.arrows.push({ let newArrow: ArrowState = {
id: this._state.nextArrowId++, id: this._state.nextArrowId++,
fromPlayerId: input.playerId, fromPlayerId: input.playerId,
targetPos: { ...input.targetPos }, targetPos: { ...input.targetPos },
targetTime: input.targetTime targetTime: input.targetTime
}); };
this._state.arrows.push(newArrow);
this.onNewArrow.forEach(v => v(newArrow));
} }
} }
else if (input.type === 'PlayerJoin') { else if (input.type === 'PlayerJoin') {
@ -69,11 +71,6 @@ export class GameSystem {
if (arrow.targetTime <= this._state.now) { if (arrow.targetTime <= this._state.now) {
// 伤害判定 // 伤害判定
let damagedPlayers = this._state.players.filter(v => { let damagedPlayers = this._state.players.filter(v => {
// 不能伤害自己
// if (v.id === arrow.fromPlayerId) {
// return false;
// }
return (v.pos.x - arrow.targetPos.x) * (v.pos.x - arrow.targetPos.x) + (v.pos.y - arrow.targetPos.y) * (v.pos.y - arrow.targetPos.y) <= gameConfig.arrowAttackRadius * gameConfig.arrowAttackRadius return (v.pos.x - arrow.targetPos.x) * (v.pos.x - arrow.targetPos.x) + (v.pos.y - arrow.targetPos.y) * (v.pos.y - arrow.targetPos.y) <= gameConfig.arrowAttackRadius * gameConfig.arrowAttackRadius
}); });
damagedPlayers.forEach(p => { damagedPlayers.forEach(p => {
@ -81,11 +78,8 @@ export class GameSystem {
p.dizzyEndTime = this._state.now + gameConfig.arrowDizzyTime; p.dizzyEndTime = this._state.now + gameConfig.arrowDizzyTime;
// Event // Event
this.onDamage.forEach(h => h({
fromPlayerId: arrow.fromPlayerId,
toPlayerId: p.id
}))
}) })
this._state.arrows.splice(i, 1); this._state.arrows.splice(i, 1);
} }
} }
@ -93,7 +87,7 @@ export class GameSystem {
} }
// Events (Game Push) // Events (Game Push)
onDamage: ((e: { fromPlayerId: number, toPlayerId: number }) => void)[] = []; onNewArrow: ((arrow: ArrowState) => void)[] = [];
} }

View File

@ -1,7 +1,5 @@
export const gameConfig = { export const gameConfig = {
syncRate: 10, syncRate: 10,
// 网络延迟(同时在服务端和客户端生效,所以实际是双倍延迟)
networkLag: 200,
// 攻击技能的冷却时间(毫秒) // 攻击技能的冷却时间(毫秒)
attackCD: 1000, attackCD: 1000,

View File

@ -1,6 +1,7 @@
import { Component, Vec3, _decorator } from 'cc'; import { Component, Vec3, _decorator } from 'cc';
import { MathUtil } from '../../scripts/models/MathUtil'; import { MathUtil } from '../../scripts/models/MathUtil';
import { gameConfig } from '../../scripts/shared/game/gameConfig';
import { ArrowState } from '../../scripts/shared/game/state/ArrowState'; import { ArrowState } from '../../scripts/shared/game/state/ArrowState';
const { ccclass, property } = _decorator; const { ccclass, property } = _decorator;
@ -27,7 +28,8 @@ export class Arrow extends Component {
this._startPos.set(startPos); this._startPos.set(startPos);
this._endPos.set(state.targetPos.x, 0, -state.targetPos.y); this._endPos.set(state.targetPos.x, 0, -state.targetPos.y);
this._startTime = Date.now(); this._startTime = Date.now();
this._endTime = this._startTime + state.targetTime - now; // 箭的展示与判定相分离,展示就按固定的飞行时长展示
this._endTime = this._startTime + gameConfig.arrowFlyTime;
this._updatePosAndForward(0); this._updatePosAndForward(0);
} }
@ -36,6 +38,10 @@ export class Arrow extends Component {
//下一个目标位置 //下一个目标位置
let percent = MathUtil.limit((Date.now() - this._startTime) / (this._endTime - this._startTime), 0, 1); let percent = MathUtil.limit((Date.now() - this._startTime) / (this._endTime - this._startTime), 0, 1);
this._updatePosAndForward(percent); this._updatePosAndForward(percent);
if (percent >= 1) {
this.node.removeFromParent();
}
} }
private _updatePosAndForward(percent: number) { private _updatePosAndForward(percent: number) {

View File

@ -6,6 +6,7 @@ import { Player } from '../../prefabs/Player/Player';
import { FollowCamera } from '../../scripts/components/FollowCamera'; import { FollowCamera } from '../../scripts/components/FollowCamera';
import { GameManager } from '../../scripts/models/GameManager'; import { GameManager } from '../../scripts/models/GameManager';
import { gameConfig } from '../../scripts/shared/game/gameConfig'; import { gameConfig } from '../../scripts/shared/game/gameConfig';
import { ArrowState } from '../../scripts/shared/game/state/ArrowState';
const { ccclass, property } = _decorator; const { ccclass, property } = _decorator;
/** /**
@ -41,8 +42,8 @@ export class GameScene extends Component {
gameManager!: GameManager; gameManager!: GameManager;
private _playerInstances: { [playerId: number]: Player } = {}; private _playerInstances: { [playerId: number]: Player | undefined } = {};
private _arrowInstances: { [arrowId: number]: Arrow } = {}; private _arrowInstances: { [arrowId: number]: Arrow | undefined } = {};
private _selfSpeed?: Vec2 = new Vec2(0, 0); private _selfSpeed?: Vec2 = new Vec2(0, 0);
onLoad() { onLoad() {
@ -61,10 +62,18 @@ export class GameScene extends Component {
} }
this.gameManager = new GameManager(); this.gameManager = new GameManager();
// 监听数据状态事件
this.gameManager.gameSystem.onNewArrow.push(v => { this._onNewArrow(v) });
// 断线一秒后重连
this.gameManager.client.flows.postDisconnectFlow.push(v => { this.gameManager.client.flows.postDisconnectFlow.push(v => {
location.reload() setTimeout(() => {
this.gameManager.join();
}, 2000)
return v; return v;
}); });
this.gameManager.join(); this.gameManager.join();
} }
@ -85,14 +94,13 @@ export class GameScene extends Component {
} }
this._updatePlayers(); this._updatePlayers();
this._updateArrows();
} }
private _updatePlayers() { private _updatePlayers() {
// Update pos // Update pos
let playerStates = this.gameManager.state.players; let playerStates = this.gameManager.state.players;
for (let playerState of playerStates) { for (let playerState of playerStates) {
let player: Player = this._playerInstances[playerState.id]; let player = this._playerInstances[playerState.id];
if (!player) { if (!player) {
let node = instantiate(this.prefabPlayer); let node = instantiate(this.prefabPlayer);
this.players.addChild(node); this.players.addChild(node);
@ -119,33 +127,27 @@ export class GameScene extends Component {
} }
} }
private _updateArrows() { private _onNewArrow(arrowState: ArrowState) {
// Update pos let arrow = this._arrowInstances[arrowState.id];
let arrowStates = this.gameManager.state.arrows; // 已经存在
for (let arrowState of arrowStates) { if (arrow) {
let arrow: Arrow = this._arrowInstances[arrowState.id]; return;
if (!arrow) {
let playerState = this.gameManager.state.players.find(v => v.id === arrowState.fromPlayerId);
if (!playerState) {
continue;
}
let playerNode = this._playerInstances[playerState.id].node;
let node = instantiate(this.prefabArrow);
this.arrows.addChild(node);
arrow = this._arrowInstances[arrowState.id] = node.getComponent(Arrow)!;
arrow.init(arrowState, playerNode.position, this.gameManager.state.now);
}
} }
// Clear left players let playerState = this.gameManager.state.players.find(v => v.id === arrowState.fromPlayerId);
for (let i = this.arrows.children.length - 1; i > -1; --i) { if (!playerState) {
let arrow = this.arrows.children[i].getComponent(Arrow)!; return;
if (!this.gameManager.state.arrows.find(v => v.id === arrow.id)) {
arrow.node.removeFromParent();
delete this._arrowInstances[arrow.id];
}
} }
let playerNode = this._playerInstances[playerState.id]?.node;
if (!playerNode) {
return;
}
// 创建新的箭矢显示
let node = instantiate(this.prefabArrow);
this.arrows.addChild(node);
arrow = this._arrowInstances[arrowState.id] = node.getComponent(Arrow)!;
arrow.init(arrowState, playerNode.position, this.gameManager.state.now);
} }
onBtnAttack() { onBtnAttack() {
@ -154,7 +156,11 @@ export class GameScene extends Component {
return; return;
} }
let playerNode = this._playerInstances[this.gameManager.selfPlayerId].node; let playerNode = this._playerInstances[this.gameManager.selfPlayerId]?.node;
if (!playerNode) {
return;
}
// 攻击落点偏移(表现层坐标) // 攻击落点偏移(表现层坐标)
let sceneOffset = playerNode.forward.clone().normalize().multiplyScalar(gameConfig.arrowDistance); let sceneOffset = playerNode.forward.clone().normalize().multiplyScalar(gameConfig.arrowDistance);
// 攻击落点(逻辑层坐标) // 攻击落点(逻辑层坐标)

View File

@ -1,5 +1,4 @@
import { WsClient } from "tsrpc-browser"; import { WsClient } from "tsrpc-browser";
import { gameConfig } from "../shared/game/gameConfig";
import { GameSystem, GameSystemState } from "../shared/game/GameSystem"; import { GameSystem, GameSystemState } from "../shared/game/GameSystem";
import { ClientInput, MsgClientInput } from "../shared/protocols/client/MsgClientInput"; import { ClientInput, MsgClientInput } from "../shared/protocols/client/MsgClientInput";
import { MsgFrame } from "../shared/protocols/server/MsgFrame"; import { MsgFrame } from "../shared/protocols/server/MsgFrame";
@ -27,14 +26,15 @@ export class GameManager {
});; });;
client.listenMsg('server/Frame', msg => { this._onServerSync(msg) }); client.listenMsg('server/Frame', msg => { this._onServerSync(msg) });
// 模拟网络延迟 // 模拟网络延迟 可通过 URL 参数 ?lag=200 设置延迟
if (gameConfig.networkLag) { let networkLag = parseInt(new URLSearchParams(location.search).get('lag') || '0') || 0;
if (networkLag) {
client.flows.preRecvDataFlow.push(async v => { client.flows.preRecvDataFlow.push(async v => {
await new Promise(rs => { setTimeout(rs, gameConfig.networkLag) }) await new Promise(rs => { setTimeout(rs, networkLag) })
return v; return v;
}); });
client.flows.preSendDataFlow.push(async v => { client.flows.preSendDataFlow.push(async v => {
await new Promise(rs => { setTimeout(rs, gameConfig.networkLag) }) await new Promise(rs => { setTimeout(rs, networkLag) })
return v; return v;
}); });
} }