Maya get Mesh Width Height Depth 幅,高さ、奥行きを測る

バウンディングボックスの関数をつかって測る

あくまでMayaの座標系での話だけど、まあ一緒か。

def get_MeshWidthHeightDepth(MeshName):
    boundingBox=cmds.polyEvaluate(MeshName, boundingBox=True )
    print("boundingBox= "+str(boundingBox))
    tapleX=boundingBox[0]
    tapleY=boundingBox[1]
    tapleZ=boundingBox[2]
    
    minX=tapleX[0]
    maxX=tapleX[1]
    depth=maxX-minX
    print("depth= "+str(depth))

    minY=tapleY[0]
    maxY=tapleY[1]
    height=maxY-minY
    print("height= "+str(height))
    
    minZ=tapleZ[0]
    maxZ=tapleZ[1]
    width=maxZ-minZ
    print("width= "+str(width))
    
    return width,height,depth

width,height,depth = get_MeshWidthHeightDepth("pCube2")

Unreal Engine C++ Developer: Learn C++ and Make Video Games | Udemy UE4.26 Simple Shooterで自分なりに理解したこと。01300 ~NavMeshとAIの動き~

NavMeshを配置して

表示できるようにします。

表示されました。

ブラシセッティングで広げます。

BP_ShooterAIControllerを開いてPathFollowingComponentが作用しているからです。

C:\Program Files\Epic Games\UE_4.26\Engine\Source\Runtime\AIModule\Classes\AIController.h

MoveToを見ると

MoveToActor

MoveToLocation

MoveTo

の3つがあります。

	/** AIを指定されたゴールアクターに向けて移動させ(宛先は継続的に更新されます)、
次のアクティブなパスを中止します
* @ paramAcceptanceRadius-ポーンが十分に近づいたら移動を終了します
* @ parambStopOnOverlap-ポーンの半径をAcceptanceRadiusに追加します
* @param bUsePathfinding-ナビゲーションデータを使用してパスを計算します
(そうでない場合は直線になります)
* @param bCanStrafe-フォーカス関連フラグを設定します:bAllowStrafe
* @ paramFilterClass-パスファインディング調整用のナビゲーションフィルター。
指定されていない場合、DefaultNavigationFilterClassが使用されます
* @ parambAllowPartialPath-目標に到達できない場合は不完全なパスを使用します
* @note AcceptanceRadiusは、ヘッダーパーサーが
UPathFollowingComponent :: DefaultAcceptanceRadiusを認識できないため、
デフォルト値または-1になります。*/
	UFUNCTION(BlueprintCallable, Category = "AI|Navigation", Meta = (AdvancedDisplay = "bStopOnOverlap,bCanStrafe,bAllowPartialPath"))
	EPathFollowingRequestResult::Type MoveToActor(AActor* Goal, float AcceptanceRadius = -1, bool bStopOnOverlap = true,
		bool bUsePathfinding = true, bool bCanStrafe = true,
		TSubclassOf<UNavigationQueryFilter> FilterClass = NULL, bool bAllowPartialPath = true);

なので

\ShooterAIController.cpp

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


#include "ShooterAIController.h"

#include "Kismet\GameplayStatics.h"

void AShooterAIController::BeginPlay()
{
    Super::BeginPlay();
    APawn* PlayerPawn= UGameplayStatics::GetPlayerPawn(GetWorld(),0);

    SetFocus(PlayerPawn);
    MoveToActor(PlayerPawn,200);

}

これでプレイしてみると一度動きます。が一度しかついてきません。

C:\Program Files\Epic Games\UE_4.26\Engine\Source\Runtime\Engine\Classes\GameFramework\Actor.h

	virtual void Tick( float DeltaSeconds );

をコピーしてShooterAIController.hにTickをオーバーライドしてこうしました。

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

#pragma once

#include "CoreMinimal.h"
#include "AIController.h"
#include "ShooterAIController.generated.h"

/**
 * 
 */
UCLASS()
class SIMPLESHOOTERCP2_API AShooterAIController : public AAIController
{
	GENERATED_BODY()
public:
	virtual void Tick( float DeltaSeconds ) override;

protected:
	virtual void BeginPlay() override;	
};

