Silverlight 2.0 ile Oyun Programlama'ya Giriş

0 dakikada yazıldı

5417 defa okundu

Düzenle

Silverlight 2.0 ile beraber .NET programlama geldiğinde göre hemen
aklımıza gelen konulardan biri de "Oyun Programlama" oluyor. Silverlight
içerisinde var olan StoryBoard yapısını kullanarak oyun
programlamaya çalıştığınız noktada ise "Bu iş böyle olmaz" diyerek
bırakacağınız kesin. Maalesef StoryBoard yapısı çoğu işi kolaylaştırsa
da ve oyun programlama içerisinde belirli bir yeri olsa da işin tamamını
halletmek için yeterli değil.

Oyun programlamada çoğu zaman kare kare çizim yapabilmemiz ve nesnelerin
koordinatları ile tek tek ilgilenebilmemiz gerekir. Daha net bir tanımla
aslında ekranda çizimi bizim kod ile yaptırmamız gerekir. Bu noktada
Silverlight 2.0 Beta 1 ile beraber gelen DispatcherTimer
nesnesini kullanarak bu makalemizde ufak bir örnek yapacağız.

Hedefimiz uygulamamızda bir kare içerisine bir top yerleştirerek bu
topun kare içerisinde duvarlara çarparak sürekli gezmesini sağlamak.
"Bu ne biçim oyun?" diyebilirsiniz. Tabi ki makale sonunda elimizde
hazır bir oyun olmayacak, amacımız oyun programlamada kullanılan yapının
bir modelini yaratmak.

İlk olarak gelin uygulamamızın görsel kısmını tamamlayalım. Yarattığımız
yeni Silverlight 2.0 uygulamasına bir Ellipse yerleştirerek en üst sol
köşeye konumlandıralım. Ellipse'in adı Top olsun. İşlemleri
tamamladığımızda elde edeceğimiz XAML aşağıdaki gibi olacak.

<UserControl
x:Class="SilverlightApplication15.Page"

    xmlns="http://schemas.microsoft.com/client/2007"

    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

    Width="400" Height="300">

  <Grid
x:Name="LayoutRoot"
Background="#FFF4E80C">

    <Ellipse
Height="30" HorizontalAlignment="Left"
Margin="0,0,0,0"
VerticalAlignment="Top" Width="30" Fill="#FFFF0000"
Stroke="#FF000000" ****
x:Name="Top"/>

  </Grid>

</UserControl>

XAML kodumuz hazır olduğuna göre artık arkaplana geçip programlamaya
başlayabiliriz. Uygulamamızda kullanılmak üzere toplam dört adet global
değişken tanımlayacağız.

    Dim Konum As New
System.Windows.Media.TranslateTransform()

    Dim Timer As New
System.Windows.Threading.DispatcherTimer

    Dim XDegisim = 5

    Dim YDegisim = 5

Bu değişkenlerden ilki olan Konum bizim için sürekli olarak topun
ekranın sol üst köşesinden ne kadar sağda ve aşağıda olacağını
saklayacak. Konum değişkeninin tipi TranslateTransform şeklinde. Bu
değişken tipi herhangi bir nesnesinin RenderTransform grubuna
aktardığımızda nesnenin X ve Y koordinatlarında yer değiştirmesini
sağlıyor. Eğer Expression Blend 2.5 içerisinde bir nesne yaratır ve
herhangi bir animasyon ile konumunu değiştirirseniz nesnenizin XAML
kodunun aşağıdaki hale geldiğini görebilirsiniz.

<Rectangle
Height="80" HorizontalAlignment="Left"
Margin="136,93,0,0"
VerticalAlignment="Top" Width="155" Fill="#FFFFFFFF"
Stroke="#FF000000"
x:Name="rectangle"
RenderTransformOrigin="0.5,0.5">

  <Rectangle.RenderTransform>

    <TransformGroup>

      <ScaleTransform/>

      <SkewTransform/>

      <RotateTransform/>

      <TranslateTransform X="10"
Y="10" />

    </TransformGroup>

  </Rectangle.RenderTransform>

</Rectangle>

Expression Blend'in bizim için yarattığı Rectangle koduna da
baktığımızda aslında yapıyı anlayabiliyoruz.Rectangle içerisine
yerleştirilen bir RenderTransform yapısındaki TransformGroup
içerisinde TranslateTransform nesnesi yer alıyor. Bu nesnenin X ve Y
özellikleri de Rectangle'ın ne kadar yer değiştireceğine karar veriyor.
Biz bu aynı yapıyı kendi Top nesnemiz için programatik olarak
kullanacağız.

Şimdi tanımladığımız global değişkenlere geri dönelim.

    Dim Konum As New
System.Windows.Media.TranslateTransform()

    Dim Timer As New
System.Windows.Threading.DispatcherTimer

    Dim XDegisim = 5

    Dim YDegisim = 5

İkinci değişkenimiz bir DispatcherTimer tipinde bir Timer nesnesi.
Bu nesne aslında Windows programlamadan bildiğimiz Timer'dan farklı
değil. Bu Timer'ın da bir Tick durumu ve Interval'i var. Biz
örneğimizde Interval'i çok düşük vererek ekranda çizim yapmak için bu
nesneyi kullanacağız.

Diğer iki global değişkenimizin aslında Top'umuzun bir defada ne kadar
yer değiştireceğine karar veriyor. Bu değerleri büyüterek topun hızını
arttırabilir veya tam tersine azaltarak topunu hızını da
yavaşlatabilirsiniz.

        Timer.Interval = New
TimeSpan(0, 0, 0, 0, 15)

        AddHandler Timer.Tick, AddressOf Timer_Tick

        Timer.Start()

