用23种设计模式打造一个cocos creator的游戏框架----(十二)状态模式

1、模式标准

模式名称:状态模式

模式分类:行为型

模式意图:允许一个对象在其内部状态改变时改变它的行为。对象看起来似乎修改了它的类。

结构图:

适用于:

1、一个对象的行为决定于它的状态,并且它必须在运行时刻根据状态改变它的行为。

2、一个操作中含有庞大的多分支的条件语句,且这些分支依赖丁该对象的状态。这个状态常用一个或多个枚举常量表示。通常,有多个操作包含这一相同的条件结构。State模式将每一个条件分支放入一个独立的类中。这使得开发者可以根据对象自身的情况将对象的状态作为一个对象,这一对象可以不依赖于其他对象独立变化。

主要成员:

  • 上下文(Context):它定义了客户端感兴趣的接口,并且维护一个指向当前状态的实例变量。
  • 状态抽象(State):这是一个接口或者抽象类,它定义了每个状态必须实现的方法。
  • 具体状态(Concrete States):它们是实现状态接口的类,每个类对应一种状态,且包含了该状态下的行为实现。

2、分析与设计  

在一般的游戏开发中状态值通常是一个枚举值,但在状态模式中,状态值是一个通过实现了 IUnitState 接口的对象表示的。这种方法的优点是它更加灵活和强大,因为这个状态值不仅仅是一个值,它还是一组行为的集合(即方法实现)。这允许您在不同的状态之间切换行为,而不是仅仅改变一个表示状态的值。

在游戏中的单位一般有以下几种状态:站立,移动,攻击,释放技能中,眩晕中,死亡。比较常见的是单位正在释放一个技能,这个时候一个飞锤飞过来,将他击晕了,他停止了技能的释放。

接下来我们修改一下我们的意图

意图:允许一个对象(单位)在其内部状态改变时(由其状态对象来)改变它的行为。对象看起来似乎修改了它的类(实际是状态对象干的)。

3、开始打造

export enum UnitStateType {
    Standing,
    Moving,
    Attacking,
    CastSkilling,
    Stuning,
    Die
}
export interface IUnitState {
    enterState(unitItem: IUnitItem): void
    //
    stand(): void; // 站立
    move(): void; // 移动
    attack(): void; // 攻击
    castSkill(): void; // 释放技能
    stun(): void; // 击晕
    die(): void; // 死亡
    // 
    getType(): UnitStateType
}
// 状态基类,包含一个指向Unit的引用
export abstract class BaseState implements IUnitState {
    protected unitItem: IUnitItem;

    enterState(unitItem: IUnitItem) {
        this.unitItem = unitItem;
    }
    // 获取状态的type值
    abstract getType(): UnitStateType;
    // 状态
    stand() {
        console.log(this.unitItem, "单位准备进入站立状态");
        this.unitItem.setState(new StandingState());
    }
    move() {
        console.log(this.unitItem, "单位准备进入移动状态");
        this.unitItem.setState(new MovingState());
    }
    attack(): void {
        console.log(this.unitItem, "单位准备进入攻击状态");
        this.unitItem.setState(new AttackingState());
    }
    castSkill(): void {
        console.log(this.unitItem, "单位准备进入释放技能状态");
        this.unitItem.setState(new CastSkillingState());
    }
    stun(): void {
        console.log(this.unitItem, "单位准备进入击晕状态");
        this.unitItem.setState(new StuningState());
    }
    die() {
        console.log(this.unitItem, "单位准备进入死亡状态");
        this.unitItem.setState(new DeadState());
    }

}

// 站立状态
export class StandingState extends BaseState {

    getType(): UnitStateType {
        return UnitStateType.Standing;
    }

    // 重写方法
    stand() {
        console.log(this.unitItem, "单位已经进入站立状态");
    }

}

// 移动状态
export class MovingState extends BaseState {

    getType(): UnitStateType {
        return UnitStateType.Moving;
    }

    // 重写方法
    move() {
        console.log(this.unitItem, "单位已经进入移动状态");
    }

}

// 攻击状态
export class AttackingState extends BaseState {

    getType(): UnitStateType {
        return UnitStateType.Attacking;
    }
    enterState(unitItem: IUnitItem) {
        super.enterState(unitItem);
        this.doAction();
    }