C:\Download\Game\SImpleShooter\SImpleShooterCp2 4.26\Source\SImpleShooterCp2\ShooterAIController.cpp

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


#include "ShooterAIController.h"

#include "Kismet\GameplayStatics.h"

void AShooterAIController::BeginPlay()
{
    Super::BeginPlay();
    //APawn* PlayerPawn= UGameplayStatics::GetPlayerPawn(GetWorld(),0);

    
}
void AShooterAIController::Tick(float DeltaSecond)
{
    APawn* PlayerPawn= UGameplayStatics::GetPlayerPawn(GetWorld(),0);
    SetFocus(PlayerPawn);
    MoveToActor(PlayerPawn,200);

}

NavMeshを広げておかないとAIキャラクターが歩きにくいみたいです

できたのがこれ、

AIキャラクターが回転しないバグは次のときに説明するみたい。

Unreal Engine C++ Developer: Learn C++ and Make Video Games | Udemy UE4.26 Simple Shooterで自分なりに理解したこと。01200 ~AI Aimining~

Control + P でAIControllerと入力して

UE_4.26\Engine\Source\Runtime\AIModule\Classes\AIController.h

を開きます。

    /* 特定の優先度にフォーカスアクター設定し、結果としてFocalPointを設定します。*/    virtual void SetFocus(AActor* NewFocus, EAIFocusPriority::Type InPriority = EAIFocusPriority::Gameplay);

/ *特定の優先度にフォーカスアクターを設定し、結果としてFocalPointを設定します。 * /
	/* Set Focus actor for given priority, will set FocalPoint as a result. */
	virtual void SetFocus(AActor* NewFocus, EAIFocusPriority::Type InPriority = EAIFocusPriority::Gameplay);

   

こっちは

指定された優先度のフォーカスをクリアし、結果としてFocalPointもクリアします@paramInPriorityフォーカス優先度をクリアします。 何を使用すればよいかわからない場合は、おそらくEAIFocusPriority :: Gameplay * /を意味します。

  virtual void ClearFocus(EAIFocusPriority::Type InPriority);

	/** 指定された優先度のフォーカスをクリアし、結果としてFocalPointもクリアします
* @paramInPriorityフォーカス優先度をクリアします。 何を使用すればよいかわからない場合は、おそらくEAIFocusPriority :: Gameplay * /を意味します。*/
	virtual void ClearFocus(EAIFocusPriority::Type InPriority);

フォーカスの優先度ってなによってなるので見てみると

その列挙型の定義を見てみると、デフォルトの動きMoveゲームプレイがあることがわかります

そしてそれらは基本的に優先順位の順にリストされています。

//これが通常の列挙型ではなく名前空間である理由は
//ゲーム固有のコードで拡張できるようにする
// @todoこれは少し面倒なので、リファクタリングする必要があります
namespace EAIFocusPriority
{
	typedef uint8 Type;

	const Type Default = 0;
	const Type Move = 1;
	const Type Gameplay = 2;

	const Type LastFocusPriority = Gameplay;
}

struct FFocusKnowledge
{
	struct FFocusItem
	{
		TWeakObjectPtr<AActor> Actor;
		FVector Position;

		FFocusItem()
		{
			Actor = nullptr;
			Position = FAISystem::InvalidLocation;
		}
	};
	
	TArray<FFocusItem> Priorities;
};

私たちは主にこのゲームプレイを使用するので、それらをあまり使用する必要はありませんでした

次に

UE_4.26\Engine\Source\Runtime\Engine\Classes\GameFramework\Actor.h

protected:
	/** Overridable native event for when play begins for this actor. */
	virtual void BeginPlay();

をコピーして

ShooterAIController.hにペーストしてオーバーライドします

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

#pragma once

#include "CoreMinimal.h"
#include "AIController.h"
#include "ShooterAIController.generated.h"

/**
 * 
 */
UCLASS()
class SIMPLESHOOTERCP2_API AShooterAIController : public AAIController
{
	GENERATED_BODY()
protected:
	virtual void BeginPlay() override;	
};

