So I've looked into this problem a bit more, and everywhere it says that just like location, rotation should update automatically without having to do anything. Because my location does update properly automatically, and it seems as if the rotation should too. Which leads me to believe I'm doing something wrong in my scripts. I'm going to include my PlayerController and Pawn classes, if you can notice for any reason why I would not be doing something correctly please let me know. I've followed several tutorials and kinda created a ad-hoc implementation which is probably why its not working.
ThePlayerController.uc
Code:
class ThePlayerController extends UTPlayerController;
//Camera variables
var ControlModule ControlModule; //Player control module to use
var config string DefaultControlModuleClass; //Default class for player control module
var Vector MouseHitWorldLocation; //Hold where the ray casted from the mouse in 3d coordinate intersect with world geometry. We will use this information for our movement target when not in pathfinding.
var Vector MouseHitWorldNormal; //Hold the normalized vector of world location to get direction to MouseHitWorldLocation (calculated in HUD, not used)
var Vector MousePosWorldLocation; //Hold deprojected mouse location in 3d world coordinates. (calculated in HUD, not used)
var Vector MousePosWorldNormal; //Hold deprojected mouse location normal. (calculated in HUD, used for camera ray from above)
/**
* Calculated in Hud after mouse deprojection, uses MousePosWorldNormal as direction vector
* This is what calculated MouseHitWorldLocation and MouseHitWorldNormal.
*
* See Hud.PostRender, Mouse deprojection needs Canvas variable.
*/
var vector StartTrace; //Hold calculated start of ray from camera
var Vector EndTrace; //Hold calculated end of ray from camera to ground
var vector RayDir; //Hold the direction for the ray query.
var Vector PawnEyeLocation; //Hold location of pawn eye for rays that query if an obstacle exist to destination to pathfind.
var Actor TraceActor; //If an actor is found under mouse cursor when mouse moves, its going to end up here
//Members for the custom mesh
var SkeletalMesh defaultMesh;
var MaterialInterface defaultMaterial0;
var AnimTree defaultAnimTree;
var array<AnimSet> defaultAnimSet;
var AnimNodeSequence defaultAnimSeq;
var PhysicsAsset defaultPhysicsAsset;
simulated function PostBeginPlay()
{
local class<ControlModule> ControlClass;
local ControlModule NewControlModule;
Super.PostBeginPlay();
SetBehindView(true);
ControlClass = class<ControlModule>(DynamicLoadObject(DefaultControlModuleClass, class'Class'));
if(ControlClass != none) {
//Associate module with PlayerController
NewControlModule = new(Outer) ControlClass;
NewControlModule.Controller = self;
NewControlModule.Init();
//Call active/inactive functions on new/old modules
if(ControlModule != none) {
ControlModule.OnBecomeInactive(NewControlModule);
NewControlModule.OnBecomeActive(ControlModule);
} else {
NewControlModule.OnBecomeActive(None);
}
ControlModule = NewControlModule;
} else {
`log("Couldn't get control module class!");
//Not having a Control Class is fine. PlayerController will use default controls.
}
resetMesh();
}
//Sets the Pawns Mesh to the resources speced in the DefaultProperties
public function resetMesh(){
self.Pawn.Mesh.SetSkeletalMesh(defaultMesh);
self.Pawn.Mesh.SetMaterial(0,defaultMaterial0);
self.Pawn.Mesh.SetPhysicsAsset(defaultPhysicsAsset );
self.Pawn.Mesh.AnimSets = defaultAnimSet;
self.Pawn.Mesh.SetAnimTreeTemplate(defaultAnimTree );
}
//Exec function for switching to a different camera by class
exec function ChangeControls( string ClassName )
{
local class<ControlModule> ControlClass;
local ControlModule NewControlModule;
ControlClass = class<ControlModule>(DynamicLoadObject(DefaultControlModuleClass, class'Class'));
if(ControlClass != none) {
//Associate module with PlayerController
NewControlModule = new(Outer) ControlClass;
NewControlModule.Controller = self;
NewControlModule.Init();
//Call active/inactive functions on new/old modules
if(ControlModule != none) {
ControlModule.OnBecomeInactive(NewControlModule);
NewControlModule.OnBecomeActive(ControlModule);
} else {
NewControlModule.OnBecomeActive(None);
}
ControlModule = NewControlModule;
} else {
`log("Couldn't get control module class!");
//Not having a Control Class is fine. PlayerController will use default controls.
}
}
//Exec function for switching to a different camera by class
exec function ChangeCamera( string ClassName )
{
local class<CameraModule> NewClass;
NewClass = class<CameraModule>(DynamicLoadObject(ClassName, class'Class'));
if(NewClass != none && ThePlayerCamera(PlayerCamera) != none) {
ThePlayerCamera(PlayerCamera).CreateCamera(NewClass);
}
}
event PlayerTick( float DeltaTime )
{
local Vector PawnXYLocation;
local Rotator NewRotation;
super.PlayerTick(DeltaTime);
PawnXYLocation.X = Pawn.Location.X;
PawnXYLocation.Y = Pawn.Location.Y;
NewRotation = Rotator(MouseHitWorldLocation - PawnXYLocation);
NewRotation.Pitch = 0;
Pawn.SetRotation(NewRotation);
}
//This is overridden to ensure that we use the CONTROLLER's rotation for references to movement
//This makes our "move forward" always use the same forward, no matter what rotation our pawn is facing. It is otherwise identical to the original
state PlayerWalking
{
function PlayerMove( float DeltaTime )
{
local vector X,Y,Z, NewAccel;
local eDoubleClickDir DoubleClickMove;
local rotator OldRotation;
local bool bSaveJump;
if(Pawn == None) {
GotoState('Dead');
} else {
GetAxes(Rotation,X,Y,Z);
//Update acceleration.
NewAccel = PlayerInput.aForward * X + PlayerInput.aStrafe * Y;
NewAccel.Z = 0;
NewAccel = Pawn.AccelRate * Normal(NewAccel);
DoubleClickMove = PlayerInput.CheckForDoubleClickMove(DeltaTime / WorldInfo.TimeDilation);
//Update rotation.
OldRotation = Rotation;
UpdateRotation( DeltaTime );
Pawn.SetRotation(oldRotation - Rotation);
bDoubleJump = false;
if(bPressedJump && Pawn.CannotJumpNow()) {
bSaveJump = true;
bPressedJump = false;
} else {
bSaveJump = false;
}
//Then save this move and replicate it
if(Role < ROLE_Authority) {
ReplicateMove(DeltaTime, NewAccel, DoubleClickMove, OldRotation - Rotation);
} else {
ProcessMove(DeltaTime, NewAccel, DoubleClickMove, OldRotation - Rotation);
}
bPressedJump = bSaveJump;
}
}
}
/**
* Returns Player's Point of View
* For the AI this means the Pawn's 'Eyes' ViewPoint
* For a Human player, this means the Camera's ViewPoint
*
* @output out_Location, view location of player
* @output out_rotation, view rotation of player
*/
simulated event GetPlayerViewPoint( out vector out_Location, out Rotator out_Rotation )
{
local Actor TheViewTarget;
//Sometimes the PlayerCamera can be none and we probably do not want this
//so we will check to see if we have a CameraClass. Having a CameraClass is
//saying: we want a camera so make certain one exists by spawning one
if(PlayerCamera == None) {
if(CameraClass != None) {
//Associate Camera with PlayerController
PlayerCamera = Spawn(CameraClass, Self);
if(PlayerCamera != None) {
PlayerCamera.InitializeFor( Self );
} else {
`log("Couldn't Spawn Camera Actor for Player!!");
}
}
TheViewTarget = GetViewTarget();
if(TheViewTarget != None) {
out_Location = Location;
out_Rotation = Rotation;
} else {
out_Location = Location;
out_Rotation = Rotation;
}
} else {
PlayerCamera.GetCameraViewPoint(out_Location, out_Rotation);
}
}
//CheckJumpOrDuck() - Called by ProcessMove() - Handles jump and duck buttons which are pressed
//Overriden to do nothing and be a good boy
function CheckJumpOrDuck() {}
//Override to do nothing and be a good boy
function ProcessViewRotation( float DeltaTime, out Rotator out_ViewRotation, Rotator DeltaRot );
defaultproperties
{
defaultMesh = SkeletalMesh'OF-ShipModels.raptor'
CameraClass = class'OmegaFrontier.ThePlayerCamera'
InputClass = class'OmegaFrontier.MyMouseInterfacePlayerInput'
}
PlayerPawn.uc
Code:
class PlayerPawn extends UTPawn;
var bool bCanDodge;
//Weapon effects use the Pawn's GetViewRotation(), so we always use the Pawn's rotation instead of the Controller's
simulated event rotator GetViewRotation()
{
return Rotation;
}
//BecomeViewTarget - Called by Camera when this actor becomes its ViewTarget
simulated event BecomeViewTarget( PlayerController PC )
{
local PlayerController ThePC;
Super.BecomeViewTarget(PC);
ThePC = ThePlayerController(PC);
//Pawn is controlled by a UMPlayerController and has a ThePlayerCamera
if(ThePC != none && ThePlayerCamera(ThePC.PlayerCamera) != none) {
//Allow custom camera to control mesh visibility, etc.
ThePlayerCamera(ThePC.PlayerCamera).BecomeViewTarget(ThePC);
}
}
/**
* Calculate camera view point, when viewing this pawn.
*
* @param fDeltaTime delta time seconds since last update
* @param out_CamLoc Camera Location
* @param out_CamRot Camera Rotation
* @param out_FOV Field of View
*
* @return true if Pawn should provide the camera point of view.
*/
simulated function bool CalcCamera( float fDeltaTime, out vector out_CamLoc, out rotator out_CamRot, out float out_FOV )
{
return false;
}
/**
* Returns base Aim Rotation without any adjustment (no aim error, no autolock, no adhesion.. just clean initial aim rotation!)
*
* Called by weapon prior to firing
* @return base Aim rotation.
*/
simulated singular event Rotator GetBaseAimRotation()
{
local vector POVLoc;
local rotator POVRot;
local ThePlayerController PC;
PC = ThePlayerController(Controller);
//Pawn is controlled by a UMPlayerController and has a ThePlayerCamera
if(PC != none && PC.ControlModule != none) {
//Allow custom camera to control aim rotation, but not if we're zoomed out
return PC.ControlModule.GetBaseAimRotation();
} else {
//If ThePlayerController exists and ThePlayerCamera is top down then
if( Controller != None && !InFreeCam() ) {
//Use the camera to get the players view
Controller.GetPlayerViewPoint(POVLoc, POVRot);
return POVRot;
//Otherwise just set the Pawn rotation
} else {
POVRot = Rotation;
POVRot.Pitch = 0;
return POVRot;
}
}
}
function AddDefaultInventory()
{
InvManager.CreateInventory(class'OmegaFrontier.OmegaGun'); //InvManager is the pawn's InventoryManager
}
//Overriden so the player cannot dodge roll
function bool Dodge(eDoubleClickDir DoubleClickMove)
{
if(bCanDodge) {
return Super.Dodge(DoubleClickMove);
} else {
return false;
}
}
//Overriden so the player cannot fake death
exec simulated function FeignDeath();
defaultproperties
{
InventoryManagerClass = class'OmegaFrontier.OmegaInventoryManager'
bCanDodge = false
bCanCrouch = false
bCanClimbLadders = false
bCanPickupInventory = false
bCanDoubleJump = false
bCanSwim = false
MaxMultiJump = 0
MultiJumpRemaining = 0
bArmsAttached = false
bPostRenderOtherTeam = true
bPostRenderIfNotVisible = true
bPhysRigidBodyOutOfWorldCheck = true
bRunPhysicsWithNoController = true
Begin Object Name=WPawnSkeletalMeshComponent
bUpdateSkelWhenNotRendered = true
bIgnoreControllersWhenNotRendered = false
bTickAnimNodesWhenNotRendered = true
bUpdateKinematicBonesFromAnimation = true
AlwaysLoadOnClient = true
AlwaysLoadOnServer = true
HiddenGame = false
HiddenEditor = false
SkeletalMesh = SkeletalMesh'OF-ShipModels.raptor'
End Object
Mesh = WPawnSkeletalMeshComponent
Components.Add(WPawnSkeletalMeshComponent)
}
In ThePlayerController.uc it seems as if when DuplicateMove is called, it should be updating the location and rotation should it not? I do have a lot of things going on in these classes and they are probably inefficient so if someone has the time to look at this and help me with what I'm doing wrong I'd really appreciate it. Thanks again in advance I apologize for the continuing annoyance of this problem.
Bookmarks