Unreal Engine - How to get the AxisMappings via C++ code - c++

I'm new to the Unreal Engine and C++...
I'm trying to get the assigned Key of an Axis. I found out that the information are stored in the DefaultInput.ini file but how do i access these data programmatically?
There's a GetAxisValue(const FName) method but it does not return anything.
FString AxisName = "MoveForward";
auto value = PlayerInputComponent->GetAxisValue(FName(*AxisName));
What am I doing wrong? I would really appreciate your help.

Im not sure because I use Blueprints most of the time for this, but one way to get the value is to bind it to a method.
(Example of the AFPSCharacter Template)
PlayerInputComponent->BindAxis("MoveForward", this, &APawn::MoveForward);
And later use it in the method
void AFPSCharacter::MoveForward(float Value){
//for example print the val
UE_LOG(LogTemp, Warning, TEXT("%f"), Value);
}

this was my first thought too but unfortunately you can't get the Keys, you just bind the method to an axis name. The MoveForward's "Value" parameter hold the scale value but not the Key value. 1.0f for example when you press "W" or -1.0f when you press "S".
I've already found a solution for my issue. The GetAxisValue(FName) is the wrong method for this purpose.
Instead I found the UInputSettings class that contains a method named GetAxisMappingByName(FName, TArray)
Here a code snippet how it works:
// Get the instance of the InputSettings
UInputSettings* InputSettings = UInputSettings::GetInputSettings();
// AxisMappings with all the information will be stored here
TArray<FInputAxisKeyMapping> VerticalKeys;
TArray<FInputAxisKeyMapping> HorizontalKeys;
// Load the AxisMappings
InputSettings->GetAxisMappingByName(FName("MoveForward"), VerticalKeys);
InputSettings->GetAxisMappingByName(FName("MoveRight"), HorizontalKeys);
// Each MovementKey gets its own variable
FKey ForwardKey;
FKey BackKey;
FKey LeftKey;
FKey RightKey;
// Assign each key to the correct direction
for (FInputAxisKeyMapping verticalKey : VerticalKeys)
{
if (verticalKey.Scale == 1.0f)
ForwardKey = verticalKey.Key;
else if (verticalKey.Scale == -1.0f)
BackKey = verticalKey.Key;
}
for (FInputAxisKeyMapping horizontalKey : HorizontalKeys)
{
if (horizontalKey.Scale == 1.0f)
RightKey = horizontalKey.Key;
else if (horizontalKey.Scale == -1.0f)
LeftKey = horizontalKey.Key;
}
Is there a better solution for assigning the keys than using for loops? Feel free to correct my code since I'm not really an expert in C++. ;-)

Related

Read a list of parameters from a LuaRef using LuaBridge

[RESOLVED]
I'm building a game engine that uses LuaBridge in order to read components for entities. In my engine, an entity file looks like this, where "Components" is a list of the components that my entity has and the rest of parameters are used to setup the values for each individual component:
-- myEntity.lua
Components = {"MeshRenderer", "Transform", "Rigidbody"}
MeshRenderer = {
Type = "Sphere",
Position = {0,300,0}
}
Transform = {
Position = {0,150,0},
Scale = {1,1,1},
Rotation = {0,0,0}
}
Rigidbody = {
Type = "Sphere",
Mass = 1
}
I'm currently using this function (in C++) in order to read the value from a parameter (given its name) inside a LuaRef.
template<class T>
T readParameter(LuaRef& table, const std::string& parameterName)
{
try {
return table.rawget(parameterName).cast<T>();
}
catch (std::exception e) {
// std::cout ...
return NULL;
}
}
For example, when calling readVariable<std::string>(myRigidbodyTable, "Type"), with myRigidbodyTable being a LuaRef with the values of Rigidbody, this function should return an std::string with the value "Sphere".
My problem is that when I finish reading and storing the values of my Transform component, when I want to read the values for "Ridigbody" and my engine reads the value "Type", an unhandled exception is thrown at Stack::push(lua_State* L, const std::string& str, std::error_code&).
I am pretty sure that this has to do with the fact that my component Transform stores a list of values for parameters like "Position", because I've had no problems while reading components that only had a single value for each parameter. What's the right way to do this, in case I am doing something wrong?
I'd also like to point out that I am new to LuaBridge, so this might be a beginner problem with a solution that I've been unable to find. Any help is appreciated :)
Found the problem, I wasn't reading the table properly. Instead of
LuaRef myTable = getGlobal(state, tableName.c_str());
I was using the following
LuaRef myTable = getGlobal(state, tableName.c_str()).getMetatable();