C:\Program Files\Epic Games\UE_4.26\Engine\Source\Runtime\Engine\Classes\Kismet\GameplayStatics.h

	/** 指定されたプレーヤーインデックスのプレーヤーポーンを返します */
	UFUNCTION(BlueprintPure, Category="Game", meta=(WorldContext="WorldContextObject", UnsafeDuringActorConstruction="true"))
	static class APawn* GetPlayerPawn(const UObject* WorldContextObject, int32 PlayerIndex);

をみると指定されたプレーヤーインデックスのプレーヤーポーンを返しますので

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


#include "ShooterAIController.h"

#include "Kismet\GameplayStatics.h"

void AShooterAIController::BeginPlay()
{
    Super::BeginPlay();
    APawn* PlayerPawn= UGameplayStatics::GetPlayerPawn(GetWorld(),0);

    SetFocus(PlayerPawn);

}

できたのがこれ

Unreal Engine C++ Developer: Learn C++ and Make Video Games | Udemy UE4.25 Simple Shooterで自分なりに理解したこと。01100 ~AIコントローラーを作成してセットアップ~

新規C++クラスを作る 親クラスにAIコントローラーを選ぶ

名前は ShooterAIController

このクラスを使ってブループリントクラスを作る

名前を BP_ShooterAIController

BP_ShooterCharacterを開いて ポーンのAI ContrallerClassにBP_ShooterAIControllerを設定

実行してBP_ShooterAIControllerがポーンされてるか確認する。

#UnrealEngine #UE5 #UE4 #Python .uassetを強引にバイナリファイルとして開いてテキストファイルとして保存してエンコーディングエラーやbytesからストリング変換エラーをうやむやにして文字列としてロード

    def assetPath_to_HDpath(self,assetPath):
        get_project_file_path=unreal.Paths.get_project_file_path()
        HD_get_project_file_path=os.path.abspath(get_project_file_path)
        project_file_dir=os.path.dirname(HD_get_project_file_path)
        project_file_dir=project_file_dir.replace("\\","/")
        unreal.log_warning("project_file_dir= "+project_file_dir)
        # /Game/
        assetHDPath=project_file_dir+"/Content"+assetPath[5:]
        assetHDPath_without_ext = os.path.splitext(assetHDPath)[0]
        assetHDPath_uasset=assetHDPath_without_ext+".uasset"
        unreal.log_warning("assetHDPath_uasset= "+assetHDPath_uasset)
        
        #print("")
        return assetHDPath_uasset
    
    def uasset_textFile_read(self,path):
        file = open(path, 'rb')
        #file = open(path, encoding="utf8", errors='ignore')
        print("1 binary open!!")
        BytesDataBox=b""
        BytesDataStr=u""
        #BytesDataStr = file.read()
        #print("BytesDataStr="+BytesDataStr)
        bytes = file.read(1)
        #print("2 binary valiabled!!")
        while bytes:
            #print(bytes)
            #print("2 printed!!")
            BytesDataBox = BytesDataBox+bytes
            #print("2 BytesDataBox added !!")
            #decoded=bytes.decode("utf-8") 
            #print("2 decoded!!")
            #print(decoded)
            #print("2 decoded printed!!")
            #ByteDataBox=ByteDataBox+decoded
            #print("2 ByteDataBox insert!!")
            bytes = file.read(1)
            #print("2 byte = file.read(1)!!")
        
        print("3 while byte end!!")
        print("BytesDataBox= ")
        #print(BytesDataBox)
        print("4 printed!!")
        print(type(BytesDataBox))
        print("4 class printed!!")
        BytesDataBox=BytesDataBox.strip()
        print("4 striped!!")
        file.close() 
        #BytesDataStr = str(BytesDataBox, 'utf-8')
        #BytesDataStr=BytesDataBox.decode(encoding ='utf-8', errors='ignore')
        self.fileWrite_byte(BytesDataBox)
        BytesDataStr=self.fileRead_byte_()
        print("4 decoded!!")
        

        pattern = r'/Game/.*?\\'

        # findall 
        results = re.findall(pattern, BytesDataStr, re.S)
        results_len=len(results)
        print("results_len= "+str(results_len))
        # Type:list
        print(type(results))
        print("4 all hit list printed!!")
        # 抽出
        for result in results:
            result_len=len(result)
            good_result=result[0:result_len-1]
            print("result_len= "+str(result_len)+"     good_result= "+ good_result)
        
        print("4 for printed!!")
        
    def fileWrite_byte(self,s):
        ReportFolderPath=self.getMyDir()+"Report"
        self.my_makedirs(ReportFolderPath)
        path_cp=ReportFolderPath+"/bytes_"+".txt"
        
        fout_utf = codecs.open(path_cp, 'w', encoding='cp932')
        fout_utf.write(s)
    def fileRead_byte_(self):
        ReportFolderPath=self.getMyDir()+"Report"
        self.my_makedirs(ReportFolderPath)
        path_cp=ReportFolderPath+"/bytes_"+".txt"
        
        fout_utf = codecs.open(path_cp, 'r', encoding='cp932')
        data=fout_utf.read()
        print("4 data!!="+data)
        return data

