Projectiles are little more than Actors that are spawned dynamically,

move around for a certain amount of time and then die, possibly inflicting damage.

In UT3 for instance, the Shock Rifle’s Shock Ball, or the Link Gun’s plasma ball are projectiles.

In today’s lesson, we will discuss when it’s best to use projectiles,

we’ll have a look at collision in general (as projectiles obviously rely heavily on it),

and see how projectiles do their job.

If you haven’t already done so, I strongly recommend you read the bit on Damage Dealing.

Projectiles vs Instant Hit

I think we can agree on the fact that mechanically speaking,

the vast majority of weapons we can find in a game is using a projectile of some sort (bullet, arrow, plasma ball, etc).

However, since assault rifle bullets are so fast, is worth making an object for them, handling its movement and all? Propably not.

That’s why game programmers had the idea of the instant hit shot (sometimes called Trace shot)

which simply draws a straight line from the weapon, and affect the first object it touched. This method has

been around since, well the dawn of FPSs. As a rule of thumb, if the projectile shot by your weapon is too

fast to be seen by the player, you’ll probably want to use an Instant Hit fire type. UT3′s Minigun and assault rifles work like that.

That said, there might be cases where you still want to use projectiles. In games that claim to have realistic ballistics (e.g.: ArmA 2, Battlefield series),

projectiles are actual projectiles, even if you don’t see them.

This allows for the projectile to actually travel across the level over time,

possibly being affected by things such as gravity along the way.

As far as Unreal Engine 3 is concerned, a projectile does not need a mesh to work.

Only a CollisionComponent.

Also, being a subclass of Actor, Projectiles can potentially take damage,

enabling interesting gameplay (e.g: Unreal’s Shock Combo). And by default,

bCanBeDamaged is set to true for projectiles (although TakeDamage is not overriden, so it won’t do anything actually).

Projectile Class

A Projectile is an Actor which defines a few additional properties regarding the following topics:

  • Motion
  • Damage
  • Collision

We’ll talk about collision more extensively later in this page.

Motion

  • float Speed: in UU/s
  • float MaxSpeed: in UU/s

The Actor class already handles linear movement through the Velocity property.

All we need to do to put our projectile in motion is to set this variable.

The Actor class also defines a LifeSpan property, holding the time after which the Actor dies.

Projectiles use LifeSpan and MaxSpeed to determine their maximum range.

UDKProjectile provides a variable that allows the projectile to have an accelaration (AccelRate, needs to be implemented).

It also provides and a few variables that will let you implement guided projectiles.

The code chunk below is from UDKProjectile.uc, UDK October 2010:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
//=======================================================
// Seeking Projectile Support
/** Currently tracked target - if set, projectile will seek it */
var actor SeekTarget;
/** Tracking strength for normal targets.*/
var float BaseTrackingStrength;
/** Tracking strength for vehicle targets with bHomingTarget=true */
var float HomingTrackingStrength;
/** Initial direction of seeking projectile */
var vector InitialDir;
/** The last time a lock message was sent (to vehicle with bHomingTarget=true) */
var float LastLockWarningTime;
/** How long before re-sending the next Lock On message update */
var float LockWarningInterval;

Damage
  • float Damage
  • float DamageRadius
  • float MomentumTransfer
  • class<DamageType> MyDamageType

You should know what all of these are for.

Firing a Projectile

While spawning the projectile itself is in essence quite easy,

spawning the projectile at the right place and in the right direction is actually more complex than it sounds.

Let’s have a look at how the Weapon.ProjectileFire() function work.

First and foremost, there is an obvious but capital concept one needs to keep in mind: In almost every situation,

the line of sight and the projectile’s trajectory are NOT aligned (or collinear, for maths people).

Even if they do share the same end point (the hit location), the starting points are very likely to be different.

For the line of sight, it’s usually the player point of view, and for the trajectory,

it’s wherever the projectile is supposed to come out of (like the gun’s barrel).

The default implementation of ProjectileFire() is trying to make sure the point I’m aiming at is where my projectile is headed.

This is summarized by the figure below (behold my amazing drawing skills!):

The [StartTrace,EndTrace] vector being our actual aim,

we need to find the right orientation from RealStartLoc to make sure the projectile is headed to EndTrace (doesn’t mean it necessarily will,

especially if external factors affect the projectile’s motion).

For the record, a real life, bullet-based firearm behaves like this (the drawing is obviously exaggerated):

Here’s how ProjectileFire() retrieves the required information:

StartTrace

It is retrevied by calling Pawn.GetWeaponStartTraceLocation(). 

That is asking the Pawn, which will in turn ask its controller (Controller.GetPlayerViewpoint()). 

That’s because depending on who controls the Pawn (AI or Player), the StartTrace won’t be the same.

For the player, it’s usually the position of the camera.

 However that might not be a valid position in cases such as top-down perspective games. 

Just override the function to specify an appropriate start point.

