Published using Google Docs
ROKKITZ Manual
Updated automatically every 5 minutes

ROKKITZ

Projectile behaviour pack

Rokkitz is a package of weapon projectile behaviours. It allows you to create rockets, grenades, cluster bombs, seeker missiles and whatever else suits your fancy. It also includes simple but functional FPS weapons inventory; and if that is not enough, Rokkitz projectiles can be easily used with UFPS system.

Even though the Rokkitz demo uses FPS mechanics, the projectiles themselves can work with any game: you can fire them from spaceships, planes, tanks, magic wands, in first person, third person, or overview perspectives - basically anywhere.

Rokkitz Overview

Rokkitz Scripts

Projectile

ProjectileSteering

GravityMovement

HomingMovement

TumblingMovement

ProjectileComponentBase

EnemySeeker

ProjectileSplit

ProximityFuse

TimedFuse

UFPSAdapter

DamagingExplosion

DetachOnDestroy

TargetableObject

EnemyTrackerBase

DamageableObject

Weapon

WeaponInventory

Launcher

Rokkitz Overview

The most important component in Rokkitz is Projectile. This script handles movement and collision detection, and send important events: Launch, Collision and Explode.

A Projectile can have a ProjectileSteering component attached. Its task is calculating projectile velocity each frame, to create more interesting movement than flying in a straight line. Examples of ProjectileSteering components are GravityMovement and HomingMovement.

You can attach more than one steering component to a projectile, but only one can be active at any given time.

Another kind of Projectile component is derived from ProjectileComponentBase. These scripts can handle projectile launch, collisions and explosion (explosion is different from collision, because it might be triggered by some other mechanism - like timed fuse). There is a number of components defined in Rokkitz, like ProximityFuse, TimedFuse, etc; and you can easily add your own.

The TargetableObject script is used to mark enemies, so that seeker missiles and proximity fuses know where to find them. It works in tandem with EnemyTrackerBase, which is used to find all enemies in some area.

WeaponInventory handles FPS-style weapon switching, while Weapon takes care of individual weapon’s animations, ammo, aiming, firing and reloading. The Launcher script actually spawns a projectile; you can have multiple Launchers on a single Weapon to fire many projectiles at once.

Other scripts included in the package are mainly there to run the demo scene: some simple UI management, and spawning/moving dummy enemies for you to shoot at.

A more thorough explanation of all scripts is in this manual next; be sure to also check the source code - it has lots of comments to help you understand what’s going on.

Rokkitz Scripts

Projectile

Projectile script is the foundation of a projectile. It handles movement, collision detection, and all parts of projectile lifecycle. Other components can add to it, but it’s the Projectile that makes them work.

The projectile lifecycle looks like this:

  1. First, the projectile is launched. Its velocity is set to start value, and OnProjectileLaunch message is sent, so that other components can do whatever initialization they need.
  2. Every FixedUpdate, the projectile is moved forward; where “forward” may be defined by the active ProjectileSteering component.
  3. Projectile uses sweep test to detect collisions. This is better than relying on built-in PhysX collision detection, as sweep test never misses even very thin walls. It can still miss fast-moving small objects, but that’s not much of an issue in practice.
  4. If a collision is detected, OnProjectileCollision message is sent, allowing any components to handle it. After that, Projectile itself can use one of predefined collision responses: stop in place, turn on Rigidbody physics, or explode (this is the default)
  5. At some time (either due to a collision, or called by another component) explosion happens - which is to say, OnExplode message is sent. By default, the projectile GameObject is destroyed on explosion, and an explosion effect prefab is instantiated.
  6. If a projectile has not exploded for some predefined time, it is silently destroyed - to prevent stray projectiles from littering the scene.

More on projectile collision: a projectile has two ways to define its shape. If it has a Rigidbody attached, then its shape (with whatever colliders it has) is used for sweep tests. Note that the Rigidbody itself would be switched to kinematic, so no physics would affect it and interfere with projectile movement. If there’s no Rigidbody, the projectile is considered a sphere with predefined radius (can be 0). In both cases, projectiles basically ignore Unity physics while flying, and only obey their own steering.

Projectile class may send three kinds of messages: OnProjectileLaunch, OnProjectileCollision, and OnExplode. The usual way to use them is attach a component derived from ProjectileComponentBase, which has virtual method for all of those. However, since the methods are called with SendMessage, any component that has methods with these names defined will get called. Note that OnExplode (and only OnExplode) is also sent to children of projectile object.

