Simple Projectile Bullets: Difference between revisions
No edit summary |
Thunder4ik (talk | contribs) m (clean up, added orphan, underlinked tags) |
||
(3 intermediate revisions by one other user not shown) | |||
Line 1: | Line 1: | ||
{{Multiple issues| | |||
{{Underlinked|date=January 2024}} | |||
{{Orphan|date=January 2024}} | |||
}} | |||
It's a great article, but there's many additional features that you might not want, and it overrides the existing hitscan method of firing bullets. This can be problematic, because you may want to keep the existing hitscan methods in-tact. | Adding simple projectile bullets is easier than you'd think. If you've looked around the site, you might have found [[Realistic Simulated Bullets]]. | ||
It's a great article, but there's many additional features that you might not want, and it overrides the existing hitscan method of firing bullets. This can be problematic, because you may want to keep the existing hitscan methods in-tact. | |||
That's where this comes in. This is a very simple method of adding projectile bullets that utilizes parts of the existing bullet methods without overriding them. It fires an invisible bullet and uses tracers as a visual stand-in for the bullet. | That's where this comes in. This is a very simple method of adding projectile bullets that utilizes parts of the existing bullet methods without overriding them. It fires an invisible bullet and uses tracers as a visual stand-in for the bullet. | ||
{{note|This has only been tested in SDK 2013 SP and won't work in MP without modifications. Feel free to edit the article to make the necessary changes to make it functional in MP.}} | {{note|This has only been tested in SDK 2013 SP and won't work in MP without modifications. Feel free to edit the article to make the necessary changes to make it functional in MP.}} | ||
==The Code== | ==The Code== | ||
Line 20: | Line 24: | ||
#include "baseentity_shared.h" | #include "baseentity_shared.h" | ||
#include "baseanimating.h" | #include "baseanimating.h" | ||
class CActualBullet : public CBaseAnimating | class CActualBullet : public CBaseAnimating | ||
Line 93: | Line 96: | ||
void CActualBullet::Think(void) | void CActualBullet::Think(void) | ||
{ | { | ||
SetNextThink(gpGlobals->curtime + 0.05f); | SetNextThink(gpGlobals->curtime + 0.05f); | ||
Vector vecStart; | Vector vecStart; | ||
Line 137: | Line 136: | ||
} | } | ||
</source> | </source> | ||
===baseentity_shared.cpp=== | ===baseentity_shared.cpp=== | ||
Now, find the following around line 1596: | Now, find the following around line 1596: | ||
Line 149: | Line 149: | ||
<source lang=cpp> | <source lang=cpp> | ||
CBaseCombatWeapon *pWeapon = pPlayer->GetActiveWeapon(); | CBaseCombatWeapon *pWeapon = pPlayer->GetActiveWeapon(); | ||
if (pWeapon | if (!pWeapon) | ||
return; | return; | ||
</source> | </source> | ||
Line 179: | Line 179: | ||
And that's it! You now have simple projectile bullets. This can be used for both player weapons AND NPC's. | And that's it! You now have simple projectile bullets. This can be used for both player weapons AND NPC's. | ||
You can see the effect in action [https://www.youtube.com/watch?v=Ksqy8vejjCk here]. | |||
[[Category:Free source code]] | [[Category:Free source code]] | ||
[[Category:Weapons programming]] | [[Category:Weapons programming]] |
Latest revision as of 22:54, 21 January 2024





January 2024

You can help by

January 2024
Adding simple projectile bullets is easier than you'd think. If you've looked around the site, you might have found Realistic Simulated Bullets.
It's a great article, but there's many additional features that you might not want, and it overrides the existing hitscan method of firing bullets. This can be problematic, because you may want to keep the existing hitscan methods in-tact.
That's where this comes in. This is a very simple method of adding projectile bullets that utilizes parts of the existing bullet methods without overriding them. It fires an invisible bullet and uses tracers as a visual stand-in for the bullet.

The Code
Add both of the following files to your Server project.
actual_bullet.h
#ifndef ACTUALBULLET_H
#define ACTUALBULLET_H
#include "cbase.h"
#include "baseentity.h"
#include "baseentity_shared.h"
#include "baseanimating.h"
class CActualBullet : public CBaseAnimating
{
DECLARE_CLASS(CActualBullet, CBaseAnimating);
DECLARE_DATADESC();
public:
void Start(void);
void Think(void);
void Stop(void);
Vector m_vecDir;
int m_Speed;
FireBulletsInfo_t info;
};
///so this is the actual bullet creation function.
inline void FireActualBullet(FireBulletsInfo_t &info, int iSpeed, const char* tracertype)
{
if (!info.m_pAttacker)
{
Warning("ERROR: Firing an actual bullet without an attacker specified. This will crash the game without it. Cancelling.\n");
return;
}
int iShots = info.m_iShots;
for (int i = 0; i < iShots; i++)
{
Vector vecSpreadSrc = info.m_vecSpread;
Vector vecSpread = Vector(RandomFloat(-vecSpreadSrc[0], vecSpreadSrc[0]), RandomFloat(-vecSpreadSrc[1], vecSpreadSrc[1]), RandomFloat(-vecSpreadSrc[2], vecSpreadSrc[2]));
Vector vecShot = info.m_vecDirShooting + vecSpread;
Vector vecShotDir = vecShot.Normalized();
trace_t tr;
UTIL_TraceLine(info.m_vecSrc, info.m_vecSrc + (vecShotDir * MAX_TRACE_LENGTH), MASK_SHOT, info.m_pAttacker, COLLISION_GROUP_NONE, &tr);
CActualBullet *pBullet = (CActualBullet*)CBaseEntity::Create("actual_bullet", info.m_vecSrc, vec3_angle, info.m_pAttacker);
pBullet->m_vecDir = vecShotDir;
pBullet->m_Speed = iSpeed;
pBullet->SetOwnerEntity(info.m_pAttacker);
pBullet->SetAbsOrigin(info.m_vecSrc);
pBullet->info = info;
pBullet->Start();
UTIL_Tracer(info.m_vecSrc, tr.endpos, info.m_pAttacker->entindex(), -1, (float)iSpeed, false, tracertype, 0);
}
}
#endif //ACTUALBULLET_H
actual_bullet.cpp
#include "cbase.h"
#include "actual_bullet.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
ConVar debug_actual_bullet("debug_actual_bullet", "0", FCVAR_GAMEDLL);
LINK_ENTITY_TO_CLASS(actual_bullet, CActualBullet);
BEGIN_DATADESC(CActualBullet)
END_DATADESC()
void CActualBullet::Start(void)
{
SetThink(&CActualBullet::Think);
SetNextThink(gpGlobals->curtime);
SetOwnerEntity(info.m_pAttacker);
}
void CActualBullet::Think(void)
{
SetNextThink(gpGlobals->curtime + 0.05f);
Vector vecStart;
Vector vecEnd;
float flInterval;
flInterval = gpGlobals->curtime - GetLastThink();
vecStart = GetAbsOrigin();
vecEnd = vecStart + (m_vecDir * (m_Speed * flInterval));
float flDist = (vecStart - vecEnd).Length();
trace_t tr;
UTIL_TraceLine(vecStart, vecEnd, MASK_SHOT, this, COLLISION_GROUP_NONE, &tr);
if (debug_actual_bullet.GetBool() == true)
DebugDrawLine(vecStart, vecEnd, 0, 128, 255, false, 0.05f);
if (tr.fraction != 1.0)
{
FireBulletsInfo_t info2;
info2.m_iShots = 1;
info2.m_vecSrc = vecStart;
info2.m_vecSpread = vec3_origin;
info2.m_vecDirShooting = m_vecDir;
info2.m_flDistance = flDist;
info2.m_iAmmoType = info.m_iAmmoType;
info2.m_iTracerFreq = 0;
GetOwnerEntity()->FireBullets(info2);
Stop();
}
else
{
SetAbsOrigin(vecEnd);
}
}
void CActualBullet::Stop(void)
{
SetThink(NULL);
UTIL_Remove(this);
}
Now, find the following around line 1596:
void CBaseEntity::FireBullets( const FireBulletsInfo_t &info )
Right before this:
int rumbleEffect = pPlayer->GetActiveWeapon()->GetRumbleEffect();
Add this:
CBaseCombatWeapon *pWeapon = pPlayer->GetActiveWeapon();
if (!pWeapon)
return;
Usage
To use the projectile bullets, add the following to the top of your weapon file:
#include "actual_bullet.h"
In your PrimaryAttack() function, set up your FireBulletsInfo_t struct like you normally would. Example:
FireBulletsInfo_t info;
info.m_iAmmoType = m_iPrimaryAmmoType;
info.m_iShots = 1;
info.m_vecSrc = pPlayer->Weapon_ShootPosition();
info.m_vecDirShooting = pPlayer->GetAutoaimVector(AUTOAIM_SCALE_DEFAULT);
info.m_vecSpread = GetBulletSpread();
info.m_pAttacker = GetOwnerEntity();
But instead of doing FireBullets(), do this:
FireActualBullet(info, 12000, GetTracerType());
Change the 12000 to whatever speed you wish, or if you want, you can set it to a ConVar to fine tune it in game.
And that's it! You now have simple projectile bullets. This can be used for both player weapons AND NPC's.
You can see the effect in action here.