----------------------------------StarterPlatformGame---李明阳2015-2-19-------------------------------------
GameType
在GameInfo中定义了角色,武器库,控制类,游戏启动时将会生成。
//What player controller class to create for the player
PlayerControllerClass=class'SPG_PlayerController'
//What default pawn archetype to spawn for the player
DefaultPawnArchetype=SPG_PlayerPawn'StarterPlatformGameContent.Archetypes.PlayerPawn'
//What default weapon archetype to spawn for the player
DefaultWeaponArchetype=SPG_Weapon'StarterPlatformGameContent.Archetypes.LinkGunWeapon'
UDK默认角色和武器
角色,武器库管理,武器库。
一个角色可以拥有不同的武器,就是武器库。不同类型的武器产生的作用不同,武器库管理就“管理”着它们的不同。
游戏开始时生成角色,当把武器附加给角色后添加武器管理。代码的执行顺序:
在Info中生成Pawn,完成Pawn中SkeletalMeshComponent的初使化,如果Pawn有定义动画资源,动画也在这时初使化。在Info中有定义武器库,当把武器库添加给Pawn时,武器类执行附加武器到Socket。
程序初使化流程:在Info类中生成Pawn,同时Pawn类组件初使化(动画);当Pawn初使化完成后Info类把武器库加给Pawn,在Weapon类中执行武器附加到Pawn的Socket。
SpawnDefaultPawnFor();PostInitAnimTree();AddDefaultInventory();ClientGivenTo()。
控制类和相机
在控制类中定义相机类,SPG_Camera类重写UpdateViewTarget,设置视点和取景朝向(旋转)。视点POV.Location始终对准Target(这里的Target是Controller占有的那个Pawn),朝向是Pawn的位置减视点位置的向量。这样相机就会保持和Pawn固定的偏移量“盯着”Pawn。
角色和控制类
在控制类有Input类和控制类有占有Pawn的情况下,控制类中的PlayerTick()就会不断调用。SPG_GameInfo的Input类是默认的PlayerInput,在GameInfo中有函数SpawnDefaultPawnFor(),在Info中有定义Controller和Pawn,SPG_PlayerController类中没有重写PlayerTick()函数,在默认的Controller中PlayerTick()就会调用,函数体中处理Pawn运动的PlayerMove(DeltaTime)函数也就被调用了。在默认的Controller类中PlayerMove()具体代码写在状态statePlayerWalking中,SPG_PlayerController.uc重写了statePlayerWalking,处理Pawn运动的实现就是SPG_PlayerController中的statePlayerWalking,在Controller中state PlayerWalking同时也是Pawn默认的状态。默认Controller的代码如下:
/**
* PlayerTick is onlycalled if the PlayerController has a PlayerInput object. Therefore, it will not be called on serversfor non-locally controlled playercontrollers
*/
event PlayerTick(floatDeltaTime )
{
if( !bShortConnectTimeOut )
{
bShortConnectTimeOut =true;
ServerShortTimeout();
}
if(Pawn != AcknowledgedPawn )
{
if( Role < ROLE_Authority )
{
// make sure old pawn controller is right
if ( (AcknowledgedPawn !=None)&& (AcknowledgedPawn.Controller == self))
AcknowledgedPawn.Controller=None;
}
AcknowledgePossession(Pawn);
}
PlayerInput.PlayerInput(DeltaTime);
if( bUpdatePosition )
{
ClientUpdatePosition();
}
PlayerMove(DeltaTime);
AdjustFOV(DeltaTime);
}
function PlayerMove(floatDeltaTime);
SPG_PlayerController中的statePlayerWalking:
默认情况下UDK的坐标系如下图:玩家的出生点位置,在默认的UTGame中第一人称相机取景点在Pawn的“眼睛”位置。在这个平台资源包游戏中,Pawn生成后的朝向是朝向世界坐标的Y轴(生成是是按PlayerStart的Rotation)。按默认情况来看,相机要放到如下图位置,按照视点偏移后在Yaw方向上要旋转90度。
关于Pawn的加速度计算:默认的UTGame中,从Input得到的aStrafe值实现了角色的左右移动,这里用相机的Y轴表示角色的加速度(移动速度方向和大小的向量),aStrafe的值用来驱动角色朝向(DesiredRotation),移动,移动速度快慢和加速度(NewAccel)大小。
//Grab the camera view point as we want to have movement aligned to the camera
PlayerCamera.GetCameraViewPoint(CameraLocation,CameraRotation);
//`log(CameraRotation.Roll@CameraRotation.Pitch@ CameraRotation.Yaw);
// Getthe individual axes of the rotation
GetAxes(CameraRotation, X, Y,Z);
//`log(X@Y@ Z);
//`log("aStrafe"@PlayerInput.aStrafe);
//Update acceleration
NewAccel = PlayerInput.aStrafe * Y;
//NewAccel.Z= 0;
NewAccel = Pawn.AccelRate * Normal(NewAccel);
// Setthe desired rotation
DesiredRotation= Rotator(NewAccel);
//Update rotation
OldRotation = Rotation;
UpdateRotation(DeltaTime);
SPG_PlayerController重写函数UpdateRotation(DeltaTime), PlayerInput.aLookUp在默认的UTGame中表示准星在屏幕上下移动的值,综合DesiredRotation 得到Pawn面部的最新朝向(Yaw)和瞄准朝向(Pitch)的DeltaRot。
SPG_PlayerPawn中重写Pawn的FaceRotation(),通过Controller传入的DeltaRot,完成Pawn的SetRotation()。
附加内容:
UDK的武器
开火就是打出一个子弹,子弹类型不唯一它们有各自的属性,比如:不同的开火状态不同的开火类型不同的射弹类型不同的开火频率不同的子弹扩散不同的伤害力不同的推力不同的伤害类型等,,,,,,这些属性一般对应的就是所谓的“武器管理”
UDK默的的开火模式:FireModeNum(0代表鼠标左键,1代表鼠标右键)
UDK开火类型:数组一一对应(比如说左键是0,所有下标为0的数组都代表左键开火)
enumEWeaponFireType
{
EWFT_InstantHit, //立即型(不需要生成射弹,类似于激光,一点就中。UTGame中的链枪)
EWFT_Projectile, //射弹型(生成射弹,射弹碰到目标后产生伤害。UTGame中的火箭弹和LinkenPlasma)
EWFT_Custom, //自定义类型
EWFT_None //没有类型
};
/** Current FireMode*/
var byteCurrentFireMode; //当前的开火模式
/** Array of firing states defining available firemodes */
var Array<Name> FiringStatesArray; //开火状态
/** Defines the type of fire (see Enum above) for each mode*/
var Array<EWeaponFireType> WeaponFireTypes; //开火类型
/** The Class of Projectile to spawn */
var Array< class<Projectile> > WeaponProjectiles; //射弹类型
/** Holds the amount of time a single shot takes */
var() Array<float> FireInterval; //开火频率(每秒发射多少子弹)
/** How much of a spread between shots */
var() Array<float> Spread; //子弹扩散(散弹)
/** How much damage does a given instanthit shot do */
var() Array<float> InstantHitDamage; //射弹即时伤害力
/** momentum transfer scaling for instant hit damage */
var() Array<float> InstantHitMomentum;//射弹即时推力(动能,惯性和作用物间的质量有关)
/** DamageTypes for Instant Hit Weapons */
var Array< class<DamageType> > InstantHitDamageTypes; //伤害类型(可能是持续伤害和瞬间伤害之类)
打出一个子弹,需要有枪口火焰,子弹生成的位置,子弹生成后朝哪个方向飞出,,,,,类似于这种行为的可以看成是武器,也就是武器库。执行这些逻辑的代码一般在Weapon类中完成。
武器开火
SPG_Weapon类中的ProjectileFire()函数
射弹生成的位置是获取Socket的Location,射弹生成的方向是Socket的方向或Pawn的朝向。Pawn的朝向是FaceRotaion()函数计算。当把武器附加到Pawn的Socket上的时候适当地调节武器的朝向和瞄准方向,函数是Weapon类中的GetAdjustedAim(),和一个动态瞄准GetAdjustedAimFor()。
(第一人称射击游戏,鼠标不停瞄准移动速度较快,动态朝向可以提高瞄准目标的精确度)
/**
* GetAdjustedAimbegins a chain of function class that allows the weapon, the pawn and thecontroller to make
* on the flyadjustments to where this weapon is pointing.
*/
simulatedfunction Rotator GetAdjustedAim(vectorStartFireLoc )
{
localrotator R;
//Start the chain, see Pawn.GetAdjustedAimFor()
if(Instigator !=None )
{
R =Instigator.GetAdjustedAimFor(Self,StartFireLoc );
}
returnAddSpread(R);
}
子弹从生成位置生成后,就按获得的朝向方向进入速度的初使化,这个过程就交给C++了,在US脚本中传入射弹朝向,初使化射弹就是开火的最后一个函数了:
// Initializethe projectile
SpawnedProjectile.Init(Vector(SpawnRotation));
射弹的生成由开火模式调用相应的射弹类型,
/**
* Returns theprojectile class based on the current fire mode
* @return Returns the class of the projectileindexed within the Projectiles array
* @network Server
*/
functionclass<Projectile> GetProjectileClass()
{
return(CurrentFireMode < Projectiles.length) ? Projectiles[CurrentFireMode] :None;
}
动态水面和材质
打开RealTime和FireFrame,水面是一个流体表面类和一个“水表面模拟器”,加上模拟水表面镜面反射的静态网格(采集反射贴图供水面材质使用)。
材质部分:无法过多地解释,有相当水平的人可以自行查看官方的资源包。
动态水面渲染为了减少程序的计算量,同时对渲染优化考虑,材质不使用光照,反射效果采集在一张贴图上。
材质节点比较多,但结构比较明显。下面控制UV横向竖向移动旋转处理出动态法线贴图作为水面的流水效果,这些计算方式都是二元运算的组合(有图形编程Shader概念或对三维材质渲染有一定功力的人相对容易理解)。有了动态的法线后根据一些Mask取出相应的图像通道加以处理用作自发光和透明。