← Home SEEBIE90 DOCS
Download PDF
No copies or uploads of M.A.W.S. assetsExample code is free to useNo printed reproduction or modification of this documentationSuggestions: Discord to the authorLicense

Start here

Your first walker – step by step

A complete, small walker you can build in an evening: a vehicle that walks at a set speed, turns, and has two legs that swing with its speed. Everything else on this site builds on this skeleton.

1. Vehicle prefab→2. Drive component→3. Two legs→4. Leg component→5. Test→6. Multiplayer

Step 1 – Start from a vehicle

A walker in Arma Reforger is a vehicle – that gives you seats, damage, replication and physics for free.

  1. In the Resource Browser find a simple wheeled vehicle prefab (for example a car or truck).
  2. Right click → Inherit in addon (creates your own prefab that inherits everything). Name it MyWalker.et.
  3. Open it. For now keep the car mesh – you will replace it with your walker body later. Seats keep working.
CheckYou should now be able to place MyWalker.et in a world and drive it like the original car.

Step 2 – Take over the driving

This component reads the driver's normal car input (throttle, brake, steering) and writes the velocity itself. The wheels still exist but no longer decide how fast you go.

Example code – free to useScripts/Game/MyWalker/MyWalker_SimpleDriveComponent.c
[ComponentEditorProps(category: "MyWalker", description: "Simple walker drive: sets the velocity directly")]
class MyWalker_SimpleDriveComponentClass : ScriptComponentClass
{
}

class MyWalker_SimpleDriveComponent : ScriptComponent
{
	[Attribute("15", desc: "Top speed forward (km/h)")]
	protected float m_fMaxSpeedKmh;

	[Attribute("5", desc: "Top speed backwards (km/h)")]
	protected float m_fMaxReverseKmh;

	[Attribute("2", desc: "Acceleration (m/s per second)")]
	protected float m_fAccel;

	[Attribute("35", desc: "Turn rate at full steering (degrees per second)")]
	protected float m_fTurnRate;

	protected float m_fSpeed;					// current walking speed (m/s, + = forward)
	protected RplComponent m_Rpl;
	protected VehicleWheeledSimulation m_Sim;

	override void OnPostInit(IEntity owner)
	{
		super.OnPostInit(owner);
		m_Rpl = RplComponent.Cast(owner.FindComponent(RplComponent));
		m_Sim = VehicleWheeledSimulation.Cast(owner.FindComponent(VehicleWheeledSimulation));
		SetEventMask(owner, EntityEvent.FRAME);
	}

	override void EOnFrame(IEntity owner, float timeSlice)
	{
		// Only the machine that simulates this vehicle may move it.
		if (m_Rpl && !m_Rpl.IsOwner())
			return;

		Physics phys = owner.GetPhysics();
		if (!phys || !phys.IsDynamic() || !m_Sim)
			return;

		// --- 1. what does the driver want?
		float throttle = m_Sim.GetThrottle();			// 0..1 (W)
		float steering = m_Sim.GetSteering();			// -1..1 (A/D)
		bool reverse = IsReverseGear();

		float target = throttle * m_fMaxSpeedKmh / 3.6;	// km/h -> m/s
		if (reverse)
			target = -throttle * m_fMaxReverseKmh / 3.6;
		if (!m_Sim.EngineIsOn())
			target = 0;

		// --- 2. move the current speed toward the target, but not faster than the acceleration allows
		float step = m_fAccel * timeSlice;
		m_fSpeed = m_fSpeed + Math.Clamp(target - m_fSpeed, -step, step);

		// --- 3. write the velocity: forward speed along the vehicle's nose, keep the vertical part (gravity)
		vector forward = owner.GetTransformAxis(2);
		forward[1] = 0;
		forward.Normalize();

		vector v = phys.GetVelocity();
		vector newVel = forward * m_fSpeed;
		newVel[1] = v[1];
		phys.SetVelocity(newVel);

		// --- 4. turning: set the rotation speed around the up axis
		vector w = phys.GetAngularVelocity();
		w[1] = steering * m_fTurnRate * Math.DEG2RAD;
		phys.SetAngularVelocity(w);
	}

	//! The gearbox numbers gears from reverse up: everything below neutral is reverse.
	protected bool IsReverseGear()
	{
		int reverseGears = m_Sim.GearboxGearsCount() - m_Sim.GearboxForwardGearsCount() - 1;
		return m_Sim.GetGear() < reverseGears;
	}
}

Compile, add MyWalker_SimpleDriveComponent to MyWalker.et, place it, get in, start the engine and drive.

CheckThe vehicle accelerates evenly to exactly 15 km/h and stops when you let go – no matter what the engine or gearbox would do. If it turns the wrong way, multiply the steering by -1.
PitfallIf nothing happens, check that EOnFrame runs at all (add a Print). Forgetting SetEventMask(owner, EntityEvent.FRAME) is the most common reason.

Step 3 – Add two legs

  1. In the prefab, add two child entities (right click the vehicle in the hierarchy → add child), name them LegL and LegR.
  2. Give each a MeshObject component with a simple mesh (a long box is fine for now).
  3. Note the position where each leg should hang from the body (the hip). You will type it into the component.

Step 4 – Make the legs swing

