プラグイン置き場

自作のPluginを置いています。
しばらくはGoogleDriveで公開します。
思ったより重いので、いつか別のところに移動します。
古いVersionは随時削除し、最新のものだけ保管します。
動作の保証はできません。自己責任で使用してください。

注意
Androidでの実機プレイやWindowsでのパッケージ化において、以下のMessageがでて正常に起動できませんでした。
問題の解決ができるまで、Pluginの配布はやめようと思います。
もしダウンロードして使ってしまっている方がいたら申し訳ありません。

導入方法
1.リンクから、Zipファイルをダウンロード。

2.画面左下から継続をクリック。(chromeの場合)

この警告は、ダウンロード数が少ないのが原因らしい。

3.クリックすると解凍される。

4.UEのプロジェクトをExplorerで開き、Pluginsのフォルダを作成する。

5.解凍したフォルダをPluginsのフォルダの中に入れる。

これで導入できました。

導入確認
1.UEのエディタのEditからPluginsを選択。

2.Pluginの左に✓マークがついていたらOK。

Rate Component

複数のものを操ったり連続した処理を作ったりするのに、少しだけ便利なActorComponent。
Ver1.1(https://drive.google.com/file/d/1KtL…)
プラグインはアップロードしていないので、代わりにコードを置いておきます。

// Fill out your copyright notice in the Description page of Project Settings.

#pragma once

#include "CoreMinimal.h"
#include "Components/ActorComponent.h"
#include "RateComponent.generated.h"


UENUM(BlueprintType)
enum class ERateDirection : uint8
{
	Forward,
	Backward
};

UENUM(BlueprintType)
enum class EConvertRateType : uint8
{
	Linear,
	SlowQuick,
	QuickSlow,
	SlowQuickSlow,
	QuickSlowQuick
};

USTRUCT(BlueprintType)
struct FRateStruct
{
	GENERATED_BODY()


		FORCEINLINE FRateStruct();
	explicit FORCEINLINE FRateStruct(float InRate, float InDuration, ERateDirection InDirection, EConvertRateType InType, float InPower, float InConvertedRate, bool InCanPlay, bool InLoop, bool InOnOneRate, bool InOnZeroRate, bool InOnStopRate, int32 InCount);


	// Not less than 0 and not greater than 1.
	UPROPERTY(EditAnywhere, BlueprintReadWrite)
		float Rate = 0;

	// The Duration Rate go from 0 to 1.
	UPROPERTY(EditAnywhere, BlueprintReadWrite)
		float Duration = 1;

	// If this is Forward, Rate goes from 0 to 1. If Backward, Rate goes from 1 to 0.
	UPROPERTY(EditAnywhere, BlueprintReadWrite)
		ERateDirection Direction = ERateDirection::Forward;

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "ConvertRate")
		EConvertRateType Type = EConvertRateType::Linear;

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "ConvertRate")
		float Power = 2;

	UPROPERTY(BlueprintReadOnly, Category = "ConvertRate")
		float ConvertedRate = 0;

	// If this is true, Rate can be played. If not, Rate cannot be played. 
	UPROPERTY(EditAnywhere, BlueprintReadWrite)
		bool bCanPlay = false;

	// If this is true, Rate doesn't stop. When Rate becomes greater than 1, the direction becomes Backward.
	UPROPERTY(EditAnywhere, BlueprintReadWrite)
		bool bLoop = false;

	// Becomes true, as soon as Rate becomes greater than 1.( If bLoop is true )
	UPROPERTY(BlueprintReadWrite)
		bool bOnOneRate = false;

	// Becomes true, as soon as Rate becomes less than 0.( If bLoop is true )
	UPROPERTY(BlueprintReadWrite)
		bool bOnZeroRate = false;

	// Becomes true, as soon as bCanPlay becomes false.
	UPROPERTY(BlueprintReadWrite)
		bool bOnStopRate = false;

	// Becomes true, as soon as bCanPlay becomes false.
	UPROPERTY(BlueprintReadWrite)
		int32 Count = 0;
};

FORCEINLINE FRateStruct::FRateStruct()
{
}

FORCEINLINE FRateStruct::FRateStruct(float InRate, float InDuration, ERateDirection InDirection, EConvertRateType InType, float InPower, float InConvertedRate, bool InCanPlay, bool InLoop, bool InOnOneRate, bool InOnZeroRate, bool InOnStopRate, int32 InCount) : Rate(InRate), Duration(InDuration), Direction(InDirection), Type(InType), Power(InPower), ConvertedRate(InConvertedRate), bCanPlay(InCanPlay), bLoop(InLoop), bOnOneRate(InOnOneRate), bOnZeroRate(InOnZeroRate), bOnStopRate(InOnStopRate), Count(InCount)
{
}




UCLASS(ClassGroup = (Custom), meta = (BlueprintSpawnableComponent))
class UNREALQUEST1_2_API URateComponent : public UActorComponent
{
	GENERATED_BODY()

public:
	// Sets default values for this component's properties
	URateComponent();

protected:
	// Called when the game starts
	virtual void BeginPlay() override;

public:
	// Called every frame
	virtual void TickComponent(float DeltaTime, ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction) override;

	///////////////////////////////////////////////////////////////////////
	//// Member Variable

	UPROPERTY(EditAnywhere, BlueprintReadWrite)
		TArray<FRateStruct> RateStructs;

	///////////////////////////////////////////////////////////////////////
	//// Main Function

		// Called in TickComponent.
	void PlayRate(float DeltaSec, UPARAM(ref) FRateStruct& Struct);

	// R means Rate, T means Type, P means Power. If Power is less than 2, Linear Rate is returned.
	UFUNCTION(BlueprintPure, meta = (P = "2"))
		float ConvertRate(float R, ERateDirection D, EConvertRateType T, float P);

	///////////////////////////////////////////////////////////////////////
	//// Get/Set/Toggle Function

		// Rate Struct
	UFUNCTION(BlueprintPure, meta = (CompactNodeTitle = "Get RateStruct"))
		FRateStruct GetRateStruct(int32 Index);

	UFUNCTION(BlueprintCallable, meta = (CompactNodeTitle = "Set RateStruct"))
		FRateStruct SetRateStruct(FRateStruct NewRateStruct, int32 Index);

	UFUNCTION(BlueprintCallable, meta = (CompactNodeTitle = "Set RateStruct"))
		FRateStruct SetRateStructFromStruct(UPARAM(ref) FRateStruct& Struct, FRateStruct NewRateStruct);