NOTE: This is also done in the case of an Instant Fire.

AimDir

Retrieved by the GetAdjustedAim(StartTrace) function, which asks for the pawn’s aim rotation, 

which in turns lets the controller modify the aim. Then spread is added, and we have our AimDir.

RealStartLoc

Retrieved by the GetPhysicalFireStartLoc(AimDir). Default implementation is native, 

so I can’t really tell what it returns. You’ll have to override it anyway.

EndTrace

Now, if StartTrace and RealStartLoc are different (and they probably will be), 

we need to adjust AimDir so it will send the projectile where we aimed. to do that, 

we need to know where we are supposed to hit.

 We doi it by getting EndTrace (calculated from translating StartTrace along AimDir over a distance equal to the weapon’s range.

 With that, we can start a trace that will tell us what’s the point of impact. Then, AimDir is adujsted according to that.

Once all this is done, when can spawn and activate the projectile. The hard part in all that is to find the right RealStartLoc.

Example

Simple projectile with mesh:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class SandboxPaintballProjectile extends UDKProjectile;
DefaultProperties
{
     Begin Object Class=DynamicLightEnvironmentComponent Name=MyLightEnvironment
         bEnabled=TRUE
     End Object
     Components.Add(MyLightEnvironment)
     begin object class =StaticMeshComponent Name=BaseMesh
         StaticMesh=StaticMesh 'SandboxContent.Meshes.SM_PaintBall'
         LightEnvironment=MyLightEnvironment
     end object
     Components.Add(BaseMesh)
}

Here is the weapon’s relevant code. I’m using the paintball gun I made in the  weapons tutorial :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
class SandboxPaintBallGun extends UDKWeapon;
simulated event vector GetPhysicalFireStartLoc( optional vector AimDir)
{
     local SkeletalMeshComponent compo;
     local SkeletalMeshSocket socket;
     compo = SkeletalMeshComponent(Mesh);
     if (compo != none )
     {
         socket = compo.GetSocketByName( 'MussleFlashSocket' );
         if (socket != none )
         {
             return compo.GetBoneLocation(socket.BoneName);
         }
     }
}
DefaultProperties
{
     FiringStatesArray( 1 )=WeaponFiring
     WeaponFireTypes( 1 )=EWFT_Projectile
     WeaponProjectiles( 1 )= class 'Sandbox.SandboxPaintballProjectile'
     FireInterval( 1 )= 0.01
     Spread( 1 ) = 0
}

And that’s what we get:

Projectile collision

When a projectile hits something, it can trigger two different events: Touch,

and Hitwall (both defined in the Actor class). If the touched Actor has bWorldGeometry set to true,

the collision will trigger the HitWall event. Otherwise, the Touch event will be triggered.

The other difference between two events is that HitWall does not provide the hit location, only the normal.

The Projectile class already defines a CylinderComponent as a Collision for the projectile,

but with a radius and height to 0, meaning the collision is reduced to a point. You might want to override that.

IMPORTANT NOTE: Projectile’s Touch and Hitwall events are specified as singular meaning they can’t be called recursively.

As a consequence, you won’t be able to call super.Touch nor super.HitWall (the compiler won’t let you).

That means that if you need to override one of these event, you must copy/paste any relevant code from the parent class’ implementation.

Touch Event

Does some network related checks. If those tests are successful,

it calls the ProcessTouch() function whose default implentation calls the Explode() function if the actor touched is not the projectile’s instigator.

Hitwall Event

The default implementation checks if the hit actor is a static mesh that can become dynamic,

and if so activates it. Then, regardless of that outcome, it calls the actor’s TakeDamage(), then calls Explode().

Explode() Function

Calls ProjectileHurtRadius() (which is a wrapper to HurtRadius() that does dodgy things to ensure a maximum of actors get hit by the projectile).

Obviously, if your actor isn’t meant to do any radius damage,

you can simply override the function and just create your own function and call it instead of Explode.

Example

I’ve overridden the HitWall event to make the projectile bounce on world geometry, deals some damage on the hit actor, and place a decal):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
class SandboxPaintballProjectile extends UDKProjectile;
simulated function ProcessTouch(Actor Other, Vector HitLocation, Vector HitNormal)
{
     if ( Other != Instigator )
     {
         WorldInfo.MyDecalManager.SpawnDecal ( DecalMaterial 'SandboxContent.Materials.DM_Paintball_Splash' ,
HitLocation, rotator (-HitNormal), 128 , 128 , 256 , false , FRand() * 360 , none );

         Other.TakeDamage( Damage, InstigatorController, Location, MomentumTransfer * Normal(Velocity), MyDamageType,, self );
         Destroy();
     }
}
simulated event HitWall( vector HitNormal, actor Wall, PrimitiveComponent WallComp)
{
     Velocity = MirrorVectorByNormal(Velocity,HitNormal); //That's the bounce
     SetRotation(Rotator(Velocity));
     TriggerEventClass( class 'SeqEvent_HitWall' , Wall);
}
DefaultProperties
{
     Begin Object Name=CollisionCylinder
         CollisionRadius= 8
         CollisionHeight= 16
     End Object
     Begin Object Class=DynamicLightEnvironmentComponent Name=MyLightEnvironment
         bEnabled=TRUE
     End Object
     Components.Add(MyLightEnvironment)
     begin object class =StaticMeshComponent Name=BaseMesh
         StaticMesh=StaticMesh 'SandboxContent.Meshes.SM_PaintBall'
         LightEnvironment=MyLightEnvironment
     end object
     Components.Add(BaseMesh)
     Damage= 25
     MomentumTransfer= 10
}

UDK – Projectiles相关推荐

  1. UDK编辑器 49条小提示

    UDK编辑器 49条小提示(转) Very Helpful~ 01. First time using the Unreal Engine?Go to http://udn.epicgames.com ...

  2. Unity,UDK,Unreal Engine4或者CryENGINE——我应该选择哪一个游戏引擎

    在digital-tutors看到的一篇文章,很多初学者都有这样的疑问,因此翻译到这里. 原文: http://blog.digitaltutors.com/unity-udk-cryengine-g ...

  3. UDK游戏开发基础命令

    编译 增量重新编译Debug版本UnrealScript脚本     UDK.exe make -debug 增量重新编译Release版本UnrealScript脚本    UDK.exe make ...

  4. 【游戏周边】Unity,UDK,Unreal Engine4或者CryENGINE——我应该选择哪一个游戏引擎

    在digital-tutors看到的一篇文章,很多初学者都有这样的疑问,因此翻译到这里. 原文:http://blog.digitaltutors.com/unity-udk-cryengine-ga ...

  5. UDK官方视频教程带中文字幕虚幻引擎UDK(16章全) ㍿

    UDK官方视频教程带中文字幕虚幻引擎UDK(16章全) 第1章主要讲解了UDK的一些基本知识. [直接观看地址]: UDK官方视频教程带中文字幕1.0.0虚幻引擎UDK用户界面介绍 [直接观看地址]: ...

  6. UDK 脚本编译运行

    UDK基础学习 1.      首先想通过简单的直接在D:\UDK\UDK-2012-03\Development\Src\UTGame\Classes加入一个脚本,实现superJump功能,就是玩 ...

  7. 【UDK官方教程】知识点学习第一章

    官方教程毕竟是视频,主要记录一些知识点,大部分是官方视频中文字幕的复制加上一些个人小提示. 官方视频1.0.0 打开UDK跳过提示,会进入到主界面,如下图 1.四个面板我们称作视口,当你在关卡中进行编 ...

  8. UDK ——脚本入门

    参考:http://v.youku.com/v_show/id_XNTMwMTU0OTIw.html 前边的话: Unreal Script,即虚幻脚本,后缀名UC,以下用UC代替. 写这篇帖子的目的 ...

  9. 游戏开发之UDK引擎介绍和模型导入

    2014-09-18 10:01:3 UnrealDevelopmentKit(虚幻引擎开发工具包).简称UDK,是一套强大并免费的游戏引擎开发套件.能够用来制作高端的3D游戏或者场景展示. 只是,假 ...

最新文章

  1. 合肥工业大学—SQL Server数据库实验一:数据库的创建和删除
  2. 多个servlet配制方法
  3. 拆解交易系统--模块拆解与服务化
  4. oracle四大语言_Oracle数据库之四大语言
  5. css改变背景透明度
  6. 保证相同类型的MDI子窗体只会被打开一次的方法
  7. CentOS 7中iptables服务暂停启动和保存备份
  8. 卡农 matlab,matlab 编的卡农
  9. 分布式系统:CAP 理论的前世今生
  10. 信息学奥赛C++语言: 队伍调整
  11. php中将excel写入mysql数据库的示例
  12. Mac 显示sudo: pip: command not found
  13. 密码生成 算法编程题
  14. 优衣库真的是一家技术驱动型公司?
  15. Keil5开发工具 --- 背景颜色绿色护眼
  16. NPOI 操作Excel学习总结
  17. win7无损分区和硬盘分区调整合并
  18. 「Vue实战」武装你的前端项目
  19. 区块链P2P网络协议演进过程
  20. WEB开发技能树-JavaScript-DOM

热门文章

  1. html中设置浏览器解码方式
  2. 华为网络安全论述题解析(2)
  3. 【Demo3d】Visual类对象操作常用方法
  4. 100个国家的数字货币政策大全
  5. 大型智慧物业管理系统源码
  6. 一些可以用于串口的一些通信协议
  7. php用Imagick扩展合并多张图片为PDF
  8. 【华为OD机试】答疑 + 注意事项
  9. Foxit PDF Reader/Editor 任意代码执行漏洞
  10. 计算机主板风扇安装,cpu风扇怎么装 cpu风扇安装方法【图文】