This component runs on every machine, because it is only for looks. It measures how fast the vehicle moves (from the position change, which works on every machine) and swings the legs forward and back in opposite phase.

Example code – free to useScripts/Game/MyWalker/MyWalker_SimpleLegsComponent.c
[ComponentEditorProps(category: "MyWalker", description: "Swings two child legs with the walking speed")]
class MyWalker_SimpleLegsComponentClass : ScriptComponentClass
{
}

class MyWalker_SimpleLegsComponent : ScriptComponent
{
	[Attribute("LegL", desc: "Name of the left leg child entity")]
	protected string m_sLeftName;

	[Attribute("LegR", desc: "Name of the right leg child entity")]
	protected string m_sRightName;

	[Attribute("-1.2 2.5 0", desc: "Left hip position relative to the vehicle (m)")]
	protected vector m_vLeftHip;

	[Attribute("1.2 2.5 0", desc: "Right hip position relative to the vehicle (m)")]
	protected vector m_vRightHip;

	[Attribute("2.0", desc: "Distance covered per full step cycle (m)")]
	protected float m_fStride;

	[Attribute("30", desc: "Maximum leg swing (degrees)")]
	protected float m_fSwingDeg;

	protected IEntity m_LegL;
	protected IEntity m_LegR;
	protected vector m_vLastPos;
	protected float m_fPhase;		// 0..1, one full step cycle
	protected float m_fSpeed;		// smoothed, m/s

	override void OnPostInit(IEntity owner)
	{
		super.OnPostInit(owner);
		m_vLastPos = owner.GetOrigin();
		SetEventMask(owner, EntityEvent.FRAME);
	}

	//! Children are attached a moment after creation: look them up lazily.
	protected void FindLegs(IEntity owner)
	{
		IEntity child = owner.GetChildren();
		while (child)
		{
			if (child.GetName() == m_sLeftName)
				m_LegL = child;
			else if (child.GetName() == m_sRightName)
				m_LegR = child;
			child = child.GetSibling();
		}
	}

	override void EOnFrame(IEntity owner, float timeSlice)
	{
		if (timeSlice <= 0)
			return;
		if (!m_LegL || !m_LegR)
			FindLegs(owner);
		if (!m_LegL || !m_LegR)
			return;

		// --- speed along the vehicle's nose, measured from the movement (works on every machine)
		vector pos = owner.GetOrigin();
		vector delta = pos - m_vLastPos;
		m_vLastPos = pos;
		float measured = vector.Dot(delta, owner.GetTransformAxis(2)) / timeSlice;
		m_fSpeed = Math.Lerp(m_fSpeed, measured, Math.Clamp(timeSlice * 5, 0, 1));	// smooth it

		// --- advance the step cycle: faster walking = faster steps
		m_fPhase = m_fPhase + (m_fSpeed / m_fStride) * timeSlice;
		m_fPhase = m_fPhase - Math.Floor(m_fPhase);		// keep it 0..1

		// --- swing amount grows with speed, standing still = legs straight
		float amount = Math.Clamp(Math.AbsFloat(m_fSpeed) / 2.0, 0, 1);
		float swing = Math.Sin(m_fPhase * Math.PI2) * m_fSwingDeg * amount;

		PoseLeg(m_LegL, m_vLeftHip, swing);
		PoseLeg(m_LegR, m_vRightHip, -swing);		// opposite phase
	}

	//! Rotate a leg around its hip (pitch = forward/back).
	protected void PoseLeg(IEntity leg, vector hip, float pitchDeg)
	{
		vector mat[4];
		Math3D.AnglesToMatrix(Vector(0, pitchDeg, 0), mat);	// yaw, pitch, roll in degrees
		mat[3] = hip;
		leg.SetLocalTransform(mat);
		leg.Update();
	}
}
CheckStanding: legs hang straight. Walking: they swing in opposite directions, faster when you walk faster. If a leg rotates around its middle instead of the hip, the mesh pivot is in the wrong place – move the mesh so its origin is at the top of the leg.

Step 5 – Hide the car

Replace the vehicle's mesh with your body mesh, or hide it, and make the wheels invisible (remove their meshes in the prefab). The wheels keep working as invisible ground contact – that is exactly how M.A.W.S. works.

Step 6 – Test in multiplayer

  1. Start a dedicated server and a client with your addon.
  2. Drive: the drive component runs only where IsOwner() is true, so the walker must still move.
  3. Watch another player's walker: its legs must swing too – the leg component measures the movement locally.
Known issueIf the legs of other players' walkers do not move on your client, the vehicle's EOnFrame is not ticking there. That is an engine behaviour for vehicles you do not own. The fix is a fallback tick, see Architecture → The fallback tick.

Where to go next

You wantRead
smooth turning toward the camera, no tipping overLeg drive
feet that stay on the ground, knees that bendProcedural leg rig
a crew that can aim while walkingTorso & aim stabilization
weapons and parts that can be swappedLoadout & modules
Example code on this site is free to use in your own projects (credit appreciated). The M.A.W.S. mods, their code and assets are covered by the M.A.W.S. License – no copies or uploads. This documentation may not be reproduced in print or modified. Suggestions: Discord. Arma Reforger / Enfusion are trademarks of Bohemia Interactive.
Impressum · Privacy Policy