和解的实现
This commit is contained in:
parent
49f8c94974
commit
23186001db
@ -0,0 +1,12 @@
|
||||
import { ApiCallWs } from "tsrpc";
|
||||
import { roomInstance } from "..";
|
||||
import { ReqJoin, ResJoin } from "../shared/protocols/PtlJoin";
|
||||
|
||||
export async function ApiJoin(call: ApiCallWs<ReqJoin, ResJoin>) {
|
||||
let playerId = roomInstance.join(call.req, call.conn);
|
||||
|
||||
call.succ({
|
||||
playerId: playerId,
|
||||
gameState: roomInstance.gameSystem.state
|
||||
})
|
||||
}
|
@ -1,12 +0,0 @@
|
||||
import { ApiCallWs } from "tsrpc";
|
||||
import { roomInstance } from "..";
|
||||
import { ReqJoinRoom, ResJoinRoom } from "../shared/protocols/PtlJoinRoom";
|
||||
|
||||
export async function ApiJoinRoom(call: ApiCallWs<ReqJoinRoom, ResJoinRoom>) {
|
||||
let uid = roomInstance.join(call.req, call.conn);
|
||||
|
||||
call.succ({
|
||||
uid: uid,
|
||||
roomState: roomInstance.state
|
||||
})
|
||||
}
|
@ -1,17 +1,36 @@
|
||||
import 'k8w-extend-native';
|
||||
import * as path from "path";
|
||||
import { WsServer } from "tsrpc";
|
||||
import { WsConnection, WsServer } from "tsrpc";
|
||||
import { Room } from './models/Room';
|
||||
import { serviceProto } from './shared/protocols/serviceProto';
|
||||
import { serviceProto, ServiceType } from './shared/protocols/serviceProto';
|
||||
|
||||
// Create the Server
|
||||
export const server = new WsServer(serviceProto, {
|
||||
port: 3000,
|
||||
// Remove this to use binary mode (remove from the client too)
|
||||
json: true
|
||||
// json: true
|
||||
});
|
||||
|
||||
// 测试,只有一个房间
|
||||
// 断开连接后退出房间
|
||||
server.flows.postDisconnectFlow.push(v => {
|
||||
let conn = v.conn as WsConnection<ServiceType>;
|
||||
if (conn.playerId) {
|
||||
roomInstance.leave(conn.playerId, conn);
|
||||
}
|
||||
|
||||
return v;
|
||||
})
|
||||
|
||||
// 模拟网络延迟
|
||||
server.flows.preRecvDataFlow.push(async v => {
|
||||
await new Promise(rs => { setTimeout(rs, 300) })
|
||||
return v;
|
||||
})
|
||||
server.flows.preSendDataFlow.push(async v => {
|
||||
await new Promise(rs => { setTimeout(rs, 300) })
|
||||
return v;
|
||||
})
|
||||
|
||||
export const roomInstance = new Room(server);
|
||||
|
||||
// Initialize before server start
|
||||
|
@ -1,102 +1,100 @@
|
||||
import { WsConnection, WsServer } from "tsrpc";
|
||||
import { ReqJoinRoom } from "../shared/protocols/PtlJoinRoom";
|
||||
import { MsgFrame } from "../shared/protocols/serverMsgs/MsgFrame";
|
||||
import { GameSystem, GameSystemInput, PlayerJoin } from "../shared/game/GameSystem";
|
||||
import { ReqJoin } from "../shared/protocols/PtlJoin";
|
||||
import { ServiceType } from "../shared/protocols/serviceProto";
|
||||
import { applyPlayerInput, PlayerInput, PlayerState } from "../shared/states/Player";
|
||||
import { RoomState } from "../shared/states/RoomState";
|
||||
|
||||
/**
|
||||
* 服务端 - 房间 - 逻辑系统
|
||||
*/
|
||||
export class Room {
|
||||
|
||||
state: RoomState = {
|
||||
players: []
|
||||
}
|
||||
|
||||
// 次数/秒
|
||||
syncRate = 10;
|
||||
lastUid = 0;
|
||||
syncRate = 3;
|
||||
nextPlayerId = 1;
|
||||
|
||||
gameSystem = new GameSystem();
|
||||
|
||||
server: WsServer<ServiceType>;
|
||||
conns: WsConnection[] = [];
|
||||
|
||||
pendingInputs: MsgFrame['inputs'] = [];
|
||||
conns: WsConnection<ServiceType>[] = [];
|
||||
pendingInputs: GameSystemInput[] = [];
|
||||
playerLastSn: { [playerId: number]: number | undefined } = {};
|
||||
lastSyncTime?: number;
|
||||
|
||||
constructor(server: WsServer<ServiceType>) {
|
||||
this.server = server;
|
||||
setInterval(() => { this.sendSyncFrame() }, 1000 / this.syncRate);
|
||||
}
|
||||
|
||||
sendSyncFrame() {
|
||||
// 发送同步帧
|
||||
this.server.broadcastMsg('serverMsgs/Frame', {
|
||||
inputs: this.pendingInputs
|
||||
}, this.conns);
|
||||
this.pendingInputs = [];
|
||||
setInterval(() => { this.sync() }, 1000 / this.syncRate);
|
||||
}
|
||||
|
||||
/** 加入房间 */
|
||||
join(req: ReqJoinRoom, conn: WsConnection<ServiceType>) {
|
||||
let player: PlayerState = {
|
||||
...req,
|
||||
uid: ++this.lastUid,
|
||||
join(req: ReqJoin, conn: WsConnection<ServiceType>) {
|
||||
let input: PlayerJoin = {
|
||||
type: 'PlayerJoin',
|
||||
playerId: this.nextPlayerId++,
|
||||
// 初始位置随机
|
||||
pos: {
|
||||
x: Math.random() * 10,
|
||||
y: Math.random() * 10
|
||||
}
|
||||
}
|
||||
this.applyInput(input);
|
||||
|
||||
this.conns.push(conn);
|
||||
this.state.players.push(player);
|
||||
|
||||
conn.uid = player.uid;
|
||||
conn.listenMsg('clientMsgs/Input', call => {
|
||||
this.pendingInputs.push({
|
||||
uid: player.uid,
|
||||
msgInput: call.msg
|
||||
});
|
||||
conn.playerId = input.playerId;
|
||||
conn.listenMsg('client/ClientInput', call => {
|
||||
this.playerLastSn[input.playerId] = call.msg.sn;
|
||||
call.msg.inputs.forEach(v => {
|
||||
this.applyInput({
|
||||
uid: player.uid,
|
||||
input: call.msg
|
||||
...v,
|
||||
playerId: input.playerId
|
||||
});
|
||||
})
|
||||
});
|
||||
|
||||
this.server.broadcastMsg('serverMsgs/Join', {
|
||||
player: player
|
||||
}, this.conns);
|
||||
return input.playerId;
|
||||
}
|
||||
|
||||
return player.uid;
|
||||
applyInput(input: GameSystemInput) {
|
||||
this.pendingInputs.push(input);
|
||||
}
|
||||
|
||||
sync() {
|
||||
let inputs = this.pendingInputs;
|
||||
this.pendingInputs = [];
|
||||
|
||||
// Apply inputs
|
||||
inputs.forEach(v => {
|
||||
this.gameSystem.applyInput(v)
|
||||
});
|
||||
|
||||
// TimePast
|
||||
let now = process.uptime();
|
||||
this.applyInput({
|
||||
type: 'TimePast',
|
||||
dt: now - (this.lastSyncTime ?? now)
|
||||
});
|
||||
this.lastSyncTime = now;
|
||||
|
||||
// 发送同步帧
|
||||
this.conns.forEach(v => {
|
||||
v.sendMsg('server/Frame', {
|
||||
inputs: inputs,
|
||||
lastSn: this.playerLastSn[v.playerId!]
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
/** 离开房间 */
|
||||
leave(uid: number, conn: WsConnection<ServiceType>) {
|
||||
this.conns.removeOne(v => v.uid === uid);
|
||||
this.state.players.removeOne(v => v.uid === uid);
|
||||
|
||||
conn.unlistenMsgAll('clientMsgs/Input');
|
||||
|
||||
this.server.broadcastMsg('serverMsgs/Leave', {
|
||||
uid: uid
|
||||
}, this.conns);
|
||||
leave(playerId: number, conn: WsConnection<ServiceType>) {
|
||||
this.conns.removeOne(v => v.playerId === playerId);
|
||||
this.applyInput({
|
||||
type: 'PlayerLeave',
|
||||
playerId: playerId
|
||||
});
|
||||
}
|
||||
|
||||
applyInput(input: RoomInput) {
|
||||
let playerIndex = this.state.players.findIndex(v => v.uid === input.uid);
|
||||
if (playerIndex > -1) {
|
||||
this.state.players[playerIndex] = applyPlayerInput(this.state.players[playerIndex], input.input);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export interface RoomInput {
|
||||
uid: number,
|
||||
input: PlayerInput
|
||||
}
|
||||
|
||||
declare module 'tsrpc' {
|
||||
export interface WsConnection {
|
||||
uid?: number;
|
||||
playerId?: number;
|
||||
}
|
||||
}
|
@ -0,0 +1,124 @@
|
||||
import { gameConfig } from "./gameConfig";
|
||||
import { ArrowState } from "./state/ArrowState";
|
||||
import { PlayerState } from "./state/PlayerState";
|
||||
|
||||
export interface GameSystemState {
|
||||
now: number,
|
||||
players: PlayerState[],
|
||||
arrow: ArrowState[],
|
||||
nextArrowId: number
|
||||
}
|
||||
|
||||
export class GameSystem {
|
||||
|
||||
// State (Render Pull)
|
||||
private _state: GameSystemState = {
|
||||
now: 0,
|
||||
players: [],
|
||||
arrow: [],
|
||||
nextArrowId: 1
|
||||
}
|
||||
get state(): Readonly<GameSystemState> {
|
||||
return this._state
|
||||
}
|
||||
|
||||
reset(state: GameSystemState) {
|
||||
this._state = Object.merge({}, state);
|
||||
}
|
||||
|
||||
// Input
|
||||
applyInput(input: GameSystemInput) {
|
||||
if (input.type === 'PlayerMove') {
|
||||
let player = this._state.players.find(v => v.id === input.playerId);
|
||||
if (!player) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (player.dizzyEndTime && player.dizzyEndTime > this._state.now) {
|
||||
return;
|
||||
}
|
||||
player.pos.x += input.speed.x * input.dt;
|
||||
player.pos.y += input.speed.y * input.dt;
|
||||
}
|
||||
else if (input.type === 'PlayerAttack') {
|
||||
let player = this._state.players.find(v => v.id === input.playerId);
|
||||
if (player) {
|
||||
this._state.arrow.push({
|
||||
id: this._state.nextArrowId++,
|
||||
fromPlayerId: input.playerId,
|
||||
startPos: { ...player.pos },
|
||||
startTime: this._state.now,
|
||||
targetPos: {
|
||||
x: player.pos.x + input.direction.x * gameConfig.arrowDistance,
|
||||
y: player.pos.y + input.direction.y * gameConfig.arrowDistance
|
||||
},
|
||||
targetTime: this._state.now + gameConfig.arrowFlyTime
|
||||
});
|
||||
}
|
||||
}
|
||||
else if (input.type === 'PlayerJoin') {
|
||||
this.state.players.push({
|
||||
id: input.playerId,
|
||||
pos: { ...input.pos }
|
||||
})
|
||||
}
|
||||
else if (input.type === 'PlayerLeave') {
|
||||
this.state.players.remove(v => v.id === input.playerId);
|
||||
}
|
||||
else if (input.type === 'TimePast') {
|
||||
this._state.now += input.dt;
|
||||
|
||||
// 落地的 Arrow
|
||||
for (let i = this._state.arrow.length - 1; i > -1; --i) {
|
||||
let arrow = this._state.arrow[i];
|
||||
if (arrow.targetTime <= this._state.now) {
|
||||
// 伤害判定
|
||||
let damagedPlayers = this._state.players.filter(v => {
|
||||
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.arrowDistance * gameConfig.arrowDistance
|
||||
});
|
||||
damagedPlayers.forEach(p => {
|
||||
// 设置击晕状态
|
||||
p.dizzyEndTime = this._state.now + gameConfig.arrowDizzyTime;
|
||||
|
||||
// Event
|
||||
this.onDamage.forEach(h => h({
|
||||
fromPlayerId: arrow.fromPlayerId,
|
||||
toPlayerId: p.id
|
||||
}))
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Events (Game Push)
|
||||
onDamage: ((e: { fromPlayerId: number, toPlayerId: number }) => void)[] = [];
|
||||
|
||||
}
|
||||
|
||||
export interface PlayerMove {
|
||||
type: 'PlayerMove',
|
||||
playerId: number,
|
||||
speed: { x: number, y: number },
|
||||
// 移动的时间 (秒)
|
||||
dt: number,
|
||||
}
|
||||
export interface PlayerAttack {
|
||||
type: 'PlayerAttack',
|
||||
playerId: number,
|
||||
direction: { x: number, y: number },
|
||||
}
|
||||
export interface PlayerJoin {
|
||||
type: 'PlayerJoin',
|
||||
playerId: number,
|
||||
pos: { x: number, y: number }
|
||||
}
|
||||
export interface PlayerLeave {
|
||||
type: 'PlayerLeave',
|
||||
playerId: number
|
||||
}
|
||||
export interface TimePast {
|
||||
type: 'TimePast',
|
||||
dt: number
|
||||
}
|
||||
export type GameSystemInput = PlayerMove | PlayerAttack | PlayerJoin | PlayerLeave | TimePast;
|
@ -0,0 +1,10 @@
|
||||
export const gameConfig = {
|
||||
// 攻击技能的冷却时间(毫秒)
|
||||
attackCD: 1000,
|
||||
|
||||
moveSpeed: 10,
|
||||
|
||||
arrowFlyTime: 1000,
|
||||
arrowDistance: 2,
|
||||
arrowDizzyTime: 1000
|
||||
}
|
@ -0,0 +1,8 @@
|
||||
export type ArrowState = {
|
||||
id: number,
|
||||
fromPlayerId: number,
|
||||
startTime: number,
|
||||
startPos: { x: number, y: number },
|
||||
targetTime: number,
|
||||
targetPos: { x: number, y: number }
|
||||
}
|
@ -0,0 +1,7 @@
|
||||
export interface PlayerState {
|
||||
id: number,
|
||||
// 位置
|
||||
pos: { x: number, y: number },
|
||||
// 晕眩结束时间
|
||||
dizzyEndTime?: number,
|
||||
}
|
@ -0,0 +1,12 @@
|
||||
import { GameSystemState } from "../game/GameSystem";
|
||||
|
||||
export interface ReqJoin {
|
||||
|
||||
}
|
||||
|
||||
export interface ResJoin {
|
||||
playerId: number,
|
||||
gameState: GameSystemState
|
||||
}
|
||||
|
||||
// export const conf = {}
|
@ -1,14 +0,0 @@
|
||||
import { PlayerState } from "../states/Player";
|
||||
import { RoomState } from "../states/RoomState";
|
||||
|
||||
export interface ReqJoinRoom {
|
||||
nickname: string;
|
||||
skinId: number;
|
||||
}
|
||||
|
||||
export interface ResJoinRoom {
|
||||
uid: number,
|
||||
roomState: RoomState
|
||||
}
|
||||
|
||||
// export const conf = {}
|
@ -0,0 +1,8 @@
|
||||
import { PlayerAttack, PlayerMove } from "../../game/GameSystem";
|
||||
|
||||
export interface MsgClientInput {
|
||||
sn: number,
|
||||
inputs: ClientInput[]
|
||||
};
|
||||
|
||||
export type ClientInput = Omit<PlayerMove, 'playerId'> | Omit<PlayerAttack, 'playerId'>;
|
@ -1,3 +0,0 @@
|
||||
import { PlayerInput } from "../../states/Player";
|
||||
|
||||
export type MsgInput = { sn: number } & PlayerInput;
|
@ -0,0 +1,6 @@
|
||||
import { GameSystemInput } from "../../game/GameSystem";
|
||||
|
||||
export interface MsgFrame {
|
||||
inputs: GameSystemInput[],
|
||||
lastSn?: number
|
||||
}
|
@ -1,8 +0,0 @@
|
||||
import { MsgInput } from "../clientMsgs/MsgInput";
|
||||
|
||||
export interface MsgFrame {
|
||||
inputs: {
|
||||
uid: number,
|
||||
msgInput: MsgInput
|
||||
}[]
|
||||
}
|
@ -1,5 +0,0 @@
|
||||
import { PlayerState } from "../../states/Player";
|
||||
|
||||
export interface MsgJoin {
|
||||
player: PlayerState;
|
||||
}
|
@ -1,3 +0,0 @@
|
||||
export interface MsgLeave {
|
||||
uid: number;
|
||||
}
|
@ -1,61 +1,41 @@
|
||||
import { ServiceProto } from 'tsrpc-proto';
|
||||
import { MsgInput } from './clientMsgs/MsgInput';
|
||||
import { ReqJoinRoom, ResJoinRoom } from './PtlJoinRoom';
|
||||
import { MsgFrame } from './serverMsgs/MsgFrame';
|
||||
import { MsgJoin } from './serverMsgs/MsgJoin';
|
||||
import { MsgLeave } from './serverMsgs/MsgLeave';
|
||||
import { MsgClientInput } from './client/MsgClientInput';
|
||||
import { ReqJoin, ResJoin } from './PtlJoin';
|
||||
import { MsgFrame } from './server/MsgFrame';
|
||||
|
||||
export interface ServiceType {
|
||||
api: {
|
||||
"JoinRoom": {
|
||||
req: ReqJoinRoom,
|
||||
res: ResJoinRoom
|
||||
"Join": {
|
||||
req: ReqJoin,
|
||||
res: ResJoin
|
||||
}
|
||||
},
|
||||
msg: {
|
||||
"clientMsgs/Input": MsgInput,
|
||||
"serverMsgs/Frame": MsgFrame,
|
||||
"serverMsgs/Join": MsgJoin,
|
||||
"serverMsgs/Leave": MsgLeave
|
||||
"client/ClientInput": MsgClientInput,
|
||||
"server/Frame": MsgFrame
|
||||
}
|
||||
}
|
||||
|
||||
export const serviceProto: ServiceProto<ServiceType> = {
|
||||
"version": 3,
|
||||
"services": [
|
||||
{
|
||||
"id": 2,
|
||||
"name": "clientMsgs/Input",
|
||||
"id": 0,
|
||||
"name": "client/ClientInput",
|
||||
"type": "msg"
|
||||
},
|
||||
{
|
||||
"id": 3,
|
||||
"name": "JoinRoom",
|
||||
"id": 1,
|
||||
"name": "Join",
|
||||
"type": "api"
|
||||
},
|
||||
{
|
||||
"id": 7,
|
||||
"name": "serverMsgs/Frame",
|
||||
"type": "msg"
|
||||
},
|
||||
{
|
||||
"id": 4,
|
||||
"name": "serverMsgs/Join",
|
||||
"type": "msg"
|
||||
},
|
||||
{
|
||||
"id": 5,
|
||||
"name": "serverMsgs/Leave",
|
||||
"id": 2,
|
||||
"name": "server/Frame",
|
||||
"type": "msg"
|
||||
}
|
||||
],
|
||||
"types": {
|
||||
"clientMsgs/MsgInput/MsgInput": {
|
||||
"type": "Intersection",
|
||||
"members": [
|
||||
{
|
||||
"id": 0,
|
||||
"type": {
|
||||
"client/MsgClientInput/MsgClientInput": {
|
||||
"type": "Interface",
|
||||
"properties": [
|
||||
{
|
||||
@ -64,24 +44,52 @@ export const serviceProto: ServiceProto<ServiceType> = {
|
||||
"type": {
|
||||
"type": "Number"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": 1,
|
||||
"name": "inputs",
|
||||
"type": {
|
||||
"type": "Array",
|
||||
"elementType": {
|
||||
"type": "Reference",
|
||||
"target": "client/MsgClientInput/ClientInput"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"client/MsgClientInput/ClientInput": {
|
||||
"type": "Union",
|
||||
"members": [
|
||||
{
|
||||
"id": 0,
|
||||
"type": {
|
||||
"target": {
|
||||
"type": "Reference",
|
||||
"target": "../game/GameSystem/PlayerMove"
|
||||
},
|
||||
"keys": [
|
||||
"playerId"
|
||||
],
|
||||
"type": "Omit"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": 1,
|
||||
"type": {
|
||||
"target": {
|
||||
"type": "Reference",
|
||||
"target": "../states/Player/PlayerInput"
|
||||
"target": "../game/GameSystem/PlayerAttack"
|
||||
},
|
||||
"keys": [
|
||||
"playerId"
|
||||
],
|
||||
"type": "Omit"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"../states/Player/PlayerInput": {
|
||||
"type": "Reference",
|
||||
"target": "../states/Player/PlayerMove"
|
||||
},
|
||||
"../states/Player/PlayerMove": {
|
||||
"../game/GameSystem/PlayerMove": {
|
||||
"type": "Interface",
|
||||
"properties": [
|
||||
{
|
||||
@ -89,12 +97,69 @@ export const serviceProto: ServiceProto<ServiceType> = {
|
||||
"name": "type",
|
||||
"type": {
|
||||
"type": "Literal",
|
||||
"literal": "move"
|
||||
"literal": "PlayerMove"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": 1,
|
||||
"name": "offset",
|
||||
"name": "playerId",
|
||||
"type": {
|
||||
"type": "Number"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": 2,
|
||||
"name": "speed",
|
||||
"type": {
|
||||
"type": "Interface",
|
||||
"properties": [
|
||||
{
|
||||
"id": 0,
|
||||
"name": "x",
|
||||
"type": {
|
||||
"type": "Number"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": 1,
|
||||
"name": "y",
|
||||
"type": {
|
||||
"type": "Number"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": 3,
|
||||
"name": "dt",
|
||||
"type": {
|
||||
"type": "Number"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"../game/GameSystem/PlayerAttack": {
|
||||
"type": "Interface",
|
||||
"properties": [
|
||||
{
|
||||
"id": 0,
|
||||
"name": "type",
|
||||
"type": {
|
||||
"type": "Literal",
|
||||
"literal": "PlayerAttack"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": 1,
|
||||
"name": "playerId",
|
||||
"type": {
|
||||
"type": "Number"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": 2,
|
||||
"name": "direction",
|
||||
"type": {
|
||||
"type": "Interface",
|
||||
"properties": [
|
||||
@ -117,87 +182,276 @@ export const serviceProto: ServiceProto<ServiceType> = {
|
||||
}
|
||||
]
|
||||
},
|
||||
"PtlJoinRoom/ReqJoinRoom": {
|
||||
"PtlJoin/ReqJoin": {
|
||||
"type": "Interface"
|
||||
},
|
||||
"PtlJoin/ResJoin": {
|
||||
"type": "Interface",
|
||||
"properties": [
|
||||
{
|
||||
"id": 0,
|
||||
"name": "nickname",
|
||||
"name": "playerId",
|
||||
"type": {
|
||||
"type": "String"
|
||||
"type": "Number"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": 1,
|
||||
"name": "skinId",
|
||||
"type": {
|
||||
"type": "Number"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"PtlJoinRoom/ResJoinRoom": {
|
||||
"type": "Interface",
|
||||
"properties": [
|
||||
{
|
||||
"id": 0,
|
||||
"name": "uid",
|
||||
"type": {
|
||||
"type": "Number"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": 3,
|
||||
"name": "roomState",
|
||||
"name": "gameState",
|
||||
"type": {
|
||||
"type": "Reference",
|
||||
"target": "../states/RoomState/RoomState"
|
||||
"target": "../game/GameSystem/GameSystemState"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"../states/RoomState/RoomState": {
|
||||
"../game/GameSystem/GameSystemState": {
|
||||
"type": "Interface",
|
||||
"properties": [
|
||||
{
|
||||
"id": 0,
|
||||
"name": "now",
|
||||
"type": {
|
||||
"type": "Number"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": 1,
|
||||
"name": "players",
|
||||
"type": {
|
||||
"type": "Array",
|
||||
"elementType": {
|
||||
"type": "Reference",
|
||||
"target": "../states/Player/PlayerState"
|
||||
"target": "../game/state/PlayerState/PlayerState"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": 2,
|
||||
"name": "arrow",
|
||||
"type": {
|
||||
"type": "Array",
|
||||
"elementType": {
|
||||
"type": "Reference",
|
||||
"target": "../game/state/ArrowState/ArrowState"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": 3,
|
||||
"name": "nextArrowId",
|
||||
"type": {
|
||||
"type": "Number"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"../states/Player/PlayerState": {
|
||||
"../game/state/PlayerState/PlayerState": {
|
||||
"type": "Interface",
|
||||
"properties": [
|
||||
{
|
||||
"id": 0,
|
||||
"name": "uid",
|
||||
"name": "id",
|
||||
"type": {
|
||||
"type": "Number"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": 1,
|
||||
"name": "nickname",
|
||||
"name": "pos",
|
||||
"type": {
|
||||
"type": "String"
|
||||
"type": "Interface",
|
||||
"properties": [
|
||||
{
|
||||
"id": 0,
|
||||
"name": "x",
|
||||
"type": {
|
||||
"type": "Number"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": 1,
|
||||
"name": "y",
|
||||
"type": {
|
||||
"type": "Number"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": 2,
|
||||
"name": "skinId",
|
||||
"name": "dizzyEndTime",
|
||||
"type": {
|
||||
"type": "Number"
|
||||
},
|
||||
"optional": true
|
||||
}
|
||||
]
|
||||
},
|
||||
"../game/state/ArrowState/ArrowState": {
|
||||
"type": "Interface",
|
||||
"properties": [
|
||||
{
|
||||
"id": 0,
|
||||
"name": "id",
|
||||
"type": {
|
||||
"type": "Number"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": 1,
|
||||
"name": "fromPlayerId",
|
||||
"type": {
|
||||
"type": "Number"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": 2,
|
||||
"name": "startTime",
|
||||
"type": {
|
||||
"type": "Number"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": 3,
|
||||
"name": "startPos",
|
||||
"type": {
|
||||
"type": "Interface",
|
||||
"properties": [
|
||||
{
|
||||
"id": 0,
|
||||
"name": "x",
|
||||
"type": {
|
||||
"type": "Number"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": 1,
|
||||
"name": "y",
|
||||
"type": {
|
||||
"type": "Number"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": 4,
|
||||
"name": "targetTime",
|
||||
"type": {
|
||||
"type": "Number"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": 5,
|
||||
"name": "targetPos",
|
||||
"type": {
|
||||
"type": "Interface",
|
||||
"properties": [
|
||||
{
|
||||
"id": 0,
|
||||
"name": "x",
|
||||
"type": {
|
||||
"type": "Number"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": 1,
|
||||
"name": "y",
|
||||
"type": {
|
||||
"type": "Number"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"server/MsgFrame/MsgFrame": {
|
||||
"type": "Interface",
|
||||
"properties": [
|
||||
{
|
||||
"id": 0,
|
||||
"name": "inputs",
|
||||
"type": {
|
||||
"type": "Array",
|
||||
"elementType": {
|
||||
"type": "Reference",
|
||||
"target": "../game/GameSystem/GameSystemInput"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": 1,
|
||||
"name": "lastSn",
|
||||
"type": {
|
||||
"type": "Number"
|
||||
},
|
||||
"optional": true
|
||||
}
|
||||
]
|
||||
},
|
||||
"../game/GameSystem/GameSystemInput": {
|
||||
"type": "Union",
|
||||
"members": [
|
||||
{
|
||||
"id": 0,
|
||||
"type": {
|
||||
"type": "Reference",
|
||||
"target": "../game/GameSystem/PlayerMove"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": 1,
|
||||
"type": {
|
||||
"type": "Reference",
|
||||
"target": "../game/GameSystem/PlayerAttack"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": 2,
|
||||
"type": {
|
||||
"type": "Reference",
|
||||
"target": "../game/GameSystem/PlayerJoin"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": 3,
|
||||
"type": {
|
||||
"type": "Reference",
|
||||
"target": "../game/GameSystem/PlayerLeave"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": 4,
|
||||
"type": {
|
||||
"type": "Reference",
|
||||
"target": "../game/GameSystem/TimePast"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"../game/GameSystem/PlayerJoin": {
|
||||
"type": "Interface",
|
||||
"properties": [
|
||||
{
|
||||
"id": 0,
|
||||
"name": "type",
|
||||
"type": {
|
||||
"type": "Literal",
|
||||
"literal": "PlayerJoin"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": 1,
|
||||
"name": "playerId",
|
||||
"type": {
|
||||
"type": "Number"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": 2,
|
||||
"name": "pos",
|
||||
"type": {
|
||||
"type": "Interface",
|
||||
@ -221,57 +475,40 @@ export const serviceProto: ServiceProto<ServiceType> = {
|
||||
}
|
||||
]
|
||||
},
|
||||
"serverMsgs/MsgFrame/MsgFrame": {
|
||||
"../game/GameSystem/PlayerLeave": {
|
||||
"type": "Interface",
|
||||
"properties": [
|
||||
{
|
||||
"id": 0,
|
||||
"name": "inputs",
|
||||
"name": "type",
|
||||
"type": {
|
||||
"type": "Array",
|
||||
"elementType": {
|
||||
"type": "Interface",
|
||||
"properties": [
|
||||
{
|
||||
"id": 0,
|
||||
"name": "uid",
|
||||
"type": {
|
||||
"type": "Number"
|
||||
"type": "Literal",
|
||||
"literal": "PlayerLeave"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": 1,
|
||||
"name": "msgInput",
|
||||
"name": "playerId",
|
||||
"type": {
|
||||
"type": "Reference",
|
||||
"target": "clientMsgs/MsgInput/MsgInput"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
"type": "Number"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"serverMsgs/MsgJoin/MsgJoin": {
|
||||
"../game/GameSystem/TimePast": {
|
||||
"type": "Interface",
|
||||
"properties": [
|
||||
{
|
||||
"id": 0,
|
||||
"name": "player",
|
||||
"name": "type",
|
||||
"type": {
|
||||
"type": "Reference",
|
||||
"target": "../states/Player/PlayerState"
|
||||
"type": "Literal",
|
||||
"literal": "TimePast"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"serverMsgs/MsgLeave/MsgLeave": {
|
||||
"type": "Interface",
|
||||
"properties": [
|
||||
{
|
||||
"id": 0,
|
||||
"name": "uid",
|
||||
"id": 1,
|
||||
"name": "dt",
|
||||
"type": {
|
||||
"type": "Number"
|
||||
}
|
||||
|
@ -1,30 +0,0 @@
|
||||
export interface PlayerState {
|
||||
uid: number,
|
||||
nickname: string,
|
||||
skinId: number,
|
||||
|
||||
// 可变状态
|
||||
pos: {
|
||||
x: number,
|
||||
y: number
|
||||
}
|
||||
}
|
||||
|
||||
export interface PlayerMove {
|
||||
type: 'move',
|
||||
// 位移距离
|
||||
offset: {
|
||||
x: number,
|
||||
y: number
|
||||
}
|
||||
}
|
||||
export type PlayerInput = PlayerMove;
|
||||
|
||||
export function applyPlayerInput(state: PlayerState, input: PlayerInput): PlayerState {
|
||||
if (input.type === 'move') {
|
||||
state.pos.x += input.offset.x;
|
||||
state.pos.y += input.offset.y;
|
||||
}
|
||||
|
||||
return state;
|
||||
}
|
@ -1,5 +0,0 @@
|
||||
import { PlayerState } from "./Player";
|
||||
|
||||
export interface RoomState {
|
||||
players: PlayerState[]
|
||||
}
|
@ -4,52 +4,32 @@
|
||||
"_objFlags": 0,
|
||||
"_native": "",
|
||||
"_effectAsset": {
|
||||
"__uuid__": "1baf0fc9-befa-459c-8bdd-af1a450a0319"
|
||||
"__uuid__": "a3cd009f-0ab0-420d-9278-b9fdab939bbc",
|
||||
"__expectedType__": "cc.EffectAsset"
|
||||
},
|
||||
"_techIdx": 0,
|
||||
"_defines": [
|
||||
{
|
||||
"USE_ALBEDO_MAP": true,
|
||||
"ROUGHNESS_CHANNEL": "g",
|
||||
"METALLIC_CHANNEL": "b",
|
||||
"OCCLUSION_CHANNEL": "r"
|
||||
"USE_TEXTURE": true
|
||||
}
|
||||
],
|
||||
"_states": [
|
||||
{
|
||||
"rasterizerState": {},
|
||||
"depthStencilState": {},
|
||||
"blendState": {
|
||||
"targets": [
|
||||
{}
|
||||
]
|
||||
},
|
||||
"depthStencilState": {},
|
||||
"rasterizerState": {}
|
||||
}
|
||||
}
|
||||
],
|
||||
"_props": [
|
||||
{
|
||||
"albedoScale": {
|
||||
"__type__": "cc.Vec4",
|
||||
"x": 1,
|
||||
"y": 1,
|
||||
"z": 1,
|
||||
"w": 1
|
||||
},
|
||||
"pbrScale": {
|
||||
"__type__": "cc.Vec4",
|
||||
"x": 1,
|
||||
"y": 0.242535620927811,
|
||||
"z": 0.400000005960464,
|
||||
"w": 1
|
||||
},
|
||||
"alphaThreshold": 1,
|
||||
"normalStrenth": 1,
|
||||
"mainTexture": {
|
||||
"__uuid__": "27e1fcb7-5016-4252-8c43-ac9c1c97308e@6c48a"
|
||||
},
|
||||
"occlusion": 1,
|
||||
"roughness": 0.242535620927811,
|
||||
"metallic": 0.400000005960464
|
||||
"__uuid__": "27e1fcb7-5016-4252-8c43-ac9c1c97308e@6c48a",
|
||||
"__expectedType__": "cc.Texture2D"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
@ -0,0 +1,12 @@
|
||||
{
|
||||
"ver": "1.1.0",
|
||||
"importer": "directory",
|
||||
"imported": true,
|
||||
"uuid": "40e7bad4-3fa9-45c6-9d50-ce41c40e8174",
|
||||
"files": [],
|
||||
"subMetas": {},
|
||||
"userData": {
|
||||
"compressionType": {},
|
||||
"isRemoteBundle": {}
|
||||
}
|
||||
}
|
@ -0,0 +1,43 @@
|
||||
{
|
||||
"__type__": "cc.Material",
|
||||
"_name": "Material #7",
|
||||
"_objFlags": 0,
|
||||
"_native": "",
|
||||
"_effectAsset": {
|
||||
"__uuid__": "1baf0fc9-befa-459c-8bdd-af1a450a0319",
|
||||
"__expectedType__": "cc.EffectAsset"
|
||||
},
|
||||
"_techIdx": 0,
|
||||
"_defines": [
|
||||
{
|
||||
"USE_ALBEDO_MAP": true
|
||||
}
|
||||
],
|
||||
"_states": [
|
||||
{
|
||||
"rasterizerState": {},
|
||||
"blendState": {
|
||||
"targets": [
|
||||
{}
|
||||
]
|
||||
},
|
||||
"depthStencilState": {}
|
||||
}
|
||||
],
|
||||
"_props": [
|
||||
{
|
||||
"mainTexture": {
|
||||
"__uuid__": "57d4c4ef-3199-4596-bf79-7c065964ca9c@291d4",
|
||||
"__expectedType__": "cc.Texture2D"
|
||||
},
|
||||
"albedoScale": {
|
||||
"__type__": "cc.Vec3",
|
||||
"x": 1,
|
||||
"y": 1,
|
||||
"z": 1
|
||||
},
|
||||
"metallic": 0.400000005960464,
|
||||
"roughness": 0.70710676908493
|
||||
}
|
||||
]
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
{
|
||||
"ver": "1.0.9",
|
||||
"importer": "material",
|
||||
"imported": true,
|
||||
"uuid": "bc711895-84b3-4729-85f8-978c46347d19",
|
||||
"files": [
|
||||
".json"
|
||||
],
|
||||
"subMetas": {},
|
||||
"userData": {}
|
||||
}
|
@ -0,0 +1,36 @@
|
||||
{
|
||||
"__type__": "cc.Material",
|
||||
"_name": "",
|
||||
"_objFlags": 0,
|
||||
"_native": "",
|
||||
"_effectAsset": {
|
||||
"__uuid__": "a3cd009f-0ab0-420d-9278-b9fdab939bbc",
|
||||
"__expectedType__": "cc.EffectAsset"
|
||||
},
|
||||
"_techIdx": 0,
|
||||
"_defines": [
|
||||
{
|
||||
"USE_INSTANCING": true,
|
||||
"USE_TEXTURE": true
|
||||
}
|
||||
],
|
||||
"_states": [
|
||||
{
|
||||
"rasterizerState": {},
|
||||
"depthStencilState": {},
|
||||
"blendState": {
|
||||
"targets": [
|
||||
{}
|
||||
]
|
||||
}
|
||||
}
|
||||
],
|
||||
"_props": [
|
||||
{
|
||||
"mainTexture": {
|
||||
"__uuid__": "e90ad74a-b668-4e2c-bf91-51a2a91b02aa@6c48a",
|
||||
"__expectedType__": "cc.Texture2D"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
{
|
||||
"ver": "1.0.9",
|
||||
"importer": "material",
|
||||
"imported": true,
|
||||
"uuid": "5cf1ff47-b589-490a-bc78-a88f743b9798",
|
||||
"files": [
|
||||
".json"
|
||||
],
|
||||
"subMetas": {},
|
||||
"userData": {}
|
||||
}
|
@ -72,7 +72,7 @@
|
||||
"userData": {
|
||||
"gltfIndex": 0,
|
||||
"wrapMode": 2,
|
||||
"sample": 60,
|
||||
"sample": 30,
|
||||
"span": {
|
||||
"from": 0.8,
|
||||
"to": 1.5
|
||||
@ -95,7 +95,7 @@
|
||||
"userData": {
|
||||
"gltfIndex": 0,
|
||||
"wrapMode": 2,
|
||||
"sample": 60,
|
||||
"sample": 30,
|
||||
"span": {
|
||||
"from": 1.5333333333333334,
|
||||
"to": 2.2
|
||||
@ -264,14 +264,12 @@
|
||||
"name": "run",
|
||||
"from": 0.8,
|
||||
"to": 1.5,
|
||||
"fps": 60,
|
||||
"wrapMode": 2
|
||||
},
|
||||
{
|
||||
"name": "attack",
|
||||
"from": 1.5333333333333334,
|
||||
"to": 2.2,
|
||||
"fps": 60,
|
||||
"wrapMode": 2
|
||||
},
|
||||
{
|
||||
|
12
examples/cocos-creator-multiplayer/frontend/assets/mat.meta
Normal file
12
examples/cocos-creator-multiplayer/frontend/assets/mat.meta
Normal file
@ -0,0 +1,12 @@
|
||||
{
|
||||
"ver": "1.1.0",
|
||||
"importer": "directory",
|
||||
"imported": true,
|
||||
"uuid": "e8e5dc6d-bdfe-4c40-8e74-4f36361cee55",
|
||||
"files": [],
|
||||
"subMetas": {},
|
||||
"userData": {
|
||||
"compressionType": {},
|
||||
"isRemoteBundle": {}
|
||||
}
|
||||
}
|
@ -0,0 +1,12 @@
|
||||
{
|
||||
"ver": "1.1.0",
|
||||
"importer": "directory",
|
||||
"imported": true,
|
||||
"uuid": "9aaf6024-7754-4b77-b5f5-7ca6d1ef973a",
|
||||
"files": [],
|
||||
"subMetas": {},
|
||||
"userData": {
|
||||
"compressionType": {},
|
||||
"isRemoteBundle": {}
|
||||
}
|
||||
}
|
Binary file not shown.
After Width: | Height: | Size: 175 KiB |
@ -0,0 +1,40 @@
|
||||
{
|
||||
"ver": "1.0.21",
|
||||
"importer": "image",
|
||||
"imported": true,
|
||||
"uuid": "ae68bc97-2fbf-4ff6-a6be-d9375f9a3423",
|
||||
"files": [
|
||||
".png",
|
||||
".json"
|
||||
],
|
||||
"subMetas": {
|
||||
"6c48a": {
|
||||
"importer": "texture",
|
||||
"uuid": "ae68bc97-2fbf-4ff6-a6be-d9375f9a3423@6c48a",
|
||||
"displayName": "grass",
|
||||
"id": "6c48a",
|
||||
"name": "texture",
|
||||
"userData": {
|
||||
"wrapModeS": "repeat",
|
||||
"wrapModeT": "repeat",
|
||||
"minfilter": "linear",
|
||||
"magfilter": "linear",
|
||||
"mipfilter": "none",
|
||||
"anisotropy": 0,
|
||||
"isUuid": true,
|
||||
"imageUuidOrDatabaseUri": "ae68bc97-2fbf-4ff6-a6be-d9375f9a3423"
|
||||
},
|
||||
"ver": "1.0.21",
|
||||
"imported": true,
|
||||
"files": [
|
||||
".json"
|
||||
],
|
||||
"subMetas": {}
|
||||
}
|
||||
},
|
||||
"userData": {
|
||||
"hasAlpha": false,
|
||||
"type": "texture",
|
||||
"redirect": "ae68bc97-2fbf-4ff6-a6be-d9375f9a3423@6c48a"
|
||||
}
|
||||
}
|
@ -0,0 +1,42 @@
|
||||
{
|
||||
"__type__": "cc.Material",
|
||||
"_name": "",
|
||||
"_objFlags": 0,
|
||||
"_native": "",
|
||||
"_effectAsset": {
|
||||
"__uuid__": "a3cd009f-0ab0-420d-9278-b9fdab939bbc",
|
||||
"__expectedType__": "cc.EffectAsset"
|
||||
},
|
||||
"_techIdx": 0,
|
||||
"_defines": [
|
||||
{
|
||||
"USE_TEXTURE": true
|
||||
}
|
||||
],
|
||||
"_states": [
|
||||
{
|
||||
"rasterizerState": {},
|
||||
"depthStencilState": {},
|
||||
"blendState": {
|
||||
"targets": [
|
||||
{}
|
||||
]
|
||||
}
|
||||
}
|
||||
],
|
||||
"_props": [
|
||||
{
|
||||
"mainTexture": {
|
||||
"__uuid__": "ae68bc97-2fbf-4ff6-a6be-d9375f9a3423@6c48a",
|
||||
"__expectedType__": "cc.Texture2D"
|
||||
},
|
||||
"tilingOffset": {
|
||||
"__type__": "cc.Vec4",
|
||||
"x": 100,
|
||||
"y": 100,
|
||||
"z": 0,
|
||||
"w": 0
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
{
|
||||
"ver": "1.0.9",
|
||||
"importer": "material",
|
||||
"imported": true,
|
||||
"uuid": "00f711c1-6f4c-4de3-bc9b-52888e03f3ac",
|
||||
"files": [
|
||||
".json"
|
||||
],
|
||||
"subMetas": {},
|
||||
"userData": {}
|
||||
}
|
@ -1,10 +1,8 @@
|
||||
import { _decorator, Component, Node, EventTouch, tween, Vec2, Vec3 } from 'cc';
|
||||
import { MathUtil } from '../../../scripts/models/MathUtil';
|
||||
import { Component, EventTouch, Node, Vec2, Vec3, _decorator } from 'cc';
|
||||
import { MathUtil } from '../../scripts/models/MathUtil';
|
||||
const { ccclass, property } = _decorator;
|
||||
|
||||
const v3_1 = new Vec3;
|
||||
const v3_2 = new Vec3;
|
||||
|
||||
export interface JoystickOptions {
|
||||
onOperate: (output: JoystickOutput) => void,
|
||||
onOperateEnd: () => void,
|
||||
@ -38,7 +36,6 @@ export class Joystick extends Component {
|
||||
this._options = v;
|
||||
}
|
||||
|
||||
|
||||
onLoad() {
|
||||
this.node.on(Node.EventType.TOUCH_START, this.onTouch, this);
|
||||
this.node.on(Node.EventType.TOUCH_MOVE, this.onTouch, this);
|
||||
@ -49,6 +46,10 @@ export class Joystick extends Component {
|
||||
|
||||
private _touchStartPos?: Vec2;
|
||||
onTouch(e: EventTouch) {
|
||||
if (!e.touch) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.disk.active = true;
|
||||
let loc = e.touch.getUILocation();
|
||||
|
||||
|
@ -0,0 +1,900 @@
|
||||
[
|
||||
{
|
||||
"__type__": "cc.Prefab",
|
||||
"_name": "",
|
||||
"_objFlags": 0,
|
||||
"_native": "",
|
||||
"data": {
|
||||
"__id__": 1
|
||||
},
|
||||
"optimizationPolicy": 0,
|
||||
"asyncLoadAssets": false
|
||||
},
|
||||
{
|
||||
"__type__": "cc.Node",
|
||||
"_name": "Player",
|
||||
"_objFlags": 0,
|
||||
"_parent": null,
|
||||
"_children": [
|
||||
{
|
||||
"__id__": 2
|
||||
}
|
||||
],
|
||||
"_active": true,
|
||||
"_components": [
|
||||
{
|
||||
"__id__": 31
|
||||
},
|
||||
{
|
||||
"__id__": 33
|
||||
}
|
||||
],
|
||||
"_prefab": {
|
||||
"__id__": 35
|
||||
},
|
||||
"_lpos": {
|
||||
"__type__": "cc.Vec3",
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"z": 0
|
||||
},
|
||||
"_lrot": {
|
||||
"__type__": "cc.Quat",
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"z": 0,
|
||||
"w": 1
|
||||
},
|
||||
"_lscale": {
|
||||
"__type__": "cc.Vec3",
|
||||
"x": 1,
|
||||
"y": 1,
|
||||
"z": 1
|
||||
},
|
||||
"_layer": 1073741824,
|
||||
"_euler": {
|
||||
"__type__": "cc.Vec3",
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"z": 0
|
||||
},
|
||||
"_id": ""
|
||||
},
|
||||
{
|
||||
"__type__": "cc.Node",
|
||||
"_name": "RootNode",
|
||||
"_objFlags": 0,
|
||||
"_parent": {
|
||||
"__id__": 1
|
||||
},
|
||||
"_children": [
|
||||
{
|
||||
"__id__": 3
|
||||
},
|
||||
{
|
||||
"__id__": 17
|
||||
},
|
||||
{
|
||||
"__id__": 19
|
||||
},
|
||||
{
|
||||
"__id__": 21
|
||||
},
|
||||
{
|
||||
"__id__": 26
|
||||
},
|
||||
{
|
||||
"__id__": 28
|
||||
}
|
||||
],
|
||||
"_active": true,
|
||||
"_components": [],
|
||||
"_prefab": {
|
||||
"__id__": 30
|
||||
},
|
||||
"_lpos": {
|
||||
"__type__": "cc.Vec3",
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"z": 0
|
||||
},
|
||||
"_lrot": {
|
||||
"__type__": "cc.Quat",
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"z": 0,
|
||||
"w": 1
|
||||
},
|
||||
"_lscale": {
|
||||
"__type__": "cc.Vec3",
|
||||
"x": 1,
|
||||
"y": 1,
|
||||
"z": 1
|
||||
},
|
||||
"_layer": 1073741824,
|
||||
"_euler": {
|
||||
"__type__": "cc.Vec3",
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"z": 0
|
||||
},
|
||||
"_id": ""
|
||||
},
|
||||
{
|
||||
"__type__": "cc.Node",
|
||||
"_name": "Dummy01",
|
||||
"_objFlags": 0,
|
||||
"_parent": {
|
||||
"__id__": 2
|
||||
},
|
||||
"_children": [
|
||||
{
|
||||
"__id__": 4
|
||||
},
|
||||
{
|
||||
"__id__": 8
|
||||
},
|
||||
{
|
||||
"__id__": 10
|
||||
},
|
||||
{
|
||||
"__id__": 12
|
||||
},
|
||||
{
|
||||
"__id__": 14
|
||||
}
|
||||
],
|
||||
"_active": true,
|
||||
"_components": [],
|
||||
"_prefab": {
|
||||
"__id__": 16
|
||||
},
|
||||
"_lpos": {
|
||||
"__type__": "cc.Vec3",
|
||||
"x": 0,
|
||||
"y": 4.31247441140831e-32,
|
||||
"z": 2.27106511374586e-9
|
||||
},
|
||||
"_lrot": {
|
||||
"__type__": "cc.Quat",
|
||||
"x": 8.146034247147302e-8,
|
||||
"y": 0,
|
||||
"z": 0,
|
||||
"w": 0.9999999999999967
|
||||
},
|
||||
"_lscale": {
|
||||
"__type__": "cc.Vec3",
|
||||
"x": 2.53999996185303,
|
||||
"y": 2.53999996185303,
|
||||
"z": 2.53999996185303
|
||||
},
|
||||
"_layer": 1073741824,
|
||||
"_euler": {
|
||||
"__type__": "cc.Vec3",
|
||||
"x": 0.000009334667642611398,
|
||||
"y": 0,
|
||||
"z": 0
|
||||
},
|
||||
"_id": ""
|
||||
},
|
||||
{
|
||||
"__type__": "cc.Node",
|
||||
"_name": "Body",
|
||||
"_objFlags": 0,
|
||||
"_parent": {
|
||||
"__id__": 3
|
||||
},
|
||||
"_children": [
|
||||
{
|
||||
"__id__": 5
|
||||
}
|
||||
],
|
||||
"_active": true,
|
||||
"_components": [],
|
||||
"_prefab": {
|
||||
"__id__": 7
|
||||
},
|
||||
"_lpos": {
|
||||
"__type__": "cc.Vec3",
|
||||
"x": -0.000466376630356535,
|
||||
"y": 0.0555356666445732,
|
||||
"z": -4.76837147544984e-9
|
||||
},
|
||||
"_lrot": {
|
||||
"__type__": "cc.Quat",
|
||||
"x": 0.0000013147252531426701,
|
||||
"y": 5.898311123805427e-7,
|
||||
"z": 0.7037748466382776,
|
||||
"w": 0.7104230888964633
|
||||
},
|
||||
"_lscale": {
|
||||
"__type__": "cc.Vec3",
|
||||
"x": 0.256809949874878,
|
||||
"y": 0.439815044403076,
|
||||
"z": 0.0870304778218269
|
||||
},
|
||||
"_layer": 1073741824,
|
||||
"_euler": {
|
||||
"__type__": "cc.Vec3",
|
||||
"x": 0.006324434041980695,
|
||||
"y": -0.006170109051330866,
|
||||
"z": 89.46130112452344
|
||||
},
|
||||
"_id": ""
|
||||
},
|
||||
{
|
||||
"__type__": "cc.Node",
|
||||
"_name": "head",
|
||||
"_objFlags": 0,
|
||||
"_parent": {
|
||||
"__id__": 4
|
||||
},
|
||||
"_children": [],
|
||||
"_active": true,
|
||||
"_components": [],
|
||||
"_prefab": {
|
||||
"__id__": 6
|
||||
},
|
||||
"_lpos": {
|
||||
"__type__": "cc.Vec3",
|
||||
"x": 0.931041061878204,
|
||||
"y": -1.62124635494365e-7,
|
||||
"z": 1.28416282052513e-8
|
||||
},
|
||||
"_lrot": {
|
||||
"__type__": "cc.Quat",
|
||||
"x": -0.000007869318285142453,
|
||||
"y": -2.023334521019378e-7,
|
||||
"z": -0.001340885290760051,
|
||||
"w": 0.9999991009819308
|
||||
},
|
||||
"_lscale": {
|
||||
"__type__": "cc.Vec3",
|
||||
"x": 1.24272096157074,
|
||||
"y": 1.03568971157074,
|
||||
"z": 1.0696634054184
|
||||
},
|
||||
"_layer": 1073741824,
|
||||
"_euler": {
|
||||
"__type__": "cc.Vec3",
|
||||
"x": -0.0009017909722726095,
|
||||
"y": -0.00002439492589956044,
|
||||
"z": -0.15365418180060705
|
||||
},
|
||||
"_id": ""
|
||||
},
|
||||
{
|
||||
"__type__": "cc.PrefabInfo",
|
||||
"root": {
|
||||
"__id__": 1
|
||||
},
|
||||
"asset": {
|
||||
"__id__": 0
|
||||
},
|
||||
"fileId": "1etT/vqTVXbIC6bSTTJON5"
|
||||
},
|
||||
{
|
||||
"__type__": "cc.PrefabInfo",
|
||||
"root": {
|
||||
"__id__": 1
|
||||
},
|
||||
"asset": {
|
||||
"__id__": 0
|
||||
},
|
||||
"fileId": "38UefSlhhbc7fGntsIPZh6"
|
||||
},
|
||||
{
|
||||
"__type__": "cc.Node",
|
||||
"_name": "legRight",
|
||||
"_objFlags": 0,
|
||||
"_parent": {
|
||||
"__id__": 3
|
||||
},
|
||||
"_children": [],
|
||||
"_active": true,
|
||||
"_components": [],
|
||||
"_prefab": {
|
||||
"__id__": 9
|
||||
},
|
||||
"_lpos": {
|
||||
"__type__": "cc.Vec3",
|
||||
"x": -0.15381583571434,
|
||||
"y": 0.0330642610788345,
|
||||
"z": -4.76837147544984e-9
|
||||
},
|
||||
"_lrot": {
|
||||
"__type__": "cc.Quat",
|
||||
"x": 0.6775014926325843,
|
||||
"y": 0.20089959890094192,
|
||||
"z": 0.6787423421146606,
|
||||
"w": -0.19984972269874676
|
||||
},
|
||||
"_lscale": {
|
||||
"__type__": "cc.Vec3",
|
||||
"x": 0.184104666113853,
|
||||
"y": 0.347824722528458,
|
||||
"z": 0.0710852295160294
|
||||
},
|
||||
"_layer": 1073741824,
|
||||
"_euler": {
|
||||
"__type__": "cc.Vec3",
|
||||
"x": -147.07673505109858,
|
||||
"y": -90.12052935501679,
|
||||
"z": 0.05309133906220757
|
||||
},
|
||||
"_id": ""
|
||||
},
|
||||
{
|
||||
"__type__": "cc.PrefabInfo",
|
||||
"root": {
|
||||
"__id__": 1
|
||||
},
|
||||
"asset": {
|
||||
"__id__": 0
|
||||
},
|
||||
"fileId": "a7AVcLwkBZ46dzYAYb4QPx"
|
||||
},
|
||||
{
|
||||
"__type__": "cc.Node",
|
||||
"_name": "legLeft",
|
||||
"_objFlags": 0,
|
||||
"_parent": {
|
||||
"__id__": 3
|
||||
},
|
||||
"_children": [],
|
||||
"_active": true,
|
||||
"_components": [],
|
||||
"_prefab": {
|
||||
"__id__": 11
|
||||
},
|
||||
"_lpos": {
|
||||
"__type__": "cc.Vec3",
|
||||
"x": 0.150058135390282,
|
||||
"y": 0.0330642610788345,
|
||||
"z": -1.43051144263495e-8
|
||||
},
|
||||
"_lrot": {
|
||||
"__type__": "cc.Quat",
|
||||
"x": 0.6356643535110694,
|
||||
"y": 0.3106639432517853,
|
||||
"z": 0.635291228429095,
|
||||
"w": -0.3095541941561399
|
||||
},
|
||||
"_lscale": {
|
||||
"__type__": "cc.Vec3",
|
||||
"x": 0.184104397892952,
|
||||
"y": 0.347825288772583,
|
||||
"z": 0.0710852593183517
|
||||
},
|
||||
"_layer": 1073741824,
|
||||
"_euler": {
|
||||
"__type__": "cc.Vec3",
|
||||
"x": -127.97583425594252,
|
||||
"y": -90.01226481486562,
|
||||
"z": 0.09407173384696697
|
||||
},
|
||||
"_id": ""
|
||||
},
|
||||
{
|
||||
"__type__": "cc.PrefabInfo",
|
||||
"root": {
|
||||
"__id__": 1
|
||||
},
|
||||
"asset": {
|
||||
"__id__": 0
|
||||
},
|
||||
"fileId": "6egLmgEjJSxb7mZpFf7FSD"
|
||||
},
|
||||
{
|
||||
"__type__": "cc.Node",
|
||||
"_name": "handRight",
|
||||
"_objFlags": 0,
|
||||
"_parent": {
|
||||
"__id__": 3
|
||||
},
|
||||
"_children": [],
|
||||
"_active": true,
|
||||
"_components": [],
|
||||
"_prefab": {
|
||||
"__id__": 13
|
||||
},
|
||||
"_lpos": {
|
||||
"__type__": "cc.Vec3",
|
||||
"x": -0.204364582896233,
|
||||
"y": 0.240019470453262,
|
||||
"z": -1.90734859017994e-8
|
||||
},
|
||||
"_lrot": {
|
||||
"__type__": "cc.Quat",
|
||||
"x": -0.00043949465228992625,
|
||||
"y": -0.00002823252593632647,
|
||||
"z": 0.9849262411574669,
|
||||
"w": -0.17297429151986207
|
||||
},
|
||||
"_lscale": {
|
||||
"__type__": "cc.Vec3",
|
||||
"x": 0.184104412794113,
|
||||
"y": 0.347825288772583,
|
||||
"z": 0.07108523696661
|
||||
},
|
||||
"_layer": 1073741824,
|
||||
"_euler": {
|
||||
"__type__": "cc.Vec3",
|
||||
"x": 179.9873448759303,
|
||||
"y": 179.94664434517173,
|
||||
"z": -19.921588202819525
|
||||
},
|
||||
"_id": ""
|
||||
},
|
||||
{
|
||||
"__type__": "cc.PrefabInfo",
|
||||
"root": {
|
||||
"__id__": 1
|
||||
},
|
||||
"asset": {
|
||||
"__id__": 0
|
||||
},
|
||||
"fileId": "50DRmSLnFemalb9mhuT9XN"
|
||||
},
|
||||
{
|
||||
"__type__": "cc.Node",
|
||||
"_name": "handLeft",
|
||||
"_objFlags": 0,
|
||||
"_parent": {
|
||||
"__id__": 3
|
||||
},
|
||||
"_children": [],
|
||||
"_active": true,
|
||||
"_components": [],
|
||||
"_prefab": {
|
||||
"__id__": 15
|
||||
},
|
||||
"_lpos": {
|
||||
"__type__": "cc.Vec3",
|
||||
"x": 0.203091412782669,
|
||||
"y": 0.240019470453262,
|
||||
"z": -1.90734859017994e-8
|
||||
},
|
||||
"_lrot": {
|
||||
"__type__": "cc.Quat",
|
||||
"x": -0.00001006337055508986,
|
||||
"y": -0.0003337875805372209,
|
||||
"z": -0.17397424484232848,
|
||||
"w": 0.9847501462889564
|
||||
},
|
||||
"_lscale": {
|
||||
"__type__": "cc.Vec3",
|
||||
"x": 0.184104338288307,
|
||||
"y": 0.347825139760971,
|
||||
"z": 0.0710852667689323
|
||||
},
|
||||
"_layer": 1073741824,
|
||||
"_euler": {
|
||||
"__type__": "cc.Vec3",
|
||||
"x": -0.008291917560534557,
|
||||
"y": -0.04030648567970078,
|
||||
"z": -20.037940451355507
|
||||
},
|
||||
"_id": ""
|
||||
},
|
||||
{
|
||||
"__type__": "cc.PrefabInfo",
|
||||
"root": {
|
||||
"__id__": 1
|
||||
},
|
||||
"asset": {
|
||||
"__id__": 0
|
||||
},
|
||||
"fileId": "5eMcps3V1RoqefFsSsm8Sx"
|
||||
},
|
||||
{
|
||||
"__type__": "cc.PrefabInfo",
|
||||
"root": {
|
||||
"__id__": 1
|
||||
},
|
||||
"asset": {
|
||||
"__id__": 0
|
||||
},
|
||||
"fileId": "e14q0XOvhSf7Wwpr+JP8WX"
|
||||
},
|
||||
{
|
||||
"__type__": "cc.Node",
|
||||
"_name": "Bip001",
|
||||
"_objFlags": 0,
|
||||
"_parent": {
|
||||
"__id__": 2
|
||||
},
|
||||
"_children": [],
|
||||
"_active": true,
|
||||
"_components": [],
|
||||
"_prefab": {
|
||||
"__id__": 18
|
||||
},
|
||||
"_lpos": {
|
||||
"__type__": "cc.Vec3",
|
||||
"x": -2.95868706703186,
|
||||
"y": 0.568015873432159,
|
||||
"z": 2.59012746810913
|
||||
},
|
||||
"_lrot": {
|
||||
"__type__": "cc.Quat",
|
||||
"x": -0.5000003129242964,
|
||||
"y": -0.49999968707550774,
|
||||
"z": -0.49999968707550774,
|
||||
"w": 0.5000003129242964
|
||||
},
|
||||
"_lscale": {
|
||||
"__type__": "cc.Vec3",
|
||||
"x": 6.45159912109375,
|
||||
"y": 6.45159912109375,
|
||||
"z": 6.45160007476807
|
||||
},
|
||||
"_layer": 1073741824,
|
||||
"_euler": {
|
||||
"__type__": "cc.Vec3",
|
||||
"x": -90,
|
||||
"y": -89.99992828301158,
|
||||
"z": 0
|
||||
},
|
||||
"_id": ""
|
||||
},
|
||||
{
|
||||
"__type__": "cc.PrefabInfo",
|
||||
"root": {
|
||||
"__id__": 1
|
||||
},
|
||||
"asset": {
|
||||
"__id__": 0
|
||||
},
|
||||
"fileId": "72wx+9XH9fS5Jsw9lb3u/+"
|
||||
},
|
||||
{
|
||||
"__type__": "cc.Node",
|
||||
"_name": "mixamorig:HeadTop_End",
|
||||
"_objFlags": 0,
|
||||
"_parent": {
|
||||
"__id__": 2
|
||||
},
|
||||
"_children": [],
|
||||
"_active": true,
|
||||
"_components": [],
|
||||
"_prefab": {
|
||||
"__id__": 20
|
||||
},
|
||||
"_lpos": {
|
||||
"__type__": "cc.Vec3",
|
||||
"x": -12.6684627532959,
|
||||
"y": 2.27624535560608,
|
||||
"z": -0.396418631076813
|
||||
},
|
||||
"_lrot": {
|
||||
"__type__": "cc.Quat",
|
||||
"x": 0.07992084217915124,
|
||||
"y": 0.35555240038341984,
|
||||
"z": 0.03850968875854815,
|
||||
"w": 0.9304365391786178
|
||||
},
|
||||
"_lscale": {
|
||||
"__type__": "cc.Vec3",
|
||||
"x": 65.5876159667969,
|
||||
"y": 65.5876617431641,
|
||||
"z": 65.587646484375
|
||||
},
|
||||
"_layer": 1073741824,
|
||||
"_euler": {
|
||||
"__type__": "cc.Vec3",
|
||||
"x": 7.027884698082062,
|
||||
"y": 41.37325087834414,
|
||||
"z": 7.382559841159056
|
||||
},
|
||||
"_id": ""
|
||||
},
|
||||
{
|
||||
"__type__": "cc.PrefabInfo",
|
||||
"root": {
|
||||
"__id__": 1
|
||||
},
|
||||
"asset": {
|
||||
"__id__": 0
|
||||
},
|
||||
"fileId": "758sU4GMNYEaDn4WLPV8VV"
|
||||
},
|
||||
{
|
||||
"__type__": "cc.Node",
|
||||
"_name": "soldier01",
|
||||
"_objFlags": 0,
|
||||
"_parent": {
|
||||
"__id__": 2
|
||||
},
|
||||
"_children": [],
|
||||
"_active": true,
|
||||
"_components": [
|
||||
{
|
||||
"__id__": 22
|
||||
}
|
||||
],
|
||||
"_prefab": {
|
||||
"__id__": 25
|
||||
},
|
||||
"_lpos": {
|
||||
"__type__": "cc.Vec3",
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"z": 0
|
||||
},
|
||||
"_lrot": {
|
||||
"__type__": "cc.Quat",
|
||||
"x": -0.7071067811865476,
|
||||
"y": 0,
|
||||
"z": 0,
|
||||
"w": 0.7071067811865476
|
||||
},
|
||||
"_lscale": {
|
||||
"__type__": "cc.Vec3",
|
||||
"x": 2.53999996185303,
|
||||
"y": 2.53999996185303,
|
||||
"z": 2.53999996185303
|
||||
},
|
||||
"_layer": 1073741824,
|
||||
"_euler": {
|
||||
"__type__": "cc.Vec3",
|
||||
"x": -90.00000000000003,
|
||||
"y": 0,
|
||||
"z": 0
|
||||
},
|
||||
"_id": ""
|
||||
},
|
||||
{
|
||||
"__type__": "cc.SkinnedMeshRenderer",
|
||||
"_name": "",
|
||||
"_objFlags": 0,
|
||||
"node": {
|
||||
"__id__": 21
|
||||
},
|
||||
"_enabled": true,
|
||||
"__prefab": {
|
||||
"__id__": 23
|
||||
},
|
||||
"_materials": [
|
||||
{
|
||||
"__uuid__": "5cf1ff47-b589-490a-bc78-a88f743b9798",
|
||||
"__expectedType__": "cc.Material"
|
||||
}
|
||||
],
|
||||
"_visFlags": 0,
|
||||
"lightmapSettings": {
|
||||
"__id__": 24
|
||||
},
|
||||
"_mesh": {
|
||||
"__uuid__": "57d4c4ef-3199-4596-bf79-7c065964ca9c@6868c",
|
||||
"__expectedType__": "cc.Mesh"
|
||||
},
|
||||
"_shadowCastingMode": 0,
|
||||
"_shadowReceivingMode": 1,
|
||||
"_enableMorph": true,
|
||||
"_skeleton": {
|
||||
"__uuid__": "57d4c4ef-3199-4596-bf79-7c065964ca9c@438fe",
|
||||
"__expectedType__": "cc.Skeleton"
|
||||
},
|
||||
"_skinningRoot": {
|
||||
"__id__": 1
|
||||
},
|
||||
"_id": ""
|
||||
},
|
||||
{
|
||||
"__type__": "cc.CompPrefabInfo",
|
||||
"fileId": "01bZIFKkBZQ5BDP5OTFTyW"
|
||||
},
|
||||
{
|
||||
"__type__": "cc.ModelLightmapSettings",
|
||||
"texture": null,
|
||||
"uvParam": {
|
||||
"__type__": "cc.Vec4",
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"z": 0,
|
||||
"w": 0
|
||||
},
|
||||
"_bakeable": false,
|
||||
"_castShadow": false,
|
||||
"_receiveShadow": false,
|
||||
"_recieveShadow": false,
|
||||
"_lightmapSize": 64
|
||||
},
|
||||
{
|
||||
"__type__": "cc.PrefabInfo",
|
||||
"root": {
|
||||
"__id__": 1
|
||||
},
|
||||
"asset": {
|
||||
"__id__": 0
|
||||
},
|
||||
"fileId": "61gKhO2zhY0LoTCP8qRD7M"
|
||||
},
|
||||
{
|
||||
"__type__": "cc.Node",
|
||||
"_name": "Bip001(__autogen 4)",
|
||||
"_objFlags": 0,
|
||||
"_parent": {
|
||||
"__id__": 2
|
||||
},
|
||||
"_children": [],
|
||||
"_active": true,
|
||||
"_components": [],
|
||||
"_prefab": {
|
||||
"__id__": 27
|
||||
},
|
||||
"_lpos": {
|
||||
"__type__": "cc.Vec3",
|
||||
"x": 9.61940002441406,
|
||||
"y": 0.568015873432159,
|
||||
"z": 1.51320099830627
|
||||
},
|
||||
"_lrot": {
|
||||
"__type__": "cc.Quat",
|
||||
"x": -0.5000003129242964,
|
||||
"y": -0.49999968707550774,
|
||||
"z": -0.49999968707550774,
|
||||
"w": 0.5000003129242964
|
||||
},
|
||||
"_lscale": {
|
||||
"__type__": "cc.Vec3",
|
||||
"x": 6.45159912109375,
|
||||
"y": 6.45159912109375,
|
||||
"z": 6.45160007476807
|
||||
},
|
||||
"_layer": 1073741824,
|
||||
"_euler": {
|
||||
"__type__": "cc.Vec3",
|
||||
"x": -90,
|
||||
"y": -89.99992828301158,
|
||||
"z": 0
|
||||
},
|
||||
"_id": ""
|
||||
},
|
||||
{
|
||||
"__type__": "cc.PrefabInfo",
|
||||
"root": {
|
||||
"__id__": 1
|
||||
},
|
||||
"asset": {
|
||||
"__id__": 0
|
||||
},
|
||||
"fileId": "ceW5W7cCxbcIDrr7BHLBqe"
|
||||
},
|
||||
{
|
||||
"__type__": "cc.Node",
|
||||
"_name": "mixamorig:HeadTop_End(__autogen 5)",
|
||||
"_objFlags": 0,
|
||||
"_parent": {
|
||||
"__id__": 2
|
||||
},
|
||||
"_children": [],
|
||||
"_active": true,
|
||||
"_components": [],
|
||||
"_prefab": {
|
||||
"__id__": 29
|
||||
},
|
||||
"_lpos": {
|
||||
"__type__": "cc.Vec3",
|
||||
"x": -0.0903754904866219,
|
||||
"y": 2.27624559402466,
|
||||
"z": -1.47334516048431
|
||||
},
|
||||
"_lrot": {
|
||||
"__type__": "cc.Quat",
|
||||
"x": 0.07992084217915124,
|
||||
"y": 0.35555240038341984,
|
||||
"z": 0.03850968875854815,
|
||||
"w": 0.9304365391786178
|
||||
},
|
||||
"_lscale": {
|
||||
"__type__": "cc.Vec3",
|
||||
"x": 65.5876159667969,
|
||||
"y": 65.5876617431641,
|
||||
"z": 65.587646484375
|
||||
},
|
||||
"_layer": 1073741824,
|
||||
"_euler": {
|
||||
"__type__": "cc.Vec3",
|
||||
"x": 7.027884698082062,
|
||||
"y": 41.37325087834414,
|
||||
"z": 7.382559841159056
|
||||
},
|
||||
"_id": ""
|
||||
},
|
||||
{
|
||||
"__type__": "cc.PrefabInfo",
|
||||
"root": {
|
||||
"__id__": 1
|
||||
},
|
||||
"asset": {
|
||||
"__id__": 0
|
||||
},
|
||||
"fileId": "9evQBDrbhSio1m7RjvuLjN"
|
||||
},
|
||||
{
|
||||
"__type__": "cc.PrefabInfo",
|
||||
"root": {
|
||||
"__id__": 1
|
||||
},
|
||||
"asset": {
|
||||
"__id__": 0
|
||||
},
|
||||
"fileId": "30u7fnOj9WDp8SK/8khE/U"
|
||||
},
|
||||
{
|
||||
"__type__": "cc.SkeletalAnimation",
|
||||
"_name": "",
|
||||
"_objFlags": 0,
|
||||
"node": {
|
||||
"__id__": 1
|
||||
},
|
||||
"_enabled": true,
|
||||
"__prefab": {
|
||||
"__id__": 32
|
||||
},
|
||||
"playOnLoad": false,
|
||||
"_clips": [
|
||||
{
|
||||
"__uuid__": "57d4c4ef-3199-4596-bf79-7c065964ca9c@1f586",
|
||||
"__expectedType__": "cc.AnimationClip"
|
||||
},
|
||||
{
|
||||
"__uuid__": "57d4c4ef-3199-4596-bf79-7c065964ca9c@cf5ee",
|
||||
"__expectedType__": "cc.AnimationClip"
|
||||
},
|
||||
{
|
||||
"__uuid__": "57d4c4ef-3199-4596-bf79-7c065964ca9c@989ed",
|
||||
"__expectedType__": "cc.AnimationClip"
|
||||
},
|
||||
{
|
||||
"__uuid__": "57d4c4ef-3199-4596-bf79-7c065964ca9c@ee525",
|
||||
"__expectedType__": "cc.AnimationClip"
|
||||
},
|
||||
{
|
||||
"__uuid__": "57d4c4ef-3199-4596-bf79-7c065964ca9c@5b2e9",
|
||||
"__expectedType__": "cc.AnimationClip"
|
||||
}
|
||||
],
|
||||
"_defaultClip": {
|
||||
"__uuid__": "57d4c4ef-3199-4596-bf79-7c065964ca9c@1f586",
|
||||
"__expectedType__": "cc.AnimationClip"
|
||||
},
|
||||
"_useBakedAnimation": false,
|
||||
"_sockets": [],
|
||||
"_id": ""
|
||||
},
|
||||
{
|
||||
"__type__": "cc.CompPrefabInfo",
|
||||
"fileId": "71bamidCpRLIBqyoKSaXUX"
|
||||
},
|
||||
{
|
||||
"__type__": "720b7a4EnZJjYpzLWJrmvT/",
|
||||
"_name": "",
|
||||
"_objFlags": 0,
|
||||
"__editorExtras__": {},
|
||||
"node": {
|
||||
"__id__": 1
|
||||
},
|
||||
"_enabled": true,
|
||||
"__prefab": {
|
||||
"__id__": 34
|
||||
},
|
||||
"_id": ""
|
||||
},
|
||||
{
|
||||
"__type__": "cc.CompPrefabInfo",
|
||||
"fileId": "fczHMULW9AAIJRjvl2FJiZ"
|
||||
},
|
||||
{
|
||||
"__type__": "cc.PrefabInfo",
|
||||
"root": {
|
||||
"__id__": 1
|
||||
},
|
||||
"asset": {
|
||||
"__id__": 0
|
||||
},
|
||||
"fileId": "71qfN53ihYmaSuBoR11P0t"
|
||||
}
|
||||
]
|
@ -0,0 +1,13 @@
|
||||
{
|
||||
"ver": "1.1.32",
|
||||
"importer": "prefab",
|
||||
"imported": true,
|
||||
"uuid": "28c95a70-5b80-4b72-8f7b-93e2cefacc98",
|
||||
"files": [
|
||||
".json"
|
||||
],
|
||||
"subMetas": {},
|
||||
"userData": {
|
||||
"syncNodeName": "Player"
|
||||
}
|
||||
}
|
@ -0,0 +1,22 @@
|
||||
|
||||
import { Component, _decorator } from 'cc';
|
||||
import { PlayerState } from '../../scripts/shared/game/state/PlayerState';
|
||||
const { ccclass, property } = _decorator;
|
||||
|
||||
@ccclass('Player')
|
||||
export class Player extends Component {
|
||||
|
||||
playerId!: number;
|
||||
isSelf = false;
|
||||
|
||||
init(state: PlayerState) {
|
||||
this.playerId = state.id;
|
||||
this.setPos(state.pos);
|
||||
}
|
||||
|
||||
// 把 GameSystem 空间映射到游戏空间
|
||||
setPos(pos: { x: number, y: number }) {
|
||||
this.node.setPosition(pos.y, 0, pos.x);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,9 @@
|
||||
{
|
||||
"ver": "4.0.22",
|
||||
"importer": "typescript",
|
||||
"imported": true,
|
||||
"uuid": "720b76b8-1276-498d-8a73-2d626b9af4ff",
|
||||
"files": [],
|
||||
"subMetas": {},
|
||||
"userData": {}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,115 @@
|
||||
|
||||
import { Component, instantiate, Node, Prefab, Vec2, _decorator } from 'cc';
|
||||
import { WsClient } from 'tsrpc-browser';
|
||||
import { Joystick } from '../../prefabs/Joystick/Joystick';
|
||||
import { Player } from '../../prefabs/Player/Player';
|
||||
import { FollowCamera } from '../../scripts/components/FollowCamera';
|
||||
import { GameManager } from '../../scripts/models/GameManager';
|
||||
import { gameConfig } from '../../scripts/shared/game/gameConfig';
|
||||
import { serviceProto, ServiceType } from '../../scripts/shared/protocols/serviceProto';
|
||||
const { ccclass, property } = _decorator;
|
||||
|
||||
/**
|
||||
* Predefined variables
|
||||
* Name = GameScene
|
||||
* DateTime = Thu Dec 02 2021 18:43:36 GMT+0800 (中国标准时间)
|
||||
* Author = k8w
|
||||
* FileBasename = GameScene.ts
|
||||
* FileBasenameNoExtension = GameScene
|
||||
* URL = db://assets/scenes/GameScene/GameScene.ts
|
||||
* ManualUrl = https://docs.cocos.com/creator/3.3/manual/zh/
|
||||
*
|
||||
*/
|
||||
|
||||
@ccclass('GameScene')
|
||||
export class GameScene extends Component {
|
||||
|
||||
@property(Joystick)
|
||||
joyStick!: Joystick;
|
||||
|
||||
@property(Prefab)
|
||||
prefabPlayer!: Prefab;
|
||||
|
||||
@property(Node)
|
||||
players!: Node;
|
||||
|
||||
@property(FollowCamera)
|
||||
camera: FollowCamera = null as any;
|
||||
|
||||
client!: WsClient<ServiceType>;
|
||||
gameManager!: GameManager;
|
||||
|
||||
private _playerInstances: { [playerId: number]: Player } = {};
|
||||
private _selfSpeed?: Vec2 = new Vec2(0, 0);
|
||||
|
||||
onLoad() {
|
||||
(window as any).game = this;
|
||||
|
||||
this.joyStick.options = {
|
||||
onOperate: v => {
|
||||
if (!this._selfSpeed) {
|
||||
this._selfSpeed = new Vec2;
|
||||
}
|
||||
this._selfSpeed.set(v.x, v.y);
|
||||
},
|
||||
onOperateEnd: () => {
|
||||
this._selfSpeed = undefined;
|
||||
}
|
||||
}
|
||||
|
||||
this.client = new WsClient(serviceProto, {
|
||||
server: 'ws://127.0.0.1:3000',
|
||||
logger: console
|
||||
});
|
||||
this.client.flows.postDisconnectFlow.push(v => {
|
||||
location.reload()
|
||||
return v;
|
||||
})
|
||||
this.gameManager = new GameManager(this.client);
|
||||
|
||||
this.gameManager.join();
|
||||
}
|
||||
|
||||
update(dt: number) {
|
||||
// Send Inputs
|
||||
if (this._selfSpeed && this._selfSpeed.lengthSqr()) {
|
||||
this._selfSpeed.normalize().multiplyScalar(gameConfig.moveSpeed);
|
||||
this.gameManager.sendClientInput({
|
||||
type: 'PlayerMove',
|
||||
speed: {
|
||||
x: this._selfSpeed.x,
|
||||
y: this._selfSpeed.y
|
||||
},
|
||||
dt: dt
|
||||
})
|
||||
}
|
||||
|
||||
let gameState = this.gameManager.state;
|
||||
|
||||
// console.log('update', gameState.players.length)
|
||||
|
||||
// Update pos
|
||||
for (let playerState of gameState.players) {
|
||||
let player: Player = this._playerInstances[playerState.id];
|
||||
if (!player) {
|
||||
let node = instantiate(this.prefabPlayer);
|
||||
this.players.addChild(node);
|
||||
player = node.getComponent(Player)!;
|
||||
player.init(playerState);
|
||||
|
||||
if (playerState.id === this.gameManager.selfPlayerId) {
|
||||
this.camera.focusTarget = node;
|
||||
}
|
||||
|
||||
this._playerInstances[playerState.id] = player;
|
||||
}
|
||||
else {
|
||||
// console.log('setPos', playerState.id, playerState.pos.x, playerState.pos.y)
|
||||
player.setPos(playerState.pos);
|
||||
}
|
||||
}
|
||||
|
||||
// Clear left players
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,9 @@
|
||||
{
|
||||
"ver": "4.0.22",
|
||||
"importer": "typescript",
|
||||
"imported": true,
|
||||
"uuid": "d472870e-cf19-4a1c-b32e-e57838f14f14",
|
||||
"files": [],
|
||||
"subMetas": {},
|
||||
"userData": {}
|
||||
}
|
@ -1,101 +0,0 @@
|
||||
import { WsClient } from 'tsrpc-browser';
|
||||
import { MsgInput } from './shared/protocols/clientMsgs/MsgInput';
|
||||
import { MsgFrame } from './shared/protocols/serverMsgs/MsgFrame';
|
||||
import { ServiceType } from "./shared/protocols/serviceProto";
|
||||
import { applyPlayerInput, PlayerInput, PlayerState } from "./shared/states/Player";
|
||||
import { RoomState } from './shared/states/RoomState';
|
||||
|
||||
/**
|
||||
* 客户端 - 房间 - 逻辑系统
|
||||
*/
|
||||
export class Room {
|
||||
|
||||
state: RoomState = {
|
||||
players: []
|
||||
}
|
||||
|
||||
client: WsClient<ServiceType>;
|
||||
|
||||
self?: {
|
||||
uid: number,
|
||||
// 最后一次权威状态
|
||||
lastServerState: PlayerState
|
||||
}
|
||||
private _lastSendInputSN = 0;
|
||||
private _sendingMsgs: MsgInput[] = [];
|
||||
|
||||
constructor(client: WsClient<ServiceType>) {
|
||||
this.client = client;
|
||||
this.client.listenMsg('serverMsgs/Frame', msg => {
|
||||
this.applyServerFrame(msg);
|
||||
});
|
||||
this.client.listenMsg('serverMsgs/Join', msg => {
|
||||
this.state.players.push(msg.player);
|
||||
});
|
||||
this.client.listenMsg('serverMsgs/Leave', msg => {
|
||||
this.state.players.removeOne(v => v.uid === msg.uid);
|
||||
});
|
||||
}
|
||||
|
||||
init(roomState: RoomState) {
|
||||
|
||||
}
|
||||
|
||||
/** 同步服务端的权威消息 */
|
||||
applyServerFrame(msg: MsgFrame) {
|
||||
msg.inputs.forEach(({ uid, msgInput }) => {
|
||||
let playerIndex = this.state.players.findIndex(v => v.uid === uid);
|
||||
if (playerIndex === -1) {
|
||||
return;
|
||||
}
|
||||
let newPlayer: PlayerState = this.state.players[playerIndex];
|
||||
|
||||
// 自己:和解
|
||||
if (uid === this.self?.uid) {
|
||||
this._sendingMsgs.remove(v => v.sn <= msgInput.sn);
|
||||
this.state.players[playerIndex] = this.self.lastServerState;
|
||||
// 预测
|
||||
this._sendingMsgs.forEach(v => {
|
||||
this.state.players[playerIndex] = applyPlayerInput(this.state.players[playerIndex], v);
|
||||
})
|
||||
}
|
||||
// 其它人:直接同步
|
||||
else {
|
||||
this.state.players[playerIndex] = applyPlayerInput(this.state.players[playerIndex], msgInput);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/** 发送客户端输入,并执行本地预测 */
|
||||
sendInput(input: PlayerInput) {
|
||||
if (!this.self) {
|
||||
return;
|
||||
}
|
||||
|
||||
let msg: MsgInput = {
|
||||
...input,
|
||||
sn: ++this._lastSendInputSN
|
||||
}
|
||||
this._sendingMsgs.push(msg);
|
||||
this.client.sendMsg('clientMsgs/Input', msg);
|
||||
}
|
||||
|
||||
async joinRoom() {
|
||||
let ret = await this.client.callApi('JoinRoom', {
|
||||
nickname: 'xxx',
|
||||
skinId: 1
|
||||
});
|
||||
|
||||
if (!ret.isSucc) {
|
||||
alert(ret.err.message);
|
||||
return;
|
||||
}
|
||||
|
||||
this.self = {
|
||||
uid: ret.res.uid,
|
||||
lastServerState: ret.res.roomState.players.find(v => v.uid === ret.res!.uid)!
|
||||
}
|
||||
this.state = ret.res.roomState;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,12 @@
|
||||
{
|
||||
"ver": "1.1.0",
|
||||
"importer": "directory",
|
||||
"imported": true,
|
||||
"uuid": "bb0fd50f-b641-4824-a798-1f06417e3e88",
|
||||
"files": [],
|
||||
"subMetas": {},
|
||||
"userData": {
|
||||
"compressionType": {},
|
||||
"isRemoteBundle": {}
|
||||
}
|
||||
}
|
@ -0,0 +1,94 @@
|
||||
import { _decorator, Component, Node, Vec3, Quat, Tween, tween } from "cc";
|
||||
import { MathUtil } from '../models/MathUtil';
|
||||
const { ccclass, property } = _decorator;
|
||||
|
||||
const v3_1 = new Vec3;
|
||||
|
||||
/**
|
||||
* 跟随摄像机
|
||||
*/
|
||||
@ccclass
|
||||
export class FollowCamera extends Component {
|
||||
|
||||
@property(Node)
|
||||
focusTarget: Node = null as any;
|
||||
|
||||
@property
|
||||
speedFactor: number = 0.05;
|
||||
|
||||
@property
|
||||
private _distance: number = 15.0;
|
||||
@property
|
||||
public get distance(): number {
|
||||
return this._distance;
|
||||
}
|
||||
public set distance(v: number) {
|
||||
this._distance = v;
|
||||
this._updateTargetWorldPos();
|
||||
}
|
||||
|
||||
// Limit range
|
||||
enableLimit: boolean = true;
|
||||
minX = -Infinity;
|
||||
maxX = Infinity;
|
||||
minZ = -Infinity;
|
||||
maxZ = Infinity;
|
||||
|
||||
protected _tweenFollow?: Tween;
|
||||
protected _targetWorldPos = new Vec3;
|
||||
protected _lastTargetPos = new Vec3;
|
||||
|
||||
start() {
|
||||
this._lastTargetPos.set(this.focusTarget.worldPosition);
|
||||
this._updateTargetWorldPos();
|
||||
this.node.setWorldPosition(this._targetWorldPos);
|
||||
}
|
||||
|
||||
protected _updateTargetWorldPos() {
|
||||
this._targetWorldPos.set(this.focusTarget.worldPosition);
|
||||
if (this.enableLimit) {
|
||||
this._targetWorldPos.x = MathUtil.limit(this._targetWorldPos.x, this.minX, this.maxX);
|
||||
this._targetWorldPos.z = MathUtil.limit(this._targetWorldPos.z, this.minZ, this.maxZ);
|
||||
}
|
||||
|
||||
this._targetWorldPos.add(this.node.forward.multiplyScalar(this.distance * -1));
|
||||
}
|
||||
|
||||
update() {
|
||||
if (!this._lastTargetPos.equals(this.focusTarget.worldPosition)) {
|
||||
this._lastTargetPos.set(this.focusTarget.worldPosition);
|
||||
this._updateTargetWorldPos();
|
||||
}
|
||||
|
||||
// 向TargetWorldPos平滑逼近
|
||||
// Limit Range
|
||||
v3_1.set(this._targetWorldPos);
|
||||
let diff = v3_1.subtract(this.node.worldPosition);
|
||||
if (diff.lengthSqr() > 0.01) {
|
||||
this.node.worldPosition.add(diff.multiplyScalar(this.speedFactor));
|
||||
this.node.setWorldPosition(this.node.worldPosition);
|
||||
}
|
||||
}
|
||||
|
||||
resetPos() {
|
||||
this._updateTargetWorldPos();
|
||||
this.node.setWorldPosition(this._targetWorldPos);
|
||||
}
|
||||
|
||||
@property
|
||||
get preview() {
|
||||
return false;
|
||||
}
|
||||
set preview(v: boolean) {
|
||||
this.resetPos();
|
||||
}
|
||||
|
||||
@property
|
||||
get autoSetDistance() {
|
||||
return false;
|
||||
}
|
||||
set autuSetDistance(v: boolean) {
|
||||
this.distance = this.node.worldPosition.clone().subtract(this.focusTarget.worldPosition).length();
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,13 @@
|
||||
{
|
||||
"ver": "4.0.22",
|
||||
"importer": "typescript",
|
||||
"imported": true,
|
||||
"uuid": "db75b6cd-267c-4760-8771-a3adc24919ef",
|
||||
"files": [],
|
||||
"subMetas": {},
|
||||
"userData": {
|
||||
"importAsPlugin": false,
|
||||
"moduleId": "project:///assets/scripts/components/FollowCamera.js",
|
||||
"simulateGlobals": []
|
||||
}
|
||||
}
|
@ -0,0 +1,12 @@
|
||||
{
|
||||
"ver": "1.1.0",
|
||||
"importer": "directory",
|
||||
"imported": true,
|
||||
"uuid": "7d1b93ce-3f28-40b7-9ad5-52f9fd2cae80",
|
||||
"files": [],
|
||||
"subMetas": {},
|
||||
"userData": {
|
||||
"compressionType": {},
|
||||
"isRemoteBundle": {}
|
||||
}
|
||||
}
|
@ -0,0 +1,97 @@
|
||||
import { WsClient } from "tsrpc-browser";
|
||||
import { GameSystem, GameSystemState } from "../shared/game/GameSystem";
|
||||
import { ClientInput, MsgClientInput } from "../shared/protocols/client/MsgClientInput";
|
||||
import { MsgFrame } from "../shared/protocols/server/MsgFrame";
|
||||
import { ServiceType } from "../shared/protocols/serviceProto";
|
||||
|
||||
export class GameManager {
|
||||
|
||||
client: WsClient<ServiceType>;
|
||||
|
||||
gameSystem = new GameSystem();
|
||||
lastServerState: GameSystemState = this.gameSystem.state;
|
||||
selfPlayerId: number = -1;
|
||||
lastSN = 0;
|
||||
|
||||
get state() {
|
||||
return this.gameSystem.state;
|
||||
}
|
||||
|
||||
constructor(client: WsClient<ServiceType>) {
|
||||
this.client = client;
|
||||
client.listenMsg('server/Frame', msg => { this._onServerSync(msg) });
|
||||
|
||||
(window as any).gm = this;
|
||||
}
|
||||
|
||||
async join(): Promise<void> {
|
||||
if (!this.client.isConnected) {
|
||||
let resConnect = await this.client.connect();
|
||||
if (!resConnect.isSucc) {
|
||||
if (confirm('连接到服务器失败,是否重试')) {
|
||||
return this.join();
|
||||
}
|
||||
else {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let ret = await this.client.callApi('Join', {});
|
||||
|
||||
if (!ret.isSucc) {
|
||||
if (confirm(`加入房间失败\n${ret.err.message}\n是否重试 ?`)) {
|
||||
return this.join();
|
||||
}
|
||||
else {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
this.gameSystem.reset(ret.res.gameState);
|
||||
this.lastServerState = Object.merge(ret.res.gameState);
|
||||
this.selfPlayerId = ret.res.playerId;
|
||||
}
|
||||
|
||||
private _onServerSync(frame: MsgFrame) {
|
||||
// 同步权威状态
|
||||
this.gameSystem.reset(this.lastServerState);
|
||||
for (let input of frame.inputs) {
|
||||
this.gameSystem.applyInput(input);
|
||||
}
|
||||
this.lastServerState = Object.merge({}, this.gameSystem.state);
|
||||
|
||||
// 和解
|
||||
let lastSn = frame.lastSn ?? -1;
|
||||
this.pendingInputMsgs.remove(v => v.sn <= lastSn);
|
||||
this.pendingInputMsgs.forEach(m => {
|
||||
m.inputs.forEach(v => {
|
||||
this.gameSystem.applyInput({
|
||||
...v,
|
||||
playerId: this.selfPlayerId
|
||||
});
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
pendingInputMsgs: MsgClientInput[] = [];
|
||||
sendClientInput(input: ClientInput) {
|
||||
if (!this.selfPlayerId) {
|
||||
return;
|
||||
}
|
||||
|
||||
let msg: MsgClientInput = {
|
||||
sn: ++this.lastSN,
|
||||
inputs: [input]
|
||||
}
|
||||
this.pendingInputMsgs.push(msg);
|
||||
this.client.sendMsg('client/ClientInput', msg);
|
||||
|
||||
// 预测
|
||||
this.gameSystem.applyInput({
|
||||
...input,
|
||||
playerId: this.selfPlayerId
|
||||
});
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,9 @@
|
||||
{
|
||||
"ver": "4.0.22",
|
||||
"importer": "typescript",
|
||||
"imported": true,
|
||||
"uuid": "977377fa-caaf-4e5e-8dac-0b429df3bdf6",
|
||||
"files": [],
|
||||
"subMetas": {},
|
||||
"userData": {}
|
||||
}
|
@ -0,0 +1,7 @@
|
||||
export class MathUtil {
|
||||
|
||||
static limit(src: number, min: number, max: number) {
|
||||
return Math.min(max, Math.max(min, src));
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,9 @@
|
||||
{
|
||||
"ver": "4.0.22",
|
||||
"importer": "typescript",
|
||||
"imported": true,
|
||||
"uuid": "6fde67c5-0d09-4389-8c51-9b57bce87ee1",
|
||||
"files": [],
|
||||
"subMetas": {},
|
||||
"userData": {}
|
||||
}
|
@ -5,5 +5,11 @@
|
||||
"name": "canvas_19",
|
||||
"value": 524288
|
||||
}
|
||||
]
|
||||
],
|
||||
"general": {
|
||||
"designResolution": {
|
||||
"width": 750,
|
||||
"height": 1334
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2,5 +2,7 @@
|
||||
/* Base configuration. Do not edit this field. */
|
||||
"extends": "./temp/tsconfig.cocos.json",
|
||||
/* Add your custom configuration here. */
|
||||
"compilerOptions": {}
|
||||
"compilerOptions": {
|
||||
"skipLibCheck": true
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user