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