#include "Chara_Player.h" #include "Chara_PlayerBase.h" #include "System.h" #include "Input.h" #include "Camera.h" #include // 攻撃1コンボ目の、2コンボ目の攻撃の入力受付開始時間 #define ATTACK1_NEXT_INPUT_START_TIME (4.0f) // 攻撃2コンボ目の、3コンボ目の攻撃の入力受付開始時間 #define ATTACK2_NEXT_INPUT_START_TIME (4.0f) // ロックオン距離 #define LOCKON_DISTANCE (1000.0f) // ロックオン角度範囲 #define LOCKON_ANGLE (1.0f) // ジャンプ力 #define JUMP_POWER (770.0f) // デバッグ機能が有効な場合のジャンプ力 #define DEBUG_JUMP_POWER (1400.0f) // ジャンプ中の速度 #define JUMPMOVE_SPEED (460.0f) // 攻撃力 #define ATTACK_POWER (40) // デバッグ機能が有効な場合の攻撃力 #define DEBUG_ATTACK_POWER (4000) // プレイヤーの状態 typedef enum _EChara_PlayerState { EChara_PlayerState_None, // 特に無し EChara_PlayerState_Attack1, // 攻撃1コンボ目 EChara_PlayerState_Attack2, // 攻撃2コンボ目 EChara_PlayerState_Attack3, // 攻撃3コンボ目 EChara_PlayerState_GuardIn, // ガード開始 EChara_PlayerState_GuardLoop, // ガード中 EChara_PlayerState_GuardOut, // ガード終了 EChara_PlayerState_GuardImpact, // ガードで攻撃を受け止め中 EChara_PlayerState_JumpIn, // ジャンプ開始 EChara_PlayerState_JumpLoop, // ジャンプ中 EChara_PlayerState_JumpOut, // ジャンプ終了 } EChara_PlayerState; // プレイヤーの情報 typedef struct _SChara_PlayerInfo { // プレイヤーの状態 EChara_PlayerState PlayerState; // 次の攻撃が予約済みかどうかのフラグ bool NextAttackRequest; // アニメーションのキャンセルイベントをチェック済みかどうかのフラグ bool AnimCancelCheck; // プレイヤーが攻撃対象としているキャラの情報構造体へのポインタ SCharaInfo * LockOnTarget; // ジャンプを開始した時点での速度 VECTOR JumpMoveSpeed; } SChara_PlayerInfo; // プレイヤーが作成された際に呼ばれる関数 // 戻り値 : 処理が正常に終了したかどうか(true:正常に終了した false:エラーが発生した) bool Chara_Player_Create( // キャラクター情報構造体のアドレス SCharaInfo *CInfo ) { SChara_PlayerInfo *PInfo; // システムにプレイヤーのキャラ情報構造体のアドレスをセット System_SetPlayerCharaInfo( CInfo ); // プレイヤーの情報構造体を格納するメモリ領域の確保 CInfo->SubData = malloc( sizeof( SChara_PlayerInfo ) ); if( CInfo->SubData == NULL ) { return false; } PInfo = ( SChara_PlayerInfo * )CInfo->SubData; // プレイヤーの情報を初期化 PInfo->NextAttackRequest = false; PInfo->AnimCancelCheck = false; PInfo->LockOnTarget = NULL; // 体力ゲージの情報を初期化 CharaHealthGaugeSetup( &CInfo->HealthGauge, true, 1.0f ); // プレイヤーは常に体力ゲージを表示する CInfo->HealthGaugeVisible = true; // 攻撃力をセット CInfo->AttackPower = ATTACK_POWER; // 正常終了 return true; } // プレイヤーが削除される際に呼ばれる関数 void Chara_Player_Delete( // キャラクター情報構造体のアドレス SCharaInfo *CInfo ) { // システムに登録したプレイヤーのキャラ情報構造体のアドレスを無効にする System_SetPlayerCharaInfo( NULL ); } // プレイヤーの状態推移処理が行われる際に呼ばれる関数 // 戻り値 : 処理が正常に終了したかどうか(true:正常に終了した false:エラーが発生した) bool Chara_Player_Step( // キャラクター情報構造体のアドレス SCharaInfo *CInfo, // 推移させる時間( 単位:秒 ) float StepTime, // デフォルトの処理を行うかどうかのフラグのアドレス bool *DefaultProcess ) { SChara_PlayerInfo *PInfo = ( SChara_PlayerInfo * )CInfo->SubData; SChara_PlayerBaseInfo *PBInfo = ( SChara_PlayerBaseInfo * )CInfo->BaseInfo->SubData; int EdgeInput; int Input; bool MoveInputFlag; bool InputLeft; bool InputRight; bool InputUp; bool InputDown; bool InputDefence; bool InputJump; bool InputAttack; VECTOR NewSpeed; float NewAngle; // デバッグ機能が有効になっているかどうかで攻撃力を変化させる if( System_GetDispDebugInfo() ) { CInfo->AttackPower = DEBUG_ATTACK_POWER; } else { CInfo->AttackPower = ATTACK_POWER; } // 入力状態を取得 EdgeInput = GetEdgeInput(); Input = GetInput(); InputLeft = ( Input & ( 1 << EInputType_Left ) ) != 0; InputRight = ( Input & ( 1 << EInputType_Right ) ) != 0; InputUp = ( Input & ( 1 << EInputType_Up ) ) != 0; InputDown = ( Input & ( 1 << EInputType_Down ) ) != 0; InputAttack = ( EdgeInput & ( 1 << EInputType_Attack ) ) != 0; InputDefence = ( Input & ( 1 << EInputType_Defence ) ) != 0; InputJump = ( EdgeInput & ( 1 << EInputType_Jump ) ) != 0; // キャラクターが移動する入力を行っているかどうかを取得 MoveInputFlag = InputLeft || InputRight || InputUp || InputDown; // 移動する入力によって新しい速度を決定 NewSpeed = VGet( 0.0f, 0.0f, 0.0f ); if( InputLeft ) { NewSpeed = VAdd( NewSpeed, VScale( Camera_RightDirection(), -1.0f ) ); } else if( InputRight ) { NewSpeed = VAdd( NewSpeed, Camera_RightDirection() ); } if( InputUp ) { NewSpeed = VAdd( NewSpeed, Camera_FrontDirection() ); } else if( InputDown ) { NewSpeed = VAdd( NewSpeed, VScale( Camera_FrontDirection(), -1.0f ) ); } // プレイヤーが敵をロックオンしている場合はその方向にプレイヤーの向きを変化させる if( PInfo->LockOnTarget != NULL ) { Chara_TargetAngleMove( CInfo, PInfo->LockOnTarget->Position ); } STATE_PROCESS: // キャラの状態によって処理を分岐 switch( CInfo->State ) { case ECharaState_Move: // 移動中 // 移動中の場合はロックオンは解除する PInfo->LockOnTarget = NULL; // ジャンプ中の場合は特に何もせず終了 if( CInfo->JumpState ) { break; } // 攻撃ボタンが押されていたら攻撃状態に移行する if( InputAttack ) { CInfo->State = ECharaState_Attack; PInfo->PlayerState = EChara_PlayerState_Attack1; PInfo->AnimCancelCheck = false; // ロックオン対象となる敵が居るか検索する PInfo->LockOnTarget = Chara_SearchTarget( CInfo, ECharaType_Enemy, LOCKON_DISTANCE, LOCKON_ANGLE ); // 攻撃1コンボ目のアニメーションを再生 if( !Chara_ChangeAnim( CInfo, ECharaAnim_Attack1, CHARA_DEFAULT_ATTACK_CHANGE_ANIM_SPEED ) ) { return false; } } else // ガードボタンが押されていたらガード状態に移行する if( InputDefence ) { CInfo->State = ECharaState_Defence; PInfo->PlayerState = EChara_PlayerState_GuardIn; // ガード開始アニメーションを再生 if( !Chara_ChangeAnim(CInfo, ECharaAnim_Guard_In, CHARA_DEFAULT_CHANGE_ANIM_SPEED ) ) { return false; } } else // ジャンプボタンが押されていたらジャンプ状態に移行する if( InputJump ) { CInfo->State = ECharaState_Jump; PInfo->PlayerState = EChara_PlayerState_JumpIn; // ジャンプを開始した時点での速度を保存しておく PInfo->JumpMoveSpeed = CInfo->PrevAnimMoveSpeed; // ジャンプ開始アニメーションを再生 if( !Chara_ChangeAnim(CInfo,ECharaAnim_Jump_In, CHARA_DEFAULT_CHANGE_ANIM_SPEED ) ) { return false; } } else // 何かしらの移動入力がされている場合は向きを変更し、走りアニメーションを再生する if( MoveInputFlag ) { NewSpeed = VNorm( NewSpeed ); NewAngle = atan2( NewSpeed.x, NewSpeed.z ); Chara_SetTargetAngle( CInfo, NewAngle, true ); if( CInfo->AnimInfo.NowAnim != ECharaAnim_Run ) { if( !Chara_ChangeAnim(CInfo, ECharaAnim_Run, CHARA_DEFAULT_CHANGE_ANIM_SPEED ) ) { return false; } } } else // 何も入力がされていない場合はニュートラルアニメーションを再生する { if( CInfo->AnimInfo.NowAnim != ECharaAnim_Neutral ) { if( !Chara_ChangeAnim( CInfo, ECharaAnim_Neutral, CHARA_DEFAULT_CHANGE_ANIM_SPEED ) ) { return false; } } } break; case ECharaState_Attack: // 攻撃中 // プレイヤーの状態によって処理を分岐 switch( PInfo->PlayerState ) { case EChara_PlayerState_Attack1: // 攻撃1コンボ目 // 攻撃2コンボ目の入力が可能になる時間を経過している状態で攻撃入力が // されたら、『次の攻撃が予約済みかどうかのフラグ』を立てる if( InputAttack && CInfo->AnimInfo.NowTime > ATTACK1_NEXT_INPUT_START_TIME ) { PInfo->NextAttackRequest = true; } // アニメーションのキャンセルイベントが発生していて、且つキャンセルイベントの // チェックをまだ行っていない場合は処理を分岐 if( CInfo->AnimInfo.Cancel && !PInfo->AnimCancelCheck ) { // キャンセルイベントのチェックを行ったかどうかのフラグを立てる PInfo->AnimCancelCheck = true; // 攻撃2コンボ目を発動させる予約がされていたら攻撃2コンボ目を開始する if( PInfo->NextAttackRequest ) { PInfo->AnimCancelCheck = false; PInfo->NextAttackRequest = false; if( !Chara_ChangeAnim( CInfo, ECharaAnim_Attack2, CHARA_DEFAULT_ATTACK_CHANGE_ANIM_SPEED ) ) { return false; } PInfo->PlayerState = EChara_PlayerState_Attack2; } } else // アニメーションが終了していたら移動状態に移行する if( CInfo->AnimInfo.End ) { CInfo->State = ECharaState_Move; PInfo->PlayerState = EChara_PlayerState_None; // 移動状態を1フレーム分実行する goto STATE_PROCESS; } break; case EChara_PlayerState_Attack2: // 攻撃2コンボ目 // 攻撃3コンボ目の入力が可能になる時間を経過している状態で攻撃入力が // されたら、『次の攻撃が予約済みかどうかのフラグ』を立てる if( InputAttack && CInfo->AnimInfo.NowTime > ATTACK2_NEXT_INPUT_START_TIME ) { PInfo->NextAttackRequest = true; } // アニメーションのキャンセルイベントが発生していて、且つキャンセルイベントの // チェックをまだ行っていない場合は処理を分岐 if( CInfo->AnimInfo.Cancel && !PInfo->AnimCancelCheck ) { // キャンセルイベントのチェックを行ったかどうかのフラグを立てる PInfo->AnimCancelCheck = true; // 攻撃3コンボ目を発動させる予約がされていたら攻撃3コンボ目を開始する if( PInfo->NextAttackRequest ) { PInfo->AnimCancelCheck = false; PInfo->NextAttackRequest = false; if( !Chara_ChangeAnim( CInfo, ECharaAnim_Attack3, CHARA_DEFAULT_ATTACK_CHANGE_ANIM_SPEED ) ) { return false; } PInfo->PlayerState = EChara_PlayerState_Attack3; } } else // アニメーションが終了していたら移動状態に移行する if( CInfo->AnimInfo.End ) { CInfo->State = ECharaState_Move; PInfo->PlayerState = EChara_PlayerState_None; // 移動状態を1フレーム分実行する goto STATE_PROCESS; } break; case EChara_PlayerState_Attack3: // 攻撃3コンボ目 // アニメーションが終了していたら移動状態に移行する if( CInfo->AnimInfo.End ) { CInfo->State = ECharaState_Move; PInfo->PlayerState = EChara_PlayerState_None; // 移動状態を1フレーム分実行する goto STATE_PROCESS; } break; } break; case ECharaState_Defence: // 防御中 // プレイヤーの状態によって処理を分岐 switch( PInfo->PlayerState ) { case EChara_PlayerState_GuardIn: // ガード開始 // ガード開始アニメーションが終了したらガード中状態に移行する if( CInfo->AnimInfo.End ) { PInfo->PlayerState = EChara_PlayerState_GuardLoop; if( !Chara_ChangeAnim( CInfo, ECharaAnim_Guard_Loop, CHARA_DEFAULT_ATTACK_CHANGE_ANIM_SPEED ) ) { return false; } } break; case EChara_PlayerState_GuardLoop: // ガード中 // 入力ボタンが離されたらガード終了状態に移行する if( !InputDefence ) { PInfo->PlayerState = EChara_PlayerState_GuardOut; if( !Chara_ChangeAnim( CInfo, ECharaAnim_Guard_Out, CHARA_DEFAULT_ATTACK_CHANGE_ANIM_SPEED ) ) { return false; } } break; case EChara_PlayerState_GuardOut: // ガード終了 // ガード終了アニメーションが終了したら移動状態に移行する if( CInfo->AnimInfo.End ) { CInfo->State = ECharaState_Move; PInfo->PlayerState = EChara_PlayerState_None; // 移動状態を1フレーム分実行する goto STATE_PROCESS; } break; case EChara_PlayerState_GuardImpact: // ガードで攻撃を受け止め中 // ガードで攻撃を受け止めるアニメーションが完了したらガード中状態に移行する if( CInfo->AnimInfo.End ) { PInfo->PlayerState = EChara_PlayerState_GuardLoop; if( !Chara_ChangeAnim( CInfo, ECharaAnim_Guard_Loop, CHARA_DEFAULT_ATTACK_CHANGE_ANIM_SPEED ) ) { return false; } } break; } break; case ECharaState_Jump: // ジャンプ中 // プレイヤーの状態によって処理を分岐 switch( PInfo->PlayerState ) { case EChara_PlayerState_JumpIn: // ジャンプ開始 // ジャンプ開始アニメーションが終了したらジャンプ中状態に移行する if( CInfo->AnimInfo.End ) { PInfo->PlayerState = EChara_PlayerState_JumpLoop; if( !Chara_ChangeAnim( CInfo, ECharaAnim_Jump_Loop, CHARA_DEFAULT_ATTACK_CHANGE_ANIM_SPEED ) ) { return false; } } break; case EChara_PlayerState_JumpOut: // ジャンプ終了 // ジャンプ終了アニメーションが終了したら移動状態に移行する if( CInfo->AnimInfo.End ) { CInfo->State = ECharaState_Move; PInfo->PlayerState = EChara_PlayerState_None; // 移動状態を1フレーム分実行する goto STATE_PROCESS; } break; } break; // 吹っ飛び、ダウン、フェードアウトはデフォルトのキャラクター処理を行う case ECharaState_Blow: case ECharaState_Down: case ECharaState_FadeOut: *DefaultProcess = true; return true; case ECharaState_Damage: // ダメージ中 // ジャンプ中にダメージアニメーションが終了した場合はジャンプ中状態に移行する if( CInfo->AnimInfo.End && CInfo->JumpState ) { CInfo->State = ECharaState_Jump; PInfo->PlayerState = EChara_PlayerState_JumpLoop; if( !Chara_ChangeAnim( CInfo, ECharaAnim_Jump_Loop, CHARA_DEFAULT_ATTACK_CHANGE_ANIM_SPEED ) ) { return false; } } else { // それ以外の場合はデフォルトの処理を行う *DefaultProcess = true; return true; } break; } // ここに来た場合はデフォルトの処理は実行しない *DefaultProcess = false; // 正常終了 return true; } // プレイヤーがダメージを受けた際に呼ばれる関数 // 戻り値 : 処理が正常に終了したかどうか(true:正常に終了した false:エラーが発生した) bool Chara_Player_Damage( // キャラクター情報構造体のアドレス SCharaInfo *CInfo, // ダメージタイプ ECharaAttack_DamageType DamageType, // ダメージ int DamagePoint, // 攻撃が当たった座標 VECTOR HitPosition, // 攻撃の方向 VECTOR AttackDirection, // 攻撃を防御したかどうかを代入する変数のアドレス bool *Defence, // デフォルトの処理を行うかどうかのフラグのアドレス bool *DefaultProcess ) { SChara_PlayerInfo *PInfo = ( SChara_PlayerInfo * )CInfo->SubData; SChara_PlayerBaseInfo *PBInfo = ( SChara_PlayerBaseInfo * )CInfo->BaseInfo->SubData; float ACos; // デバッグ機能が有効になっていたらダメージを受けない if( System_GetDispDebugInfo() ) { *Defence = true; *DefaultProcess = false; return true; } // ガード中ではない場合はダメージを受ける if( CInfo->State != ECharaState_Defence ) { *Defence = false; *DefaultProcess = true; return true; } // ガードをしている場合でも背後側から攻撃されたらダメージを受ける ACos = VDot( AttackDirection, CInfo->AngleInfo.FrontDirection ); if( ACos >= 0.0f ) { *Defence = false; *DefaultProcess = true; return true; } // ガード音を再生する Sound_PlaySound3D( HitPosition, PBInfo->DefenceSuccessSound, DX_PLAYTYPE_BACK ); // ガードで攻撃を受け止めた状態に移行する PInfo->PlayerState = EChara_PlayerState_GuardImpact; if( !Chara_ChangeAnim( CInfo, ECharaAnim_Guard_Impact, CHARA_DEFAULT_ATTACK_CHANGE_ANIM_SPEED ) ) { return false; } // ガードをしたかどうかのフラグを立てる *Defence = true; // ダメージを受けなかった場合はデフォルトの動作を行わない *DefaultProcess = false; // 正常終了 return true; } // プレイヤーが着地した際に呼ばれる関数 // 戻り値 : 処理が正常に終了したかどうか(true:正常に終了した false:エラーが発生した) bool Chara_Player_Landed( // キャラクター情報構造体のアドレス SCharaInfo *CInfo, // デフォルトの処理を行うかどうかのフラグのアドレス bool *DefaultProcess ) { SChara_PlayerInfo *PInfo = ( SChara_PlayerInfo * )CInfo->SubData; SChara_PlayerBaseInfo *PBInfo = ( SChara_PlayerBaseInfo * )CInfo->BaseInfo->SubData; // 吹っ飛び中やダウン中の場合はデフォルトの動作を行う if( CInfo->State == ECharaState_Blow || CInfo->State == ECharaState_Down || CInfo->State == ECharaState_FadeOut ) { *DefaultProcess = true; return true; } // 横方向の移動速度を0にする CInfo->MoveSpeed.x = 0.0f; CInfo->MoveSpeed.z = 0.0f; // ジャンプ終了状態に移行する CInfo->State = ECharaState_Jump; PInfo->PlayerState = EChara_PlayerState_JumpOut; if( !Chara_ChangeAnim( CInfo, ECharaAnim_Jump_Out, CHARA_DEFAULT_ATTACK_CHANGE_ANIM_SPEED ) ) { return false; } // ここに来た場合はデフォルトの動作は行わない *DefaultProcess = false; // 正常終了 return true; } // アニメーションイベント「その他」が発生した際に呼ばれる関数 // 戻り値 : 処理が正常に終了したかどうか(true:正常に終了した false:エラーが発生した) bool Chara_Player_AnimOtherEvent( // キャラクター情報構造体のアドレス SCharaInfo *CInfo ) { SChara_PlayerInfo *PInfo = ( SChara_PlayerInfo * )CInfo->SubData; SChara_PlayerBaseInfo *PBInfo = ( SChara_PlayerBaseInfo * )CInfo->BaseInfo->SubData; // ジャンプ中の速度をセット CInfo->MoveSpeed = PInfo->JumpMoveSpeed; // デバッグ機能が有効な場合は大ジャンプをする if( System_GetDispDebugInfo() ) { CInfo->MoveSpeed.y = DEBUG_JUMP_POWER; } else { CInfo->MoveSpeed.y = JUMP_POWER; } // ジャンプ状態かどうかのフラグを立てる CInfo->JumpState = true; // 正常終了 return true; }