VR-Engage  2.2
Loading...
Searching...
No Matches
Custom Projectile Example

Overview

Purpose: This example demonstrates how to extend VR-Forces' projectile system by creating custom projectile types with additional runtime state. It shows the pattern for inheriting from DtProjectile, adding custom per-projectile properties, and integrating with the projectile factory.

Observable Behavior: When running this example, you will see:

  • Custom projectile type available in VR-Forces simulation
  • Projectiles created with additional time-in-flight state that accumulates while in flight
  • Projectiles function identically to standard projectiles with added time-in-flight tracking

Prerequisites:

  • Understanding of VR-Forces simulation architecture
  • Familiarity with C++ inheritance and virtual functions
  • Basic understanding of projectile ballistics

Related Examples:

  • VR-Forces projectile documentation

Key Concepts Demonstrated

This example demonstrates:

  1. VR-Forces Projectile Extension - Inheriting from DtProjectile to add custom behavior
    • Adds additional per-projectile runtime state
    • Unique aspect: Shows complete pattern for extending simulation objects
  2. Factory Pattern Integration - Registering custom types with VR-Forces factory system
    • Type identifier enables deserialization of custom projectiles
    • Factory creates correct subclass when loading from file
  3. Simulation Object Lifecycle - Proper update logic and state management
    • Override update() to maintain custom state during simulation
    • Base class methods handle standard ballistics and physics

Code Walkthrough

Custom Projectile Class Definition

The custom projectile adds a time-in-flight parameter to track how long the projectile has been airborne:

// File: examples/customProjectile/customProjectile.h
{
public:
DtCustomProjectile(const DtString& name, DtReaderWriterRegistry* const parentRegistry = nullptr);
// Override to update time-in-flight parameter
virtual makVre::DtProjectileDetonationResult update(double deltaTime);
// Required for factory creation
static makVre::DtProjectile* creator(const DtString& name, DtReaderWriterRegistry* const parentRegistry = nullptr);
// Required for cloning and comparison
virtual makVre::DtProjectile* clone() const;
virtual DtString type() const;
protected:
// Custom runtime-only state tracking accumulated time in flight
};
Custom projectile class with additional time-in-flight tracking.
Definition customProjectile.h:54
double myTimeInFlight
Custom time-in-flight parameter.
Definition customProjectile.h:191
virtual DtString type() const override
Return the class type identifier string.
virtual makVre::DtProjectile * clone() const override
Create a deep copy of this projectile.
DtCustomProjectile()
Default constructor - not implemented (projectiles require names)
virtual makVre::DtProjectileDetonationResult update(double deltaTime) override
Update projectile state for one simulation frame.
static makVre::DtProjectile * creator(const DtString &name, DtReaderWriterRegistry *const parentRegistry=nullptr)
Static factory creator method.
Class representing the result of a projectile detonation.
Definition projectileDetonationResult.h:33
Class representing ballistic projectiles in simulations.
Definition projectile.h:42

Key Points:

  • Inherits from DtProjectile to use existing ballistics
  • DtRwReal wrapper provides automatic serialization
  • Static creator() method required for factory instantiation
  • type() returns unique identifier for this projectile class

Constructor and Registry Integration

The constructor initializes the base class and sets the initial time-in-flight state:

// File: examples/customProjectile/customProjectile.cxx
DtCustomProjectile::DtCustomProjectile(const DtString& name, DtReaderWriterRegistry* const parentRegistry)
: DtProjectile(name, parentRegistry)
, myTimeInFlight(0.0)
{
}
DtCustomProjectile::DtCustomProjectile(const DtCustomProjectile& orig, DtReaderWriterRegistry* const parentRegistry)
: DtProjectile(orig, parentRegistry)
, myTimeInFlight(orig.myTimeInFlight)
{
}
  • Time-in-flight starts at zero for new projectiles
  • Time-in-flight is internal runtime state, not configurable from data files
  • Copy constructor preserves accumulated time-in-flight when cloning projectiles
  • Initialization happens before simulation starts

Update Logic for Custom Behavior

The update method is called each simulation frame to maintain custom state:

// File: examples/customProjectile/customProjectile.cxx
DtProjectileDetonationResult DtCustomProjectile::update(double deltaTime)
{
// Update custom runtime state
myTimeInFlight += deltaTime;
// Call base class to handle ballistics, collision detection, etc.
return DtProjectile::update(deltaTime);
}
  • Called once per simulation frame with time delta
  • Custom logic executes before base class ballistics
  • Base class handles trajectory, collision, detonation logic
  • Return value indicates if projectile should be destroyed

Factory Registration

The plugin registers the custom projectile type during VR-Forces initialization:

