美文网首页一只腊鸭做游戏
决战-Pow!第五集:游戏主逻辑

决战-Pow!第五集:游戏主逻辑

作者: 回忆并快 | 来源:发表于2018-02-14 23:35 被阅读5次

    最近几天,忙收拾回家的东西,又落下了几天,噶咩纳塞。
    为了方便逻辑的开发,我通过一个单例GameManager来管理游戏主逻辑。

    这个主要是游戏玩法的处理,创建对象,删除对象,碰撞检测,游戏更新均通过此类完成。

    // 此管理类继承于事件分发器,让其拥有事件处理的能力。
    class GameManager extends Laya.EventDispatcher {
        private static _instance: GameManager = null;
        constructor() {
            super();
        }
        // 派发事件
        public dispatchEvent(type:string, data?:any){
            this.event(type, data);
        }
        // 单例
        public static getInstance(): GameManager {
            return this._instance || (this._instance = new this());
        }
    
        // 游戏是否运行中
        private _isRunning: boolean;
        public get isRunning(): boolean {
            return this._isRunning;
        }
    
        // 游戏上下文 持有引用
        private _gameContext: GameContext;
        public get gameContext(): GameContext {
            return this._gameContext;
        }
    
        // 游戏模式(分单机和网络版本)
        public get gameMode(): GameMode {
            return this._gameContext.param.mode;
        }
    
        // 游戏玩家列表
        private _listPlayer: List<PowPlayer> = new List<PowPlayer>();
    
        // 玩家死亡回调
        public onPlayerDie: any = null;
    
        // 玩家数据与id的Dictionary,用于通过id查找游戏玩家的数据
        private _mapPlayerData: Dictionary<number, PlayerData> = new Dictionary<number, PlayerData>();
        // 主玩家id
        private _mainPlayerId:number = 0;
        // 对手玩家id
        private _opponentPlayerId:number = 0;
        // 注册主游戏玩家数据
        public regPlayerData(data: PlayerData) {
            this._mainPlayerId = data.id;
            if (this._mapPlayerData.containsKeyValue(data.id)) {
                this._mapPlayerData.set(data.id, data);
            }else{
                this._mapPlayerData.addKeyValue(data.id, data);
            }
        }
        // 注册对手玩家数据
        public regOpponentData(data: PlayerData){
            this._opponentPlayerId = data.id;
            if (this._mapPlayerData.containsKeyValue(data.id)) {
                this._mapPlayerData.set(data.id, data);
            }else{
                this._mapPlayerData.addKeyValue(data.id, data);
            }
        }
    
        // 获取主玩家的数据
        public getMainPlayerData(){
            return this._mapPlayerData.get(this._mainPlayerId);
        }
        // 获取对手玩家的数据
        public getOpponentPlayerData(){
            return this._mapPlayerData.get(this._opponentPlayerId);
        }
    
        // 拳头列表
        private _playerPows:List<PowEntity> = new List<PowEntity>();
        // 对手拳头列表
        private _opponentPows:List<PowEntity> = new List<PowEntity>();
    
        // 添加拳头
        addPlayerPow(pow:PowEntity){
            this._playerPows.add(pow);
        }
    
        // 移除拳头
        removePlayerPowAt(i:number){
            let pow:PowEntity = this._playerPows.get(i);
            this._playerPows.removeAt(i);
            pow.releaseWithAnim(()=>{
                EntityFactory.releaseEntity(pow);
            });
        }
    
        // 添加对手的拳头
        addOpponentPow(pow:PowEntity){
            this._opponentPows.add(pow);
        }
        
        // 移除对手的拳头
        removeOpponentPowAt(i:number){
            let pow:PowEntity = this._opponentPows.get(i);
            this._opponentPows.removeAt(i);
            pow.releaseWithAnim(()=>{
                EntityFactory.releaseEntity(pow);
            });
        }
    
        // 帧更新
        enterFrame(frameIndex: number) {
            if (!this._isRunning) {
                return;
            }
            // 帧驱动
            if (frameIndex < 0) {
                this._gameContext.currentFrameIndex++;
            } else {
                this._gameContext.currentFrameIndex = frameIndex;
            }
    
            // 每一帧前先移除所有标记释放的对象(回池子)
            EntityFactory.clearReleaseObjects();
    
            // 玩家逻辑更新
            for (var i = 0; i < this._listPlayer.count; i++) {
                this._listPlayer.get(i).enterFrame(frameIndex);
            }
    
            // 拳头逻辑更新
            for (var i = 0; i < this._playerPows.count; i++) {
                let pow:PowEntity = this._playerPows.get(i) as PowEntity;
                pow.enterFrame(frameIndex);
                // 拳头碰撞到边界
                if(pow.hitBound()){
                    // 血条更新
                    if(this.onPlayerInfoUpdate != null){
                        let opponentData:PlayerData = GameManager.getInstance().getOpponentPlayerData();
                        opponentData.hp -= 10;
                        this.onPlayerInfoUpdate(opponentData, false);
                    }
                    // 删除当前这个拳头,记住要把index-1,因为删除了当前这个,需要回到上一个index
                    this.removePlayerPowAt(i);
                    i--;
                }
                // 获取当前碰撞到的拳头index
                let hitItemIdx:number = pow.hit(this._opponentPows);
                let hitItem:PowEntity = this._opponentPows.get(hitItemIdx);
                // 如果有
                if(hitItem != null){
                    // 胜利检测
                    let res:number = this.compete(pow.type, hitItem.type);
                    if(res == 0){ // 平手
                        this.removePlayerPowAt(i);
                        i--;
                        this.removeOpponentPowAt(hitItemIdx);
                    }else if(res == 1){ //胜利
                        this.removeOpponentPowAt(hitItemIdx);
                    }else{ // 失败
                        this.removePlayerPowAt(i);
                        i--;
                    }
                }
            }
    
            // 对手拳头的逻辑处理,因为在主玩家拳头逻辑中处理了,这里只需要做边界碰撞处理
            for (var i = 0; i < this._opponentPows.count; i++) {
                let pow:PowEntity = this._opponentPows.get(i) as PowEntity;
                pow.enterFrame(frameIndex);
                if(pow.hitBound()){
                    if(this.onPlayerInfoUpdate != null){
                        let mainPlayerData:PlayerData = GameManager.getInstance().getMainPlayerData();
                        mainPlayerData.hp -= 10;
                        this.onPlayerInfoUpdate(mainPlayerData, true)
                    }
                    this.removeOpponentPowAt(i);
                    i--;
                }
            }
            // 检测当前是否有已经生命值为0的玩家
            let listDiePlayerId: List<number> = new List<number>();
            for (var i = 0; i < this._listPlayer.count; i++) {
                let player:PowPlayer = this._listPlayer.get(i);
                let playerData:PlayerData = player.data;
                if (playerData.hp <= 0) {
                    listDiePlayerId.add(playerData.id);
                    this.releasePlayerAt(i);
                    i--;
                    continue;
                }
            }
            // 死亡回调
            if (this.onPlayerDie != null) {
                for (var i = 0; i < listDiePlayerId.count; i++) {
                    this.onPlayerDie(listDiePlayerId.get(i))
                }
            }
        }
    
        public onPlayerInfoUpdate:any = null;
    
        // 0 平手 1 胜 -1 败 (剪刀石头布的判定)
        public compete(myType:GameVKey, otherType:GameVKey){
            if (myType == otherType) return 0;
            return (myType - otherType + 3) % 3 == 1 ? 1 : -1;
        }
    
        // 游戏创建
        createGame(param: GameData) {
            if (this._isRunning) {
                Logger.log("Game is Running.");
                return;
            }
            Logger.log("Game is create success.")
            // 建立游戏上下文(主要用于管理当前游戏的元信息)
            this._gameContext = new GameContext();
            this._gameContext.param = param;
            this._gameContext.random = param.randomSeed;
            this._gameContext.currentFrameIndex = 0;
    
            // 初始化工厂
            EntityFactory.init();
            ViewFactory.init(Laya.stage);
    
            this._isRunning = true;
        }
    
        // 创建玩家
        createPlayer(playerId: number) {
            let data: PlayerData = this._mapPlayerData.get(playerId);
            if (data != null) {
                let player: PowPlayer = new PowPlayer();
                player.create(data);
                this._listPlayer.add(player);
            } else {
                Logger.log('PlayerData找不到~');
            }
        }
    
        // 释放游戏
        releaseGame() {
            if (!this._isRunning) {
                return;
            }
            this._isRunning = false;
    
            for (var i = 0; i < this._listPlayer.count; i++) {
                this._listPlayer.get(i).release();
            }
            this._listPlayer.clear();
            
            for (var i = 0; i < this._playerPows.count; i++) {
                this._playerPows.get(i).release();
            }
            this._playerPows.clear();
    
            for (var i = 0; i < this._opponentPows.count; i++) {
                this._opponentPows.get(i).release();
            }
            this._opponentPows.clear();
    
            ViewFactory.release();
            EntityFactory.release();
    
            this.onPlayerDie = null;
        }
    
        // 玩家逻辑输入
        inputVKey(vkey: number, args: any, playerId: number) {
            if (playerId == 0) {
                // 处理其他vkey,全局的vkey
                this.handleOtherVKey(vkey, args, playerId);
            } else {
                // Logger.log('playerId' + playerId);
                let player: PowPlayer = this.getPlayer(playerId);
                // Logger.log('player' + player);
                if (player != null) {
                    player.inputVKey(vkey, args);
                } else {
                    // 处理其他vkey
                    this.handleOtherVKey(vkey, args, playerId);
                }
            }
        }
    
        handleOtherVKey(vkey: number, args: any, playerId: number) {
            // 全局的VKey处理
            // let hasHandled:boolean = false;
            // hasHandled = hasHandled || this.doCreatePlayer(vkey, args, playerId);
            // hasHandled = hasHandled || this.doReleasePlayer(vkey, args, playerId)
            // this.doCreatePlayer(vkey, args, playerId);;
        }
    
        // 执行创建玩家
        doCreatePlayer(vkey: number, args: any, playerId) {
            if (vkey == GameVKey.CREATE_PLAYER) {
                this.createPlayer(playerId);
                return true;
            }
            return false;
        }
    
        // 执行释放玩家
        doReleasePlayer(vkey: number, args: any, playerId) {
            if (vkey == FSPVKeyBase.GAME_EXIT) {
                this.releasePlayer(playerId);
                return true;
            }
            return false;
        }
    
        // 释放玩家
        releasePlayer(playerId: number) {
            let index: number = this.getPlayerIndex(playerId);
            this.releasePlayerAt(index);
        }
    
        // 释放指定位置的玩家
        releasePlayerAt(index: number) {
            if (index >= 0) {
                let player: PowPlayer = this._listPlayer.get(index);
                this._listPlayer.removeAt(index);
                player.release();
            }
        }
    
        // 获得玩家列表
        getPlayerList() {
            return this._listPlayer;
        }
    
        // 获取玩家
        getPlayer(playerId: number) {
            let index: number = this.getPlayerIndex(playerId);
            if (index >= 0) {
                return this._listPlayer.get(index);
            }
            return null;
        }
    
        // 获得玩家index
        getPlayerIndex(playerId: number) {
            // Logger.log(this._listPlayer);
            for (var index = 0; index < this._listPlayer.count; index++) {
                if (this._listPlayer.get(index).id == playerId) {
                    return index;
                }
            }
            return -1;
        }
    
        // 初始化
        initialize() {
            Logger.log("initialize.")
        }
    }
    

    这里逻辑比较多,我直接贴代码,但上面有相应的注释,你应该看的明白~

    创建一个PVEGame,人机对战游戏

    class PVEGame{
        public onGameEnd:any = null;
        public onMainPlayerDie:any = null;
        private _mainPlayerId:number = 1;
        private _frameIndex:number = 0;
        private _pause = false;
        private _gameContext:GameContext;
        private _startTime:number = 0;
        constructor(){}
        // 游戏开始
        start(param:GameData){
            // 创建游戏
            GameManager.getInstance().createGame(param);
            GameManager.getInstance().onPlayerDie = this.onPlayerDie.bind(this);
            this._gameContext = GameManager.getInstance().gameContext;
    
            // 初始化输入
            GameInput.getInstance().initialize();
            GameInput.getInstance().onVKey = this.onVKey.bind(this);
    
            // 创建用户数据
            let ud:UserData = new UserData();
            ud.id = 999999;
            ud.coin = 1000;
            ud.name = "quinsmpang";
            ud.powid = 1;
            UserManager.getInstance().updateMainUserData(ud);
            // 需要注册player数据
            this.createPlayer();
            this.createOpponent();
    
            Logger.log("cur ms:" + Laya.timer.currTimer);
            this._startTime = Laya.timer.currTimer;
            // enterFame 帧循环
            Laya.timer.frameLoop(1, this, this.update);
        }
        createPlayer(){
            // 创建玩家
            let data:PlayerData = new PlayerData();
            data.id = this._mainPlayerId;
            data.userId = UserManager.getInstance().mainUserData.id;
            data.powData.speed = -10;
            data.powData.id = 3;
            data.powData.size = 60;
            data.powData.offsetY = -55;
            data.ai = 0;
            data.isMain = true;
            data.hp = data.maxHp = 100;
            GameManager.getInstance().regPlayerData(data);
            GameManager.getInstance().createPlayer(data.id);
        }
        createOpponent(){
            // 创建对手
            let data:PlayerData = new PlayerData();
            data.id = 2;
            data.powData.speed = 10;
            data.powData.id = 3;
            data.powData.size = 60;
            data.powData.offsetY = -55;
            data.ai = 1;
            data.isMain = false;
            data.hp = data.maxHp = 100;
            GameManager.getInstance().regOpponentData(data);
            GameManager.getInstance().createPlayer(data.id);
        }
        rebornPlayer(){
            // 重建玩家
            this.createPlayer();
        }
        stop(){
            // 停止
            Laya.timer.clear(this, this.update);
            GameInput.getInstance().finalize();
            GameManager.getInstance().releaseGame();
            this.onGameEnd = null;
            this.onMainPlayerDie = null;
            this._gameContext = null;
        }
        update(){
            // 游戏更新
            if(this._pause) return;
            this._frameIndex ++;
            GameManager.getInstance().enterFrame(this._frameIndex);
            this.checkTimeEnd();
        }
        
        public get isTimelimited() : boolean {
            // 是否限时
            return this._gameContext.param.mode == GameMode.PVE;
        }
    
        getRemainTime(){
            // 剩余时间
            if(this._gameContext.param.mode == GameMode.PVE){
                // return GameUtils.toInt((this._gameContext.param.limitedTime - this._gameContext.currentFrameIndex * 0.033333333));
                return this._gameContext.param.limitedTime - this.getElapsedTime();
            }
            return 0;
        }
    
        getElapsedTime(){
            // 流逝时间
            // return GameUtils.toInt(this._gameContext.currentFrameIndex * 0.033333333)
            // Logger.log("this ms:" + Laya.timer.currTimer);
            // Logger.log("s:" + GameUtils.toInt((Laya.timer.currTimer - this._startTime) * 0.001))
            return GameUtils.toInt((Laya.timer.currTimer - this._startTime) * 0.001);
        }
    
        getElapsedTimeMS(){
            // 流逝的时间ms
            // return GameUtils.toInt(this._gameContext.currentFrameIndex * 0.033333333)
            // Logger.log("this ms:" + Laya.timer.currTimer);
            // Logger.log("s:" + GameUtils.toInt((Laya.timer.currTimer - this._startTime) * 0.001))
            return Laya.timer.currTimer - this._startTime;
        }
    
        checkTimeEnd(){
            // 检查游戏是否结束
            if(this.isTimelimited){
                let remainTime = this.getRemainTime();
                // Logger.log("remainTime:" + remainTime);
                if(remainTime <= 0){
                    this.terminate();
                }
            }
        }
        onVKey(vkey:number, args:any){
            // 用户输入
            GameManager.getInstance().inputVKey(vkey, args, this._mainPlayerId);
        }
        public onOpponentPlayerDie:any = null;
        // 玩家死亡处理
        onPlayerDie(playerId:number){
            if(this._mainPlayerId === playerId){
                if(this.onMainPlayerDie != null)
                {
                    this.onMainPlayerDie();
                }else{
                    Logger.log('OnPlayerDie() onMainPlayerDie == null!');
                }
            }else{
                if(this.onOpponentPlayerDie != null)
                {
                    this.onOpponentPlayerDie();
                }else{
                    Logger.log('OnPlayerDie() onOpponentPlayerDie == null!');
                }
            }
        }
        // 游戏暂停
        pause(){
            this._pause = true;
        }
        // 游戏继续
        resume(){
            this._pause = false;
        }
        // 游戏终止
        terminate(){
            this.pause();
            if(this.onGameEnd != null){
                this.onGameEnd();
            }
        }
    }
    

    最后就是通过一个插件来调用PVEGame的逻辑:

    class PVEPlugin extends BasePlugin {
        constructor() {
            super();
        }
        private _game: PVEGame = null;
        open() {
            this.startGame(GameMode.PVE);
        }
        startGame(mode: GameMode) {
            let param: GameData = new GameData();
            param.mode = mode;
    
            this._game = new PVEGame();
            this._game.start(param);
            this._game.onGameEnd = this.stopGame.bind(this);
            // 打开战斗UI
            UICommon.showBackground();
            UIManager.getInstance().openPage(BattlePage, true);
        }
        stopGame() {
            if (this._game != null) {
                this._game.stop();
                this._game = null;
            }
            // 关闭战斗UI
            UIManager.getInstance().closePage(BattlePage);
        }
        getCurrentGame(): PVEGame {
            return this._game;
        }
        close(){
            this.stopGame();
        }
    }
    

    这个插件非常简单,控制UI和游戏逻辑。
    到此,一个简单的单机游戏基本完成~里面涉及一些简单的游戏AI和游戏输入,下回补充讲解。

    相关文章

      网友评论

        本文标题:决战-Pow!第五集:游戏主逻辑

        本文链接:https://www.haomeiwen.com/subject/vvqytftx.html