	// Rate

	UFUNCTION(BlueprintPure, meta = (CompactNodeTitle = "Get Rate"))
		float GetRate(int32 Index);

	UFUNCTION(BlueprintPure, meta = (CompactNodeTitle = "Get Rate"))
		float GetRateFromStruct(FRateStruct Struct);

	UFUNCTION(BlueprintCallable, meta = (CompactNodeTitle = "Set Rate"))
		void SetRate(float NewRate, int32 Index);

	UFUNCTION(BlueprintCallable, meta = (CompactNodeTitle = "Set Rate"))
		void SetRateFromStruct(float NewRate, UPARAM(ref) FRateStruct& Struct);

	// Duration

	UFUNCTION(BlueprintPure, meta = (CompactNodeTitle = "Get Duration"))
		float GetDuration(int32 Index);

	UFUNCTION(BlueprintPure, meta = (CompactNodeTitle = "Get Duration"))
		float GetDurationFromStruct(FRateStruct Struct);

	UFUNCTION(BlueprintCallable, meta = (CompactNodeTitle = "Set Duration"))
		void SetDuration(float NewDuration, int32 Index);

	UFUNCTION(BlueprintCallable, meta = (CompactNodeTitle = "Set Duration"))
		void SetDurationFromStruct(float NewDuration, UPARAM(ref) FRateStruct& Struct);

	// Direction

	UFUNCTION(BlueprintPure, meta = (CompactNodeTitle = "Get Direction"))
		ERateDirection GetDirection(int32 Index);

	UFUNCTION(BlueprintPure, meta = (CompactNodeTitle = "Get Direction"))
		ERateDirection GetDirectionFromStruct(FRateStruct Struct);

	UFUNCTION(BlueprintCallable, meta = (CompactNodeTitle = "Set Direction"))
		void SetDirection(ERateDirection NewDirection, int32 Index);

	UFUNCTION(BlueprintCallable, meta = (CompactNodeTitle = "Set Direction"))
		void SetDirectionFromStruct(ERateDirection NewDirection, UPARAM(ref) FRateStruct& Struct);

	UFUNCTION(BlueprintCallable, meta = (CompactNodeTitle = "Toggle Direction"))
		void ToggleDirection(int32 Index);

	UFUNCTION(BlueprintCallable, meta = (CompactNodeTitle = "Toggle Direction"))
		void ToggleDirectionFromStruct(UPARAM(ref) FRateStruct& Struct);

	// Type

	UFUNCTION(BlueprintPure, meta = (CompactNodeTitle = "Get Type"))
		EConvertRateType GetType(int32 Index);

	UFUNCTION(BlueprintPure, meta = (CompactNodeTitle = "Get Type"))
		EConvertRateType GetTypeFromStruct(FRateStruct Struct);

	UFUNCTION(BlueprintCallable, meta = (CompactNodeTitle = "Set Type"))
		void SetType(EConvertRateType NewType, int32 Index);

	UFUNCTION(BlueprintCallable, meta = (CompactNodeTitle = "Set Type"))
		void SetTypeFromStruct(EConvertRateType NewType, UPARAM(ref) FRateStruct& Struct);

	// Power

	UFUNCTION(BlueprintPure, meta = (CompactNodeTitle = "Get Power"))
		float GetPower(int32 Index);

	UFUNCTION(BlueprintPure, meta = (CompactNodeTitle = "Get Power"))
		float GetPowerFromStruct(FRateStruct Struct);

	UFUNCTION(BlueprintCallable, meta = (CompactNodeTitle = "Set Power"))
		void SetPower(float NewPower, int32 Index);

	UFUNCTION(BlueprintCallable, meta = (CompactNodeTitle = "Set Power"))
		void SetPowerFromStruct(float NewPower, UPARAM(ref) FRateStruct& Struct);

	// ConvertedRate

	UFUNCTION(BlueprintPure, meta = (CompactNodeTitle = "Get Converted Rate"))
		float GetConvertedRate(int32 Index);

	UFUNCTION(BlueprintPure, meta = (CompactNodeTitle = "Get Converted Rate"))
		float GetConvertedRateFromStruct(FRateStruct Struct);

	// CanPlay

	UFUNCTION(BlueprintPure, meta = (CompactNodeTitle = "Get CanPlay"))
		bool GetCanPlay(int32 Index);

	UFUNCTION(BlueprintPure, meta = (CompactNodeTitle = "Get CanPlay"))
		bool GetCanPlayFromStruct(FRateStruct Struct);

	UFUNCTION(BlueprintCallable, meta = (CompactNodeTitle = "Set CanPlay"))
		void SetCanPlay(bool NewCanPlay, int32 Index);

	UFUNCTION(BlueprintCallable, meta = (CompactNodeTitle = "Set CanPlay"))
		void SetCanPlayFromStruct(bool NewCanPlay, UPARAM(ref) FRateStruct& Struct);

	UFUNCTION(BlueprintCallable, meta = (CompactNodeTitle = "Toggle CanPlay"))
		void ToggleCanPlay(int32 Index);

	UFUNCTION(BlueprintCallable, meta = (CompactNodeTitle = "Toggle CanPlay"))
		void ToggleCanPlayFromStruct(UPARAM(ref) FRateStruct& Struct);

	// Loop

	UFUNCTION(BlueprintPure, meta = (CompactNodeTitle = "Get Loop"))
		bool GetLoop(int32 Index);

	UFUNCTION(BlueprintPure, meta = (CompactNodeTitle = "Get Loop"))
		bool GetLoopFromStruct(FRateStruct Struct);

	UFUNCTION(BlueprintCallable, meta = (CompactNodeTitle = "Set Loop"))
		void SetLoop(bool NewLoop, int32 Index);

	UFUNCTION(BlueprintCallable, meta = (CompactNodeTitle = "Set Loop"))
		void SetLoopFromStruct(bool NewLoop, UPARAM(ref) FRateStruct& Struct);

	UFUNCTION(BlueprintCallable, meta = (CompactNodeTitle = "Toggle Loop"))
		void ToggleLoop(int32 Index);

	UFUNCTION(BlueprintCallable, meta = (CompactNodeTitle = "Toggle Loop"))
		void ToggleLoopFromStruct(UPARAM(ref) FRateStruct& Struct);

	// OnOneRate

	UFUNCTION(BlueprintPure, meta = (CompactNodeTitle = "Get OnOne"))
		bool GetOnOneRate(int32 Index);

