Setting Up Projectiles
An explanation of how to set up custom projectiles for a custom gun.
If you are unaware of how projectiles and projectile modules function, it is recommended that you read up on that here before continuing.
As a good rule of thumb, the first thing one ought to do is add a projectile module from an existing gun in the base game. This means that most things are already accounted for and won't cause errors.
To do this, add the following code to your gun's initialization module.
gun.AddProjectileModuleFrom(PickupObjectDatabase.GetById(86) as Gun, true, false);
The number inside of this line (in this case 86) is the numerical id for the gun from which you want to copy your projectile from. 86 refers to the Marine Sidearm, which is often a good starting point as it is a highly generic projectile with few special features, and as such is essentially a blank slate.
If you are planning on adding a custom sprite to your projectile, and want that sprite to rotate depending on the projectile's orientation, it is best instead to start with 56, which refers to the 38 Special. The 38 Special's projectiles rotate by default and as such cause fewer problems when attempting to set up a rotating projectile.
The next step is to take the projectile from the module that you have cloned, and 'Instantiating' it, and 'FakePrefabing' it.
Instantiation refers to the process of separating the cloned projectile from the original projectile. Without instantiation, and changes you make to your projectile will also affect the base game projectile that you copied from.
FakePrefabing refers to marking the projectile as a fake prefab, which prevents the game from erasing the new projectile when it is loaded.
Both can be done fairly easily using the following code;
Projectile projectile = UnityEngine.Object.Instantiate<Projectile>(gun.DefaultModule.projectiles);
Now that you've copied and instantiated base game projectile, you can alter it's stats and effects.
Please note that this guide does not cover adjusting the stats of the projectile module, just the stats within the projectile itself.
Most of the projectile's stats are contained within it's baseData, which can be easily accessed fairly simply. Below is a list of examples where all the stats have been set to 5.
projectile.baseData.damage = 5;
projectile.baseData.speed = 5;
projectile.baseData.range = 5;
projectile.baseData.force = 5;
Most stats are self-explanatory except for 'force', which simply refers to the amount of knockback the projectile inflicts upon enemies.
However, not all stats are contained within the baseData. Certain stats such as the projectile's scale, jammed damage multiplier, and boss damage multiplier are contained directly within the projectile. Here is a demonstration where they are all set to five.
projectile.AdditionalScaleMultiplier = 5;
projectile.BlackPhantomDamageMultiplier = 5;
projectile.BossDamageMultiplier = 5;
The AdditionalScaleMultiplier affects the size of the projectile. It is rarely necessary to set it in the prefab, and is more useful for items that adjust shot size like Fat Bullets, but it is still possible.
BossDamageMultiplier is how much the bullet's damage is multiplied by against boss enemies. For example, if the projectile's damage was 7, and the boss damage multiplier was 3, the projectile would deal 21 damage to bosses, as 21 is 7 multiplied by 3.
The BlackPhantomDamageMultiplier is the same as the BossDamageMultiplier, except it affects jammed enemies instead of boss enemies. Jammed enemies are often referred to internally in the game's code as 'Black Phantoms'.
If you do not want your projectile dealing any more or less damage to jammed enemies or bosses, set these multipliers to 1. If you have copied from the Marine Sidearm or 38 Special, these variables are 1 by default and do not need to be changed.
ignoreDamageCapscan be used to allow the projectile to break the boss damage-per-second cap. Certain base game guns such as the Makeshift Cannon or Glass Cannon have this set to true.
projectile.ignoreDamageCaps = true;
Setting this to true is not recommended unless you plan for your gun to be able to break the balance of the game in such a way.
The variable 'pierceMinorBreakables' can be used to allow projectiles to pierce through the various decorative objects strewn around rooms in the Gungeon.
projectile.pierceMinorBreakables = true;
While set to true, any breakable objects that the projectile impacts with will not stop it's movement when they are destroyed, and the projectile will be allowed to pass right through.
The content in this section requires the use of the GunTools class. If you have not set up the GunTools class, you will not be able to use the following code.
First, you need to create your new sprite. Tips and advice for spriting can be found here. Once your sprite is finished, export it as a file, and place that file inside of your mod's ProjectileCollection folder.
To change a projectile's sprite to a custom one, you can use the following code;
projectile.SetProjectileSpriteRight("projectilename", 6, 6, true, tk2dBaseSprite.Anchor.MiddleCenter, 4, 4);
There are multiple variables in that line of code, and all of them are important. The following is an explanation of what each variable does;
- "projectilename" - This is the name that the code uses to determine which sprite in the ProjectileCollection folder you want to use. This should be set to the exact same name as what you called the sprite's file in the folder.
- Eg: If you named your sprite 'mygunprojectile.png' in the ProjectileCollection folder, you should set this to 'mygunprojectile'. Do not include the file extension.
- 6, 6 - The two numbers following the sprite name are the dimensions of the sprite. They are both set to 6 here for example, but if your projectile sprite is 8 pixels long by 3 pixels high, you would instead use the values 8, 3.
- The first number refers to the width of the sprite, the second to the height.
- Setting these numbers incorrectly may result in your projectile appearing squashed or stretched.
- true - This boolean variable determines whether the projectile emits light. Set to true to make it emit light, or set to false to prevent it.
- tk2dBaseSprite.Anchor.MiddleCenter - This controls where the sprite is anchored on the projectile's body. Usually, this will not need to be changed and is set to MiddleCenter here by default. However, if you do need to change the anchoring of the sprite, Visual Studio's autocomplete feature will show you a full list of valid anchors upon typing in tk2dBaseSprite.Anchor.
- 4, 4 - The final two numbers refer to the width and height, in pixels, of the projectile's hitbox. In this example, it is set to 4 pixels wide by 4 pixels high.
- It is good practice to set your projectiles hitbox to be slightly smaller than it's sprite, though this is by no means a firm rule.
That covers the simple setup of projectile sprites.
Once you've done everything above, or at least as much as you wanted to, you then need to reassign the modified projectile back to your gun using the following code.
gun.DefaultModule.projectiles = projectile;
Once that is done, your gun's projectiles are ready to go!
This is by no means a comprehensive list of everything you can do with projectiles, it is merely a simplified guide to hopefully explain how to set up the very basics of a projectile.