Advanced Tutorials

Using the combat improvements

From September 2021 (Neon Coast) we have introduced improvements to how gun combat works, this guide will show you how to get started with these changes, and how you can get them working in your gun game.

You will need to either create a new gun game from the template games, or you should look in the packages and install the update if you already have a game with the Gun package imported.

For more information about these new features, you can read more about them on this blog post.

Per-bone collisions

The first change will allow you to get unique data about the player skeleton, you should be able to find out which area of the character you are hitting with a raycast. We’ve added a new 4th parameter, ‘highFidelityCollision‘.

If you set this to true, your Raycast will no longer collide with the bounding capsule around players – it will only collide with the smaller internal collision bounds of the character.  You can tell which part of a player you have hit by querying GetPartName() on your hit result.

For example, you can detect if your ray has hit the player’s head like so:

	rayStart + (rayDirection * rayLength), 
	true, -- use high fidelity collision
	function(hitEntity, hit)
	if hitEntity then
		print(hitEntity.GetPartName()) -- prints "head" if you hit a character's head

Note : High fidelity rays will continue to collide with voxels/meshes the same as they did before.  In such cases, GetPartName will return “bounds” to indicate you have hit the regular bounding collision of these entities.  Also, if not using high fidelity collision and you hit a player, GetPartName() will likely return “bounds“, but if an arm is extended out from this bounding capsule the ray will still hit this and return the name of the part of the arm instead.

Ammo boxes and limited ammo

We have added the option to have limited ammo clips on your weapons and then require the player to pick up ammo boxes. This adds a level of realism and a new mechanic to your gun games as you need to now pick up ammo.

How do I add limited ammo to my game?

All new games will see the new ‘Has Limited Clip’ parameter in gunScript for each of your guns.

Once you have ticked Has Limited Clip, you’ll be presented with a few more options:

  • Shots Per Clips – how many bullets can this gun hold at one time
  • Start with Full Clip – if true, your gun will start with the amount of bullets set in Shots Per Clip.  If false, you’ll start with zero bullets.
  • Ammo Template – This is the type of ammunition this gun requires.

What’s an Ammo Template?

The ammo template is no more than another inventory item which has been set as being a type of currency.  We’ve created a new Ammo stock package to help you which you can download from the Community tab

Once downloaded, you’ll see a new template called Ammo (which has been assigned as the ‘Ammo Template’ in the gunScript parameters above).  Ammo is simply an inventoryItemSpecScript with ‘IsCurrency‘ ticked. 

With the properties set above, we should now have a gun that can hold 30 bullets per clip, and an inventory that can store 120 more unloaded bullets of this type.  Note that if another gun uses the same Ammo template, then both guns will share the same pool of extra bullets in your inventory to reload with.

Here’s how the game UI should look with the above settings applied:

Note : The game starts with the gun containing a full clip of 30 bullets.  This is because ‘Shots Per Clip’ for this gun was set to 30, and ‘Start with Full Clip‘ was ticked.  The number under this shows how many of these bullets are currently in your inventory.  In this case it is zero, despite us setting “Max Currency” to 120, we haven’t actually added any bullets to the gun yet, we’ve only set the maximum number of these bullets your inventory can contain. 

To add bullets to your inventory, you can simply add the Ammo template to the list of items you have by default at the start of the game, like so:

Now when the game starts, your player should have the Gun in their inventory by default (as they already did before). Gun has been set to use Ammo as it’s ammunition type. We’ve also added 60 Ammo to the inventory.  So we should snow start with a gun with a full clip of 30 bullets, and start with 60 extra bullets (out of the maximum possible 120) in our inventory to reload with.

Ammo Pickup

The Ammo package also contains an ammo pickup template, which can be used as a pickup in your game that adds some much needed ammunition to your inventory during the game. This template simply has a pickupSpawnerScript on it from the stock Inventory package. In the example shown, this ammo pickup will spawn every 5 seconds, and add 30 bullets to your inventory each time it is collected. Note that it will not increase the number of bullets in your inventory over the maximum value of 120 we set earlier.