#UE4 #UE4Study #UE5 #UE5Study #UnrealEngineのPythonScriptPluginのpython3へのPyside2のインストール方法

Pyside2はpipを使ってインストールするのが基本です。

https://forums.unrealengine.com/t/fyi-ue4-switching-to-python-3-7-7-by-default-4-26/151803

より

C:\Program Files\Epic Games\UE_4.26\Engine\Plugins\Experimental\PythonScriptPlugin\Source\PythonScriptPluginPreload\PythonScriptPluginPreload.Build.csで

// Copyright Epic Games, Inc. All Rights Reserved.
using UnrealBuildTool;

namespace UnrealBuildTool.Rules
{
	public class PythonScriptPluginPreload : ModuleRules
	{
		public PythonScriptPluginPreload(ReadOnlyTargetRules Target) : base(Target)
		{
			PublicDependencyModuleNames.AddRange(
				new string[] {
					"Core",
				}
			);

			if (Target.bBuildEditor)
			{
				PrivateIncludePathModuleNames.AddRange(
					new string[] {
						"Python3",
					}
				);
			}
			else
			{
				PrivateDefinitions.Add("WITH_PYTHON=0");
			}
		}
	}
}

となっているのでPython3を参照しているので

::python.exeへ移動して
cd C:\Program Files\Epic Games\UE_4.26\Engine\Binaries\ThirdParty\Python3\Win64
::pip install Pyside2というかんじで詳細はこのようにインストール
python -m pip install --target="C:\Program Files\Epic Games\UE_4.26\Engine\Binaries\ThirdParty\Python3\Win64\Lib\site-packages" Pyside2


するとローカルではうまく起動しました。

参考URL
https://qiita.com/7CIT/items/a480a84bb9d249544f5f

プラグインを有効にする感じのやり方もあります。
Python Editor¥3,177 これをインストールしてしまえば使えるようです。
https://www.unrealengine.com/marketplace/ja/product/python-editor?sessionInvalidated=true

参照

Unreal Engine C++ Developer: Learn C++ and Make Video Games | Udemy UE4.25 Simple Shooterで自分なりに理解したこと。01000 ~ブループリント純粋関数ノードを作る ~


彼が死ぬまでこのキャラクターを撃つことができるようになったので

アニメーションBPのこのブール値をゲームプレイから自動的に設定する必要があります。

UFUNCTION()マクロ
UFUNCTION(BluePrintCallable)//ブループリント呼び出し可能。
UFUNCTION(BluePrintPure)純粋ノード

それがブループリント呼び出し可能の実行ピンがある関数か、

それがブループリントピュア=純粋ノードで実行ピンが必要ない関数です。

ShooterCharacter.h

public:	
	UFUNCTION(BluePrintPure)
	bool IsDead() const;

ShooterCharacter.cpp

bool AShooterCharacter::IsDead() const
{
	return Health <= 0;
}

ブループリントで見てみると IsDead純粋関数としてノードが作られました。

ShooterCharacter.h 全文

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

#pragma once

#include "CoreMinimal.h"
#include "GameFramework/Character.h"
#include "ShooterCharacter.generated.h"

class AGun;


