标签:检索 out 前缀 locking ras eai 几何体 产生 技术分享
虚幻引擎 3 中供玩家使用的相机系统由三个主要类组成:Camera、Pawn 和 PlayerController。这些类都会交互以控制位置、旋转量以及任何其他在游戏过程中应该用于玩家相机的特效。
PlayerController 有一个对被使用的 Camera 以及被控制的 Pawn 的引用。PlayerController 会接收玩家的输入数据并将其用于更新它正在控制的 Pawn 的位置和旋转。默认情况下,Camera 会将其更新传递给 Pawn,它反过来会更新相机的位置和旋转。
通过修改这些类中的一个或多个及其交互方式,可以将玩家的相机设置为使用任何适合于您正在制作的游戏类型的视角向玩家显示这个游戏世界。默认情况下,玩家的相机会使用第一人称,并提供可以将其触发为一个第三人称肩后镜头视角的选项。可以轻松地将它改为自上而下视角、等角视图、横向卷轴视角或任何其他您的游戏可能需要的视图。
camera类代表玩家进入世界的视角。玩家相机的位置和旋转量可以确定场景显示在屏幕上时进行渲染的视点。Camera 类还包含一些可以控制通过相机看到世界的方式的属性,例如,设置视图字段、屏幕长宽比等等。相机还具有可以被应用于它们的特效,例如后期处理、镜头特效、相机修改器、相机动画等等。
注意:所有 FOV 变量都是全角,用度数表示。
相机属性
相机函数
后期特效是在向玩家展示之前应用于已渲染的场景的效果。每个相机都可以使用它自己的后期处理设置的集合,可以覆盖世界、音量、或默认后期特效设置。
要了解更多有关后期特效的信息,请参阅 PostProcessEditorUserGuide(后期编辑器用户指南)、PostProcessTechnicalGuide(后期技术指南)以及 PostProcessMaterials(后期材质)。
后期特效属性
后期特效函数
镜头特效是粒子特效,可以将其用于玩家的相机的镜头。这些镜头特效可以用于创建诸如相机镜头中下的雨滴、血溅、镜头上的污物或灰尘等等这一类的效果。这个 camera 类会包含可以使用这些特效类型的函数。
要了解有关粒子系统和特效的更多信息,请参阅ParticleSystemReference(粒子系统参考)。
镜头特效属性
镜头特效函数
相机动画是那些可以在 Matinee 中创建的动画(或者可以选择在一个外部动画编辑器中创建,然后将其导入),它在游戏的过程中使用动画的平移和旋转信息来偏置相机。它们还提供模拟功能,通常可以在 Matinee 中模拟相机的任何其他属性,例如,FOV 或后期特效。它对于创建诸如相机振动、手持式相机的手惯性摆动的特效或者任何其他动画特效都十分有效。
要了解有关创建相机动画的更多信息,请参阅SettingUpCameras(设置相机).
相机动画函数
相机修改器是应用于相机时可以修改相机的属性的物体。CameraModifier 类是这些效果的基类。通过建这个类的子类并覆盖其中的函数,完全自定义可以创建的修改器。CameraModifier_CameraShake 类是一个可以通过使用相机修改器完成的很恰当的示例。
相机修改器属性
相机修改器函数
PlayerController 主要负责将玩家输入平移到游戏动作中,例如移动一个 Pawn 或控制相机。PlayerController 的旋转量使相机旋转很常用,尽管这不是严格必需。 创建新的相机视角时,可能必需更新或覆盖一些 PlayerController 类中的功能,因为每个不同的相机类型将玩家的输入平移到 Pawn 中的运动和方向都有所不同。下面将会介绍一些与运动和相机有关的属性和函数。
玩家控制器属性
玩家控制器函数
Pawn 不只是玩家在世界中肉体的代表,还可以负责控制玩家的相机的位置和旋转量。它包含可以被覆盖的函数,创建完全新的相机视角。如下所示是一些与相机相关的函数。
Pawn 函数
有2种主要的方法可以实现自定义您的相机。 视图目标 Pawn 可以执行 CalcCamera(),或者您可以创建一个自定义 Camera 扩展类。
执行 Pawn.CalcCamera() 对于简单易懂的相机模式非常有效。 通过这种方法有些功能可能不完全有作用,包括后期特效或相机动画。
创建一个自定义相机类可以消耗多一点进行设置,但是会得到更加全面功能化。 GameFramework.GamePlayerCamera 是这种方法的一个示例。
下面是一些使用 Pawn 的 CalcCamera() 函数修改玩家相机视角以及在某些实例中如何处理玩家输入的基本示例。这并不表示所有您的相机需求都可以采用完全即插即用的解决方法。它们只是开始创建您自己的自定义相机设置的起始点。
很明显,建立这些正确可发行相机类型需要进行大量其他可以并应该进行的修改。您可能想要实现在任何非第一人称模式中通过滚动鼠标滚轮调整相机与玩家的距离这个功能。如果您不打算为避免这样的事情而专门设计您的关卡,那么用添加代码的方法避免相机在某些模式中侵占世界几何体,这个主意相当不错。此外,在某些模式中改变绘制瞄准线的方式而不是将其完全删除可能会更好。
所有这些示例都需要一个新的自定义游戏类型类,它可以通知游戏使用这个新的 Pawn 和 PlayerController 类。
UDNGame.uc
class UDNGame extends UTDeathMatch;
defaultproperties
{
DefaultPawnClass=class‘UDNExamples.UDNPawn‘
PlayerControllerClass=class‘UDNExamples.UDNPlayerController‘
MapPrefixes[0]="UDN"
}
将需要对 DefaultGame.ini 进行修改,以通知引擎同时将这个新的游戏类型作为默认值使用。
DefaultGame.ini
[Engine.GameInfo] DefaultGame=UDNExamples.UDNGame DefaultServerGame=UDNExamples.UDNGame
注意: 为了要使用这个新的游戏类型,您将需要确保您的地图的前缀正确。我们会在我们的游戏类型中将这个前缀设置为"UDN",这样所有地图都将需要以"UDN-"为前缀进行命名。还可以使用编辑器中的地图快速测试这个新的游戏类型,将这个地图的 World Properties(世界属性)中的 Game Type PIE 属性设置为这个新的游戏类型。
第一人称视角是从 UTPawn 扩展而来的所有 pawn 的默认相机类型。该示例会从每个相关的类中抽取组成相机类型的主要部分,并将其放置在新的子类中,以便可以更好地演示有关创建一个基本的第一人称相机的流程。

UDNPawn.uc
class UDNPawn extends UTPawn;
simulated function bool CalcCamera( float fDeltaTime, out vector out_CamLoc, out rotator out_CamRot, out float out_FOV )
{
// 计算第一人称相机位置和旋转量
GetActorEyesViewPoint( out_CamLoc, out_CamRot );
return true;
}
defaultproperties
{
}
UDNPlayerController.uc
class UDNPlayerController extends UTPlayerController;
state PlayerWalking
{
ignores SeePlayer, HearNoise, Bump;
function ProcessMove(float DeltaTime, vector NewAccel, eDoubleClickDir DoubleClickMove, rotator DeltaRot)
{
if( Pawn == None )
{
return;
}
if (Role == ROLE_Authority)
{
// 为远程客户端更新 ViewPitch
Pawn.SetRemoteViewPitch( Rotation.Pitch );
}
Pawn.Acceleration = NewAccel;
CheckJumpOrDuck();
}
}
function UpdateRotation( float DeltaTime )
{
local Rotator DeltaRot, newRotation, ViewRotation;
ViewRotation = Rotation;
if (Pawn!=none)
{
Pawn.SetDesiredRotation(ViewRotation);
}
// 计算将会应用在 ViewRotation 上的 Delta
DeltaRot.Yaw = PlayerInput.aTurn;
DeltaRot.Pitch = PlayerInput.aLookUp;
ProcessViewRotation( DeltaTime, ViewRotation, DeltaRot );
SetRotation(ViewRotation);
NewRotation = ViewRotation;
NewRotation.Roll = Rotation.Roll;
if ( Pawn != None )
Pawn.FaceRotation(NewRotation, deltatime);
}
defaultproperties
{
}
第三人称相机设置同时被列为 UTPawn 的所有子类的备选相机类型。该示例会抽取主要部分并将默认相机覆盖为第三人称相机。

