サンプルプログラム キャラクターに付いていくカメラ

キャラクターに付いていくカメラ

 3Dのゲームといえば、殆どの場合に視点( カメラ )はキャラクターの周囲にあるか、プレイヤーキャラの
視点がゲームの視点となっています。

 このサンプルはプレイヤーキャラクターの周囲に視点があるタイプの処理の例です。
 Z・C・S・Xキーでカメラの向きを変更することができ、方向キーで移動する方向はカメラの向きを考慮した
ものになっています。

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


// キャラクターに付いていくカメラ
//
// <操作>
// 方向キー:キャラクターモデル移動
// Z,Cキー:カメラの水平角度を変更
// S,Xキー:カメラの垂直角度を変更

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

// 移動速度
#define MOVESPEED			10.0f

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

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

// カメラの回転速度
#define CAMERA_ANGLE_SPEED		3.0f

// カメラの注視点の高さ
#define CAMERA_LOOK_AT_HEIGHT		400.0f

// カメラと注視点の距離
#define CAMERA_LOOK_AT_DISTANCE		2150.0f

// ラインを描く範囲
#define LINE_AREA_SIZE			10000.0f

// ラインの数
#define LINE_NUM			50

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    MoveFlag ;
	float  Angle ;
	float  CameraHAngle ;
	float  CameraVAngle ;
	VECTOR MoveVector ;
	float  SinParam ;
	float  CosParam ;

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

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

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

	// カメラの向きを初期化
	CameraHAngle = 0.0f ;
	CameraVAngle = 40.0f ;

	// 向きを初期化
	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 ) ;

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

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

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

		// ZCSXキーでカメラの操作
		if( CheckHitKey( KEY_INPUT_C ) == 1 )
		{
			CameraHAngle += CAMERA_ANGLE_SPEED ;
			if( CameraHAngle >= 180.0f )
			{
				CameraHAngle -= 360.0f ;
			}
		}

		if( CheckHitKey( KEY_INPUT_Z ) == 1 )
		{
			CameraHAngle -= CAMERA_ANGLE_SPEED ;
			if( CameraHAngle <= -180.0f )
			{
				CameraHAngle += 360.0f ;
			}
		}

		if( CheckHitKey( KEY_INPUT_S ) == 1 )
		{
			CameraVAngle += CAMERA_ANGLE_SPEED ;
			if( CameraVAngle >= 80.0f )
			{
				CameraVAngle = 80.0f ;
			}
		}

		if( CheckHitKey( KEY_INPUT_X ) == 1 )
		{
			CameraVAngle -= CAMERA_ANGLE_SPEED ;
			if( CameraVAngle <= 0.0f )
			{
				CameraVAngle = 0.0f ;
			}
		}

		// 移動ベクトルを初期化
		MoveVector = VGet( 0.0f, 0.0f, 0.0f ) ;

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

		// 方向入力に従ってキャラクターの移動ベクトルと向きを設定
		if( CheckHitKey( KEY_INPUT_LEFT ) == 1 )
		{
			Angle        = 90.0f - CameraHAngle ;
			MoveFlag     = TRUE ;
			MoveVector.x = -MOVESPEED ;
		}

		if( CheckHitKey( KEY_INPUT_RIGHT ) == 1 )
		{
			Angle        = -90.0f - CameraHAngle ;
			MoveFlag     = TRUE ;
			MoveVector.x = MOVESPEED ;
		}

		if( CheckHitKey( KEY_INPUT_DOWN ) == 1 )
		{
			Angle        = 0.0f - CameraHAngle ;
			MoveFlag     = TRUE ;
			MoveVector.z = -MOVESPEED ;
		}

		if( CheckHitKey( KEY_INPUT_UP ) == 1 )
		{
			Angle        = 180.0f - CameraHAngle ;
			MoveFlag     = TRUE ;
			MoveVector.z = MOVESPEED ;
		}

		// 移動した場合は、カメラの水平角度を考慮した方向に座標を移動する
		if( MoveFlag == TRUE )
		{
			VECTOR TempMoveVector ;

			// カメラの角度に合わせて移動ベクトルを回転してから加算
			SinParam = sin( CameraHAngle / 180.0f * DX_PI_F ) ;
			CosParam = cos( CameraHAngle / 180.0f * DX_PI_F ) ;
			TempMoveVector.x = MoveVector.x * CosParam - MoveVector.z * SinParam ;
			TempMoveVector.y = 0.0f ;
			TempMoveVector.z = MoveVector.x * SinParam + MoveVector.z * CosParam ;

			Position = VAdd( Position, TempMoveVector ) ;
		}

		// 今までと状態が変化した場合はアニメーションを変更する
		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 ;
		}
		else
		{
			// アニメーション再生時間を進める
			AnimNowTime += 200.0f ;

			// アニメーション再生時間がアニメーションの総時間を越えていたらループさせる
			if( AnimNowTime >= AnimTotalTime )
			{
				// 新しいアニメーション再生時間は、アニメーション再生時間からアニメーション総時間を引いたもの
				AnimNowTime -= AnimTotalTime ;
			}
		}

		// 新しいアニメーション再生時間をセット
		MV1SetAttachAnimTime( ModelHandle, AnimAttachIndex, AnimNowTime ) ;

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

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

		// カメラの位置と向きを設定
		{
			VECTOR TempPosition1 ;
			VECTOR TempPosition2 ;
			VECTOR CameraPosition ;
			VECTOR CameraLookAtPosition ;

			// 注視点はキャラクターモデルの座標から CAMERA_LOOK_AT_HEIGHT 分だけ高い位置
			CameraLookAtPosition    = Position ;
			CameraLookAtPosition.y += CAMERA_LOOK_AT_HEIGHT ;

			// カメラの位置はカメラの水平角度と垂直角度から算出

			// 最初に垂直角度を反映した位置を算出
			SinParam = sin( CameraVAngle / 180.0f * DX_PI_F ) ;
			CosParam = cos( CameraVAngle / 180.0f * DX_PI_F ) ;
			TempPosition1.x = 0.0f ;
			TempPosition1.y =  SinParam * CAMERA_LOOK_AT_DISTANCE ;
			TempPosition1.z = -CosParam * CAMERA_LOOK_AT_DISTANCE ;

			// 次に水平角度を反映した位置を算出
			SinParam = sin( CameraHAngle / 180.0f * DX_PI_F ) ;
			CosParam = cos( CameraHAngle / 180.0f * DX_PI_F ) ;
			TempPosition2.x = CosParam * TempPosition1.x - SinParam * TempPosition1.z ;
			TempPosition2.y = TempPosition1.y ;
			TempPosition2.z = SinParam * TempPosition1.x + CosParam * TempPosition1.z ;

			// 算出した座標に注視点の位置を加算したものがカメラの位置
			CameraPosition = VAdd( TempPosition2, CameraLookAtPosition ) ;

			// カメラの設定に反映する
			SetCameraPositionAndTarget_UpVecY( CameraPosition, CameraLookAtPosition );
		}

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

		// 位置関係が分かるように地面にラインを描画する
		{
			int i ;
			VECTOR Pos1 ;
			VECTOR Pos2 ;

			SetUseZBufferFlag( TRUE ) ;

			Pos1 = VGet( -LINE_AREA_SIZE / 2.0f, 0.0f, -LINE_AREA_SIZE / 2.0f ) ;
			Pos2 = VGet( -LINE_AREA_SIZE / 2.0f, 0.0f,  LINE_AREA_SIZE / 2.0f ) ;
			for( i = 0 ; i <= LINE_NUM ; i ++ )
			{
				DrawLine3D( Pos1, Pos2, GetColor( 255,255,255 ) ) ;
				Pos1.x += LINE_AREA_SIZE / LINE_NUM ;
				Pos2.x += LINE_AREA_SIZE / LINE_NUM ;
			}

			Pos1 = VGet( -LINE_AREA_SIZE / 2.0f, 0.0f, -LINE_AREA_SIZE / 2.0f ) ;
			Pos2 = VGet(  LINE_AREA_SIZE / 2.0f, 0.0f, -LINE_AREA_SIZE / 2.0f ) ;
			for( i = 0 ; i < LINE_NUM ; i ++ )
			{
				DrawLine3D( Pos1, Pos2, GetColor( 255,255,255 ) ) ;
				Pos1.z += LINE_AREA_SIZE / LINE_NUM ;
				Pos2.z += LINE_AREA_SIZE / LINE_NUM ;
			}

			SetUseZBufferFlag( FALSE ) ;
		}

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

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

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

戻る