Authoring a Brush Entity: Difference between revisions

From Valve Developer Community
Jump to navigation Jump to search
m (added russian otherlang)
(partial rewrite)
Line 1: Line 1:
Our last example dealt with [[Authoring a Model Entity|giving entities a model]]. Here we’ll use world architecture (or <i>brushes</i>) to represent our entity and how it collides and moves around the world. We’ll also look at the touch function, available to all entities. This will let us make the entity move when touched.
''This tutorial assumes you have completed and understood [[Authoring a Logical Entity]] and, ideally, [[Authoring a Model Entity]].''


=Create a .CPP file for the new entity=
Our last example dealt with [[Authoring a Model Entity|giving entities a model]]. Here we'll use world architecture ("[[brush]]es") to represent our entity and to decide how it collides and moves around the world. We'll also look at the touch function, available to all entities, which we will use to make the entity move when touched.


[[Image:Add existing item3.gif|Add the source file to the server.dll project by right-clicking.]]
== Declaration and DATADESC ==


* Create a file named <code>sdk_brushentity.cpp</code>. The file should go under the dlls folder under your source code folder. For example, if you installed the source code into C:\MyMod\src, then you would create a file called <code>C:\MyMod\src\dlls\sdk\sdk_brushentity.cpp</code>.
<span style="color:blue;">#include</span> <span style="color:brown;">"cbase.h"</span>
* Next, copy [[Brush Entity Code | this code]] and paste it into this new file.
* Last, add this file to your server.dll project. If you opened the <code>game_sdk.sln</code> solution, then you can right-click on the <code>hl</code> project in the Solution Explorer window and choose '''Add''', then '''Add Existing Item'''.
<span style="color:blue;">class</span> CMyBrushEntity : <span style="color:blue;">public</span> CBaseToggle
{
<span style="color:blue;">public</span>:
DECLARE_CLASS( CMyBrushEntity, CBaseToggle );
DECLARE_DATADESC();
<span style="color:blue;">void</span> Spawn();
<span style="color:blue;">bool</span> CreateVPhysics();
<span style="color:blue;">void</span> BrushTouch( CBaseEntity *pOther );
};
LINK_ENTITY_TO_CLASS( my_brush_entity, CMyBrushEntity );
BEGIN_DATADESC( CMyBrushEntity )
<span style="color:green;">// Declare this function as being a touch function</span>
DEFINE_ENTITYFUNC( BrushTouch ),
END_DATADESC()


=Walking through the code=
A brush entity can inherit from <code>CBaseEntity</code> if it really wants to, but in our example we'll take advantage of some code that's already written in <code>CBaseToggle</code>.<!-- Which is deprecated now, so I'll have to figure out the proper baseclass before finishing -->


==Creating the Class Definition==
<code>DEFINE_ENTITYFUNC</code> is a badly-named command to declare what function should be executed [[OnTouch]] - i.e. when the entity touches or is touched by another. Aside from our intended use, it's good for for explode-on-contact ordnance, flying entities colliding with things, picking up health etc. (on foot or in a vehicle), [[trigger]]s, and so on.
<pre>
class CMyBrushEntity : public CBaseToggle
{
public:
      DECLARE_CLASS( CMyBrushEntity, CBaseToggle );
      DECLARE_DATADESC();


      void Spawn( void );
There is no constructor for this entity as there are no variables to initialise.
      bool CreateVPhysics( void );


      void BrushTouch( CBaseEntity *pOther );
== Spawn() ==
};
</pre>


We descend our new entity from the CBaseToggle class. This class has some basic functions to help us move our brush entity through the world.
<span style="color:blue;">void</span> CMyBrushEntity::Spawn()
 
{
==Defining the Data Description==
<span style="color:green;">// We want to capture touches from other entities</span>
<pre>
SetTouch( &CMyBrushEntity::BrushTouch );
LINK_ENTITY_TO_CLASS( my_brush_entity, CMyBrushEntity );
 
<span style="color:green;">// We should collide with physics</span>
// Start of our data description for the class
SetSolid( SOLID_VPHYSICS );
BEGIN_DATADESC( CMyBrushEntity )
   
<span style="color:green;">// We push things out of our way</span>
    // Declare this function as being a touch function
SetMoveType( MOVETYPE_PUSH );
    DEFINE_ENTITYFUNC( BrushTouch ),
 
<span style="color:green;">// Use our brushmodel</span>
END_DATADESC()
SetModel( STRING( GetModelName() ) );
</pre>
 
<span style="color:green;">// Create our physics hull information</span>
Here we simply declare our touch function that we’ll use. See the [[Data Descriptions|Data Description Table Document]] for more information.
CreateVPhysics();
 
}
==Create the Spawn() function==
<pre>
void CMyBrushEntity::Spawn( void )
{
      // We want to capture touches from other entities
      SetTouch( &CMyBrushEntity::BrushTouch );
 
      // We should collide with physics
      SetSolid( SOLID_VPHYSICS );
     
      // We push things out of our way
      SetMoveType( MOVETYPE_PUSH );
     
      // Use our brushmodel
      SetModel( STRING( GetModelName() ) );
 
      // Create our physics hull information
      CreateVPhysics();
}
</pre>


