GameSystem
This commit is contained in:
parent
1b7b1d229f
commit
0f89b080cd
@ -1,3 +1,4 @@
|
||||
import 'k8w-extend-native';
|
||||
import * as path from "path";
|
||||
import { WsServer } from "tsrpc";
|
||||
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,
|
||||
"_native": "",
|
||||
"_effectAsset": {
|
||||
"__uuid__": "a3cd009f-0ab0-420d-9278-b9fdab939bbc"
|
||||
"__uuid__": "a3cd009f-0ab0-420d-9278-b9fdab939bbc",
|
||||
"__expectedType__": "cc.EffectAsset"
|
||||
},
|
||||
"_techIdx": 0,
|
||||
"_defines": [
|
||||
@ -26,7 +27,8 @@
|
||||
"_props": [
|
||||
{
|
||||
"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