UDNPawn.uc
class UDNPawn extends UTPawn;
//覆盖使默认情况下的玩家网格物体可见
simulated event BecomeViewTarget( PlayerController PC )
{
local UTPlayerController UTPC;
Super.BecomeViewTarget(PC);
if (LocalPlayer(PC.Player) != None)
{
UTPC = UTPlayerController(PC);
if (UTPC != None)
{
//将玩家控制器设置在视图后面,并使网格物体可见
UTPC.SetBehindView(true);
SetMeshVisibility(UTPC.bBehindView);
}
}
}
simulated function bool CalcCamera( float fDeltaTime, out vector out_CamLoc, out rotator out_CamRot, out float out_FOV )
{
local vector CamStart, HitLocation, HitNormal, CamDirX, CamDirY, CamDirZ, CurrentCamOffset;
local float DesiredCameraZOffset;
CamStart = Location;
CurrentCamOffset = CamOffset;
DesiredCameraZOffset = (Health > 0) ? 1.2 * GetCollisionHeight() + Mesh.Translation.Z : 0.f;
CameraZOffset = (fDeltaTime < 0.2) ? DesiredCameraZOffset * 5 * fDeltaTime + (1 - 5*fDeltaTime) * CameraZOffset : DesiredCameraZOffset;
if ( Health <= 0 )
{
CurrentCamOffset = vect(0,0,0);
CurrentCamOffset.X = GetCollisionRadius();
}
CamStart.Z += CameraZOffset;
GetAxes(out_CamRot, CamDirX, CamDirY, CamDirZ);
CamDirX *= CurrentCameraScale;
if ( (Health <= 0) || bFeigningDeath )
{
// 调整相机位置,确保它没有剪切到世界中
// @todo fixmesteve. 注意:如果 FindSpot 失败,您仍然可以获得剪切(很少发生)
FindSpot(GetCollisionExtent(),CamStart);
}
if (CurrentCameraScale < CameraScale)
{
CurrentCameraScale = FMin(CameraScale, CurrentCameraScale + 5 * FMax(CameraScale - CurrentCameraScale, 0.3)*fDeltaTime);
}
else if (CurrentCameraScale > CameraScale)
{
CurrentCameraScale = FMax(CameraScale, CurrentCameraScale - 5 * FMax(CameraScale - CurrentCameraScale, 0.3)*fDeltaTime);
}
if (CamDirX.Z > GetCollisionHeight())
{
CamDirX *= square(cos(out_CamRot.Pitch * 0.0000958738)); // 0.0000958738 = 2*PI/65536
}
out_CamLoc = CamStart - CamDirX*CurrentCamOffset.X + CurrentCamOffset.Y*CamDirY + CurrentCamOffset.Z*CamDirZ;
if (Trace(HitLocation, HitNormal, out_CamLoc, CamStart, false, vect(12,12,12)) != None)
{
out_CamLoc = HitLocation;
}
return true;
}
defaultproperties
{
}
UDNPlayerController.uc
class UDNPlayerController extends UTPlayerController;
state PlayerWalking
{
ignores SeePlayer, HearNoise, Bump;
function ProcessMove(float DeltaTime, vector NewAccel, eDoubleClickDir DoubleClickMove, rotator DeltaRot)
{
if( Pawn == None )
{
return;
}
if (Role == ROLE_Authority)
{
// 为远程客户端更新 ViewPitch
Pawn.SetRemoteViewPitch( Rotation.Pitch );
}
Pawn.Acceleration = NewAccel;
CheckJumpOrDuck();
}
}
function UpdateRotation( float DeltaTime )
{
local Rotator DeltaRot, newRotation, ViewRotation;
ViewRotation = Rotation;
if (Pawn!=none)
{
Pawn.SetDesiredRotation(ViewRotation);
}
// 计算将会应用在 ViewRotation 上的 Delta
DeltaRot.Yaw = PlayerInput.aTurn;
DeltaRot.Pitch = PlayerInput.aLookUp;
ProcessViewRotation( DeltaTime, ViewRotation, DeltaRot );
SetRotation(ViewRotation);
NewRotation = ViewRotation;
NewRotation.Roll = Rotation.Roll;
if ( Pawn != None )
Pawn.FaceRotation(NewRotation, deltatime);
}
defaultproperties
{
}
可以通过进行某些额外的修改创建自上而下相机。它与第三人称相机设置相似,但是它还需要限制 Pawn 的旋转量,特别是不允许它的 pitch 向上或向下瞄准。

UDNPawn.uc
class UDNPawn extends UTPawn;
var float CamOffsetDistance; //相机在玩家上方偏移的距离
var bool bFollowPlayerRotation; //如果是真,相机会与玩家一起旋转
//覆盖使默认情况下的玩家网格物体可见
simulated event BecomeViewTarget( PlayerController PC )
{
local UTPlayerController UTPC;
Super.BecomeViewTarget(PC);
if (LocalPlayer(PC.Player) != None)
{
UTPC = UTPlayerController(PC);
if (UTPC != None)
{
//将玩家控制器设置在视图后面,并使网格物体可见
UTPC.SetBehindView(true);
SetMeshVisibility(UTPC.bBehindView);
UTPC.bNoCrosshair = true;
}
}
}
simulated function bool CalcCamera( float fDeltaTime, out vector out_CamLoc, out rotator out_CamRot, out float out_FOV )
{
out_CamLoc = Location;
out_CamLoc.Z += CamOffsetDistance;
if(!bFollowPlayerRotation)
{
out_CamRot.Pitch = -16384;
out_CamRot.Yaw = 0;
out_CamRot.Roll = 0;
}
else
{
out_CamRot.Pitch = -16384;
out_CamRot.Yaw = Rotation.Yaw;
out_CamRot.Roll = 0;
}
return true;
}
simulated singular event Rotator GetBaseAimRotation()
{
local rotator POVRot, tempRot;
tempRot = Rotation;
tempRot.Pitch = 0;
SetRotation(tempRot);
POVRot = Rotation;
POVRot.Pitch = 0;
return POVRot;
}
defaultproperties
{
bFollowPlayerRotation = false;
CamOffsetDistance=384.0
}
UDNPlayerController.uc
class UDNPlayerController extends UTPlayerController;
state PlayerWalking
{
ignores SeePlayer, HearNoise, Bump;
function ProcessMove(float DeltaTime, vector NewAccel, eDoubleClickDir DoubleClickMove, rotator DeltaRot)
{
if( Pawn == None )
{
return;
}
if (Role == ROLE_Authority)
{
// 为远程客户端更新 ViewPitch
Pawn.SetRemoteViewPitch( Rotation.Pitch );
}
Pawn.Acceleration = NewAccel;
CheckJumpOrDuck();
}
}
function UpdateRotation( float DeltaTime )
{
local Rotator DeltaRot, newRotation, ViewRotation;
ViewRotation = Rotation;
if (Pawn!=none)
{
Pawn.SetDesiredRotation(ViewRotation);
}
// 计算将会应用在 ViewRotation 上的 Delta
DeltaRot.Yaw = PlayerInput.aTurn;
DeltaRot.Pitch = 0;
ProcessViewRotation( DeltaTime, ViewRotation, DeltaRot );
SetRotation(ViewRotation);
NewRotation = ViewRotation;
NewRotation.Roll = Rotation.Roll;
if ( Pawn != None )
Pawn.FaceRotation(NewRotation, deltatime);
}
defaultproperties
{
}
简单的等角型相机与上面介绍的自上而下相机相似。沿着 X 和 Z 两个轴偏移相机,然后向下旋转该 pitch 聚焦于玩家。