UCLASS()
class SIMPLESHOOTERCP2_API AShooterCharacter : public ACharacter
{
	GENERATED_BODY()

public:
	// Sets default values for this character's properties
	AShooterCharacter();

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

public:	
	UFUNCTION(BluePrintPure)
	bool IsDead() const;

	// Called every frame
	virtual void Tick(float DeltaTime) override;

	// Called to bind functionality to input
	virtual void SetupPlayerInputComponent(class UInputComponent* PlayerInputComponent) override;
	
	virtual float TakeDamage(float DamageAmount, struct FDamageEvent const& DamageEvent, class AController* EventInstigator, AActor* DamageCauser) override;

private:
	void MoveForward(float AxisValue);
	void MoveRight(float AxisValue);
	void LockUpRate(float AxisValue);
	void LockRightRate(float AxisValue);
	void Shoot();
	
	UPROPERTY(EditAnyWhere)
	float RotationRate = 10;

	UPROPERTY(EditDefaultsOnly)
	float MaxHealth=100;

	UPROPERTY(VisibleAnyWhere)
	float Health;

	UPROPERTY(EditDefaultsOnly)
	TSubclassOf<AGun> GunClass;

	UPROPERTY()
	AGun* Gun;


};

ShooterCharacter.cpp

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


#include "ShooterCharacter.h"
#include "Gun.h"
//#include "Engine/Engine.h"
// Sets default values
AShooterCharacter::AShooterCharacter()
{
 	// Set this character to call Tick() every frame.  You can turn this off to improve performance if you don't need it.
	PrimaryActorTick.bCanEverTick = true;

}

// Called when the game starts or when spawned
void AShooterCharacter::BeginPlay()
{
	Super::BeginPlay();
	
	Health = MaxHealth;

	Gun = GetWorld()->SpawnActor<AGun>(GunClass);
	GetMesh()->HideBoneByName(TEXT("weapon_r"),EPhysBodyOp::PBO_None );
	Gun->AttachToComponent(GetMesh(), FAttachmentTransformRules::KeepRelativeTransform, TEXT("weaponSocket"));
	Gun->SetOwner(this);
}
bool AShooterCharacter::IsDead() const
{
	return Health <= 0;
}
// Called every frame
void AShooterCharacter::Tick(float DeltaTime)
{
	Super::Tick(DeltaTime);

}

void AShooterCharacter::Shoot()
{
	Gun->PullTrigger();
}

// Called to bind functionality to input
void AShooterCharacter::SetupPlayerInputComponent(UInputComponent* PlayerInputComponent)
{
	Super::SetupPlayerInputComponent(PlayerInputComponent);

	PlayerInputComponent ->BindAxis(TEXT("MoveForward"),this,&AShooterCharacter::MoveForward);
	PlayerInputComponent ->BindAxis(TEXT("LockUp"),this,&APawn::AddControllerPitchInput);
	PlayerInputComponent ->BindAxis(TEXT("MoveRight"),this,&AShooterCharacter::MoveRight);
	PlayerInputComponent ->BindAxis(TEXT("LockRight"),this,&APawn::AddControllerYawInput);
	PlayerInputComponent ->BindAxis(TEXT("LockUpRate"),this,&AShooterCharacter::LockUpRate);
	PlayerInputComponent ->BindAxis(TEXT("LockRightRate"),this,&AShooterCharacter::LockRightRate);
	PlayerInputComponent ->BindAction(TEXT("Jump"),EInputEvent::IE_Pressed,this,&ACharacter::Jump);
	PlayerInputComponent ->BindAction(TEXT("Shoot"),EInputEvent::IE_Pressed,this,&AShooterCharacter::Shoot);
}

float AShooterCharacter::TakeDamage(float DamageAmount, struct FDamageEvent const& DamageEvent, class AController* EventInstigator, AActor* DamageCauser)
{
	float DamageToApply = Super::TakeDamage(DamageAmount,DamageEvent,EventInstigator,DamageCauser);
	DamageToApply = FMath::Min(Health,DamageToApply);
	Health -= DamageToApply;
	UE_LOG(LogTemp,Display,TEXT("Health Left %F"),Health);
	float TimeToDisplay =5.0f;
	FString Health_str = FString::SanitizeFloat(Health);
	FString TestHUDString =TEXT("Health Left")+	Health_str;
	GEngine->AddOnScreenDebugMessage(-1,TimeToDisplay,FColor::Green,TestHUDString);
	return DamageToApply;
}

