Tuesday, September 25, 2012

UDK-Toturial-CH3.UnrealScript-Camera

1.SetingUp GameInfo.
2.Get Viewport.
3.Dissable Crosshair,default gun,fix rotation to fit Pawn angle.
4.CustomPawn,Isometric Camera.
5.Top-Down Camera.


A. SettingUp GameInfo
在UDK裡,做一個遊戲必須先定義出遊戲的GameType,其中GameInfo定義遊戲如何開始與結束,定義著遊戲的規則。
其中:當GameType為None時,這代表的是下圖,沒有任何的人物、HUD、結束條件。
當GameType:當為UTDeathmatch,在HUD上多了右上方雷達、準心、子彈數、等,這同時也定義了遊戲如何結束。



在WorldProperties可以看到一些UDK定義出來的GameInfo

因此先做出一個自訂的GameType,產生一個FunnyGameInfo.uc先繼承UTDeathMatch,這足夠我們完成遊戲
class FunnyGameInfo extends UTDeathMatch;

DefaultProperties
{
}

接下來我們必須指定Controller給玩家,因此產生一個CustomController.uc 繼承UTPlayerController
class CustomPlayerController extends UTPlayerController;
simulated function PostBeginPlay()
{
super.PostbeginPlay();
`log("Our CustomPlayerController");
}
DefaultProperties
{
}

回到FunnyGameInfo.uc,在DefaultProperties設定PlayerController
class FunnyGameInfo extends UTDeathMatch;

DefaultProperties
{
PlayerControllerClass=class’Tutorial.CustomPlayerController’
}

Complier Code開啟Editor,將WorldProperties改成FunnyGameInfo

執行後,馬上按ESC觀看log

ScriptLog: Our CustomPlayerController出現代表有執行成功自行定義的CustomPlayerController.uc,其中有一些ScriptWarning在執行上不太影響,不過可以些進行一些修改:

將WorldInfo底下的 My Map Info改成UTMapInfo,因為是繼承UTPlayerController而不是UDKPlayerController,ScriptWarning會只剩下Accessed None ‘ViewportClient’,可以先暫時不用去管它。
B. Change Camera Angle
當CustomPlayerController 繼承 UTPlayerController,因此有些function只要去Override 它即可達到效果,在遊戲需要把Camera移至需要的位置,要去override GetPlayerViewPoint function:
先必須把camera位置設定
var vector PlayerViewOffset;
在DefaultProperties給予起始值
PlayerViewOffset=(X=-64,Y=0,Z=1024)
由上可知是一個Top-Down的視角。不像Unity3D以Y-Axis為向上軸,UDK以Z-Axis在匯入模型上要注意,X=-64 在預設上的第一人稱射擊視點,玩家視點有稍微往X axis座移動,PlayerViewOffset就可以放視點放在人物中心,從Z=1024往下看,
接下來要在CustomPlayerController.uc禮Override GetPlayerViewPoint function:
Simulated event GetPlayerViewPoint(out vector out_Location,out Rotator out_Rotation)
{
super.GetPlayerViewPoint(out_Location,out_Rotation);
}
並super.GetPlayerViewPoint(out_Location,out_Rotation)加上
If(Pawn !=none)
{
out_Location=Pawn.Location + PlayerViewOffset;
out_Rotation=rotator(Pawn.Location – out_Location);
}
在if判斷式中判斷在CustomPlayerController是否有沒有Pawn,在UDK中Pawn表示player,當Pawn的位置改變時,camera必須要跟著移動,因此改變Player的ViewPoint,Camera成像位置跟一般遊戲引擎一樣用向量表示,Compiler後執行:


在預設上是不會看到自己的Pawn,但Top-Down的視角必須顯示出人物,在meshes的參數有bOwnerNoSee,必須要把它設定成False,在剛新增的Script的位置最上面:
Pawn.Mesh.SetOwnerNoSee(false);
現在CustomPlayerController.us:
class CustomPlayerController extends UTPlayerController;
var vector PlayerViewOffset;
simulated function PostBeginPlay()
{
super.PostBeginPlay();
`log("Our CustomPlayerController");
}
simulated event GetPlayerViewPoint(out vector out_Location,out rotator out_Rotation)
{
super.GetPlayerViewPoint(out_Location,out_Rotation);
if(Pawn != none)
{
Pawn.Mesh.SetOwnerNoSee(false);
out_Location = Pawn.Location + PlayerViewOffset;
out_Rotation = rotator(Pawn.Location - out_Location);
}
}
DefaultProperties
{
PlayerViewOffset=(X=-64,Y=0,Z=1024)
}

