Push Gameplay: Difference between revisions

From Valve Developer Community
Jump to navigation Jump to search
(Spelling)
No edit summary
Line 1: Line 1:
{{cleanup}} {{tutpov}}
Push gameplay is one of the many types of mapping techs out there at the moment. The idea truly is to create an area that forces the player to move forward within the map and causes the area usually not able to be back tracked, preventing the player from reaching previous areas of the map.


I realize this is not a complete walkthrough tutorial, but this is as good as I am able to get at my current work load.


I had originally posted on here, in the discussion page, as well as on hl2coding, and would like to direct you back there so I don't have to copy over all the images, that are used just for relaying what I'm trying to do with this entity.
One of the main ideas is to create an event that "pushes" the player forward. Mainly how you create that event is up to you but here are a few ways that mods and even Valve have implemented into their work.


http://www.hl2coding.com/forums/viewtopic.php?t=1205
== '''Height Push''' ==


You guys can ... wikificate this all you wish. Its working, tested and in game as it stands.
One of the most common ones really in nature. The hight push forces the player to move or jump off of a certain hight, and land a few feet below their original height. One of the main reasons this is used is due mainly to it being one of the most easiest things to pull off in mapping. Once the player drops off the ledge then the player cannot go back due to the ledge now being just a little to high to reach. One map in Half Life 2 Episode 1 utilizes this method. The player exits an old hospital and then must drop off a ledge about waste hight high then falls to the ground. However the player cannot return to that area due now to the ledge being just a tad too high.
 
* 1 Brush Entity
* 1 FGD Entry
 
Done...
 
== Brush Entity ==
<pre>//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============//
//
// Purpose: White --- Push Point Entity
//
//=============================================================================//
#include "cbase.h"
extern ConVar showtriggers;
class CPushPoint : public CBaseToggle
{
public:
DECLARE_CLASS( CPushPoint, CBaseToggle );
DECLARE_DATADESC();
void Spawn( void );
virtual void StartTouch( CBaseEntity *pOther );
virtual void EndTouch( CBaseEntity *pOther );
void PlayerUpdateThink();
bool CreateVPhysics( void );
// Push Functions
int GetStatus( void );
private:
// Push Controls
int m_nControlled; // Has this point been captured? By which team?
float m_fCaptured; // Timer for capture
// Alien Variables & Outputs
COutputEvent m_OnAlienCapture;
COutputEvent m_OnAlienStartTouch;
COutputEvent m_OnAlienEndTouch;
CUtlVector<CBasePlayerHandle> m_hAliens;
 
// Human Variables & Outputs
COutputEvent m_OnHumanCapture;
COutputEvent m_OnHumanStartTouch;
COutputEvent m_OnHumanEndTouch;
CUtlVector<CBasePlayerHandle> m_hHumans;
 
// Mapping Tagged Fields
string_t m_sNext;
string_t m_sPrev;
string_t m_sLocation;
float m_fCapture_time;
 
// Misc. Outputs
COutputEvent m_OnCapture;
COutputEvent m_OnStartTouch;
COutputEvent m_OnEndTouch;
};
LINK_ENTITY_TO_CLASS( push_block, CPushPoint );
// Start of our data description for the class
BEGIN_DATADESC( CPushPoint )
// Think Functions
DEFINE_THINKFUNC( PlayerUpdateThink ),
 
// Mapping Tagged Fields
DEFINE_KEYFIELD( m_sNext, FIELD_STRING, "next" ),
DEFINE_KEYFIELD( m_sPrev, FIELD_STRING, "prev" ),
DEFINE_KEYFIELD( m_sLocation, FIELD_STRING, "location"),
DEFINE_KEYFIELD( m_fCapture_time, FIELD_FLOAT, "timer" ),
// Alien Outputs
DEFINE_OUTPUT( m_OnAlienCapture, "OnAlienCapture" ),
DEFINE_OUTPUT( m_OnAlienStartTouch, "OnAlienStartTouch" ),
DEFINE_OUTPUT( m_OnAlienEndTouch, "OnAlienEndTouch" ),
 
// Human Outputs
DEFINE_OUTPUT( m_OnHumanCapture, "OnHumanCapture" ),
DEFINE_OUTPUT( m_OnHumanStartTouch, "OnHumanStartTouch" ),
DEFINE_OUTPUT( m_OnHumanEndTouch, "OnHumanEndTouch" ),
 
