此日志将总结近半年来代码开发的内容,主要是卡牌桌游的代码实现思路,如果对日志有什么意见和想法的欢迎留言讨论。
后续内容:
1,时机详细分析
一,卡牌游戏的组成元素
以面向对象的思路进行代码实现需要将游戏进行时的内容拆分成一个个元素,经过我以往的游戏经验,一个完整的卡牌游戏由玩家,卡牌,卡牌区域,回合与阶段,效果,时机,指示物等元素组成。在此章节只是简单的阐述每种元素的含义,具体的实现逻辑将会在后续内容详写。游戏在进行描述时,为了避免繁琐,往往会将一些步骤与操作的描述进行简化,在进行代码编写时,需要尽可能的分析清除想要实现的效果,以下将用万智牌进行举例说明.
1,玩家
①参与游戏的玩家,具有唯一标识和玩家组两个属性。
②唯一标识:用来区分玩家。
③回合顺序:用于控制游戏进行时玩家回合的顺序。
玩家组:用来区分敌对和友好关系(适用于多人游戏)。1v1或者多人混战游戏中每名玩家所属玩家组不同,2v2游戏中将会分为两个玩家组。
2,卡牌
卡牌是桌游组成的基础元素。卡牌具有的属性:
①名称,用作标识
②类别,类别有分为主类别与副类别,主类别例如生物,法术,用于规则的制定,让卡牌变得多样化。副类别主要用于增加风味和判定检索。
③特殊数值,例如施放费用和力量,生命等。
④效果集合,让每张卡拥有不同的作用。
3,卡牌区域
卡牌放置的区域,比如手牌栏,坟场,牌库等。另外还会存在一些较为隐藏的区域,例如下图中,【远景烁影】是无法触发【鳞文寇特蛇】的,按照定义来看,
【鳞文寇特蛇】抓一张牌:一张牌从【牌库区域】移动至【玩家手牌区域】
【远景烁影】:将【牌库区域】的四张牌移动至【检视区域】,再将选中的牌移动从【检视区域】移动至【玩家手牌区域】,剩下的牌移回【牌库区域】。
卡牌区域具有的属性:
①一个卡牌集合用来存放属于这个区域的卡牌。
②区域所归属的玩家,例如玩家A与玩家B的牌库是两个区域,有些游戏有公共区域不归属任何玩家。
③区域卡牌数量上限,用来控制牌组上限,手牌上限等。
4,回合与阶段
回合指每个玩家轮流进行操作的循环,阶段指每个回合的流程拆分。
回合的属性:
① 回合所拥有的阶段集合。
阶段的属性:
① 唯一标识code。
② 阶段的序号,用于确定阶段执行的顺序。
③ 是否自动,例如回合的准备阶段与结束阶段是自动执行的,回合的主要阶段(玩家进行打出卡牌操作的阶段)是手动阶段。
④ 阶段的状态,阶段的状态分为开始,执行中,结束。
5,效果
效果是游戏中最重要的一环,是整个游戏的核心。效果可以分为两种,第一种是规则效果,我将游戏的规则部分也纳入了效果,这样更容易进行整个游戏的开发。例如卡牌游戏都会存在一些特殊的模式增加乐趣,如【每召唤一个生物时抽一张牌】,特殊规则相当于在游戏开始时就存在与场上并生效的卡牌。第二种就是卡牌所具有的异能效果。
将效果进行细分,可以分为三个部分
使用上文中 【鳞文寇特蛇】的效果文本进行分析:每当你抓一张牌时,在鳞文寇特蛇上放置一个+1/+1指示物。
①绿色字体标注的【每当你抓一张牌时】,【抓一张牌】就是触发器时机(时机元素将会在下文讲到),其中的【你】就是触发器时机的限制条件。
②黄色字体标注的【鳞文寇特蛇】和【+1/+1指示物】就是效果需要寻找的操作目标,操作目标包括游戏中的每一个元素,玩家,卡牌区域,甚至是效果都可以成为操作目标。【鳞文寇特蛇】的操作目标类型为【卡牌】,名称鳞文寇特蛇为限制条件,【+1/+1指示物】的操作目标类型为指示物类别,+1/+1为限制条件。
③红色字体标注的【放置】就是效果操作,生成一个【+1/+1指示物】放置到【鳞文寇特蛇】上。
6,时机
时机主要用于效果的触发,游戏中将会存在很多时机,例如上文提到的【抓一张牌】,在程序中就是当一张牌从牌库区域移动至手牌区域时将会发送这个时机通知,另外还有当一张牌进入墓地时,当一个生物进行攻击时,等等。
时机是一个比较抽象的概念,属性只有唯一编码来区分不同的时机,具体的内容将会单独与效果一起说明。
7,指示物
指示物并不是游戏所必须具备的,指示物可以视作一种特殊的卡牌,可以放置在其他的元素上提供额外的效果。
8,其他
在游戏中也会存在其他的比较特殊的元素,根据需求,例如在我的项目中,将含有进攻方和防守方的战斗视为一种元素,针对某一元素的统计和判断结果,地形系统等,都是比较抽象的概念,如果有机会写到相关内容时在详细解释。
二,操控元素的管理器
在这一章节将会介绍针对元素的管理与控制。
1,流程控制器
流程控制器主要用到【玩家】与【回合阶段】两个元素。
主要属性有
①当前回合玩家。 ②当前阶段。
具体的一个简单流程如下图所示:
2,时机控制器。
时机控制器中存在一个Map映射,当游戏开始时,将会获取所有效果(卡牌的效果,规则效果)放入到这个map中,其中key为效果对应的时机,value为这个时机将会触发的所有效果集合。当游戏中产生一个新的效果(例如创建了一张牌,一个指示物),也会将其添加到这个Map中。当一个元素,例如卡牌的所属区域发生了变化,某一个阶段的执行,玩家的生命值发生变化。都会发送一个事件到时机控制器中。
一个时机包含的属性有:
①时机的唯一标识
②时机内容,发出时机的元素
③时机执行完毕的回调委托函数。这是一个比较重要的元素,用于处理在一个时机中产生了新的时机的特殊情况。例如【在你的准备阶段开始时你抽一张牌】,这个效果将会在【准备阶段开始时】触发生效,然后将会产生一个【抽一张牌的时机】,需要等待【准备阶段开始时】时机触发激活的所有新时机和效果都结算完毕后,才能进入到【准备阶段执行】,具体的逻辑流程见下图。
④时机的种类
因为属性的第③项,时机控制器有一个队列(Queue,先进先出)来储存等待触发检测的时机,和一个栈(Stack,先进后厨)来储存触发检测完毕的时机。
时机分为两种。一种是普通的触发时机,控制器接收后将会从Map中取出对应的效果集合,通过效果中的时机的限制条件(见上一章节效果部分)来判断效果是否会被触发,将会被触发的效果发送至效果控制器。另外一种则是由于为了流程的合理性而产生的特殊时机,这种时机不会触发效果检测,是为了占用一个时机的位置,例如生物之间发生了战斗,进行伤害计算时将会产生生物受到或者造成伤害的时机,为了避免产生的时机影响到战斗的结算,每一个战斗步骤都将会占用一个时机来完成结算,具体的将会在战斗控制器中详细介绍。
3,效果控制器
在时机控制器中触发的效果将会发送到效果控制器,发送时以组的形式发送(因为同一个时机可能会触发多个效果),在效果控制器中将会有一个队列用来存储这些效果组。
效果控制器将会通过效果的状态来确定进行的操作。
单个效果的状态
New,新建
GoToStack,队列中
InProgress,执行中
Completed,执行完毕
(一)目标的寻找
其中在InProgress执行中状态里,将会首先寻找目标,寻找目标的状态为
UnStart,未开始
LookingFor,寻找中
Finded,寻找完毕
Failure,寻找失败
需要注意的是,寻找目标并不是指寻找单一的目标,很多时候将会存在寻找多个目标,例如【展示你牌堆顶四张牌】,将会寻找到四个目标,还会存在【至多】【至少】【选择其中一个】等多种情况,将会出现等待玩家操作的需求,这里需要产生一个玩家操作发送至操作控制器获取玩家的操作结果(详情见后面的操作控制器)。
当无法找到满足条件的目标时,将会进入寻找失败状态。
当进入玩家操作时,会暂停效果的执行,等待玩家操作完毕后,将操作结果放入目标寻找中,并继续执行效果。
(二)效果的执行
当所有目标寻找完毕后,进入效果执行阶段,会根据相应的操作进行处理,此步骤有可能会产生新的时机,触发新的效果,触发的新的效果组将会存入到队列中等待执行。
【额外内容】不同效果的实现方式,因为我的游戏中效果的处理编辑并没有依赖代码实现(为每一个效果编写一段实现代码),而是通过编辑器的方式进行组合设置。
编辑器如图(请点击),是一种较为复杂的实现方式,甚至都有点后悔使用这种方式,如果你使用代码段来执行效果,可以略过此部分
一些复杂的效果将会由多个子效果组成,或者多个子效果共用同一个对象,就需要设计复合效果。
类型一,如图所示
如上图,【致命暴风】中【消灭所有生物】为执行的第一个子效果,【每位牌手各失去若干生命,其数量等同于由他操控的生物中,以此法被消灭的数量。】为执行的第二个子效果,第二个子效果将会用到第一个效果中的参数。同理,【碎骨贯身】中需要确认【牺牲一个生物】能够执行,才可以执行【消灭目标生物】。
所以需要在效果中为每一个【寻找到的目标组】和【目标操作】设置输出code,可以通过输出code让排序在其后的内容可以访问已经完成的内容。
暂无关于此日志的评论。