hướng dẫn camera 3D 100% của RPG

Go down

hướng dẫn camera 3D 100% của RPG

Bài gửi  honglong99 on Thu Jul 08, 2010 9:01 am

Bây giờ mình sẽ chỉ các bạn một camera 3D có thể xoay quanh nhân vật 100% bằng right_click. Tuy nhiên mình vẫn còn khá nhiều điều không hợp lý và hy vọng ai làm tutorial này nếu có thể chỉnh sửa cùng góp ý với mình thì rất cảm ơn. Cuối bài mình sẽ nêu những điều mình còn chưa hài lòng sau.

- Đầu tiên là phần chuẩn bị: Ở đây mình cần 4 file, các bạn đã biết cách tạo file UnrealScript rồi thì mình sẽ không nói lại phần ấy. 4 file đó là: main, MyPawn, MyCamera, MyGamePlayerController. Các bạn có thể đặt tên khác nhau thì tùy miễn các bạn biết các bạn đặt làm gì.

+ Với file MyPawn các bạn chỉnh extends đến Pawn
class MyPawn extends GamePawn;
Tương tự: MyCamera: các bạn extends đến Camera; MyGamePlayerController: các bạn extends đến GamePlayerController ; main thì là GameInfo

+Ở đây mình sẽ giải thích 1 tí, các bạn đừng nhầm UnrealScript chỉ sử dụng trên ngôn ngữ C/C++, ở đây nó còn sử dụng cả Java, bằng chứng là nó sử dụng Extends để mở rộng đến các classes khác, mỗi class con chỉ được extends đến 1 class cha thôi và như bạn biết nó sẽ có thể sử dụng những gì mà class cha đã build sẵn, tất nhiên không phải cái gì build sẵn ở class cha cũng xài được mà đôi khi ta cần phải viết lại hàm đó. Lát nữa phần dưới các bạn sẽ gặp vấn đề như thế.

+ 1 điều nữa là công cụ sẽ rất đắc lực với bạn trong đây là Search ( Ctrl+shift+F ), tôi nghĩ các bạn nên làm quen đi, vì các hàm trong Unreal con số có thể lên tới 300 hàm và nhiều biến nhỏ chưa tính đấy. Bạn ko thể nào ngồi mà tìm từng dòng đâu. Thay vào đó là Search hoặc với 1 hàm hoặc biến mà các bạn trong khi nghiên cứu code của người khác mà ko biết nó nằm chỗ nào, hãy double_click lên hàm ( biến ), sau đó right_click >>> " Go To Definition ", bạn sẽ biết hàm đó ( biến ) nó định nghĩa ở đâu.

-Cơ bản các file chúng ta đã có, giờ chúng ta sẽ vào từng file để thêm code. Bắt đầu sẽ là MyGamePlayerController
class MyGamePlayerController extends GamePlayerController;



