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.

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;
}


