Talk:Point viewcontrol

From Valve Developer Community
Revision as of 20:25, 1 May 2013 by ArmageddonSnipe (talk | contribs) (Increase or decrease the speed at which the camera looks at the "Entity to look at")

Jump to: navigation, search

Update August 17th, 2006: The Camera-Not-Looking-At-Target bug has been fixed in the SDK release at the beginning of August, 2006. The other two bugs are still present, however, and the fixes below still apply.

Bugs

Camera won't look at target

Note:This bug was corrected in the 8/2006 SDK update.

There is a bug with the camera pointing at the targetted entity. Currently (8/9/06) the camera always points to the origin when a target is set. To fix this, go into the code and open triggers.cpp. Starting at line 2892, the code looks like

if ( m_iAttachmentIndex )
{
 	Vector vecOrigin;
	m_hTarget->GetBaseAnimating()->GetAttachment( m_iAttachmentIndex, vecOrigin );
	VectorAngles( vecOrigin - GetLocalOrigin(), vecGoal );
}
else
{
	if ( m_hTarget )
	{
		VectorAngles( m_hTarget->GetLocalOrigin() - GetLocalOrigin(), vecGoal );
	}
	else
	{
		// Use the viewcontroller's angles
		vecGoal = GetAbsAngles();
	}
}

Change the code to be this:

if ( m_iAttachmentIndex )
{
	Vector vecOrigin;
	m_hTarget->GetBaseAnimating()->GetAttachment( m_iAttachmentIndex, vecOrigin );
	VectorAngles( vecOrigin - GetAbsOrigin(), vecGoal ); //Changed to use AbsOrigin
}
else
{
	if ( m_hTarget )
	{
		VectorAngles( m_hTarget->GetAbsOrigin() - GetAbsOrigin(), vecGoal ); //Changed to use AbsOrigin
	}
	else
	{
		// Use the viewcontroller's angles
		vecGoal = GetAbsAngles();
	}
}

--Ndnichols 20:42, 9 Aug 2006 (PDT)

Camera won't follow path correctly

There is an apparent bug with getting the camera to follow the path_controls set up for it. To fix this, go to triggers.cpp and do the following. To the declaration of CTriggerCamera, add the following private member:

Vector m_vecLastPos;

and also declare it with the DEFINE_FIELD macro (I believe this is necessary for the camera to save and load properly.)

DEFINE_FIELD( m_vecLastPos, FIELD_VECTOR),

In CTriggerCamera::Enable() is the code block

if ( m_pPath )
{
	if ( m_pPath->m_flSpeed != 0 )
		m_targetSpeed = m_pPath->m_flSpeed;
	
	m_flStopTime += m_pPath->GetDelay();
}

Change this block to be

if ( m_pPath )
{
	if ( m_pPath->m_flSpeed != 0 )
		m_targetSpeed = m_pPath->m_flSpeed;
	
	m_flStopTime += m_pPath->GetDelay();
	m_vecMoveDir = m_pPath->GetLocalOrigin() - GetLocalOrigin();
	m_moveDistance = VectorNormalize( m_vecMoveDir );
	m_flStopTime = gpGlobals->curtime + m_pPath->GetDelay();
}
else
{
	m_moveDistance = 0;
}

Near the end of the Enable() function is the line

m_moveDistance = 0;

Change this to be

m_vecLastPos = GetAbsOrigin();

Now, in the CTrigger::Move() function, change the line that reads

m_moveDistance -= m_flSpeed * gpGlobals->frametime;

to read

m_moveDistance -= VectorNormalize(GetAbsOrigin() - m_vecLastPos);

Finally, add the line

m_vecLastPos = GetAbsOrigin();

to the very end of the Move() function.

(I believe the two bugs were that m_moveDistance wasn't being calculated properly in Enable(), and that the m_flSpeed * gpGlobals->frametime expression reported moving much farther than actually happened. This caused the camera to think it had arrived at the destination camera before it actually had.)

I haven't tested this extensively at all, but it seems to work for me. Please let me know if you have any issues. --Ndnichols 13:09, 10 Aug 2006 (PDT)

Teleport spawnflag on path_corner doesn't do anything for camera

The point_viewcontrol currently ignores the "Teleport to THIS path_corner" spawn flag on a path_corner. To fix, this, go to line 2533 in trigger.cpp (right after the SF_CAMERA_PLAYER_* #defines and add the line

#define SF_PATHCORNER_TELEPORT 2

Now, go to the line that decreases m_moveDistance. It begins with

m_moveDistance -= 

near the beginning of CTriggerCamera::Move(). (The actual line depends on whether or not you have changed it as per the above bug-fixes.) Regardless, change the code from

m_moveDistance -= VectorNormalize(GetAbsOrigin() - m_vecLastPos);

to

if (m_pPath->GetSpawnFlags() & SF_PATHCORNER_TELEPORT)
{
	SetAbsOrigin(m_pPath->GetAbsOrigin());
	m_moveDistance = -1;  //Make sure we enter the conditional below and advance to the next corner.
}
else
{	
	// Subtract movement from the previous frame
	m_moveDistance -= VectorNormalize(GetAbsOrigin() - m_vecLastPos);
}

If you're working on with a .VCD script with camera movements (presumably fired with triggers from the scene) it can be convenient to put a path_corner at the camera's starting position that the camera teleports to. This ensures that if you modify the scene and reload it without exiting HL2, the camera will always start at the correct point (and not wherever it ended up with after the previous completion of the scene.) --Ndnichols 11:18, 12 Aug 2006 (PDT)

A parented point_viewcontrol doesn't look at its target

I don't really know if I'm doing something wrong or what, but when I parent a point_viewcontrol to a moving entity, and then try to make it look a target entity, it doesn't look at it, at all. The view is always somewhat shifted. I know I should make it follow path_tracks rather than parenting it to an object, but I need it to be inside the moving object (a vehicle). The problem is that the point_viewcontrol's path is way too different than the tracktrain's one, even if they're using the same path_tracks. --NykO18 16:00, 26 Aug 2008 (PDT)

ETC.

The camera won't fall path_corners without having a "look at" target set. This is because the think function is only being set if m_hTarget is valid. Just give the camera something to look at, and it should work fine. --Ndnichols 10:11, 12 Aug 2006 (PDT)

The New Train Rot. speed on a path_corner doesn't actually change how quickly the camera turns. The speed is a constant (currently set to 40) and is used on line 3136 of triggers.cpp:

vecAngVel.Init( dx * 40 * gpGlobals->frametime, dy * 40 * gpGlobals->frametime, GetLocalAngularVelocity().z );

--Ndnichols 11:01, 23 Mar 2007 (PDT)

Additional Features

These are small bits of code you can add to increase the functionality of the point_viewcontrol entity.

Camera Stack

Currently, if you have viewcontrol A enabled, then enable viewcontrol B, then disable B, the view will be reset to the player (not viewcontrol A.) This makes it difficult to go from one camera to another and back without carefully timed enables and disables. It is easy to change this behaviour, though, and have a viewcontrol "stack". Each successively enabled viewcontrol will add a camera to the "stack", and when the top of the stack is popped (by disabling the top camera), view will return to the viewcontrol that is now at the top of the stack. Please note that if you disable cameras out of order (ie, enable A, enable B, disable A) things will get weird and out-of-sync; so, always make sure to disable the most recently enabled camera. Now, for the implementation. (The gist is that when a camera is enabled, it stores the player's current ViewEntity; when the camera is disabled, then, we set the player's view entity to be the previous view entity, and not automatically the player. If we DO reset it to the player (because the player was the original view entity), we also make sure to re-enable the player's movement, etc.)

Open triggers.cpp, and add the following private declaration to CTriggerCamera:

CBaseEntity* m_pPrevViewEntity;

and make sure to add it with the DEFINE_FIELD macro so it will be saved as well:

DEFINE_FIELD( m_pPrevViewEntity, FIELD_CLASSPTR ),

Now, in the enable function, just before the line where you set the ViewEntity:

((CBasePlayer*)m_hPlayer.Get())->SetViewEntity( this );

add the line

m_pPrevViewEntity = ((CBasePlayer*)m_hPlayer.Get())->GetViewEntity(); // Store the current view entity

Now, in the disable function, we use to always reset the view to the player and restore movement/weapons with this code:

((CBasePlayer*)m_hPlayer.Get())->SetViewEntity( m_hPlayer );
((CBasePlayer*)m_hPlayer.Get())->EnableControl(TRUE);
// Restore the player's viewmodel
if ( ((CBasePlayer*)m_hPlayer.Get())->GetActiveWeapon() )
{
      ((CBasePlayer*)m_hPlayer.Get())->GetActiveWeapon()->RemoveEffects( EF_NODRAW );
}

Remove this block, though, and replace it with the following:

((CBasePlayer*)m_hPlayer.Get())->SetViewEntity( m_pPrevViewEntity );
if (m_pPrevViewEntity == (CBasePlayer*)m_hPlayer.Get()) //If the previous viewentity is the player, reset everything properly
{		
	((CBasePlayer*)m_hPlayer.Get())->EnableControl(TRUE);
	// Restore the player's viewmodel
	if ( ((CBasePlayer*)m_hPlayer.Get())->GetActiveWeapon() )
	{
		((CBasePlayer*)m_hPlayer.Get())->GetActiveWeapon()->RemoveEffects( EF_NODRAW );
	}
}

Now, the point_viewcontrol entity will work as it used to, as well as being able to be "stacked." I haven't tested this thoroughly, but it works for me. Please let me know if you have any problems.--Ndnichols 11:13, 17 Aug 2006 (PDT)

Record Camera in Demo

Currently, if you record a demo where a point_viewcontrol camera is active, when you playback the demo, the camera is not active. This is because CBasePlayer.m_hViewEntity is not networked, and (I believe) the demo system works by recording the packets sent and then playing them back. So, since the m_hViewEntity is never sent, it is never set when playing back the demo. The obvious fix is to make m_hViewEntity a networked variable. We can change this thusly:

Open player.h, and change line 894 from

EHANDLE m_hViewEntity;

to

CNetworkHandle( CBaseEntity, m_hViewEntity );

Now, in player.cpp, add the following line:

SendPropEHandle ( SENDINFO( m_hViewEntity)),

near line 6990. Now, serverside CBasePlayer is sending it, but the clientside C_BasePlayer needs to receive it. So, go to c_baseplayer.h and add:

EHANDLE   m_hViewEntity;

as a private variable. (I added it at line 369.) Also in c_baseplayer.h, add the following public inline member function:

CBaseEntity *GetViewEntity( void ) { return m_hViewEntity; }

(I added it at line 334.) Now we need to add it to the network receiving table. In c_baseplayer.cpp, add the line:

RecvPropEHandle ( RECVINFO( m_hViewEntity)),

(I added it at line 198.)

Now, CBasePlayer is transmitting the ViewEntity, and C_BasePlayer is receiving it. Now we just need to ensure that the demo playback is checking for a ViewEntity and responding appropriately. In view.cpp, right after the

if ( engine->IsPlayingDemo() )

line at 684, add the following block:

if (pPlayer->GetViewEntity())
{
     VectorCopy( pPlayer->GetViewEntity()->GetAbsOrigin(), m_View.origin );
     VectorCopy( pPlayer->GetViewEntity()->GetAbsAngles(), m_View.angles );
}

(Those lines occupy lines 686-690 for me.) The logic here obviously is that if we are playing back a demo, and pPlayer has a specific view entity, we copy its origins and angles over and the scene is rendered from the camera's point of view as expected. --Ndnichols 11:18, 20 Mar 2007 (PDT)


Another Point viewcontrol Bug

It seems that the point_viewcontrol only moves along paths if you check the "Freeze Player" flag in the "Flags" tab. --Skucker 17:16, 28 Oct 2006 (EDT)

Really? This works fine for me.--Ndnichols 11:01, 23 Mar 2007 (PDT)

Another one is that point_viewcontrol doesn't work when Thirdperson is turned on. It doesn't point where it should. --LukeSkybox 09:16, 24 June 2008 (EDT)

The reason it does not work is because that command does not have any thing to do with that entitie and for it to work you should make a seprate entitie or trigger that has a output to it such as a trigger_once and lets say that the point_viewcontrol's name is camera now if we go to the trigger_once we hit ctrl t and we go to outputs on the tab then we create a out put have the output name be OnStartTouch then target entities name be camera and then have its Via this input be enable . This should create 3rd person camrea but I dont know how to make it so it fully works with multiplayer levels but for single player maps you can take a model and parent it with the player spawn and you can have either the camrea parented with that model or you have a bunch of triggers that enable camreas that show different views such as like in the first resident evil games. You can also create top view and side view and side scrollers and platform maps

Can't see self client models

I am trying to use this entitie to create a top view map but I am having a main problem the point_viewcontrol is not showing playermodels of the clients self but they can see the rest of the clients models but not there own causing confusion and you can not put a model inside the clients on a multiplayer map because when you go to play online with it half life 2 engine crashes making it very hard to create any type of multiplayer 3d person maps. Does any one know how I can make a 3d person map that shows your own player model but can also play online with? also please do not put any codes I am a mapper not a coder plus these maps are not for mods that are not made yet they are for mods that are already out there that I would need to do with in the map not with in the mod because the mods are already massivly popular and why would anyone want to update there mod just for a few 3rd person view maps-- Undeadbobop September 5, 2008

It's impossible to show a player his/her own player model, at least in all iterations of Goldsource and Source engine games. Solokiller 06:32, 6 Sep 2008 (PDT)
That's odd, because In Episode 2, if you go thirdperson, there's an ugly blackish model of gordon showing up. --NykO18 08:02, 6 Sep 2008 (PDT)

It is not impossible for single player mods only for multiplayer unless there is a way to show where the player is with out crashing the engine such as a sprite or something small not a model because It crashes with models. Which is what i was asking is there a way to show the players location at all because with sprites sence they are 2d you can make them switch sprites if you set it up right where the player has a 2d sprite of a player causeing a alusion of a 3d object kinda like in most old games with flat images making the game play different because if you can change a player model to a invisible model and you have a sprite a sprite as a player model instead but I need to know a way how to do all this in maping terms and not just ideaism also most mods are not for e2 only regular hl2 so that info does not help much. I am trying to make a map pack for multiple mods such as zombie panic source and zombie master and most zombie themed mods that are multiplayer.

Angled views?

Is there a way to control the angles (Roll) of the camera? Setting "Snap to goal angles" doesn't seem to work with path_tracks. I'm trying to simulate my player getting knocked out from the side, and want to portray them falling to their side. —Mattshu (Talk) 22:21, 5 March 2011 (UTC)

I would also like to know about this. —SparkZ (Talk) 5:31, 3 June 2011 (CST)

I'm not sure, but have you tried parenting the camera to a func_rotating or func_door_rotating, and parenting the func_rotating to a func_tracktrain? Theoretically, you could control the camera's roll this way (not tried). Also - if you get the problem of the camera not aiming where it should, parent a set of entities like this (listed from child to parent): point_viewcontrol -> func_rotating -> func_tank -> func_tracktrain
func_rotating would control camera roll.
func_tank would control camera pitch & yaw
func_tracktrain would control camera movement --Pandaboy 00:21, 18 November 2011 (PST)
The best way to achieve complex camera movement is to animate a small 1x1x1 unit box and attach the camera to it, as done in almost every Valve game.
--Mr. P. Kiwi (Talk | Contributions) 01:32, 18 November 2011 (PST)

Multiplayer: enabling for one player only?

Is there a way to make a point_viewcontrol only enabled for a certain player in a multiplayer game (for example garry's mod)? --Pandaboy 00:33, 18 November 2011 (PST)

Increase or decrease the speed at which the camera looks at the "Entity to look at"

I have my camera working flawlessly along a track (always looking at a info_target) until the very end. The last few tracks create a sharp turn and the camera takes its sweet time adjusting to the info_target. I'm going to try and mess with the path_tracks I'm using in the meantime.


Parent it to a func_tank which tracks the players at a fixed speed. --ArmageddonSnipe 13:25, 1 May 2013 (PDT)