	UFUNCTION(BlueprintPure, meta = (CompactNodeTitle = "Get OnOne"))
		bool GetOnOneRateFromStruct(FRateStruct Struct);

	// OnZeroRate

	UFUNCTION(BlueprintPure, meta = (CompactNodeTitle = "Get OnZero"))
		bool GetOnZeroRate(int32 Index);

	UFUNCTION(BlueprintPure, meta = (CompactNodeTitle = "Get OnZero"))
		bool GetOnZeroRateFromStruct(FRateStruct Struct);

	// OnStopRate

	UFUNCTION(BlueprintPure, meta = (CompactNodeTitle = "Get Stop"))
		bool GetOnStopRate(int32 Index);

	UFUNCTION(BlueprintPure, meta = (CompactNodeTitle = "Get Stop"))
		bool GetOnStopRateFromStruct(FRateStruct Struct);

	// Count

	UFUNCTION(BlueprintPure, meta = (CompactNodeTitle = "Get Count"))
		int32 GetCount(int32 Index);

	UFUNCTION(BlueprintPure, meta = (CompactNodeTitle = "Get Count"))
		int32 GetCountFromStruct(FRateStruct Struct);

	UFUNCTION(BlueprintCallable, meta = (CompactNodeTitle = "Set Count"))
		void SetCount(int32 NewCount, int32 Index);

	UFUNCTION(BlueprintCallable, meta = (CompactNodeTitle = "Set Count"))
		void SetCountFromStruct(int32 NewCount, UPARAM(ref) FRateStruct& Struct);

	UFUNCTION(BlueprintCallable, meta = (CompactNodeTitle = "++ Count"))
		int32 IncrementCount(int32 Index);

	UFUNCTION(BlueprintCallable, meta = (CompactNodeTitle = "++ Count"))
		int32 IncrementCountFromStruct(UPARAM(ref) FRateStruct& Struct);

	UFUNCTION(BlueprintCallable, meta = (CompactNodeTitle = "Reset Count"))
		void ResetCount(int32 Index);

	UFUNCTION(BlueprintCallable, meta = (CompactNodeTitle = "Reset Count"))
		void ResetCountFromStruct(UPARAM(ref) FRateStruct& Struct);

	// PlusMinusRate

	UFUNCTION(BlueprintPure, meta = (CompactNodeTitle = "Get +-Rate"))
		float GetPlusMinusRate(int32 Index);

	UFUNCTION(BlueprintPure, meta = (CompactNodeTitle = "Get +-Rate"))
		float GetPlusMinusRateFromStruct(UPARAM(ref) FRateStruct& Struct);
};

// Fill out your copyright notice in the Description page of Project Settings.


#include "RateComponent.h"

// Sets default values for this component's properties
URateComponent::URateComponent()
{
	// Set this component to be initialized when the game starts, and to be ticked every frame.  You can turn these features
	// off to improve performance if you don't need them.
	PrimaryComponentTick.bCanEverTick = true;

	// ...
}


// Called when the game starts
void URateComponent::BeginPlay()
{
	Super::BeginPlay();

	// ...

}


// Called every frame
void URateComponent::TickComponent(float DeltaTime, ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction)
{
	Super::TickComponent(DeltaTime, TickType, ThisTickFunction);

	// ...

	int32 Num = RateStructs.Num();
	for (int32 i = 0; i < Num; i++)
	{
		PlayRate(DeltaTime, RateStructs[i]);
	}

}


///////////////////////////////////////////////////////////////////////
//// Main Function

void URateComponent::PlayRate(float DeltaSec, FRateStruct& Struct)
{
	if (Struct.bCanPlay == false) return;

	float DeltaRate = DeltaSec / Struct.Duration;

	if (Struct.Direction == ERateDirection::Forward)
	{
		Struct.Rate += DeltaRate;
	}
	else
	{
		Struct.Rate -= DeltaRate;
	}

	Struct.ConvertedRate = ConvertRate(Struct.Rate, Struct.Direction, Struct.Type, Struct.Power);

	if (Struct.Rate < 0.f)
	{
		if (Struct.bLoop)
		{
			Struct.Direction = ERateDirection::Forward;
			Struct.Count += 1;
			Struct.bOnZeroRate = true;
		}
		else
		{
			Struct.bCanPlay = false;
			Struct.bOnStopRate = true;
		}
	}
	else if (Struct.Rate > 1.f)
	{
		if (Struct.bLoop)
		{
			Struct.Direction = ERateDirection::Backward;
			Struct.bOnOneRate = true;
		}
		else
		{
			Struct.bCanPlay = false;
			Struct.bOnStopRate = true;
		}
	}
}

float URateComponent::ConvertRate(float R, ERateDirection D, EConvertRateType T, float P)
{
	if (P < 2) return R;

	switch (T)
	{
	case EConvertRateType::Linear: return R;
	case EConvertRateType::SlowQuick:
	{
		if (D == ERateDirection::Forward)
		{
			return FMath::Clamp(std::pow(R, P), 0, 1);
		}
		else
		{
			return FMath::Clamp(1 - std::pow((1 - R), P), 0, 1);
		}
		break;
	}
	case EConvertRateType::QuickSlow:
	{
		if (D == ERateDirection::Backward)
		{
			return FMath::Clamp(std::pow(R, P), 0, 1);
		}
		else
		{
			return FMath::Clamp(1 - std::pow((1 - R), P), 0, 1);
		}
		break;
	}
	case EConvertRateType::SlowQuickSlow:
	{
		if (R < 0.5)
		{
			return FMath::Clamp(std::pow(2, P - 1) * std::pow(R, P), 0, 1);
		}
		else
		{
			return FMath::Clamp(1 - std::pow(2, P - 1) * std::pow((1 - R), P), 0, 1);
		}
		break;
	}
	case EConvertRateType::QuickSlowQuick:
	{
		if (R < 0.5)
		{
			return FMath::Clamp(0.5 - std::pow(2, P - 1) * std::pow((0.5 - R), P), 0, 1);
		}
		else
		{
			return FMath::Clamp(std::pow(2, P - 1) * std::pow(R - 0.5, P) + 0.5, 0, 1);
		}
		break;
	}
	default: return R;
	}
}


///////////////////////////////////////////////////////////////////////
//// Get/Set/Toggle Function

FRateStruct URateComponent::GetRateStruct(int32 Index)
{
	return RateStructs[Index];
}


FRateStruct URateComponent::SetRateStruct(FRateStruct NewRateStruct, int32 Index)
{
	RateStructs[Index] = NewRateStruct;
	return RateStructs[Index];
}

