Unity3D自带例子AngryBots的分析.docx_第1页
Unity3D自带例子AngryBots的分析.docx_第2页
Unity3D自带例子AngryBots的分析.docx_第3页
Unity3D自带例子AngryBots的分析.docx_第4页
Unity3D自带例子AngryBots的分析.docx_第5页
已阅读5页,还剩5页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

研究一下Unity3d自带的AngryBots项目,了解基本的游戏运行机制:1. 人物的动作控制逻辑*Player对象*外形Player对象里有一个对象具有Skinned Mesh Renderer组件,该组件使用的Mesh名为main_player_lorez。类似的还有表达武器的,名为main_weapon001的GameObject。操作: (InputManager)*移动*定义:移动在InputManager里添加了2种操作方式:水平移动,名为 Horizontal垂直移动,名为 Vertical并设置了一些属性,比如对应的按键,加速度,类型等等。在脚本(PlayerMoveController.js)里,通过Input.GetAxis(“Horizontal”) 和 Input.GetAxis(“Vertical”)获得玩家的按键状态转化成的运动方向。并储存在MovementMotor.js脚本定义的movementDirection变量里。实现:Player添加了RigidBody组件,该组件提供了按物理规律改变GameObject的Transform的能力。在FreeMovementMotor.js脚本里,定义了一些参数,用于和movementDirection一起,计算出作用于RigidBody对象上的力(Force)。角色就开始向指定方向移动了。*面向(facingDirection)*直接使用Input.mousePosition作为屏幕坐标,用角色所在位置定义一个平面,求得射线焦点,将该角色所在位置到该点的方向作为面向。并储存在MovementMotor.js脚本定义的facingDirection变量里。动作播放:Player Animation(Script)(PlayerAnimation.js)var moveAnimations : MoveAnimation; 因为是public变量,所以可以在inspector中直接修改,例子中定义了6个动作 run_forward/run_backward/run_right/run_left 和 idle/turn 。由于这个例子里角色的动作定义了6个clip,和上述6个动作名称一一对应。动作的播放不是在转向发生,或是ASWD按下时发生的。该脚本对比Player的Transform在2帧内的变化,根据面向、移动方向,计算出具体播放哪个动作。同时,有动作混合逻辑,使得动作的切换是有过程并且平滑的。上半身转动到一定角度,下半身也会调整,这个也是逻辑做的功能。2. 从射击到命中的整个处理流程,射击特效的制作原理创建子弹Cache对象ObjectCache类var prefab : GameObject;var cacheSize : int = 10;Spawner.jsvar caches : ObjectCache;function Awake () cachesi.Initialize ();static function Spawn();static function Destroy();有一个对象cache池,即为objectCache对象的实例,该对象初始化固定数量的对象实例,并顺序的提供对象实例。Spawner对象按Prefab类型将多个ObjectCache对象组织起来,并通过Spawn 和 Destroy 函数提供统一的接口来创建和销毁各种对象实例例如子弹,导弹。发射子弹的时机WeaponSlotTriggerOnMouseOrJoystick.jspublic var mouseDownSignals : SignalSender;public var mouseUpSignals : SignalSender;SignalSender.jspublic function SendSignals (sender : MonoBehaviour)public var receivers : ReceiverItem;AutoFire.jsfunction Update ()if (firing) if (Time.time lastFireTime + 1 / frequency) var go : GameObject = Spawner.Spawn (bulletPrefab, spawnPoint.position, spawnPoint.rotation * coneRandomRotation) as GameObject;WeaponSlot(GameObject)对象有一个脚本组件 , 名为TriggerOnMouseOrJoystick该脚本的update方法通过Input.GetMouseButtonDown (0) 来监测鼠标左键的按下状态,同时使用SignalSender对象将事件Fire出去。SignalSender本质上来说是一个发布订阅模式,EventSource通过声明SignalSender变量,来声明会发起的事件(event name),并在必要的时机,调用SignalSender.SendSignals(this)来fire事件。事件的接收方由SignalSender的receivers变量给出。因为它是个全局变量,所以可以在inspector里设置。客户方的处理逻辑和事件源就是通过这样的方式关联起来的。事件的名称也是通过inspector来设置的。SendSignals方法接受的参数为MonoBehaviour类型,因此可以通过这个事件机制,在不同的脚本中调用不同的功能。由于GameObject的SendMessage的实现原理,只需要保证事件的接收方包含与事件名称相同的函数,即会被自动调用。(疑惑:这种方式是不带参数的,如果需要对Event做额外的参数传递怎么办呢?能想到的是在一个公共的地方做数据交换)通过SignalSender,武器的逻辑状态”开火”已经被逻辑识别了,例子将结果保存在AutoFire脚本的firing变量中。开火后,在AutoFire里,激活了子弹的实例对象。开火的特效WeaponSlotAutoFire.jsmuzzleFlashFront.active = true;audio.Play ();通过SignalSender,武器的逻辑状态”开火”已经被逻辑识别了,例子将结果保存在AutoFire脚本的firing变量中。同一时刻,也播放了一些开火的特效:*武器开火的音效,这只是调用AudioSource组件。*武器枪口的火花,muzzleFlashFront对象,在inspector中指定为一个GameObject。其中包含一些Mesh和一个Light,以及一个将Mesh旋转和缩放以达到比较酷的喷射火光的脚本。*人物的射击动作通过另一组监听实现的,不在AutoFire脚本中触发。命中时的事情PerFrameRaycast.jsprivate var hitInfo : RaycastHit;AutoFire.js(命中判定)var hitInfo : RaycastHit = raycast.GetHitInfo ();AutoFire.js(击退敌人)var force : Vector3 = transform.forward * (forcePerSecond / frequency);hitInfo.rigidbody.AddForceAtPosition (force, hitInfo.point, ForceMode.Impulse);AutoFire.js(播放击中的音效)var sound : AudioClip = MaterialImpactManager.GetBulletHitSound (hitInfo.collider.sharedMaterial);AudioSource.PlayClipAtPoint (sound, hitInfo.point, hitSoundVolume);游戏中实现的命中,和子弹飞行无关,是通过PerFrameRaycast.js脚本提供的射线查询结果来做的命中判定。PerFrameRaycast每帧做一次射线查询,将得到的结果保存在hitInfo中。AutoFire在update的时候,检查是否命中了对象。如果命中了对象,计算各种伤害,并调用Health脚本组件的相关方法。(Health相关的事情稍后详细描述)子弹的飞行子弹是一个名为InstanceBullet的GameObject,它由名为InstanceBullet的Prefab对象来描述,主要包含了一个表达子弹轨迹的长条形的mesh,和一个用于控制其飞行的脚本SimpleBullet.js。SimpleBullet.jsfunction Update () tr.position += tr.forward * speed * Time.deltaTime;function Update () if (Time.time spawnTime + lifeTime | dist 0) Spawner.Destroy (gameObject);SimpleBullet.js包含了一些参数,保证子弹有以下行为:沿创建的方向飞行有时限,时间到了会被休眠(Spawner.Destroy)有距离上限,超过距离会休眠(Spawner.Destroy)AutoFire.jsbullet.dist = hitInfo.distance;除了上述2种方式消隐子弹实例外,子弹可以穿过场景里的石头,但是无法穿越箱子,也无法穿越将石头移开后露出的场景边界。这是因为在AutoFire做命中判定的同时,根据射线查询的结果调整了子弹的距离上限参数。3. 怪物的激活、攻击、动作控制原理,你所遇到的第一个怪物KamikazeBuzzer的攻击特效的实现原理第1个KamikazeBuzzerSimpleBuzzers7EnemyArea.jsBox ColliderKamikazeBuzzerKamikazeMovementMotor.jsBuzzerKamikazeControllerAndAi.jsDestroyObject.jsHealth.jsAudioSource外形buzzer_bot动作这个怪物的mesh没动作。激活EnemyArea.jsfunction OnTriggerEnter (other : Collider) if (other.tag = “Player”)ActivateAffected (true);角色进入 Box Collider 的范围时,会触发OnTriggerEnter,这时会将SimpleBuzzers7的子对象KamikazeBuzzer设置为激活的。挂载到KamikazeBuzzer对象上的脚本组件也就可以开始执行了。移动KamikazeMovementMotor.js该脚本控制KamikazeBuzzer的刚体属性,根据参数和一定的计算规则计算出力,作用于刚体,让KamikazeBuzzer动起来,类似于Player的移动原理。BuzzerKamikazeControllerAndAi.js该脚本根据怪物和Player之间的位置关系,按一定计算规则算出KamikazeMovementMotor需要的参数,从而达到控制其移动的目的。direction = (player.position character.position);因为方向总是朝着player,所以看起来就有个“追击”的效果。rechargeTimer 0.8f 这个判断达到了“追过头”的效果。攻击特效当移动流程里“追到了”条件达成后,主要调用DoElectricArc函数来表达攻击方式。zapNoise = Vector3 (Random.Range (-1.0f, 1.0f), 0.0f, Random.Range(-1.0f, 1.0f) * 0.5f;zapNoise = transform.rotation * zapNoise;这里有些小随机,是为了让每次电到Player的位置不一样。public var electricArc : LineRenderer;electricArc.SetPosition (0, electricArc.transform.position);electricArc.SetPosition (1, player.position + zapNoise);主要靠LineRenderer来描述闪电弧。LineRenderer用来构造若干条连续的线段,可以设置起始的宽度和结束的宽度。被击DamagePos(GameObject)Transform(Component)KamikazeBuzzer(GameObject)Health.jsHealth.jsprivate var damageEffect : ParticleEmitter;function OnDamage (amount : float, fromDirection : Vector3) damageEffect.Emit();DamagePos对象聚合了一个Transform组件,该组件为被击效果提供坐标信息。KamikazeBuzzer聚合了一个Health.js,其中的damageEffect指定为ElectricSparksHitA(prefab)。在之前子弹的命中流程中,被击中的target,会调用其Health组件的OnDamage函数。KamikazeBuzzer的Health的OnDamage,就是创建ElectricSparksHitA(Clone) 对象,从而达到播放被击特效。死亡和爆炸Health.jspublic var dieSignals : SignalSender;function OnDamage (amount : float, fromDirection : Vector3) if (health = 0)dieSignals.SendSignals (this);SpawnObject.jsfunction OnSignal () spawned = Spawner.Spawn (objectToSpawn, transform.position, transform.rotation);DestroyObject.jsfunction OnSignal () Spawner.Destroy (objectToDestroy);当health值减少到0及0以下,对象就被判定为死亡了。DamagePos对象聚合了一个SpawnObject.js脚本。在其OnSignal函数里创建一个ExplosionSequenceBuzzer(prefab);ExplosionSequenceBuzzer是用来表达爆炸效果的。在其EffectSequencer.js脚本中,控制了一些粒子的变化。KamikazeBuzzer对象聚合了一个DestroyObject.js脚本。在其OnSignal函数里销毁了KamikazeBuzzer对象实例。4. 人物与怪相关的health处理相关流程Player和怪物的血量,都是通过聚合一个Health.js脚本组件来完成。伤害计算则是在各自的组件里独立编写计算的。Player是AutoFire,KamikazeBuzzer是在其AI脚本里。Health组件主要定义了血量被击特效受伤的痕迹被击事件死亡事件协作方式已经在分析Player和KamikazeBuzzer的行为方式时有所表述。5. 摄像机跟随与控制PlayerMoveController.js里面根据角色位置计算摄像机位置。根据鼠标位置,微调摄像机位置。6. 雨滴相关效果的实现原理,包括雨滴掉落、落到地面产生的波纹、地表水面的实现与反射效果等【雨滴】相关GameObjectRain 表达雨声RainBox 表达雨滴RainEffect 将各种东西组织起来的Root对象RainDrops 雨滴掉落的Root对象RainslpashesBig 表达雨滴的大涟漪的Root对象RainslpashesSmall 表达雨滴的小涟漪的Root对象splashbox 表达涟漪Mesh&MaterialRainDrops_LQ0/1/2RainsplashesBig_LQ0/1/2RainsplashesSmall_LQ0/1/2ShaderRainRainSplash组织关系Environment(dynamic)RainEffects(位置000)RainDrops(RainManager.js)RainBox*NRainBox.jsRain(Shader)RainDrops_LQ0(Mesh)RainslpashesBig(RainsplashManager.js)splashboxRainsplashBox.jsRainSplash(Shader)RainsplashesBig_LQ0(Mesh)RainslpashesSmallsplashboxRainsplashBox.jsRainSplash(Shader)RainsplashesSmall_LQ0(Mesh)落雨RainManager.jsfunction CreateMesh () : Mesh public function GetPreGennedMesh () : Mesh RainManager 在运行期创建了雨幕的Mesh和Material,思路为在固定大小的长方体里,随机生成只有4个顶点的小片。生成的对象和名字有关,即为 GameO + _LQ0/1/2,一共3种类型的Mesh,只是生成的片的位置,uv坐标等不一致。RainBox.jsfunction Update() function OnDrawGizmos () Update里的逻辑让雨幕Mesh在Y方向上从上自下的循环运动,从而达到雨滴落下的效果。OnDrawGizmos函数是为了在编辑期绘制雨幕的外形。涟漪的创建RainsplashManager.jsRainsplashBox.js涟漪的创建方式和雨幕原理一样,只是在小片生成时的坐标,法线方向略有不同。大涟漪和小涟漪只是创建的片的数量和区域大小不同而已。涟漪的扩散RainSplash(Shader)里,对传进来的定点上的uv坐标和颜色做了一定的变换,从而做出涟漪从小变大和逐渐消隐。(疑问)材质从哪里指定的?inspector手工指定?(疑问)RainBox.js 里的enable,禁止和允许了哪些调用?【地表水面与反射】相关GameObjectpolySurface5097地表RealtimeReflectionInWaterFlow.shader处理水面模拟和反射的shaderMain CameraReflectionMain Camera反射摄像机RealtimeReflectionReplacement.shader备用的shader方案Main Camera主摄像机ReflectionFx.cs生成反射贴图的脚本public System.String reflectionSampler = “_ReflectionTex”; 反射贴图reflectionMask关键代码ReflectionFx.cspublic Transform reflectiveObjects;private Camera reflectionCamera;public LayerMask reflectionMask;计算反射摄像机的位置和朝向,将变换合并为反射矩阵渲染到反射贴图RealtimeReflectionInWaterFlow.shader_ReflectionTex(“_ReflectionTex”

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论