void AShooterCharacter::MoveForward(float AxisValue)
{
	AddMovementInput(GetActorForwardVector() * AxisValue);
}
void AShooterCharacter::MoveRight(float AxisValue)
{
	AddMovementInput(GetActorRightVector() * AxisValue);
}

void AShooterCharacter::LockUpRate(float AxisValue)
{
	AddControllerPitchInput(AxisValue * RotationRate * GetWorld()->GetDeltaSeconds());
}
void AShooterCharacter::LockRightRate(float AxisValue)
{
	AddControllerYawInput(AxisValue * RotationRate * GetWorld()->GetDeltaSeconds());
}
// void AShooterCharacter::LockUp(float AxisValue)
// {
// 	AddControllerPitchInput(AxisValue);
// }

できたのがこれ

Unreal Engine C++ Developer: Learn C++ and Make Video Games | Udemy UE4.25 Simple Shooterで自分なりに理解したこと。00800 ~TakeDamageのオーバーライド ~

基本的にはデフォルトのTakeDamageが来た時に処理を追加したいのでオーバーライドします。

UE4/Engine/Sounce/Runtime/Engine/Classes/GameFramework/Actor.h

virtual float TakeDamage(float DamageAmount, struct FDamageEvent const& DamageEvent, class AController* EventInstigator, AActor* DamageCauser);
をコピーして

ShooterCharacter.h

にこれをペーストしてoverrideキーワードを追加しました。
    virtual float TakeDamage(float DamageAmount, struct FDamageEvent const& DamageEvent, class AController* EventInstigator, AActor* DamageCauser) override;

ShooterCharacter.cppはこうやって元のSuper::TakeDamegeを追加します

float AShooterCharacter::TakeDamage(float DamageAmount, struct FDamageEvent const& DamageEvent, class AController* EventInstigator, AActor* DamageCauser) ;
{
	float DamageApplied = Super::TakeDamage(DamageAmount,DamageEvent,EventInstigator,DamageCauser);
	
}

次に、ダメージを受けた時のヒットポイントを健康状態のとしてHealth変数を用意します。

ShooterCharacter.h

	UPROPERTY(EditDefaultsOnly)
	float MaxHealth=100;

	UPROPERTY(VisibleAnyWhere)
	float Health;

ShooterCharacter.cppでBeginPlayにHealth = MaxHealth;追加

void AShooterCharacter::BeginPlay()
{
	Super::BeginPlay();
	
	Health = MaxHealth;

	Gun = GetWorld()->SpawnActor<AGun>(GunClass);
	GetMesh()->HideBoneByName(TEXT("weapon_r"),EPhysBodyOp::PBO_None );
	Gun->AttachToComponent(GetMesh(), FAttachmentTransformRules::KeepRelativeTransform, TEXT("weaponSocket"));
	Gun->SetOwner(this);
}

ShooterCharacter.cppでTakeDamageに以下追加

DamageToApply = FMath::Min(Health,DamageToApply);   
Health -= DamageToApply;   
UE_LOG(LogTemp,Display,TEXT(“Health Left %F”),Health);

float TimeToDisplay =5.0f;   
FString Health_str = FString::SanitizeFloat(Health);   
(\UE_4.25\Engine\Source\Runtime\Core\Private\Containers\String.cppにある)
FString TestHUDString =TEXT(“Health Left”)+ Health_str;   

GEngine->AddOnScreenDebugMessage(-1,TimeToDisplay,FColor::Green,TestHUDString);
(\UE_4.25\Engine\Source\Runtime\Engine\Private\UnrealEngine.cppにある)
詳細は以下
FString | UnrealEngineのドキュメント

https://docs.unrealengine.com/4.27/ja/ProgrammingAndScripting/ProgrammingWithCPP/UnrealArchitecture/StringHandling/FString/

return DamageToApply;

float AShooterCharacter::TakeDamage(float DamageAmount, struct FDamageEvent const& DamageEvent, class AController* EventInstigator, AActor* DamageCauser)
{
	float DamageToApply = Super::TakeDamage(DamageAmount,DamageEvent,EventInstigator,DamageCauser);
	DamageToApply = FMath::Min(Health,DamageToApply);
	Health -= DamageToApply;
	UE_LOG(LogTemp,Display,TEXT("Health Left %F"),Health);
	float TimeToDisplay =5.0;
	FString Health_str = FString::SanitizeFloat(Health);
	FString TestHUDString =TEXT("Health Left")+	Health_str;
	GEngine->AddOnScreenDebugMessage(-1,TimeToDisplay,FColor::Green,TestHUDString);
	return DamageToApply;
}

ShooterCharacter.h 全文

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

#pragma once

#include "CoreMinimal.h"
#include "GameFramework/Character.h"
#include "ShooterCharacter.generated.h"

class AGun;


UCLASS()
class SIMPLESHOOTERCP2_API AShooterCharacter : public ACharacter
{
	GENERATED_BODY()

public:
	// Sets default values for this character's properties
	AShooterCharacter();

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

public:	
	// Called every frame
	virtual void Tick(float DeltaTime) override;

	// Called to bind functionality to input
	virtual void SetupPlayerInputComponent(class UInputComponent* PlayerInputComponent) override;
	
	virtual float TakeDamage(float DamageAmount, struct FDamageEvent const& DamageEvent, class AController* EventInstigator, AActor* DamageCauser) override;

private:
	void MoveForward(float AxisValue);
	void MoveRight(float AxisValue);
	void LockUpRate(float AxisValue);
	void LockRightRate(float AxisValue);
	void Shoot();
	
	UPROPERTY(EditAnyWhere)
	float RotationRate = 10;

	UPROPERTY(EditDefaultsOnly)
	float MaxHealth=100;

	UPROPERTY(VisibleAnyWhere)
	float Health;

	UPROPERTY(EditDefaultsOnly)
	TSubclassOf<AGun> GunClass;

	UPROPERTY()
	AGun* Gun;


};

ShooterCharacter.cpp 全文

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


#include "ShooterCharacter.h"
#include "Gun.h"
//#include "Engine/Engine.h"
// Sets default values
AShooterCharacter::AShooterCharacter()
{
 	// Set this character to call Tick() every frame.  You can turn this off to improve performance if you don't need it.
	PrimaryActorTick.bCanEverTick = true;

}

// Called when the game starts or when spawned
void AShooterCharacter::BeginPlay()
{
	Super::BeginPlay();
	
	Health = MaxHealth;

	Gun = GetWorld()->SpawnActor<AGun>(GunClass);
	GetMesh()->HideBoneByName(TEXT("weapon_r"),EPhysBodyOp::PBO_None );
	Gun->AttachToComponent(GetMesh(), FAttachmentTransformRules::KeepRelativeTransform, TEXT("weaponSocket"));
	Gun->SetOwner(this);
}

// Called every frame
void AShooterCharacter::Tick(float DeltaTime)
{
	Super::Tick(DeltaTime);

}

void AShooterCharacter::Shoot()
{
	Gun->PullTrigger();
}

// Called to bind functionality to input
void AShooterCharacter::SetupPlayerInputComponent(UInputComponent* PlayerInputComponent)
{
	Super::SetupPlayerInputComponent(PlayerInputComponent);

	PlayerInputComponent ->BindAxis(TEXT("MoveForward"),this,&AShooterCharacter::MoveForward);
	PlayerInputComponent ->BindAxis(TEXT("LockUp"),this,&APawn::AddControllerPitchInput);
	PlayerInputComponent ->BindAxis(TEXT("MoveRight"),this,&AShooterCharacter::MoveRight);
	PlayerInputComponent ->BindAxis(TEXT("LockRight"),this,&APawn::AddControllerYawInput);
	PlayerInputComponent ->BindAxis(TEXT("LockUpRate"),this,&AShooterCharacter::LockUpRate);
	PlayerInputComponent ->BindAxis(TEXT("LockRightRate"),this,&AShooterCharacter::LockRightRate);
	PlayerInputComponent ->BindAction(TEXT("Jump"),EInputEvent::IE_Pressed,this,&ACharacter::Jump);
	PlayerInputComponent ->BindAction(TEXT("Shoot"),EInputEvent::IE_Pressed,this,&AShooterCharacter::Shoot);
}