Launching a projectile is normally handled by Launcher component (or UFPSAdapter). If you want to launch a projectile from your own code, you should do the following:

Projectile class has some properties to fine-tune its behaviour:

ProjectileSteering

ProjectileSteering is the abstract base class for components that steer projectiles. Inheriting classes are meant to override CalculateVelocity method. This method is called each FixedUpdate to calculate projectile velocity for that frame.

Another useful method to override is SetAim. This one is called to set projectile target for homing behaviours.

Only one ProjectileSteering component can be active at any time; but you can change which one is at any time. One way to do that is integrated into ProjectileSteering itself: the ActivationDelay property defines time, in second, before this component is activated. Using it, you can create a timed “stack” of steering behaviours. For example, a projectile that flies forward for 0.3 seconds, then starts homing on target, and after 5 seconds falls down, running out of fuel.

Rokkitz contains three predefined ProjectileSteering classes: GravityMovement, HomingMovement and TumblingMovement.

GravityMovement

This is a steering component that adds gravity to projectiles, making for a parabolic trajectory. It has one property, which is the gravity force. The gravity force is always pointed along world down axis (Vector3.down) and does not depend on projectile mass (if it even has one)

HomingMovement

This component steers the projectile towards a target. It depends on having a target, that must be set by calling SetAim on the projectile when HomingMovement is active (or just directly on HomingMovement component) If the target is not set, the projectile just flies in a straight line.

HomingMovement has one property, AngularTrackingSpeed, which is maximum turning velocity when homing, in degrees per second.

TumblingMovement

TumblingMovement component makes a projectile go sideways in random direction, with optionally spinning, and then gradually righting itself. It looks cool when launching multiple projectiles at once. TumblingMovement is controlled by several properties:

ProjectileComponentBase

This is an abstract base class for generic projectile components. It defines three virtual method to override in derived classes: OnProjectileLaunch, OnProjectileCollision and OnExplode.

EnemySeeker

This component looks for enemies in front of the projectile and aims at them (calling SetAim). It does not do any steering, and so requires HomingMovement or similar component that actually uses aim target. Enemies to look for are obtained using EnemyTrackerBase.

EnemySeeker has the following properties:

ProjectileSplit

Creates a number of secondary projectiles on explosion. Use this for cluster bombs etc.

Split is controlled by following properties:

ProximityFuse

ProximityFuse keeps track of enemies nearby and explodes when the projectile is closest to one. (Or, alternatively, the moment an enemy appears close enough.) It uses EnemyTrackerBase to track nearby enemies.

ProximityFuse is controlled by following properties:

TimedFuse

This component explodes the projectile after a set delay. It has two properties:

UFPSAdapter

This component should be used with UFPS package. If you want to fire a Rokkitz projectile from a UFPS gun, just add this script and use projectile as usual with vp_WeaponShooter. The adapter will “pretend” that the projectile was launched from Rokkitz Launcher and call all necessary methods.

DamagingExplosion

This component damages all DamageableObjects in radius when the projectile explodes. It’s quite basic, and should be used as a template for your own one, rather than directly (although it may be enough for a simple game). DamagingExplosion uses EnemyTrackerBase to find objects to damage, meaning it will only affect objects that also have TargetableObject attached.

DamagingExplosion has the following properties:

DetachOnDestroy

This is a simple script that detaches its GameObject from parent when OnExplode is called. It’s used for rocket trails, so that they don’t disappear immediately when a rocket explodes, but linger for some time.

TargetableObject

Marks an object as a possible target for projectiles. Marking is achieved by registering in EnemyTrackerBase object that must exist in the scene (one gets created automatically if none is found). TargetableObject has a single property (not visible in inspector) that defines its center - i.e. the point where the projectile should aim. By default, it’s the center of first attached collider; or simply transform position if no collider exists (though that’s strange for a TargetableObject to have no collider - you wouldn’t be able to hit it without one! - it’s still allowed).

EnemyTrackerBase 

This script keeps track of all TargetableObjects in the scene, and can find all of them in a giver radius. It’s meant to be a singleton, and is automatically created if none is found.

