【精品教程】Cocos游戏《FantasyWarrior3D》结构分析

FantasyWarrior3D 是基于Cocos2d-x+Lua的一款3D开源游戏项目,使用Cocos Code IDE开发。

d5f6705814b15a44acfd43900a24a613.jpeg

假设大家都了解Cocos(3.3rc0),以及用过Cocos Code IDE(1.01)。这篇文章主要的内容是这个游戏的的实现思路,具体细节会暂时(就)跳(是)过(懒)。

游戏总共有四个场景,分别是

7f7707f7f2391e293dc26bc7fbdbb413.jpeg

我们着重讲一下BattleScene这个场景的结构

BattleScene的层次

21e6240967fefbf0f0fada8f1221ec2e.jpeg

这个层次还是比较简单的。一个Scene加一个Layer,其他元素都是AddChild到Layer上,包括英雄和怪物。其中比较特殊的是camera,这是一个摄像机对象,用来控制画面远近、视角等,另外uiLayer是挂在camera上的(我们在摄像机跟踪一节解释这个做法)

然后绝大部分逻辑由gameController这个定时器函数来控制,其中包括碰撞检测、攻击指令、摄像头跟踪、以及游戏主逻辑。这个定时器函数每一帧都会被引擎调用。

7f20c445e5e53638c45add2c03e5dfed.jpeg

最后currentLayer支持触摸,这个用来触发英雄的特殊技能和控制镜头。

碰撞检测

collisionDectect是gameController内第一个被调用的函数,用来检查所有游戏中的所有角色。如果角色离的太近,会让他们’推‘开;如果超过游戏场景边缘,会把他们’挪‘回来。

每一个游戏角色有一个圆形区域,这个区域大小由_radius决定;另外它有重量,由_mass决定;

所有有效的游戏角色都被放入了HeroManager和MonsterMananger内,所以碰撞检测的逻辑就是:取出每一个角色,与剩下的角色进行计算距离,小于两者半径只和判定为发生‘碰撞’;按两者中心点的直线方向,计算应该后退的距离,设置新的位置坐标(由重量决定后退的比例)。

碰撞检测结束后,会顺便检测角色是否超过预先设定的场景边缘位置,这在isOutOfBound内实现。

注意,碰撞检测不会处理已经‘死亡’的游戏角色,碰撞检测中HeroManager和MonsterManager会移除死亡的游戏角色。

摄像机跟踪

在我们的游戏中,摄像机有两种跟踪方式:

第一种跟随三个主角所在位置自动移动,同时根据玩家手指移动稍微改变位置;

第二种是游戏角色释放特殊技能时切换特殊的视角;

这两种摄像机跟踪都在同一个函数moveCamera内实现,核心逻辑是通过setPosition3D不断改变摄像机的位置,同时通过lookAt让摄像机‘看’向正确的位置。你可以想象一支笔的两端,一端是摄像头位置,一端是它‘看’的位置。

另外,由于摄像机位置需要从A点改变到B点,看的位置从a点到b点,我们不能直接setPosition3D(B)和lookAt(b),而是需要计算从A到B,以及从a到b的差值位置。在游戏中我们通过cc.pLerp(A, B)来计算得到需要逐步移动的位置。

在BattleScene的onTouchMoved函数内,玩家通过触摸改变cameraOffset的值,接摄像机位置会随这个值改变,于是实现了玩家在限制范围内控制摄像机位置的功能。

最后,我们把uiLayer挂在摄像头上(addChild),就是由于摄像机位置一直变化。如果放在currentLayer上,摄像机一移动,UI界面就看不到了。现在uiLayer会随着摄像机移动改变位置,所以我们就能一直看到UI界面,这就像你带了一副眼镜,不管你怎么转头,眼镜架还是在你鼻梁上。

最后用几张图来表示摄像机在3D空间的位置和移动的方式(待补)

UI层

这一层用来显示游戏角色头像、血量、愤怒值,角色受到攻击头像会震动,角色死亡后会变成黑白色,可以触摸角色头像触发特殊技能攻击敌人,胜利时显示成功界面。

值得一说的是,我们把UI层逻辑和游戏逻辑拆分开,用注册消息\函数回调的方式来解决数据传输的问题。

在BattleScene中,我们注册了BLOOD_MINUS,ANGRY_CHANGE消息,用来接收血量变化、愤怒值变化,通过回调函数boodMinus,angryChange,调用uiLayer改变血量,愤怒值。

角色类结构

游戏角色类都放在actors文件夹下,它们的关系如下

d1b47e1a3e238e3d7a3781efa5defb98.jpeg

每个游戏角色在创建的时候,都拥有一个自身update函数,运行时每帧调用一次。这个update函数负责调用如下逻辑:

afdc6dadef332ce7b6ce7ddde7e9d7fd.jpeg

baseUpdate函数,它负责定时执行角色的AI逻辑(具体内容我们在角色AI一节解释)。

stateMachineUpdate函数,它负责根据目前角色状态值让角色表现对应状态的动作、动画。

movementUpdate函数,它负责两件事情,一是在不断改变自己的位置,让角色在游戏中移动;二是改变旋转角度,让角色面向目标方向。

角色的状态机

角色的状态在GlobalVariables.lua文件中定义,由下图几个状态组成

5989351aac1d11622d54c1fb6eac8566.jpeg

角色的状态被stateMachineUpdate控制,不断的在以上六种状态中切换,切换的逻辑如下图:

9230f2aa1b2290ace0683233b45cd667.jpeg

  • walkUpdate的逻辑是:如果角色已经有一个目标(角色AI中实现),如果目标在攻击范围内,就切换到attackMode;如果不在攻击范围,继续移动过去。如果没有目标,继续往右走,如果右边不能再走了,就停在那里发呆(移动在movementUpdate里实现)。

  • attackUpdate的逻辑是:每次攻击需要花一定时间,首先判断是否到了下一次攻击的时间;如果是,根据概率发出普通攻击或者特殊攻击,然后播放攻击动画。特殊攻击的时候做三件事情,一、除了发技能的角色意外的游戏画面全部暗下来(通过发送SPECIAL_PERSPECTIVE消息,调用回调函数实现);二、让摄像头移动,形成特写效果;三、通过setTimeScale降低scheduler的速度,形成慢动作效果。此外无论是特殊攻击还是普通攻击,会生成攻击环(这个在攻击指令一节中说明)。

  • knockingUpdate的逻辑是:每次被击中需要一定时间播放受击动画,首先判断被攻击动画是否播放结束;如果是,判断目标是否在自己的攻击范围内,如果是,进入attackMode,如果不是,切换到walkMode。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值