Pencereleri nasıl açacağımızı öğrendik ama henüz nasıl durduracağımızı bilmiyoruz. Şimdi pencere olaylarını nasıl yakalayacağımızı ve onları düzgün bir şekilde nasıl yöneteceğimizi göreceğiz.
Olayları Almak
Temel olarak, olaylar pencereleme sisteminden iki şekilde alınır:
SFML, olayları almak için bir kuyruklama sistemi kullanır. GetEvent, bu iş için kullanılır. Bu fonksiyon, bir sf::Event kopyası doldurur ve bekleyen olaylar varsa true, bekleme yığını boşsa false döndürür.
Olayları İşlemek
Bir olay alındığında bakılacak ilk şey Type üyesi içindeki biçimini kontrol etmektir. SFML aşağıdaki olay biçimlerini destekler:
Olay örnekleri, olayın biçimine göre farklı parametreler alabilir:
Boyutlandırma olayları (Resized)
Fare içinse beş sabit tanımlanmıştır: sf::Mouse::Left, sf::Mouse::Right, sf::Mouse::Middle (tekerlek tuşu), sf::Mouse::XButton1 ve sf::Mouse::XButton2.
Uygulamalarımıza geri dönelim ve uygulamamıza olayları yönetebilmesi için gerekli eklemeleri yapalım. Kullanıcı kapatma düğmesine veya ESC tuşuna bastığında uygulamayı durdurmak için:
Bir Pencereyi Kapatmak
SFML ile bir süre uğraştıktan sonra fark edeceksiniz ki kapat düğmesine basmak bir Closed olayı yaratıyor fakat pencereyi yok etmiyor. Bu, kullanıcıya pencere kapatılmadan önce istediği kodları çalıştırması (yapılanların saklanmak istenip istenmediğinin sorulması, vb.) ya da bu işlemi iptal etmesi için fırsat vermektedir. Bir pencereyi gerçekten kapatmak için sf::Window örneğini yok etmeli ya da o pencerenin Close() fonksiyonunu çağırmalısınız.
Bir pencerenin açık olup olmadığını anlamak için IsOpened() fonksiyonunu çağırabilirsiniz.
Şimdi daha güzel görünen bir ana döngü kuralım:
Gerçek Zamanlı Girdiler Almak
Bu olay sistemi, pencere kapatmak ya da tek bir tuşu takip etmek için yeterince iyi. Bununla birlikte, sürekli hareket halindeki bir karakterin kontrolü gibi örneklerde, bir yön tuşuna bastığınızda bir problemle karşılaşacaksınız: her hareket arasında işletin sistemince tanımlanmış bir gecikme yaşanacak.
Bu gibi durumlar için daha iyi bir strateji izlenmelidir. Bunun için bir ikilik değişkene, bir tuşa basıldığında true değeri verilebilir ve tuş serbest bırakıldığında bu değişken sıfırlanabilir. Böylece döngü her yeniden başladığında eğer değişken sıfır değilse karakter hareket eder. Bu iş için fazladan bir değişken kullanılması can sıkıcı olabilir, özellikle onlarla baş edemeyeceğiniz kadar çoğaldıklarında. Bunun için SFML, sf::Input ile gerçek zamanlı girdilere erişmek için kolay bir yol sunar.
sf::Input örnekleri kendi başlarına yaşayamazlar, bir pencereye eklenmelidirler. Gerçekte her sf::Window, kendi sf::Input örneğini yönetir ve bunlara sadece istediğinizde sahip olursunuz. Pencereyle ilişkilendirilmiş bir girdiden referans almak için GetInput fonksiyonu kullanılır.
Farenin pencere üzerindeki konumunu konsol üzerinden söyleyen bir örnekle eğitseli tamamlayalım:
Bu eğitselle ilgili diğer örneklere sfml-gelistirme deposundan ulaşabilirsiniz.
Kaynak: Window - Handling events
Olayları Almak
Temel olarak, olaylar pencereleme sisteminden iki şekilde alınır:
- Pencereden her döngüde olaylar için beklemesini istersiniz -ki buna kuyruklama (polling) denir-.
- Pencereye bir fonksiyon işaretçisi verebilir ve sonra pencerenin bir olay aldığı zaman onu çağırması için bekleyebilirsiniz. Buna sanırım "geri çağırma fonksiyonları kullanımı" diyebiliriz.
SFML, olayları almak için bir kuyruklama sistemi kullanır. GetEvent, bu iş için kullanılır. Bu fonksiyon, bir sf::Event kopyası doldurur ve bekleyen olaylar varsa true, bekleme yığını boşsa false döndürür.
// App'ın bir sf::Window kopyası / örneği olduğunu hatırlayınHer karede alınması gereken birden çok olay olabilir ve eğer biz yalnızca bir tanesini alırsak olaylar birikir ve hiçbir zaman işlenmez. Tüm bekleyen olayları almak için en doğru yol, tüm olayları alabileceğimiz döngü kurmaktır:
sf::Event Event;
if (App.GetEvent(Event))
{
// Olayı işle
}
sf::Event Event;"Ama bir saniye, nereye ekleyeceğim ben bu kod parçasını?" sorusunun tam zamanı şimdi. Olayların her karede işlenmesi gerektiğinden olay yönetimine ait kodları ana döngünün başına ekleyebilirsiniz:
while (App.GetEvent(Event))
{
// Olayı işle
}
while (Running)
{
sf::Event Event;
while (App.GetEvent(Event))
{
// Olayı işle
}
App.Display();
}
Olayları İşlemek
Bir olay alındığında bakılacak ilk şey Type üyesi içindeki biçimini kontrol etmektir. SFML aşağıdaki olay biçimlerini destekler:
- Closed (Kapatıldı)
- Resized (Boyutlandırıldı)
- LostFocus (OdakKaybedildi)
- GainedFocus (OdakKazanıldı)
- TextEntered (MetinGirildi)
- KeyPressed (TuşaBasıldı)
- KeyReleased (TuşBırakıldı)
- MouseWheelMoved (FareTekeriHareketettirildi)
- MouseButtonPressed (FareTuşunaBasıldı)
- MouseButtonReleased (FareTuşuBırakıldı)
- MouseMoved (FareHareketettirildi)
- MouseEntered (FareGirdi)
- MouseLeft (FareÇıktı)
- JoyButtonPressed (OyunçubuğuTuşunaBasıldı)
- JoyButtonReleased (OyunçubuğuTuşuBırakıldı)
- JoyMoved (OyunçubuğuHareketettirildi)
Olay örnekleri, olayın biçimine göre farklı parametreler alabilir:
Boyutlandırma olayları (Resized)
- Event.Size.Width piksel olarak yeni pencere genişliğini içerir
- Event.Size.Height piksel olarak yeni pencere yüksekliğini içerir
- Event.Key.Code basılan / bırakılan tuşun kodunu içerir
- Event.Key.Alt Alt tuşunun basılıp basılmadığını söyler
- Event.MouseButton.Button fare tuşuna basılıp basılmadığını (ya da bırakılıp bırakılmadığını) içerir
- Event.MouseMove.X yerel kordinatlarda (pencere içinde) fare imlecinin o anki X konumunu içerir
- Event.MouseMove.Y yerel kordinatlarda (pencere içinde) fare imlecinin o anki Y konumunu içerir
- Event.MouseWheel.Delta fare tekeri hareketini içerir (ileri için pozitif, geri için negatif değer)
Fare içinse beş sabit tanımlanmıştır: sf::Mouse::Left, sf::Mouse::Right, sf::Mouse::Middle (tekerlek tuşu), sf::Mouse::XButton1 ve sf::Mouse::XButton2.
Uygulamalarımıza geri dönelim ve uygulamamıza olayları yönetebilmesi için gerekli eklemeleri yapalım. Kullanıcı kapatma düğmesine veya ESC tuşuna bastığında uygulamayı durdurmak için:
sf::Event Event;
while (App.GetEvent(Event))
{
// Pencere kapatıldı
if (Event.Type == sf::Event::Closed)
Running = false;
// ESC tuşuna basıldı
if ((Event.Type == sf::Event::KeyPressed) && (Event.Key.Code == sf::Key::Escape))
Running = false;
}
Bir Pencereyi Kapatmak
SFML ile bir süre uğraştıktan sonra fark edeceksiniz ki kapat düğmesine basmak bir Closed olayı yaratıyor fakat pencereyi yok etmiyor. Bu, kullanıcıya pencere kapatılmadan önce istediği kodları çalıştırması (yapılanların saklanmak istenip istenmediğinin sorulması, vb.) ya da bu işlemi iptal etmesi için fırsat vermektedir. Bir pencereyi gerçekten kapatmak için sf::Window örneğini yok etmeli ya da o pencerenin Close() fonksiyonunu çağırmalısınız.
Bir pencerenin açık olup olmadığını anlamak için IsOpened() fonksiyonunu çağırabilirsiniz.
Şimdi daha güzel görünen bir ana döngü kuralım:
while (App.IsOpened())
{
sf::Event Event;
while (App.GetEvent(Event))
{
// Pencere kapatıldı
if (Event.Type == sf::Event::Closed)
App.Close();
// ESC tuşuna basıldı
if ((Event.Type == sf::Event::KeyPressed) && (Event.Key.Code == sf::Key::Escape))
App.Close();
}
}
Gerçek Zamanlı Girdiler Almak
Bu olay sistemi, pencere kapatmak ya da tek bir tuşu takip etmek için yeterince iyi. Bununla birlikte, sürekli hareket halindeki bir karakterin kontrolü gibi örneklerde, bir yön tuşuna bastığınızda bir problemle karşılaşacaksınız: her hareket arasında işletin sistemince tanımlanmış bir gecikme yaşanacak.
Bu gibi durumlar için daha iyi bir strateji izlenmelidir. Bunun için bir ikilik değişkene, bir tuşa basıldığında true değeri verilebilir ve tuş serbest bırakıldığında bu değişken sıfırlanabilir. Böylece döngü her yeniden başladığında eğer değişken sıfır değilse karakter hareket eder. Bu iş için fazladan bir değişken kullanılması can sıkıcı olabilir, özellikle onlarla baş edemeyeceğiniz kadar çoğaldıklarında. Bunun için SFML, sf::Input ile gerçek zamanlı girdilere erişmek için kolay bir yol sunar.
sf::Input örnekleri kendi başlarına yaşayamazlar, bir pencereye eklenmelidirler. Gerçekte her sf::Window, kendi sf::Input örneğini yönetir ve bunlara sadece istediğinizde sahip olursunuz. Pencereyle ilişkilendirilmiş bir girdiden referans almak için GetInput fonksiyonu kullanılır.
const sf::Input& Input = App.GetInput();Daha sonra, istediğiniz zaman sf::Input örneğiyle fare, klavye ve oyun çubuğu durumları alınabilir:
bool LeftKeyDown = Input.IsKeyDown(sf::Key::Left);Bu eğitselde kısaca pencere girdilerini yönetmeyi ve gerçek zamanlı klavye ve fare durumlarını kullanmayı öğrendik.
bool RightButtonDown = Input.IsMouseButtonDown(sf::Mouse::Right);
bool Joy0Button1Down = Input.IsJoystickButtonDown(0, 1);
unsigned int MouseX = Input.GetMouseX();
unsigned int MouseY = Input.GetMouseY();
float Joystick1X = Input.GetJoystickAxis(1, sf::Joy::AxisX);
float Joystick1Y = Input.GetJoystickAxis(1, sf::Joy::AxisY);
float Joystick1POV = Input.GetJoystickAxis(1, sf::Joy::AxisPOV);
Farenin pencere üzerindeki konumunu konsol üzerinden söyleyen bir örnekle eğitseli tamamlayalım:
Bu eğitselle ilgili diğer örneklere sfml-gelistirme deposundan ulaşabilirsiniz.
Kaynak: Window - Handling events
Yorumlar
Yorum Gönder