// Misc. Outputs
DEFINE_OUTPUT( m_OnCapture, "OnCapture" ),
DEFINE_OUTPUT( m_OnStartTouch, "OnStartTouch" ),
DEFINE_OUTPUT( m_OnEndTouch, "OnEndTouch" ),
END_DATADESC()
//-----------------------------------------------------------------------------
// Purpose: Sets up the entity's initial state
//-----------------------------------------------------------------------------
void CPushPoint::Spawn( void )
{
m_nControlled = 0;
// We should use the bsp
SetSolid( SOLID_BSP );
// And not collide with it
AddSolidFlags( FSOLID_NOT_SOLID );
// But still use it for interaction
AddSolidFlags( FSOLID_TRIGGER );
// use the trigger no draw garbage
if ( showtriggers.GetInt() == 0 )
{
AddEffects( EF_NODRAW );
}
 
// Use our brushmodel
SetModel( STRING( GetModelName() ) );
// Create our physics hull information
CreateVPhysics();
}
//-----------------------------------------------------------------------------
// Purpose: Setup our physics information so we collide properly
//-----------------------------------------------------------------------------
bool CPushPoint::CreateVPhysics( void )
{
// For collisions with physics objects
VPhysicsInitShadow( false, false );
return true;
}
int CPushPoint::GetStatus( void )
{
return m_nControlled;
}
void CPushPoint::StartTouch( CBaseEntity *pOther )
{
// Someone has touched me
if (!pOther->IsPlayer())
return;
 
// they are a player... grab him/her
CBasePlayer *pPlayer = ToBasePlayer(pOther);
// if their team is in control of me...
if (pPlayer->GetTeamNumber() == m_nControlled)
{
// let them know and skip out
Msg("You already control this point '%s'.\n", m_sLocation.ToCStr() );
return;
}
 
// Someone has touched me and im not captured by them...
m_OnStartTouch.FireOutput(pOther,this);
 
// See which previous point to call...
string_t pPrevious = pPlayer->GetTeamNumber() == TEAM_HUMANS? m_sNext : m_sPrev;
// See who the fuck just touched me
pPlayer->GetTeamNumber() == TEAM_HUMANS? m_OnHumanStartTouch.FireOutput(pPlayer, this) : m_OnAlienStartTouch.FireOutput(pPlayer, this);;
 
// Grab the previous push point
CPushPoint *pPush = dynamic_cast<CPushPoint *>(gEntList.FindEntityByName( NULL, pPrevious, NULL ));
// If there is a previous push point AND its not captured by the jerk who touched me...
if (pPush && pPush->GetStatus() != pPlayer->GetTeamNumber())
{
Msg("You do not control the previous point '%s'.\nGo back.\n",  m_sLocation.ToCStr() );
return ;
}
 
// Cool, i guess i can start thinking now.
SetThink( &CPushPoint::PlayerUpdateThink );
SetNextThink( gpGlobals->curtime + 0.2 );
 
BaseClass::StartTouch( pOther );
}
void CPushPoint::EndTouch( CBaseEntity *pOther )
{
// Someone stopped touching me, is it a player?
if (pOther->IsPlayer())
{
// grab the player
CBasePlayer *player = ToBasePlayer(pOther);
 
// see what they team they are on...
if (player->GetTeamNumber() == TEAM_HUMANS)
{
// remove them
m_hHumans.FindAndRemove(player);
// Fire output
m_OnHumanEndTouch.FireOutput(player,this);
}
else if (player->GetTeamNumber() == TEAM_ALIENS)
{
// remove them
m_hAliens.FindAndRemove(player);
// fire output
m_OnAlienEndTouch.FireOutput(player,this);
}
 
// If there is no one of importance touching me...
if (m_hAliens.Count() == 0 && m_hHumans.Count() == 0)
{
// Clear the thinking and timer
SetThink(NULL);
SetNextThink(0);
m_fCaptured = 0;
}
}
BaseClass::EndTouch( pOther );
}
// look for dead/spectating players in our volume, to call touch on
void CPushPoint::PlayerUpdateThink()
{
// Set up my next thought process
SetThink( &CPushPoint::PlayerUpdateThink );
SetNextThink( gpGlobals->curtime + 0.2 );
 
// Clear out the lists
m_hAliens.RemoveAll();
m_hHumans.RemoveAll();
 
// See who is intersecting me and put them into the appropriate list
for (int i=0; i<gpGlobals->maxClients; i++ )
{
// this player
CBasePlayer *player = UTIL_PlayerByIndex( i );
// is ... not a player...
if ( !player )
continue;
// oh they are, they have to be alive too so...
if ( !player->IsAlive() )
continue;
// if the player is intersecting the trigger, track it by storing them into the appropriate listing
if ( Intersects( player ) )
player->GetTeamNumber() == TEAM_ALIENS ? m_hAliens.AddToTail( player ) : m_hHumans.AddToTail( player );
}
 
DevMsg(1,"humans %d aliens %d\n capture time %.2f offset %.2f", m_hHumans.Count(), m_hAliens.Count(), m_fCaptured, m_fCapture_time);
if (m_hAliens.Count() && !m_hHumans.Count() || !m_hAliens.Count() && m_hHumans.Count())
if (m_fCaptured)
{
if (m_fCaptured < gpGlobals->curtime)
{
m_nControlled = m_hAliens.Count() ? TEAM_ALIENS : TEAM_HUMANS;
Msg("You have just captured the %s\n", m_sLocation.ToCStr());
SetThink(NULL);
SetNextThink(0);
}
}
else
m_fCaptured = gpGlobals->curtime + m_fCapture_time;
else
if (m_fCaptured)
{
Msg("Fuck He's Here!\n");
m_fCaptured = 0;
}
}</pre>
== FGD Entry ==
<pre>@include "base.fgd"
 
