Unity 子弹做法总结

来源:互联网 发布:mac docker 教程 编辑:程序博客网 时间:2024/04/29 01:16


纯粹 "子弹" 的话. Unity自带的例子 AngryBots 中给出了一种做法.发射时利用射线检测射击到的目标点.直接给予伤害及特效音效表现.而子弹只是作为一道快速的直线飞过.并没有什么判断逻辑.代码如下( JS版 ):

发射 : 

// Spawn visual bulletvar coneRandomRotation = Quaternion.Euler (Random.Range (-coneAngle, coneAngle), Random.Range (-coneAngle, coneAngle), 0);var go : GameObject = Spawner.Spawn (bulletPrefab, spawnPoint.position, spawnPoint.rotation * coneRandomRotation) as GameObject;var bullet : SimpleBullet = go.GetComponent.<SimpleBullet> ();lastFireTime = Time.time;// Find the object hit by the raycastvar hitInfo : RaycastHit = raycast.GetHitInfo ();if (hitInfo.transform) {// Get the health component of the target if anyvar targetHealth : Health = hitInfo.transform.GetComponent.<Health> ();if (targetHealth) {// Apply damagetargetHealth.OnDamage (damagePerSecond / frequency, -spawnPoint.forward);}// Get the rigidbody if anyif (hitInfo.rigidbody) {// Apply force to the target object at the position of the hit pointvar force : Vector3 = transform.forward * (forcePerSecond / frequency);hitInfo.rigidbody.AddForceAtPosition (force, hitInfo.point, ForceMode.Impulse);}// Ricochet soundvar sound : AudioClip = MaterialImpactManager.GetBulletHitSound (hitInfo.collider.sharedMaterial);AudioSource.PlayClipAtPoint (sound, hitInfo.point, hitSoundVolume);bullet.dist = hitInfo.distance;}else {bullet.dist = 1000;}

子弹 : 

function Update () {tr.position += tr.forward * speed * Time.deltaTime;dist -= speed * Time.deltaTime;if (Time.time > spawnTime + lifeTime || dist < 0) {Spawner.Destroy (gameObject);}}


这样虽然逻辑上看是子弹表现和伤害表现有先后.但只要子弹速度够快.是感受不出来的.

这里的 够快 指的速度至少是1秒内子弹能飞到目标点.然后伤害表现上稍微做个缓冲效果.就没有问题.


但有时我们想要的"子弹"表现不仅仅是这样快速飞过去的.还可能是稍慢速的炮弹.曲线轨迹的导弹.穿透型的导弹.这样一来预先算好爆炸点的方式就不适用了.只能加Collider做实时碰撞.


在各种尝试之后发现,想使用Unity的RigidBody来控制子弹运动.是不合适的.有以下问题.

1.Unity的物理运动是放在FixUpdate中计算的.与渲染的帧数不同步.会导致物体运动看起来一卡一卡.可以通过设置 Rigidbody.interpolation 为 RigidbodyInterpolation.Interpolate来解决.但发现碰撞检测有延迟.即已经穿透一段距离后才发出碰撞消息.

2.可能穿透物体.

3.碰到后会被撞开.无法做穿透效果.

单个问题来看.

2可以通过设置 Rigidbody.detectCollisions = Continuous来解决

3可以通过设置Rigidbody为IsKinematic为ture.自己控制transform来解决

但一旦设置了IsKinematic.则1和2的设置等于无效.不过因为是自己控制.放在Update中改变位置.则1的问题不复存在.主要是2.


假设认为慢速子弹不存在穿透问题.那么将快速子弹使用射线的方式.慢速子弹使用Collider的方式.似乎就解决了问题.但如果是一个曲线轨迹的快速子弹.似乎两种都不合适.

难道每帧检测飞行方向上的射线?1可能有效率问题.2在曲线拐弯处的路径补偿计算会比较复杂.


综上所述.最后尝试使用了一种动态调整Collider大小的方式来解决以上问题.即根据当前的deltaTime和自身速度来动态调整Collider大小.将自身大小调整到与一帧移动距离相同.则可以避免穿透问题

void ReCalculeteSize( bool bFront ){BoxCollider bc = gameObject.GetComponent<BoxCollider>();if( bc == null )return;float fNewSize = m_BulletType.fSpeed * Time.deltaTime;fNewSize -= 0.4f;if( fNewSize < m_BulletType.fSize )fNewSize = m_BulletType.fSize;bc.size = new Vector3( m_BulletType.fSize, 5f, fNewSize * transform.localScale.z );float fNewCenterZ = 0f;if( bFront ){fNewCenterZ = -fNewSize / 2 + m_BulletType.fSize;if( fNewCenterZ > 0 )fNewCenterZ = 0f;}else{fNewCenterZ = fNewSize / 2 - m_BulletType.fSize;if( fNewCenterZ < 0 )fNewCenterZ = 0f;}bc.center = new Vector3( 0f, 0f, fNewCenterZ);}


最后.如果想自己控制position.要设置 IsKinematic 为 true. interpolation 一定要设为None


0 0