Skip to main content

Arc-Ball kamera tipi, sabit bir hedefe bakan ve bu hedef etrafında serbestçe dönen kamera tipidir. Bu kamera türü ile genellikle araba yarışı oyunlarında arabamızı modifiye ederken yaptığımız değişiklikleri inceleyebildiğimiz sahnelerde karşılaşırız. Bu kamera sınıfında hedef etrafında rahatça dönmeye izin verilirken, hedefi çevirmeye veya görüntüden çıkmasına izin verilmez.

kamera_arc_ball

Birçok oyunda bu kamera kullanılırken dönme veya uzaklaşma için bir limit belirlenir. Bu durumları da göze alarak, oluşturacağımız kamera sınıfı için gerekli kod aşağıdaki gibidir.

    public class ArcBallCamera : Camera
    {
        // İki eksen etrafındaki dönme miktarları
        public float RotationX { get; set; }
        public float RotationY { get; set; }
        // Y ekseni dönme limitleri (radian)
        public float MinRotationY { get; set; }
        public float MaxRotationY { get; set; }
        // Hedef ile kamera arası mesafe
        public float Distance { get; set; }
        // Mesafe limitleri
        public float MinDistance { get; set; }
        public float MaxDistance { get; set; }
        // Hesaplanan konum ve hedef 
        public Vector3 Position { get; private set; }
        public Vector3 Target { get; set; }
        public ArcBallCamera(Vector3 Target, float RotationX, float RotationY, float MinRotationY, float MaxRotationY, float Distance, float MinDistance, float MaxDistance, GraphicsDevice graphicsDevice)
            : base(graphicsDevice)
        {
            this.Target = Target;
            this.MinRotationY = MinRotationY;
            this.MaxRotationY = MaxRotationY;
            // Y ekseni etrafındaki dönme miktarlarının limitler ile kilitlenmesi
            this.RotationY = MathHelper.Clamp(RotationY, MinRotationY, MaxRotationY);
            this.RotationX = RotationX;
            this.MinDistance = MinDistance;
            this.MaxDistance = MaxDistance;
            // Uzaklığın limitlere göre kilitlenmesi
            this.Distance = MathHelper.Clamp(Distance, MinDistance, MaxDistance);
        }
        public void Move(float DistanceChange)
        {
            this.Distance += DistanceChange;
            this.Distance = MathHelper.Clamp(Distance, MinDistance, MaxDistance);
        }
        public void Rotate(float RotationXChange, float RotationYChange)
        {
            this.RotationX += RotationXChange;
            this.RotationY += -RotationYChange;
            this.RotationY = MathHelper.Clamp(RotationY, MinRotationY, MaxRotationY);
        }
        public void Translate(Vector3 PositionChange)
        {
            this.Position += PositionChange;
        }
        public override void Update()
        {
            // Dönme değerlerine göre dönme matrisini hesapla
            Matrix rotation = Matrix.CreateFromYawPitchRoll(RotationX, - RotationY, 0);
            // Kamera ile hedef arasındaki uzaklığa göre Z eksenini hesapla, daha sonra kamera etrafında dönerek son görünümü bul
            Vector3 translation = new Vector3(0, 0, Distance);
            translation = Vector3.Transform(translation, rotation);
            Position = Target + translation;
            // Dönme matrisine göre kameranın üst kısmının matrisini hesapla
            Vector3 up = Vector3.Transform(Vector3.Up, rotation);
            View = Matrix.CreateLookAt(Position, Target, up);
        }
    }

Bu kamerayı oyunumuzda kullanmak için ise, ilk önce LoadContent() bölümünde tanımlamamız gerekir.

camera = new ArcBallCamera(Vector3.Zero, MathHelper.ToRadians(160), MathHelper.ToRadians(20), 0, MathHelper.PiOver2, 500, 400, 1500, GraphicsDevice);

Ayrıca kameranın güncellenmesinden sorumlu updateCamera() methodunu da yeni kamera türüne göre değiştirmemiz gerekir.

void updateCamera(GameTime gameTime)
{
    // Klavye ve fare durumlarını al
    MouseState mouseState = Mouse.GetState();
    KeyboardState keyState = Keyboard.GetState();
    // Kameranın ne kadar döneceğini hesapla
    float deltaX = (float)lastMouseState.X - (float)mouseState.X;
    float deltaY = (float)lastMouseState.Y - (float)mouseState.Y;
    // Kamerayı döndür
    ((ArcBallCamera)camera).Rotate(deltaX * .01f, deltaY * .01f);
    // Fare tekerinin dönme miktarını hesapla
    float scrollDelta = (float)lastMouseState.ScrollWheelValue - (float)mouseState.ScrollWheelValue;
    // Kamerayı hareket ettir
    ((ArcBallCamera)camera).Move(scrollDelta);
    // Kamerayı güncelle
    camera.Update();
    // Farenin konumunu güncelle
    lastMouseState = mouseState;
}