Creating a third-person view of an entity.

I’m trying to create a third-person view which is centered on a vehicle the player is driving and allows them to rotate around a fixed point. Basically, what’s already included in the sandbox gamemode except for use in fretta. I can’t use player:SpectateEntity() because the player still needs to be able to drive the car. I also can’t use player.SetViewEntity() because the view needs to be able to rotate. Is there any other way to do this, or can one of those two functions actually be used? Thanks.

I’d use this little thing right here: http://wiki.garrysmod.com/?title=ENT.CalcView

To do that, would I need to make a sent? I’m trying to do this with the default hl2 jeep and seeing as it’s already an entity and I have no knowledge of sents whatsoever, I don’t know if it’s possible.

http://wiki.garrysmod.com/?title=Player.SpectateEntity ?

What gives you that idea… :S

[editline]06:15PM[/editline]

Also use this for vehicles:

Well I thought that entity hooks could only be used for scripted entites or something. If I use player.SetScriptedVehicle() then how do I use ENT:CalcView() to adjust the view, because I’m not sure how to pass the vehicle entity to it when I hook to it.

Sorry if I’m not making sense, I don’t really know what I’m doing in this case.

Eh, nevermind I reread your first post, you will want to use ENT:CalcView() instead of player.SetScriptedVehicle

To use ENT:CalcView():

Read the 2 examples from them both, isn’t to hard to figure out.

Also, is there any way to allow the player to continue using the mouse to look around, because it seems like this locks your view to one angle.

Lets start by thinking about what we’re given and what we’re trying to figure out.

We’re given the following:
p is the point we want the camera to look at
x is how far away (in game units) the camera should be from p.
a1 is the angle that the camera is positioned relative to the object.

We’re trying to figure out the following:
c is the position of the camera.
a2 is the angle the camera will be facing.

Here’s a drawing to put this in perspective



 x units
    |
    v      c
      _.-`
p_.-`a1)___


So what might a function that returns the position of the camera look like?
[lua]
function OrbitCamera(p,a1,x)
–TODO: code
return c,a2;
end
[/lua]

To help write this function, lets try and think about the simplest facts and cases.

a2 is simple to figure out - a2 will always be the opposite of a1. We can reverse a1 by doing the following:
[lua]
function OrbitCamera(p,a1,x)
local a2=(a1:Forward()*-1):Angle();
return c,a2;
end
[/lua]

Now that we’ve taken care of a2, lets take care of c.
We don’t really have a simple formula for c like we did for a1, so we’ll look at cases that we can easily figure out what c will be.

Lets say that for simplicity’s sake that p is Vector(0,0,0), and a1 is Angle(0,0,0). If x is 100, c will be at Vector(100,0,0) - Or in other words, the camera will be 100 units to the right of p.

But, what if we changed a1 - the angle the camera was at relative to p?
If we change a1 to Angle(0,90,0), that would put c at (0,100,0).
If we change a1 to Angle(0,180,0), that would put c at (-100,0,0).
If we change a1 to Angle(0,270,0), that would put c at (0,-100,0).

It should be clear what’s going on here. Whenever the camera is at 0,0,0, the camera’s default position (the position the camera would be at when the Angle is 0,0,0) is being pivoted around Vector(0,0,0), according to a1.

In Lua, this can be accomplished by rotating the Vector(x,0,0) by a1 degrees.
[lua]
function OrbitCamera(p,a1,x)
local a2=(a1:Forward()*-1):Angle();
local c=Vector(x,0,0);
c:Rotate(a1);
return c,a2;
end
[/lua]

Now that we’ve got the rotation part taken care of, all we have to worry about is c, the position we’re looking at. Luckily, this part is easy.

Remember the simple fact that the camera is always x units away from p.
In our earlier example, p was Vector(0,0,0), a1 was Angle(0,0,0), and x was 100.
In this case, c was at Vector(100,0,0) - 100 units to the right of p.

Wouldn’t it make sense that whenever p changes, c should change too?
What if c was Vector(10,0,0)? That would put the camera at Vector(110,0,0) - 100 units to the right of p.
But, what if c was Vector(0,10,0)? That would put the camera at Vector(100,10,0) - again, exactly 100 units to the right of p.

Clearly, p is added onto c.
So lets write that into the code:
[lua]
function OrbitCamera(p,a1,x)
local a2=(a1:Forward()*-1):Angle();
local c=Vector(x,0,0);
c:Rotate(a1);
c=c+p;
return c,a2;
end
[/lua]

Voila! We’re done!
You can get the angle and position the camera should be at like so:
[lua]
–Look at a point at a given angle, put the camera 1000 units away
local campos,camang=OrbitCamera(LookAtPoint,LookAtAngle,1000);
[/lua]

Hope this was more helpful than confusing.

EDIT:
For your specific case, this code will probably be what you’re after:
[lua]
function OrbitCamera(p,a1,x)
local a2=(a1:Forward()*-1):Angle();
local c=Vector(x,0,0);
c:Rotate(a1);
c=c+p;
return c,a2;
end

function CalcView(Player, Origin, Angles, FieldOfView)
–LookAtPoint is where-ever you want to look at. 1000 is how far away you want the camera to be
local View = {};
View.origin = OrbitCamera(LookAtPoint,(Angles:Forward()*-1):Angle(),1000);
View.angles = Angles;
View.fov = FieldOfView;
return View;
end
[/lua]

Thanks very much, this is very helpful. It should probably be on the wiki if it isn’t already.

[editline]12:46PM[/editline]

One thing I don’t understand is why you’re passing (Angles:Forward()*-1):Angle() as an argument to OrbitCamera, because doesn’t that mean the angle is reversed twice therefore making a2 equal the angle of CalcView?

Also, is the angle argument of CalcView itself initially equal to the angle the player is facing?

Also, isn’t the view angle unaffected by the OrbitCamera function since View.angles is being set to Angles?

And also this doesn’t allow camera rotation with the mouse still, does it?

a1 determines which direction the camera is moved away from p. The camera needs to be moved in the opposite direction the camera should be facing, which is why I reversed a1.

The View Angle is not affected by the Orbit Camera function.

Remember that a2 is the opposite of a1. In this code, a1 is the opposite of Angles.
Angles * -1 * -1 = Angles

This is a general purpose function that can be used anywhere you want an orbiting camera (such as a Model Panel, if you wanted).
For this particular case, however, I could perform a simplification. The camera’s facing direction, a2, will be the same as Angles, the player’s facing direction.

It does allow for camera rotation.
When the player moves his mouse, he changes his facing angle: Angles. The opposite of the player’s facing direction is passed into the function, so if the player is facing left, the camera will be positioned to the right.

Ok I understand better now, but for some reason I still can’t move the mouse.

[lua]function OrbitCamera(p,a1,x)
local a2=(a1:Forward()*-1):Angle();
local c=Vector(x,0,0);
c:Rotate(a1);
c=c+p;
return c,a2;
end

function CLASS:CalcView(pl, Origin, Angles, Fov)
local view = {}
if pl:GetVehicle() and pl:GetVehicle():IsValid() then
view.origin = OrbitCamera(pl:GetVehicle():GetPos(), (Angles:Forward()-1):Angle(), 400)
else
view.origin = OrbitCamera(pl:GetPos(), (Angles:Forward()
-1):Angle(), 400)
end
view.angles = Angles
view.fov = Fov
return view
end[/lua]
is what I have. When I run it, my view is locked to one angle and it doesn’t let me rotate around the point.

Hmm, I’m certain the orbit camera function works, but I may have assumed some things about CalcView incorrectly. I’ll see if I can look into this a little later.