Why is the lambda function not copying out the struct?

I'm modifying a code-base to get a struct (TheClipInfo) out of a Lambda so I can return one of it's properties (CurrentFrameCount).
I think I'm passing it by reference, but clearly I'm missing something.
Comments below show where I modified the code.
int32 UTimeSynthComponent::StopClipOffset(FTimeSynthClipHandle InClipHandle, ETimeSynthEventClipQuantization EventQuantization)
{
Audio::EEventQuantization StopQuantization = GlobalQuantization;
if (EventQuantization != ETimeSynthEventClipQuantization::Global)
{
int32 ClipQuantizationEnumIndex = (int32)EventQuantization;
check(ClipQuantizationEnumIndex >= 1);
StopQuantization = (Audio::EEventQuantization)(ClipQuantizationEnumIndex - 1);
}
FPlayingClipInfo TheClipInfo; // I want the Lambda to put data here.
SynthCommand([this, InClipHandle, StopQuantization, &TheClipInfo] // The first Lambda
{
EventQuantizer.EnqueueEvent(StopQuantization,
[this, InClipHandle, &TheClipInfo](uint32 NumFramesOffset) // The Second Lambda
{
int32* PlayingClipIndex = ClipIdToClipIndexMap_AudioRenderThread.Find(InClipHandle.ClipId);
if (PlayingClipIndex)
{
// Grab the clip info
FPlayingClipInfo& PlayingClipInfo = PlayingClipsPool_AudioRenderThread[*PlayingClipIndex]; // The Struct I want to get out.
// Only do anything if the clip is not yet already fading
if (PlayingClipInfo.CurrentFrameCount < PlayingClipInfo.DurationFrames)
{
// Adjust the duration of the clip to "spoof" it's code which triggers a fade this render callback block.
PlayingClipInfo.DurationFrames = PlayingClipInfo.CurrentFrameCount + NumFramesOffset;
}
TheClipInfo = PlayingClipInfo; // I think this should make a copy.
}
});
});
return TheClipInfo.CurrentFrameCount; // This is always returning 0.
}
I'm assuming this is all happening in the same thread and in order (not some async callback like JavaScript).
My first attempt was with an int32, but that can't be passed by reference. I really want just one value from it.
Snap!
EventQuantizer.EnqueueEvent
Adds the second lambda to an event queue. So it is asynch. Which is why it's not working as I'd like.
The simplest thing that could work is to copy the code out of the lambda and use it for the return.

AutoCAD C++ When AcDbEntity need to open for read?

