请问如何实现两人对战,使用同一牌库抽牌和出牌的功能?



  • 对战双方使用的是同一牌库,且第一次每人抽4张,之后每轮每人抽两张。但当牌库空时自动把牌库补满(即牌库中重新出现所有牌)



  • 需要其中一方作为数据计算方(例如可以自己认定回合状态为“自己回合”的一方作为数据计算方),数据计算方负责随机牌库,并在随机完牌库后,把牌库数据传给对方,以确保双方用的牌库顺序、卡牌数量等数据一致,然后每有一方抽牌,双方就各自自己从牌库中减去牌即可,只有重置牌库时才只由数据计算方随机牌库并传给对方。



  • @欧拉欧拉 您好,您说的意思我明白啦!那,请问要怎么设置随机牌库并且实现出牌和洗牌效果呢?



  • @繁华4231 牌库可以存在数组里,数组的x编号顺序就是牌库的卡牌顺序,洗牌其实就是把弃牌堆的所有卡牌重新设置给牌库,然后打乱牌库顺序,所以还需要一个弃牌堆,这个也可以用数组来做,每次使用完卡牌后,就把弃牌堆数组在x轴上加1行并设置刚刚打出的牌的数据,表示有一张牌进入了弃牌堆。当牌库数组由于抽牌导致x轴元素(也就是数组宽度)为0时,表示牌库抽完了,用“从字符串读取”动作,读取弃牌堆数组的表达式asjson,就能将弃牌堆数组的数据复制过来,表示弃牌堆的牌成为了新的牌堆,然后需要清空弃牌堆,这个设置弃牌堆数组宽度为0即可,这时我们拿到了一个新的牌堆,但它里面的卡牌顺序是之前的出牌顺序,所以还需要将它打乱才能达到洗牌的效果,这点可以给这个数组的y轴加1个元素,并通过random表达式设置一个随机数给它,这样每一行x轴数据就都有了一个随机数,然后对这个随机数所在的y编号进行排序即可,由于随机数有高有低,重新排序后自然会打乱原先的顺序,也就完成了数据上的洗牌操作。
    抽牌的话,则固定从牌库数组x编号=0的那一行获取数据,并在数据获取后删除这行数据即可。
    如果不是对数组比较熟悉的话,上面这个思路看起来应该会比较懵,可以先研究一下数组的用法,再来研究这个思路,简单来说就是通过数组模拟现实中牌库、弃牌堆的操作流程而已。



  • @欧拉欧拉 您好,您说的逻辑我大概明白了,但是,请问要怎样“把牌库存在数组里”呢?😖



  • @繁华4231 卡牌一般会有一些信息的,例如“卡牌名称”、“卡牌效果”之类的,每张卡的卡牌名称一般是唯一的,当然也有多张相同卡的那种设计(例如扑克牌里所有牌,从图案+数字/字母的角度讲,它们每张牌都是唯一的,而只从数字/字母的角度讲,除了鬼牌其他牌都有4张重复的),假设你不需要把每一张牌都认定成独立的一张卡牌,那把卡牌名称存在数组里即可,数组就像是一个表格,有多少个格子就能填多少个数据,只需要指定好格子的x编号和y编号(其实还有z编号,但一般很少用,所以可以不管),就能拿到对应格子的数据,想象一下,假设现在有一个表格,只有一列数据,如下:
    undefined

    那这列数据其实就像摞起来的一个卡组,然后现在抽牌,其实就是获取最上面的,也就是x编号等于0的那个数据,然后数据拿到了,我们就能根据这个数据判断这张牌是什么卡牌,需要做什么处理,例如图中我们拿到的数据是“卡牌A”这串字,那我们就根据这串字去把卡牌A的实例创建出来,把卡牌A需要用到的一些数据都赋予给它,从画面上营造出抽卡的效果。
    这个就是大致的思路,实际上会复杂一些,因为这个过程其实是把数据和画面表现进行了分开的处理。
    其实我还见过有人用一种取巧的方式做过抽卡,不用数组,而是把所有卡牌事先创建好,只是放在画面外或者隐藏起来不让玩家看见,然后通过实例筛选来使特定的卡出现在画面上,不过这种方式其实做联机对战时我个人觉得反而会比较麻烦。



  • @欧拉欧拉 您好,我已经把所有的卡牌放进了一个同类组,假设一共3种卡牌,每种有4张(同类组里就是5种的),那么请问需要按您的举例,在创建的数组中把每张卡的名称写出来(一共12个)吗?
    最重要的疑问:请问要如何实现将数组中的元素与实际卡牌(即同类组里的精灵)联系起来呢?
    (抽牌部分我的设想就只是把牌从牌库里抽出来,也就是显示到屏幕上,暂时不需要实现卡牌本身的能力(如攻击等))
    您说的那个不用数组抽卡的例子我也看到了,但是实现起来确实不是很方便,所以就更不知道该怎么处理了😢



  • @繁华4231 直接编辑数组的初始值就行,在对象库里我记得双击数组就能打开编辑界面,因为你说的数量不算多,直接写反而方便点,如果数量特别多,可以通过观察卡牌的规律结合循环来写,或者是通过xml组件导入外部数据,但是后两个方法其实对你目前来说反而比较麻烦。
    至于你提到的联系起来,其实可以把对应卡牌的对象名作为数组的数据,例如你有“卡牌A”、“卡牌B”、“卡牌C”、“卡牌D”四个对象,然后都归属在同类组“卡牌组”里,然后你数组里存放的也是这些对象名,那么获取到对应对象名时,就能通过获取的数据直接用动作“按名称创建实例”来创建对应的卡牌精灵,然后通过条件选取最新创建的“卡牌组”实例,去做创建时的后续操作,比如下面这样:
    undefined
    效果_抽卡表现(按名称创建对应的实例后,通过在子事件选中“精灵组”的最新创建的实例,让创建的不同精灵由同类组做统一操作):
    undefined
    效果_数组中的数据变化(可以看到数组的width一直在减少,数组里的数据就像被抽卡抽走了一样,每次都删去x编号为0的那个数据):
    undefined
    我之前其实也有做过一个范例给坛友,但做法上是把所有卡牌用同一个对象的不同动画帧来处理的,如果你感兴趣也可以看看
    https://bbs.evkworld.com/topic/1128/%E5%A6%82%E4%BD%95%E5%AE%9E%E7%8E%B0%E7%B1%BB%E4%BC%BC%E6%9C%88%E5%9C%86%E4%B9%8B%E5%A4%9C%E5%92%8C%E6%9D%80%E6%88%AE%E5%B0%96%E5%A1%94%E7%9A%84%E6%8A%BD%E6%89%8B%E7%89%8C/2?_=1620351129521



  • @欧拉欧拉 您好,您说的这个抽牌的功能我实现啦😊 ,那请问要怎样实现抽出的牌为随机(也就是洗牌)呢?您前面提到的
    “给这个数组的y轴加1个元素,并通过random表达式设置一个随机数给它,这样每一行x轴数据就都有了一个随机数,然后对这个随机数所在的y编号进行排序即可,由于随机数有高有低,重新排序后自然会打乱原先的顺序,也就完成了数据上的洗牌操作。”
    意思我理解了,但是我不知道要怎么实现,目前我只设置了触发条件为:当数组容量=12时(假设12张牌),不知道实现动作应该怎样设置😥



  • 上面演示抽牌的时候,可以看到数组的height只有1,也就是只有一列数据,洗牌这个其实就相当于多加1列数据,但是这列数据的值是随机的,这样一来每一行的第一个数据就是“卡牌名称”,第二个数据就是一个随机数,然后通过数组的“整体排序”动作,以随机数所在的那一列为排序依据,就能重新排序所有行的位置,而由于每一行的随机数都大小不一,这样一番排序就反而达成了打乱原有排序的效果,也就起到了洗牌的效果了,具体范例如下:
    undefined
    效果如下,逗号前的那个数据,就是每一行的第一个数据也就是“卡牌名称”,每一次执行洗牌,你都可以看到这个数据的上下排序在产生变化,具体逻辑就如上面提到的,而由于你抽牌只需要引用每行的第一个数据,所以即使后面加了新的一列随机数,其实也不会干扰到之前的抽牌逻辑。
    undefined



  • @欧拉欧拉 您好,洗牌功能我也实现啦,现在摸牌方面还有最后一个小问题,就是请问怎样能像您的这个例子一样,卡牌出现的位置不同呢?我按您这一个模板试了一下,但是还是无法实现这个效果🤕
    以下是您的举例:
    undefined



  • @繁华4231 其实这种效果看起来好看,但加上后续的其他功能的话,处理起来可能会比较复杂,我个人是不太推荐直接从这个效果开始做的😂 ,如果你想了解一下这个逻辑,我倒是可以简单讲讲:
    主要逻辑是下面这两个事件,核心内容是红框这一句,这一句会把所有的手牌计算好它们在手牌中的位置,并设置到它们各自的变量中,这样每张牌都有一个各自的手牌位置,方便取消出牌、抽牌等情况时每张牌都移动到自己的目标位置,但这一句毕竟只是数据上的,并不会实际把卡牌移动到目标位置。
    undefined
    把卡牌移动到目标位置的是第11号事件,这个事件的条件是卡牌不被拖拽时才会持续生效,动作部分是一个卡牌的设置位置动作,设置位置里用到了lerp这样一个表达式,这个表达式lerp(a,b,c)的效果是返回ab之间以c为比例的值,具体的计算公式大概是a+(b-a)*c,例如lerp(2,12,0.1)的值就是3,而这里填的三个值是 卡牌.x、卡牌.手中位置x和10*dt,最后的10*dt大约是1/6的意思,换成其他小数值也可以,这里lerp的主要作用是返回卡牌的当前x坐标和目标x坐标之间1/6比例的值,由于当前x坐标每次都会因为上一次设置而变成新的值,所以当前x坐标和目标x坐标在这个表达式下每1帧(1/60秒)都会缩短1/6的距离,所以两者随着时间推进会无限接近,y坐标同理,两者结合就从视觉上就产生了一种先快后慢移动到目标位置的效果。
    效果上比较好看,但也相对比较麻烦,其实直接设置位置到目标位置会更直接一点,不过可能就没那么流畅的感觉,比较生硬。因为我这个卡牌是单一的对象,你的卡牌是同类组,所以具体的细节上自然会有不同的处理,没能顺利实现可能是有什么其他事件干扰了,或者写错了哪些部分之类的,这个可能就需要慢慢排查测试了。



  • @欧拉欧拉 实现啦!谢谢您!


登录后回复