// File: examples/customProjectile/plugin.cxx
DT_VRF_DLL_PLUGIN bool DtPostInitializeVrfPlugin(DtCgf* cgf)
{
// Register creator function with projectile factory
DtCustomProjectileType, // Type identifier string
DtCustomProjectile::creator); // Static creator function
return true;
}
virtual void addCreatorFcn(const std::string &type, DtProjectileCreatorFcn fcn)
Registers a projectile creation function with the factory.
static DtProjectileFactory * factory()
The factory for creating objects of type DtProjectile. The factory is used to generate projectiles on...
constexpr char DtCustomProjectileType[]
Type identifier string for custom projectile class Used by factory system to create instances and for...
Definition customProjectile.h:25
  • Factory uses type string to instantiate correct subclass
  • Required for loading custom projectiles from saved scenarios
  • Called during VR-Forces post-initialization phase
  • Type string must match value returned by type() method

Static Creator Method

The factory calls this method to instantiate custom projectiles:

// File: examples/customProjectile/customProjectile.cxx
makVre::DtProjectile* DtCustomProjectile::creator(const DtString& name, DtReaderWriterRegistry* const parentRegistry)
{
return new DtCustomProjectile(name, parentRegistry);
}

Key Points:

  • Static method enables factory to create instances without existing object
  • Signature matches factory's creator function pointer type
  • Returns base class pointer for polymorphic use

Deployment and Testing

Installation

Build the example (see Environment Setup & Build Guide):

cd examples\build
cmake --build . --config RelWithDebInfo --target customProjectile

Install the plugin to the VR-Engage installation:

cmake --install . --config RelWithDebInfo

This copies the plugin to <VR-Engage-Install-Dir>\plugins64\vrForces\release\exampleCustomProjectile.dll

Verify installation:

dir "<VR-Engage-Install-Dir>\plugins64\vrForces\release\exampleCustomProjectile.dll"

Configuration

Backend plugin loads automatically: The VR-Engage toolkit installer automatically installs the backend plugin configuration file appData/plugins/exampleCustomProjectile.xml which tells VR-Forces to load the DLL. No manual plugin configuration is required.

Use custom projectile in weapon definitions (in .mtl files):

munition "CustomRound"
{
projectile "DtCustomProjectile"
{
// Standard projectile parameters
mass 10.0
caliber 0.155
velocity 800.0
}
}

For details on munition configuration, see VR-Forces documentation.

Testing Procedure

  1. Launch VR-Forces with the custom projectile plugin loaded
  2. Create entity with weapon using the custom munition type
  3. Fire weapon during simulation
  4. Expected Behavior:
    • Projectile created using DtCustomProjectile class
    • Time-in-flight parameter increments each frame
    • Projectile ballistics and detonation function normally
    • Custom parameter persists if scenario saved/loaded

Verification:

  • Check VR-Forces log (logs\*.log) for plugin initialization:
    [Plugin] Loaded exampleCustomProjectile
    [Projectile Factory] Registered DtCustomProjectile
  • Enable debug logging to see projectile creation:
    [Projectile] Created DtCustomProjectile instance
  • Use VR-Forces debugger to inspect projectile properties during flight

Troubleshooting

Plugin not loading:

  • Verify DLL is in <VR-Engage-Install-Dir>\plugins64\vrForces\release\
  • Check plugin package configuration includes correct path
  • Review VR-Forces log for load errors or missing dependencies

Custom projectile not created:

  • Symptom: Standard DtProjectile created instead of DtCustomProjectile
  • Cause: Type string mismatch or factory not registered
  • Solution: Verify DtCustomProjectileType matches type used in .mtl file

Simulation crash during projectile flight:

  • Symptom: Crash when custom projectile updates or detonates
  • Cause: Missing base class method call or invalid state
  • Solution: Verify update() calls DtProjectile::update() and returns result

Technical Reference

File Structure

examples/customProjectile/
├── CMakeLists.txt # Build configuration
├── README.md # This documentation
├── plugin.cxx # VR-Forces plugin entry point
├── customProjectile.h # Custom projectile class declaration
└── customProjectile.cxx # Custom projectile implementation

Key Classes

Class Base Class Purpose Header
DtCustomProjectile DtProjectile Extended projectile with time-in-flight tracking customProjectile.h

API Methods Used

  • DtProjectile::DtProjectile() - Base class constructor
  • DtProjectile::update() - Frame update with ballistics and collision
  • DtProjectile::factory() - Access to projectile factory singleton
  • DtProjectileFactory::addCreatorFcn() - Register custom projectile type

Reader-Writer Registry Types

VR-Forces provides several parameter wrapper types:

Type Purpose Example
DtRwReal Single floating-point value myMass
DtRwInt Integer value myFragmentCount
DtRwString Text string myMunitionName
DtRwBool Boolean flag myHasGuidance
DtRwVector3 3D vector myVelocity, myAcceleration
DtRwEnum Enumerated value myFuseType

Projectile Update Return Values

Value Meaning
DT_PROJECTILE_CONTINUE Projectile continues flight
DT_PROJECTILE_DETONATE Projectile detonates (impact, fuse)
DT_PROJECTILE_DUD Projectile becomes inactive (fuse failure)
DT_PROJECTILE_DESTROY Projectile should be removed (left simulation area)

Build Targets

  • Plugin: exampleCustomProjectile.dll (Windows)
  • Install Location: plugins64/vrForces/release/

Related Documentation: