サンプルプログラム アニメーションによる座標移動 + 方向入力によるキャラクター移動( カメラ固定 )

アニメーションによる座標移動 + 方向入力によるキャラクター移動( カメラ固定 )

 『アニメーションによる座標移動』はプログラムの簡略化のために実際にアニメーションによる移動値を使って
入力に沿った方向に移動するプログラムとなっていなかったので、『方向入力によるキャラクター移動( カメラ固定 )』と
組み合わせて入力した方向への移動にアニメーションによる移動値を使用するようにしたのがこちらのサンプルです。

 ( プログラムの実行に必要なファイルはこちら )


// アニメーションによる座標移動 + 方向入力によるキャラクター移動( カメラ固定 )

#include "DxLib.h"
#include <math.h>

// DxChara.x での走りアニメーションの番号
#define ANIM_RUN		1

// DxChara.x での待機アニメーションの番号
#define ANIM_NEUTRAL		4

int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow )
{
	int    ModelHandle ;
	float  AnimTotalTime ;
	float  AnimNowTime ;
	int    AnimAttachIndex ;
	int    RunFlag ;
	int    MoveAnimFrameIndex ;
	VECTOR Position ;
	int    Input ;
	int    MoveFlag ;
	float  Angle ;
	VECTOR PrevPosition ;
	VECTOR NowPosition ;
	VECTOR MoveVector ;
	float  SinParam ;
	float  CosParam ;

	// ウインドウモードで起動
	ChangeWindowMode( TRUE ) ;

	// DXライブラリの初期化
	if( DxLib_Init() < 0 ) return -1 ;

	// 3Dモデルの読み込み
	ModelHandle = MV1LoadModel( "DxChara.x" ) ;

	// 向きを初期化
	Angle = 0.0f ;

	// 走っているフラグを倒す
	RunFlag = FALSE ;

	// 待機アニメーションをアタッチ
	AnimAttachIndex = MV1AttachAnim( ModelHandle, ANIM_NEUTRAL ) ;

	// 待機アニメーションの総時間を取得しておく
	AnimTotalTime = MV1GetAttachAnimTotalTime( ModelHandle, AnimAttachIndex ) ;

	// アニメーション再生時間を初期化
	AnimNowTime = 0.0f ;
	MV1SetAttachAnimTime( ModelHandle, AnimAttachIndex, AnimNowTime ) ;

	// アニメーションで移動をしているフレームの番号を検索する
	MoveAnimFrameIndex = MV1SearchFrame( ModelHandle, "BasePoint" ) ;

	// アニメーションで移動をしているフレームを無効にする
	MV1SetFrameUserLocalMatrix( ModelHandle, MoveAnimFrameIndex, MV1GetFrameLocalMatrix( ModelHandle, MoveAnimFrameIndex ) ) ;

	// 3Dモデルの座標を初期化
	Position = VGet( 0.0f, 0.0f, 0.0f ) ;

	// 描画先を裏画面にする
	SetDrawScreen( DX_SCREEN_BACK ) ;

	// カメラの位置と向きを設定
	SetCameraPositionAndTarget_UpVecY( VGet( 0.0f, 1200.0f, -2000.0f ), VGet( 0.0f, 400.0f, 0.0f ) );

	// カメラのクリッピング距離を設定
	SetCameraNearFar( 16.0f, 5000.0f );

	// 背景の色を灰色にする
	SetBackgroundColor( 128, 128, 128 ) ;

	// メインループ(何かキーが押されたらループを抜ける)
	while( ProcessMessage() == 0 )
	{
		// 画面のクリア
		ClearDrawScreen() ;

		// ゲームパッド+キーボードの入力を取得
		Input = GetJoypadInputState( DX_INPUT_KEY_PAD1 ) ;

		// 移動しているかどうかのフラグを倒す
		MoveFlag = FALSE ;

		// 方向入力の判定
		// ( 最初に斜め入力の判定を、その後上下左右単体の入力の判定をしています )
		if( ( Input & PAD_INPUT_LEFT ) != 0 && ( Input & PAD_INPUT_UP ) != 0 )
		{
			Angle       = 135.0f ;
			MoveFlag    = TRUE ;
		}
		else
		if( ( Input & PAD_INPUT_UP ) != 0 && ( Input & PAD_INPUT_RIGHT ) != 0 )
		{
			Angle       = -135.0f ;
			MoveFlag    = TRUE ;
		}
		else
		if( ( Input & PAD_INPUT_RIGHT ) != 0 && ( Input & PAD_INPUT_DOWN ) != 0 )
		{
			Angle       = -45.0f ;
			MoveFlag    = TRUE ;
		}
		else
		if( ( Input & PAD_INPUT_DOWN ) != 0 && ( Input & PAD_INPUT_LEFT ) != 0 )
		{
			Angle       = 45.0f ;
			MoveFlag    = TRUE ;
		}
		else
		if( ( Input & PAD_INPUT_LEFT ) != 0 )
		{
			Angle       = 90.0f ;
			MoveFlag    = TRUE ;
		}
		else
		if( ( Input & PAD_INPUT_RIGHT ) != 0 )
		{
			Angle       = -90.0f ;
			MoveFlag    = TRUE ;
		}
		else
		if( ( Input & PAD_INPUT_DOWN ) != 0 )
		{
			Angle       = 0.0f ;
			MoveFlag    = TRUE ;
		}
		else
		if( ( Input & PAD_INPUT_UP ) != 0 )
		{
			Angle       = 180.0f ;
			MoveFlag    = TRUE ;
		}

		// 今までと状態が変化した場合はアニメーションを変更する
		if( RunFlag != MoveFlag )
		{
			// 走っているかどうかのフラグを保存
			RunFlag = MoveFlag ;

			// 今までアタッチしていたアニメーションをデタッチ
			MV1DetachAnim( ModelHandle, AnimAttachIndex ) ;

			// 新しいアニメーションをアタッチ
			if( RunFlag )
			{
				AnimAttachIndex = MV1AttachAnim( ModelHandle, ANIM_RUN ) ;
			}
			else
			{
				AnimAttachIndex = MV1AttachAnim( ModelHandle, ANIM_NEUTRAL ) ;
			}

			// アニメーションの総時間を取得しておく
			AnimTotalTime = MV1GetAttachAnimTotalTime( ModelHandle, AnimAttachIndex ) ;

			// アニメーション再生時間を初期化
			AnimNowTime = 0.0f ;
			MV1SetAttachAnimTime( ModelHandle, AnimAttachIndex, AnimNowTime ) ;
		}

		// アニメーション時間を進める前の『アニメーションで移動をしているフレームの座標』を取得しておく
		PrevPosition = MV1GetAttachAnimFrameLocalPosition( ModelHandle, AnimAttachIndex, MoveAnimFrameIndex ) ;

		// アニメーション再生時間を進める
		AnimNowTime += 200.0f ;

		// アニメーション再生時間がアニメーションの総時間を越えているかどうかで処理を分岐
		if( AnimNowTime >= AnimTotalTime )
		{
			// 超えている場合は、まず『アニメーション再生時間を進める前の「アニメーションで移動しているフレームの座標」』と、
			// 『アニメーションの終端での「アニメーションで移動しているフレームの座標」』との差分を移動ベクトルとする
			MV1SetAttachAnimTime( ModelHandle, AnimAttachIndex, AnimTotalTime ) ;
			NowPosition = MV1GetAttachAnimFrameLocalPosition( ModelHandle, AnimAttachIndex, MoveAnimFrameIndex ) ;
			MoveVector = VSub( NowPosition, PrevPosition ) ;

			// 新しいアニメーション再生時間は、アニメーション再生時間からアニメーション総時間を引いたもの
			AnimNowTime -= AnimTotalTime ;

			// 次に『新しいアニメーション再生時間での「アニメーションで移動をしているフレームの座標」と
			// 『アニメーション再生時間0での「アニメーションで移動しているフレームの座標」』との差分を移動ベクトルに加算する
			MV1SetAttachAnimTime( ModelHandle, AnimAttachIndex, 0.0f ) ;
			PrevPosition = MV1GetAttachAnimFrameLocalPosition( ModelHandle, AnimAttachIndex, MoveAnimFrameIndex ) ;
			MV1SetAttachAnimTime( ModelHandle, AnimAttachIndex, AnimNowTime ) ;
			NowPosition = MV1GetAttachAnimFrameLocalPosition( ModelHandle, AnimAttachIndex, MoveAnimFrameIndex ) ;
			MoveVector = VAdd( MoveVector, VSub( NowPosition, PrevPosition ) ) ;
		}
		else
		{
			// 新しいアニメーション再生時間をセット
			MV1SetAttachAnimTime( ModelHandle, AnimAttachIndex, AnimNowTime ) ;

			// 『新しいアニメーション再生時間での「アニメーションで移動をしているフレームの座標」』と、
			// 『アニメーション再生時間を進める前の「アニメーションで移動をしているフレームの座標」』との差分を移動ベクトルとする
			NowPosition = MV1GetAttachAnimFrameLocalPosition( ModelHandle, AnimAttachIndex, MoveAnimFrameIndex ) ;
			MoveVector = VSub( NowPosition, PrevPosition ) ;
		}

		// キャラクターの向きに合わせて移動ベクトルの角度を回転させて、キャラクターモデルの座標に加算
		SinParam = sin( -Angle / 180.0f * DX_PI_F ) ;
		CosParam = cos( -Angle / 180.0f * DX_PI_F ) ;
		Position.x += MoveVector.x * CosParam - MoveVector.z * SinParam ;
		Position.z += MoveVector.x * SinParam + MoveVector.z * CosParam ;

		// 3Dモデルに新しい座標をセット
		MV1SetPosition( ModelHandle, Position ) ;

		// 新しい向きをセット
		MV1SetRotationXYZ( ModelHandle, VGet( 0.0f, Angle / 180.0f * DX_PI_F, 0.0f ) ) ;

		// 3Dモデルの描画
		MV1DrawModel( ModelHandle ) ;

		// 裏画面の内容を表画面に反映
		ScreenFlip() ;
	}

	// DXライブラリの後始末
	DxLib_End() ;

	// ソフトの終了
	return 0 ;
}

戻る