FRateStruct URateComponent::SetRateStructFromStruct(FRateStruct& Struct, FRateStruct NewRateStruct)
{
	Struct = NewRateStruct;
	return Struct;
}

// Rate
float URateComponent::GetRate(int32 Index)
{
	return RateStructs[Index].Rate;
}

float URateComponent::GetRateFromStruct(FRateStruct Struct)
{
	return Struct.Rate;
}

void URateComponent::SetRate(float NewRate, int32 Index)
{
	RateStructs[Index].Rate = NewRate;
}

void URateComponent::SetRateFromStruct(float NewRate, FRateStruct& Struct)
{
	Struct.Rate = NewRate;
}

// Duration
float URateComponent::GetDuration(int32 Index)
{
	return RateStructs[Index].Duration;
}

float URateComponent::GetDurationFromStruct(FRateStruct Struct)
{
	return Struct.Duration;
}

void URateComponent::SetDuration(float NewDuration, int32 Index)
{
	RateStructs[Index].Duration = NewDuration;
}

void URateComponent::SetDurationFromStruct(float NewDuration, FRateStruct& Struct)
{
	Struct.Duration = NewDuration;
}


// Direction
ERateDirection URateComponent::GetDirection(int32 Index)
{
	return RateStructs[Index].Direction;
}

ERateDirection URateComponent::GetDirectionFromStruct(FRateStruct Struct)
{
	return Struct.Direction;
}

void URateComponent::SetDirection(ERateDirection NewDirection, int32 Index)
{
	RateStructs[Index].Direction = NewDirection;
}

void URateComponent::SetDirectionFromStruct(ERateDirection NewDirection, FRateStruct& Struct)
{
	Struct.Direction = NewDirection;
}

void URateComponent::ToggleDirection(int32 Index)
{
	if (RateStructs[Index].Direction == ERateDirection::Forward)
	{
		RateStructs[Index].Direction = ERateDirection::Backward;
	}
	else
	{
		RateStructs[Index].Direction = ERateDirection::Forward;
	}
}

void URateComponent::ToggleDirectionFromStruct(FRateStruct& Struct)
{
	if (Struct.Direction == ERateDirection::Forward)
	{
		Struct.Direction = ERateDirection::Backward;
	}
	else
	{
		Struct.Direction = ERateDirection::Forward;
	}
}

// Type
EConvertRateType URateComponent::GetType(int32 Index)
{
	return RateStructs[Index].Type;
}

EConvertRateType URateComponent::GetTypeFromStruct(FRateStruct Struct)
{
	return Struct.Type;
}

void URateComponent::SetType(EConvertRateType NewType, int32 Index)
{
	RateStructs[Index].Type = NewType;
}

void URateComponent::SetTypeFromStruct(EConvertRateType NewType, FRateStruct& Struct)
{
	Struct.Type = NewType;
}

float URateComponent::GetPower(int32 Index)
{
	return RateStructs[Index].Power;
}

float URateComponent::GetPowerFromStruct(FRateStruct Struct)
{
	return Struct.Power;
}

void URateComponent::SetPower(float NewPower, int32 Index)
{
	RateStructs[Index].Power = NewPower;
}

void URateComponent::SetPowerFromStruct(float NewPower, FRateStruct& Struct)
{
	Struct.Power = NewPower;
}

// Converted Rate
float URateComponent::GetConvertedRate(int32 Index)
{
	return RateStructs[Index].ConvertedRate;
}

float URateComponent::GetConvertedRateFromStruct(FRateStruct Struct)
{
	return Struct.ConvertedRate;
}

// CanPlay
bool URateComponent::GetCanPlay(int32 Index)
{
	return RateStructs[Index].bCanPlay;
}

bool URateComponent::GetCanPlayFromStruct(FRateStruct Struct)
{
	return Struct.bCanPlay;
}

void URateComponent::SetCanPlay(bool NewCanPlay, int32 Index)
{
	RateStructs[Index].bCanPlay = NewCanPlay;
}

void URateComponent::SetCanPlayFromStruct(bool NewCanPlay, FRateStruct& Struct)
{
	Struct.bCanPlay = NewCanPlay;
}

void URateComponent::ToggleCanPlay(int32 Index)
{
	RateStructs[Index].bCanPlay = !RateStructs[Index].bCanPlay;
}

void URateComponent::ToggleCanPlayFromStruct(FRateStruct& Struct)
{
	Struct.bCanPlay = !Struct.bCanPlay;
}

// Loop

bool URateComponent::GetLoop(int32 Index)
{
	return RateStructs[Index].bLoop;
}

bool URateComponent::GetLoopFromStruct(FRateStruct Struct)
{
	return Struct.bLoop;
}

void URateComponent::SetLoop(bool NewLoop, int32 Index)
{
	RateStructs[Index].bLoop = NewLoop;
}

void URateComponent::SetLoopFromStruct(bool NewLoop, FRateStruct& Struct)
{
	Struct.bLoop = NewLoop;
}

void URateComponent::ToggleLoop(int32 Index)
{
	RateStructs[Index].bLoop = !RateStructs[Index].bLoop;
}

void URateComponent::ToggleLoopFromStruct(FRateStruct& Struct)
{
	Struct.bLoop = !Struct.bLoop;
}

// OnOneRate

bool URateComponent::GetOnOneRate(int32 Index)
{
	return RateStructs[Index].bOnOneRate;
}

bool URateComponent::GetOnOneRateFromStruct(FRateStruct Struct)
{
	return Struct.bOnOneRate;
}

// OnZeroRate

bool URateComponent::GetOnZeroRate(int32 Index)
{
	return RateStructs[Index].bOnZeroRate;
}

bool URateComponent::GetOnZeroRateFromStruct(FRateStruct Struct)
{
	return Struct.bOnZeroRate;
}

// OnStopRate

bool URateComponent::GetOnStopRate(int32 Index)
{
	return RateStructs[Index].bOnStopRate;
}

bool URateComponent::GetOnStopRateFromStruct(FRateStruct Struct)
{
	return Struct.bOnStopRate;
}

// Count

int32 URateComponent::GetCount(int32 Index)
{
	return RateStructs[Index].Count;
}

int32 URateComponent::GetCountFromStruct(FRateStruct Struct)
{
	return Struct.Count;
}

void URateComponent::SetCount(int32 NewCount, int32 Index)
{
	RateStructs[Index].Count = NewCount;
}