Compiler


在一般射擊遊戲裡,當人物旋轉方向後攻擊的角度也被須跟著被改變,因此還要去override GetAdjustedAimFor(),因此在GetPlayerViewPoint()後新增:
function Rotator GetAdjustedAimFor(Weapon w,vector startFireLoc)
{
Return Pawn.Rotation;
}
這是在告訴武器使用Pawn的rotation而不是跟著camera的rotation。
再把位於畫面中央的準星去掉,override PostBeginPlay():
Simulated function PostBeginPlay()
{
super.PostBeginPlay();
bNoCrosshair = true;
}
因為crosshair是儲存在config 的bool,意味著不能再DefaultProperties修改,有config的字眼都會儲存在INI的檔案裡,我們不能要求玩家去修改ini檔案,因此直接在script初始化時將bNoCrosshair=true。
接下來把在剛剛還有看到一個武器(給第一人稱使用的武器),將它隱藏起來,在GetPlayerViewPoint()裡的 if判斷式增加:
If(Pawn.Weapon != none)
{
Pawn.Weapon.SetHidden(true);
}
以下是所有CustomPlayerController.us Code:
class CustomPlayerController extends UTPlayerController;

var vector PlayerViewOffset;

simulated function PostBeginPlay()
{
super.PostBeginPlay();
`log("Our CustomPlayerController");
bNoCrosshair=true;
}

simulated event GetPlayerViewPoint(out vector out_Location,out rotator out_Rotation)
{
super.GetPlayerViewPoint(out_Location,out_Rotation);
if(Pawn != none)
{
Pawn.Mesh.SetOwnerNoSee(false);
if(Pawn.Weapon !=none)
Pawn.Weapon.SetHidden(true);

out_Location = Pawn.Location + PlayerViewOffset;
out_Rotation = rotator(Pawn.Location - out_Location);
}
}

function Rotator GetAdjustedAimFor(Weapon W,vector startFireLoc)
{
return Pawn.Rotation;
}
DefaultProperties
{
PlayerViewOffset=(X=-64,Y=0,Z=600)
}




Isometric Camera
產生一個新的Controller,CustomIsometricController.uc:

Class CustomeIsometricController extends UTPlayerController;
simulated function PostBeginPlay()
{
super.PostBeginPlay();
`log(IsoMeticController);
bNoCrosshair=true;
}
simulated event GetPlayerViewPoint(out vector out_Location,out rotator out_Rotation)
{
super.GetPlayerViewPoint(out_Location,out_Rotation);
if(Pawn != none)
{
Pawn.Mesh.SetOwnerNoSee(false);
If(Pawn.Weapon != none)
{
Pawn.Weapon.SetHidden(true);
}
}
}

在GetPlayerViewPoint() 後 override UpdateRotation()
Simulated function UpdateRotation(float DeltaTime)
{
local Rotator DeltaRot,newRotation,ViewRotation;
ViewRotation=Rotation;
If(Pawn != none)
Pawn.SetDesiredRotation(ViewRotation);
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);
}
ProcessViewRotation()定義在Engine.PlayerController,根據玩家輸入,SetRotation()定義在Engine.Actor旋轉腳色(Actor)的Rotation,Pawn代表腳色定義在Engine.Pawn,DeltaRot.Pitch=0這鎖定了角色(Actor)Pitch,在Isometric因視角關係都會把這些值去除,以免攻擊不到,Compiler後即發現腳色Pitch被鎖定不能轉向。
接下來要做出自訂的Pawn因此,產生CustomPawn.uc:

class CustomPawn extends UTPawn;
DefaultProperties
{
}



不忘了要改FunnyGameInfo.uc:
class FunnyGameInfo extends UTDeathmatch;
DefaultProperties
{
PlayerControllerClass = class'Tutorial.CustomIsometricController'
DefaultPawnClass=class'Tutorial.CustomPawn'
}

