Authoring a weapon entity:ru

From Valve Developer Community
Jump to: navigation, search

Необходимо сделать: Данная статья переведена не полностью.

Как не удивительно Source имеет надёжные оружейные системы. Эта статья описывает шаги необходимые для создания пулевых и снарядных оружий и как правильно настроить их для использования в мультиплеере.

Общие сведения

Большинство свойств оружия может быть сконфигурировано с помощью оружейных скриптов
Если всё что тебе требуется - это выстреливать пули с постоянной скоростью, тебе необходимы какие-никакие навыки в программировании.
Оружейный огонь может быть прогнозирован игроком и запозданием сервера
Обычно это выглядит как снаряды в виде ракет, гранат, и других снарядов материализующихся из воздуха на компьютерах наблюдателей.
Моделька от первого лица - это отдельная сущность
Она создается игроком и делится между всеми видами оружия.
В SDK есть широкий выбор оружия для изучения
Valve предоставляет исходный код как однопользовательских, так и многопользовательских игр.

Оружейные скрипты

От оружейных скриптов зависит много свойств оружия , включая её модель, амуницию , звуки , размер обоймы , и имя в пользовательском интерфейсе. Использование, расширение и шифрование оружейных скриптов описано в их статье.

Скрипт оружия будет автоматически загружен для любого оружия с назначенным именем класса. Для более лёгкого кэширования ресурсов, определяемых скриптами вызовите PRECACHE_WEAPON_REGISTER(имя) и никаких кавычек вокруг имени класса.

Точки входа

There are four functions on a weapon which are called each frame by the owning player entity:

Called before the player has moved. In Episode Two, decides whether now is a good time to display a HUD hint on weapon usage.
Called before the player has moved, if the weapon is not active. Does nothing by default.
Called after the player has moved, if the player cannot fire. Does nothing by default.
Called after the player has moved. The most important function, as it leads to one of the following:
  • PrimaryAttack()
  • SecondaryAttack()
  • HandleFireOnEmpty()
  • Reload()
  • WeaponIdle()


A gun will typically shoot when the +attack key is active and (m_flNextPrimaryAttack <= gpGlobals->curtime). For secondary fire, +attack2 and m_flNextSecondaryAttack are checked instead.

To do: How do NPCs attack?


Hitscan bullets are fired by passing a FireBulletsInfo_t object to GetOwner()->FireBullets().

If all you want is a primary fire attack that spits out a constant stream of bullets (no matter whether they are 2 or 0.2 seconds apart) CBaseCombatWeapon is already up to the job and you only need write two functions:

float GetFireRate()
Seconds between each bullet.
const Vector& GetBulletSpread()
Cone within which bullets will be randomly spread. Use the VECTOR_CONE_* #defines to avoid doing the maths yourself.

Skip on to the networking section if this fits your bill; effects will be handled for you. Otherwise see FireBulletsInfo_t for details on setting up your own hitscan attack.


Rockets, grenades, and other projectiles are entities in their own right which exist independently of the weapon they came from. The weapon should spawn them with Create():

CBaseEntity::Create( "my_projectile", GetOwner()->Weapon_ShootPosition(), GetOwner()->EyeAngles(), GetOwnerEntity() );

Note that the owner is the player who own the weapon (GetOwnerEntity()), not the weapon itself.

Tip.png Tip: Don't lag compensate or predict this call - but do predict viewmodel animation, ammo depletion and reloading.

Further reading:


This section assumes you are using the new particle system, which is driven by artists. The old, hard-coded particle tech was never documented.


Tracers should be dispatched from CBaseEntity::MakeTracer(). CBasePlayer is set up to emit the old hard-coded tracer effects; if you want to make changes it's best to implement particles. Doing so is easy:


// always emit tracers; let the particle system determine volume
// (if you don't mind editing CBasePlayer, just change m_iTracerFreq there)
void CMyPlayer::FireBullets( const FireBulletsInfo_t &info )
	FireBulletsInfo_t new_info(info);
	new_info.m_iTracerFreq = 1;

// pass through to weapon, if desired
void CMyPlayer::MakeTracer( const Vector &vecTracerSrc, const trace_t &tr, int iTracerType )

// emit weapon-specific tracer
void CMyWeapon::MakeTracer( const Vector &vecTracerSrc, const trace_t &tr, int iTracerType )
	// 1 is attachment #1, which should be the muzzle

The code above will create a new particle system for each bullet fired, which is suitable for one-shot effects. If your weapon shoots rapidly consider instead dispatching an effect which spawns a stream of particles when the player starts firing and using StopParticleEffects(this) to terminate it when they finish. Test (CBasePlayer::m_nButtons & IN_ATTACK) to achieve this.

Note.png Note: If your weapon has other particle effects you'll need stop the tracers with ParticleProp()->StopEmission(CNewParticleEffect* pEffect) instead, which is client-side.

See also UTIL_ParticleTracer.


To do: CBaseEntity::DoImpactEffect()


To do: Shared code, prediction, predicted viewmodels, compensation...

Sample weapon

See Adding a new weapon to your mod.