void URateComponent::SetCountFromStruct(int32 NewCount, FRateStruct& Struct)
{
	Struct.Count = NewCount;
}

int32 URateComponent::IncrementCount(int32 Index)
{
	RateStructs[Index].Count += 1;
	return RateStructs[Index].Count;
}



int32 URateComponent::IncrementCountFromStruct(FRateStruct& Struct)
{
	Struct.Count += 1;
	return Struct.Count;
}

void URateComponent::ResetCount(int32 Index)
{
	RateStructs[Index].Count = 0;
}

void URateComponent::ResetCountFromStruct(FRateStruct& Struct)
{
	Struct.Count = 0;
}

float URateComponent::GetPlusMinusRate(int32 Index)
{
	switch (RateStructs[Index].Count % 2)
	{
	case 0:
	{
		return RateStructs[Index].ConvertedRate;
	}
	case 1:
	{
		return (-1) * RateStructs[Index].ConvertedRate;
	}
	default:
		return RateStructs[Index].ConvertedRate;
	}
}

float URateComponent::GetPlusMinusRateFromStruct(FRateStruct& Struct)
{
	switch (Struct.Count % 2)
	{
	case 0:
	{
		return Struct.ConvertedRate;
	}
	case 1:
	{
		return (-1) * Struct.ConvertedRate;
	}
	default:
		return Struct.ConvertedRate;
	}
}

メンバ変数
RateStructsのみ。
(構造体FRateStructの配列)
FRateStructのメンバ変数
Rate
0から1の間の数をとるfloat型の変数。
Defaulでは0から1に向かって変化。
bCanPlayがOnならば、Tickで数値が変化する。
Direction
型はERateDirection(ここで定義)。
ForwardならRateは0から1に変化。
Backwardなら、1から0に変化。
Duration
Rateが0から1に変わるまでの時間。
Type
RateからConvertedRateに変換する方法の種類。
型は、ここで定義したEnumのEConvertRateType。
Linear:変化は一定。(Rateのまま)
SlowQuick:初めは遅く、だんだん速く変化。
QuickSlow:初めは速く、だんだん遅く変化。
SlowQuickSlow:だんだん速くなり、その後だんだん遅くなる。
QuickSlowQuick:だんだん遅くなり、その後だんだん速くなる。
Power
int32型。数が大きいほど、遅いときと速いときの速度の差が大きい。
2未満の場合はLinearになる。
ConvertedRate
RateをConvertRateの関数で変換したもの。
bCanPlay
bool型。trueならRateが変化。
Rateが1を超えたり、0未満になったときにfalseになる。
bLoop
bool型。trueなら、Rateが変化し続ける。
DirectionがForwardなら、Rateが1を超えるとBackwardに変わる。
DirectionがBackwardなら、Rateが0未満になるとForwardに変わる。
bOnOneRate
bool型。bLoopがtrueのとき、Rateが1を超えるとtrueになる。
BlueprintImprementableEventの代わりとして作成。
bOnZeroRate
bool型。bLoopがtrueのとき、Rateが0未満になるとtrueになる。
BlueprintImprementableEventの代わりとして作成。
bOneStopRate
bool型。bLoopがfalseのとき、Rateが1を超えたり、0未満になるとtrueになる。
BlueprintImprementableEventの代わりとして作成。
Count
int32型。初期値は0。
bLoopがfalseのとき、Rateが0になるたびに1ずつ増加。

メインの関数
PlayRate
Rateを変化させる関数。Tickの中に入れてある。
ConvertRate
Rateを変化する関数。
その他の関数
メンバ変数のGet/Set/Toggle
Structを引数としたものと、ArrayのIndexを引数にしたものを作成した。
GetPlusMinusRate
Countが偶数のときはPlus、奇数のときはMinusに符号が変化したConvertedRate。
PlusMinusRateは-1から1の間の値をとる。

ジップライン

SplineMove

落ちる床

Chikuwa

Kishiro Library

