PDA

View Full Version : Isometric camera and mouse cursor basic tutorial (closed)



roychr
11-24-2009, 04:57 PM
EDIT Friday 18th december 2009

This tutorial has been made irrelevant by the following thread, please follow it instead :

http://forums.epicgames.com/showthread.php?p=27043379#post27043379

-------------------------------------------------------------------------------------
Ok these are my first UDK tutorials, if they are not that good, please be kind :)

Some of the stuff included in these tutorial :

Default GameInfo
Isometric Camera based on ThirdPerson
Basic Controller
Basic Pawn
Basic Hud with mouse support


you can get the tutorials here :

Isometric Camera : http://x9productions.com/blog/?p=250

Mouse Cursor : http://x9productions.com/blog/?p=269

I also want to thanks Chris2009 for his excellent insights. I will post a Mouse click tutorial next to get the pawn moving with A.I. so people with RTS and RPG like me can start doing great games !

I know there is a post here (http://forums.epicgames.com/showthread.php?t=708724) that talks about Mouse and pawn moving from JeremyStieglitz

To Quote :

"The easiest way I know of (and perhaps the only way within the UDK) to show the mouse is to open a UI scene that has DisplayMouse set to true in its properties. You can open a UI scene through code, using "class'UIRoot'.static.GetSceneClient().OpenScene(. ...);"

... Or most easily through Kismet using the OpenScene action.

As for Diablo style movement, meaning moving towards the last place that the player clicked:

In the StartFire PlayerController event (i.e. when the player clicks the mouse button), you should calculate and store the location that your "Deprojected" Trace collided with:

Trace(TargetLocation,TraceHitNormal,MouseProjectio nOrigin + MouseProjectionDirection*50000,MouseProjectionOrig in,false);

You can probably use LocalPlayer(Player).DeProject() in your PlayerController to calculate the Deprojection values... however, the last time I tried using that version of the function, it did not give me correct results.

So if that LocalPlayer.DeProject() function doesn't work for you, then just store the last Deprojected WorldOrigin and WorldDirection in your HUD's PostRender() function (as I've indicated in my response above), and access those in the PlayerController (using its 'myHUD') to do the Trace.

Then, in the your PlayerController's PlayerMove function, calculate the "NewAccel" to be Normal(TargetLocation - Pawn.Location). There you should probably also set the Pawn's Desired Rotation (using SetDesiredRotation) to look towards that direction as well.

-Jer "

sueds
11-24-2009, 05:17 PM
nice ! thank you

Xero
11-24-2009, 06:14 PM
Yay! *dose imaginary backflips*
I actually found a way to get my thirdperson camera to work the way I want it just this morning. The problem is I have no idea why it's working the way it. lol I only understand about half the code I used. Maybe this tut will help my understanding.

Thanks roychr, you rock.

roychr
11-24-2009, 06:22 PM
Yay! *dose imaginary backflips*
I actually found a way to get my thirdperson camera to work the way I want it just this morning. The problem is I have no idea why it's working the way it. lol I only understand about half the code I used. Maybe this tut will help my understanding.

Thanks roychr, you rock.

Well try not to use calcCamera in Pawn Class if you did that, it got me confused alot and simply overrid the DefaultProperties of my thirdperson_default. So I asked for help here (http://forums.epicgames.com/showthread.php?p=26995772#post26995772) and it helped alot !

Brexer
11-24-2009, 07:47 PM
Thank you, excellent stuff and well written :)

Will look forward for mouse picking on terrain for movement (will it be with pathfinding to move around objects i wonder ?) :)

roychr
11-25-2009, 12:51 AM
I will try, give me some time to figure it out though :D

Chris2009
11-25-2009, 01:05 AM
Thanks for posting these tutorials, I hope it will stop people asking about these very things.

The problem I have been pondering is saving and loading. Since a there is no quick save in the udk. :eek:

roychr
11-25-2009, 02:16 AM
Thanks for posting these tutorials, I hope it will stop people asking about these very things.

The problem I have been pondering is saving and loading. Since a there is no quick save in the udk. :eek:

You should check into the UTDataStore_GameSettingsDM.uc, its logical to think that files are treated as datastore file. Maybe the config(Game) serves that purpose. For example it would be fitting to think that defaultproperties or other variables such as the console font be loaded from file or cfg. I saw the console font being loaded in the UTHud somewhere. I would also guess that serialization of variables would be native so its transparent to unrealscript.

LordsWarrior
11-25-2009, 03:40 AM
YES!!! Ran thru the mouse pointer tutorial and it worked. Thanks!! ANd the tutorial information was very good. It makes sence now :)