UDNPawn.uc
class UDNPawn extends UTPawn;
var float CamOffsetDistance; //相机从玩家处偏移的距离
var int IsoCamAngle;
//覆盖使默认情况下的玩家网格物体可见
simulated event BecomeViewTarget( PlayerController PC )
{
local UTPlayerController UTPC;
Super.BecomeViewTarget(PC);
if (LocalPlayer(PC.Player) != None)
{
UTPC = UTPlayerController(PC);
if (UTPC != None)
{
//将玩家控制器设置在视图后面,并使网格物体可见
UTPC.SetBehindView(true);
SetMeshVisibility(UTPC.bBehindView);
UTPC.bNoCrosshair = true;
}
}
}
simulated function bool CalcCamera( float fDeltaTime, out vector out_CamLoc, out rotator out_CamRot, out float out_FOV )
{
out_CamLoc = Location;
out_CamLoc.X -= Cos(IsoCamAngle * UnrRotToRad) * CamOffsetDistance;
out_CamLoc.Z += Sin(IsoCamAngle * UnrRotToRad) * CamOffsetDistance;
out_CamRot.Pitch = -1 * IsoCamAngle;
out_CamRot.Yaw = 0;
out_CamRot.Roll = 0;
return true;
}
simulated singular event Rotator GetBaseAimRotation()
{
local rotator POVRot, tempRot;
tempRot = Rotation;
tempRot.Pitch = 0;
SetRotation(tempRot);
POVRot = Rotation;
POVRot.Pitch = 0;
return POVRot;
}
defaultproperties
{
IsoCamAngle=6420 //35.264 度
CamOffsetDistance=384.0
}
UDNPlayerController.uc
class UDNPlayerController extends UTPlayerController;
state PlayerWalking
{
ignores SeePlayer, HearNoise, Bump;
function ProcessMove(float DeltaTime, vector NewAccel, eDoubleClickDir DoubleClickMove, rotator DeltaRot)
{
if( Pawn == None )
{
return;
}
if (Role == ROLE_Authority)
{
// 为远程客户端更新 ViewPitch
Pawn.SetRemoteViewPitch( Rotation.Pitch );
}
Pawn.Acceleration = NewAccel;
CheckJumpOrDuck();
}
}
function UpdateRotation( float DeltaTime )
{
local Rotator DeltaRot, newRotation, ViewRotation;
ViewRotation = Rotation;
if (Pawn!=none)
{
Pawn.SetDesiredRotation(ViewRotation);
}
// 计算将会应用在 ViewRotation 上的 Delta
DeltaRot.Yaw = PlayerInput.aTurn;
DeltaRot.Pitch = 0;
ProcessViewRotation( DeltaTime, ViewRotation, DeltaRot );
SetRotation(ViewRotation);
NewRotation = ViewRotation;
NewRotation.Roll = Rotation.Roll;
if ( Pawn != None )
Pawn.FaceRotation(NewRotation, deltatime);
}
defaultproperties
{
}
一个简单的横版相机不只需要控制相机的视点,还需要修改处理玩家输入数据的方式。只允许玩家在画面上向左和向右移动,并且始终面向他们移动的方向。需要输入数据,这样 A 和 D 按键才可以向前后向后移动玩家。