固定軸周りの回転運動に、少しだけ便利な機能が入っているBlueprintLibrary。
これから中身は増やしていく予定。
Ver1.1(https://drive.google.com/file/d/1EN8…)
プラグインはアップロードしていないので、代わりにコードを置いておきます。

// Copyright Epic Games, Inc. All Rights Reserved.

#pragma once

#include "CoreMinimal.h"
#include "Kismet/BlueprintFunctionLibrary.h"
#include "KishiroLibrary.generated.h"

USTRUCT(BlueprintType)
struct FPhysicalRotationStruct
{
	GENERATED_BODY()

		// Key is Start Point of Force.
		// Value is Force.
		UPROPERTY(BlueprintReadWrite)
		TMap<FVector, FVector> ForceMap;

	UPROPERTY(BlueprintReadWrite)
		float Angle = 0;

	UPROPERTY(BlueprintReadWrite)
		float MinAngle = -10;

	UPROPERTY(BlueprintReadWrite)
		float MaxAngle = 10;

	UPROPERTY(BlueprintReadWrite)
		float AngularVelocity = 0;

	UPROPERTY(BlueprintReadWrite)
		float MomentOfInertia = 500;

	UPROPERTY(BlueprintReadWrite)
		float CoefficientOfRestitution = 0.5;

	UPROPERTY(EditDefaultsOnly, BlueprintReadWrite)
		float SleepAngularVelocityThreshold = 0.001;

	UPROPERTY(EditDefaultsOnly, BlueprintReadWrite)
		int32 SleepCounterThreshold = 4;

	UPROPERTY(BlueprintReadWrite)
		bool bCanSleep = false;

	int32 SleepCounter = 0;

	UPROPERTY(BlueprintReadWrite)
		UArrowComponent* Axis = nullptr;

	UPROPERTY(BlueprintReadWrite)
		USceneComponent* Root = nullptr;

};


UCLASS()
class UNREALQUEST1_2_API UKishiroLibrary : public UBlueprintFunctionLibrary
{
	GENERATED_UCLASS_BODY()

		//////////////////////////////////////////////
		///// Physical Rotation 

		UFUNCTION(BlueprintCallable)
		static void AddForceMap(FVector StartPoint, FVector Force, UPARAM(ref) FPhysicalRotationStruct& Struct);

	UFUNCTION(BlueprintCallable, meta = (CompactNodeTitle = "Get Torque"))
		static FVector GetTorqueFromForceMap(FVector Fulcurm, UPARAM(ref) TMap<FVector, FVector>& ForceMap);

	UFUNCTION(BlueprintCallable)
		static FRotator GetRotFromTorque(FVector Torque, float DeltaSec, UPARAM(ref) FPhysicalRotationStruct& Struct);

	UFUNCTION(BlueprintCallable, meta = (CompactNodeTitle = "Get Physical Rotation"))
		static FRotator GetPhysicalRotation(float DeltaSec, UPARAM(ref) FPhysicalRotationStruct& Struct);

	UFUNCTION(BlueprintCallable, meta = (MinAngle = "-10", MaxAngle = "10", MomentOfInertia = "500", Restitution = "0.3", SleepThreshold = "0.001", CounterThreshold = "4"))
		static FRotator InitialSetting(float Angle, float MinAngle, float MaxAngle, float AngularVelocity, float MomentOfInertia, float Restitution, UArrowComponent* Axis, USceneComponent* Root, UPARAM(ref) FPhysicalRotationStruct& Struct);

	UFUNCTION(BlueprintCallable, meta = (CompactNodeTitle = "Add Acceleration"))
		static void AddAcceleration(float Torque, UPARAM(ref) FPhysicalRotationStruct& Struct);

	UFUNCTION(BlueprintCallable, meta = (CompactNodeTitle = "Add Resistance"))
		static void AddResistance(float Resistance, UPARAM(ref) FPhysicalRotationStruct& Struct);

	UFUNCTION(BlueprintCallable, meta = (CompactNodeTitle = "Bounce"))
		static void Bounce(float Restitution, UPARAM(ref) FPhysicalRotationStruct& Struct);

	UFUNCTION(BlueprintCallable)
		static void ResetState(float MinAngle, float MaxAngle, float Restitution, UPARAM(ref) FPhysicalRotationStruct& Struct);

	// Property GetSet
	// Angle

	UFUNCTION(BlueprintPure, meta = (CompactNodeTitle = "Get Angle"))
		static float GetAngle(FPhysicalRotationStruct Struct);

	UFUNCTION(BlueprintCallable, meta = (CompactNodeTitle = "Set Angle"))
		static void SetAngle(float NewAngle, UPARAM(ref) FPhysicalRotationStruct& Struct);

	// Min Angle

	UFUNCTION(BlueprintPure, meta = (CompactNodeTitle = "Get Min"))
		static float GetMinAngle(FPhysicalRotationStruct Struct);

	UFUNCTION(BlueprintCallable, meta = (CompactNodeTitle = "Set Min"))
		static void SetMinAngle(float NewMin, UPARAM(ref) FPhysicalRotationStruct& Struct);

	// Max Angle

	UFUNCTION(BlueprintPure, meta = (CompactNodeTitle = "Get Max"))
		static float GetMaxAngle(FPhysicalRotationStruct Struct);

	UFUNCTION(BlueprintCallable, meta = (CompactNodeTitle = "Set Max"))
		static void SetMaxAngle(float NewMax, UPARAM(ref) FPhysicalRotationStruct& Struct);

	// Angular Velocity

	UFUNCTION(BlueprintPure, meta = (CompactNodeTitle = "Get Velocity"))
		static float GetAngularVelocity(FPhysicalRotationStruct Struct);

	UFUNCTION(BlueprintCallable, meta = (CompactNodeTitle = "Set Velocity"))
		static void SetAngularVelocity(float NewAngularVelocity, UPARAM(ref) FPhysicalRotationStruct& Struct);

	// Moment Of Inertia

	UFUNCTION(BlueprintPure, meta = (CompactNodeTitle = "Get Inertia"))
		static float GetMomentOfInertia(FPhysicalRotationStruct Struct);

	UFUNCTION(BlueprintCallable, meta = (CompactNodeTitle = "Set Inertia"))
		static void SetMomentOfInertia(float NewRestitution, UPARAM(ref) FPhysicalRotationStruct& Struct);

	// Coefficient Of Restitution

	UFUNCTION(BlueprintPure, meta = (CompactNodeTitle = "Get Restitution"))
		static float GetRestitution(FPhysicalRotationStruct Struct);

	UFUNCTION(BlueprintCallable, meta = (CompactNodeTitle = "Set Restitution"))
		static void SetRestitution(float NewRestitution, UPARAM(ref) FPhysicalRotationStruct& Struct);

	// Sleep Angular Velocity Threshold

	UFUNCTION(BlueprintPure, meta = (CompactNodeTitle = "Get Velocity Threshold"))
		static float GetSleepAngularVelocityThreshold(FPhysicalRotationStruct Struct);

	UFUNCTION(BlueprintCallable, meta = (CompactNodeTitle = "Set Velocity Threshold"))
		static void SetSleepAngularVelocityThreshold(float NewThreshold, UPARAM(ref) FPhysicalRotationStruct& Struct);

	// Sleep Counter Threshold

	UFUNCTION(BlueprintPure, meta = (CompactNodeTitle = "Get Counter Threshold"))
		static int32 GetSleepCounterThreshold(FPhysicalRotationStruct Struct);

	UFUNCTION(BlueprintCallable, meta = (CompactNodeTitle = "Set Counter Threshold"))
		static void SetSleepCounterThreshold(int32 NewThreshold, UPARAM(ref) FPhysicalRotationStruct& Struct);

	// Can Sleep

	UFUNCTION(BlueprintPure, meta = (CompactNodeTitle = "Get CanSleep"))
		static bool GetCanSleep(FPhysicalRotationStruct Struct);

	UFUNCTION(BlueprintCallable, meta = (CompactNodeTitle = "Set CanSleep"))
		static void SetCanSleep(bool CanSleep, UPARAM(ref) FPhysicalRotationStruct& Struct);

	//////////////////////////////////////////////
	///// Other Function

	UFUNCTION(BlueprintCallable)
		static FVector GetForceForRotationalMotion(UPrimitiveComponent*& OutTarget, UPrimitiveComponent* Target, FVector CenterLoc, float Intensity, float DeltaSec, bool bAway, bool bNear);


};

// Copyright Epic Games, Inc. All Rights Reserved.


#include "KishiroLibrary.h"
#include <Components/ArrowComponent.h>

UKishiroLibrary::UKishiroLibrary(const FObjectInitializer& ObjectInitializer)
	: Super(ObjectInitializer)
{

}

void UKishiroLibrary::AddForceMap(FVector StartPoint, FVector Force, FPhysicalRotationStruct& Struct)
{
	const FVector* ForcePtr = Struct.ForceMap.Find(StartPoint);
	if (ForcePtr)
	{
		Struct.ForceMap.Add(StartPoint, Force + *ForcePtr);
	}
	else
	{
		Struct.ForceMap.Add(StartPoint, Force);
	}
}

FVector UKishiroLibrary::GetTorqueFromForceMap(FVector Fulcurm, TMap<FVector, FVector>& ForceMap)
{
	FVector Torque = FVector(0, 0, 0);
	TArray<FVector> StartPoints;
	ForceMap.GetKeys(StartPoints);
	int Num = StartPoints.Num();
	for (int32 i = 0; i < Num; i++)
	{
		FVector StartPoint = StartPoints[i];
		FVector Distance = StartPoint - Fulcurm;
		FVector Force = ForceMap[StartPoint];
		Torque += FVector::CrossProduct(Distance, Force);
	}
	ForceMap.Empty();
	return Torque;
}

FRotator UKishiroLibrary::GetRotFromTorque(FVector Torque, float DeltaSec, FPhysicalRotationStruct& Struct)
{
	if (Struct.Axis == nullptr || Struct.Root == nullptr) return FRotator(0, 0, 0);
	float TorqueAroundAxis = FVector::DotProduct(Torque, Struct.Axis->GetForwardVector());

	// Update Angle
	float AngularAcceleration = TorqueAroundAxis / Struct.MomentOfInertia;
	Struct.AngularVelocity += AngularAcceleration * DeltaSec;
	// Sleep
	float LocalAngle = Struct.Angle + Struct.AngularVelocity;
	float LocalVelocity = FMath::Clamp(LocalAngle, Struct.MinAngle, Struct.MaxAngle) - Struct.Angle;
	if (-Struct.SleepAngularVelocityThreshold < LocalVelocity && LocalVelocity < Struct.SleepAngularVelocityThreshold)
	{
		Struct.SleepCounter++;
		if (Struct.SleepCounter > Struct.SleepCounterThreshold)
		{
			Struct.AngularVelocity = 0;
			Struct.bCanSleep = true;
		}
	}
	else
	{
		Struct.SleepCounter = 0;
		Struct.bCanSleep = false;
	}
	Struct.Angle += Struct.AngularVelocity * DeltaSec;

	if (Struct.MinAngle == Struct.MaxAngle)
	{
		if (Struct.Angle < -360) Struct.Angle += 360;
		else if (360 < Struct.Angle) Struct.Angle -= 360;
	}

	// Restitution
	if ((Struct.Angle < Struct.MinAngle || Struct.MaxAngle < Struct.Angle) && (Struct.MaxAngle != Struct.MinAngle))
	{
		Struct.AngularVelocity *= (-1) * Struct.CoefficientOfRestitution;
		Struct.Angle = FMath::Clamp(Struct.Angle, Struct.MinAngle, Struct.MaxAngle);
	}
	// Make Rotation
	FVector AxisVector = Struct.Axis->GetForwardVector();
	FVector FixedAxisVector = (Struct.Root->GetComponentRotation() * (-1)).RotateVector(AxisVector);
	return FQuat(FixedAxisVector, FMath::DegreesToRadians(Struct.Angle)).Rotator();

}

FRotator UKishiroLibrary::GetPhysicalRotation(float DeltaSec, FPhysicalRotationStruct& Struct)
{
	FVector Torque = GetTorqueFromForceMap(Struct.Axis->GetComponentLocation(), Struct.ForceMap);
	return GetRotFromTorque(Torque, DeltaSec, Struct);
}



FRotator UKishiroLibrary::InitialSetting(float Angle, float MinAngle, float MaxAngle, float AngularVelocity, float MomentOfInertia, float Restitution, UArrowComponent* Axis, USceneComponent* Root, FPhysicalRotationStruct& Struct)
{
	Struct.Angle = Angle;
	Struct.MinAngle = MinAngle;
	Struct.MaxAngle = MaxAngle;
	Struct.AngularVelocity = AngularVelocity;
	Struct.MomentOfInertia = MomentOfInertia;
	Struct.CoefficientOfRestitution = Restitution;
	Struct.Axis = Axis;
	Struct.Root = Root;

	FVector AxisVector = (Struct.Root->GetComponentRotation() * (-1)).RotateVector(Struct.Axis->GetForwardVector());
	return FQuat(AxisVector, FMath::DegreesToRadians(Angle)).Rotator();
}

void UKishiroLibrary::AddAcceleration(float Torque, FPhysicalRotationStruct& Struct)
{
	FVector Fulcurm = Struct.Axis->GetComponentLocation();
	FVector StartPoint = Fulcurm + Struct.Axis->GetRightVector() * 100;
	FVector Force = Struct.Axis->GetUpVector() * Torque;
	AddForceMap(StartPoint, Force, Struct);
}

void UKishiroLibrary::AddResistance(float Resistance, FPhysicalRotationStruct& Struct)
{
	float Torque = Resistance * Struct.AngularVelocity * (-1);
	AddAcceleration(Torque, Struct);
}

void UKishiroLibrary::Bounce(float Restitution, FPhysicalRotationStruct& Struct)
{
	Struct.CoefficientOfRestitution = Restitution;
	if (Struct.AngularVelocity > 0)
	{
		Struct.MaxAngle = Struct.Angle;
		Struct.MinAngle = Struct.Angle - 1000;
	}
	else
	{
		Struct.MinAngle = Struct.Angle;
		Struct.MaxAngle = Struct.Angle + 1000;
	}
}

void UKishiroLibrary::ResetState(float MinAngle, float MaxAngle, float Restitution, FPhysicalRotationStruct& Struct)
{
	Struct.MinAngle = MinAngle;
	Struct.MaxAngle = MaxAngle;
	Struct.CoefficientOfRestitution = Restitution;
}

// Angle

float UKishiroLibrary::GetAngle(FPhysicalRotationStruct Struct)
{
	return Struct.Angle;
}

void UKishiroLibrary::SetAngle(float NewAngle, FPhysicalRotationStruct& Struct)
{
	Struct.Angle = NewAngle;
}

// Min Angle

float UKishiroLibrary::GetMinAngle(FPhysicalRotationStruct Struct)
{
	return Struct.MinAngle;
}

void UKishiroLibrary::SetMinAngle(float NewMin, FPhysicalRotationStruct& Struct)
{
	Struct.MinAngle = NewMin;
}

// Max Angle

float UKishiroLibrary::GetMaxAngle(FPhysicalRotationStruct Struct)
{
	return Struct.MaxAngle;
}

void UKishiroLibrary::SetMaxAngle(float NewMax, FPhysicalRotationStruct& Struct)
{
	Struct.MaxAngle = NewMax;
}

// Angular Velocity

float UKishiroLibrary::GetAngularVelocity(FPhysicalRotationStruct Struct)
{
	return Struct.AngularVelocity;
}

void UKishiroLibrary::SetAngularVelocity(float NewAngularVelocity, FPhysicalRotationStruct& Struct)
{
	Struct.AngularVelocity = NewAngularVelocity;
}

// Moment Of Inertia

float UKishiroLibrary::GetMomentOfInertia(FPhysicalRotationStruct Struct)
{
	return Struct.MomentOfInertia;
}

void UKishiroLibrary::SetMomentOfInertia(float NewMomentOfInertia, FPhysicalRotationStruct& Struct)
{
	Struct.MomentOfInertia = NewMomentOfInertia;
}

// Coefficient Of Restitution

float UKishiroLibrary::GetRestitution(FPhysicalRotationStruct Struct)
{
	return Struct.CoefficientOfRestitution;
}

void UKishiroLibrary::SetRestitution(float NewRestitution, FPhysicalRotationStruct& Struct)
{
	Struct.CoefficientOfRestitution = NewRestitution;
}

// Sleep Angular Velocity Threshold

float UKishiroLibrary::GetSleepAngularVelocityThreshold(FPhysicalRotationStruct Struct)
{
	return Struct.SleepAngularVelocityThreshold;
}

void UKishiroLibrary::SetSleepAngularVelocityThreshold(float NewThreshold, FPhysicalRotationStruct& Struct)
{
	Struct.SleepAngularVelocityThreshold = NewThreshold;
}

// Sleep Counter Threshold

int32 UKishiroLibrary::GetSleepCounterThreshold(FPhysicalRotationStruct Struct)
{
	return Struct.SleepCounterThreshold;
}

void UKishiroLibrary::SetSleepCounterThreshold(int32 NewThreshold, FPhysicalRotationStruct& Struct)
{
	Struct.SleepCounterThreshold = NewThreshold;
}

// Can Sleep

bool UKishiroLibrary::GetCanSleep(FPhysicalRotationStruct Struct)
{
	return Struct.bCanSleep;
}

void UKishiroLibrary::SetCanSleep(bool CanSleep, FPhysicalRotationStruct& Struct)
{
	Struct.bCanSleep = CanSleep;
}

FVector UKishiroLibrary::GetForceForRotationalMotion(UPrimitiveComponent*& OutTarget, UPrimitiveComponent* Target, FVector CenterLoc, float Intensity, float DeltaSec, bool bAway, bool bNear)
{
	if (Target == nullptr) return FVector(0, 0, 0);
	OutTarget = Target;
	FVector UnitVecToCenter = (CenterLoc - Target->GetComponentLocation()).GetSafeNormal(0.0001);
	float DotFloat = FVector::DotProduct(UnitVecToCenter, Target->GetComponentVelocity());

	if (DotFloat > 0)
	{
		if (!bNear) DotFloat = 0;
	}
	else
	{
		if (!bAway) DotFloat = 0;
	}

	return UnitVecToCenter * Intensity * DotFloat * DeltaSec * (-3000);

}

Ver1.1
・Get Force for Rotational Motionを追加。

構造体。メンバ関数をまとめる。
Angle:角度。
MinAngle:角度の最小値。
MaxAngle:角度の最大値。
MinAngleとMaxAngleの値が同じときは無限にまわる設定。
Angular Velocity:角速度。
Moment of Inertia:慣性モーメント。角度の変化しづらさを決める。
CoefficientOfRestitution:反発係数の英語を調べたやつ。
SleepAngularVelocityThreshold:角速度がこの値以下になると眠りそうになる。
SleepCounterThreshold:この数値分のTickの間、眠りそうだとbCanSleepがtrueになる。
bCanSleep:寝ることができる状態。角速度は0になる。Tickをfalseに変える条件に使える。
Axis:ArrowComponentを入れる変数。回転の中心に置く。向きは回転軸の方向にする。
Root:RootのReferenceを入れる変数。SceneComponent。

Initial Setting
初期設定をする関数。Construction Scriptなどで使用。

使用例

Add Force Map
力のベクトル(Force)と、そのベクトルの始点を入れたMap。
ベクトルの始点がKeyになっている。同じKeyがあっても問題はない。
Tickの中で使う。
Get Physical Rotation
回転を出力するノード。
Force MapからTorqueを作り、角加速度を出す。
そして、角加速度からRotationを計算。

使用イメージ
使用例。複数のAddMapを関数にまとめている。

Add Acceleration
一定の大きさのTorqueを加える。絶対値が大きいほど加速度が大きくなる。
マイナスにすると逆回転。
Add Resistance
速度に比例したTorqueを加える。空気抵抗のようなもの。
floatの数を大きくすると、抵抗が強くなる。

Bounce
MinAngleとMaxAngleとRestitutionをいじることでバウンドさせる。
Reset State
MinAngleとMaxAngleとRestitutionを設定しなおすことができる。Bounceの後に使うため作成。

使っているうちに問題が出てくると思うのでまとめておく。
複数軸問題
2軸に増やしてみたが上手くいかない。Angleの絶対値が45を超えたところで回転がおかしくなる。
Rotationの計算においてQuaternionを使っているようだが、それが原因かも。
Quaterが4分の1って意味だし関係ありそう。
気が向けば調べてみる。

CombineRotators(ComposeRotators)

FRotator UKismetMathLibrary::ComposeRotators(FRotator A, FRotator B)
{
	FQuat AQuat = FQuat(A);
	FQuat BQuat = FQuat(B);

	return FRotator(BQuat*AQuat);
}

でも、Construction Scriptのこれは45度を超えても正常に回っている。Instance上で回した結果。

ちょっと見た感じ、45度は特別な角度っぽい。計算を追うのは大変そうだけど。

Quaternion を完全に理解した | VirtualCast Blog
バーチャルキャスト公式ブログ。バーチャル...

回転運動の軌道から外れる速度に対して、それを妨げる力を出力する関数。
Awayがtrueだと、外側に外れる速度に対して力を出力。
Nearがtrueだと、内側に外れる速度に対して力を出力。
Intensityには質量を入れておけば、それっぽい動きになるように少しだけ調整してある。

使用例①Character MovementのAddForceに繋げる。
使用例②SimulatePhysicsを適用した物体に対するAddForceと繋げる。

Twitterしてます

ブログの更新をお知らせ

コメント

タイトルとURLをコピーしました