Thursday, September 27, 2012

UDK-Toturial-CH4.UnrealScript-Weapon


1.CustomWeapon
2.Weapon Projectile
3.Upgradeable Weapon
4.Class Modifier
5.Show/Hide Categories

A. Simple Weapon:
處理武器的升級,在一般遊戲裡,武器可能因為得到東西而提高武器威力或攻擊速度,產生一個CustomWeapon.uc:
class CustomWeapon extends UTWeapon;
var int CurrentWeaponLevel;
function UpgradeWeapon()
{
CurrentWeaponLevel++;
}
DefaultProperties
{
}

用來記錄武器等級,使用UDK有的RocketLauncher來當武器,產生一個CustomRocketWeapon.uc:
class CustomRifleWeapon extends CustomWeapon;
DefaultProperties
{
AttachmentClass=class'UTGameContent.UTAttachment_ShockRifle'
WeaponFireTypes(0)=EWFT_Projectile
WeaponFireTypes(1)=EWFT_Projectile
WeaponProjectiles(0)=class'UTProj_ShockBall'
WeaponProjectiles(1)=class'UTProj_Rocket'
AmmoCount=40
MaxAmmoCount=40
}

WeaponProjectiles(0)、WeaponProjectiles(1)武器種類設定完全不一樣,在撿到武器後可以發現滑鼠左右鍵發射的東西是完全不一樣的,AttachmentClass是代表撿到武器後主角手上的武器是顯示的類別和外觀。
在地圖上放置一個UTWeaponPickupFactory
Actor|Classes|Pickups|Weapon|UTWeaponPickupFactory 將 Weapon Pickup Class選擇CustomRifleWeapon

Play in editor,會發現UTWeaponPickupFactory上面並沒有武器,但當人物走到的時候會撿到武器:

這是因為並未設定顯在上面的Mesh因此在DefaultProperties 加上
Begin Object Name=PickupMesh
SkeletalMesh=SkeletalMesh’WP_ShockRifle.Mesh.SK_WP_ShockRifle _3P’
End Object
Components.Add(PickupMesh)
Name可以自行定義,SkeletalMesh’ WP_ShockRifle.Mesh.SK_WP_ShockRifle _3P’則表示是SkeletalMesh的模型,它在的Package為WP_ShockRifle.Mesh.SK_WP_ShockRifle_3P,在ContentBrowser搜尋SK_WP_ShockRifle_3P 即可看到模型
其增加SkeletalMesh後結果:

若一個Actor不去增加Component其功能會少很多且無法顯示(SpriteCompoent、StaticComponent、SkeletalMeshComponent)。
UpgradeableWeapon:
先產生升級武器的指示物,在這裡先用方塊來代表,也可以匯入自行模型,產生一個AlexGameActor.uc:
class AlexGameActor extends Actor;
DefaultProperties
{
}

產生一個WeaponUpgrade.uc:
class WeaponUpgrade extends AlexGameActor
placeable;
DefaultProperties
{
}

因為WeaponUpgrade有 extend AlexGameActor 有關鍵字placeable,因此在Actor Classes 可以看到

現在玩家當碰觸到WeaponUpgrade這Actor後必須有做出反應因此在WeaponUpgrade.uc增加function:
event Touch(Actor Other,PrimitiveComponent OtherComp,vector HitLocation,vector HitNormal)
{
if(Pawn(Other) != none && CustomWeapon(Pawn(Other).Weapon) != none)
{
CustomWeapon(Pawn(Other).Weapon).UpgradeWeapon();
Destory();
}
}
用一個Touch 的Event去呼叫兩個Actor撞再一起,先判斷Actor是否撞到Pawn(玩家),如果是的話再判斷是否拿著我們的武器(CustomWeapon),這之間要做typecasting:
第一個就是把Actor轉成Pawn,才能確定是否撞到Actor的是Pawn,再來就是Pawn(Other).Weapon,因為Actor並沒有Weapon這個值,Weapon是在Pawn,所以就是把撞到的主角(Pawn)裡面的Weapon數值是否為none,最後就是CustomWeapon(Pawn(Other).Weapon).UpgradeWeapon(),因為一直做typecast所以可以呼叫CustomWeapon.uc的UpgradeWeapon()並執行CurrentWeaponLevel++。
在DefaultProperties 新增:
bCollideActors =true
Begin Object Class=DynamicLightEnvironmentComponent Name=myLight
bEnabled=true
End Object
Components.add(myLight)
Begin Object Class=StaticMeshComponent Name=myMesh
StaticMesh=StaticMesh'UN_SimpleMeshes.TexPropCube_Dup'
Materials(0)=Material'EditorMaterials.WidgetMaterial_Y'
Scale3D=(X=0.125,Y=0.125,Z=0.125)
End Object
Components.Add(myMesh)
Begin Object Class=CylinderComponent Name=myCollision
CollisionRadius=16.0
CollisionHeight=16.0
BlockNonZeroExtent=true
BlockZeroExtent=true
BlockActors=true
CollideActors=true
End Object
CollisionComponent=myCollision
Components.Add(myCollision)
bCollideActors讓Actor如果有東西跑過來去執行Touch,StaticMeshComponent是為顯示Cube(UN_SimpleMeshes.TexPropCube_Dup),Material(0)設定了材質(EditorMaterials.WidgetMaterial_Y),Scale3D則對Cube做縮放,而CylinderComponent則針對Collision的範圍作修改,同時也給予Cube CollisionComponent這個屬性

