GameSystem
This commit is contained in:
parent
1b7b1d229f
commit
0f89b080cd
@ -1,3 +1,4 @@
|
|||||||
|
import 'k8w-extend-native';
|
||||||
import * as path from "path";
|
import * as path from "path";
|
||||||
import { WsServer } from "tsrpc";
|
import { WsServer } from "tsrpc";
|
||||||
import { serviceProto } from './shared/protocols/serviceProto';
|
import { serviceProto } from './shared/protocols/serviceProto';
|
||||||
|
@ -0,0 +1,153 @@
|
|||||||
|
import { gameConfig } from "./gameConfig";
|
||||||
|
import { GameSystemEvent } from "./GameSystemEvent";
|
||||||
|
import { GameSystemInput } from "./GameSystemInput";
|
||||||
|
import { GameSystemState } from "./GameSystemState";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 前后端复用的状态计算模块
|
||||||
|
*/
|
||||||
|
export class GameSystem {
|
||||||
|
|
||||||
|
// 当前状态
|
||||||
|
state: GameSystemState;
|
||||||
|
|
||||||
|
constructor(state: GameSystemState) {
|
||||||
|
this.state = state;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 应用输入,计算状态变更
|
||||||
|
applyInput(input: GameSystemInput) {
|
||||||
|
switch (input.type) {
|
||||||
|
// 击中敌机
|
||||||
|
case 'PlayerHitEnemy': {
|
||||||
|
let enemyIndex = this.state.enemies.findIndex(v => v.id === input.enemyId);
|
||||||
|
let player = this.state.players.find(v => v.id === input.playerId);
|
||||||
|
if (player && enemyIndex > -1) {
|
||||||
|
this.state.enemies.splice(enemyIndex, 1);
|
||||||
|
// 得 1 分
|
||||||
|
player.score += 1;
|
||||||
|
this.emit('enemyDie', { enemyId: input.enemyId })
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
// 吃到子弹道具
|
||||||
|
case 'PlayerHitFightIcon': {
|
||||||
|
let fightIconIndex = this.state.fightIcons.findIndex(v => v.id === input.fightIconId);
|
||||||
|
let player = this.state.players.find(v => v.id === input.playerId);
|
||||||
|
if (player && fightIconIndex > -1) {
|
||||||
|
let fightIcon = this.state.fightIcons[fightIconIndex];
|
||||||
|
this.state.fightIcons.splice(fightIconIndex, 1);
|
||||||
|
player.currentBulletType = fightIcon.type;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
// 玩家受到伤害
|
||||||
|
case 'PlayerHurt': {
|
||||||
|
let player = this.state.players.find(v => v.id === input.playerId);
|
||||||
|
if (player) {
|
||||||
|
player.life = Math.max(0, player.life - input.hurtLife);
|
||||||
|
if (player.life === 0) {
|
||||||
|
this.state.players.removeOne(v => v.id === input.playerId);
|
||||||
|
this.emit('playerDie', { playerId: player.id })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
// 移动并攻击
|
||||||
|
case 'PlayerMove': {
|
||||||
|
let player = this.state.players.find(v => v.id === input.playerId);
|
||||||
|
if (player) {
|
||||||
|
// Update Pos
|
||||||
|
player.pos.x += input.offset.x;
|
||||||
|
player.pos.y += input.offset.y;
|
||||||
|
// Update Bullets
|
||||||
|
player.bullets.push(...input.createBullets);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
// 子弹碰撞,抵消
|
||||||
|
case 'BulletHit': {
|
||||||
|
let player = this.state.players.find(v => v.id === input.player.id);
|
||||||
|
let enemy = this.state.enemies.find(v => v.id === input.enemy.id);
|
||||||
|
if (player && enemy) {
|
||||||
|
player.bullets.removeOne(v => v.id === input.player.bulletId);
|
||||||
|
enemy.bullets.removeOne(v => v.id === input.enemy.bulletId);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
// 时间流逝
|
||||||
|
case 'TimePast': {
|
||||||
|
// 更新己方子弹位置
|
||||||
|
this.state.players.forEach(player => {
|
||||||
|
player.bullets.forEach(bullet => {
|
||||||
|
bullet.pos.x = bullet.init.pos.x + bullet.init.direction.x * gameConfig.player.bulletSpeed * (this.state.now - bullet.init.time);
|
||||||
|
bullet.pos.y = bullet.init.pos.y + bullet.init.direction.y * gameConfig.player.bulletSpeed * (this.state.now - bullet.init.time);
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
// 更新敌机
|
||||||
|
this.state.enemies.forEach(enemy => {
|
||||||
|
// 更新敌机位置
|
||||||
|
const enemyTime = this.state.now - enemy.init.time;
|
||||||
|
enemy.pos.y = enemy.init.pos.y - gameConfig.enemy.speed * enemyTime;
|
||||||
|
|
||||||
|
// 更新敌机子弹位置
|
||||||
|
enemy.bullets.forEach(bullet => {
|
||||||
|
bullet.pos.y = bullet.init.pos.y - gameConfig.enemy.bulletSpeed * (this.state.now - bullet.init.time);
|
||||||
|
})
|
||||||
|
|
||||||
|
// 敌机发射子弹
|
||||||
|
if ((this.state.now - enemy.lastBulletTime) >= gameConfig.enemy.bulletGapTime) {
|
||||||
|
enemy.bullets.push({
|
||||||
|
id: enemy.nextId.bullet++,
|
||||||
|
pos: { ...enemy.pos },
|
||||||
|
init: {
|
||||||
|
time: this.state.now,
|
||||||
|
pos: { ...enemy.pos },
|
||||||
|
}
|
||||||
|
})
|
||||||
|
enemy.lastBulletTime = this.state.now;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// 创建新敌机
|
||||||
|
this._createEnemies();
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private _createEnemies() {
|
||||||
|
// 前 10 秒
|
||||||
|
// 每 1 秒创建一个敌机
|
||||||
|
|
||||||
|
// 10~20秒
|
||||||
|
// 每3秒一个组合,然后每秒一个敌机
|
||||||
|
|
||||||
|
// 20秒以后
|
||||||
|
// 每 2 秒一个组合(组合1 / 组合2 / xxx)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 简易的事件侦听器
|
||||||
|
private _eventHandlers: { [key: string]: Function[] } = {};
|
||||||
|
on<T extends keyof GameSystemEvent>(eventName: T, handler: (e: GameSystemEvent[T]) => void): (e: GameSystemEvent[T]) => void {
|
||||||
|
if (!this._eventHandlers[eventName]) {
|
||||||
|
this._eventHandlers[eventName] = [];
|
||||||
|
}
|
||||||
|
this._eventHandlers[eventName].push(handler);
|
||||||
|
return handler;
|
||||||
|
}
|
||||||
|
off<T extends keyof GameSystemEvent>(eventName: T, handler?: (e: GameSystemEvent[T]) => void): void {
|
||||||
|
if (!handler) {
|
||||||
|
this._eventHandlers[eventName] = [];
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this._eventHandlers[eventName]?.removeOne(v => v === handler);
|
||||||
|
}
|
||||||
|
emit<T extends keyof GameSystemEvent>(eventName: T, eventData: GameSystemEvent[T]) {
|
||||||
|
this._eventHandlers[eventName]?.forEach(v => v(eventData));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,10 @@
|
|||||||
|
import { uint } from "tsrpc";
|
||||||
|
|
||||||
|
export interface GameSystemEvent {
|
||||||
|
playerDie: {
|
||||||
|
playerId: uint
|
||||||
|
},
|
||||||
|
enemyDie: {
|
||||||
|
enemyId: uint
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,54 @@
|
|||||||
|
import { uint } from "tsrpc";
|
||||||
|
import { PlayerState } from "./GameSystemState";
|
||||||
|
|
||||||
|
// 移动并攻击
|
||||||
|
export interface PlayerMove {
|
||||||
|
type: 'PlayerMove',
|
||||||
|
playerId: uint,
|
||||||
|
offset: { x: number, y: number },
|
||||||
|
createBullets: PlayerState['bullets']
|
||||||
|
}
|
||||||
|
|
||||||
|
// 命中敌机
|
||||||
|
export interface PlayerHitEnemy {
|
||||||
|
type: 'PlayerHitEnemy',
|
||||||
|
playerId: uint,
|
||||||
|
enemyId: uint
|
||||||
|
}
|
||||||
|
|
||||||
|
// 吃到 FightIcon
|
||||||
|
export interface PlayerHitFightIcon {
|
||||||
|
type: 'PlayerHitFightIcon',
|
||||||
|
playerId: uint,
|
||||||
|
fightIconId: uint
|
||||||
|
}
|
||||||
|
|
||||||
|
// 被敌机击中
|
||||||
|
export interface PlayerHurt {
|
||||||
|
type: 'PlayerHurt',
|
||||||
|
playerId: uint,
|
||||||
|
// 伤害血量
|
||||||
|
hurtLife: number,
|
||||||
|
}
|
||||||
|
|
||||||
|
// 子弹互相碰撞,双双消失
|
||||||
|
export interface BulletHit {
|
||||||
|
type: 'BulletHit',
|
||||||
|
player: {
|
||||||
|
id: uint,
|
||||||
|
bulletId: uint
|
||||||
|
},
|
||||||
|
enemy: {
|
||||||
|
id: uint,
|
||||||
|
bulletId: uint
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
// 时间流逝
|
||||||
|
export interface TimePast {
|
||||||
|
type: 'TimePast',
|
||||||
|
dt: number
|
||||||
|
}
|
||||||
|
|
||||||
|
// 输入定义
|
||||||
|
export type GameSystemInput = PlayerMove | PlayerHitEnemy | PlayerHitFightIcon | PlayerHurt | BulletHit | TimePast;
|
@ -0,0 +1,87 @@
|
|||||||
|
import { uint } from "tsrpc";
|
||||||
|
|
||||||
|
// 坐标系:X-Y 原点在左下角
|
||||||
|
|
||||||
|
export interface GameSystemState {
|
||||||
|
// 游戏时间
|
||||||
|
now: number,
|
||||||
|
|
||||||
|
players: PlayerState[],
|
||||||
|
enemies: EnemyState[],
|
||||||
|
fightIcons: FightIconState[],
|
||||||
|
|
||||||
|
// ID 生成器
|
||||||
|
nextId: {
|
||||||
|
enemy: uint,
|
||||||
|
fightIcon: uint
|
||||||
|
},
|
||||||
|
// 上次创建敌机的时间
|
||||||
|
lastCreateEnemyTime: number,
|
||||||
|
randomSeed: number,
|
||||||
|
}
|
||||||
|
|
||||||
|
// 玩家
|
||||||
|
export interface PlayerState {
|
||||||
|
id: uint,
|
||||||
|
// 得分
|
||||||
|
score: number,
|
||||||
|
// 生命值
|
||||||
|
life: number,
|
||||||
|
// 当前子弹
|
||||||
|
currentBulletType: PlayerBulletType,
|
||||||
|
// 位置
|
||||||
|
pos: { x: number, y: number },
|
||||||
|
bullets: {
|
||||||
|
id: uint,
|
||||||
|
type: PlayerBulletType,
|
||||||
|
pos: { x: number, y: number },
|
||||||
|
// 初始状态
|
||||||
|
init: {
|
||||||
|
time: number,
|
||||||
|
pos: { x: number, y: number },
|
||||||
|
direction: { x: number, y: number }
|
||||||
|
}
|
||||||
|
}[],
|
||||||
|
nextId: {
|
||||||
|
bullet: uint
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export type PlayerBulletType = 'M' | 'H' | 'S';
|
||||||
|
|
||||||
|
// 敌机
|
||||||
|
export interface EnemyState {
|
||||||
|
id: uint,
|
||||||
|
type: uint,
|
||||||
|
pos: { x: number, y: number },
|
||||||
|
init: {
|
||||||
|
time: number,
|
||||||
|
pos: { x: number, y: number },
|
||||||
|
speed: { y: number }
|
||||||
|
}
|
||||||
|
bullets: {
|
||||||
|
id: uint,
|
||||||
|
pos: { x: number, y: number },
|
||||||
|
// 初始状态
|
||||||
|
init: {
|
||||||
|
time: number,
|
||||||
|
// 目前只能向下飞
|
||||||
|
pos: { x: number, y: number },
|
||||||
|
}
|
||||||
|
}[],
|
||||||
|
// 上次发射子弹的时间
|
||||||
|
lastBulletTime: number,
|
||||||
|
nextId: {
|
||||||
|
bullet: uint
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 子弹图标
|
||||||
|
export interface FightIconState {
|
||||||
|
id: uint,
|
||||||
|
type: PlayerBulletType,
|
||||||
|
init: {
|
||||||
|
time: number,
|
||||||
|
pos: { x: number, y: number }
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,7 @@
|
|||||||
|
export class GameSystemUtil {
|
||||||
|
|
||||||
|
static getPlayerBulletPos() { }
|
||||||
|
|
||||||
|
static getEnemyBulletPos() { }
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,16 @@
|
|||||||
|
export const gameConfig = {
|
||||||
|
syncRate: 10,
|
||||||
|
|
||||||
|
enemy: {
|
||||||
|
speed: 10,
|
||||||
|
bulletSpeed: 20,
|
||||||
|
// 第一次发射子弹的延迟时间
|
||||||
|
bulletDelayTime: 1500,
|
||||||
|
// 每次发射子弹的间隔
|
||||||
|
bulletGapTime: 500
|
||||||
|
},
|
||||||
|
|
||||||
|
player: {
|
||||||
|
bulletSpeed: 10,
|
||||||
|
},
|
||||||
|
}
|
@ -4,7 +4,8 @@
|
|||||||
"_objFlags": 0,
|
"_objFlags": 0,
|
||||||
"_native": "",
|
"_native": "",
|
||||||
"_effectAsset": {
|
"_effectAsset": {
|
||||||
"__uuid__": "a3cd009f-0ab0-420d-9278-b9fdab939bbc"
|
"__uuid__": "a3cd009f-0ab0-420d-9278-b9fdab939bbc",
|
||||||
|
"__expectedType__": "cc.EffectAsset"
|
||||||
},
|
},
|
||||||
"_techIdx": 0,
|
"_techIdx": 0,
|
||||||
"_defines": [
|
"_defines": [
|
||||||
@ -26,7 +27,8 @@
|
|||||||
"_props": [
|
"_props": [
|
||||||
{
|
{
|
||||||
"mainTexture": {
|
"mainTexture": {
|
||||||
"__uuid__": "e163c875-c8dd-4512-b96a-e6fd360a1b99@6c48a"
|
"__uuid__": "e163c875-c8dd-4512-b96a-e6fd360a1b99@6c48a",
|
||||||
|
"__expectedType__": "cc.Texture2D"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
Loading…
Reference in New Issue
Block a user