//-------------------------------------------------------------------------
//
// Push Point Map Entity
//
//-------------------------------------------------------------------------
@SolidClass base(Targetname) = push_block : "Push Entity Brush."
[
    // Mapping Tagged Fields
next(string) : "Next Objective" : "" : "Set this to the next objective's name."
prev(string) : "Previous Objective" : "" : "Set this to the previous objective's name."
    location(string) : "Location" : "" : "Set this to the name of this location to be echoed."
timer(float) : "Time To Capture" : "1.0" : "Set this to the time it takes to capture this point."
 
// Alien Outputs
output OnAlienCapture(void) : "Fired when the Aliens team captures this point."
output OnAlienStartTouch(void) : "Fired when the Aliens team touches this point, if this point has not been captured."
output OnAlienEndTouch(void) : "Fired when the Aliens team stops touching this point, if this point has not been captured."
 
// Human Outputs
output OnHumanCapture(void) : "Fired when the Humans team captures this point."
output OnHumanStartTouch(void) : "Fired when the Humans team touches this point, if this point has not been captured."
output OnHumanEndTouch(void) : "Fired when the Humans team stops touching this point, if this point has not been captured."
 
// Misc. Outputs
output OnCapture(void) : "Fired when this point is captured."
output OnStartTouch(void) : "Fired when this point is touched, if this point has not been captured."
output OnEndTouch(void) : "Fired when a player stops touching this point, if this point has not been captured."
]</pre>
 
----
== Contact me as needed ==
Full tutorial is possibly going to be on my site if this post is frequented enough to give me cause enough to write it.
 
[[User:Imatard|ImaTard]] 04:14, 10 Feb 2006 (PST)

Revision as of 02:43, 27 July 2007

Push gameplay is one of the many types of mapping techs out there at the moment. The idea truly is to create an area that forces the player to move forward within the map and causes the area usually not able to be back tracked, preventing the player from reaching previous areas of the map.


One of the main ideas is to create an event that "pushes" the player forward. Mainly how you create that event is up to you but here are a few ways that mods and even Valve have implemented into their work.

Height Push

One of the most common ones really in nature. The hight push forces the player to move or jump off of a certain hight, and land a few feet below their original height. One of the main reasons this is used is due mainly to it being one of the most easiest things to pull off in mapping. Once the player drops off the ledge then the player cannot go back due to the ledge now being just a little to high to reach. One map in Half Life 2 Episode 1 utilizes this method. The player exits an old hospital and then must drop off a ledge about waste hight high then falls to the ground. However the player cannot return to that area due now to the ledge being just a tad too high.