TPSカメラ
Sceneファイルに下記設定を追加
"items": [
{
"name": "Camera",
"type": "camera"
}
]
実装例
const float TPSCAMERA_PITCH_LIMIT = 80.0f; // カメラのX軸回転の上限
const float TPSCAMERA_PITCH_LIMIT_MINUS = -45.0f; // カメラのX軸回転の下限
const float TPSCAMERA_DEFAULT_DISTANCE = -10.0f; // プレイヤーからカメラまでの距離
const float TPSCAMERA_DEFAULT_YAW = 180.0f; // カメラの初期Y軸回転(180度後ろ向き)
const float TPSCAMERA_MOUSE_SENSITIVITY = 3.0f;
component TestPlayerTPSCamera
{
Player m_Player;
// カメラ関連
Item m_Camera;
Vector3 m_CameraPosition;
Quaternion m_CameraCurrentQuaternion;
Vector3 m_CameraNextEuler;
Vector3 m_TargetPos;
// マウス関連
int m_PreMousePosX;
int m_PreMousePosY;
HS2DI m_CurrentMousePos;
bool m_IsMouseLLock; // マウスドラッグを無効にするためのロック
bool m_PreMouseLDown; // 前フレームのマウス左クリック状態
public TestPlayerTPSCamera()
{
m_Player = hsPlayerGet();
// カメラ用
// シーンファイルにnameが「Camera」のcameraタイプアイテムがある前提で取得する
m_Camera = hsGetItem("Camera");
if(m_Camera !== null)
{
// カメラとして設定
m_Camera.SetCamera();
}
m_CameraCurrentQuaternion = new Quaternion();
m_CameraNextEuler = makeVector3(TPSCAMERA_DEFAULT_DISTANCE,TPSCAMERA_DEFAULT_YAW,0.0f);
m_TargetPos = new Vector3();
// マウス用
m_PreMousePosX = 0.0f;
m_PreMousePosY = 0.0f;
m_CurrentMousePos = new HS2DI();
m_IsMouseLLock = false;
m_PreMouseLDown = false;
}
public void Update()
{
if(m_Player === null || m_Camera === null) return;
// マウス入力によるカメラ回転制御
UpdateCameraRotateByMouse();
// カメラの位置・回転を更新
UpdateCamera();
// プレイヤー→カメラ方向にレイを飛ばし、遮蔽物があればカメラ位置を補正する
Vector3 Dir = m_TargetPos.SubNew(m_Camera.GetPos()).GetNormalize();
UpdateCameraCollisionWorld(m_Camera.GetPos(),Dir);
}
void UpdateCameraRotateByMouse()
{
int CurrentMousePosX,CurrentMousePosY;
hsInputGetMousePos(CurrentMousePosX,CurrentMousePosY);
m_CurrentMousePos.SetXY(CurrentMousePosX,CurrentMousePosY);
// マウスダウン
bool IsNowDown = hsInputClickButton(HSMouse_Left);
if(!m_PreMouseLDown && IsNowDown && !hsCanvasGetIsInEmptyArea(m_CurrentMousePos))
{
// ドラッグ開始位置がGUI上であればロックをかけドラッグ操作を無効化
m_IsMouseLLock = true;
}
// マウスアップ
else if(m_PreMouseLDown && !IsNowDown)
{
m_IsMouseLLock = false;
}
// ロックされていない場合のみドラッグ処理を行う
if(!m_IsMouseLLock)
{
bool CurrentLClick = hsInputClickButton(HSMouse_Left);
if(CurrentLClick)
{
// マウス移動量
float DeltaMouseX = (CurrentMousePosX - m_PreMousePosX) * hsCameraGetRotateSpeed() * hsSystemGetDeltaTime() * TPSCAMERA_MOUSE_SENSITIVITY;
float DeltaMouseY = (CurrentMousePosY - m_PreMousePosY) * hsCameraGetRotateSpeed() * hsSystemGetDeltaTime() * TPSCAMERA_MOUSE_SENSITIVITY;
// カメラ設定「上下操作」によって傾ける方向を反転させる
if(hsCameraGetXRotateReverse()) m_CameraNextEuler.x = Clamp(m_CameraNextEuler.x + DeltaMouseY, TPSCAMERA_PITCH_LIMIT_MINUS, TPSCAMERA_PITCH_LIMIT);
else m_CameraNextEuler.x = Clamp(m_CameraNextEuler.x - DeltaMouseY, TPSCAMERA_PITCH_LIMIT_MINUS, TPSCAMERA_PITCH_LIMIT);
// カメラ設定「左右操作」によって傾ける方向を反転させる
if(hsCameraGetYRotateReverse()) m_CameraNextEuler.y -= DeltaMouseX;
else m_CameraNextEuler.y += DeltaMouseX;
}
}
// 前フレームのマウスクリックと位置の状態を保存
m_PreMouseLDown = IsNowDown;
m_PreMousePosX = CurrentMousePosX;
m_PreMousePosY = CurrentMousePosY;
}
void UpdateCamera()
{
// カメラの回転を計算
Quaternion CameraYRotate = makeQuaternionYRotation(hsMathDegToRad(m_CameraNextEuler.y));
Quaternion CameraXRoate = makeQuaternionXRotation(hsMathDegToRad(m_CameraNextEuler.x));
Quaternion NextRotate = makeQuaternionMul(CameraYRotate,CameraXRoate);
Quaternion NormNextRotate = GetNormailizeQuaternion(NextRotate);
m_CameraCurrentQuaternion = NormNextRotate;
// プレイヤーの背後にカメラを配置するための位置を計算
Vector3 OffsetPos = makeVector3(0.0f, 0.0f, TPSCAMERA_DEFAULT_DISTANCE);
Vector3 Direction = OffsetPos.Rotate(m_CameraCurrentQuaternion).GetNormalize();
OffsetPos = makeVector3(Direction.x * TPSCAMERA_DEFAULT_DISTANCE,Direction.y * TPSCAMERA_DEFAULT_DISTANCE,Direction.z * TPSCAMERA_DEFAULT_DISTANCE);
m_TargetPos = makeVector3(m_Player.GetPos().x,m_Player.GetPos().y + m_Player.GetHeadHeight(), m_Player.GetPos().z);
Vector3 FinalPos = makeVector3Add(m_TargetPos,OffsetPos);
Quaternion FinalRotate = makeQuaternionMul(m_CameraCurrentQuaternion,makeQuaternionYRotation(hsMathDegToRad(TPSCAMERA_DEFAULT_YAW)));
m_Camera.SetPos(FinalPos);
m_Camera.SetQuaternion(FinalRotate);
}
void UpdateCameraCollisionWorld(Vector3 Origin , Vector3 Dir)
{
float Length = m_TargetPos.Distance(m_Camera.GetPos());
HSRaycastHIT HitItem = hsItemRaycast(Origin, Dir, Length);
if(HitItem === null) return;
m_Camera.SetPos(HitItem.Pos);
}
Quaternion GetNormailizeQuaternion(Quaternion q)
{
Quaternion Result = new Quaternion();
float Denom = hsMathSqrt(q.x * q.x + q.y * q.y + q.z * q.z + q.w * q.w);
if(Denom!=0.0f)
{
Result.x = q.x / Denom;
Result.y = q.y / Denom;
Result.z = q.z / Denom;
Result.w = q.w / Denom;
}
return Result;
}
float Clamp(float value, float minVal, float maxVal)
{
if (value < minVal) return minVal;
if (value > maxVal) return maxVal;
return value;
}
}