- 最后登录
- 2014-10-23
- 注册时间
- 2011-7-19
- 阅读权限
- 90
- 积分
- 81303
- 纳金币
- -1
- 精华
- 11
|
生命值(Hit Points)
脚本Explosion和MachineGun已经展示了当物体被击中时(火箭弹或子弹),如何设定毁伤程度,并把伤害值传给周围的游戏物体。但是,游戏物体并不知道这些值意味着什么。
游戏物体的健康程度可以通过使用变量hitPoints来进行跟踪。每个物体都有自己的生命值(根据物体自身的生命强度)。每个游戏物体也应该对伤害有所反应并使用了ApplyDamage()函数(注意,这正是Explosion和MachineGun脚本中调用的用来产生伤害函数)。这个函数将会根据伤害程度降低游戏物体的生命值,并在生命值为零时调用其它函数来产生一定的变化(例如死亡或爆炸)。
下一节我们来看看如何使用生命值(hitPoints)和函数ApplyDamage()
爆炸的桶子(Exploding Barrels)
下面的脚本是通用脚本,所以可以作为一个部件加载在任何可以产生毁伤的物体上。DamageReceiver脚本代码如下:
var hitPoints = 100.0;
var detonationDelay = 0.0;
var explosion : Transform;
var deadReplacement : Rigidbody;
function ApplyDamage (damage : float)
{
// We already have less than 0 hitpoints, maybe we got killed already?
if (hitPoints <= 0.0)
return;
hitPoints -= damage;
if (hitPoints <= 0.0)
{
// Start emitting particles
var emitter : ParticleEmitter = GetComponentInChildren(ParticleEmitter);
if (emitter)
emitter.emit = ***e;
Invoke("DelayedDetonate", detonationDelay);
}
}
函数对被击中或被爆炸影响的物体应用毁伤效果。如果物体生命值已经是0或者更少,不会有任何效果,否则生命数值会根据毁伤效果不断减小。当生命值比零还小的时候就会调用DelayedDetonate函数(延迟只是为了爆炸效果更酷,没别的原因)。
function DelayedDetonate ()
{
BroadcastMessage ("Detonate");
}
这就是引爆游戏物体和其子物体的方法
function Detonate ()
{
// Destroy ourselves
Destroy(gameObject);
// Create the explosion
if (explosion)
Instantiate (explosion, transform.position, transform.rotation);
如果桶子上加载了爆炸预制,那么生命值为0是就会显示这个爆炸预制。
// If we have a dead barrel then replace ourselves with it!
if (deadReplacement)
{
var dead : Rigidbody = Instantiate(deadReplacement, transform.position,
transform.rotation);
// For better effect we assign the same velocity to the exploded barrel
dead.rigidbody.velocity = rigidbody.velocity;
dead.angularVelocity = rigidbody.angularVelocity;
}
如果游戏物体还有一个死亡状态,那么桶子爆炸,然后用这种死亡状态代替这个游戏物体。同时要注意方向的一致性。
// If there is a particle emitter stop emitting and detach so it doesnt get destroyed
// right away
var emitter : ParticleEmitter = GetComponentInChildren(ParticleEmitter);
if (emitter)
{
emitter.emit = false;
emitter.transform.parent = null;
}
}
// We require the barrel to be a rigidbody, so that it can do nice physics
@script RequireComponent (Rigidbody)
下面我们在几个桶子上使用DamageReceiver脚本。先插入一些资源:
拖放Objects/crateAndBarrel/barrel物体到场景中
对桶子(barrel)添加刚体属性
给桶子增加一个盒子碰撞器(box collider)。根据桶子大小调节盒子碰撞器大小。在盒子碰撞器参数栏中的Size中调节。
层级栏中,把脚本DamageReceiver付给桶子
把标准资源库中的explosion预制付给Explosion变量(在桶子的毁伤接收器属性中)
创建一个新预制Barrel(注意大写B,插入的模型桶子名字是小写b)
把设置好的桶子物体(barrel)从层级栏中拖放到工程栏中的新建的预制上
增加几个Barrel到场景(直接复制即可)
运行游戏
你可能注意到,当桶子爆炸后,它仅仅就只消失了,我们还需要添加一个爆炸后的桶子的来代替它。
创建一个新预制Barrel-dead
把原始桶子物体付给预制(从文件夹Objects/crateAndBarrel中导入的)
此时,桶子(Barrel)和爆炸后的桶子(Barrel-dead)看上去是一样的,因为他们的纹理一样(barrel1)
我们需要炸后的桶子纹理跟桶子纹理不一样,这样玩家才知道爆炸没爆炸,类似烧毁的纹理。仅仅调节barrel1是不行的,必须创建一个新的材质付给Barrel-dead。首先复制材质barrel1,调节成烧毁的样子。
工程栏中选择barrel1材质(点击Barrel-dead,在参数Mesh Renderer中点 Materials,然后工程栏中会高亮显示barrel1)
复制材质barrel1(Ctrl+D),重命名为barrelDead。注意,复制的材质会自动命名为barrel2
设定材质,在参数Main Color中把颜色调为黑色
工程栏中选择Barrel-dead,材质栏中下拉菜单选择barrelDead
比较两个材质的不同
下一步,点选Barrel-dead,为其增加盒子碰撞器和刚体属性
把Barrel-dead配置到Barrel的Dead Replacement参数中
运行游戏,将会出现桶子爆炸前后不一样的效果
防卫机枪(Sentry Gun)
最后我们在游戏中增加一个敌人,一挺防卫机枪。防卫机枪将自动寻找玩家,并进行射击。
首先插入机枪模型:
把Object/weapons文件夹下的sentryGun物体拖放到场景中
给机枪增加box collider和rigidbody属性
调节下盒子碰撞器大小,使他包裹炮塔上机枪管
把脚本DamageReceiver付给机枪
现在我们来解释下防卫机枪的脚本代码。全代码如下SentryGun:
var attackRange = 30.0;
var shootAngleDistance = 10.0;
var target : Transform;
function Start () {
if (target == null && GameObject.FindWithTag("layer"))
target = GameObject.FindWithTag("layer").transform;
}
函数Start检测是否给机枪赋予了一个目标物体(参数面板中可以设置),但在参数面板中把Player标签付给参数会更方便(马上来操作)。
function Update () {
if (target == null)
return;
if (!CanSeeTarget ())
return;
// Rotate towards target
var targetPoint = target.position;
var targetRotation = Quaternion.LookRotation (targetPoint - transform.position,
Vector3.up);
transform.rotation = Quaternion.Slerp(transform.rotation, targetRotation,
Time.deltaTime * 2.0);
如果玩家在游戏中,并被防卫机枪发现,机枪炮塔将从当前角度旋转朝向玩家。
// If we are almost rotated towards target - fire one clip of ammo
var forward = transform.TransformDirection(Vector3.forward);
var targetDir = target.position - transform.position;
if (Vector3.Angle(forward, targetDir) < shootAngleDistance)
SendMessage("Fire");
}
如果当前机枪管位置与玩家的夹角小于shootAngleDistance所设置的数值,机枪将开始开火。
function CanSeeTarget () : boolean
{
if (Vector3.Distance(transform.position, target.position) > attackRange)
return false;
var hit : RaycastHit;
if (Physics.Linecast (transform.position, target.position, hit))
return hit.transform == target;
return false;
}
函数CanSeeTarget计算出机枪是否看见了目标(在这里是玩家)
最后我们来完成对防卫机枪最后的设置:
设置防卫机枪的目标。层级面板中点选Fps控制器,标签栏中的下拉菜单选择标签Player。
把脚本SentryGun配置给防卫机枪的子物体sentryGunRotateY。这会使防卫机枪仅仅顶部旋转,三角基座固定不动。
把爆炸预制配置给机枪中DamageReceiver属性中的爆炸栏
把防卫机枪配置到DamageReceiver属性中的Dead Replacement栏(也可以配置一个自己创建的物体作为破坏状态物体)
把脚本MachineGun付给sentryGunRotateY
在资源库中,把sentryGunTop的子物体muzzleflash配置给机枪属性中的Muzzle Flash变量。
层级栏中点选muzzleflash,把它的着色器类型改为Particles/Additive
运行游戏。现在可以朝油桶和机枪开火了
天空物体(Skybox)
给场景添加天空效果。
选择Edit>Render Settings。把skyBoxTest拖放配置给Skybox材质。这样就创建了天空。
由 lsermao 发表 |
|