    doAction() {
        // 执行攻击
        this.unitItem.role.attack(); // 攻击
        // 如果攻击顺利完成,进行清理并返回到正常状态
        // 例如,设置一个延时来模拟攻击动作的时间
        let attackDuration = 1000
        setTimeout(() => {
            if (this.unitItem.getCurrentState().getType() == UnitStateType.Attacking) {
                console.log('单位已从攻击状态到站立状态')
                this.unitItem.setState(new StandingState());
            }
        }, attackDuration);
    }
    // 重写方法
    attack(): void {
        console.log(this.unitItem, "单位已经进入攻击状态");
    }

}

// 释放技能状态
export class CastSkillingState extends BaseState {

    getType(): UnitStateType {
        return UnitStateType.CastSkilling;
    }

    enterState(unitItem: IUnitItem) {
        super.enterState(unitItem);
        this.doAction();
    }

    doAction() {
        // 执行攻击
        // this.unitItem.role.attack(); // 攻击
        // 如果攻击顺利完成,进行清理并返回到正常状态
        // 例如,设置一个延时来模拟攻击动作的时间
        let attackDuration = 1000
        setTimeout(() => {
            if (this.unitItem.getCurrentState().getType() == UnitStateType.CastSkilling) {
                console.log('单位已从技能释放状态到站立状态')
                this.unitItem.setState(new StandingState());
            }
        }, attackDuration);
    }
    // 重写方法
    castSkill(): void {
        console.log(this.unitItem, "单位已经进入释放技能状态");
    }

}


// 击晕状态
export class StuningState extends BaseState {

    getType(): UnitStateType {
        return UnitStateType.Stuning;
    }

    enterState(unitItem: IUnitItem) {
        super.enterState(unitItem);
        this.stopCurrentAction();
    }
    // 重写方法
    stun(): void {
        console.log(this.unitItem, "单位已经进入击晕状态");
    }

    stopCurrentAction() {
        console.log(this.unitItem, "单位所有动作停止,因为被击晕");
        // 如果有正在进行的释放技能的操作,这里将其中断
        // 这可能包括清除技能计时器、动画等
    }

}
// 死亡状态
export class DeadState extends BaseState {

    getType(): UnitStateType {
        return UnitStateType.Dead;
    }

    enterState(unitItem: IUnitItem) {
        super.enterState(unitItem);
        this.stopCurrentAction();
    }
    // 重写方法
    die() {
        console.log(this.unitItem, "单位已经进入死亡状态");
    }

    stopCurrentAction() {
        console.log(this.unitItem, "单位所有动作停止,因为已死亡");
        // 如果有正在进行的释放技能的操作,这里将其中断
        // 这可能包括清除技能计时器、动画等
    }
}

接着是单位里的

export class UnitItem  extends Component implements IItem, IUnitItem {

    ad: number = 100;
    mp: number = 0;
    role: Fighter;
    private currentState: IUnitState = null;

    accept(visitor: IAttackVisitor) {
        visitor.visitUnitItem(this)
    }


    setRole(role: Fighter): void {
        this.role = role;
    }

    setState(state: IUnitState) {
        this.currentState = state;
        state.enterState(this);
    }
    getCurrentState(): IUnitState {
        if (this.currentState == null) {
            this.setState(new StandingState())
        }
        return this.currentState;
    }
    move() {
        this.getCurrentState().move()
    }
    idle() {
        this.getCurrentState().stand()
    }
    attack(unitItem: UnitItem<T>) {
        if (!this.canAttack()) {
            // 不能处理攻击的逻辑,可能是显示消息或者进入其他状态
            return;
        }
        // 尝试进入攻击状态
        this.getCurrentState().attack()
        let damage = this.ad
        let attackVisitor = new MonomerAttackVisitor(damage)
        unitItem.accept(attackVisitor)

        // 临时 todo 删除
        console.log('假装本次攻击带有击晕效果')
        unitItem.getCurrentState().stun()

    }
    skill() {
        if (!this.canSkill()) {
            // 不能处理攻击的逻辑,可能是显示消息或者进入其他状态
            return;
        }
        // 尝试进入攻击状态
        this.getCurrentState().castSkill()
    }