And with that, you have full setup the limited ammo and the ammo pickups within your game.

Adjusting your aim

AdjustAim is a new system available to creators that has been added to the character API.

What is it?

AdjustAim allows your game to control exactly where the player character needs to look, as well as providing control over how this change in look-at orientation is applied smoothly over time.

Why has this been added?

The eagle-eyed among you may recognize this behaviour as sounding quite similar to the existing SetLookOverride functionality in the User API

Using SetLookOverride, you can for example set your game to ignore any rotation input from the player’s mouse/gamepad, and instead force the player to rotate as if the analogue stick on the gamepad was set half way between the centre & full-right position, using the following code:

 user:SetLookOverride(Vector2D.New(0,0), Vector2D.New(0.5,0))

So what does AdjustAim allow us to do that SetLookOverride didn’t?

The subtle difference between the two is that SetLookOverride was a way to adjust the player’s rotation input from their mouse/gamepad which is being fed into the character (this is why it’s found in the User API), whereas AdjustAim alters the character entity’s rotation directly (which is why it’s found in the Character API).  This gives you far more control over precisely where you want the player to be looking towards!

How do I use it?

To trigger this new feature, a new function has been added to the character API – AdjustAim. The AdjustAim API uses a similar set of parameters used for Timelines, where you can specify a list of rotations to be performed one after another.

Example 1 – Passing entities as ‘look-at’ targets


The above code will rotate the character at a speed of 50 degrees/sec until they are looking at the ‘oneMesh‘, and it’ll apply this movement over time with a nice smooth “easeinout“.  Once done, it’ll do the same thing but look at ‘twoMesh‘, and finally ‘threeMesh‘.  Here’s how that might look:

Example 2 – Rotate by angle

                    Rotation.New(0, 360, 0), 
                    Rotation.New(45, 0, 0), 
                    Rotation.New(-45, 0, 0), 
                    Rotation.New(0, -360, 0))

The above code will rotate the character 360 degrees to the right at 180 degrees/sec (note the lack of any smoothing, such as “easeinout“, for the first entry – when no smoothing is specified, it’ll default to “linear”).  it’ll show them smoothly look up then down, before linearly rotating back to the left by 360 degrees at 180 degrees/sec:

Note: You can mix and match this list of parameters to include both entities to look at and/or angles to rotate by, so you could look at the oneMesh entity, then spin around 360 degrees.

                    Roation.New(0, 360, 0), 

Example 3 – tables as parameters

local aimTable = {}
for index = 1, do
	table.insert(aimTable, 45) -- rotate at 45 degrees/sec
	table.insert(aimTable,	Rotation.New(0, 360 /, 0),
	table.insert(aimTable, "easeinout")  -- smoothly turn during each segment)

Just like timelines, tables of values can be passed too to support procedural generation.  In this example, I rotate the player 360 degrees at 45 degrees per second, but this rotation is split up into a number of individual turns, specified by the turnSections property on this script.  In this example video, turnSections is set to 4, so the player will rotate 360 degrees using four 90 degree turns:

Adjust Aim Handles

The AdjustAim API returns a handle to the active aim adjustment.

self.adjustAimHandle =  character:AdjustAim(50, 
                        Rotation.New(0, 360, 0), 

You can query whether this adjusted aim is still in progress using IsActive().

if self.adjustAimHandle.IsActive() then

And you can use Cancel() to instantly stop the active adjust aim after it has begun, or by passing the handle into the equivalent function on the character API.

-- these 2 lines will do the same thing

You can also query if any aim adjustment is currently active on the player.


Where can I see examples of this being used in Crayta?

We have added Recoil to the stock gun packages, this is a great example of the kind of thing that is now easy to do with the new AdjustAim API!

While we were at it, we also decided to improve the existing Aim Assist that was present in the stock Gun package to use AimAdjust.  We can’t wait to see what other uses you come up with for it!