-
Notifications
You must be signed in to change notification settings - Fork 0
FAQ & Common Issues
BroMaker provides the [SaveableSetting]
attribute which you can set on any serializable static variable in a class that inherits from CustomHero. Variables with this attribute will automatically be loaded when the mod starts up, and automatically saved when you press "Save" in the Unity Mod Manager window or when the game shutdowns. If you force close the game the settings may not be saved however.
If you want to display these options and allow users to change them, you can use the UIOptions() method
Example:
[SaveableSetting]
public static bool doubleTapSwitch = true;
Visual Studio has the ability to show descriptions of methods when you're hovering over them or typing them out and looking at them in autocomplete:
In order for these to show up, you'll need to make sure that you have the .xml files for whichever assembly contains the given member. So for methods provided by BroMaker, you'll need the BroMakerLib.xml file, which you can find here.
You'll want to download that file and place it next to your BroMakerLib.dll. You need to make sure that it's the same .dll that you added to your solution's references though, as you may have some of these .dlls in multiple locations.
I'd recommend making sure you have all of the following .xml files from here, as well as BroMakerLib.xml, and RocketLib.xml
You can check the isOnHelicopter
variable to see if your bro is attached to a helicopter. It's a good idea to check this if you have some continuous visual / audio effect that you need to cancel when your bro gets on a helicopter.
Example:
// Stop proton gun when getting on helicopter
if ( this.isOnHelicopter )
{
this.StopProtonGun();
this.protonAudio.enabled = false;
}
Use the parameters
section in your JSON file to set these sprites:
{
"parameters": {
"Avatar": "avatar.png",
"SpecialIcons": "special_icons.png"
}
}
See Parameters for all available sprite parameters.
Provide arrays instead of single values in your parameters to create variants that are randomly selected on spawn:
{
"parameters": {
"Sprite": ["sprite1.png", "sprite2.png", "sprite3.png"],
"Avatar": ["avatar1.png", "avatar2.png", "avatar3.png"]
}
}
See this page for detailed information on variants.
To play audio continuously (like for a proton gun, flamethrower, or other sustained effects), you need to add an AudioSource component to your bro or projectile and configure it for looping playback. Here's the typical pattern:
1. Add and configure the AudioSource:
// Declare as public field in your bro class (required for prefab serialization)
public AudioSource continuousAudio;
// In your bro's AfterPrefabSetup() method
this.continuousAudio = base.gameObject.AddComponent<AudioSource>();
this.continuousAudio.rolloffMode = AudioRolloffMode.Linear;
this.continuousAudio.minDistance = 200f;
this.continuousAudio.maxDistance = 500f;
this.continuousAudio.spatialBlend = 1f;
this.continuousAudio.volume = 0.33f;
2. Start the continuous loop:
// When starting your effect
if (!this.continuousAudio.isPlaying)
{
this.continuousAudio.clip = myLoopSound;
this.continuousAudio.loop = true;
this.continuousAudio.Play();
}
3. Stop audio when dying / level ending:
// In your Update() method
if (this.isOnHelicopter || this.actionState == ActionState.Dead)
{
this.continuousAudio.enabled = false;
}
Transition from Startup to Loop:
// For effects with startup and loop sounds (like Brostbuster's proton gun)
if (!this.continuousAudio.isPlaying)
{
this.continuousAudio.clip = loopSound;
this.continuousAudio.loop = true;
this.continuousAudio.Play();
}
The primary way to set a projectile's hitbox is through the projectileSize
property, which defines the collision radius. This value is used for both horizontal and vertical collision detection by default.
Basic Configuration:
// In your projectile's Awake() method
this.projectileSize = 10f; // Sets collision radius to 10 pixels
Additional Properties:
-
horizontalProjectile
(default:true
) - Controls wall collision detection method:-
true
: Raycasts from 2×projectileSize behind (X-offset only) in the velocity direction -
false
: Raycasts from projectile center in the velocity direction
-
-
isWideProjectile
(default:false
) - Only affects horizontal projectiles:-
true
: Performs dual collision checks above and below center (for very wide projectiles) -
false
: Single collision check at center
-
Important Notes:
- Broforce's collision system assumes roughly circular/square hitboxes
- Very large projectiles (>20 units) may need custom collision code as the default system wasn't designed for them
- For complex shapes or very large projectiles, you'll need to override collision methods
- The visual sprite size doesn't need to match
projectileSize
- they're independent
Projectiles don't have gravity by default. You have two options:
Option 1: Inherit from CustomGrenade instead of CustomProjectile Grenades have gravity built-in, so if your projectile should arc and bounce, consider making it a grenade.
Option 2: Apply gravity manually in Update()
protected virtual void ApplyGravity()
{
this.yI -= 500f * this.t; // 500 is gravity strength
}
protected override void Update()
{
this.ApplyGravity();
base.Update();
}
The gravity value of 500 is typical for normal falling speed. Adjust higher for faster falling or lower for floatier projectiles.
Flexing and other gesture animations can reset the frame counter during melee attacks. To prevent this, override SetGestureAnimation
and check if the melee is active:
public override void SetGestureAnimation(GestureElement.Gestures gesture)
{
if (this.doingMelee)
{
return; // Don't allow gestures during melee
}
base.SetGestureAnimation(gesture);
}
Wall jumping and climbing reset the base frame counter, which can reset special animations. The easiest solution is to track special frames separately:
// Declare a separate frame counter for specials
protected int usingSpecialFrame = 0;
// Override IncreaseFrame to increment it
protected override void IncreaseFrame()
{
base.IncreaseFrame();
if (this.usingSpecial)
{
++this.usingSpecialFrame;
}
}
// Use the separate counter in AnimateSpecial instead of base.frame
protected override void AnimateSpecial()
If you have questions or need help with creating custom bros, you can join the Free Lives Discord Server and post your questions in the bf-mods channel.