I’m not sure when open entities for read is necessary, and when it may be omit.
For example I know I don’t need to open entity when I want to use objectId() but there are some methods which require to open entity before.
I don’t know if it’s necessary to open AcDbPolyline before getArcSegAt(). In many cases I can simple try to use method before it’s open I will get what I want or not. But maybe there is some easy rule for that?
Example:
AcDbObjectId id = somethingNotImportant();
AcDbPolyline* _pPoly = NULL;
if (id.isValid())
{
AcDbEntity* pEnt = NULL;
Acad::ErrorStatus es;
es = acdbOpenObject(pEnt, id, AcDb::kForRead);
if( es == Acad::eOk)
{
if(pEnt->isKindOf(AcDbPolyline::desc()))
{
this->_pPoly = AcDbPolyline::cast(pEnt);
}
es = pEnt->close();
}
}
now _pPoly is initiallized , but it is closed because of pEnt->close();
now I want for example use:
AcGePoint3d Px = initializedSomehow();
double distAtPx = 0;
_pPoly->getDistAtPoint(Px , distAtPx);
do I need to :
es = acdbOpenObject(_pPoly, id, AcDb::kForRead);
before:
_pPoly->getDistAtPoint(Px , distAtPx);
I would consider it good practise to use the appropriate read access on your object first. That way you are guaranteed to know if you are only able to read the entity or also write to the entity.
This way you are in control. If you just go ahead and use the entity you have no way of knowing in the underlying library changes it's default behaviour.
Sorry if this does not answer your question.
I've looked in the documentation, and I'm not seeing anything that indicates anything about being able to use methods on a closed object. I expect that the assumption is that to work with any real AutoCAD data requires the object to be open for at least reading.
In that case, there are two ways to improve upon your example.
First option: do the work before closing the object. This keeps the open/close code all together with the work being done in the middle. This is nice that it should be clear when the object is open and can be worked with and that the object is not left open. This also meets the recommendation in the documentation to not keep object open any longer than necessary.
AcGePoint3d Px = initializedSomehow();
double distAtPx = 0;
AcDbObjectId id = somethingNotImportant();
if (id.isValid())
{
AcDbEntity* pEnt = NULL;
Acad::ErrorStatus es;
es = acdbOpenObject(pEnt, id, AcDb::kForRead);
if( es == Acad::eOk)
{
if(pEnt->isKindOf(AcDbPolyline::desc()))
{
AcDbPolyline*_pPoly = AcDbPolyline::cast(pEnt);
//Do work with poly here
_pPoly->getDistAtPoint(Px , distAtPx);
}
es = pEnt->close();
}
}
Second option: close the object only after doing the work, and only if the object is the right type. This allows for non-local usage of the opened object, but you need to make sure you close it later!
AcDbObjectId id = somethingNotImportant();
AcDbPolyline* _pPoly = NULL;
if (id.isValid())
{
AcDbEntity* pEnt = NULL;
Acad::ErrorStatus es;
es = acdbOpenObject(pEnt, id, AcDb::kForRead);
if( es == Acad::eOk)
{
if(pEnt->isKindOf(AcDbPolyline::desc()))
{
_pPoly = AcDbPolyline::cast(pEnt);
}
else
es = pEnt->close(); //not polyline, close now
}
}
AcGePoint3d Px = initializedSomehow();
double distAtPx = 0;
if (_pPoly)
{
//Do work with poly here
_pPoly->getDistAtPoint(Px , distAtPx);
_pPoly->close();
}

Xamarin Forms - Get the size of an AbsoluteLayout