UDNPawn.uc
class UDNPawn extends UTPawn;
var float CamOffsetDistance; //Y-轴上要锁定相机的位置
//覆盖使默认情况下的玩家网格物体可见
simulated event BecomeViewTarget( PlayerController PC )
{
local UTPlayerController UTPC;
Super.BecomeViewTarget(PC);
if (LocalPlayer(PC.Player) != None)
{
UTPC = UTPlayerController(PC);
if (UTPC != None)
{
//将玩家控制器设置在视图后面,并使网格物体可见
UTPC.SetBehindView(true);
SetMeshVisibility(UTPC.bBehindView);
UTPC.bNoCrosshair = true;
}
}
}
simulated function bool CalcCamera( float fDeltaTime, out vector out_CamLoc, out rotator out_CamRot, out float out_FOV )
{
out_CamLoc = Location;
out_CamLoc.Y = CamOffsetDistance;
out_CamRot.Pitch = 0;
out_CamRot.Yaw = 16384;
out_CamRot.Roll = 0;
return true;
}
simulated singular event Rotator GetBaseAimRotation()
{
local rotator POVRot;
POVRot = Rotation;
if( (Rotation.Yaw % 65535 > 16384 && Rotation.Yaw % 65535 < 49560) ||
(Rotation.Yaw % 65535 < -16384 && Rotation.Yaw % 65535 > -49560) )
{
POVRot.Yaw = 32768;
}
else
{
POVRot.Yaw = 0;
}
if( POVRot.Pitch == 0 )
{
POVRot.Pitch = RemoteViewPitch << 8;
}
return POVRot;
}
defaultproperties
{
CamOffsetDistance=0.0
}
UDNPlayerController.uc
class UDNPlayerController extends UTPlayerController;
state PlayerWalking
{
ignores SeePlayer, HearNoise, Bump;
function ProcessMove(float DeltaTime, vector NewAccel, eDoubleClickDir DoubleClickMove, rotator DeltaRot)
{
local Rotator tempRot;
if( Pawn == None )
{
return;
}
if (Role == ROLE_Authority)
{
// 为远程客户端更新 ViewPitch
Pawn.SetRemoteViewPitch( Rotation.Pitch );
}
Pawn.Acceleration.X = -1 * PlayerInput.aStrafe * DeltaTime * 100 * PlayerInput.MoveForwardSpeed;
Pawn.Acceleration.Y = 0;
Pawn.Acceleration.Z = 0;
tempRot.Pitch = Pawn.Rotation.Pitch;
tempRot.Roll = 0;
if(Normal(Pawn.Acceleration) Dot Vect(1,0,0) > 0)
{
tempRot.Yaw = 0;
Pawn.SetRotation(tempRot);
}
else if(Normal(Pawn.Acceleration) Dot Vect(1,0,0) < 0)
{
tempRot.Yaw = 32768;
Pawn.SetRotation(tempRot);
}
CheckJumpOrDuck();
}
}
function UpdateRotation( float DeltaTime )
{
local Rotator DeltaRot, ViewRotation;
ViewRotation = Rotation;
// 计算将会应用在 ViewRotation 上的 Delta
DeltaRot.Yaw = Pawn.Rotation.Yaw;
DeltaRot.Pitch = PlayerInput.aLookUp;
ProcessViewRotation( DeltaTime, ViewRotation, DeltaRot );
SetRotation(ViewRotation);
}
defaultproperties
{
}
该示例会将所有其他示例合成为一个单独的执行过程,它允许玩家在任何相机类型之间进行切换并通过使用可执行函数调整它们。
UDNPawn.uc
class UDNPawn extends UTPawn;
Enum CameraPerspective
{
CAM_FirstPerson,
CAM_ThirdPerson,
CAM_TopDown,
CAM_SideScroller,
CAM_Isometric
};
var bool bFollowPlayerRotation;
var CameraPerspective CameraType;
var float CamOffsetDistance;
var int IsoCamAngle;
exec function CameraMode(CameraPerspective mode)
{
local UTPlayerController UTPC;
CameraType = mode;
UTPC = UTPlayerController(Controller);
if (UTPC != None)
{
if(CameraType != CAM_FirstPerson)
{
UTPC.SetBehindView(true);
if(CameraType != CAM_ThirdPerson)
{
UTPC.bNoCrosshair = true;
}
else
{
UTPC.bNoCrosshair = false;
}
}
else
{
UTPC.bNoCrosshair = false;
UTPC.SetBehindView(false);
}
SetMeshVisibility(UTPC.bBehindView);
}
}
exec function IsoAngle(int angle)
{
IsoCamAngle = angle;
}
/* BecomeViewTarget
在这个 actor 变为它的 ViewTarget 时会被 Camera 调用 */
simulated event BecomeViewTarget( PlayerController PC )
{
local UTPlayerController UTPC;
Super.BecomeViewTarget(PC);
if (LocalPlayer(PC.Player) != None)
{
UTPC = UTPlayerController(PC);
if (UTPC != None)
{
if(CameraType != CAM_FirstPerson)
{
UTPC.SetBehindView(true);
if(CameraType != CAM_ThirdPerson)
{
UTPC.bNoCrosshair = true;
}
else
{
UTPC.bNoCrosshair = false;
}
}
else
{
UTPC.bNoCrosshair = false;
UTPC.SetBehindView(false);
}
SetMeshVisibility(UTPC.bBehindView);
}
}
}
/**
* 从这个 pawn 观看时计算相机视点。
*
* @param fDeltaTime 自从上次更新开始的 delta 时间(秒)
* @param out_CamLoc 计算机位置
* @param out_CamRot 相机旋转量
* @param out_FOV 视角
*
* @返回 如果 Pawn 应该提供相机视点,那么返回真。
*/
simulated function bool CalcCamera( float fDeltaTime, out vector out_CamLoc, out rotator out_CamRot, out float out_FOV )
{
// 处理固定的相机
if (bFixedView)
{
out_CamLoc = FixedViewLoc;
out_CamRot = FixedViewRot;
}
else
{
if ( CameraType == CAM_ThirdPerson ) // 处理后视图
{
CalcThirdPersonCam(fDeltaTime, out_CamLoc, out_CamRot, out_FOV);
}
else if ( CameraType == CAM_TopDown ) // 处理后视图
{
CalcTopDownCam(fDeltaTime, out_CamLoc, out_CamRot, out_FOV);
}
else if ( CameraType == CAM_SideScroller ) // 处理后视图
{
CalcSideScrollerCam(fDeltaTime, out_CamLoc, out_CamRot, out_FOV);
}
else if ( CameraType == CAM_Isometric ) // 处理后视图
{
CalcIsometricCam(fDeltaTime, out_CamLoc, out_CamRot, out_FOV);
}
else
{
// 默认情况下,我们通过 Pawn 的眼睛浏览。
GetActorEyesViewPoint( out_CamLoc, out_CamRot );
}
if ( UTWeapon(Weapon) != none)
{
UTWeapon(Weapon).WeaponCalcCamera(fDeltaTime, out_CamLoc, out_CamRot);
}
}
return true;
}
simulated function bool CalcTopDownCam( float fDeltaTime, out vector out_CamLoc, out rotator out_CamRot, out float out_FOV )
{
out_CamLoc = Location;
out_CamLoc.Z += CamOffsetDistance;
if(!bFollowPlayerRotation)
{
out_CamRot.Pitch = -16384;
out_CamRot.Yaw = 0;
out_CamRot.Roll = 0;
}
else
{
out_CamRot.Pitch = -16384;
out_CamRot.Yaw = Rotation.Yaw;
out_CamRot.Roll = 0;
}
return true;
}
simulated function bool CalcSideScrollerCam( float fDeltaTime, out vector out_CamLoc, out rotator out_CamRot, out float out_FOV )
{
out_CamLoc = Location;
out_CamLoc.Y = CamOffsetDistance;
out_CamRot.Pitch = 0;
out_CamRot.Yaw = 16384;
out_CamRot.Roll = 0;
return true;
}
simulated function bool CalcIsometricCam( float fDeltaTime, out vector out_CamLoc, out rotator out_CamRot, out float out_FOV )
{
out_CamLoc = Location;
out_CamLoc.X -= Cos(IsoCamAngle * UnrRotToRad) * CamOffsetDistance;
out_CamLoc.Z += Sin(IsoCamAngle * UnrRotToRad) * CamOffsetDistance;
out_CamRot.Pitch = -1 * IsoCamAngle;
out_CamRot.Yaw = 0;
out_CamRot.Roll = 0;
return true;
}
/**
* 会返回没有经过任何调整的基础“瞄准旋转量?”(没有瞄准误差、没有自动锁定、没有附着.. 就是没有用过的初始瞄准旋转量!)
*
* @返回 基本 Aim 旋转量。
*/
simulated singular event Rotator GetBaseAimRotation()
{
local vector POVLoc;
local rotator POVRot, tempRot;
if(CameraType == CAM_TopDown || CameraType == CAM_Isometric)
{
tempRot = Rotation;
tempRot.Pitch = 0;
SetRotation(tempRot);
POVRot = Rotation;
POVRot.Pitch = 0;
}
else if(CameraType == CAM_SideScroller)
{
POVRot = Rotation;
if( (Rotation.Yaw % 65535 > 16384 && Rotation.Yaw % 65535 < 49560) ||
(Rotation.Yaw % 65535 < -16384 && Rotation.Yaw % 65535 > -49560) )
{
POVRot.Yaw = 32768;
}
else
{
POVRot.Yaw = 0;
}
if( POVRot.Pitch == 0 )
{
POVRot.Pitch = RemoteViewPitch << 8;
}
}
else
{
if( Controller != None && !InFreeCam() )
{
Controller.GetPlayerViewPoint(POVLoc, POVRot);
return POVRot;
}
else
{
POVRot = Rotation;
if( POVRot.Pitch == 0 )
{
POVRot.Pitch = RemoteViewPitch << 8;
}
}
}
return POVRot;
}
defaultproperties
{
CameraType=CAM_FirstPerson;
bFollowPlayerRotation = false;
CamOffsetDistance=384.0
IsoCamAngle=6420 //35.264 度
}
UDNPlayerController.uc
class UDNPlayerController extends UTPlayerController;
state PlayerWalking
{
function ProcessMove(float DeltaTime, vector NewAccel, eDoubleClickDir DoubleClickMove, rotator DeltaRot)
{
local UDNPawn P;
local Rotator tempRot;
if( (Pawn != None) )
{
P = UDNPawn(Pawn);
if(P != none)
{
if(P.CameraType == CAM_SideScroller)
{
Pawn.Acceleration.X = -1 * PlayerInput.aStrafe * DeltaTime * 100 * PlayerInput.MoveForwardSpeed;
Pawn.Acceleration.Y = 0;
Pawn.Acceleration.Z = 0;
tempRot.Pitch = P.Rotation.Pitch;
tempRot.Roll = 0;
if(Normal(Pawn.Acceleration) Dot Vect(1,0,0) > 0)
{
tempRot.Yaw = 0;
P.SetRotation(tempRot);
}
else if(Normal(Pawn.Acceleration) Dot Vect(1,0,0) < 0)
{
tempRot.Yaw = 32768;
P.SetRotation(tempRot);
}
}
else
{
if ( (DoubleClickMove == DCLICK_Active) && (Pawn.Physics == PHYS_Falling) )
DoubleClickDir = DCLICK_Active;
else if ( (DoubleClickMove != DCLICK_None) && (DoubleClickMove < DCLICK_Active) )
{
if ( UTPawn(Pawn).Dodge(DoubleClickMove) )
DoubleClickDir = DCLICK_Active;
}
Pawn.Acceleration = newAccel;
}
if (Role == ROLE_Authority)
{
// 为远程客户端更新 ViewPitch
Pawn.SetRemoteViewPitch( Rotation.Pitch );
}
}
CheckJumpOrDuck();
}
}
}
function UpdateRotation( float DeltaTime )
{
local UDNPawn P;
local Rotator DeltaRot, newRotation, ViewRotation;
P = UDNPawn(Pawn);
ViewRotation = Rotation;
if (p != none && P.CameraType != CAM_SideScroller)
{
Pawn.SetDesiredRotation(ViewRotation);
}
// 计算将会应用在 ViewRotation 上的 Delta
if( P != none && P.CameraType == CAM_SideScroller )
{
DeltaRot.Yaw = Pawn.Rotation.Yaw;
}
else
{
DeltaRot.Yaw = PlayerInput.aTurn;
}
DeltaRot.Pitch = PlayerInput.aLookUp;
ProcessViewRotation( DeltaTime, ViewRotation, DeltaRot );
SetRotation(ViewRotation);
ViewShake( deltaTime );
NewRotation = ViewRotation;
NewRotation.Roll = Rotation.Roll;
if (P != None && P.CameraType != CAM_SideScroller )
Pawn.FaceRotation(NewRotation, deltatime);
}
defaultproperties
{
}
该示例会采用与之前集合不同的方法。这些方法都使用了 Pawn 类中的 CalcCamera() 函数修改相机。在这个示例中,将会创建自定义相机框架,这样可以轻松地插入不同的相机模型以便快速修改相机操作。重要的是,我们具有所有相机功能的全部访问权限,例如后期特效、相机动画和特效等等。此外之外,玩家控制器类将添加该功能,使用玩家控制模块覆盖某些特定角度的玩家运动和瞄准。
该示例的设置比相对简单的覆盖一些函数更复杂一些,正如其他示例中所示的情况。该示例需要覆盖很多在前面的示例中提到的函数,但是不用直接在这些函数中直接添加或更改功能,这些函数将只会负责自定义相机和控制系统,提供它们通常执行的功能。
新的相机类实质上将会充当相机模块的界面。它包含一些函数,它们可以创建新相机模块以及处理相机具有除玩家的 Pawn 之外的视图目标的情况。它的职责除了这些以外,还可以将函数调用从各种不同 Engine 类中传递给当前相机模块以便进行管理。同样地,这个新的 PlayerController 类会引用一个用来处理 PlayerController 和 Pawn 类中特定运动和瞄准函数的控制模块。它允许针对相机和控制类型的功能全部包含在紧凑的自包含类中,这些自包含类可以随意进行替换,快速并轻松地实现新的相机类型。
基础相机模块类通过 Object 类扩展而来,并且定义了所有相机模块将会共有的属性和运转状态。它的一个属性是对拥有它的相机的一个引用。定义了一些初始化和取消初始化函数,但是这个类中的主要函数功能由可以计算玩家相机的新位置和旋转量的 UpdateCamera() 函数执行,而且可以应用任何其他想要的效果或修改。
使用 config(Camera) 修饰符定义这个类,这样应该可以配置或在特定相机模块中永远存在的所有属性将会在 *Camera.ini 文件中找到。它还会被定义为 abstract ,这样实际上就不能够使用它。它更像是一个可以进行特定相机模块构建的模板,不是实际使用自己本身的类。
UDNCameraModule.uc
class UDNCameraModule extends Object
abstract
config(Camera);
//具有相机控制权
var transient UDNPlayerCamera PlayerCamera;
//针对模式的初始化
function Init();
/** 在相机变为 active 的时候调用 */
function OnBecomeActive( UDNCameraModule OldCamera );
/** 在相机变为 inactive 的时候调用 */
function OnBecomeInActive( UDNCameraModule NewCamera );
//计算新的相机位置和旋转量
function UpdateCamera(Pawn P, UDNPlayerCamera CameraActor, float DeltaTime, out TViewTarget OutVT);
//初始化新的视图目标
simulated function BecomeViewTarget( UDNPlayerController PC );
//处理镜头推近
function ZoomIn();
//处理镜头推近
function ZoomOut();
defaultproperties
{
}
这个新的相机类由 Camera 基类扩展而来,覆盖一些函数并添加新的函数功能处理相机模块。在这个系统中相机的主要任务是担任相机模块的中间人,它现在处理大部分计算工作。
UDNPlayerCamera.uc
class UDNPlayerCamera extends Camera
config(Camera);
var UDNPlayerController PlayerOwner; //玩家控制器具有这个相机控制权
var UDNCameraModule CurrentCamera; //正在使用的当前相机模式
var config string DefaultCameraClass; //默认相机模式??类
function PostBeginPlay()
{
local class<UDNCameraModule> NewClass;
Super.PostBeginPlay();
// 设置相机模式
if ( (CurrentCamera == None) && (DefaultCameraClass != "") )
{
//获取要使用的默认相机类
NewClass = class<UDNCameraModule>( DynamicLoadObject( DefaultCameraClass, class‘Class‘ ) );
//创建默认相机
CurrentCamera = CreateCamera(NewClass);
}
}
//初始化 PlayerCamera 使其拥有 PlayerController
function InitializeFor(PlayerController PC)
{
//进行父代初始化
Super.InitializeFor(PC);
//将 PlayerOwner 设置为玩家控制器
PlayerOwner = UDNPlayerController(PC);
}
/**
* 内部。创建并初始化一个新的相机指定类,返回这个对象参数。
*/
function UDNCameraModule CreateCamera(class<UDNCameraModule> CameraClass)
{
local UDNCameraModule NewCam;
//创建新的相机并进行初始化
NewCam = new(Outer) CameraClass;
NewCam.PlayerCamera = self;
NewCam.Init();
//在新/旧的相机上调用 active/inactive 函数
if(CurrentCamera != none)
{
CurrentCamera.OnBecomeInactive(NewCam);
NewCam.OnBecomeActive(CurrentCamera);
}
else
{
NewCam.OnBecomeActive(None);
}
//将新相机设置为当前值
CurrentCamera = NewCam;
return NewCam;
}
/**
* 查询 ViewTarget(视图目标)并输出 Point Of View(视角)。
*
* @param OutVT 要使用的 ViewTarget。
* @param DeltaTime 自从上次相机更新后的 Delta Time(以秒为单位)。
*/
function UpdateViewTarget(out TViewTarget OutVT, float DeltaTime)
{
local CameraActor CamActor;
local TPOV OrigPOV;
local Vector Loc, Pos, HitLocation, HitNormal;
local Rotator Rot;
local Actor HitActor;
// 不要在插值的过程中更新输出观察目标
if( PendingViewTarget.Target != None && OutVT == ViewTarget && BlendParams.bLockOutgoing )
{
return;
}
OrigPOV = OutVT.POV;
// 视图目标上的默认 FOV
OutVT.POV.FOV = DefaultFOV;
// 浏览相机 actor。
CamActor = CameraActor(OutVT.Target);
if( CamActor != None )
{
CamActor.GetCameraView(DeltaTime, OutVT.POV);
// 通过 CameraActor 获取长宽比。
bConstrainAspectRatio = bConstrainAspectRatio || CamActor.bConstrainAspectRatio;
OutVT.AspectRatio = CamActor.AspectRatio;
// 查看 CameraActor 是否需要覆盖使用的 PostProcess 设置。
CamOverridePostProcessAlpha = CamActor.CamOverridePostProcessAlpha;
CamPostProcessSettings = CamActor.CamOverridePostProcess;
}
else
{
// 为 Pawn Viewtarget 提供了一个指定相机位置的机会。
// 如果 Pawn 没有覆盖相机视图,那么我们将会继续使用我们自己的默认设置
if( Pawn(OutVT.Target) == None ||
!Pawn(OutVT.Target).CalcCamera(DeltaTime, OutVT.POV.Location, OutVT.POV.Rotation, OutVT.POV.FOV) )
{
//Pawn 不需要控制,我们有一个自定义模式
if(CurrentCamera != none)
{
//允许模式处理相机更新
CurrentCamera.UpdateCamera(Pawn(OutVT.Target), self, DeltaTime, OutVT);
}
//没有自定义模式 - 使用默认相机类型
else
{
switch( CameraStyle )
{
case ‘Fixed‘ : // 没有更新,保留以前的相机位置
// 通过恢复保存的 POV,如果 CalcCamera 更改它,但是仍然会返回 false
OutVT.POV = OrigPOV;
break;
case ‘ThirdPerson‘ : // 简单的第三人称视角实现
case ‘FreeCam‘ :
case ‘FreeCam_Default‘:
Loc = OutVT.Target.Location;
Rot = OutVT.Target.Rotation;
//OutVT.Target.GetActorEyesViewPoint(Loc, Rot);
if( CameraStyle == ‘FreeCam‘ || CameraStyle == ‘FreeCam_Default‘ )
{
Rot = PCOwner.Rotation;
}
Loc += FreeCamOffset >> Rot;
Pos = Loc - Vector(Rot) * FreeCamDistance;
// @fixme, 各个 BlockingVolume.bBlockCamera=false
HitActor = Trace(HitLocation, HitNormal, Pos, Loc, FALSE, vect(12,12,12));
OutVT.POV.Location = (HitActor == None) ? Pos : HitLocation;
OutVT.POV.Rotation = Rot;
break;
case ‘FirstPerson‘ : // 简单的第一人称,通过视图目标的‘眼睛’观看
default : OutVT.Target.GetActorEyesViewPoint(OutVT.POV.Location, OutVT.POV.Rotation);
break;
}
}
}
}
ApplyCameraModifiers(DeltaTime, OutVT.POV);
// 设置相机的位置和旋转量,处理我们没有被锁定到视图目标的情况
SetRotation(OutVT.POV.Rotation);
SetLocation(OutVT.POV.Location);
}
//将视图目标初始化传递到相机模式
simulated function BecomeViewTarget( PlayerController PC )
{
CurrentCamera.BecomeViewTarget(UDNPlayerController(PC));
}
//将放大传递给相机模式
function ZoomIn()
{
CurrentCamera.ZoomIn();
}
//将缩小传递给相机模式
function ZoomOut()
{
CurrentCamera.ZoomOut();
}
defaultproperties
{
}
基础控制模块类通过 Object 类扩展而来,并且定义了所有控制模块将会共有的属性和运转状态。它包含一个对拥有它同时控制当前鼠标光标位置的控制的引用。像基础相机模块一样,定义了初始化和取消初始化函数,可以针对任何类型进行可能需要的设置或清除。这个类的其他部分由将会同时控制玩家运动和瞄准的函数构成。
使用 config(Control) 修饰符定义这个类,这样应该可以配置或在特定控制模块中永远存在的所有属性将会在 *Control.ini 文件中找到。它还会被定义为 abstract ,这样实际上就不能够使用它。它只不过是一个用来进行构建的特定控制模块的模板,而不是一个始终实际会使用自己本身的类。
UDNControlModule.uc
class UDNControlModule extends Object
abstract
config(Control);
//引用具有控制权的控制器
var UDNPlayerController Controller;
//针对模式的初始化
function Init();
/** 在相机变为 active 的时候调用 */
function OnBecomeActive( UDNControlModule OldModule );
/** 在相机变为 inactive 的时候调用 */
function OnBecomeInActive( UDNControlModule NewModule );
//计算 Pawn 瞄准目标旋转量
simulated singular function Rotator GetBaseAimRotation();
//控制自定义玩家运动
function ProcessMove(float DeltaTime, vector NewAccel, eDoubleClickDir DoubleClickMove, rotator DeltaRot);
//计算控制器旋转
function UpdateRotation(float DeltaTime);
defaultproperties
{
}
一些引擎类需要扩展才能与新的相机和控制系统接口,其中主要的是 PlayerController、Pawn 和 HUD 类。还会利用这些新的类创建一个新的游戏类型
这个新的 PlayerController 类会添加可以更改同时作为缩小或扩大使用的相机模块类型的可执行函数(缩放函数的工作方式由当前相机模块实现它们的方式决定)。覆盖 PlayerWalking 状态的 ProcessMove() 函数和 UpdateRotation() 函数向控制模块添加调用。最后,覆盖并修改 GetPlayerViewPoint() 函数防止相机被损坏,同时强制 PlayerController 在存在新自定义相机的情况下使用它。
UDNPlayerController.uc
class UDNPlayerController extends UTPlayerController;
var UDNControlModule ControlModule; //要使用的玩家控制模块
var config string DefaultControlModuleClass; //玩家控制模块的默认类
//通过类切换到其他相机的可执行函数
exec function ChangeControls( string ClassName )
{
local class<UDNControlModule> ControlClass;
local UDNControlModule NewControlModule;
ControlClass = class<UDNControlModule>( DynamicLoadObject( DefaultControlModuleClass, class‘Class‘ ) );
if(ControlClass != none)
{
// 将模块与 PlayerController 联系起来
NewControlModule = new(Outer) ControlClass;
NewControlModule.Controller = self;
NewControlModule.Init();
//在新/旧模块上调用 active/inactive 函数
if(ControlModule != none)
{
ControlModule.OnBecomeInactive(NewControlModule);
NewControlModule.OnBecomeActive(ControlModule);
}
else
{
NewControlModule.OnBecomeActive(None);
}
ControlModule = NewControlModule;
}
else
{
`log("Couldn‘t get control module class!");
// 没有一个 Control Class 的情况很好。 PlayerController 将使用默认控制。
}
}
//通过类切换到其他相机的可执行函数
exec function ChangeCamera( string ClassName )
{
local class<UDNCameraModule> NewClass;
NewClass = class<UDNCameraModule>( DynamicLoadObject( ClassName, class‘Class‘ ) );
if(NewClass != none && UDNPlayerCamera(PlayerCamera) != none)
{
UDNPlayerCamera(PlayerCamera).CreateCamera(NewClass);
}
}
//镜头推近可执行函数
exec function ZoomIn()
{
if(UDNPlayerCamera(PlayerCamera) != none)
{
UDNPlayerCamera(PlayerCamera).ZoomIn();
}
}
//镜头拉远可执行函数
exec function ZoomOut()
{
if(UDNPlayerCamera(PlayerCamera) != none)
{
UDNPlayerCamera(PlayerCamera).ZoomOut();
}
}
simulated function PostBeginPlay()
{
local class<UDNControlModule> ControlClass;
local UDNControlModule NewControlModule;
Super.PostBeginPlay();
ControlClass = class<UDNControlModule>( DynamicLoadObject( DefaultControlModuleClass, class‘Class‘ ) );
if(ControlClass != none)
{
// 将模块与 PlayerController 联系起来
NewControlModule = new(Outer) ControlClass;
NewControlModule.Controller = self;
NewControlModule.Init();
//在新/旧模块上调用 active/inactive 函数
if(ControlModule != none)
{
ControlModule.OnBecomeInactive(NewControlModule);
NewControlModule.OnBecomeActive(ControlModule);
}
else
{
NewControlModule.OnBecomeActive(None);
}
ControlModule = NewControlModule;
}
else
{
`log("Couldn‘t get control module class!");
// 没有一个 Control Class 的情况很好。 PlayerController 将使用默认控制。
}
}
state PlayerWalking
{
function ProcessMove(float DeltaTime, vector NewAccel, eDoubleClickDir DoubleClickMove, rotator DeltaRot)
{
//控制器有一个 UDNPlayerCamera
if(ControlModule != none)
{
//允许自定义相机覆盖玩家运动
ControlModule.ProcessMove(DeltaTime, NewAccel, DoubleClickMove, DeltaRot);
}
else
{
Super.ProcessMove(DeltaTime, NewAccel, DoubleClickMove, DeltaRot);
}
}
}
function UpdateRotation( float DeltaTime )
{
//控制器有一个 UDNPlayerCamera
if(ControlModule != none)
{
//允许自定义相机更新我们的旋转量
ControlModule.UpdateRotation(DeltaTime);
}
else
{
Super.UpdateRotation(DeltaTime);
}
}
/* GetPlayerViewPoint: 会返回 Player 的 Point of View(视角)
对于 AI,它代表的是 Pawn 的 Eyes ViewPoint(眼睛视角)
对于 Human 玩家,它代表的是 Camera 的 ViewPoint(视角) */
simulated event GetPlayerViewPoint( out vector POVLocation, out Rotator POVRotation )
{
local float DeltaTime;
local UTPawn P;
P = IsLocalPlayerController() ? UTPawn(CalcViewActor) : None;
DeltaTime = WorldInfo.TimeSeconds - LastCameraTimeStamp;
LastCameraTimeStamp = WorldInfo.TimeSeconds;
// 支持使用 CameraActor 视角
if ( CameraActor(ViewTarget) != None )
{
if ( PlayerCamera == None )
{
super.ResetCameraMode();
SpawnCamera();
}
super.GetPlayerViewPoint( POVLocation, POVRotation );
}
else
{
//没有损坏我们的相机!!!
/* if ( PlayerCamera != None )
{
PlayerCamera.Destroy();
PlayerCamera = None;
} */
//没有相机,我们有视图目标 - 使视图目标在控制中
if ( PlayerCamera == None && ViewTarget != None )
{
POVRotation = Rotation;
if ( (PlayerReplicationInfo != None) && PlayerReplicationInfo.bOnlySpectator && (UTVehicle(ViewTarget) != None) )
{
UTVehicle(ViewTarget).bSpectatedView = true;
ViewTarget.CalcCamera( DeltaTime, POVLocation, POVRotation, FOVAngle );
UTVehicle(ViewTarget).bSpectatedView = false;
}
else
{
ViewTarget.CalcCamera( DeltaTime, POVLocation, POVRotation, FOVAngle );
}
if ( bFreeCamera )
{
POVRotation = Rotation;
}
}
//没有相机,没有视图目标 - 由我们负责
else if(PlayerCamera == None)
{
CalcCamera( DeltaTime, POVLocation, POVRotation, FOVAngle );
return;
}
//我们有一个相机 - 让相机在控制中
else
{
POVLocation = PlayerCamera.ViewTarget.POV.Location;
POVRotation = PlayerCamera.ViewTarget.POV.Rotation;
FOVAngle = PlayerCamera.ViewTarget.POV.FOV;
}
}
// 应用视图振动
POVRotation = Normalize(POVRotation + ShakeRot);
POVLocation += ShakeOffset >> Rotation;
if( CameraEffect != none )
{
CameraEffect.UpdateLocation(POVLocation, POVRotation, GetFOVAngle());
}
// 缓存结果
CalcViewActor = ViewTarget;
CalcViewActorLocation = ViewTarget.Location;
CalcViewActorRotation = ViewTarget.Rotation;
CalcViewLocation = POVLocation;
CalcViewRotation = POVRotation;
if ( P != None )
{
CalcEyeHeight = P.EyeHeight;
CalcWalkBob = P.WalkBob;
}
}
defaultproperties
{
CameraClass=class‘UDNExamples.UDNPlayerCamera‘
MatineeCameraClass=class‘UDNExamples.UDNPlayerCamera‘
}
这个新的 Pawn 类会重载 CalcCamera() 函数,只返回 false,使新的相机系统始终控制相机方位和位置。重载 BecomeViewTarget() 和 GetBaseAimRotation() 函数将它们的功能处理分别传递给相机和控制系统。
UDNPawn.uc
class UDNPawn extends UTPawn;
/* BecomeViewTarget
在这个 actor 变为它的 ViewTarget 时会被 Camera 调用 */
simulated event BecomeViewTarget( PlayerController PC )
{
local UDNPlayerController UDNPC;
UDNPC = UDNPlayerController(PC);
//Pawn 由 UDNPlayerController 进行控制,而且有一个 UDNPlayerCamera
if(UDNPC != none && UDNPlayerCamera(UDNPC.PlayerCamera) != none)
{
//允许相机控制网格物体可视性等等。
UDNPlayerCamera(UDNPC.PlayerCamera).BecomeViewTarget(UDNPC);
}
else
{
Super.BecomeViewTarget(PC);
}
}
/**
* 从这个 pawn 观看时计算相机视点。
*
* @param fDeltaTime 自从上次更新开始的 delta 时间(秒)
* @param out_CamLoc 相机方位
* @param out_CamRot 相机旋转量
* @param out_FOV 视角
*
* @如果 Pawn 应该提供相机视点,那么返回真。
*/
simulated function bool CalcCamera( float fDeltaTime, out vector out_CamLoc, out rotator out_CamRot, out float out_FOV )
{
//返回 false,允许自定义相机控制它的方位和旋转量
return false;
}
/**
* 会返回没有经过任何调整的基础“瞄准旋转量?”(没有瞄准误差、没有自动锁定、没有附着.. 就是没有用过的初始瞄准旋转量!)
*
* @返回基本 Aim 旋转量。
*/
simulated singular event Rotator GetBaseAimRotation()
{
local vector POVLoc;
local rotator POVRot;
local UDNPlayerController PC;
PC = UDNPlayerController(Controller);
//Pawn 由 UDNPlayerController 进行控制,而且有一个 UDNPlayerCamera
if(PC != none && PC.ControlModule != none)
{
//允许自定义相机控制目标旋转量
return PC.ControlModule.GetBaseAimRotation();
}
else
{
if( Controller != None && !InFreeCam() )
{
Controller.GetPlayerViewPoint(POVLoc, POVRot);
return POVRot;
}
else
{
POVRot = Rotation;
if( POVRot.Pitch == 0 )
{
POVRot.Pitch = RemoteViewPitch << 8;
}
return POVRot;
}
}
}
defaultproperties
{
}
这个新的 gametype 类是 UTDeathMatch 类的一个基础扩展类,UTDeathMatch 类可以设置要使用的新 HUD、Pawn 和 PlayerController 类。它还可以将 bUseClassicHUD 设置为 True,这样将会使用在这里指定的 HUD 类替换 UTGFxHUDWrapper,在没有设置这个布尔变量的情况下将会硬编码使用 UTGFxHUDWrapper。
UDNGame.uc
class UDNGame extends UTDeathMatch;
defaultproperties
{
DefaultPawnClass=class‘UDNExamples.UDNPawn‘
PlayerControllerClass=class‘UDNExamples.UDNPlayerController‘
MapPrefixes[0]="UDN"
}
在使用新相机框架的示例中,将会安装一个 Top-Down(自上而下)相机。生成一个新的相机模块是实现基础相机模块类中定义的函数的主要问题。如果您已经看过上面的 CalcCamera() 示例,将会觉得很多内容非常熟悉。
UDNCameraModule_TopDown.uc
class UDNCameraModule_TopDown extends UDNCameraModule;
var float CamAltitude; //相机偏离玩家的实际高度
var float DesiredCamAltitude; //要将相机移动到的新高度偏移量
var float MaxCamAltitude; //相机可以距离玩家的最大偏移量
var float MinCamAltitude; //相机可以距离玩家的最小偏移量
var float CamZoomIncrement; //每次点击鼠标滑缩放单元格的数量
//计算新的相机位置和旋转量
function UpdateCamera(Pawn P, UDNPlayerCamera CameraActor, float DeltaTime, out TViewTarget OutVT)
{
//如果不是想要得到的高度,那么插入新的相机偏移量
if(CamAltitude != DesiredCamAltitude)
{
CamAltitude += (DesiredCamAltitude - CamAltitude) * DeltaTime * 3;
}
//在高度 (Z) 偏移量上将相机与玩家对齐
OutVT.POV.Location = OutVT.Target.Location;
OutVT.POV.Location.Z += CamAltitude;
//将相机旋转量设置为向下
OutVT.POV.Rotation.Pitch = -16384;
OutVT.POV.Rotation.Yaw = 0;
OutVT.POV.Rotation.Roll = 0;
}
//初始化新的视图目标
simulated function BecomeViewTarget( UDNPlayerController PC )
{
if (LocalPlayer(PC.Player) != None)
{
//将玩家网格物体设置为可视
PC.SetBehindView(true);
UDNPawn(PC.Pawn).SetMeshVisibility(PC.bBehindView);
PC.bNoCrosshair = true;
}
}
function ZoomIn()
{
//减少相机高度
DesiredCamAltitude -= CamZoomIncrement;
//将相机高度锁定在限制范围内
DesiredCamAltitude = FMin(MaxCamAltitude, FMax(MinCamAltitude, DesiredCamAltitude));
}
function ZoomOut()
{
//增加相机高度
DesiredCamAltitude += CamZoomIncrement;
//将相机高度锁定在限制范围内
DesiredCamAltitude = FMin(MaxCamAltitude, FMax(MinCamAltitude, DesiredCamAltitude));
}
defaultproperties
{
CamAltitude=384.0
DesiredCamAltitude=384.0
MaxCamAltitude=1024.0
MinCamAltitude=160.0
CamZoomIncrement=96.0
}
UDNControlModule_TopDown.uc
class UDNControlModule_TopDown extends UDNControlModule;
//计算 Pawn 瞄准目标旋转量
simulated singular function Rotator GetBaseAimRotation()
{
local rotator POVRot;
//Pawn 所面向的目标 - 锁定跨度
POVRot = Controller.Pawn.Rotation;
POVRot.Pitch = 0;
return POVRot;
}
//控制自定义玩家运动
function ProcessMove(float DeltaTime, vector NewAccel, eDoubleClickDir DoubleClickMove, rotator DeltaRot)
{
if( Controller.Pawn == None )
{
return;
}
if (Controller.Role == ROLE_Authority)
{
// 为远程客户端更新 ViewPitch
Controller.Pawn.SetRemoteViewPitch( Controller.Rotation.Pitch );
}
Controller.Pawn.Acceleration = NewAccel;
Controller.CheckJumpOrDuck();
}
//计算控制器旋转
function UpdateRotation(float DeltaTime)
{
local Rotator DeltaRot, NewRotation, ViewRotation;
ViewRotation = Controller.Rotation;
//旋转 pawn 面向光标
if (Controller.Pawn!=none)
Controller.Pawn.SetDesiredRotation(ViewRotation);
DeltaRot.Yaw = Controller.PlayerInput.aTurn;
DeltaRot.Pitch = 0;
Controller.ProcessViewRotation( DeltaTime, ViewRotation, DeltaRot );
Controller.SetRotation(ViewRotation);
NewRotation = ViewRotation;
NewRotation.Roll = Controller.Rotation.Roll;
if ( Controller.Pawn != None )
Controller.Pawn.FaceRotation(NewRotation, DeltaTime);
}
defaultproperties
{
}
所有下面的这些文件都应该防止在 UDKgame/Config 目录中。由于某些可能是新添加的目录,所以您需要自己进行创建。其他可以简单地修改使它们可以包括这些新的配置设置。
DefaultCamera.ini 文件应该含有在新相机类中出现的各种配置变量的值。在这个示例中,它只包含设置一个默认的相机模块类。
DefaultCamera.ini
[UDNExamples.UDNPlayerCamera] DefaultCameraClass=UDNExamples.UDNCameraModule_TopDown
DefaultGame.ini 文件应该将 [Engine.GameInfo] 项修改为指向这个新游戏类型,而且它还需要在底部添加一个项来指定要使用的默认控制模块类。
DefaultGame.ini
... [Engine.GameInfo] DefaultGame=UDNExamples.UDNGame DefaultServerGame=UDNExamples.UDNGame ... [UDNExamples.UDNPlayerController] DefaultControlModuleClass=UDNExamples.UDNControlModule_TopDown
只要创建了这些配置和/或使用希望得到的配置设置填充或修改了这些配置后,下次运行游戏或编辑器的时候将会创建 UDKCamera.ini 和 UDKGame.ini 文件。
注意: 为了要使用这个新的游戏类型,您将需要确保您的地图的前缀正确。我们会在我们的游戏类型中将这个前缀设置为"UDN",这样所有地图都将需要以"UDN-"为前缀进行命名。还可以使用编辑器中的地图快速测试这个新的游戏类型,将这个地图的 World Properties(世界属性)中的 Game Type PIE 属性设置为这个新的游戏类型。
标签:检索 out 前缀 locking ras eai 几何体 产生 技术分享
原文地址:http://www.cnblogs.com/wodehao0808/p/7256868.html