Silverlight uygulamamız sayfada ilk açıldığında hemen Timer nesnemizin
Interval'ini 15 milisaniye olarak ayarlıyoruz. Her 15 milisaniyede bir
ekrandaki Top'un yeni konumunu belirleyeceğiz böylece animasyon
oluşturmuş olacağız. Doğal olarak Timer nesnemizin Tick durumunu da
yakalamamız lazım. Onun için bir de event-handler tanımıyoruz.
Event-Handler kodumuza birazdan bakacağız. Son olarak Timer'ın Start
metodu ile sayacı başlatıyoruz.

Sıra geldi Timer'ın her bir Tick durumunda topun yeni pozisyonunu
ayarlamaya. Aslında kullanacağımız kod çok basit.

        Konum.X += XDegisim

        Konum.Y += YDegisim

        Top.RenderTransform = Konum

Global değişkenimiz olan Konum değişkeninin X ve Y değerlerine
değişim miktarlarını ekleyerek Top'un RenderTransform'una
eşitleyerek Top'un yeni konumunu almasını sağlıyoruz. Fakat ortada bir
sorun var; Top'un duvarlardan sekmesi lazım. Kabaca baktığımızda aslında
yapmamız gereken dört kontrol var. Eğer top alt kenara çarptıysa artık
XDegisim miktarı 5 değil de -5 olmalı. Böylece top tekrar yukarıya doğru
gitmeye başlamalı. Aynı şekilde her kenar için bu kontrolün yapılması
lazım. Eğer top sağ kenara çarptıysa artık YDegisim miktarı 5 değil
de -5 olmalı. Tüm bu kontrolleri yaptığımızda aşağıdaki gibi bir kod
elde ediyoruz.

        If Konum.X = Me.LayoutRoot.ActualWidth - Top.Width Then

            XDegisim = -XDegisim

        End If

        If Konum.Y = Me.LayoutRoot.ActualHeight - Top.Height
Then

            YDegisim = -YDegisim

        End If

        If Konum.X = 0 Then

            XDegisim = Math.Abs(XDegisim)

        End If

        If Konum.Y = 0 Then

            YDegisim = Math.Abs(YDegisim)

        End If

        Konum.X += XDegisim

        Konum.Y += YDegisim

        Top.RenderTransform = Konum

IF kontrollerimizi sırasıyla incelersek; ilkinde eğer topun konumu
sahnemizdeki ana Canvas'ımız olan LayoutRoot'un genişliğinden
Top'un genişliğini de çıkararak aldığımız koordinata ulaşmış ise
hemen XDegisim miktarını - hale getiriyoruz. Böylece Top geri
gitmeye başlayacak. Aynı şekilde ikinci IF kontrolünde de Y yönünde aynı
kontrolü yapıyoruz. Tabi bir de işin diğer tarafı var, yani değişim
miktarı eksi iken top ekranın üstüne veya soluna doğru gidecek. Bu
durumda da üçüncü ve dördüncü IF kontrolümüz ile Top bu pozisyonlara
gelmiş ise değişim miktarlarının mutlak değerini alarak pozitif hale
çeviriyoruz.

Bu hali ile uygulamamızı çalıştırdığımızda topumuzun duvarlardan sekerek
sonsuza dek gezecektir. Kodumuzun son hali aşağıdaki şekilde;

Partial Public Class Page

    Inherits UserControl

 

    Public Sub New()

        InitializeComponent()

    End Sub

 

    Dim Konum As New
System.Windows.Media.TranslateTransform()

    Dim Timer As New
System.Windows.Threading.DispatcherTimer

    Dim XDegisim = 5

    Dim YDegisim = 5

 

    Private Sub Page_Loaded(ByVal sender As Object,
ByVal e As System.Windows.RoutedEventArgs) Handles Me.Loaded

        Timer.Interval = New
TimeSpan(0, 0, 0, 0, 15)

        AddHandler Timer.Tick, AddressOf Timer_Tick

        Timer.Start()

    End Sub

 

    Private Sub Timer_Tick(ByVal sender As Object,
ByVal e As System.EventArgs)

        If Konum.X = Me.LayoutRoot.ActualWidth - Top.Width Then

            XDegisim = -XDegisim

        End If

        If Konum.Y = Me.LayoutRoot.ActualHeight - Top.Height
Then

            YDegisim = -YDegisim

        End If

        If Konum.X = 0 Then

            XDegisim = Math.Abs(XDegisim)

        End If

        If Konum.Y = 0 Then

            YDegisim = Math.Abs(YDegisim)

        End If

        Konum.X += XDegisim

        Konum.Y += YDegisim

        Top.RenderTransform = Konum

    End Sub

 

    Private Sub Page_MouseLeftButtonDown(ByVal sender As Object,
ByVal e As
System.Windows.Input.MouseButtonEventArgs) Handles Me.MouseLeftButtonDown

        If Timer.IsEnabled Then

            Timer.Stop()

        Else

            Timer.Start()

        End If

    End Sub

End Class

Ek olarak bir de sayfanın genelinde MouseLeftButtonDown durumunu
yakalayarak Silverlight uygulamasına tıklandığında Timer'ın
durdurulabilerek tekrar başlatılabilmesi için gerekli kodu da yazarsak
örneğimiz artık tamamlanmış demektir. Artık farklı animasyon yapmak,
farklı koordinat kontrolleri yapmak hatta matematiksel koordinat
hesaplamalarını ortaokula dönüp biraz da trigonometri ekleyerek lise
bilgisi ile de vektörel hesaplamalara çevirmek tamamen size kalmış.

Hepinize kolay gelsin.