目前的WeaponUpgrade.uc:
class WeaponUpgrade extends AlexGameActor
placeable;
event Touch(Actor Other,PrimitiveComponent OtherComp,vector HitLocation,vector HitNormal)
{
if(Pawn(Other) != none && CustomWeapon(Pawn(Other).Weapon) != none)
{
CustomWeapon(Pawn(Other).Weapon).UpgradeWeapon();
Destroy();
}
}
DefaultProperties
{
bCollideActors =true
Begin Object Class=DynamicLightEnvironmentComponent Name=myLight
bEnabled=true
End Object
Components.add(myLight)

Begin Object Class=StaticMeshComponent Name=myMesh
StaticMesh=StaticMesh'UN_SimpleMeshes.TexPropCube_Dup'
Materials(0)=Material'EditorMaterials.WidgetMaterial_Y'
Scale3D=(X=0.125,Y=0.125,Z=0.125)
End Object
Components.Add(myMesh)
Begin Object Class=CylinderComponent Name=myCollision
CollisionRadius=16.0
CollisionHeight=16.0
BlockNonZeroExtent=true
BlockZeroExtent=true
BlockActors=true
CollideActors=true
End Object
CollisionComponent=myCollision
Components.Add(myCollision)
}

新增的Component一定要Add進去。
在Editor內放置WeaponUpgrade,一定要把槍撿起來,再碰WeaponUpgrade Actor發現他會被Destroy,在CustomWeapon.uc新增加log便於觀察
function UpgradeWeapon(){
CurrentWeaponLevel++;
`log(“Our CustomWeaponUpgradeLevel:” @ CurrentWeaponLevel);
}

在CustomWeapon.uc 新增:
class CustomWeapon extends UTWeapon;
var int CurrentWeaponLevel;
const MAX_Level = 5;
function UpgradeWeapon()
{
if(CurrentWeaponLevel < MAX_Level)
CurrentWeaponLevel++
`log("Our CustomWeaponUpgradeLevel:" @ CurrentWeaponLevel);
}
DefaultProperties
{
CurrentWeaponLevel=0
}

不過事實上,即使吃了武器能力還沒做變化。
實作改變武器攻擊速率:
在CustomWeapon.uc宣告:
var float FireRate[MAX_LEVEL]
在DefaultProperties 設定FireRate值
FireRate(0)=1.0
FireRate(1)=0.8
FireRate(2)=0.5
FireRate(3)=0.3
FireRate(4)=0.1
在UpgradeWeapon()裡改變FireInterval:
FireInterval[0]=FireRate[CurrentWeaponLevel -1];
因為if(CurrentWeaponLevel < MAX_Level){CurrentWeaponLevel++;} ,因此要在CurrentWeaponLevel-1 才會從0開始。再來就是當拿到新的武器把firing timer rest,在UpgradeWeapon()新增:
if(IsInState('WeaponFiring')))
{
ClearTimer(nameof(RefireCheckTimer));
TimeWeaponFiring(CurrentFireMode);
}
再撿起武器時,同時把武器子彈填滿:
AddAmmo(MaxAmmoCount);
這已定義在UTWeapon.uc
完整CustomWeapon.uc
class CustomWeapon extends UTWeapon;
var int CurrentWeaponLevel;
const MAX_Level = 5;
var float FireRate[MAX_Level];
function UpgradeWeapon()
{
if(CurrentWeaponLevel < MAX_Level)
CurrentWeaponLevel++;
FireInterval[0]=FireRate[CurrentWeaponLevel-1];
if(IsInState('WeaponFiring'))
{
ClearTimer(nameof(RefireCheckTimer));
TimeWeaponFiring(CurrentFireMode);
}
AddAmmo(MaxAmmoCount);
`log("Our CustomWeaponUpgradeLevel:" @ CurrentWeaponLevel);
}
DefaultProperties
{
CurrentWeaponLevel=0
FireRate(0)=1.0
FireRate(1)=0.8
FireRate(2)=0.5
FireRate(3)=0.3
FireRate(4)=0.1
}


每吃一個Actor,武器攻擊速率發生變化。
B. Script Usage:Class Modifiers & Some Tips
當實作一個基本的Actor 其功能,基本的category,這裡先而外創造一個GameActor.uc做說明:

顯示不出任何東西,如果將宣告var() int GravitValue 則

若想把GravityValue放置在Physics的category則宣告方式變成var(Physics) int GravityValue;

Hidecategories:
當寫好Actor給其他Level Design但又不想要給他們更改到category裡的值,設定上可以使用Hidecategories:
class GameActor extends Actor
hidecategories(Mobile,Debug)
placeable;
var(Physics) int GravitValue;
function PostBeginPlay()
{
super.PostBeginPlay();
}
DefaultProperties
{
Begin Object Class=SpriteComponent Name=TextureSprite
Sprite=Texture2D'EditorResources.S_NavP'
End Object
Components.Add(TextureSprite)
}

在extends Actor 後面加上hidecategories(Mobile,Debug) 即可,其結果

Abstract:
先看地圖上的UTWeaponPickupFactory裡的Weapon Pickup Class:

之前實作CustomWeapon 繼承UTWeapon,而CustomRifleWeapon 繼承 CustomWeapon,而在使用武器時,真正實作到功能的是CustomRifleWeapon,CustomWeapon不應該出現在Weapon pickup class以免不小心選擇到,因此在CustomWeapon.uc 增加Abstract:
class CustomWeapon extends UTWeapon
abstract;
其CustomWeapon就會被隱藏

被標示為abstract的class不能被Script spawn出來。
Native:
一般來說是完全用不到的,也不需要用在自己定義的Script裡面,通常出現在Engine source code,而一般也不能去修改,可以無視它。
Showcategories:
使用方式跟HideCategories一樣
class GameActor extends Actor
showcategories(Mobile,Debug)
placeable;

Done
File: CH4.Zip

No comments:

Post a Comment