float AShooterCharacter::TakeDamage(float DamageAmount, struct FDamageEvent const& DamageEvent, class AController* EventInstigator, AActor* DamageCauser)
{
	float DamageToApply = Super::TakeDamage(DamageAmount,DamageEvent,EventInstigator,DamageCauser);
	DamageToApply = FMath::Min(Health,DamageToApply);
	Health -= DamageToApply;
	UE_LOG(LogTemp,Display,TEXT("Health Left %F"),Health);
	float TimeToDisplay =5.0f;
	FString Health_str = FString::SanitizeFloat(Health);
	FString TestHUDString =TEXT("Health Left")+	Health_str;
	GEngine->AddOnScreenDebugMessage(-1,TimeToDisplay,FColor::Green,TestHUDString);
	return DamageToApply;
}

void AShooterCharacter::MoveForward(float AxisValue)
{
	AddMovementInput(GetActorForwardVector() * AxisValue);
}
void AShooterCharacter::MoveRight(float AxisValue)
{
	AddMovementInput(GetActorRightVector() * AxisValue);
}

void AShooterCharacter::LockUpRate(float AxisValue)
{
	AddControllerPitchInput(AxisValue * RotationRate * GetWorld()->GetDeltaSeconds());
}
void AShooterCharacter::LockRightRate(float AxisValue)
{
	AddControllerYawInput(AxisValue * RotationRate * GetWorld()->GetDeltaSeconds());
}
// void AShooterCharacter::LockUp(float AxisValue)
// {
// 	AddControllerPitchInput(AxisValue);
// }

こうなった。

maya PythonのOpenMaya の Vector で任意の座標からもっとも近い線分上の点を求める

こんな感じの状態、

# -*- coding: utf-8 -*-
import maya.cmds as cmds
from maya import OpenMaya
#任意の1点と線分の両端の座標から線分上のもっとも近い点を返す
def xGetClosestPoint(myPoint, begin, end):
    myVector3D = OpenMaya.MVector(myPoint[0] - begin[0], myPoint[1] - begin[1], myPoint[2] - begin[2])
    baseVector3D = OpenMaya.MVector(end[0] - begin[0], end[1] - begin[1], end[2] - begin[2])
    nDotProduct = myVector3D * baseVector3D
    print("nDotProduct= "+str(nDotProduct))
    if (nDotProduct > 0):
        print("Big if")
        nBaseLength = baseVector3D.length()
        print("nBaseLength= "+str(nBaseLength))
        nProjection = nDotProduct / nBaseLength
        
        if (nProjection < nBaseLength):
            print("small if")
            scaleValue = nProjection / nBaseLength
            print("scaleValue= "+str(scaleValue))
            baseVector3D = baseVector3D * scaleValue
            
            return [begin[0] + baseVector3D[0], begin[1] + baseVector3D[1], begin[2] + baseVector3D[2]]
        else:
            print("small else")
            return end

    else:
        print("Big else")
        return begin;
    

sel = cmds.ls(sl =True)

# get Translate
start = cmds.xform(sel[0],q=1 ,ws =True,t=True)
mid = cmds.xform(sel[1],q=1 ,ws =True,t=True)
end = cmds.xform(sel[2],q=1 ,ws =True,t=True)

# Vector for Translate
#startV = OpenMaya.MVector(start[0] ,start[1],start[2])
#midV = OpenMaya.MVector(mid[0] ,mid[1],mid[2])
#midV = OpenMaya.MVector(end[0] ,end[1],end[2])

c_vPos = xGetClosestPoint(mid, start, end)
cmds.xform("pSphere1",ws =True,translation=(c_vPos[0], c_vPos[1], c_vPos[2]) )

線状に乗った!!

参考URL

野中文雄先生の任意の座標からもっとも近い線分上の点を求める

http://www.fumiononaka.com/TechNotes/Flash/FN1104002.html

MAYAチュートリアル:Pythonで極ベクトルを正しく配置する方法