I cannot find the way to get the Width and the Height of a Xamarin.Forms.View.
I have this object:
public class SquareLayout : View
{
public static readonly BindableProperty ScalingBaseProperty =
BindableProperty.Create(nameof(ScalingBase), typeof(ScalingBaseType), typeof(SquareLayout), ScalingBaseType.Average,
propertyChanged: OnScalingBasePropertyChanged);
public ScalingBaseType ScalingBase
{
get { return (ScalingBaseType)GetValue(ScalingBaseProperty); }
set { SetValue(ScalingBaseProperty, value); }
}
public enum ScalingBaseType
{
Average,
Height,
Width
}
public static void OnScalingBasePropertyChanged(BindableObject bindable, object oldValue, object newValue)
{
SquareLayout sq = ((SquareLayout)bindable);
Debug.WriteLine("|Width = {0}|Height = {1}|", sq.Bounds.Width, sq.Bounds.Height);
switch (sq.ScalingBase)
{
case ScalingBaseType.Average:
double size = (sq.Bounds.Width + sq.Bounds.Height) / 2;
sq.WidthRequest = size;
sq.HeightRequest = size;
break;
case ScalingBaseType.Height:
sq.WidthRequest = sq.Bounds.Height;
break;
case ScalingBaseType.Width:
sq.HeightRequest = sq.Bounds.Width;
break;
}
Debug.WriteLine("|Width = {0}|Height = {1}|", sq.Bounds.Width, sq.Bounds.Height);
}
}
Basically, you declare somewhere this SquareLayout and then, based on an Enum, the layout is resized as a Square.
So, I then have this XAML part
<ContentPage.Content>
<AbsoluteLayout BackgroundColor="White">
...
<AbsoluteLayout x:Name="ToolsLayout" BackgroundColor="Red"
AbsoluteLayout.LayoutBounds="0.5, 0.05, 0.9, 0.075"
AbsoluteLayout.LayoutFlags="All">
<control:SquareLayout BackgroundColor="White" ScalingBase="Height"
AbsoluteLayout.LayoutBounds="0, 0.5, 0.1, 1"
AbsoluteLayout.LayoutFlags="All">
</control:SquareLayout>
<control:SquareLayout BackgroundColor="White" ScalingBase="Height"
AbsoluteLayout.LayoutBounds="1, 0.5, 0.1, 1"
AbsoluteLayout.LayoutFlags="All">
</control:SquareLayout>
</AbsoluteLayout>
...
</AbsoluteLayout>
</ContentPage.Content>
Which would give me a Rectangle with two Square around.. But nothing !
I tried to display the Width and the Height but nothing.. I tried the Bounds as well as you can see in the example, but nothing one more time..
The only values I get are -1
Does someone can help me? Thank in advance !
Xamarin has very less documentation for newbies , took some time to figure this out , basically during design time the the width and height property have a default value of -1 , which indicates auto , there is no way of knowing during design time what the values will be , hence you need to use 'events' to get the width and height property in this case you will use SizeChanged event , when the layout bounds are set during runtime this event will trigger.
In your xaml codebehind use this event to get your widh and height of yourlayout , i have used a lambda function , this can be implemented in many ways i just find this method easy.
yourlayout.SizeChanged+=(sender,e)=>
{
//Add your child objects here and set its values using yourlayout.Height etc
};
Instead of adding your children within this function you can use it to return a value and use that instead.
NOTE:I am not sure if this is the best practice for MVVM or otherwise

Indentifier not found in non-program loop script

I have tried to look up the "identifier not found" error only to find posts where the function must be moved outside the main loop or should use a forward declaration. However, my script is used as a module for a game engine thus has no real main loop and the function in question is called by a different function above the failing line with no issues:
// Create a Steam ID
CSteamID Steam::createSteamID(uint32 steamID, int accountType){
CSteamID cSteamID;
if(accountType < 0 || accountType >= k_EAccountTypeMax){
accountType = 1;
}
cSteamID.Set(steamID, EUniverse(k_EUniversePublic), EAccountType(accountType));
return cSteamID;
}
// Set a Steam user as someone recently played with
void Steam::setPlayedWith(int steamID){
if(SteamFriends() == NULL){
return;
}
CSteamID friendID = createSteamID(steamID);
SteamFriends()->SetPlayedWith(friendID);
}
// Get friend's Steam username
String getFriendPersonaName(int steamID){
if(SteamFriends() == NULL || steamID == 0){
return "";
}
CSteamID friendID = createSteamID(steamID);
bool isDataLoading = SteamFriends()->RequestUserInformation(friendID, true);
if(!isDataLoading){
return SteamFriends()->GetFriendPersonaName(friendID);
}
}
The ID creation function sits at the very top and these two functions come much later. The first one (setPlayedWith) succeeds no problem but the second one (getFriendPersonaName) fails with: 'createSteamID': identifier not found when compiling the script.
I'm kind of at a loss and hopefully someone can point me in the right direction.
if getFriendPersonaName() is a member function then you have forgotten to define it the correct way so it will look like:
string Steam::getFriendPersonaName(int steamID)...
if it is not a member then you can't access it. however you can Only access it if getFriendPersonaName() is a friend function where you should edit the signature to:
String getFriendPersonaName(int steamID, const steam& rhs);