View Full Version : Getting player's position from a custom Kismet event?!
Can somebody please get this straight once and for all?
How do you get the player's (actor) pawn's position in the current level from a custom Kismet event?!
I have tried using:
PlayerLocation = LocalPlayer.Location;
and:
PlayerLocation = LocalPlayer.WorldInfo.GetALocalPlayerController(). Location;
where PlayerLocation is a Vector and LocalPlayer is an Actor that has been initialized with:
VariableLinks.Add((ExpectedType=class'Engine.SeqVa r_Object',LinkDesc="Player",PropertyName=LocalPlayer,MaxVars=1))
Both of these seem to return the exact same coordinates regardless of where I am in the level. So.... how do I get the player's coordinates?!
Wizzard~Of~Ozz
05-15-2010, 11:08 AM
LocalPlayer.Actor.Pawn.Location ?
LocalPlayer already is an Actor, and it doesn't seem to have a Pawn member... o_O
Edit: Oh yeah, and I checked - Seqvar_Object doesn't have an Actor member
Wizzard~Of~Ozz
05-15-2010, 11:23 AM
LocalPlayer extends Player, Player has a variable called Actor which is the Playercontroller.
// The actor this player controls.
var transient const playercontroller Actor;
PlayerController has a variable through superclass called Pawn.
/** Pawn currently being controlled by this controller. Use Pawn.Possess() to take control of a pawn */
var repnotify Pawn Pawn;
Gotta love some ambiguity in variable names.
I assumed if you were already calling LocalPlayer it was available.
Hmm.
I declared LocalPlayer to be an instance of the Player class.
Now I got the Actor and Actor.Pawn members. :)
The problem now is that the coordinates returned are 0,0 and 0.
And Player.Actor.WorldInfo.Title returns squat.
This... kind of makes sense, I think.
I am calling the event when I'm pressing a button in a custom MidGameMenu. I think this is a UIScene and thus it has no notion of the player's position in the actual game-level.
So... erm.... yeah.
Any ideas? :(
Wizzard~Of~Ozz
05-15-2010, 11:57 AM
If you create an instance, it will be @ 0,0,0. You need to get the instance.
Why not use GetLocationAndRotation Action already in Kismet?
Begin Object Class=SeqEvent_PlayerSpawned Name=SeqEvent_PlayerSpawned_0
MaxWidth=201
OutputLinks(0)=(DrawY=674)
VariableLinks(0)=(LinkedVariables=(SeqVar_Player'S eqVar_Player_0'),DrawX=110)
VariableLinks(1)=(DrawX=202)
ObjInstanceVersion=1
ParentSequence=Sequence'Main_Sequence'
ObjPosX=48
ObjPosY=608
DrawWidth=123
DrawHeight=123
Name="SeqEvent_PlayerSpawned_0"
ObjectArchetype=SeqEvent_PlayerSpawned'Engine.Defa ult__SeqEvent_PlayerSpawned'
End Object
Begin Object Class=SeqVar_Player Name=SeqVar_Player_0
ObjInstanceVersion=1
ParentSequence=Sequence'Main_Sequence'
ObjPosX=312
ObjPosY=888
DrawWidth=32
DrawHeight=32
Name="SeqVar_Player_0"
ObjectArchetype=SeqVar_Player'Engine.Default__SeqV ar_Player'
End Object
Begin Object Class=SeqAct_GetLocationAndRotation Name=SeqAct_GetLocationAndRotation_0
InputLinks(0)=(DrawY=634)
OutputLinks(0)=(DrawY=634)
VariableLinks(0)=(LinkedVariables=(SeqVar_Player'S eqVar_Player_0'),DrawX=781)
VariableLinks(1)=(DrawX=864)
VariableLinks(2)=(DrawX=956)
ObjInstanceVersion=2
ParentSequence=Sequence'Main_Sequence'
ObjPosX=736
ObjPosY=600
DrawWidth=274
DrawHeight=80
Name="SeqAct_GetLocationAndRotation_0"
ObjectArchetype=SeqAct_GetLocationAndRotation'Engi ne.Default__SeqAct_GetLocationAndRotation'
End Object
I didn't create an instance?
I just changed it's type...
var() Player LocalPlayer;
and then in defaultproperties:
defaultproperties
{
ObjName="SaveEvent"
ObjCategory="Misc"
InputLinks.Empty
InputLinks.Add((LinkDesc="Activate"))
VariableLinks.Empty
VariableLinks.Add((ExpectedType=class'Engine.SeqVa r_Object',LinkDesc="Player",PropertyName=LocalPlayer,MaxVars=1))
}
Wizzard~Of~Ozz
05-15-2010, 12:51 PM
Well, aside from reinventing the wheel, I wrote this up which does work as a standalone.
class MySeqAct_GetLocation extends SequenceAction;
/** The location of the actor */
var() editconst Vector Location;
var Object Target;
function Activated()
{
if( Pawn( Target ) != None )
Location = Pawn( Target ).Location;
else if ( Controller ( Target ) != None )
Location = Controller( Target ).Pawn.Location;
}
defaultproperties
{
ObjName="Get Player Location"
ObjCategory="Custom"
ObjColor=(R=255,G=0,B=255,A=255)
VariableLinks(0)=(ExpectedType=class'SeqVar_Object ',LinkDesc="Target Player",PropertyName=Target)
VariableLinks(1)=(ExpectedType=class'SeqVar_Vector ',LinkDesc="Location",PropertyName=Location, bWriteable=true)
}
Wow!
Thank you so much! :)
Here's the final code I ended up with (feel free to copypasta from this anyone):
class LarryLoadEvent extends SequenceEvent DLLBind(Sex);
struct Save
{
//var string LevelName;
var float X, Y, Z;
};
var() Object LocalPlayer;
var() Vector PlayerLocation;
var() string SaveFile;
var() Save ReturnedSave;
dllimport final function Save LoadGame(string LoadPath);
dllimport final function string LoadDiag();
event Activated()
{
SaveFile = LoadDiag();
ReturnedSave = LoadGame(SaveFile);
//`log(ReturnedSave.LevelName);
`log(ReturnedSave.X);
`log(ReturnedSave.Y);
`log(ReturnedSave.Z);
PlayerLocation.X = ReturnedSave.X;
PlayerLocation.Y = ReturnedSave.Y;
PlayerLocation.Z = ReturnedSave.Z;
if(Pawn(LocalPlayer) != none)
Pawn(LocalPlayer).SetLocation(PlayerLocation);
else if(Controller(LocalPlayer) != none)
Controller(LocalPlayer).Pawn.SetLocation(PlayerLoc ation);
`log("Event activated!");
}
event bool IsValidUISequenceObject(optional UIScreenObject TargetObject)
{
return true;
}
defaultproperties
{
ObjName="LoadEvent"
ObjCategory="Misc"
InputLinks.Empty
InputLinks.Add((LinkDesc="Activate"))
VariableLinks.Empty
VariableLinks.Add((ExpectedType=class'Engine.SeqVa r_Object',LinkDesc="Player",PropertyName=LocalPlayer,MaxVars=1))
}
class LarrySaveEvent extends SequenceEvent DLLBind(Sex) dependson(LarryPlayerController);
var Object LocalPlayer;
var() Vector PlayerLocation;
var() string SaveFile;
dllimport final function bool SaveGame(string LevelName, float X, float Y, float Z, string SavePath);
dllimport final function string SaveDiag();
event Activated()
{
local string LevelName;
if(Pawn(LocalPlayer) != none)
{
PlayerLocation = Pawn(LocalPlayer).Location;
LevelName = Pawn(LocalPlayer).WorldInfo.Title;
}
else if(Controller(LocalPlayer) != none)
{
PlayerLocation = Controller(LocalPlayer).Pawn.Location;
LevelName = Controller(LocalPlayer).Pawn.WorldInfo.Title;
}
SaveFile = SaveDiag();
`log(SaveFile);
SaveGame(LevelName, PlayerLocation.X, PlayerLocation.Y, PlayerLocation.Z, SaveFile);
`log("Event activated!");
}
event bool IsValidUISequenceObject(optional UIScreenObject TargetObject)
{
return true;
}
defaultproperties
{
ObjName="SaveEvent"
ObjCategory="Misc"
InputLinks.Empty
InputLinks.Add((LinkDesc="Activate"))
VariableLinks.Empty
VariableLinks.Add((ExpectedType=class'Engine.SeqVa r_Object',LinkDesc="Player",PropertyName=LocalPlayer,MaxVars=1))
}
Edit: Turns out I had just made a rudimentary mistake in my C++ code when reading the save file. Here is the updated code:
// SaveDLL.cpp : Defines the exported functions for the DLL application.
//
#include "stdafx.h"
#include "OSFDlg.h"
#include <fstream>
#include <iostream>
#include <sstream>
using namespace std;
template <typename Target, typename Source>
Target lexical_cast(Source source)
{
Target target;
std::wostringstream os;
os << source;
std::wistringstream is(os.str());
is >> target;
return target;
}
extern "C"
{
struct Save
{
//wchar_t *LevelName;
float X, Y, Z;
};
wchar_t* ReadLine(wifstream *Stream)
{
wchar_t *Line = new wchar_t[256];
wchar_t ControlChar = '0';
int i = 0;
while(ControlChar != '\n')
{
ControlChar = Stream->get();
cout << ControlChar;
Line[i] = ControlChar;
i++;
if(i == 256)
break;
}
return Line;
}
__declspec(dllexport) unsigned int SaveGame(wchar_t* LevelName, float X, float Y, float Z, wchar_t* SavePath)
{
wofstream SaveStream(SavePath, ios::out);
SaveStream << LevelName;
SaveStream << std::endl;
SaveStream << X;
SaveStream << std::endl;
SaveStream << Y;
SaveStream << std::endl;
SaveStream << Z;
SaveStream << std::endl;
SaveStream.close();
return 1;
}
__declspec(dllexport) Save* LoadGame(wchar_t* LoadPath)
{
wifstream LoadStream(LoadPath, ios::in);
wchar_t *LevelName = new wchar_t[100];
wchar_t *X = new wchar_t[100];
wchar_t *Y = new wchar_t[100];
wchar_t *Z = new wchar_t[100];
static Save NewSave;
LevelName = new wchar_t[100];
LevelName = ReadLine(&LoadStream);
X = ReadLine(&LoadStream);
NewSave.X = lexical_cast<float, wchar_t[]>(X);
Y = ReadLine(&LoadStream);
NewSave.Y = lexical_cast<float, wchar_t[]>(Y);
Z = ReadLine(&LoadStream);
NewSave.Z = lexical_cast<float, wchar_t[]>(Z);
LoadStream.close();
/*wstringstream WSS;
WSS << NewSave.X;
MessageBox(NULL, (LPCWSTR)WSS.str().c_str(), TEXT("LoadGame()"), MB_OKCANCEL);*/
delete X;
delete Y;
delete Z;
return &NewSave;
}
__declspec(dllexport) wchar_t *SaveDiag()
{
//Filter
TCHAR szFilter[] = TEXT("Save Files (*.SAV)\0*.sav\0");
//Default Extension
TCHAR szDefExtension[] = TEXT("sav\0");
static COSFDialog SaveDiag;
static wchar_t* Filename;
if(SaveDiag.FileSaveDlg(szFilter, szDefExtension, TEXT("Save Game")))
{
Filename = (wchar_t*)SaveDiag.GetFileName();
return Filename;
}
}
__declspec(dllexport) wchar_t *LoadDiag()
{
//Filter
TCHAR szFilter[] = TEXT("Save Files (*.SAV)\0*.sav\0");
//Default Extension
TCHAR szDefExtension[] = TEXT("sav\0");
static COSFDialog LoadDiag;
static wchar_t* Filename;
if(LoadDiag.FileOpenDlg(szFilter, szDefExtension, TEXT("Load Game"), false))
{
Filename = (wchar_t*)LoadDiag.GetFileName();
return Filename;
}
}
}
Warning: Doesn't really have any error checking and is basically a hacked-together mess. But it works. :)
Also, notice that if you're going to load a specific level (which you should do before placing the player at a given position), you need to implement a separate C++ function for that, because Unreal doesn't like you returning structs with strings in them. It's taken me a month to figure out that....
Ok, so I made a quick function in C++ to load a level's name.
The level seems to load nicely in UDK using the 'Open' consolecommand, but when I try to set the player's position afterwards, it doesn't work! :(
if(Pawn(LocalPlayer) != none)
{
Pawn(LocalPlayer).WorldInfo.ConsoleCommand("Open " $LevelName, true);
Pawn(LocalPlayer).SetLocation(PlayerLocation);
}
else if(Controller(LocalPlayer) != none)
{
Controller(LocalPlayer).Pawn.WorldInfo.ConsoleComm and("Open " $LevelName, true);
Controller(LocalPlayer).Pawn.SetLocation(PlayerLoc ation);
}
Is there another way of loading a level besides using a console command, and how do you set a player's position after a level has been loaded?
Honestly, is there no way of setting a player's position after a level has been loaded? :\
mightyenigma
01-08-2012, 04:24 AM
Is SetLocation not working?
UnrealEverything
01-08-2012, 08:04 AM
You need to wait until the new map is loaded until you can set location (in other words, wait for level loaded and then setlocation)
Powered by vBulletin® Version 4.2.0 Copyright © 2013 vBulletin Solutions, Inc. All rights reserved.