The first thing we do in this block is setup our touch function to point to <i>BrushTouch()</i> where we’ll do our movement code. Next we tell the entity to use <code>SOLID_VPHYSICS</code> so we’ll use our exact bounds to collide. Setting the entity to <code>MOVETYPE_PUSH</code> means that we’ll attempt to move entities out of our way, instead of just being blocked.
The first thing we do in this block is setup our touch function to point to <i>BrushTouch()</i> where we’ll do our movement code. Next we tell the entity to use <code>SOLID_VPHYSICS</code> so we’ll use our exact bounds to collide. Setting the entity to <code>MOVETYPE_PUSH</code> means that we’ll attempt to move entities out of our way, instead of just being blocked.
Line 68: Line 58:
In this example we use the <code>SetModel()</code> with our model name from the editor. In this case it tells the entity to use its brush model, as defined in the map.
In this example we use the <code>SetModel()</code> with our model name from the editor. In this case it tells the entity to use its brush model, as defined in the map.


<pre>
== CreateVPhysics() ==
bool CMyBrushEntity::CreateVPhysics( void )
{
      // For collisions with physics objects
      VPhysicsInitShadow( false, false );


      return true;
bool CMyBrushEntity::CreateVPhysics()
}
{
</pre>
// For collisions with physics objects
VPhysicsInitShadow( false, false );
return true;
}


Finally, we call <code>CreateVPhysics()</code> to setup our collision shadow. This is what we’ll use to collide with physics objects in the world. Without this, the brush would pass through those objects.
Finally, we call <code>CreateVPhysics()</code> to setup our collision shadow. This is what we’ll use to collide with physics objects in the world. Without this, the brush would pass through those objects.<!-- Why is this a separate function? The returned value is never used... -->


==Create the BrushTouch() function==
== BrushTouch() ==


The entity has been told to notify us when its been touched, via the <code>BrushTouch()</code> function. When we receive this notification, we’ll cause the entity to move away from the entity that touched it. To do this, we’ll need information about the events surrounding the touch. This information is provided in the <code>trace_t</code> structure, returned by the <code>GetTouchTrace()</code> function. This returns the actual trace collision that generated the event.
The entity has been told to notify us when its been touched, via the <code>BrushTouch()</code> function. When we receive this notification, we’ll cause the entity to move away from the entity that touched it. To do this, we’ll need information about the events surrounding the touch. This information is provided in the <code>trace_t</code> structure, returned by the <code>GetTouchTrace()</code> function. This returns the actual trace collision that generated the event.


<pre>
void CMyBrushEntity::BrushTouch( CBaseEntity *pOther )
void CMyBrushEntity::BrushTouch( CBaseEntity *pOther )
{
{
// Get the collision information
    // Get the collision information
const trace_t &tr = GetTouchTrace();
    const trace_t &tr = GetTouchTrace();
 
// We want to move away from the impact point along our surface
    // We want to move away from the impact point along our surface
Vector vecPushDir = tr.plane.normal;
    Vector vecPushDir = tr.plane.normal;
vecPushDir.Negate();
    vecPushDir.Negate();
vecPushDir.z = 0.0f;
    vecPushDir.z = 0.0f;
 
// Move slowly in that direction
    // Move slowly in that direction
LinearMove( GetAbsOrigin() + ( vecPushDir * 64.0f ), 32.0f );
    LinearMove( GetAbsOrigin() + ( vecPushDir * 64.0f ), 32.0f );
}
}
</pre>


First we retrieve the normal of the surface that was hit. In our case, this will be one of the planes of the brush entity. We negate that value to point towards the direction of the impact, and then remove the Z component of the direction to keep us parallel to the floor.
First we retrieve the normal of the surface that was hit. In our case, this will be one of the planes of the brush entity. We negate that value to point towards the direction of the impact, and then remove the Z component of the direction to keep us parallel to the floor.
Line 104: Line 92:
Finally, we use the <code>LinearMove()</code> function to cause the brush to move to a location at a given speed. The <code>LinearMove()</code> function is implemented by <code>CBaseToggle</code> and takes care of behind-the-scenes maintenance in how the brush model moves.
Finally, we use the <code>LinearMove()</code> function to cause the brush to move to a location at a given speed. The <code>LinearMove()</code> function is implemented by <code>CBaseToggle</code> and takes care of behind-the-scenes maintenance in how the brush model moves.


==Create The FGD Entry==
== FGD entry ==
 
To use the entity within Hammer, we’ll need to create an entry in our FGD file. Hammer will use this data to interpret the various keyvalues and functions the entity is exposing. See the [[FGD|FGD Format document]] for more information about FGD files.
 
The FGD entry allows you to assign the entity to a brush.