Note. The 3rd Person Camera didnt seem to look like yours even after cut'n'pasting into a clean mod , but I had my own script for this already so IM ok. Just letting you know maybe something is missing? Some one else can try too just in case Im wrong.

Question. I notice this doesnt require making a UIScene in the map to activate the mouse, wher other threads say its needed. What are your thoughts/preferences on this.

Thanks so much again....this stuff is really useful for learning to have a full example in one place!

-LW

TheSpaceMan
11-25-2009, 05:36 AM
A slight edit on the DeProject for the mouse when using a LocalPlayer instead of a Canvas. The Comments mark out that the DeProject in the Canvas is faster because lot of the data already exist, in the Local Player this data has to be created when you call the function.

Also Remember that (atleast for the Local Player DeProject) the Screen size is handled as 0.0<->1.0 in both axis, so you need to devide your mouse position with the width/height of the viewport in the releventa axis. A small optimization would be to calculate a Width and Height Delta that only get set on startup or viewport size change.

WidthDelta = 1.0f/ViewPortWidth;
HeightDeleta = 1.0f/ViewPortHeight;

When getting the 0.0f<->1.0f position you simply do mouseDelta = mousePosition.x * WidthDelta; And save a / calculation each time. This might sound silly, but once i heard that * is 12 times faster then / calculations. And if it's done alot you could save a bit.

R2D5
11-25-2009, 08:39 AM
Thank you this tutorials was exactly what i was looking for. Im looking forward to the mouse click tutorial. Could you maybe cover how to place a mesh(static mesh) at the coursor position? Maybe on Terrain? (Buildings)

roychr
11-25-2009, 12:14 PM
"Question. I notice this doesnt require making a UIScene in the map to activate the mouse, wher other threads say its needed. What are your thoughts/preferences on this."

From my experience, mouse handling functions for movement go traditionally inside the HUD when you can, because its there you will create user feedback and pop-ups. If you check the UTHud, you will understand the principles behind what I say, and after this tutorial you will easily find how to instantiate a Material or other nice visual. Now I have not delved yet into Kismet and I save it for game play so UIScene will be called only for menus. Again I am starting to get a full grasp of the SDK, I maybe wrong in certain deductions.

TheSpaceMan : That seems to be good information, but I do not understand the context of your deproject statement, although I would like to know more about it. As for * being faster, its because additions (+) are really fast on processors and * is a series of + from my limited knowledge of assembly.

roychr
11-26-2009, 12:09 AM
Here is something to chew on until I finish off this tutorial on automated movement. Right now I am figuring out states for controllers. I might have to check AiController also to look at navigation with built-in path nodes.

Have a look here for some movement and constuction of a simple moving fish : http://udn.epicgames.com/Three/MasteringUnrealScriptFunctions.html;)

Draganos
11-26-2009, 05:56 AM
Hey

I just read your tutorial for the isometric camera and tried to use it in my game.
There's just one problem:
The camera seems to be located IN the pawn. So how do I set another location for the camera? I looked through the PlayerController class but couldn't find a solution.

Here are screenshots so you see exactly what I mean:
What it looks like after doing the tutorial:
http://img5.imagebanana.com/view/fgor6ru/BrightTune_NewCam.JPG
What it looked like before I did the new camera:
http://img5.imagebanana.com/view/5zmmkoz/BrightTune1.JPG

