GameSystem

This commit is contained in:
k8w 2021-12-27 21:58:54 +08:00
parent 1b7b1d229f
commit 0f89b080cd
8 changed files with 332 additions and 2 deletions

View File

@ -1,3 +1,4 @@
import 'k8w-extend-native';
import * as path from "path";
import { WsServer } from "tsrpc";
import { serviceProto } from './shared/protocols/serviceProto';

View File

@ -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));
}
}

View File

@ -0,0 +1,10 @@
import { uint } from "tsrpc";
export interface GameSystemEvent {
playerDie: {
playerId: uint
},
enemyDie: {
enemyId: uint
}
}

View File

@ -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;

View File

@ -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 }
}
}

View File

@ -0,0 +1,7 @@
export class GameSystemUtil {
static getPlayerBulletPos() { }
static getEnemyBulletPos() { }
}

View File

@ -0,0 +1,16 @@
export const gameConfig = {
syncRate: 10,
enemy: {
speed: 10,
bulletSpeed: 20,
// 第一次发射子弹的延迟时间
bulletDelayTime: 1500,
// 每次发射子弹的间隔
bulletGapTime: 500
},
player: {
bulletSpeed: 10,
},
}

View File

@ -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"
}
}
]