在CustomPawn.uc:
var float CamOffsetDistance;
var int IsoCamAngle;
在DefaultProperties設定起始值:
CamOffsetDistance=384.0
IsoCamAngle=6420 //35度視角
直接改變Pawn的Camera而不是在GetPlayerViewPoint做修改,在CustomPawn.uc override CalcCamera function
Simulated function bool CalcCamera(float CDeltaTime,out vector out_CamLoc,out Rotator oit_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;
}
在這裡遊戲裡視角都已正常,不過射擊的方式是錯誤的因此,在CalcCamera下在override GetBaseAimRotation:
simulated event Rotator GetBaseAimRotation()
{
Local rotator POVRot,tempRot;
tempRot = Rotation;
tempRot.Pitch=0;
SetRotation(tempRot);
POVRot=Rotation;
POVRot.Pitch=0;
Return POVRot;
}
手臂的旋轉也必須忽略Pitch.
完整程式碼:
FunnyGameInfo:

class FunnyGameInfo extends UTDeathmatch;
DefaultProperties
{
PlayerControllerClass = class'Tutorial.CustomIsometricController'
DefaultPawnClass=class'Tutorial.CustomPawn'
}
CustomIsometricController.uc:
class CustomIsometricController extends UTPlayerController;
var float CamOffsetDistance;
var int IsoCamAngle;
simulated function PostBeginPlay()
{
super.PostBeginPlay();
`log("Our CustomIsometricPlayerController");
bNoCrosshair=true;
}
simulated event GetPlayerViewPoint(out vector out_Location,out rotator out_Rotation)
{
super.GetPlayerViewPoint(out_Location,out_Rotation);
if(Pawn != none)
{
Pawn.Mesh.SetOwnerNoSee(false);
if(Pawn.Weapon != none)
Pawn.Weapon.SetHidden(true);
}
}
simulated function UpdateRotation(float DeltaTime)
{
local Rotator DeltaRot,newRotation,ViewRotation;
ViewRotation = Rotation;
if(Pawn != none)
{
Pawn.SetDesiredRotation(ViewRotation);
}
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
{
}

CustomPawn.uc:
class CustomPawn extends UTPawn;
var float CamOffsetDistance;
var int IsoCamAngle;
simulated function bool CalcCamera(float CDeltaTime,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 event Rotator GetBaseAimRotation()
{
local rotator POVRot,tempRot;
tempRot = Rotation;
tempRot.Pitch=0;
SetRotation(tempRot);
POVRot = Rotation;
POVRot.Pitch=0;
return POVRot;
}
DefaultProperties
{
IsoCamAngle = 6420
CamOffsetDistance=384.0
}

Isometric Camera:

Top-Down Camera(better than before):
CustomTopDownPawn.uc:
class CustomTopDownPawn extends UTPawn;

var float CamOffsetDistance;
var bool bFollowPlayerRotation;
simulated function bool CalcCamera(float dDeltaTime,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.Roll=0;
out_CamRot.Yaw=Rotation.Yaw;
}
return true;
}

simulated 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
}

在Top-Down視點,攻擊方向不應該包含Pitch,一開始的視點並未鎖定住Pitch方向。
CustomTopDownController.uc:
class CustomTopDownController extends UTPlayerController;
simulated function PostBeginPlay()
{
super.PostBeginPlay();
`log("Our CustomIsometricPlayerController");
bNoCrosshair=true;
}
simulated event GetPlayerViewPoint(out vector out_Location,out rotator out_Rotation)
{
super.GetPlayerViewPoint(out_Location,out_Rotation);
if(Pawn != none)
{
Pawn.Mesh.SetOwnerNoSee(false);
if(Pawn.Weapon !=none)
Pawn.Weapon.SetHidden(true);
}
}
function UpdateRotation(float DeltaTime )
{
local Rotator DeltaRot,newRotation,ViewRotation;
ViewRotation = Rotation;
if(Pawn != none)
Pawn.SetDesiredRotation(ViewRotation);
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
{
}

FunnyGameInfo.uc:
class FunnyGameInfo extends UTDeathmatch;


DefaultProperties
{
PlayerControllerClass = class'Tutorial.CustomTopDownController'
DefaultPawnClass=class'Tutorial.CustomTopDownPawn'
}


Basic done.
Here is Code: CH3.ZIP

No comments:

Post a Comment