Code:
class MyGamePlayerController extends GamePlayerController;
simulated event PostBeginPlay()
{
    super.PostBeginPlay();
    `Log("I am alive !");

}

exec function ZoomCameraIn()
{
    if(PlayerCamera.FreeCamDistance >=100 )
    PlayerCamera.FreeCamDistance -=10;
}

exec function ZoomCameraOut()
{
 
    if(PlayerCamera.FreeCamDistance <=170)
    PlayerCamera.FreeCamDistance +=10;
}
exec function Free()
{
    MyCamera(PlayerCamera).BeginFreeLook();
}

exec function NonFree()
{
    MyCamera(PlayerCamera).StopFreeLook();
}

DefaultProperties
{
    CameraClass=class'UDKProject.MyCamera'
}

+ 'Log ("I am Alive)") ở đây chỉ thêm để check coi Class MyGamePlayerController có hoạt động hay ko, nếu hoạt động thì trong bảng Log ( nếu các bạn để ý khi cài đặt nfringe ở tab Debug tôi có kêu check mục " Open Log at Position" >>> nó sẽ hiện 1 bảng log đen khi chạy debug ) sẽ hiện chữ "Script Log: Iam Alive " >>> Class hoạt động tốt đấy.



+Như tôi đã nói ở trên, không phải lúc nào Class cha cũng đáp ứng các nhu cầu của Class con, như tôi muốn xuất 'Log ngay khi game vừa chạy, tôi không muốn phải vào Class cha GamePlayerController để sửa ( để ý Class này đã bị khóa bởi ReadOnly, cái này nhằm tránh cho chúng ta sửa kẻo hư luôn toàn bộ code ). Vậy làm sao để sửa, Simulated sẽ giúp chúng ta điều đó, nó sẽ nói rằng, chúng ta viết ngược lại event PostBeginPlay( ) >>> giờ thì hệ thống sẽ không dùng PostBeginPlay( ) trong Class Cha GamePlayerController nữa mà sẽ dùng ở Class con MyGamePlayerController. Có những trường hợp Class Cha hoàn toàn xài được nhưng vẫn thiếu 1 số cái ta cần, nghĩa là ta có thể sử dụng lại toàn bộ code trong hàm đó mà ko cần sửa gì cả, chủ yếu là ta cần thêm váo 1 số code của riêng ta ( ko đụng tới code hàm cha ), lúc ấy hãy dùng Super.Function . Super sẽ nói, ta muốn sử dụng lại toàn bộ code trong hàm PostBeginPlay () trong Class Cha >>> khỏi phải viết lại.

+ exec giống như hàm chạy, tôi cũng ko biết nói thế nào cho rõ ý nghĩa của nó, hy vọng có ai đó sẽ giúp tôi trong việc dịch ý nghĩa của các biến và class build sẵn trong UnrealScript (http://udn.epicgames.com/Three/UnrealScriptReference.html). ZoomCameraIn ,ZoomCameraOut, Free, NonFree tương ứng với MouseScrollUp, MouseScrollDown, Right_click, và khi thả Right_Click ( Release Right_Click ). Các biến này sẽ được định nghĩa trong thư mục UDKGame/Config/UDKInput.ini . Trong đây nó sẽ định nghĩa các phím, chuột,button gamepad. Các bạn thêm vào cuối [Engine.PlayerInput]
Code:
Bindings=(Name="RightMouseButton",Command="Free | OnRelease NonFree")
Bindings=(Name="MouseScrollUp",Command="ZoomCameraIn")
Bindings=(Name="MouseScrollDown",Command="ZoomCameraOut")
Phần Name"" các bạn phải đúng như UnrealScript quy định ( cái này google search đi, quên trang rồi ), còn Command"" các bạn có thể đặt tên tùy ý thích, miễn khi sử dụng dùng đúng tên đó là được. Riêng RightMouseButton các bạn thấy đặc biệt là "Free | OnRelease NonFree" >> nghĩa là khi click right_click là Free, khi thả ra là OnRelease. Tuy nhiên, tôi thiết lập các hàm BeginFreeLook () và StopFreeLook (), FreeCamDistance bên MyCamera nên chắc các bạn hiểu tôi ghi gì ở đây rồi.

+ OK, ở defaultPropertise các bạn thấy có CameraClass=Class'UDKProject.MyCamera' >>> vì theo hệ thống Unreal, Camera được định nghĩa trong Class PlayerController ( các bạn có thể Search"CameraClass" và tìm ở file PlayerController các bạn sẽ thấy các liên quan để CameraClass ), nhưng ở đây ta ko cùng Class Camera mà ta sẽ dùng Class MyCamera của chúng ta nên chúng ta phải default lại Propertise.

+MyGamePlayerController giống như là nơi tập trung các vấn đề về điều khiển nhân vật, điều khiển hệ thống, để tìm hiểu thêm các bạn có thể vào file PlayerController để xem nó defaul cái gì và nó viết những hàm gì, hy vọng sẽ giúp các bạn hiểu ý tôi nói.

-Còn bây giờ là tới MyCamera.
Code:
class MyCamera extends Camera;
var bool bFreeLookMode;
var bool batdau;
simulated function UpdateViewTarget(out TViewTarget OutVT, float DeltaTime)
{
    local vector        Loc, Pos, HitLocation, HitNormal;
    local rotator        Rot;
    local Actor            HitActor;
    local CameraActor    CamActor;
    local bool            bDoNotApplyModifiers;
    local TPOV            OrigPOV;

    // store previous POV, in case we need it later
    OrigPOV = OutVT.POV;

    // Default FOV on viewtarget
    OutVT.POV.FOV = DefaultFOV;

    // Viewing through a camera actor.
    CamActor = CameraActor(OutVT.Target);
    if( CamActor != None )
    {
    CamActor.GetCameraView(DeltaTime, OutVT.POV);

    // Grab aspect ratio from the CameraActor.
    bConstrainAspectRatio    = bConstrainAspectRatio || CamActor.bConstrainAspectRatio;
    OutVT.AspectRatio        = CamActor.AspectRatio;

    // See if the CameraActor wants to override the PostProcess settings used.
    CamOverridePostProcessAlpha = CamActor.CamOverridePostProcessAlpha;
    CamPostProcessSettings = CamActor.CamOverridePostProcess;
    }
    else
    {
    // Give Pawn Viewtarget a chance to dictate the camera position.
    // If Pawn doesn't override the camera view, then we proceed with our own defaults
    if( Pawn(OutVT.Target) == None ||
    !Pawn(OutVT.Target).CalcCamera(DeltaTime, OutVT.POV.Location, OutVT.POV.Rotation, OutVT.POV.FOV) )
    {
    // don't apply modifiers when using these debug camera modes.
    bDoNotApplyModifiers = TRUE;
    if(!batdau)
                            {
                   
                                FreeCamDistance=50;
                            }
                            batdau=true;
    switch( CameraStyle )
    {
    case 'Fixed'        :    // do not update, keep previous camera position by restoring
    // saved POV, in case CalcCamera changes it but still returns false
    OutVT.POV = OrigPOV;
    break;

    case 'ThirdPerson'    : // Simple third person view implementation
    case 'FreeCam'        :
    case 'FreeCam_Default':
                            Loc = OutVT.Target.Location;
                            Rot = OutVT.Target.Rotation;

                            http://OutVT.Target.GetActorEyesViewPoint(Loc, Rot);
                            if( CameraStyle == 'FreeCam' || CameraStyle == 'FreeCam_Default' )
                            {
                            Rot = PCOwner.Rotation;
                            }
                            Loc += FreeCamOffset >> Rot;

                            Pos = Loc - Vector(Rot) * FreeCamDistance;
                            // @fixme, respect 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 'Isometric':
                             
                                Loc = OutVT.Target.Location;
                             
                         
                                if(CameraStyle=='Isometric' && bFreeLookMode == true)
                                {
                             
                                    Rot = PCOwner.Rotation;
                             
                                }
                                Loc += FreeCamOffset >> Rot;
                         
                                Pos = Loc - Vector(Rot) * FreeCamDistance;
                             
                             
                                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'    : // Simple first person, view through viewtarget's 'eyes'
    default                :    OutVT.Target.GetActorEyesViewPoint(OutVT.POV.Location, OutVT.POV.Rotation);
    break;

    }
    }
    }

    if( !bDoNotApplyModifiers )
    {
    // Apply camera modifiers at the end (view shakes for example)
    ApplyCameraModifiers(DeltaTime, OutVT.POV);
    }
    //`log( WorldInfo.TimeSeconds  @ GetFuncName() @ OutVT.Target @ OutVT.POV.Location @ OutVT.POV.Rotation @ OutVT.POV.FOV );
}
function BeginFreeLook()
{
 
    `Log("Press");
    http://Controller.SetRotation(Rotation);
    bFreeLookMode = true;
 
}

function  StopFreeLook()
{
 
    bFreeLookMode = false;
}
DefaultProperties
{
    DefaultFOV=90.f //Zoom ( giong nhu aim )

    bFreeLookMode=false
}
+ UpdateViewTarget () sẽ có tác dụng cập nhật những gì chúng ta hoạt động như di chuyển tọa độ camera.... nói chung là thiết lập camera cho khỏi dài dòng. Như các bạn thấy tron Switch () có các case như 'ThirdPerson' , 'FreeCam' , 'FreeCam_default' và 'FirstPerson' riêng 'Isometric' là của tui viết. Các bạn có thể vọc bằng cách thay vì xài 'Isometric' thì có thể xài các case kia để hiểu tôi làm gì ở đây nhé, và chút nữa tôi sẽ chỉ làm cách nào để xài các case này. Ok, ngoài ra còn có các hàm BeginFreeLook (), StopFreeLook() mà tôi dùng ở đây chắc ko quá khó hiểu đâu nhỉ. Để nhanh gọn chúng ta qua tiếp file cuối là MyPawn.

-Thêm các code sau vào MyPawn:
Code:
class MyPawn extends GamePawn;
var bool bFreeLookMode;
simulated function name GetDefaultCameraMode( PlayerController RequestedBy )
{
    return 'Isometric';
    //return 'FreeCam';
    //return 'FreeCam_Default';
    //return 'ThirdPerson';
}
simulated event bool InFreeCam()
{
    local PlayerController    PC;

    PC = PlayerController(Controller);
 
    return (PC != None && PC.PlayerCamera != None && (PC.PlayerCamera.CameraStyle == 'FreeCam' || PC.PlayerCamera.CameraStyle == 'FreeCam_Default'||PC.PlayerCamera.CameraStyle == 'Isometric') );
}

DefaultProperties
{
    Components.Remove(Sprite)

    Begin Object Class=DynamicLightEnvironmentComponent Name=MyLightEnvironment
        ModShadowFadeoutTime=0.25
        MinTimeBetweenFullUpdates=0.2
        AmbientGlow=(R=.01,G=.01,B=.01,A=1)
        AmbientShadowColor=(R=0.15,G=0.15,B=0.15)
        LightShadowMode=LightShadow_ModulateBetter
        ShadowFilterQuality=SFQ_High
        bSynthesizeSHLight=TRUE
    End Object
    Components.Add(MyLightEnvironment)

    Begin Object Class=SkeletalMeshComponent Name=InitialSkeletalMesh
        CastShadow=true
        bCastDynamicShadow=true
        bOwnerNoSee=false
        LightEnvironment=MyLightEnvironment;
        BlockRigidBody=true;
        CollideActors=true;
        BlockZeroExtent=true;
        PhysicsAsset=PhysicsAsset'CH_AnimCorrupt.Mesh.SK_CH_Corrupt_Male_Physics'
        AnimSets(0)=AnimSet'CH_AnimHuman.Anims.K_AnimHuman_AimOffset'
        AnimSets(1)=AnimSet'CH_AnimHuman.Anims.K_AnimHuman_BaseMale'
        AnimTreeTemplate=AnimTree'CH_AnimHuman_Tree.AT_CH_Human'
        SkeletalMesh=SkeletalMesh'CH_LIAM_Cathode.Mesh.SK_CH_LIAM_Cathode'
    End Object

    Mesh=InitialSkeletalMesh;
    Components.Add(InitialSkeletalMesh);

}
Tương tự PlayerController, để hiểu Pawn có tác dụng gì thì hãy tìm hiểu trong file Pawn. Nào, giờ chúng ta muốn sử dụng case nào trong Mycamera thì vào GetDefaultCameraMode mà return nhé ( dịch tên cũng hiểu rồi ). Riêng hàm InFreeCam thì tôi mới khám phá ra khi tôi nghiên cứu camera, trước khi thêm code hàm này, các bạn hãy lần lượt thử Case 'ThirdPerson' và 'FreeCam' để cảm nhận nhé, với 'ThirdPerson' các bạn sẽ thấy cả màn hình xoay chuyển theo hồng tâm và cả con robot cũng xoay theo hồng tâm, nhưng 'FreeCam' thì ko, nó chỉ xoay quanh con robot như khi bạn xài right_click chơi RPG vậy. Sau đó các bạn hãy dùng case 'Isomertic' để ý vì sao code 'FreeCam' và 'Isomertic' gần như giống nhau mà tại sao khi xài 'Isometric' con robot vẫn xoay theo hướng ta xoay hồng tâm. Đó là do hàm InFreeCam ( ) gốc trong file Pawn ( Search "FreeCam", các bạn sẽ thấy nó có liên quan đến InFree trong Pawn). Tôi muốn viết lại hàm này nên dùng Simulated và thêm vào PC.PlayerCamera.CameraStyle == 'Isometric' với ý muốn khi tôi right_click thì nó xoay quanh con robot chứ ko phải con robot xoay theo hồng tâm. OK, còn vì sao có con robot thì các bạn nhìn vào DefaultPropertise , nguyên đoạn code trong đó nó sẽ load con robot trong Content browse của UDK ( code gần như C# đấy ).

Chúng ta đã xong tutorial rồi đấy, giờ tôi sẽ nói những điểm tôi chưa hài lòng, thứ nhất khi xoay camera = right_click, nó xoay tốt đấy, nhưng khi release nó ko update lại hướng mà camera tôi thả ra,.... nó xoay về cái hướng con robot đang nhìn. Tôi chưa code Movement nên có thể vì thế mà kết quả chưa như ý. đặc biệt khi bạn di chuyển bạn sẽ thấy. Tôi hy vọng có thể tìm một team nào đó nghiên cứu code UnrealScript vì nói thật một mình tôi ko thể nghiên cứu hết được những gì bất cập hiện này.

honglong99

Tổng số bài gửi : 24
Join date : 08/07/2010

Xem lý lịch thành viên

Về Đầu Trang Go down

Về Đầu Trang


 
Permissions in this forum:
Bạn không có quyền trả lời bài viết