<pre>
@include "base.fgd"
@SolidClass base(Targetname) = my_brush_entity : "Tutorial brush entity."
[
@SolidClass base(Targetname) = my_brush_entity : "Tutorial brush entity."
[
]
</pre>
]


Be sure to add the line <code>@include "base.fgd"</code> at the top of the FGD file, which provides Hammer with some necessary functions. (That is appropriate for a total conversion. For a mod based on existing content, include the appropriate FGD instead; eg, for an [[HL2]] mod, include <code>halflife2.fgd</code> instead of <code>base.fgd</code>.)
== See also ==


*[[Brush Entity Code|Tutorial code in full]]
*[[My First Entity]]
{{otherlang:en}}
{{otherlang:en}}
{{otherlang:en:ru|Authoring a Brush Entity:ru}}
{{otherlang:en:ru|Authoring a Brush Entity:ru}}


[[Category:Programming]]
[[Category:Programming]]

Revision as of 13:56, 2 March 2008

This tutorial assumes you have completed and understood Authoring a Logical Entity and, ideally, Authoring a Model Entity.

Our last example dealt with giving entities a model. Here we'll use world architecture ("brushes") to represent our entity and to decide how it collides and moves around the world. We'll also look at the touch function, available to all entities, which we will use to make the entity move when touched.

Declaration and DATADESC

#include "cbase.h"

class CMyBrushEntity : public CBaseToggle
{
public:
	DECLARE_CLASS( CMyBrushEntity, CBaseToggle );
	DECLARE_DATADESC();

	void Spawn();
	bool CreateVPhysics();

	void BrushTouch( CBaseEntity *pOther );
};

LINK_ENTITY_TO_CLASS( my_brush_entity, CMyBrushEntity );

BEGIN_DATADESC( CMyBrushEntity )
	
	// Declare this function as being a touch function
	DEFINE_ENTITYFUNC( BrushTouch ),

END_DATADESC()

A brush entity can inherit from CBaseEntity if it really wants to, but in our example we'll take advantage of some code that's already written in CBaseToggle.

DEFINE_ENTITYFUNC is a badly-named command to declare what function should be executed OnTouch - i.e. when the entity touches or is touched by another. Aside from our intended use, it's good for for explode-on-contact ordnance, flying entities colliding with things, picking up health etc. (on foot or in a vehicle), triggers, and so on.

There is no constructor for this entity as there are no variables to initialise.

Spawn()

void CMyBrushEntity::Spawn()
{
	// We want to capture touches from other entities
	SetTouch( &CMyBrushEntity::BrushTouch );

	// We should collide with physics
	SetSolid( SOLID_VPHYSICS );
	
	// We push things out of our way
	SetMoveType( MOVETYPE_PUSH );
	
	// Use our brushmodel
	SetModel( STRING( GetModelName() ) );

	// Create our physics hull information
	CreateVPhysics();
}

The first thing we do in this block is setup our touch function to point to BrushTouch() where we’ll do our movement code. Next we tell the entity to use SOLID_VPHYSICS so we’ll use our exact bounds to collide. Setting the entity to MOVETYPE_PUSH means that we’ll attempt to move entities out of our way, instead of just being blocked.

In this example we use the SetModel() with our model name from the editor. In this case it tells the entity to use its brush model, as defined in the map.

CreateVPhysics()

bool CMyBrushEntity::CreateVPhysics()
{
	// For collisions with physics objects
	VPhysicsInitShadow( false, false );

	return true;
}

Finally, we call CreateVPhysics() to setup our collision shadow. This is what we’ll use to collide with physics objects in the world. Without this, the brush would pass through those objects.

BrushTouch()

The entity has been told to notify us when its been touched, via the BrushTouch() function. When we receive this notification, we’ll cause the entity to move away from the entity that touched it. To do this, we’ll need information about the events surrounding the touch. This information is provided in the trace_t structure, returned by the GetTouchTrace() function. This returns the actual trace collision that generated the event.

void CMyBrushEntity::BrushTouch( CBaseEntity *pOther )
{
	// Get the collision information
	const trace_t &tr = GetTouchTrace();

	// We want to move away from the impact point along our surface
	Vector	vecPushDir = tr.plane.normal;
	vecPushDir.Negate();
	vecPushDir.z = 0.0f;

	// Move slowly in that direction
	LinearMove( GetAbsOrigin() + ( vecPushDir * 64.0f ), 32.0f );
}

First we retrieve the normal of the surface that was hit. In our case, this will be one of the planes of the brush entity. We negate that value to point towards the direction of the impact, and then remove the Z component of the direction to keep us parallel to the floor.

Finally, we use the LinearMove() function to cause the brush to move to a location at a given speed. The LinearMove() function is implemented by CBaseToggle and takes care of behind-the-scenes maintenance in how the brush model moves.

FGD entry

@include "base.fgd"

@SolidClass base(Targetname) = my_brush_entity : "Tutorial brush entity."
[
	
]

See also

Template:Otherlang:en Template:Otherlang:en:ru