You can inherit from EnemyTrackerBase and create your own tracker in the scene, if you need some advanced tracking algorithms. The default one would work OK as long as you don’t have too many (over a hundred) enemies in the scene at the same time.

DamageableObject

This script handles being damaged and destroyed. It only has the most basic functionality: a hit points counter that is decreased when damage is dealt. when HPs reach 0, the object is destroyed, and optionally replaced with a ragdoll prefab.

DamageableObject is too basic for any but the most simple games, and should be used as a template for your own, more advanced component.

Weapon

Weapon behaviour is a generic FPS weapon. It’s meant to be a part of WeaponInventory, but can be used without it. The behaviour handles animations, state changes, ammo spending and reloading, aiming and firing.

A Weapon can be in one of these states:

Current state is given by State property. It cannot be set directly, only through use of methods like Equip, Unequip, StartFiring and Reload - they take care of starting necessary animations and keeping everything consistent.

Weapon can animate both the weapon object itself (if it has an Animator component) and the player (i.e. player’s hands) - this requires setting up PlayerAnimator reference on the Weapon object.

Animations use triggers: EquipAnimTrigger, UnequipAnimTrigger, ReloadAnimTrigger and FireAnimTrigger. When respective state starts, this trigger is set on both the weapon’s and the player’s Animators - provided Animator exists and trigger name is not empty. For (un)equipping and reloading, the state ends when animation event OnEquipFinished (or similar for other states) is called by weapon Animator. Alternatively, you can set an EquipAnimDelay to automatically end the state after this delay passes.

Firing does not have FireAnimDelay, because this state ends when shot is fired (or for full-auto, when fire button is released). But there is FireAnimBool property that defines name for a bool parameter. It will be set to true in both animators whenever the weapon is in firing state - this is useful for full-auto weapons that shake or rotate barrels continuously while firing.

When aiming, weapon uses a raycast from player’s eyes - i.e. Camera - position. This camera can be set using PlayerCamera property; if not set, main camera would be used. You can also set crosshair position in case you don’t want aim at screen center.

AimRaycastLayers controls which layers this raycast would hit, and MaxAimDistance is raycast distance. The point where raycast hits an obstacle is the point where the weapon aims. Aiming does not rotate the weapon object in any way - instead, it just determines where the projectile would be facing at launch.

To simulate weapon inaccuracy, this firing direction can also be changed randomly whenever a projectile is fired. This sway is defined by AimSpread property. Its value is maximum distance that a projectile will deviate from target, if it travels 100 units from launch. In other words, when AimSpread is 1, and you fire at a target 100 units away, the projectile would hit some spot within 1 unit from the target.

When the fire button is pressed, Weapon switches to Firing state and launches projectile(s). Every weapon must have some Launcher objects attached to it; when firing, every Launcher spawns and shoots one projectile. The FireRate property limits firing rate to no more than FireRate shots per second.

ContinuousFire defines auto behaviour: when true, the weapon would fire continuously (obeying FireRate) as long as fire button is pressed; when false, the weapon would fire only once, and wait for the button to be released and pressed again.

Every shot spends AmmoPerShot ammo from the clip (it’s technically called magazine, but who cares.) Current ammo in clip is defined by CurrentAmmoInClip property, and CurrentAmmo give ammo reserves (excluding clip). MaxAmmo and ClipSize define maximum counts for reserves and clip, respectively.

Whenever reload is finished, Weapon takes ammo from CurrentAmmo and adds to CurrentAmmoInClip, up to ClipSize. Reloading can be triggered externally (via Reload method), or automatically when trying to fire with empty clip.

There are also two flags: InfiniteAmmo and InfiniteClip, to “cheat” and make a weapon that does not spend ammo or does not even need reloading.

WeaponInventory

WeaponInventory is a collection of Weapons that can be switched around. It’s meant to be attached to the player object, with Weapons as different s attached lower in hierarchy. Weapon switching is controlled by Next and Previous methods, which equip next and previous weapons respectively (in transform order). The list is cyclic, i.e. Next will switch last weapon to first.

WeaponInventory has two read-only properties, CurrentWeaponIndex and CurrentWeapon. Note that CurrentWeapon is not necessarily already equipped and ready to fire - it might be equipping, or even just waiting for previous weapon to unequip.

Launcher

Launcher script is responsible for actually creating and launching a projectile. It has a ProjectilePrefab property that defines what actually gets launched.