    die() {
        this.getCurrentState().die()
    }
    private canSkill(): boolean {
        // 检查单位是否可以进行技能攻击
        // 例如,单位是否处于晕眩状态或者攻击是否冷却中
        if (this.mp < 100) {
            console.log('不能处理skill攻击的逻辑,因为魔法值不足100')
            return false
        }
        if (this.getCurrentState().getType() == UnitStateType.CastSkilling) {
            console.log('不能处理skill攻击的逻辑,因为已经处于技能释放中')
            return false
        }
        if (this.getCurrentState().getType() == UnitStateType.Stuning) {
            console.log('不能处理skill攻击的逻辑,因为已经被击晕')
            return false
        }
        if (this.getCurrentState().getType() == UnitStateType.Dead) {
            console.log('不能处理skill攻击的逻辑,因为已经死亡')
            return false
        }
        return true;
    }

    private canAttack(): boolean {
        // 检查单位是否可以进行攻击
        // 例如,单位是否处于晕眩状态或者攻击是否冷却中
        if (this.getCurrentState().getType() == UnitStateType.Attacking) {
            console.log('不能处理攻击的逻辑,因为已经处于攻击中')
            return false
        }
        if (this.getCurrentState().getType() == UnitStateType.Stuning) {
            console.log('不能处理攻击的逻辑,因为已经被击晕')
            return false
        }
        if (this.getCurrentState().getType() == UnitStateType.Dead) {
            console.log('不能处理攻击的逻辑,因为已经死亡')
            return false
        }
        return true;
    }
}

 在非状态对象类中使用时都是用以下的方式调用

this.getCurrentState().stand()
this.getCurrentState().move()

   在方法里面会执行从当前状态到下一个状态所需要的动作

在状态类中,如果需要到下一个状态就需要再状态类中new一个新的状态,如

    castSkill(): void {
        console.log(this.unitItem, "单位准备进入释放技能状态");
        this.unitItem.setState(new CastSkillingState());
    }

接着在下一个状态CastSkillingState中的enterState,方法内其他动作

4、开始使用

  

        let unitItem001 = xhgame.itemFactory.createUnitItem('kuloubing', UnitType.UnitSpine)
        let unitItem002 = xhgame.itemFactory.createUnitItem('kuloubing', UnitType.UnitSpine)

        unitItem001.idle()
        unitItem002.idle()
        unitItem002.skill()
        unitItem002.mp = 100;
        unitItem002.skill()

        unitItem001.setRole(new Cavalry(new Sword()));
        console.log('unitItem001(骑兵)准备使用【剑】对unitItem002发起了攻击')
        unitItem001.attack(unitItem002)

        unitItem001.setRole(new Cavalry(new Bow()));
        console.log('unitItem001(骑兵)准备使用【弓】对unitItem002发起了攻击')
        unitItem001.attack(unitItem002)

  • 7
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 5
    评论
Cocos Creator是一款面向游戏开发者的跨平台游戏开发工具,它集成了Cocos2d-x游戏引擎和Cocos Studio编辑器,支持多种平台上的游戏开发,如iOS、Android、Windows等。 消灭星星是一款基于Cocos Creator开发的游戏。在游戏中,玩家需要消除屏幕上的星星,以获得分数。游戏开始时,屏幕上会随机生成一些星星,玩家可以通过点击相连的星星来消除它们。消除的星星越多,得到的分数就越高。玩家可以通过不断消除星星来刷新高分记录,挑战自己的极限。 在消灭星星游戏中,Cocos Creator提供了丰富的功能和工具,为游戏开发者提供了便利。开发者可以使用Cocos Creator的图形界面编辑器来创建游戏场景、导入资源和设置游戏规则等。同时,Cocos Creator还提供了强大的脚本编写功能,开发者可以使用JavaScript或TypeScript编写游戏逻辑,实现游戏中的各种功能。 除了基本的消除星星玩法,Cocos Creator还支持添加特殊道具、关卡设计、人物角色等功能。开发者可以根据自己的需求,自定义游戏的玩法和功能,使游戏更加有趣和有挑战性。 总而言之,Cocos Creator游戏开发工具提供了强大的功能和便捷的开发环境,使开发者可以轻松地开发出各种各样的游戏,包括消灭星星这样的小而精致的休闲游戏。无论是想要学习游戏开发还是实现自己的游戏创意,Cocos Creator都是一个不错的选择。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值