-
-
Save Reputeless/834bda9457df2a6015df39c2d3d0eed6 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# include <Siv3D.hpp> | |
/// @brief 目標に追従するカメラクラス | |
/// @note 追従方向、追従距離、追従高さを指定して、目標に追従するカメラを作成します。 | |
class SimpleFollowCamera3D : public BasicCamera3D | |
{ | |
public: | |
SimpleFollowCamera3D() = default; | |
/// @brief 3D カメラを作成します。 | |
/// @param sceneSize シーンのサイズ | |
/// @param verticalFOV 縦方向の視野角(ラジアン) | |
/// @param focusPosition 注目点 | |
/// @param followAngle 追従方向(0 が Z 軸正方向、時計まわり) | |
/// @param followDistance 追従距離 | |
/// @param followHeight 追従高さ | |
SimpleFollowCamera3D(const Size& sceneSize, double verticalFOV, const Vec3& focusPosition, double followDirection, double followDistance, double followHeight) noexcept | |
: BasicCamera3D{ sceneSize, verticalFOV, (focusPosition + CalculateFollowOffset(followDirection, followDistance, followHeight)), focusPosition } | |
, m_currentFocus{ focusPosition } | |
, m_targetFocus{ focusPosition } | |
, m_followDirection{ followDirection } | |
, m_followDistance{ followDistance } | |
, m_followHeight{ followHeight } {} | |
/// @brief カメラを更新します。 | |
/// @param smoothTime 平滑化時間(最大速度で目標に向かうときに期待される所要時間)。動く目標を追いかけるときの遅延時間で、小さいと目標に早く到達する。 | |
/// @param deltaTime 前回からの経過時間。デフォルトでは Scene::DeltaTime() | |
void update(double smoothTime, double deltaTime = Scene::DeltaTime()) | |
{ | |
m_currentFocus = Math::SmoothDamp(m_currentFocus, m_targetFocus, m_focusVelocity, smoothTime, unspecified, deltaTime); | |
BasicCamera3D::setView((m_currentFocus + getFollowOffset()), m_currentFocus, m_upDirection); | |
} | |
/// @brief 追従する対象の位置を設定します。 | |
/// @param targetFocus 追従する対象の位置 | |
/// @param direction 追従する対象の向いている方向(0 が Z 軸正方向、時計まわり) | |
void setTarget(const Vec3& targetFocus, double followAngle = 0.0) noexcept | |
{ | |
m_targetFocus = targetFocus; | |
m_followDirection = followAngle; | |
} | |
/// @brief 追従する対象の位置を設定します(即座に移動します)。 | |
/// @param targetFocus 追従する対象の位置 | |
/// @param followAngle 追従する対象の向いている方向(0 が Z 軸正方向、時計まわり) | |
void jumpToTarget(const Vec3& targetFocus, double followAngle = 0.0) noexcept | |
{ | |
m_currentFocus = m_targetFocus = targetFocus; | |
m_focusVelocity = Vec3{ 0, 0, 0 }; | |
m_followDirection = followAngle; | |
BasicCamera3D::setView((m_currentFocus + getFollowOffset()), m_currentFocus, m_upDirection); | |
} | |
/// @brief 追従距離と追従高さを設定します。 | |
/// @param distance 追従距離 | |
/// @param height 追従高さ | |
void setFollowOffset(double followDistance, double followHeight) noexcept | |
{ | |
m_followDistance = followDistance; | |
m_followHeight = followHeight; | |
} | |
/// @brief 追従対象に対するオフセットを計算します。 | |
/// @return 追従対象に対するオフセット | |
[[nodiscard]] | |
Vec3 getFollowOffset() const noexcept | |
{ | |
return CalculateFollowOffset(m_followDirection, m_followDistance, m_followHeight); | |
} | |
private: | |
static Vec3 CalculateFollowOffset(double direction, double distance, double height) noexcept | |
{ | |
return Cylindrical{ distance, (-90_deg - direction), height }; | |
} | |
Vec3 m_currentFocus = Vec3{ 0, 0, 0 }; | |
Vec3 m_targetFocus = Vec3{ 0, 0, 0 }; | |
Vec3 m_focusVelocity = Vec3{ 0, 0, 0 }; | |
double m_followDirection = 0.0_deg; | |
double m_followDistance = 10.0; | |
double m_followHeight = 10.0; | |
}; | |
void Main() | |
{ | |
Window::Resize(1280, 720); | |
const Font font{ FontMethod::MSDF, 48, Typeface::Bold }; | |
const ColorF backgroundColor = ColorF{ 0.4, 0.6, 0.8 }.removeSRGBCurve(); | |
const Texture uvChecker{ U"example/texture/uv.png", TextureDesc::MippedSRGB }; | |
const MSRenderTexture renderTexture{ Scene::Size(), TextureFormat::R8G8B8A8_Unorm_SRGB, HasDepth::Yes }; | |
constexpr double Speed = 4.0; | |
Vec3 currentPos{ 0, 1, 0 }; | |
Vec3 targetPos{ 0, 1, 0 }; | |
Vec3 velocity{ 0, 0, 0 }; | |
constexpr double FollowDistance = 15.0; | |
double followHeight = 8.0; | |
double followDirection = 0.0_deg; | |
SimpleFollowCamera3D camera{ renderTexture.size(), 30_deg, currentPos, 0.0_deg, FollowDistance, followHeight }; | |
while (System::Update()) | |
{ | |
const double deltaTime = Scene::DeltaTime(); | |
// 追従の調整 | |
{ | |
if (KeyLeft.pressed()) | |
{ | |
followDirection -= (90_deg * deltaTime); | |
} | |
if (KeyRight.pressed()) | |
{ | |
followDirection += (90_deg * deltaTime); | |
} | |
if (KeyDown.pressed()) | |
{ | |
followHeight = Min((followHeight + 4.0 * deltaTime), 20.0); | |
} | |
if (KeyUp.pressed()) | |
{ | |
followHeight = Max((followHeight - 4.0 * deltaTime), 0.0); | |
} | |
} | |
// キャラクターの移動 | |
{ | |
if (KeyA.pressed()) | |
{ | |
targetPos.x -= (Speed * deltaTime); | |
} | |
if (KeyD.pressed()) | |
{ | |
targetPos.x += (Speed * deltaTime); | |
} | |
if (KeyW.pressed()) | |
{ | |
targetPos.z += (Speed * deltaTime); | |
} | |
if (KeyS.pressed()) | |
{ | |
targetPos.z -= (Speed * deltaTime); | |
} | |
currentPos = Math::SmoothDamp(currentPos, targetPos, velocity, 0.12); | |
} | |
if (KeyC.down()) | |
{ | |
currentPos = targetPos = Vec3{ 0, 1, 0 }; | |
velocity = Vec3{ 0, 0, 0 }; | |
followHeight = 8.0; | |
followDirection = 0.0_deg; | |
camera.jumpToTarget(currentPos, followDirection); | |
} | |
// カメラの更新 | |
{ | |
camera.setTarget(currentPos, followDirection); | |
camera.setFollowOffset(FollowDistance, followHeight); | |
camera.update(0.15); | |
Graphics3D::SetCameraTransform(camera); | |
} | |
// 3D 描画 | |
{ | |
const ScopedRenderTarget3D target{ renderTexture.clear(backgroundColor) }; | |
Plane{ 64 }.draw(uvChecker); | |
Box{ currentPos, 2 }.draw(ColorF{ 0.8, 0.6, 0.4 }.removeSRGBCurve()); | |
} | |
// 3D シーンを 2D シーンに描画 | |
{ | |
Graphics3D::Flush(); | |
renderTexture.resolve(); | |
Shader::LinearToScreen(renderTexture); | |
} | |
RoundRect{ 20, 20, 680, 200, 10 }.draw(ColorF{ 0.0, 0.6 }); | |
font(U"キャラクター位置: {:.2f}"_fmt(currentPos)).draw(24, Vec2{ 40, 40 }); | |
font(U"追従方向: {:.1f}°"_fmt(Math::ToDegrees(Math::NormalizeAngle(followDirection)))).draw(24, Vec2{ 40, 80 }); | |
font(U"追従距離: {:.2f}"_fmt(FollowDistance)).draw(24, Vec2{ 240, 80 }); | |
font(U"追従高さ: {:.2f}"_fmt(followHeight)).draw(24, Vec2{ 440, 80 }); | |
font(U"追従オフセット: {:.2f}"_fmt(camera.getFollowOffset())).draw(24, Vec2{ 40, 120 }); | |
font(U"移動: WASD, 追従方向: ←→, 追従高さ: ↑↓ リセット: C"_fmt(camera.getFollowOffset())).draw(24, Vec2{ 40, 160 }); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment