Game Build Breakdown
Iron Vanguard: Designing Heavy Mech Combat for the Browser
A mech game should feel heavy without feeling slow. Iron Vanguard is a good teaching case because every system has to sell mass: camera lag, recoil, reload timing, missile locks and sector pacing.
Production context
This guide studies Iron Vanguard, a published Supagames game. Repository source: biggames/iron-vanguard/index.html.
The snippets below are intentionally smaller than the production file. They isolate transferable systems so you can reuse the idea in your own browser game without copying every detail of the original project.
1. Heavy Movement Comes from Acceleration
The fastest way to make a mech feel fake is to set velocity directly from input. Heavy machines need acceleration, braking and a maximum speed. That gives the player the sense that they are commanding mass instead of dragging a camera around a map.
The trick is not to make movement unresponsive. Input should affect acceleration immediately, while velocity changes over a short readable interval.
function updateMechMovement(input, dt) {
const desired = new THREE.Vector3(input.x, 0, input.z).normalize();
const accel = input.sprint ? 18 : 11;
mech.velocity.addScaledVector(desired, accel * dt);
mech.velocity.multiplyScalar(Math.exp(-4.2 * dt));
mech.velocity.clampLength(0, input.sprint ? 13 : 8);
mech.position.addScaledVector(mech.velocity, dt);
}
2. Gatling Fire Needs Heat, Not Just Ammo
A Gatling weapon becomes more interesting when firing creates heat. The player can hold the trigger for pressure, but overheating forces a short tactical pause. This creates a readable combat loop without requiring complex inventory.
Heat is also easy to show in the HUD and in the weapon model. Bar color, barrel glow and audio pitch can all read from the same normalized value.
function updateGatling(dt, triggerHeld) {
weapon.heat = Math.max(0, weapon.heat - 0.38 * dt);
if (triggerHeld && weapon.heat < 1 && weapon.fireTimer <= 0) {
fireBulletFromPool();
weapon.heat += 0.055;
weapon.fireTimer = 0.055;
}
weapon.fireTimer -= dt;
}
3. Missile Locks Reward Keeping Aim Stable
Lock-on missiles are not just stronger bullets. They ask the player to hold a target in view long enough to earn a reliable shot. This makes camera direction, target selection and UI reticles part of the weapon system.
A simple lock meter can increase while the target stays inside an aim cone and decay when it leaves. The missile only launches after the meter fills.
function updateMissileLock(target, cameraForward, dt) {
const toTarget = target.position.clone().sub(mech.position).normalize();
const aligned = cameraForward.dot(toTarget) > 0.94;
missile.lock = THREE.MathUtils.clamp(
missile.lock + (aligned ? dt : -dt * 1.8),
0,
1
);
}
4. Boss Sectors Need Downtime
Thirty sectors and six bosses sound exciting, but pacing matters. Between heavy fights, give the player a short state change: reload, repair, choose an upgrade, or simply see the next objective. This resets attention and makes the next wave feel deliberate.
In code, treat intermission as a real game state. Do not keep enemy spawners ticking behind a menu unless that is a conscious design choice.
function enterIntermission(nextSector) {
game.state = "intermission";
spawner.enabled = false;
player.shield = player.maxShield;
hud.showUpgradeChoice(nextSector);
}
5. Build checklist
- Use acceleration and damping to sell mech mass without making controls mushy.
- Add heat or cooldown pressure to rapid-fire weapons so sustained fire has a cost.
- Build lock-on missiles as aim stability systems, not instant guaranteed damage.
- Represent intermissions as explicit states so wave pacing stays under control.