(I changed the camera because I think your way to do it is better than mine.)

Thanks for your help.

roychr
11-26-2009, 10:47 AM
Be sure to override in your controller :


function UpdateRotation( float DeltaTime )
{
local Rotator ViewRotation;

ViewRotation.Pitch = (-45.0f * DegToRad) * RadToUnrRot;
ViewRotation.Yaw = (-45.0f * DegToRad) * RadToUnrRot;

SetRotation(ViewRotation);
}

Inside the default state of the controller (take a look at PlayerWalking::PlayerMove, UpdateRotation of controller is called.

Now in the tutorial we extended the GamePlayerCamera and specified it in the default properties of the controller.

if you take a look at the playercontroller.uc, you will rapidly locate the camera variables :


class PlayerController extends Controller
config(Game)
native(Controller)
nativereplication
dependson(OnlineSubsystem,OnlineGameSearch,SeqAct_ ControlMovieTexture);

var const Player Player; // Player info
var(Camera) editinline Camera PlayerCamera; // Camera associated with this Player Controller
var const class<Camera> CameraClass; // Camera class to use for the PlayerCamera

Now the actual spawning of the camera occurs in this obvious function which is part of the PlayerController :

event SpawnPlayerCamera()
{
if( CameraClass != None && IsLocalPlayerController() )
{
// Associate Camera with PlayerController
PlayerCamera = Spawn( CameraClass, self );
if( PlayerCamera != None )
{
PlayerCamera.InitializeFor( self );
}
else
{
`Log( "Couldn't Spawn Camera Actor for Player!!" );
}
}
else
{
// not having a CameraClass is fine. Another class will handing the "camera" type duties
// usually PlayerController
}
}

Hope it answered your questions

CrazyIwan
11-26-2009, 06:00 PM
Hi roychr,

i will thank you for your great tutorial.
I've wrote all classes and scripts and it works so far. But, if i use UTPawn, the Camera stack in Player. Its isometric, but not third person view, so i cant see the model just only a part from the floor. I think something like Draganos already wrote. I've tried to understand your last posting, but i dont really understand how it can helps to repair the camera.

So, sorry for my bad english and my noobish question :)

roychr
11-26-2009, 06:47 PM
you cannot extend UTPawn for you pawn, It did not work for me using this setup. Extend Pawn simply, you are not doing a FPS anyways with this kind of camera.

CrazyIwan
11-26-2009, 06:57 PM
Ah ok thanks! I will try it and build my own Pawn.

Hmm, its any simple way to build Pawn with UT Model? I do understand the script so far, but i dont know which defaultproperties do i need.

roychr
11-27-2009, 12:26 PM
Ah ok thanks! I will try it and build my own Pawn.

Hmm, its any simple way to build Pawn with UT Model? I do understand the script so far, but i dont know which defaultproperties do i need.


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_C H_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);
}

that will put the corrupt model with basic animation and an environment light to be sure to see it always.

CrazyIwan
11-28-2009, 05:29 PM
thank you very much, it works perfect :)

roychr
11-29-2009, 11:52 AM
Update : I am having some headache over making the pawn use the builtin navigation system of UTBot like functions. I do not know if somebody has any resources on UDN to point to to help me into making the pawn move intelligently toward a hit point but it could be really appreciated for the next tutorial. On a followup to save/load thread. If anybody is searching on how to load/save rpg like data, its on UDN now : http://udn.epicgames.com/Three/ConfigSavegameSystem.html

rahatropa
11-30-2009, 01:05 AM
Glad to see the savegame tut made it online, I'll be giving this a look when I finish setting up point-n-click. Not sure if I hadn't mentioned it yet but great tutorial I found it very useful. How is the progress coming on player movement, I will be working all night trying to come up with a solution and if I find any useful info I'll make sure to share an update here.

rahatropa
11-30-2009, 02:10 AM
Regarding the trace, I believe I have it working somewhat right.. currently testing by logging TargetLocation and comparing it with static meshes world position info provided in properties..

anyway, the function..

exec function NexLeftClick()
{
local Vector TargetLocation, TraceHitNormal, TraceStart, TraceEnd;
local Actor a;

TraceStart = WorldOrigin;
TraceEnd = WorldOrigin+WorldDirection*5000;
a = Trace(TargetLocation, TraceHitNormal, TraceEnd, TraceStart, false);

`log("Mouse has been clicked");
`log("Trace hit" @ TargetLocation);

}

Result: it appears to be working with TargetLocation outputting x,y's relatively close to the meshes worldpositions, making me believe the actual trace code is correct. The z value outputs a steady value when I click on the ground, as it should, only when I click on a mesh that has height does the value change.

roychr
11-30-2009, 10:43 AM
These are the new functions I added to GameController. Now the Result is that the player moves but there is a spring effect :



//Add this on top
var Vector2D MousePosition;
var Vector WorldOrigin;
var Vector WorldDirection;

var Vector MouseClickWorldLocation;
var Vector MouseClickWorldNormal;

exec function StartFire(optional byte FireModeNum)
{
Trace(MouseClickWorldLocation, MouseClickWorldNormal, WorldOrigin + (WorldDirection * 10000), WorldOrigin, false);
`Log("If have fired the mouse click to" @ MouseClickWorldLocation);
GotoState('PlayerAutonomousWalking');
}

// Player movement.
// Player Standing, walking, running, falling.
state PlayerAutonomousWalking
{
ignores SeePlayer, HearNoise, Bump;

/*
event NotifyPhysicsVolumeChange( PhysicsVolume NewVolume )
{
if ( NewVolume.bWaterVolume && Pawn.bCollideWorld )
{
GotoState(Pawn.WaterMovementState);
}
}*/

function ProcessMove(float DeltaTime, vector NewAccel, eDoubleClickDir DoubleClickMove, rotator DeltaRot)
{
if( Pawn == None )
{
return;
}

if (Role == ROLE_Authority)
{
// Update ViewPitch for remote clients
Pawn.SetRemoteViewPitch( Rotation.Pitch );
}

Pawn.Acceleration = NewAccel;

CheckJumpOrDuck();
}

function PlayerMove( float DeltaTime )
{
local vector NewAccel;
local eDoubleClickDir DoubleClickMove;
local rotator OldRotation;
local bool bSaveJump;
local Vector NewDirection;

if( Pawn == None )
{
GotoState('Dead');
}
else
{

//GetAxes(Pawn.Rotation,X,Y,Z);

// Update acceleration.
//NewAccel = PlayerInput.aForward*X + PlayerInput.aStrafe*Y;
//NewAccel.Z = 0;
//NewAccel = Pawn.AccelRate * Normal(NewAccel);
MouseClickWorldLocation.Z = 0;
NewDirection = MouseClickWorldLocation - Pawn.Location;
if(VSize(NewDirection) < 5.0f)
{
MouseClickWorldLocation = Pawn.Location;
}
NewAccel = Pawn.AccelRate * Normal(NewDirection);
//Pawn.SetDesiredRotation(Rotator(NewDirection), false, false, DeltaTime);

//DoubleClickMove = PlayerInput.CheckForDoubleClickMove( DeltaTime/WorldInfo.TimeDilation );

// Update rotation.
OldRotation = Rotation;

//Here is the call to our Isometric camera fix inside our controller :)
UpdateRotation( DeltaTime );

bDoubleJump = false;
bSaveJump = false;

if( Role < ROLE_Authority ) // then save this move and replicate it
{
ReplicateMove(DeltaTime, NewAccel, DoubleClickMove, OldRotation - Rotation);
}
else
{
ProcessMove(DeltaTime, NewAccel, DoubleClickMove, OldRotation - Rotation);
}
//bPressedJump = bSaveJump;
}
}

event BeginState(Name PreviousStateName)
{
DoubleClickDir = DCLICK_None;
bPressedJump = false;
GroundPitch = 0;
if ( Pawn != None )
{
Pawn.ShouldCrouch(false);
if (Pawn.Physics != PHYS_Falling && Pawn.Physics != PHYS_RigidBody) // FIXME HACK!!!
Pawn.SetPhysics(PHYS_Walking);
}
}

event EndState(Name NextStateName)
{
GroundPitch = 0;
if ( Pawn != None )
{
Pawn.SetRemoteViewPitch( 0 );
if ( bDuck == 0 )
{
Pawn.ShouldCrouch(false);
}
}
}

Begin:
}

And then in the Hud change the PostRender to this to get the variables into the controller :



//Canvas is only valid during PostRender phase
event PostRender()
{
local MyPlayerController MyPController;

MousePosition = GetMouseCoordinates();
Canvas.DeProject(MousePosition, WorldOrigin, WorldDirection);

//TODO: Send our calculated mouse projection to the controller(At some point you will need to optimize this)
MyPController = MyPlayerController(PlayerOwner);
MyPController.MousePosition = MousePosition;
MyPController.WorldOrigin = WorldOrigin;
MyPController.WorldDirection = WorldDirection;

//now you have the world origin and direction vector of the mouse deprojection
//so you can do with it whatever you'd like, such as do a Trace with it to see what the mouse is pointing at
DrawHUD();
}

3dxero
12-02-2009, 05:49 PM
Working on this myself.
The value 5.0f seems to be too low to stop him from running.
I'm using 98.0f now and it seems to be ok.
Needs more testing, especially around inclines?



function PlayerMove( float DeltaTime )
{
local vector NewAccel;
local eDoubleClickDir DoubleClickMove;
local rotator OldRotation;
//local bool bSaveJump;
local Vector NewDirection;
local Vector MyPawnLocation;

DoubleClickMove = DCLICK_None;
if( Pawn == None )
{
GotoState('Dead');
}
else
{

//GetAxes(Pawn.Rotation,X,Y,Z);
// Update acceleration.
//NewAccel = PlayerInput.aForward*X + PlayerInput.aStrafe*Y;
//NewAccel.Z = 0;
//NewAccel = Pawn.AccelRate * Normal(NewAccel);

MouseClickWorldLocation.Z = 0;
MyPawnLocation = Pawn.Location;
MyPawnLocation.Z = 0;
NewDirection = MouseClickWorldLocation - MyPawnLocation;
if(VSize(NewDirection) < 98.0f)
{
//`Log("Setting new accel to 0");
MouseClickWorldLocation = Pawn.Location;
NewAccel = Normal(Pawn.Location - Pawn.Location);
}
else
{
//NewDirection.Z =0;
//`Log("Vsize is " @ VSize(NewDirection));
NewAccel = Pawn.AccelRate * Normal(NewDirection);
}


//Pawn.SetDesiredRotation(Rotator(NewDirection), false, false, DeltaTime);
//DoubleClickMove = PlayerInput.CheckForDoubleClickMove( DeltaTime/WorldInfo.TimeDilation );
// Update rotation.
OldRotation = Rotation;
//Here is the call to our Isometric camera fix inside our controller :)
UpdateRotation( DeltaTime );
bDoubleJump = false;
//bSaveJump = false;
if( Role < ROLE_Authority ) // then save this move and replicate it
{
ReplicateMove(DeltaTime, NewAccel, DoubleClickMove, OldRotation - Rotation);
}
else
{
ProcessMove(DeltaTime, NewAccel, DoubleClickMove, OldRotation - Rotation);
}
//bPressedJump = bSaveJump;
}
}

3dxero
12-02-2009, 07:54 PM
I Like this even better:



MouseClickWorldLocation.Z = 0;
MyPawnLocation = Pawn.Location;
MyPawnLocation.Z = 0;
NewDirection = MouseClickWorldLocation - MyPawnLocation;
MyX = (MouseClickWorldLocation.X - MyPawnLocation.X);
MyY = (MouseClickWorldLocation.Y - MyPawnLocation.Y);
MyDistance = sqrt((MyX*MyX) + (MyY*MyY));

//`Log("Distance is " @ MyDistance);

//if(VSize(NewDirection) < 98.0f)
if(MyDistance < 1)
{
//`Log("Setting new accel to 0");
MouseClickWorldLocation = Pawn.Location;
NewAccel = Normal(Pawn.Location - Pawn.Location);
}
else
{
//NewDirection.Z =0;
//`Log("Vsize is " @ VSize(NewDirection));
NewAccel = Pawn.AccelRate * Normal(NewDirection);
}

roychr
12-03-2009, 01:32 PM
I wonder if VSize is exactly the same as your manual distance calculation. In Unity there was a function for calculating distance. I wonder if there is a native version or VSize is supposed to work... I Heard a bunch of tutorial on pathFinding was supposed to come out on UDN today, you can find them here (http://forums.epicgames.com/showthread.php?t=710419)

3dxero
12-04-2009, 01:46 PM
Well, I assume Vsize does X Y and Z, and I only wanted X and Y. Spewing out the return of vsize was around 100 even when on the spot, my calcs return actual units. It gets pretty close to 0 at the spot you clicked. Hope this helps.

rahatropa
12-04-2009, 07:25 PM
I just got my internet back so I haven't had much time to mess with UDK. If I recall I believe in unity one could do a simple Vector3.Distance(transform.pos, movePos) as roy mentioned, anyway ill try both methods, thanks a lot for sharing!

roychr
12-06-2009, 10:46 PM
Just want to let you know I have been a little busy last week and did not make any head ways for the navigation bots. I will put my energies toward that goal this week.

Label
12-08-2009, 12:16 AM
Awesome tutorials, I have picked up quite a bit thanks. :)

A quick question, is there a way we are able to shoot at the position which has been picked with the mouse also?

I know there is the function Rotator GetAdjustedAimFor( Weapon W, vector StartFireLoc )
which I currently use to shoot where the player is looking in 3rd person, but is there a way to make it so the player shoots where he clicks..? (hoping that makes sense it's 5am here ;_;, this may also seem useless to some people but I think it would be good for an RTS etc)

Looter222
12-08-2009, 01:29 PM
Very useful tutorials, thanks!

It would be very cool if you could make one about relating where the person clicks to a vector/trace into the game world.

roychr
12-11-2009, 02:45 PM
Just want to update this thread. I got some help in this thread (http://forums.epicgames.com/showthread.php?p=27028546#post27028546) for understanding the path finding. I sugget you read it if it is something of interest to learn for you.

Corrections to the two tutorials on the camera and mouse cursor are on the way as well as a tutorial on pathfinding with indepth explanations.

Keep up the fight :)

rahatropa
12-11-2009, 09:06 PM
That's the spirit :P The UDK community needs more members such as yourself. As for me, I've begun multi-tasking on my project, creating new assets, as my last encounter with unrealscript was giving me unexpected results, and we know how frustrating that can be :P

My problem involves getting my pawn to rotate to the MouseClickLocation. SetDesiredRotation, SetRotation, and other similar functions were not providing me with expected results. My PlayerMove function, like yours, is also a close copy of the already scripted PlayerMove function by Epic. My finals are this week so I don't expect having much free time to try and solve this small issue, but when I do get the time I plan to look into the code that is executed when a Bot see's Player as this involves the Bot rotating towards the player.

LordAero
12-13-2009, 07:44 PM
I suppose is never late to say Thanks :) nice web BTW, useful links too

roychr
12-13-2009, 09:00 PM
Thanks for the encouragements I posted a video of my progress here for the mouse clicks and pathfinding. In a couple of days there should be a corrections of the tutorials with available source code zipped as well as french version of the tutorials.

You can see it here :

english (http://x9productions.com/blog/?p=348)
french (http://x9productions.com/blog/?p=342)

Of note is that I am almost at the end of assasin's creed 2 source of great distraction for my projects :D

modproductions
03-13-2010, 09:44 AM
I just worked through this and wanted to thank you. Nice work and very very helpful!