<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	xmlns:georss="http://www.georss.org/georss" xmlns:geo="http://www.w3.org/2003/01/geo/wgs84_pos#" xmlns:media="http://search.yahoo.com/mrss/"
	>

<channel>
	<title>Videogames Laboratory &#187; .NET</title>
	<atom:link href="http://videogameslab.wordpress.com/category/net/feed/" rel="self" type="application/rss+xml" />
	<link>http://videogameslab.wordpress.com</link>
	<description>O συναρπαστικός κόσμος της ανάπτυξης βιντεοπαιχνιδιών</description>
	<lastBuildDate>Tue, 22 Dec 2009 09:49:02 +0000</lastBuildDate>
	<generator>http://wordpress.com/</generator>
	<language>el</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<cloud domain='videogameslab.wordpress.com' port='80' path='/?rsscloud=notify' registerProcedure='' protocol='http-post' />
<image>
		<url>http://www.gravatar.com/blavatar/255dbf67d2b39d909d863d39cc6cb572?s=96&#038;d=http://s.wordpress.com/i/buttonw-com.png</url>
		<title>Videogames Laboratory &#187; .NET</title>
		<link>http://videogameslab.wordpress.com</link>
	</image>
	<atom:link rel="search" type="application/opensearchdescription+xml" href="http://videogameslab.wordpress.com/osd.xml" title="Videogames Laboratory" />
		<item>
		<title>Videogames Laboratory Challenge #2</title>
		<link>http://videogameslab.wordpress.com/2009/10/29/videogames-laboratory-challenge-2/</link>
		<comments>http://videogameslab.wordpress.com/2009/10/29/videogames-laboratory-challenge-2/#comments</comments>
		<pubDate>Thu, 29 Oct 2009 13:02:24 +0000</pubDate>
		<dc:creator>Κώστας Αναγνώστου</dc:creator>
				<category><![CDATA[.NET]]></category>
		<category><![CDATA[Arkanoid]]></category>
		<category><![CDATA[C#]]></category>
		<category><![CDATA[Challenge]]></category>
		<category><![CDATA[XNA Game Studio]]></category>
		<category><![CDATA[Ανάπτυξη βιντεοπαιχνιδιών]]></category>
		<category><![CDATA[Προγραμματισμός]]></category>

		<guid isPermaLink="false">http://videogameslab.wordpress.com/?p=462</guid>
		<description><![CDATA[Η περίοδος αυτή αποδεικνύεται η πιο πολυάσχολη του χρόνου με τις προθεσμίες αιτήσεων για χρηματοδότηση έρευνας στο Πανεπιστήμιο να πλησιάζουν ταχύτατα. Αυτό έχει αντίκτυπο και στο blog μιας ο διαθέσιμος ελεύθερος χρόνος μου έχει συρρικνωθεί. Μέχρι να βρω λοιπόν το χρόνο να ολοκληρώσω τη σειρά tutorial για το Arkanoid, σκέφτηκα να εμπλέξω τους αναγνώστες του [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=videogameslab.wordpress.com&blog=5040448&post=462&subd=videogameslab&ref=&feed=1" />]]></description>
			<content:encoded><![CDATA[<div class='snap_preview'><br /><p><span style="font-family:Verdana;font-size:9pt;">Η περίοδος αυτή αποδεικνύεται η πιο πολυάσχολη του χρόνου με τις προθεσμίες αιτήσεων για χρηματοδότηση έρευνας στο Πανεπιστήμιο να πλησιάζουν ταχύτατα. Αυτό έχει αντίκτυπο και στο blog μιας ο διαθέσιμος ελεύθερος χρόνος μου έχει συρρικνωθεί. Μέχρι να βρω λοιπόν το χρόνο να ολοκληρώσω τη σειρά tutorial για το Arkanoid, σκέφτηκα να εμπλέξω τους αναγνώστες του blog με ένα Videogames Laboratory Challenge. Στην ουσία είναι το δεύτερο challenge μιας και το πρώτο αφορούσε την <a href="http://videogameslab.wordpress.com/2009/08/13/squash-the-bugs/" target="_blank">εκσφαλμάτωση ενός παιχνιδιού</a> (και για το οποίο έλαβα ελάχιστες απαντήσεις δυστυχώς).<br />
</span></p>
<p><span style="font-family:Verdana;font-size:9pt;">Μέχρι στιγμής στο <a href="http://videogameslab.wordpress.com/category/arkanoid/" target="_blank">Arkanoid</a> χρησιμοποιούμε το παρακάτω κώδικα για να σχεδιάσουμε τη πίστα και να τοποθετήσουμε τα τουβλάκια στην οθόνη:<br />
</span></p>
<pre class="brush: csharp;">
            for (int j = 0; j &lt; numOfRows; j++)
            {
                for (int i = 0; i &lt; bricksPerRow; i++)
                {
                    Rectangle rect = new Rectangle(i * (brickWidth + brickSpacing),
                                                   rowStart + j * (brickHeight + brickSpacing),
                                                   brickWidth, brickHeight);
                    bricks[j * bricksPerRow + i] = new Brick(rect, Color.Red, whiteTile);
                    numOfVisibleBricks++;
                }
            }
</pre>
<p><span style="font-family:Verdana;font-size:9pt;">Σε ένα for-loop δηλαδή τοποθετούμε τα τουβλάκια, ανά τακτά διαστήματα, σε γραμμές και στήλες. Αυτός το τρόπος σχεδιασμού πίστας (level design) είναι πολύ δύσχρηστος και επιβάλλει στο σχεδιαστή της πίστας να συνεργάζεται άμεσα με το προγραμματιστή έτσι ώστε να του υποδεικνύει τι αλλαγές πρέπει να γίνουν στο σχέδιο της πίστας και πού (και να γίνεται πάλι compile ο κώδικας με κάθε αλλαγή). Επιπλέον είναι αρκετά δύσκολο να αλλάξεις το σχέδιο της πίστας σε κάτι άλλο από γραμμές με τουβλάκια. Από την άλλη είναι επιθυμητό ο σχεδιαστής να μην ασχολείται καθόλου με το κώδικα του παιχνιδιού, να σχεδιάζει με κάποιο τρόπο τη πίστα και να μεταφέρει το αποτέλεσμα στο προγραμματιστή για απεικόνιση (data-driven development), όπως γίνεται άλλωστε και στη βιομηχανία ανάπτυξης βιντεοπαιχνιδιών.<br />
</span></p>
<p><span style="font-family:Verdana;font-size:9pt;">Η πρόκληση λοιπόν αφορά το εξής:<br />
</span></p>
<p><span style="font-family:Verdana;font-size:9pt;"><strong>Προτείνετε τρόπους με τους οποίους μπορεί να γίνει ο σχεδιασμός της πίστας πιο εύκολος και ευέλικτος. Προσοχή, με τον όρο σχεδιασμό αναφέρομαι στο καθορισμό της τοποθεσίας που θα καταλήξει το κάθε τουβλάκι. Η τοποθέτηση και απεικόνιση καθαυτή θα γίνει με κώδικα αναγκαστικά.</strong><br />
</span></p>
<p><span style="font-family:Verdana;font-size:9pt;">Αν ο τρόπος που προτείνετε είναι «καλύτερος» από αυτόν που έχω εγώ υπόψη (και σε λογικό επίπεδο δυσκολίας για ένα εισαγωγικό tutorial), θα γίνει υλοποίηση αυτού στο επόμενο tutorial (με τιμές και δάφνες στο άτομο που το πρότεινε). Σε κάθε περίπτωση μπορείτε και κάνετε την υλοποίηση οι ίδιοι και να ανεβάσετε το κώδικα στο <a href="http://videogameslab.wordpress.com/2009/07/23/code-repository-2/" target="_blank">Code Repository</a>. Απορίες και διευκρινίσεις στα σχόλια του post.<br />
</span></p>
<p><span style="font-family:Verdana;font-size:9pt;">Περιμένουμε τις συμμετοχές σας!<br />
</span></p>
  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/videogameslab.wordpress.com/462/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/videogameslab.wordpress.com/462/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/videogameslab.wordpress.com/462/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/videogameslab.wordpress.com/462/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/videogameslab.wordpress.com/462/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/videogameslab.wordpress.com/462/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/videogameslab.wordpress.com/462/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/videogameslab.wordpress.com/462/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/videogameslab.wordpress.com/462/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/videogameslab.wordpress.com/462/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=videogameslab.wordpress.com&blog=5040448&post=462&subd=videogameslab&ref=&feed=1" /></div>]]></content:encoded>
			<wfw:commentRss>http://videogameslab.wordpress.com/2009/10/29/videogames-laboratory-challenge-2/feed/</wfw:commentRss>
		<slash:comments>9</slash:comments>
	
		<media:content url="http://0.gravatar.com/avatar/4bd00ab99710c6e67ef0a28c68628aad?s=96&#38;d=http%3A%2F%2F0.gravatar.com%2Favatar%2Fad516503a11cd5ca435acc9bb6523536%3Fs%3D96" medium="image">
			<media:title type="html">thinkinggamer</media:title>
		</media:content>
	</item>
		<item>
		<title>Arkanoid: Game State Management μέρος 2ο</title>
		<link>http://videogameslab.wordpress.com/2009/10/06/arkanoid-game-state-part2/</link>
		<comments>http://videogameslab.wordpress.com/2009/10/06/arkanoid-game-state-part2/#comments</comments>
		<pubDate>Tue, 06 Oct 2009 10:00:46 +0000</pubDate>
		<dc:creator>Κώστας Αναγνώστου</dc:creator>
				<category><![CDATA[.NET]]></category>
		<category><![CDATA[Arkanoid]]></category>
		<category><![CDATA[C#]]></category>
		<category><![CDATA[XNA Game Studio]]></category>
		<category><![CDATA[Ανάπτυξη βιντεοπαιχνιδιών]]></category>
		<category><![CDATA[Προγραμματισμός]]></category>

		<guid isPermaLink="false">http://videogameslab.wordpress.com/?p=452</guid>
		<description><![CDATA[Στο προηγούμενο tutorial σχεδιάσαμε το game state management του Arkanoid και το υλοποιήσαμε για την διαδικασία Update του παιχνιδιού. Σήμερα θα το υλοποιήσουμε και για την διαδικασία Draw, συμπληρώνοντας παράλληλα το παιχνίδι με Εισαγωγική οθόνη, λειτουργία Pause και οθόνη επιτυχίας ή αποτυχίας του παίκτη.
Είχαμε αναφέρει ότι το game state management υλοποιείται στην απλή μορφή του [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=videogameslab.wordpress.com&blog=5040448&post=452&subd=videogameslab&ref=&feed=1" />]]></description>
			<content:encoded><![CDATA[<div class='snap_preview'><br /><p><span style="font-family:Verdana;font-size:9pt;">Στο <a href="http://videogameslab.wordpress.com/2009/10/02/arkanoid-part3/" target="_blank">προηγούμενο tutorial</a> σχεδιάσαμε το game state management του Arkanoid και το υλοποιήσαμε για την διαδικασία Update του παιχνιδιού. Σήμερα θα το υλοποιήσουμε και για την διαδικασία Draw, συμπληρώνοντας παράλληλα το παιχνίδι με Εισαγωγική οθόνη, λειτουργία Pause και οθόνη επιτυχίας ή αποτυχίας του παίκτη.</span><br />
<span id="more-452"></span><span style="font-family:Verdana;font-size:9pt;">Είχαμε αναφέρει ότι το game state management υλοποιείται στην απλή μορφή του με ένα switch-statement. Το ίδιο ακριβώς swith-statement (το σκελετό δηλαδή) που χρησιμοποιήσαμε στην Update θα χρησιμοποιήσουμε και στην Draw. Πριν αρχίσουμε όμως, χάριν ευαναγνωσιμότητας(!) του κώδικα, θα κάνουμε και πάλι μια μικρή αναδιοργάνωση του κώδικα της Draw, δημιουργώντας μια νέα μέθοδο renderWorld() η οποία θα απεικονίζει όλα τα αντικείμενα του παιχνιδιού (τουβλάκια, ρακέτα, μπάλα και σκορ) στην οθόνη:<br />
</span></p>
<pre class="brush: csharp;">
        private void renderWorld()
        {
            string message = String.Format(&quot;Lives: {0}, Score: {1}&quot;, lives, score);

            spriteBatch.DrawString(font, message, new Vector2(10, 10), Color.Yellow);

            foreach (Brick brick in bricks)
            {
                brick.Draw(spriteBatch);
            }

            spriteBatch.Draw(whiteTile, paddle, Color.White);
            spriteBatch.Draw(whiteTile, ball, Color.Yellow);
        }
</pre>
<p><span style="font-family:Verdana;font-size:9pt;">Όπως και στην updateWorld(), καμιά νέα λειτουργία δεν συμπεριλαμβάνεται στην renderWorld(). Ο κώδικας της Draw() γίνεται τώρα:<br />
</span></p>
<pre class="brush: csharp;">
        protected override void Draw(GameTime gameTime)
        {
            GraphicsDevice.Clear(Color.Black);

            spriteBatch.Begin();
            renderWorld();
            spriteBatch.End();

            base.Draw(gameTime);
        }
</pre>
<p><span style="font-family:Verdana;font-size:9pt;">Τίποτα το συγκλονιστικό μέχρις εδώ. Προσθέτουμε τώρα το switch-statement που αναφέραμε παραπάνω:<br />
</span></p>
<pre class="brush: csharp;">
        protected override void Draw(GameTime gameTime)
        {
            GraphicsDevice.Clear(Color.Black);

            spriteBatch.Begin();

            switch (gameState)
            {
                case GameState.Intro:

                    break;
                case GameState.Playing:

                    renderWorld();

                    break;
                case GameState.Paused:

                    break;
                case GameState.Won:

                    break;
                case GameState.Lost:

                    break;
            }

            spriteBatch.End();

            base.Draw(gameTime);
        }
</pre>
<p><span style="font-family:Verdana;font-size:9pt;">Αν παρατηρήσατε, μετακίνησα τη renderWorld() στο block του GameState.Playing, μια και λογικά πρέπει να απεικονίζουμε τα αντικείμενα του παιχνιδιού όταν ο παίκτης παίζει. Ας προσθέσουμε την εισαγωγική οθόνη τώρα. Σε ένα οποιοδήποτε σχεδιαστικό πρόγραμμα φτιάχνουμε με μεγάλα γράμματα το λογότυπο του παιχνιδιού. Εγώ το έφτιαξα σε Fireworks και το έσωσα ως logo.png. Μπορείτε επιπλέον να το αποθηκεύσετε ως jpg, gif και bmp.<br />
</span></p>
<p><img src="http://videogameslab.files.wordpress.com/2009/10/100609_1000_arkanoidgam1.png" alt="" /><span style="font-family:Verdana;font-size:9pt;"><br />
</span></p>
<p><span style="font-family:Verdana;font-size:9pt;">Προσθέτουμε το αρχείο του λογότυπου στο Content project του παιχνιδιού (δεξί κλικ επάνω στο όνομα, Add/New Item).<br />
</span></p>
<p><span style="font-family:Verdana;font-size:9pt;">Για να χρησιμοποιήσουμε την υφή στο παιχνίδι θα ορίσουμε μια μεταβλητή logoTexture στην κυρίως κλάση του παιχνιδιού:<br />
</span></p>
<pre class="brush: csharp;">
    public class Game1 : Microsoft.Xna.Framework.Game
    {
        …

        Texture2D logoTexture;
        …
</pre>
<p><span style="font-family:Verdana;font-size:9pt;">Στην LoadContent φορτώνουμε την υφή ως συνήθως:<br />
</span></p>
<pre class="brush: csharp;">
        protected override void LoadContent()
        {
       	 …

            whiteTile = Content.Load&lt;Texture2D&gt;(&quot;white_tile&quot;);
            logoTexture = Content.Load&lt;Texture2D&gt;(&quot;logo&quot;);

        	…
        }
</pre>
<p><span style="font-family:Verdana;font-size:9pt;">Στην Draw τώρα, στο block GameState.Intro, απλά απεικονίζουμε την υφή με τη χρήση της spritebatch στην τοποθεσία (50,150):<br />
</span></p>
<pre class="brush: csharp;">
        protected override void Draw(GameTime gameTime)
        {
            GraphicsDevice.Clear(Color.Black);

            spriteBatch.Begin();

            switch (gameState)
            {
                case GameState.Intro:

                    spriteBatch.Draw(logoTexture, new Vector2(50,150), Color.White);

                    break;

                case GameState.Playing:
                    renderWorld();
                    break;

                case GameState.Paused:
                    break;

                case GameState.Won:
                    break;

                case GameState.Lost:
                    break;
            }

            spriteBatch.End();
            base.Draw(gameTime);
        }
</pre>
<p><span style="font-family:Verdana;font-size:9pt;">Προσοχή πρέπει να δοθεί στο τρόπο χρήσης της spriteBatch.Draw (), δεν έχω ορίσει Rectangle μέσα στο οποίο θα απεικονιστεί η υφή, την τοποθεσία στην οποία θα απεικονιστεί. Για το λόγο αυτό η spriteBatch.Draw() θα την απεικονίσει στο φυσικό της μέγεθος (χωρίς μεγέθυνση ή σμίκρυνση).<br />
</span></p>
<p><span style="font-family:Verdana;font-size:9pt;">Αν τρέξουμε τώρα το παιχνίδι με F5, θα δούμε την εισαγωγική οθόνη του παιχνιδιού με το λογότυπο:<br />
</span></p>
<p><img src="http://videogameslab.files.wordpress.com/2009/10/100609_1000_arkanoidgam2.png" alt="" /><span style="font-family:Verdana;font-size:9pt;"><br />
</span></p>
<p><span style="font-family:Verdana;font-size:9pt;">Επειδή έχουμε υλοποιήσει ήδη το state machine στην Update, αν πατήσουμε ENTER το παιχνίδι θα αρχίσει. Όμως ο παίκτης δεν το ξέρει αυτό και θα πρέπει να τον ενημερώσουμε με σχετικό μήνυμα. Γνωρίζουμε ήδη πώς να απεικονίζουμε κείμενο στην οθόνη με τη χρήση της spriteBatch.DrawString. Επειδή στο παιχνίδι θέλω σε πολλές περιπτώσεις να απεικονίζω κείμενο στο κέντρο της οθόνης, όσον αφορά τη Χ διάσταση σε οποιοδήποτε ύψος Υ, θα φτιάξω μια βοηθητική μέθοδο που θα το κάνει αυτόματα αυτό:<br />
</span></p>
<pre class="brush: csharp;">
        private void renderStringCentered(string message, int Y, Color color)
        {
            Vector2 msgSize = font.MeasureString(message);
            spriteBatch.DrawString(font, message, new Vector2((viewWidth - msgSize.X) / 2, Y), color);
        }
</pre>
<p><span style="font-family:Verdana;font-size:9pt;">Η μέθοδος renderStringCentered() παίρνει ως όρισμα το κείμενο, το ύψος Y στο οποίο θέλω να εμφανίζεται και το χρώμα του. Στην συνέχεια υπολογίζει το πλάτος του κειμένου με τη χρήση της μεθόδου font.MeasureString(). Το font είναι το αντικείμενο που περιέχει τη γραμματοσειρά που φορτώσαμε από το δίσκο και που χρησιμοποιούμε για να απεικονίσουμε κείμενο. Το αντικείμενο αυτό ξέρει το πλάτος και το ύψος κάθε χαρακτήρα της γραμματοσειράς. Οπότε αν του δώσουμε ως όρισμα το κείμενο που θέλουμε να απεικονίσουμε αυτό θα μας επιστρέψει το ύψος και το πλάτος του σε pixel, σε μια μεταβλητή τύπου Vector2. Τέλος η renderStringCentered() απεικονίζει το κείμενο στην οθόνη με τη χρήση της spriteBatch.DrawString() χρησιμοποιώντας το πλάτος του κειμένου που υπολογίσαμε προηγουμένως (msgSize.X) για να κεντράρει το κείμενο στην οθόνη.<br />
</span></p>
<p><span style="font-family:Verdana;font-size:9pt;">Επιπλέον, για να κάνω την εισαγωγική οθόνη σχετική με το παιχνίδι θα απεικονίσω πίσω από το λογότυπο μερικές σειρές τουβλάκια:<br />
</span></p>
<pre class="brush: csharp;">
        protected override void Draw(GameTime gameTime)
        {
            GraphicsDevice.Clear(Color.Black);

            spriteBatch.Begin();

            switch (gameState)
            {
                case GameState.Intro:

                    for (int j = 0; j &lt; 10; j++)
                    {
                        for (int i = 0; i &lt; bricksPerRow; i++)
                        {
                            Rectangle rect = new Rectangle(i * (brickWidth + brickSpacing),
                                                           100 + j * (brickHeight + brickSpacing),
                                                           brickWidth, brickHeight);

                            spriteBatch.Draw(whiteTile, rect, Color.LimeGreen);
                        }
                    }

                    spriteBatch.Draw(logoTexture, new Vector2(50,150), Color.White);
                    renderStringCentered( &quot;Press [Enter] to begin&quot;,430, Color.White);
                    break;

                case GameState.Playing:
                    renderWorld();
                    break;

                case GameState.Paused:
                    break;

                case GameState.Won:
                    break;

                case GameState.Lost:
                    break;
            }

            spriteBatch.End();
            base.Draw(gameTime);
        }
</pre>
<p><span style="font-size:9pt;"><span style="font-family:Verdana;">Απεικονίζουμε 10 σειρές τουβλάκια πίσω από το λογότυπο με πράσινο χρώμα. Επιπλέον απεικονίζουμε τη προτροπή στο χρήστη να πατήσει το ENTER για να ξεκινήσει το παιχνίδι (προτάσεις για καλύτερες επιλογές χρώματων δεκτές! </span><span style="font-family:Wingdings;">J</span><span style="font-family:Verdana;"> ).<br />
</span></span></p>
<p><img src="http://videogameslab.files.wordpress.com/2009/10/100609_1000_arkanoidgam3.png" alt="" /><span style="font-family:Verdana;font-size:9pt;"><br />
</span></p>
<p><span style="font-family:Verdana;font-size:9pt;">Έχουμε μέχρι στιγμής υλοποιήσει τις καταστάσεις GameState.Intro και GameState.Playing. Οι υπόλοιπες καταστάσεις είναι ακόμα πιο απλές. Για τη Paused το μόνο που έχουμε να κάνουμε είναι να δείξουμε στο χρήστη ότι το παιχνίδι έχει «παγώσει».<br />
</span></p>
<pre class="brush: csharp;">
        protected override void Draw(GameTime gameTime)
        {
            GraphicsDevice.Clear(Color.Black);

            spriteBatch.Begin();

            switch (gameState)
            {
//υπόλοιπος κώδικας

                case GameState.Paused:
                    renderWorld();
                    renderStringCentered(&quot;PAUSED!&quot;, 270, Color.Yellow);
                    break;

//υπόλοιπος κώδικας
            }

            spriteBatch.End();
            base.Draw(gameTime);
        }
</pre>
<p><span style="font-family:Verdana;font-size:9pt;">Η κατάσταση αυτή μπορεί να λάβει χώρα όταν ο παίκτης παίζει το παιχνίδι, οπότε είναι καλό μαζί με το μήνυμα να απεικονίζουμε στο φόντο και τα αντικείμενα του παιχνιδιού (αλλιώς θα φαινόταν παράξενο να βλέπει το «PAUSED» σε μια μαύρη οθόνη). Το μόνο που έχουμε να κάνουμε είναι να καλέσουμε τη renderWorld() λίγο πριν απεικονίσουμε το κείμενο. Επειδή στην Update δεν ανανεώνουμε τις θέσεις των αντικειμένων του παιχνιδιού όταν το παιχνίδι βρίσκεται σε κατάσταση GameState.Paused, τα αντικείμενα δεν μετακινούνται και έτσι απλά υλοποιείται η λειτουργία Paused. Το παιχνίδι ξαναρχίζει όταν ο παίκτης πατήσει το πλήκτρο P ξανά.<br />
</span></p>
<p><span style="font-family:Verdana;font-size:9pt;">Οι καταστάσεις GameState.Won και GameState.Lost έχουν ακριβώς την ίδια λογική:<br />
</span></p>
<pre class="brush: csharp;">
        protected override void Draw(GameTime gameTime)
        {
            GraphicsDevice.Clear(Color.Black);

            spriteBatch.Begin();

            switch (gameState)
            {
//υπόλοιπος κώδικας

                case GameState.Won:
                    renderWorld();
                    renderStringCentered(&quot;YOU WIN!&quot;, 270, Color.Yellow);
                    renderStringCentered(&quot;Press Enter to play again&quot;, 300, Color.White);
                    break;

                case GameState.Lost:
                    renderWorld();
                    renderStringCentered(&quot;YOU LOSE!&quot;, 270, Color.Yellow);
                    renderStringCentered(&quot;Press Enter to play again&quot;, 300, Color.White);
                    break;
            }

            spriteBatch.End();
            base.Draw(gameTime);
        }
</pre>
<p><span style="font-family:Verdana;font-size:9pt;">Στις περιπτώσεις αυτές εμφανίζουμε το ανάλογο μήνυμα επιτυχίας ή αποτυχίας στο παίκτη και τον προτρέπουμε να πατήσει ENTER για να παίξει ξανά. Αν πατήσει το ESC το παιχνίδι θα τον μεταφέρει στην Εισαγωγική οθόνη.<br />
</span></p>
<p><span style="font-family:Verdana;font-size:9pt;">Αυτό ήταν, το game state management, μαζί με τις διάφορες οθόνες του παιχνιδιού (σχεδόν) υλοποιήθηκε. Μένουν 2-3 (ουσιαστικές) λεπτομέρειες. Καταρχάς δεν έχουμε ορίσει ακόμα πως το παιχνίδι θα μεταβαίνει στη κατάσταση Won ή Lost. Η Lost είναι απλή, το μόνο που έχουμε να κάνουμε είναι να ελέγξουμε στην updateWorld αν ο παίκτης έχει χάσει όλες τις ζωές του.<br />
</span></p>
<pre class="brush: csharp;">
        private void updateWorld()
        {
            //υπόλοιπος κώδικας

            //check if player lost all lives
            if (lives &lt;= 0)
            {
                gameState = GameState.Lost;
            }
        }
</pre>
<p><span style="font-family:Verdana;font-size:9pt;">Το αν κέρδισε είναι λίγο πιο πολύπλοκο, πρέπει να διαπιστώσουμε αν όλα τα τουβλάκια στην οθόνη έχουν καταστραφεί. Ο πιο απλός τρόπος να υλοποιήσουμε αυτή τη λειτουργία είναι να ορίσουμε μια μεταβλητή numOfVisibleBricks στη κλαση Game1 που να μειώνεται κατά ένα κάθε φορά που καταστρέφεται ένα τουβλάκι μέχρι να γίνει 0.<br />
</span></p>
<pre class="brush: csharp;">
    public class Game1 : Microsoft.Xna.Framework.Game
    {
        int numOfVisibleBricks;
</pre>
<p><span style="font-family:Verdana;font-size:9pt;">Στην LoadContent αυξάνω τη τιμή της μεταβλητής κάθε φορά που δημιουργώ ένα νέο τουβλάκι με τη χρήση του τελεστή new:<br />
</span></p>
<pre class="brush: csharp;">
        protected override void LoadContent()
        {
            //υπόλοιπος κώδικας

            for (int j = 0; j &lt; numOfRows; j++)
            {
                for (int i = 0; i &lt; bricksPerRow; i++)
                {
                    Rectangle rect = new Rectangle(i * (brickWidth + brickSpacing),
                                                   rowStart + j * (brickHeight + brickSpacing),
                                                   brickWidth, brickHeight);
                    bricks[j * bricksPerRow + i] = new Brick(rect, Color.Red, whiteTile);
                    numOfVisibleBricks++;
                }
            }
        }
</pre>
<p><span style="font-family:Verdana;font-size:9pt;">Τέλος στην updateWorld, μειώνω την τιμή της κατά ένα, κάθε φορά που διαπιστώνω σύγκρουση μπάλας με τουβλάκι.<br />
</span></p>
<pre class="brush: csharp;">
       private void updateWorld()
        {
            //υπόλοιπος κώδικας

            //check ball-brick collision
            foreach (Brick brick in bricks)
            {
                if (brick.CheckHit(ball))
                {
                    numOfVisibleBricks--;
                    ballDirection.Y = -ballDirection.Y;
                    score += 1000;
                    if (score % 10000 == 0)
                    {
                        ballSpeed += 1;
                    }
                    break;
                }
            }

            //check if player lost all lives
            if (lives &lt;= 0)
            {
                gameState = GameState.Lost;
            }
            else if (numOfVisibleBricks &lt;= 0)
            {
                gameState = GameState.Won;
            }
        }
</pre>
<p><span style="font-family:Verdana;font-size:9pt;">Παράλληλα, στο τέλος της updateWorld, ελέγχω μήπως ο αριθμός των ορατών bricks έχει φτάσει στο μηδέν. Σε μια τέτοια περίπτωση αλλάζω το state του παιχνιδιού σε GameState.Won και το παιχνίδι τελειώνει.<br />
</span></p>
<p><span style="font-family:Verdana;font-size:9pt;">Υπάρχουν και πιο κομψοί τρόποι να υλοποιηθεί αυτό (από μια global μεταβλητή εννοώ). Γενικά στα παιχνίδια στα οποία υπάρχουν πολλά «όμοια» αντικείμενα (διαστημόπλοια, εχθροί, τουβλάκια, συστήματα σωματιδίων κλπ), συνήθως ορίζουμε ένα αντικείμενο-manager το οποίο αναλαμβάνει τη διαχείριση τους, το οποίο είναι υπεύθυνο και για πληροφορίες όπως αυτή που ζητάμε. Αυτό είναι όμως κάτι που θα γνωρίσουμε σε επόμενο παιχνίδι.<br />
</span></p>
<p><span style="font-family:Verdana;font-size:9pt;">Αν τρέξετε το παιχνίδι τώρα και πατήσετε ΕΝΤΕR για να αρχίσει και P για να παγώσει, θα παρατηρήσετε ότι άλλες φορές ενεργοποιείται το πάγωμα και άλλες όχι. Αυτό συμβαίνει και με άλλες λειτουργίες στο παιχνίδι και οφείλεται στο ότι το παιχνίδι αλλάζει πολλές φορές state όσο ένα πλήκτρο (το P στην περίπτωση μας είναι πατημένο). Πρέπει συνεπώς να υλοποιήσουμε μια λειτουργία που να μου επιστρέφει true όταν το κάποιο πλήκτρο πατήθηκε για πρώτη φορά και false όσο είναι πατημένο.<br />
</span></p>
<p><span style="font-family:Verdana;font-size:9pt;">Καταρχάς πρέπει να ορίσουμε μια μεταβλητή previousKeyboardState η οποία θα κρατά το keyboardState του προηγούμενου καρέ (frame) του παιχνιδιού:<br />
</span></p>
<pre class="brush: csharp;">
    public class Game1 : Microsoft.Xna.Framework.Game
    {
        int numOfVisibleBricks;
        GameState gameState;
        KeyboardState keyboardState;
        KeyboardState previousKeyboardState;
</pre>
<p><span style="font-family:Verdana;font-size:9pt;">Στην συνέχεια, πριν ολοκληρώσουμε την Update του τρέχοντος καρέ, αποθηκεύουμε το keyboardState στην μεταβλητή αυτή:<br />
</span></p>
<pre class="brush: csharp;">
        protected override void Update(GameTime gameTime)
        {
            //υπόλοιπος κώδικας

            previousKeyboardState = keyboardState;

            base.Update(gameTime);
        }
</pre>
<p><span style="font-family:Verdana;font-size:9pt;">Τώρα είμαστε έτοιμοι να υλοποιήσουμε τη μέθοδο που να επιστρέφει true μόνο όταν το δεδομένο πληκτρο key πατιέται για πρώτη φορά.<br />
</span></p>
<pre class="brush: csharp;">
        private bool keyPressed(Keys key)
        {
            if (previousKeyboardState.IsKeyUp(key) &amp;&amp; keyboardState.IsKeyDown(key))
            {
                return true;
            }
            return false;
        }
</pre>
<p><span style="font-family:Verdana;font-size:9pt;">Αν στο προηγούμενο καρέ το πλήκτρο key ήταν ελεύθερο (previousKeyboardState.IsKeyUp(key)) και στο τρέχον καρέ είναι πατημένο (keyboardState.IsKeyDown(key)), τότε επιστρέφουμε true, διαφορετικά false.<br />
</span></p>
<p><span style="font-family:Verdana;font-size:9pt;">Θα αξιοποιήσουμε τη μέθοδο αυτή στην Update σε 3 game states:<br />
</span></p>
<pre class="brush: csharp;">
        protected override void Update(GameTime gameTime)
        {
            keyboardState = Keyboard.GetState();

            switch (gameState)
            {
                case GameState.Intro:
                    if (keyPressed(Keys.Escape))
                    {
                        this.Exit();
                    }
                    else if (keyboardState.IsKeyDown(Keys.Enter))
                    {
                        gameState = GameState.Playing;
                    }
                break;
                case GameState.Playing:
                    if (keyboardState.IsKeyDown(Keys.Escape))
                    {
                        gameState = GameState.Intro;
                    }
                    else if (keyPressed(Keys.P))
                    {
                        gameState = GameState.Paused;
                    }
                    else
                    {
                        updateWorld();
                    }
                    break;
                case GameState.Paused:
                    if (keyPressed(Keys.P))
                    {
                        gameState = GameState.Playing;
                    }
                    break;

               //υπόλοιπος κώδικας

            }

            previousKeyboardState = keyboardState;

            base.Update(gameTime);
        }
</pre>
<p><span style="font-family:Verdana;font-size:9pt;">Στο GameState.Intro, επειδή φτάνουμε στην κατάσταση αυτή με ESC από άλλες καταστάσεις (την ώρα που παίζει ο χρήστης, ή βρίσκεται σε οθόνη αποτυχίας), πρέπει να εξασφαλίσουμε ότι ο χρήστης πάτησε μια ακόμα φορά το ESC πριν κλείσουμε εντελώς το παιχνίδι (αλλιώς θα βγει από το παιχνίδι χωρίς να το έχει επιλέξει). Τέλος για τη λειτουργία Pause μιλήσαμε, πρέπει να ενεργοποιείται και απενεργοποιείται με διακριτά πατήματα του πλήκτρου P.<br />
</span></p>
<p><span style="font-size:9pt;"><span style="font-family:Verdana;">Όποιος έχει μείνει ζωντανός μέχρι σ&#8217;αυτό το σημείο το έχει κάνει από την αστείρευτη επιθυμία και επιμονή του να δει το παιχνίδι ολοκληρωμένο οπότε δεν μπορώ να του το στερήσω αυτό. Οι υπόλοιποι έχουν έτσι κι αλλιώς αποκοιμηθεί ή τα παρατήσει οπότε δεν θα τους πειράξει </span><span style="font-family:Wingdings;">J</span><span style="font-family:Verdana;">. Μένει ακόμα κάτι να υλοποιήσουμε πριν ολοκληρώσουμε το game state management και αυτό είναι η δυνατότητα του παίκτη να ξαναρχίζει τη πίστα από την αρχή. Χρειαζόμαστε ένα τρόπο να απεικονίζουμε ξανά τα τουβλάκια στις αρχικές τους θέσεις, να μηδενίζουμε το σκορ και να επαναρχικοποιουμε τις ζωές του παίκτη και να τοποθετούμε ρακέτα και μπάλα εκεί που ήταν αρχικά.<br />
</span></span></p>
<p><span style="font-family:Verdana;font-size:9pt;">Μέχρι στιγμής αυτές τις λειτουργίες τις κάναμε εν μέρει στην μέθοδο Initialize() και εν μέρει στην LoadContent(). Αυτό που θα πρέπει να γίνει είναι να μεταφέρουμε όλες τις αρχικοποιήσεις σε μια μέθοδο την οποία θα μπορούμε να  καλούμε από οπουδήποτε:<br />
</span></p>
<pre class="brush: csharp;">
        private void resetGame()
        {
            paddle = new Rectangle(150, 550, 90, 15);
            paddleSpeed = 10;

            ball = new Rectangle(150, 400, 15, 15);
            ballDirection = new Vector2(1, -1);
            ballDirection.Normalize();
            ballSpeed = 5;

            lives = 3;
            score = 0;

            numOfVisibleBricks = 0;
            for (int j = 0; j &lt; numOfRows; j++)
            {
                for (int i = 0; i &lt; bricksPerRow; i++)
                {
                    Rectangle rect = new Rectangle(i * (brickWidth + brickSpacing),
                                                   rowStart + j * (brickHeight + brickSpacing),
                                                   brickWidth, brickHeight);
                    bricks[j * bricksPerRow + i] = new Brick(rect, Color.Red, whiteTile);
                    numOfVisibleBricks++;
                }
            }
        }
</pre>
<p><span style="font-family:Verdana;font-size:9pt;">Η resetGame() πραγματοποιεί όλες τις αρχικοποιήσεις που αναφέραμε. Προσοχή πρέπει να δοθεί στο ότι οι αντίστοιχες αρχικοποιήσεις έχουν αφαιρεθεί από τις Initialize() και LoadContent().<br />
</span></p>
<p><span style="font-family:Verdana;font-size:9pt;">Την resetGame θα την καλέσουμε από την Update κάθε φορά που θέλουμε να αρχικοποιήσουμε τη πίστα:<br />
</span></p>
<pre class="brush: csharp;">
        protected override void Update(GameTime gameTime)
        {
            keyboardState = Keyboard.GetState();

            switch (gameState)
            {
                case GameState.Intro:
                    if (keyPressed(Keys.Escape))
                    {
                        this.Exit();
                    }
                    else if (keyboardState.IsKeyDown(Keys.Enter))
                    {
                        resetGame();
                        gameState = GameState.Playing;
                    }
                break;

               //υπόλοιπος κώδικας

                case GameState.Won:
                    if (keyboardState.IsKeyDown(Keys.Escape))
                    {
                        gameState = GameState.Intro;
                    }
                    else if (keyboardState.IsKeyDown(Keys.Enter))
                    {
                        resetGame();
                        gameState = GameState.Playing;
                    }
                    break;
                case GameState.Lost:
                    if (keyboardState.IsKeyDown(Keys.Escape))
                    {
                        gameState = GameState.Intro;
                    }
                    else if (keyboardState.IsKeyDown(Keys.Enter))
                    {
                        resetGame();
                        gameState = GameState.Playing;
                    }
                    break;
            }

            previousKeyboardState = keyboardState;

            base.Update(gameTime);
        }
</pre>
<p><span style="font-family:Verdana;font-size:9pt;">Τη πίστα την αρχικοποιούμε στο block GameState.Intro, όταν ο παίκτης πατήσει το ENTER για να αρχίσει το παιχνίδι, όπως και στα block GameState.Won και GameState.Lost για τον ίδιο λόγο (να δοκιμάσει την πίστα ξανά).<br />
</span></p>
<p><span style="font-family:Verdana;font-size:9pt;">Αυτό ήταν, τελειώσαμε για σήμερα (αλήθεια!). Το παιχνίδι είναι πλήρες από λειτουργίες και ο παίκτης μπορεί να δοκιμάσει τη πίστα όσες φορές θέλει.<br />
</span></p>
<p><span style="font-family:Verdana;font-size:9pt;">Σήμερα καλύψαμε πολύ έδαφος. Το συμπέρασμα της ημέρας πρέπει να είναι ότι όσο απλό και αν είναι ένα παιχνίδι, απαιτεί πολύ συνοδευτικό κώδικα για να υλοποιήθούν λειτουργίες που δεν έχουν άμεση σχέση με τη διαδικασία παιχνιδιού, άλλα είναι απαραίτητες για την καλή εμπειρία του χρήστη.<br />
</span></p>
<p><span style="font-family:Verdana;font-size:9pt;">Ο κώδικας του tutorial βρίσκεται στο <a href="http://code.google.com/p/videogameslab/" target="_blank">Code Repository</a> μέσω SVN ή και σε <a href="http://videogameslab.googlecode.com/files/Arcanoid_part4.zip" target="_blank">zip μορφή</a>. Στο επόμενο tutorial θα δούμε πως μπορούμε να φτιάξουμε διαφορετικές πίστες στο παιχνίδι.<br />
</span></p>
  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/videogameslab.wordpress.com/452/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/videogameslab.wordpress.com/452/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/videogameslab.wordpress.com/452/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/videogameslab.wordpress.com/452/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/videogameslab.wordpress.com/452/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/videogameslab.wordpress.com/452/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/videogameslab.wordpress.com/452/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/videogameslab.wordpress.com/452/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/videogameslab.wordpress.com/452/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/videogameslab.wordpress.com/452/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=videogameslab.wordpress.com&blog=5040448&post=452&subd=videogameslab&ref=&feed=1" /></div>]]></content:encoded>
			<wfw:commentRss>http://videogameslab.wordpress.com/2009/10/06/arkanoid-game-state-part2/feed/</wfw:commentRss>
		<slash:comments>8</slash:comments>
	
		<media:content url="http://0.gravatar.com/avatar/4bd00ab99710c6e67ef0a28c68628aad?s=96&#38;d=http%3A%2F%2F0.gravatar.com%2Favatar%2Fad516503a11cd5ca435acc9bb6523536%3Fs%3D96" medium="image">
			<media:title type="html">thinkinggamer</media:title>
		</media:content>

		<media:content url="http://videogameslab.files.wordpress.com/2009/10/100609_1000_arkanoidgam1.png" medium="image" />

		<media:content url="http://videogameslab.files.wordpress.com/2009/10/100609_1000_arkanoidgam2.png" medium="image" />

		<media:content url="http://videogameslab.files.wordpress.com/2009/10/100609_1000_arkanoidgam3.png" medium="image" />
	</item>
		<item>
		<title>Arkanoid: Game State Management</title>
		<link>http://videogameslab.wordpress.com/2009/10/02/arkanoid-part3/</link>
		<comments>http://videogameslab.wordpress.com/2009/10/02/arkanoid-part3/#comments</comments>
		<pubDate>Fri, 02 Oct 2009 17:47:06 +0000</pubDate>
		<dc:creator>Κώστας Αναγνώστου</dc:creator>
				<category><![CDATA[.NET]]></category>
		<category><![CDATA[Arkanoid]]></category>
		<category><![CDATA[C#]]></category>
		<category><![CDATA[XNA Game Studio]]></category>
		<category><![CDATA[Ανάπτυξη βιντεοπαιχνιδιών]]></category>
		<category><![CDATA[Προγραμματισμός]]></category>

		<guid isPermaLink="false">http://videogameslab.wordpress.com/?p=441</guid>
		<description><![CDATA[Μέχρι στιγμής στο παιχνίδι Arkanoid (μέρος 1, μέρος 2) έχουμε υλοποιήσει την κλάση που εκπροσωπεί τα τουβλάκια (Brick) έχουμε τοποθετήσει τα τουβλάκια στην σωστή θέση, έχουμε υλοποιήσει κίνηση της μπάλας και της ρακέτας, συγκρούσεις μεταξύ των αντικειμένων του παιχνιδιού και αυξάνουμε και το σκορ του παίκτη. Το παιχνίδι είναι λειτουργικό, μπορεί να ελέγξει ο παίκτης [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=videogameslab.wordpress.com&blog=5040448&post=441&subd=videogameslab&ref=&feed=1" />]]></description>
			<content:encoded><![CDATA[<div class='snap_preview'><br /><p><span style="font-family:Verdana;font-size:9pt;">Μέχρι στιγμής στο παιχνίδι Arkanoid (<a href="http://videogameslab.wordpress.com/2009/09/14/arkanoid-part-1/" target="_blank">μέρος 1</a>, <a href="http://videogameslab.wordpress.com/2009/09/24/arkanoid-part2/" target="_blank">μέρος 2</a>) έχουμε υλοποιήσει την κλάση που εκπροσωπεί τα τουβλάκια (Brick) έχουμε τοποθετήσει τα τουβλάκια στην σωστή θέση, έχουμε υλοποιήσει κίνηση της μπάλας και της ρακέτας, συγκρούσεις μεταξύ των αντικειμένων του παιχνιδιού και αυξάνουμε και το σκορ του παίκτη. Το παιχνίδι είναι λειτουργικό, μπορεί να ελέγξει ο παίκτης τη μπάλα και να καταστρέψει τα τουβλάκια, αλλά δεν έχουμε ορίσει το πότε νικά και πότε χάνει ο παίκτης έτσι ώστε να σταματάμε το παιχνίδι και να του εμφανίζουμε το ανάλογο μήνυμα. Για να το κάνουμε λίγο πιο εύκολο και κομψό αυτό, θα κάνουμε ένα βήμα πίσω και θα υλοποιήσουμε στο παιχνίδι κάτι που ονομάζεται game state management (διαχείριση καταστάσεων παιχνιδιού;).</span><br />
<span id="more-441"></span><br />
<span style="font-family:Verdana;font-size:9pt;">Το game state management βασίζεται σε κάτι που ονομάζεται μηχανή καταστάσεων (state machine), η οποία είναι ένα σύνολο από καταστάσεις και κανόνες που ορίζουν μεταβάσεις μεταξύ των. Αυτό δεν είναι τόσο τρομακτικό όσο ακούγεται και το εξηγώ με ένα παράδειγμα. Φανταστείτε μια μέρα από τη ζωή σας. Το βράδυ βρίσκεστε στο κρεβάτι σας και κοιμάστε. Στις 8 το πρωί χτυπά το ξυπνητήρι και ξυπνάτε. Αν πεινάτε, μπορεί να φάτε πρωινό ή μπορεί και να φύγετε αμέσως για την δουλειά/σχολείο/πανεπιστήμιο σας. Στο σχολείο (ας πούμε), παρακολουθείτε το μάθημα μέχρι να χτυπήσει το κουδούνι, και μετά βγαίνετε διάλλειμα. Μετά ξαναχτυπά το κουδούνι και μπαίνετε στην τάξη. Όταν έρθει 2 η ώρα πηγαίνετε σπίτι. Εκεί, αν πεινάτε τρώτε και κοιμάστε, διαφορετικά κοιμάστε απευθείας (βαρετή ζωή ομολογουμένως).<br />
</span></p>
<p><span style="font-family:Verdana;font-size:9pt;">Αν μελετήσετε την παραπάνω αφήγηση, μπορείτε να διακρίνετε ότι αποτελείται από καταστάσεις στις οποίες εσείς βρίσκεστε (κοιμάμαι, τρώω, παρακολουθώ μάθημα) και συμβάντα (κανόνες) που προκαλούν αλλαγή στην κατάσταση σας (ξυπνητήρι, κουδούνι). Μπορούμε να ζωγραφίσουμε λοιπόν στο χαρτί ένα σχήμα (γράφος) που να περιγράφει εποπτικά την παραπάνω αφήγηση ως εξής:<br />
</span></p>
<p><img src="http://videogameslab.files.wordpress.com/2009/10/100209_1747_arkanoidgam1.png" alt="" /><span style="font-family:Verdana;font-size:9pt;"><br />
</span></p>
<p><span style="font-family:Verdana;font-size:9pt;">Κάθε έλλειψη περιέχει μια κατάσταση στην οποία μπορεί να βρίσκεται ο αναγνώστης. Τα βελάκια δείχνουν μεταβάσεις από μια κατάσταση σε μια άλλη όταν λάβει χώρα το συμβάν με μαύρα γράμματα που υπάρχει δίπλα σε κάθε γραμμή μετάβασης. Από την κατάσταση «κοιμάμαι» θα μεταβώ στην κατάσταση «ξύπνησα» όταν χτυπήσει το ξυπνητήρι. Από την κατάσταση «Παρακολουθώ μάθημα» θα μεταβώ στην κατάσταση «Διάλλειμα» όταν χτυπήσει το κουδούνι, και το αντίστροφο.<br />
</span></p>
<p><span style="font-family:Verdana;font-size:9pt;">Ο γράφος αυτός καταστάσεων, και μεταβάσεων μεταξύ τους, ονομάζεται state machine (μηχανή καταστάσεων). Και επειδή ο αριθμός των καταστάσεων είναι περιορισμένος (όχι άπειρος), ο γράφος ονομάζεται πιο συγκεκριμένα <strong>finite state machine</strong> (μηχανή πεπερασμένων καταστάσεων).<br />
</span></p>
<p><span style="font-family:Verdana;font-size:9pt;">To finite state machine είναι από τα πιο χρήσιμα εργαλεία για την ανάπτυξη βιντεοπαιχνιδιών. Αν σκεφτεί κανείς ένα οποιοδήποτε παιχνίδι, αυτό βρίσκεται ανά πάσα στιγμή σε μια προκαθορισμένη κατάσταση: Εισαγωγή/Τίτλοι, Μενού, Παίξιμο, Παύση (Pause), Οθόνη νίκης, Οθόνη αποτυχίας κλπ. Για να μεταβούμε από την μια κατάσταση σε μια άλλη συνήθως πατάμε κάποιο πλήκτρο στο χειριστήριο ή στο πληκτρολόγιο.<br />
</span></p>
<p><span style="font-family:Verdana;font-size:9pt;">Μπορούμε να αξιοποιήσουμε ένα finite state machine στο Arkanoid λοιπόν για να του δώσουμε μια εισαγωγική οθόνη και οθόνες νίκης και αποτυχίας στο παίκτη. Για να το κάνουμε αυτό χρειαζόμαστε 2 πράγματα, μια απαρίθμηση των καταστάσεων και μια μεταβλητή που θα κρατά την τρέχουσα κατάσταση. Στο αρχείο Game1.cs προσθέτουμε στην κορυφή (εκτός της κλάσης Game1):<br />
</span></p>
<pre class="brush: csharp;">
namespace Arcanoid
{
    public enum GameState
    {
        Intro,
        Playing,
        Paused,
        Lost,
        Won
    };
</pre>
<p><span style="font-family:Verdana;font-size:9pt;">Ορίζουμε 5 καταστάσεις στις οποίες μπορεί να βρίσκεται το παιχνίδι, την εισαγωγή (Intro), το κανονικό παίξιμο (Playing), την παύση (Paused), την αποτυχία (Lost) και τη νίκη (Won) του παίκτη. Το enum ορίζει ουσιαστικά ένα τύπο δεδομένων GameState ο οποίο μπορεί να πάρει μόνο κάποια από τις 5 αυτές τιμές. Μπορώ να ορίσω μια μεταβλητή τύπου GameState ως εξής:<br />
</span></p>
<pre class="brush: csharp;">
    public class Game1 : Microsoft.Xna.Framework.Game
    {
        GameState gameState;

        GraphicsDeviceManager graphics;
        SpriteBatch spriteBatch;
        SpriteFont font;
</pre>
<p><span style="font-family:Verdana;font-size:9pt;">Η μεταβλητή gameState θα μπορεί να λάβει λοιπόν μια από τις 5 προκαθορισμένες τιμές που περιγράφουν τη κατάσταση του παιχνιδιού. Από τη στιγμή που έχουμε ορίσει τις καταστάσεις του παιχνιδιού πρέπει να ορίσουμε πως θα γίνεται η μετάβαση από τη μια στην άλλη. Φτιάχνουμε ένα finite state machine ανάλογο με αυτό που περιγράψαμε παραπάνω:<br />
</span></p>
<p><img src="http://videogameslab.files.wordpress.com/2009/10/100209_1747_arkanoidgam2.png" alt="" /><span style="font-family:Verdana;font-size:9pt;"><br />
</span></p>
<p><span style="font-family:Verdana;font-size:9pt;">Οι ελλείψεις με έντονο περίγραμμα σηματοδοτούν την αρχική και τελική κατάσταση του παιχνιδιού. Έχουμε μια έλλειψη για κάθε κατάσταση παιχνιδιού που αναφέραμε και τις μεταξύ τους μεταβάσεις που ορίζονται από κανόνες. Για παράδειγμα αν είμαστε στην αρχική οθόνη και ο παίκτης πατήσει το πλήκτρο ENTER τότε το παιχνίδι θα αρχίσει (θα αλλάξει η κατάσταση του σε Playing δηλαδή). Αν το παιχνίδι τρέχει (Playing) και ο παίκτης πατήσει το πλήκτρο P τότε το παιχνίδι θα παγώσει (Paused) και θα επιστρέψει στην κατάσταση Playing μόνο αν ο παίκτης ξαναπατήσει το πλήκτρο P. Από τη κατάσταση Playing ο παίκτης θα μεταβεί στη Lost όταν χάσει όλες τις ζωές του (lives = 0). Από την κατάσταση Playing θα μεταβεί στην κατάσταση Won (κερδίσει) μόνο όταν χτυπήσει όλα τα τουβλάκια, και ούτω κάθε εξής.<br />
</span></p>
<p><span style="font-family:Verdana;font-size:9pt;">Με βάση το state machine που δημιουργήσαμε παραπάνω μπορούμε εύκολα να υλοποιήσουμε το game state management του παιχνιδιού μας. Το μόνο που έχουμε να ελέγξουμε είναι το σε ποια κατάσταση είμαστε κάθε χρονική στιγμή (gameState) και αν συντρέχει κάποιος λόγος (πάτημα πλήκτρου κλπ) να μεταβούμε σε κάποια άλλη κατάσταση. Δυνητικά αυτό θα μπορούσε να υλοποιηθεί με μια σειρά από if-then-else αλλά γρήγορα θα δημιουργούσε κώδικα δυσανάγνωστο. Παράδειγμα για την μετάβαση από Intro σε Playing και μόνο, θα είχαμε:<br />
</span></p>
<pre class="brush: csharp;">
            if (gameState == GameState.Intro)
            {
                if (Keyboard.GetState().IsKeyDown(Keys.Escape))
                {
                    this.Exit();
                }
                else if (Keyboard.GetState().IsKeyDown(Keys.Enter))
                {
                    gameState = GameState.Playing;
                }
            }
</pre>
<p><span style="font-family:Verdana;font-size:9pt;">Και για τις 5 καταστάσεις η αναγνωσιμότητα του κώδικα θα μειωνόταν σημαντικά. Επιπλέον πολλά παιχνίδια έχουν πολλές περισσότερες από 5 καταστάσεις (αν είχε μενού, προφίλ παίκτη, βοήθεια, inventory κλπ).<br />
</span></p>
<p><span style="font-family:Verdana;font-size:9pt;">Για το λόγω αυτό θα χρησιμοποιήσουμε ένα συνδυασμό switch-statement και αναδιοργάνωσης κώδικα. Το switch-statement είναι μια πιο κομψή έκδοση του if-then-else και υπάρχει σε όλες τις γλώσσες από C/C++/Java, μέχρι και Visual Basic. Στη μορφή που θα το χρησιμοποιήσουμε μοιάζει ως εξής:<br />
</span></p>
<pre class="brush: csharp;">
            switch (gameState)
            {
                case GameState.Intro:

                    break;
                case GameState.Playing:

                    break;
                case GameState.Paused:

                    break;
                case GameState.Won:

                    break;
                case GameState.Lost:

                    break;
            }
</pre>
<p><span style="font-family:Verdana;font-size:9pt;">Ανάλογα με την τιμή της gameState, η εκτέλεση του κώδικα θα συνεχίσει σε κάποιο από τα &#8220;case GameState.XXXX&#8221;. Όταν ο κώδικας συναντήσει την εντολή break η εκτέλεση του συγκεκριμένου block κώδικα θα διακοπεί και θα συνεχίσει μετά το τέλος του switch.<br />
</span></p>
<p><span style="font-family:Verdana;font-size:9pt;">Πριν προσθέσω αυτό το switch-statement στην μέθοδο Update(), θα κάνω μια μικρή αναδιαμόρφωση του κώδικα, δημιουργώντας μια νέα μέθοδο updateWorld() στην οποία θα μεταφέρω όλο το κώδικα της Update() που ασχολείται με την κίνηση των αντικειμένων και την ανίχνευση συγκρούσεων. Ο κώδικας αυτός εκτελείται μόνο στην περίπτωση του το παιχνίδι βρίσκεται στην κατάσταση Playing (ο παίκτης μπορεί και παίζει δηλαδή) και δεν αφορά της άλλες καταστάσεις. Εξάγοντας τον σε μια ξεχωριστή μέθοδο κάνω την Update() και το switch-statement πιο ευανάγνωστο:<br />
</span></p>
<pre class="brush: csharp;">
        private void updateWorld()
        {
            if (Keyboard.GetState().IsKeyDown(Keys.Left))
            {
                paddle.X -= (int)paddleSpeed;
            }

            if (Keyboard.GetState().IsKeyDown(Keys.Right))
            {
                paddle.X += (int)paddleSpeed;
            }

            ball.X += (int)(ballDirection.X * ballSpeed);
            ball.Y += (int)(ballDirection.Y * ballSpeed);

            //check paddle-wall collision
            if (paddle.Left &lt; 0)
            {
                paddle.X = 0;
            }
            else if (paddle.Right &gt; viewWidth)
            {
                paddle.X = viewWidth - paddle.Width;
            }

            //check ball-wall collision
            if (ball.Left &lt;= 0 || ball.Right &gt;= viewWidth)
            {
                ballDirection.X = -ballDirection.X;
            }
            else if (ball.Top &lt;= 0 || ball.Bottom &gt;= viewHeight)
            {
                ballDirection.Y = -ballDirection.Y;

                if (ball.Bottom &gt;= viewHeight)
                {
                    lives--;
                }
            }

            //check ball-paddle collision
            if (ballDirection.Y &gt; 0 &amp;&amp;
                ball.Bottom &gt;= paddle.Top &amp;&amp;
                ((ball.Left &gt;= paddle.Left &amp;&amp; ball.Left &lt;= paddle.Right) ||
                  (ball.Right &gt;= paddle.Left &amp;&amp; ball.Right &lt;= paddle.Right))
                )
            {
                ballDirection.Y = -ballDirection.Y;
            }

            //check ball-brick collision
            foreach (Brick brick in bricks)
            {
                if (brick.CheckHit(ball))
                {
                    ballDirection.Y = -ballDirection.Y;
                    score += 1000;
                    break;
                }
            }

        }
</pre>
<p><span style="font-family:Verdana;font-size:9pt;">Η μέθοδος updateWorld() δεν περιέχει καμιά νέα λειτουργία. Την ορίζω ως private γιατί δεν έχω σκοπό να την καλέσω εκτός του κυρίως αντικειμένου του παιχνιδιού (Game1).<br />
</span></p>
<p><span style="font-family:Verdana;font-size:9pt;">Έπειτα ορίζω μια μεταβλητή τύπου KeyboardState στην οποία θα αποθηκεύσω την κατάσταση του πληκτρολογίου (για να μην την ζητώ συνέχεια από την μέθοδο Keyboard.GetState()).<br />
</span></p>
<pre class="brush: csharp;">
    public class Game1 : Microsoft.Xna.Framework.Game
    {
        GameState gameState;
        KeyboardState keyboardState;
</pre>
<p><span style="font-family:Verdana;font-size:9pt;">Είμαστε έτοιμοι τώρα να ορίσουμε τις μεταβάσεις μεταξύ των διάφορων καταστάσεων στην Update. Διαβάζοντας το παραπάνω state machine που δημιουργήσαμε και μεταφράζοντας το σε κώδικα έχουμε:<br />
</span></p>
<pre class="brush: csharp;">
        protected override void Update(GameTime gameTime)
        {
            keyboardState = Keyboard.GetState();

            switch (gameState)
            {
                case GameState.Intro:
                    if (keyboardState.IsKeyDown(Keys.Escape))
                    {
                        this.Exit();
                    }
                    else if (keyboardState.IsKeyDown(Keys.Enter))
                    {
                        gameState = GameState.Playing;
                    }
                break;
                case GameState.Playing:
                    if (keyboardState.IsKeyDown(Keys.Escape))
                    {
                        gameState = GameState.Intro;
                    }
                    else if (keyboardState.IsKeyDown(Keys.P))
                    {
                        gameState = GameState.Paused;
                    }

                    updateWorld();

                    break;
                case GameState.Paused:
                    if (keyboardState.IsKeyDown(Keys.P))
                    {
                        gameState = GameState.Playing;
                    }
                    break;
                case GameState.Won:
                    if (keyboardState.IsKeyDown(Keys.Escape))
                    {
                        gameState = GameState.Intro;
                    }
                    else if (keyboardState.IsKeyDown(Keys.Enter))
                    {
                        gameState = GameState.Playing;
                    }
                    break;
                case GameState.Lost:
                    if (keyboardState.IsKeyDown(Keys.Escape))
                    {
                        gameState = GameState.Intro;
                    }
                    else if (keyboardState.IsKeyDown(Keys.Enter))
                    {
                        gameState = GameState.Playing;
                    }
                    break;
            }

            base.Update(gameTime);
        }
</pre>
<p><span style="font-family:Verdana;font-size:9pt;">Είναι αρκετά ξεκάθαρο το τι συμβαίνει στο switch-statement. Αν για παράδειγμα το gameState είναι ίσο με GameState.Intro, τότε ελέγχουμε αν το πλήκτρο ESC έχει πατηθεί. Αν ναι τότε βγαίνουμε από το παιχνίδι εντελώς. Αλλιώς, αν έχουμε πατήσει το ENTER, τότε η κατάσταση του παιχνιδιού (gameState) αλλάζει σε GameState.Playing. Την επόμενη φορά που θα κληθεί η Update, το switch-statement θα εκτελέσει το block που αφορά το GameState.Playing. Εκεί θα γίνει ο έλεγχος αν ο παίκτης έχει πατήσει το πλήκτρο ESC και σε μια τέτοια περίπτωση η κατάσταση του παιχνιδιού (gameState) θα αλλάξει σε GameState.Intro. Αλλιώς ελέγχεται αν έχει πατηθεί το πλήκτρο P και αυτή τη περίπτωση το παιχνίδι μεταβαίνει στην κατάσταση GameState.Paused. Επίσης στο block αυτό (GameState.Playing)  και μόνο καλούμε και την μέθοδο updateWorld() για να κινήσουμε αντικείμενα και να υπολογίσουμε συγκρούσεις. Παρόμοια είναι και η λογική για τις υπόλοιπες καταστάσεις. Ανάλογα με το πια κατάσταση βρίσκεται το παιχνίδι κάθε φορά και ανάλογα με κάποια συνθήκη το παιχνίδια θα μεταβεί στην προκαθορισμένη κατάσταση.<br />
</span></p>
<p><span style="font-family:Verdana;font-size:9pt;">Μένουν αρκετά να κάνουμε έτσι ώστε να ολοκληρώσουμε το game state management και το tutorial έγινε αρκετά μεγάλο οπότε θα σταματήσουμε εδώ για σήμερα. Ήταν αρκετά θεωρητικό το άρθρο, αλλά δημιουργήσαμε την υποδομή για να προσθέσουμε στο επόμενο tutorial πολλές λειτουργίες όπως αρχική οθόνη, λειτουργία Pause, και οθόνες επιτυχίας και αποτυχίας στο παιχνίδι.<br />
</span></p>
<p><span style="font-family:Verdana;font-size:9pt;">Νέος κώδικας δεν υπάρχει στο Code Repository. Όμως για να μην μείνετε παραπονεμένοι και να σας ανοίξει η όρεξη για περισσότερα πάρτε μια μικρή γεύση από το επόμενο tutorial:<br />
</span><br />
<span style="font-family:Verdana;font-size:9pt;"><br />
<img src="http://videogameslab.files.wordpress.com/2009/10/100209_1747_arkanoidgam3.png" alt="" /><br />
</span></p>
  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/videogameslab.wordpress.com/441/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/videogameslab.wordpress.com/441/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/videogameslab.wordpress.com/441/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/videogameslab.wordpress.com/441/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/videogameslab.wordpress.com/441/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/videogameslab.wordpress.com/441/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/videogameslab.wordpress.com/441/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/videogameslab.wordpress.com/441/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/videogameslab.wordpress.com/441/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/videogameslab.wordpress.com/441/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=videogameslab.wordpress.com&blog=5040448&post=441&subd=videogameslab&ref=&feed=1" /></div>]]></content:encoded>
			<wfw:commentRss>http://videogameslab.wordpress.com/2009/10/02/arkanoid-part3/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
	
		<media:content url="http://0.gravatar.com/avatar/4bd00ab99710c6e67ef0a28c68628aad?s=96&#38;d=http%3A%2F%2F0.gravatar.com%2Favatar%2Fad516503a11cd5ca435acc9bb6523536%3Fs%3D96" medium="image">
			<media:title type="html">thinkinggamer</media:title>
		</media:content>

		<media:content url="http://videogameslab.files.wordpress.com/2009/10/100209_1747_arkanoidgam1.png" medium="image" />

		<media:content url="http://videogameslab.files.wordpress.com/2009/10/100209_1747_arkanoidgam2.png" medium="image" />

		<media:content url="http://videogameslab.files.wordpress.com/2009/10/100209_1747_arkanoidgam3.png" medium="image" />
	</item>
		<item>
		<title>Arkanoid μέρος 2ο</title>
		<link>http://videogameslab.wordpress.com/2009/09/24/arkanoid-part2/</link>
		<comments>http://videogameslab.wordpress.com/2009/09/24/arkanoid-part2/#comments</comments>
		<pubDate>Thu, 24 Sep 2009 07:07:19 +0000</pubDate>
		<dc:creator>Κώστας Αναγνώστου</dc:creator>
				<category><![CDATA[.NET]]></category>
		<category><![CDATA[Arkanoid]]></category>
		<category><![CDATA[XNA Game Studio]]></category>
		<category><![CDATA[Ανάπτυξη βιντεοπαιχνιδιών]]></category>
		<category><![CDATA[Προγραμματισμός]]></category>

		<guid isPermaLink="false">http://videogameslab.wordpress.com/?p=421</guid>
		<description><![CDATA[Ξεκινήσαμε με το προηγούμενο άρθρο τη δεύτερη σειρά tutorial πάνω στην ανάπτυξη βιντεοπαιχνιδιών, εστιάζοντας στο παιχνίδι Arkanoid αυτή τη φορά. Το άρθρο βγήκε αναγκαστικά μεγάλο διότι έπρεπε να ορίσουμε ένα νέο αντικείμενο το οποίο θα αναπαριστά το τουβλάκι στο παιχνίδι, καθώς και την συμπεριφορά του (απεικόνιση και έλεγχος συγκρούσεων). Με βάση τη κλάση αυτή δημιουργήσαμε [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=videogameslab.wordpress.com&blog=5040448&post=421&subd=videogameslab&ref=&feed=1" />]]></description>
			<content:encoded><![CDATA[<div class='snap_preview'><br /><p><span style="font-family:Verdana;font-size:9pt;">Ξεκινήσαμε με το προηγούμενο <a href="http://videogameslab.wordpress.com/2009/09/14/arkanoid-part-1/" target="_blank">άρθρο</a> τη δεύτερη σειρά tutorial πάνω στην ανάπτυξη βιντεοπαιχνιδιών, εστιάζοντας στο παιχνίδι Arkanoid αυτή τη φορά. Το άρθρο βγήκε αναγκαστικά μεγάλο διότι έπρεπε να ορίσουμε ένα νέο αντικείμενο το οποίο θα αναπαριστά το τουβλάκι στο παιχνίδι, καθώς και την συμπεριφορά του (απεικόνιση και έλεγχος συγκρούσεων). Με βάση τη κλάση αυτή δημιουργήσαμε και απεικονίσαμε τις σειρές με τα τουβλάκια στην οθόνη. Επιπλέον ορίσαμε και απεικονίσαμε τη ρακέτα και την μπάλα.<br />
</span></p>
<p><span style="font-family:Verdana;font-size:9pt;">Στο σημερινό άρθρο, για να το κρατήσουμε σε λογικό μέγεθος, θα προσθέσουμε στο παιχνίδι μόνο κίνηση της μπάλας και της ρακέτας, ανίχνευση συγκρούσεων (collision detection) και σκορ παίκτη.<br />
<span id="more-421"></span></span><span style="font-family:Verdana;font-size:9pt;">Το πώς υλοποιούμε την κίνηση της ρακέτας και της μπάλας το εξηγήσαμε κατά την δημιουργία του <a href="http://videogameslab.wordpress.com/2009/07/13/hello-pong-part-3/" target="_blank">Pong</a>. Ορίζουμε ένα Rectangle paddle το οποίο περιγράφει την θέση και το μέγεθος της ρακέτας, και παρομοίως ένα Rectangle ball για τη μπάλα. Επιπλέον χρειαζόμαστε ένα διάνυσμα Vector2 με το όνομα ballDirection το οποίο δείχνει την κατεύθυνση κίνησης της μπάλας και μια μεταβλητή ballSpeed η οποία καθορίζει πόσο γρήγορα κινείται η μπάλα και μια αντίστοιχη paddleSpeed για τη ρακέτα.<br />
</span></p>
<pre class="brush: csharp;">
public class Game1 : Microsoft.Xna.Framework.Game
{
     GraphicsDeviceManager graphics;
     SpriteBatch spriteBatch;
     Texture2D whiteTile;
     Rectangle paddle;
     Vector2 paddleDirection;
     float paddleSpeed;
     Rectangle ball;
     Vector2 ballDirection;
     float ballSpeed;
</pre>
<p><span style="font-family:Verdana;font-size:9pt;">Η ρακέτα στο Arkanoid κινείται μόνο αριστερά δεξιά, όποτε για να πετύχουμε τη κίνηση αυτή πρέπει να μεταβάλλουμε τη μεταβλητή paddle.X στην μέθοδο Update ανάλογα με το αν ο παίκτη πατά το αριστερό ή το δεξί βελάκι (cursor key):<br />
</span></p>
<pre class="brush: csharp;">
protected override void Update(GameTime gameTime)
{
     // Allows the game to exit
     if (Keyboard.GetState().IsKeyDown(Keys.Escape))
     {
          this.Exit();
     }

     if (Keyboard.GetState().IsKeyDown(Keys.Left))
     {
          paddle.X -= (int)paddleSpeed;
     }

     if (Keyboard.GetState().IsKeyDown(Keys.Right))
     {
          paddle.X += (int)paddleSpeed;
     }

     base.Update(gameTime);
}
</pre>
<p><span style="font-family:Verdana;font-size:9pt;">Θυμίζω ότι για να διαπιστώσουμε ποιο πλήκτρο πατά ο χρήστης χρησιμοποιούμε τη μέθοδο GetState() του αντικειμένου Keyboard (το οποίο δημιουρυγεί εξορισμού το XNA).<br />
</span></p>
<p><span style="font-family:Verdana;font-size:9pt;">Για να μετακινήσουμε τη μπάλα, δεν έχουμε παρά να προσθέσουμε στις X και Y συντεταγμένες του Rectangle ball μια μετατόπιση που προκύπτει από το διάνυσμα κατευθυνσης ballDirection και τη ταχύτητα της μπάλας ballSpeed.<br />
</span></p>
<p><span style="font-family:Verdana;font-size:9pt;">Στην Initialise αρχικοποιούμε τις δυο αυτές μεταβλητές ως:<br />
</span></p>
<pre class="brush: csharp;">
protected override void Initialize()
{
     viewHeight = graphics.GraphicsDevice.Viewport.Height;
     viewWidth = graphics.GraphicsDevice.Viewport.Width;

     paddle = new Rectangle(150, 550, 90, 15);
     paddleSpeed = 10;

     ball = new Rectangle(150, 400, 15, 15);
     ballDirection = new Vector2(1, -1);
     ballDirection.Normalize();
     ballSpeed = 5;
</pre>
<p><span style="font-family:Verdana;font-size:9pt;">Η αρχική κατεύθυνση της μπάλας είναι δηλαδή προς τα πάνω και δεξιά και η ταχύτητα της είναι 5. Επίσης κανονικοποιώ το διάνυσμα της κατεύθυνσης ballDirection με τη μέθοδο Normalize() ώστε αυτό να έχει μήκος ένα και η τελική μετατόπιση τη μπάλας να εξαρτάται μόνο από την ταχύτητα της ballSpeed.<br />
</span></p>
<p><span style="font-family:Verdana;font-size:9pt;">Επιστροφή στην Update για υπολογισμό της νέας θέσης της μπάλας:<br />
</span></p>
<pre class="brush: csharp;">
protected override void Update(GameTime gameTime)
{
     // Allows the game to exit
     if (Keyboard.GetState().IsKeyDown(Keys.Escape))
     {
          this.Exit();
     }

     if (Keyboard.GetState().IsKeyDown(Keys.Left))
     {
          paddle.X -= (int)paddleSpeed;
     }

     if (Keyboard.GetState().IsKeyDown(Keys.Right))
     {
          paddle.X += (int)paddleSpeed;
     }

     ball.X += (int)(ballDirection.X * ballSpeed);
     ball.Y += (int)(ballDirection.Y * ballSpeed);
     base.Update(gameTime);
}
</pre>
<p><span style="font-family:Verdana;font-size:9pt;">Αν τρέξουμε τώρα το παιχνίδι (με F5), θα μπορούμε να ελέγξουμε την κίνηση της ρακέτας αριστερά-δεξιά και η μπάλα θα κινηθεί προς τα πάνω-δεξιά μέχρι να βγει εκτός των ορίων της πίστας (χωρίς να συγκρουστεί με κανένα τουβλάκι). Αυτό που μας λείπει είναι η ανίχνευση συγκρούσεων.<br />
</span></p>
<p><span style="font-family:Verdana;font-size:9pt;">Καταρχάς ας περιορίσουμε τη κίνηση της ρακέτας μέσα στα όρια της πίστας:<br />
</span></p>
<pre class="brush: csharp;">
protected override void Update(GameTime gameTime)
{
     // υπόλοιπος κώδικας

     ball.X += (int)(ballDirection.X * ballSpeed);
     ball.Y += (int)(ballDirection.Y * ballSpeed);

     //check paddle-wall collision
     if ( paddle.Left&lt;0)
     {
          paddle.X = 0;
     }
     else if (paddle.Right &gt; viewWidth)
     {
          paddle.X = viewWidth - paddle.Width;
     }
     base.Update(gameTime);
}
</pre>
<p><span style="font-family:Verdana;font-size:9pt;">Αυτό γίνεται εύκολα με το να μην αφήσουμε τη Left μεταβλητή του paddle να γίνει μικρότερη του μηδενός και την Right μεγαλύτερη του viewWidth (πλάτος πίστας) μείον το μήκος της ρακέτας.<br />
</span></p>
<p><span style="font-family:Verdana;font-size:9pt;">Παρόμοια είναι και η λογική για τη μπάλα μόνο που πρέπει να ελέγξουμε εκτός από τα αριστερά και δεξιά τοιχώματα και τα πάνω και κάτω:<br />
</span></p>
<pre class="brush: csharp;">
protected override void Update(GameTime gameTime)
{
     // υπόλοιπος κώδικας

     //check paddle-wall collision
     if ( paddle.Left &lt; 0)
     {
          paddle.X = 0;
     }
     else if (paddle.Right &gt; viewWidth)
     {
          paddle.X = viewWidth - paddle.Width;
     }

     //check ball-wall collision
     if (ball.Left &lt;= 0 || ball.Right &gt;= viewWidth)
     {
          ballDirection.X = -ballDirection.X;
     }
     else if (ball.Top &lt;= 0 || ball.Bottom &gt;= viewHeight)
     {
          ballDirection.Y = -ballDirection.Y;
     }
     base.Update(gameTime);
}
</pre>
<p><span style="font-family:Verdana;font-size:9pt;">Σε περίπτωση που η μπάλα συγκρουστεί με κάποιο κάθετο τοίχωμα απλά αλλάζουμε τη κατεύθυνση στο Χ άξονα, διαφορετικά στο Υ. Επιπλέον πρέπει να ελέγξουμε αν η μπάλα συγκρούστηκε με τη ρακέτα:<br />
</span></p>
<pre class="brush: csharp;">
protected override void Update(GameTime gameTime)
{
     // υπόλοιπος κώδικας

     //check ball-wall collision
     if (ball.Left &lt;= 0 || ball.Right &gt;= viewWidth)
     {
          ballDirection.X = -ballDirection.X;
     }
     else if (ball.Top &lt;= 0 || ball.Bottom &gt;= viewHeight)
     {
          ballDirection.Y = -ballDirection.Y;
     }

     //check ball-paddle collision
     if (ballDirection.Y &gt; 0 &amp;&amp;
          ball.Bottom &gt;= paddle.Top &amp;&amp;
          ((ball.Left &gt;= paddle.Left &amp;&amp; ball.Left &lt;= paddle.Right) ||
          (ball.Right &gt;= paddle.Left &amp;&amp; ball.Right &lt;= paddle.Right))
     )
     {
          ballDirection.Y = -ballDirection.Y;
     }
     base.Update(gameTime);
}
</pre>
<p><span style="font-family:Verdana;font-size:9pt;">Η λογική της ανίχνευσης σύγκρουσης με τη ρακέτα είναι ανάλογη με αυτή του Pong. Καταρχάς εξασφαλίζουμε ότι η μπάλα έχει τη σωστή κατεύθυνση (προς τα κάτω, δηλαδή ballDirection.Y &gt; 0). Έπειτα ελέγχουμε αν υπάρχει επικάλυψη. Αν ισχύουν και τα δύο, τότε απλά αλλάζουμε τη κατεύθυνση της μπάλας στο Υ άξονα και η μπάλα αναπηδά προς τα πάνω.<br />
</span></p>
<p><span style="font-family:Verdana;font-size:9pt;">Τρέχοντας τώρα το παιχνίδι (F5), η ρακέτα και η μπάλα κινούνται εντός ορίων και επιπλέον η μπάλα αναπηδά πάνω στην ρακέτα. Αυτό που απομένει τώρα είναι τα μπορέσουμε επιτέλους να καταστρέψουμε και κανένα τουβλάκι. Αυτό γίνεται εύκολα με την λειτουργικότητα που έχουμε προσθέσει στη κλάση Brick στο προηγούμενο άρθρο. Το μόνο που έχουμε να κάνουμε είναι να διατρέξουμε όλο το πίνακα με τα τουβλάκια (bricks) και να καλέσουμε την μέθοδο CheckHit του κάθε brick περνώντας το Rectangle της μπάλας ως όρισμα:<br />
</span></p>
<pre class="brush: csharp;">
protected override void Update(GameTime gameTime)
{
     // υπόλοιπος κώδικας

     //check ball-brick collision
     foreach (Brick brick in bricks)
     {
          if (brick.CheckHit(ball))
          {
               ballDirection.Y = -ballDirection.Y;
               break;
          }
     }

     base.Update(gameTime);
}
</pre>
<p><span style="font-family:Verdana;font-size:9pt;">Πάλι χρησιμοποιώ ένα for-each loop για να διατρέξω στο πίνακα. Δεν έχει ιδιαίτερες διαφορές με το κλασσικό for-loop απλά στη περίπτωση αυτή είναι πιο βολικό. Η μέθοδος CheckHit() θα ελέγξει αν υπάρχει επικάλυψη μεταξύ του τρέχοντος brick και της μπάλας. Αν ναι τότε θα κάνει το brick αόρατο (visible = false;) και θα επιστρέψει τη τιμή true. Διαφορετικά θα επιστρέψει false.<br />
</span></p>
<pre class="brush: csharp;">
public bool CheckHit(Rectangle ball)
{
     if (visible &amp;&amp; Intersects(ball))
     {
          visible = false;
          return true;
     }
     return false;
}
</pre>
<p><span style="font-family:Verdana;font-size:9pt;">Σε περίπτωση του η μέθοδος CheckHit() επιστρέψει true, το if-statement θα είναι αληθές και θα αλλάξει την κάθετη κατεύθυνση της μπάλας έτσι ώστε αυτή να αναπηδήσει από το τουβλάκι. Κάτι τελευταίο, όταν ανιχνεύσουμε σύγκρουση με ένα τουβλάκι (το if-statement είναι αληθές δηλαδή), καλούμε την εντολή break. Η εντολή αυτή σταματά άμεσα την επανάληψη σε οποιοδήποτε loop. Από τη στιγμή που υπήρξε σύγκρουση με ένα τουβλάκι δεν υπάρχει λόγος να συνεχίσω την ανίχνευση για αυτό το frame.<br />
</span></p>
<p><span style="font-family:Verdana;font-size:9pt;">Τώρα μπορούμε να τρέξουμε το παιχνίδι και να παίξουμε κανονικά καταστρέφοντας τουβλάκια. Λείπουν μόνο το σκορ και η συνθήκη τερματισμού του παιχνιδιού.<br />
</span></p>
<p><span style="font-family:Verdana;font-size:9pt;">Για το σκορ προσθέτουμε μια μεταβλητή score στη κλάση του παιχνιδιού Game1. Επιπλέον προθέτουμε μια μεταβλητή για τον αριθμό ζώων του παίκτη:<br />
</span></p>
<pre class="brush: csharp;">
public class Game1 : Microsoft.Xna.Framework.Game
{
     //υπόλοιπος κώδικας

     int score;
     int lives;
</pre>
<p><span style="font-family:Verdana;font-size:9pt;">Την μεταβλητή lives την αρχικοποιούμε σε 3 στην μέθοδο Intialize(). Κάθε φορά που ανιχνεύουμε μια σύγκρουση της μπάλας με το κάτω μέρος της πίστας αφαιρούμε μια ζωή. Κάθε φορά που ανιχνεύουμε μια σύγκρουση της μπάλας με ένα τουβλάκι αυξάνουμε το σκορ:<br />
</span></p>
<pre class="brush: csharp;">
protected override void Update(GameTime gameTime)
{
     // υπόλοιπος κώδικας

     //check ball-wall collision
     if (ball.Left &lt;= 0 || ball.Right &gt;= viewWidth)
     {
          ballDirection.X = -ballDirection.X;
     }
     else if (ball.Top &lt;= 0 || ball.Bottom &gt;= viewHeight)
     {
          ballDirection.Y = -ballDirection.Y;

          if (ball.Bottom &gt;= viewHeight)
          {
               lives--;
          }
     }

     // υπόλοιπος κώδικας

     //check ball-brick collision
     foreach (Brick brick in bricks)
     {
          if (brick.CheckHit(ball))
          {
               ballDirection.Y = -ballDirection.Y;
               score += 1000;
               break;
          }
     }

     base.Update(gameTime);
}
</pre>
<p><span style="font-family:Verdana;font-size:9pt;">Αυξάνουμε το σκορ κατά 1000 κάθε φορά που ο παίκτης καταστρέφει ένα τουβλάκι. Ο λόγος που αυξάνουμε τόσο πολύ, αντί για +1 τη φορά είναι ότι ένας παίκτης πάντα αισθάνεται μεγαλύτερη ικανοποίηση όταν πετυχαίνει μεγάλο σκορ, παρά μικρό έστω και αν αυτό το σκορ είναι φαινομενικά μεγάλο. Είναι εντυπωσιακότερο να καταστρέφω 100 τουβλάκια και να πετυχαίνω σκορ 100.000 πάρα να καταστρέφω 100 τουβλάκια και να πετυχαίνω σκορ 100.<br />
</span></p>
<p><span style="font-family:Verdana;font-size:9pt;">Πρέπει τέλος να απεικονίσουμε το σκορ και τις ζωές στην οθόνη. Προσθέτουμε ένα font στο project Content του παιχνιδιού με τον τρόπο που <a href="http://videogameslab.wordpress.com/2009/07/17/hello-pong-part4/" target="_blank">περιγράψαμε εδώ</a>. Το ονομάζουμε Arial. Επιπλέον, ανοίγουμε το αρχείο του font (Arial.spritefont) και αλλάζουμε το μέγεθος σε 25 (γραμμή</span><span style="font-family:Courier New;font-size:10pt;"><span style="color:blue;"> &lt;</span><span style="color:#a31515;">Size</span><span style="color:blue;">&gt;</span>14<span style="color:blue;">&lt;/</span><span style="color:#a31515;">Size</span><span style="color:blue;">&gt;).<br />
</span></span></p>
<p><span style="font-family:Verdana;font-size:9pt;">Για να φορτώσουμε το font ορίζουμε μια μεταβλητή SpriteFont:<br />
</span></p>
<pre class="brush: csharp;">
public class Game1 : Microsoft.Xna.Framework.Game
{
     GraphicsDeviceManager graphics;
     SpriteBatch spriteBatch;
     SpriteFont font;
</pre>
<p><span style="font-family:Verdana;font-size:9pt;">Τέλος φορτώνουμε το font στην μέθοδο Load όπως κάθε άλλο αρχείο περιεχομένου:<br />
</span></p>
<pre class="brush: csharp;">
protected override void LoadContent()
{
     // Create a new SpriteBatch, which can be used to draw textures.
     spriteBatch = new SpriteBatch(GraphicsDevice);
     font = Content.Load(&quot;arial&quot;);
</pre>
<p><span style="font-family:Verdana;font-size:9pt;">Στην μέθοδο Draw τώρα, απεικονίζουμε το σκορ και τις ζωές με τη χρήση της spriteBatch.DrawString():<br />
</span></p>
<pre class="brush: csharp;">
protected override void Draw(GameTime gameTime)
{
     GraphicsDevice.Clear(Color.Black);

     string message = String.Format(&quot;Lives: {0}, Score: {1}&quot;, lives, score);
     spriteBatch.Begin();

     spriteBatch.DrawString(font, message, new Vector2(10, 10), Color.Yellow);

     foreach (Brick brick in bricks)
     {
          brick.Draw(spriteBatch);
     }

     spriteBatch.Draw(whiteTile, paddle, Color.White);
     spriteBatch.Draw(whiteTile, ball, Color.Yellow);

     spriteBatch.End();

     base.Draw(gameTime);
}
</pre>
<p><span style="font-family:Verdana;font-size:9pt;">Δημιουργούμε ένα νέο string το οποίο θα αποθηκεύσει το κείμενο που θέλουμε να απεικονίσουμε. Χρησιμοποιούμε την String.Format η οποία έχει το χαρακτηριστικό να αντικαθιστά ότι επισημάνσεις του στυλ «{X}» βρει στο κείμενο με τις τιμές των μεταβλητών που της δίνουμε ως όρισμα (η String.Format μοιάζει λίγο με την printf της C για όποιον είναι γνώστης). Στην περίπτωση μας θα αντικαταστήσει το {0} με τη τιμής της lives και το {1} με την τιμή της μεταβλητής score.<br />
</span></p>
<p><span style="font-family:Verdana;font-size:9pt;">Στο τέλος τυπώνουμε το κείμενο στην οθόνη με τη χρήση της spriteBatch.DrawString(), στη θέση (10,10), με χρώμα κίτρινο.<br />
</span></p>
<p><span style="font-family:Verdana;font-size:9pt;">Θα σταματήσουμε το tutorial εδώ, το παιχνίδι είναι λειτουργικό σε μεγάλο βαθμό, το σκορ του παίκτη αυξάνεται όταν χτυπά τα τουβλάκια και οι ζωές ελαττώνονται όταν χάνει τη μπάλα αλλά ουσιαστικά το παιχνίδι δεν τελειώνει. Αυτό, μαζί με άλλες βελτιώσεις θα τα υλοποιήσουμε το επόμενο άρθρο.<br />
</span></p>
<p><span style="font-family:Verdana;font-size:9pt;">Μπορείτε να βρείτε το κώδικα που αναπτύξαμε μέχρι στιγμής σε <a href="http://videogameslab.googlecode.com/files/Arcanoid_part2.zip" target="_blank">.zip</a> αλλά και μέσω SVN στο <a href="http://videogameslab.wordpress.com/2009/07/23/code-repository-2/" target="_blank">Code Repository</a>.<br />
</span></p>
<p><span style="font-family:Verdana;font-size:9pt;"><br />
</span></p>
  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/videogameslab.wordpress.com/421/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/videogameslab.wordpress.com/421/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/videogameslab.wordpress.com/421/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/videogameslab.wordpress.com/421/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/videogameslab.wordpress.com/421/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/videogameslab.wordpress.com/421/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/videogameslab.wordpress.com/421/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/videogameslab.wordpress.com/421/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/videogameslab.wordpress.com/421/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/videogameslab.wordpress.com/421/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=videogameslab.wordpress.com&blog=5040448&post=421&subd=videogameslab&ref=&feed=1" /></div>]]></content:encoded>
			<wfw:commentRss>http://videogameslab.wordpress.com/2009/09/24/arkanoid-part2/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
	
		<media:content url="http://0.gravatar.com/avatar/4bd00ab99710c6e67ef0a28c68628aad?s=96&#38;d=http%3A%2F%2F0.gravatar.com%2Favatar%2Fad516503a11cd5ca435acc9bb6523536%3Fs%3D96" medium="image">
			<media:title type="html">thinkinggamer</media:title>
		</media:content>
	</item>
		<item>
		<title>Δημιουργώντας το Arkanoid μέρος 1ο</title>
		<link>http://videogameslab.wordpress.com/2009/09/14/arkanoid-part-1/</link>
		<comments>http://videogameslab.wordpress.com/2009/09/14/arkanoid-part-1/#comments</comments>
		<pubDate>Mon, 14 Sep 2009 09:54:48 +0000</pubDate>
		<dc:creator>Κώστας Αναγνώστου</dc:creator>
				<category><![CDATA[.NET]]></category>
		<category><![CDATA[Arkanoid]]></category>
		<category><![CDATA[C#]]></category>
		<category><![CDATA[XNA Game Studio]]></category>
		<category><![CDATA[Ανάπτυξη βιντεοπαιχνιδιών]]></category>
		<category><![CDATA[Προγραμματισμός]]></category>

		<guid isPermaLink="false">http://videogameslab.wordpress.com/?p=399</guid>
		<description><![CDATA[Ήρθε η ώρα να ξεσκονίσουμε τα πληκτρολόγια μας και να αρχίσουμε τη δεύτερη σειρά tutorial ανάπτυξης βιντεοπαιχνιδιού. Αυτή τη φορά θα ασχοληθούμε με το πολύ γνωστό Arkanoid (Taito, 1986). Στο παιχνίδι αυτό ο παίκτης χειρίζεται μια ρακέτα και προσπαθεί να οδηγήσει μια μπάλα έτσι ώστε να καταστρέψει σειρές από «τουβλάκια» στο πάνω μέρος της οθόνης.


Tο [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=videogameslab.wordpress.com&blog=5040448&post=399&subd=videogameslab&ref=&feed=1" />]]></description>
			<content:encoded><![CDATA[<div class='snap_preview'><br /><p><span style="font-family:Verdana;font-size:9pt;">Ήρθε η ώρα να ξεσκονίσουμε τα πληκτρολόγια μας και να αρχίσουμε τη δεύτερη σειρά tutorial ανάπτυξης βιντεοπαιχνιδιού. Αυτή τη φορά θα ασχοληθούμε με το πολύ γνωστό Arkanoid (Taito, 1986). Στο παιχνίδι αυτό ο παίκτης χειρίζεται μια ρακέτα και προσπαθεί να οδηγήσει μια μπάλα έτσι ώστε να καταστρέψει σειρές από «τουβλάκια» στο πάνω μέρος της οθόνης.<br />
</span></p>
<p><img src="http://videogameslab.files.wordpress.com/2009/09/091409_0954_1.png" alt="" /></p>
<p><span style="font-family:Verdana;font-size:9pt;"><span id="more-399"></span></span><span style="font-family:Verdana;font-size:9pt;">Tο γεγονός ότι το Arkanoid έχει πολλές ομοιότητες με το </span><span style="font-family:Verdana;font-size:9pt;"> Pong, </span><span style="font-family:Verdana;font-size:9pt;">οποίο αναπτύξαμε σε προηγούμενη σειρά tutotials (<a href="http://videogameslab.wordpress.com/2009/07/03/hello-pong-part1/" target="_blank">μέρος 1</a>, <a href="http://videogameslab.wordpress.com/2009/07/06/hello-pong-part2/" target="_blank">μέρος 2</a>, <a href="http://videogameslab.wordpress.com/2009/07/13/hello-pong-part-3/" target="_blank">μέρος 3</a>, <a href="http://videogameslab.wordpress.com/2009/07/17/hello-pong-part4/" target="_blank">μέρος 4</a>, <a href="http://videogameslab.wordpress.com/2009/07/23/hello-pong-part5/" target="_blank">μέρος 5</a>), αποτελεί απόδειξη του ότι ο σχεδιασμός παιχνιδιών είναι εξελικτική διαδικασία δηλαδή ότι οι ιδέες για νέα παιχνίδια δεν εμφανίζονται ξαφνικά αλλά αποτελούν εξέλιξη παλαιότερων ιδεών (όπως ισχύει και για τις ταινίες και τα βιβλία άλλωστε).<br />
</span></p>
<p><span style="font-family:Verdana;font-size:9pt;">Ήδη γνωρίζουμε πώς να χειριστούμε τη ρακέτα, να αποκρούσουμε τη μπάλα, να περιορίσουμε τη κίνηση της μπάλας στο κλειστό πλαίσιο του παιχνιδιού και να κρατήσουμε το σκορ του παίκτη. Η διαφορά με το προηγούμενο παιχνίδι που αναπτύξαμε είναι ότι τώρα πρέπει να προσθέσουμε τα τουβλάκια και τη λογική «εξαφάνισης» τους όταν αυτά συγκρούονται με τη μπάλα.<br />
</span></p>
<p><span style="font-family:Verdana;font-size:9pt;">Στο Pong είχαμε ουσιαστικά τρία αντικείμενα στο παιχνίδι, τη μπάλα και τις 2 ρακέτες. Για το λόγο αυτό είχαμε την άνεση να αποθηκεύσουμε τα δεδομένα που τα περιγράφουν  (θέση, κατεύθυνση, χρώμα, μέγεθος κλπ) σε απλές μεταβλητές, και αυτό κάναμε. Στο Arkanoid όμως ο αριθμός των αντικειμένων του παιχνιδιού είναι μεγάλος, εκτός της ρακέτας και της μπάλας έχουμε και τις σειρές με τα τουβλάκια. Συνεπώς για το παιχνίδι αυτό θα προσθέσουμε μια κλάση (class) η οποία θα περιγράφει το αντικείμενο «τουβλάκι». Σημείωση: θα μπορούσαμε να κάνουμε το ίδιο και για τη μπάλα και τη ρακέτα, αλλά δεν θα προσέφερε τίποτα ιδιαίτερο μιας και έχουμε μόνο ένα αντικείμενο από κάθε κατηγορία.<br />
</span></p>
<p><span style="font-family:Verdana;font-size:9pt;">Τρέχουμε τη Visual C# και δημιουργούμε ένα νέο project με το όνομα Arkanoid (δείτε εδώ αν δεν θυμάστε πως). Αφότου το project έχει δημιουργηθεί, στο Solution Explorer, κάνουμε δεξί κλικ πάνω στο όνομα του και από το μενού επιλέγουμε Add/New Item…<br />
</span></p>
<p><img src="http://videogameslab.files.wordpress.com/2009/09/091409_0954_2.png" alt="" /><span style="font-family:Verdana;font-size:9pt;"><br />
</span></p>
<p><span style="font-family:Verdana;font-size:9pt;">Από το παράθυρο που θα εμφανιστεί επιλέγουμε το template Class και το ονομάζουμε Brick.<br />
</span></p>
<p><img src="http://videogameslab.files.wordpress.com/2009/09/091409_0954_3.png" alt="" /><span style="font-family:Verdana;font-size:9pt;"><br />
</span></p>
<p><span style="font-family:Verdana;font-size:9pt;">To project τώρα θα περιέχει ένα νέο αρχείο με το όνομα Brick.cs το οποίο περιέχει μια κλάση με το όνομα Brick, η οποία είναι κενή.<br />
</span></p>
<pre class="brush: csharp;">
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Arcanoid
{
    class Brick
    {
    }
}
</pre>
<p><span style="font-family:Verdana;font-size:9pt;">Ας σκεφτούμε λίγο τα χαρακτηριστικά ενός brick (τουβλάκι) στο παιχνίδι. Έχει θέση και μέγεθος, χρώμα και υφή. Επιπλέον ανάλογα με το αν έχει χτυπηθεί ή όχι, μπορεί να είναι ορατό ή αόρατο. Η θέση και το μέγεθος μπορούν να περιγραφούν με μια μεταβλητή τύπου Rectangle, όπως κάναμε και στο Pong. To χρωμα είναι μια μεταβλητή τύπου Color και η υφή μια μεταβλητή τύπου Texture. Τέλος μια μεταβλητή bool αρκεί για να περιγράψει αν το brick είναι ορατό ή αόρατο. Προσθέτουμε λοιπόν στη κλάση Βrick τις μεταβλητές αυτές:<br />
</span></p>
<pre class="brush: csharp;">
namespace Arcanoid
{
    class Brick
    {
        Rectangle rectangle;
        Texture2D texture;
        Color color;
        bool visible;
    }
}
</pre>
<p><span style="font-family:Verdana;font-size:9pt;">Για να θέσουμε αρχικές τιμές στις μεταβλητές αυτές μπορούμε να χρησιμοποιήσουμε μια constructor. O constructor είναι μια μέθοδος της κλάσης, με το ίδιο όνομα όπως η κλάση, η οποία καλείται κάθε φορά που δημιουργούμε ένα αντικείμενο της κλάσης με το τελεστή new. Χρησιμοποιείται κυρίως για αρχικοποιήσεις μεταβλητών.<br />
</span></p>
<pre class="brush: csharp;">
    class Brick
    {
        Rectangle rectangle;
        Texture2D texture;
        Color color;
        bool visible;

        public Brick(Rectangle rect, Color col, Texture2D tex)
        {
            rectangle = rect;
            color = col;
            texture = text;
            visible = true;
        }
    }
</pre>
<p><span style="font-family:Verdana;font-size:9pt;">Ο constructor μιας κλάσης είναι πάντα public και δεν επιστρέφει τιμή. Ως ορίσματα, περνάμε το Rectangle που καθορίζει τη θέση και μέγεθος του brick, το χρώμα του και την υφή του. Η μεταβλητή visible είναι true εξορισμού μιας και το τουβλάκι είναι ορατό μέχρι να χτυπηθεί από την μπάλα.<br />
</span></p>
<p><span style="font-family:Verdana;font-size:9pt;">Αφότου έχουμε ορίσει τις μεταβλητές της κλάσης, πρέπει να σκεφτούμε και τις μεθόδους που χρειάζονται οι οποίες ορίζουν την λειτουργικότητα του αντικειμένου. Θέλουμε το κάθε brick να μπορεί να ζωγραφίζει τον εαυτό του στην οθόνη (Draw), και θέλουμε με κάποιο τρόπο να διαπιστώσουμε αν έχει χτυπηθεί από την μπάλα (CheckHit).<br />
</span></p>
<pre class="brush: csharp;">
    class Brick
    {
        Rectangle rectangle;
        Texture2D texture;
        Color color;
        bool visible;

        public Brick(Rectangle rectangle, Color color, Texture2D texture)
        {
            this.rectangle = rectangle;
            this.color = color;
            this.texture = texture;
            visible = true;
        }

        public void Draw(SpriteBatch spriteBatch)
        {
            if (visible)
            {
                spriteBatch.Draw(texture, rectangle, color);
            }
        }

        public bool CheckHit(Rectangle ball)
        {
            if (visible &amp;&amp; intersects(ball))
            {
                visible = false;
                return true;
            }
            return false;
        }
    }
</pre>
<p><span style="font-family:Verdana;font-size:9pt;">H λειτουργία της μεθόδου Draw είναι προφανής, δέχεται ως όρισμα ένα spriteBatch (το οποίο είναι το αντικείμενο που χρησιμοποιούμε για να απεικονίσουμε sprites στην οθόνη όπως έχουμε αναφέρει), και αν το τρέχον brick είναι ορατό το απεικονίζει (</span><span style="font-family:Courier New;font-size:10pt;">spriteBatch.Draw</span><span style="font-family:Verdana;font-size:9pt;"> )στην οθόνη με την συγκεκριμένη υφή και χρώμα.<br />
</span></p>
<p><span style="font-family:Verdana;font-size:9pt;">Η μέθοδος CheckHit πραγματοποιεί περισσότερες λειτουργίες. Καταρχάς δέχεται ως όρισμα το Rectagle της μπάλας, το οποιο περιέχει τη θέση και το μέγεθος της. Στην συνέχεια, και αν το τρέχον brick είναι ορατό, ελέγχει αν το Rectagle της μπάλας τέμνει το Rectagle του brick. Αν συμβαίνει αυτό, τότε κάνει το τουβλάκι αόρατο (visible = false;) και επιστρέφει true για να ειδοποιήσει το κυρίως παιχνίδι ότι υπηρξε σύγκρουση. Σε διαφορετική περίπτωση επιστρέφει false.<br />
</span></p>
<p><span style="font-family:Verdana;font-size:9pt;">H κλάση Brick είναι σχεδόν έτοιμη για χρήση, το μόνο που μας λείπει είναι η μέθοδος <strong>intersects()</strong> που υπολογίζει αν υπήρξε σύγκρουση μεταξύ του τούβλου και τη μπάλας.<br />
</span></p>
<p><img src="http://videogameslab.files.wordpress.com/2009/09/091409_0954_4.png" alt="" /><span style="font-family:Verdana;font-size:9pt;"><br />
</span></p>
<p><span style="font-family:Verdana;font-size:9pt;">Θυμίζω ότι ο τύπος Rectagle του XNA μας παρέχει τις μεταβλητές Left, Top, Right, Bottom που αποθηκεύουν στις Χ και Y συντεταγμένες κάθε γωνίας του.<br />
</span></p>
<p><span style="font-family:Verdana;font-size:9pt;">Κοιτώντας το παραπάνω σχήμα είναι εύκολο να εξάγουμε τη λογική με την οποία διαπιστώνουμε αν υπάρχει επικάλυψη μεταξύ 2 Rectangles. Αν για παράδειγμα η Top συντεταγμένη του κόκκινου ορθογωνίου είναι μεγαλύτερη από τη Bottom συντεταγμένη του κίτρινου, δεν υπάρχει περίπτωση τα 2 αυτά ορθογώνια να επικαλύπτονται γιατί το κόκκινο βρίσκεται κάτω του κίτρινου. Ανάλογα ισχύει για τις περιπτώσεις πάνω, αριστερά και δεξιά.<br />
</span></p>
<p><span style="font-family:Verdana;font-size:9pt;">Σε κώδικα αυτό υλοποιείται ως εξής:<br />
</span></p>
<pre class="brush: csharp;">
    class Brick
    {
        Rectangle rectangle;
        Texture2D texture;
        Color color;
        bool visible;

        public Brick(Rectangle rectangle, Color color, Texture2D texture)
        {
            ……
        }

        public void Draw(SpriteBatch spriteBatch)
        {
            ……
        }

        public bool CheckHit(Rectangle ball)
        {
            ……
        }

        private bool intersects(Rectangle ball)
        {
            if (rectangle.Right &lt; ball.Left ||
                rectangle.Left &gt; ball.Right ||
                rectangle.Top &gt; ball.Bottom ||
                rectangle.Bottom &lt; ball.Top)
            {
                return false;
            }

            return true;

        }
    }
</pre>
<p><span style="font-family:Verdana;font-size:9pt;">H μέθοδος intersect δέχεται ως όρισμα το rectangle της μπάλας και επιστρέφει true αν υπάρχει σύγκρουση (επικάλυψη) και false διαφορετικά. Το if-statement που χρησιμοποιούμε είναι σύνθετο και ελέγχει πολλές συνθήκες με το τελεστή || (OR). Το if-statement θα είναι αληθές αρκεί μια από τις 4 συνθήκες να είναι αληθής. Στη περίπτωση αυτή δεν υπάρχει επικάλυψη μεταξύ του brick και της μπάλας και η μέθοδος επιστρέφει false.<br />
</span></p>
<p><span style="font-family:Verdana;font-size:9pt;">Σημείωση: Για προλάβω τα σχόλια ατόμων που γνωρίζουν κάτι παραπάνω για το XNA, ο τύπος Rectangle υλοποιεί την δική του μέθοδο Intersects που κάνει τη δουλειά που κάναμε παραπάνω αυτόματα. Αν όμως χρησιμοποιείς από την αρχή το κομπιουτεράκι, δεν θα μάθεις ποτέ πρόσθεση!<br />
</span></p>
<p><span style="font-family:Verdana;font-size:9pt;">Ολοκληρώσαμε έτσι τη κλάση Brick και είμαστε έτοιμοι να την χρησιμοποιήσουμε στο παιχνίδι. Επιστρέφουμε στη κύρια κλάση του παιχνιδιού στο αρχείο Game1.cs.<br />
</span></p>
<p><span style="font-family:Verdana;font-size:9pt;">Τα αντικείμενα του παιχνιδιού μας είναι η ρακέτα και η μπάλα και πολλά τουβλάκια. Η δημιουργία της ρακέτας και τη μπάλας είναι εύκολη και δεν διαφέρει από αυτή του Pong. Ορίζουμε από ένα Rectangle για τη θέση και το μέγεθος (paddle, ball), 2 διανύσματα για την κατεύθυνση (paddleDirection, ballDirection) και 2 float μεταβλητές και την ταχύτητα τους (paddleSpeed, ballSpeed).<br />
</span></p>
<pre class="brush: csharp;">
public class Game1 : Microsoft.Xna.Framework.Game
{
	GraphicsDeviceManager graphics;
	SpriteBatch spriteBatch;
	Texture2D whiteTile;
	Rectangle paddle;
	Vector2 paddleDirection;
	float paddleSpeed;
	Rectangle ball;
	Vector2 ballDirection;
	float ballSpeed;
</pre>
<p><span style="font-family:Verdana;font-size:9pt;">Τις μεταβλητές spriteBatch και whiteTile, τις γνωρίζουμε και από το προηγούμενο tutorial, το spriteBatch είναι το αντικείμενο που θα χρησιμοποιήσουμε για να απεικονίσουμε τα αντικείμενα στην οθόνη και το whiteTile αντιπροσωπεύει μια υφή.<br />
</span></p>
<p><span style="font-family:Verdana;font-size:9pt;">Για να τοποθετήσουμε τα τουβλάκια (bricks) στην πίστα χρειαζόμαστε μερικές επιπλέον μεταβλητές. Για να γίνει πιο κατανοητή η ύπαρξη τους κρατήστε στο μυαλό σας την παρακάτω εικόνα.<br />
</span></p>
<p><img src="http://videogameslab.files.wordpress.com/2009/09/091409_0954_5.png" alt="" /><span style="font-family:Verdana;font-size:9pt;"><br />
</span></p>
<p><span style="font-family:Verdana;font-size:9pt;">Χρειαζόμαστε δυο μεταβλητές <strong>brickWidth</strong>, <strong>brickHeight</strong>, με το πλάτος και το ύψος κάθε brick, μια μεταβλητή <strong>numOfRows</strong> με τον αριθμό των γραμμών από τουβλάκια, τον αριθμό από τουβλάκια σε κάθε γραμμή <strong>bricksPerRow</strong>, το κενό διάστημα μεταξύ 2 τουβλακίων <strong>brickSpacing</strong> και τη συντεταγμένη Y στη οποία θα αρχίσουμε να τοποθετούμε τα τουβλάκια <strong>rowStart</strong>. Τέλος για να αποθηκεύσουμε τα τουβλάκια θα χρησιμοποιήσουμε ένα πίνακα:<br />
</span></p>
<pre class="brush: csharp;">
    public class Game1 : Microsoft.Xna.Framework.Game
    {
        GraphicsDeviceManager graphics;
        SpriteBatch spriteBatch;
        Texture2D whiteTile;
        Rectangle paddle;
        Vector2 paddleDirection;
        float paddleSpeed;
        Rectangle ball;
        Vector2 ballDirection;
        float ballSpeed;

        int brickWidth;
        int brickHeight;
        int bricksPerRow;
        int numOfRows;
        int brickSpacing;
        int rowStart;
        Brick[] bricks;

        int viewWidth;
        int viewHeight;
</pre>
<p><span style="font-family:Verdana;font-size:9pt;">Οι 2 τελευταίες μεταβλητές (viewWidth, viewHeight) αποθηκεύουν το πλάτος και το ύψος του παραθύρου (viewport) του παιχνιδιού.<br />
</span></p>
<p><span style="font-family:Verdana;font-size:9pt;">Ας αρχίσουμε να τοποθετούμε τα αντικείμενα του παιχνιδιού, το καθένα στη θέση του, τώρα. Αυτό θα το κάνουμε στην μέθοδο Initialize():<br />
</span></p>
<pre class="brush: csharp;">
	protected override void Initialize()
	{
		viewHeight = graphics.GraphicsDevice.Viewport.Height;
		viewWidth = graphics.GraphicsDevice.Viewport.Width;

		paddle = new Rectangle(150, 550, 90, 15);
		ball = new Rectangle(150, 400, 15, 15);

		bricksPerRow = 13;
		numOfRows = 5;
		brickSpacing = 10;

		bricks = new Brick[bricksPerRow * numOfRows];

		brickWidth = (viewWidth - (bricksPerRow - 1) * brickSpacing) / bricksPerRow ;

		brickHeight = 20;
		paddleSpeed = 10;
		rowStart = 3 * brickHeight;

		base.Initialize();
	}
</pre>
<p><span style="font-family:Verdana;font-size:9pt;">Το αντικείμενο graphics.GraphicsDevice.Viewport μας δίνει το πλάτος και το ύψος του παραθύρου του παιχνιδιού. Στην συνέχεια δημιουργώ τα Rectangle για τη ρακέτα και τη μπάλα. H ρακέτα θα βρίσκεται στο σημείο (150, 500) και έχει πλάτος 90 pixel και ύψος 15. Αναλόγως για την μπάλα.<br />
</span></p>
<p><span style="font-family:Verdana;font-size:9pt;">Ορίζω ότι θα έχουμε 13 τουβλάκια ανά γραμμή (bricksPerRow) και 5 γραμμές από τουβλάκια (numOfRows). Επιπλέον θέλω τα τουβλάκια να έχουν απόσταση 10 pixel μεταξύ τους στο Χ και Υ άξονα. Να τονίσω ότι οι επιλογές αυτές είναι λίγο-πολύ αυθαίρετες, απλώς έφτιαξα κάτι που φαίνεται εντάξει στο μάτι. Μπορούμε αργότερα να τα αλλάξουμε κατά πως θέλουμε.<br />
</span></p>
<p><span style="font-family:Verdana;font-size:9pt;">Στη συνέχεια πρέπει να δημιουργήσουμε το πίνακα που θα αποθηκεύσει τα τουβλάκια. Ο αριθμός από τουβλάκια που υπάρχουν στην πίστα δίνεται από το γινόμενο numOfRows * bricksPerRow. Στην περίπτωση μας έχουμε 5 γραμμές με 13 τουβλάκια η κάθε μία (65 το σύνολο). Χρησιμοποιώντας το τελεστή new μπορούμε να δεσμεύσουμε μνήμη λοιπόν για  numOfRows * bricksPerRow τουβλάκια:<br />
</span></p>
<p>bricks = new Brick[bricksPerRow * numOfRows];</p>
<blockquote><p><span style="font-family:Verdana;font-size:9pt;"><strong>C# και πίνακες</strong><br />
</span></p>
<p><span style="font-family:Verdana;font-size:9pt;">O παραπάνω τρόπος μπορεί να χρησιμοποιηθεί για τη δημιουργία πινάκων οποιαδήποτε τύπου. Αν ήθελα για παράδειγμα να δημιουργήσω ένα πίνακα από ακέραιους (int) με 10 στοιχεία θα έγραφα<br />
</span></p>
<pre class="brush: csharp;">
int[] numbers;
numbers = new int[10];
</pre>
<p><span style="font-family:Verdana;font-size:9pt;">Προσοχή πρέπει να δοθεί κατά τη δημιουργία και χρήση ενός πινάκα βασικών τύπων (int, float, char κλπ) και ενός πίνακα αντικειμένων όπως το Brick που ορίσαμε εμείς. Ένας πίνακας βασικών τύπων μπορεί να χρησιμοποιηθεί αμέσως μετά τη δημιουργία του με τη χρήση του τελεστή new:<br />
</span></p>
<pre class="brush: csharp;">
int[] numbers;
numbers = new int[10];
numbers[2] = 125;
</pre>
<p><span style="font-family:Verdana;font-size:9pt;">Αντίθετα η δημιουργία και χρήση ενός πίνακα Ν αντικειμένων είναι μια διαδικασία 2 βημάτων. Πρέπει καταρχάς με τη χρήση του τελεστή new να δεσμεύσουμε μνήμη για N «δείκτες» ή «αναφορές» σε αντικείμενα του δεδομένου τύπου (πχ Brick). <em>Για τους γνώστες C/C++ ο δείκτης αυτός είναι ανάλογος του pointer και ο πίνακας που δημιουργώ είναι στην ουσία ένας πίνακας από pointers</em>. Τα αντικείμενα αυτά δεν υπάρχουν ακόμα. Για να τα δημιουργήσω πρέπει να χρησιμοποιήσω ξανά το τελεστή new για κάθε ένα από αυτά και να τα αντιστοιχήσω στις θέσεις του πίνακα που δημιούργησα στο πρώτο βήμα. Ακούγεται (ή το έκανα να ακούγεται) περίπλοκο, αλλά δεν είναι:<br />
</span></p>
<pre class="brush: csharp;">
Brick[] bricks;
bricks = new Brick[10]; // μέχρι το σημείο αυτό έχω μόνο το πίνακα με τις αναφορές στα αντικείμενα
brick[0] = new Brick(); // δημιουργώ ένα αντικείμενο τύπου Brick και το αντιστοιχίζω στη θέση 0
brick[0].Draw();  // Τώρα μπορώ να το χρησιμοποιήσω

brick[1].Draw();  // ΛΑΘΟΣ, δεν έχω αντιστοιχήσει ένα αντικείμενο στη θέση αυτή.
brick[1] = new Brick(); // δημιουργώ ένα αντικείμενο τύπου Brick και το αντιστοιχίζω στη θέση 1
brick[1].Draw();  // Τώρα μπορώ να το χρησιμοποιήσω
</pre>
</blockquote>
<p><span style="font-family:Verdana;font-size:9pt;">Στη συνέχεια υπολογίζουμε το πλάτος κάθε τούβλου (brickWidth) αυτόματα, έτσι ώστε οι σειρές να γεμίζουν το παράθυρο του παιχνιδιού. Η λογική είναι η εξής: έχω bricksPerRow τούβλα σε κάθε σειρά, τα οποία έχουν συνολικό πλάτος bricksPerRow * brickWidth. Επιπλέον έχω και bricksPerRow-1 κενά ανάμεσα στα τούβλα τα οποία έχουν συνολικό πλάτος (bricksPerRow-1) * brickSpacing. Θέλω το άθροισμα τους να ισούται με το πλάτος του παραθύρου viewWidth, δηλαδή:</span></p>
<p><span style="font-family:Verdana;font-size:9pt;">bricksPerRow * brickWidth + (bricksPerRow-1) * brickSpacing = viewWidth</span></p>
<p><span style="font-family:Verdana;font-size:9pt;">Ο καλός προγραμματιστής βιντεοπαιχνιδιών δεν πρέπει να φοβάται λίγα απλά μαθηματικά! Αν λύσω τη παραπάνω εξίσωση ως προς brickWidth θα βρω τι πλάτος πρέπει να έχει το κάθε τουβλάκι έτσι ώστε η σειρά να «γεμίζει» το παράθυρο.<br />
</span></p>
<p><span style="font-family:Verdana;font-size:9pt;">Τέλος θέτω το ύψος του κάθε brick (brickHeight) σε 20, τη ταχύτητα της ρακέτας (paddleSpeed) σε 10 και προσδιορίζω ότι η γραμμές με τα τουβλάκια θέλω να αρχίζουν σε ύψος 3*brickHeight (πάλι, αυθαίρετα).<br />
</span></p>
<p><span style="font-family:Verdana;font-size:9pt;">Το tutorial έχει γίνει ήδη πολύ μεγάλο και ίσως κούρασε τον αναγνώστη. Θα το σταματούσα στο σημείο αυτό όμως είναι ωραίο να μπορούμε να δούμε έστω κάποιο αποτέλεσμα των κόπων μας στην οθόνη, οπότε θα παρουσιάσω στα γρήγορα τη δημιουργία και απεικόνιση των αντικειμένων του παιχνιδιού, χωρίς να μπω στην λογική του.<br />
</span></p>
<p><span style="font-family:Verdana;font-size:9pt;">Στην συνάρτηση LoadContent(), θα φορτώσουμε την υφή και θα δημιουργήσουμε στο πίνακα τις σειρές με τα τουβλάκια:<br />
</span></p>
<pre class="brush: csharp;">
        protected override void LoadContent()
        {
            // Create a new SpriteBatch, which can be used to draw textures.
            spriteBatch = new SpriteBatch(GraphicsDevice);

            whiteTile = Content.Load&lt;Texture2D&gt;(&quot;white_tile&quot;);

            for (int j = 0; j &lt; numOfRows; j++)
            {
                for (int i = 0; i &lt; bricksPerRow; i++)
                {
                    Rectangle rect = new Rectangle(i * (brickWidth + brickSpacing),
                                                   rowStart + j * (brickHeight + brickSpacing),
                                                   brickWidth, brickHeight);
                    bricks[j * bricksPerRow + i] = new Brick(rect, Color.Red, whiteTile);
                }
            }
        }
</pre>
<p><span style="font-family:Verdana;font-size:9pt;">Το whiteTile είναι μια άσπρη εικόνα (υφή) την οποία χρησιμοποιούμε ως παράμετρο στην spriteBatch.Draw() αργότερα για να απεικονίσουμε τα αντικείμενα του παιχνιδιού. Στη συνέχεια με ένα διπλό for-loop δημιουργώ στην μνήμη τα τουβλάκια (με το τελεστή new), ορίζοντας τη θέση και το μέγεθος τους (Rectagle rect), το χρώμα τους και τη υφή τους. Ουσιαστικά διατρέχουμε το πίνακα bricks που είχαμε δημιουργήσει στην Initialize και για κάθε θέση του δεσμεύουμε μνήμη για κάθε αντικείμενο-τούβλο.<br />
</span></p>
<p><span style="font-family:Verdana;font-size:9pt;">Τέλος απεικονίζω τα τουβλάκια, τη μπάλα και την ρακέτα στην μέθοδο Draw(), ως συνήθως, χρησιμοποιώντας το αντικείμενο spriteBatch:<br />
</span></p>
<pre class="brush: csharp;">
        protected override void Draw(GameTime gameTime)
        {
            GraphicsDevice.Clear(Color.Black);

            spriteBatch.Begin();

            foreach (Brick brick in bricks)
            {
                brick.Draw(spriteBatch);
            }

            spriteBatch.Draw(whiteTile, paddle, Color.White);
            spriteBatch.Draw(whiteTile, ball, Color.Yellow);

            spriteBatch.End();

            base.Draw(gameTime);
        }
</pre>
<p><span style="font-family:Verdana;font-size:9pt;">Έχουμε εξηγήσει πως χρησιμοποιούμε το spriteBatch για να απεικονίσουμε τη ρακέτα και τη μπάλα στην οθόνη. Το μόνο στο οποίο αξίζει να αναφερθώ είναι ο τρόπος με τον οποίο απεικονίζουμε τα τουβλάκια. Διατρέχουμε με ένα for-each loop το πίνακα με αυτά (bricks) και για κάθε ένα από αυτά καλώ τη μέθοδο απεικόνισης του Draw, δίνοντας το αντικείμενο spriteBatch ως όρισμα. Θυμίζω ότι τη μέθοδο Draw της κλάσης Brick την ορίσαμε εμείς παραπάνω. Η μέθοδος αυτή απεικονίζει το αντίστοιχο τουβλάκι στην οθόνη.<br />
</span></p>
<p><span style="font-family:Verdana;font-size:9pt;">Το for-each loop που χρησιμοποίησα παραπάνω είναι ένας κάπως πιο ευανάγνωστος και εύχρηστος τρόπος να διατρέξουμε τα στοιχεία ενός πίνακα. Είναι ισοδύναμος με το κλασσικό for-loop που στην συγκεκριμένη περίπτωση θα ήταν<br />
</span></p>
<pre class="brush: csharp;">
	for (int i = 0; i &lt; bricks.Length; i++)
	{
		bricks[i].Draw(spriteBatch);
	}
</pre>
<p><span style="font-family:Verdana;font-size:9pt;">Πατώντας τώρα το F5, το παιχνίδι θα κάνει επιτέλους compile και θα τρέξει παρουσιάζοντας τη παρακάτω εικόνα:<br />
</span></p>
<p><img src="http://videogameslab.files.wordpress.com/2009/09/091409_0954_6.png" alt="" /><span style="font-family:Verdana;font-size:9pt;"><br />
</span></p>
<p><span style="font-family:Verdana;font-size:9pt;">Σήμερα κάναμε αρκετή δουλειά ώστε να στήσουμε το παιχνίδι, στο επόμενο tutorial θα είναι πιο εύκολα τα πράγματα καθώς θα προσθέσουμε συγκρούσεις και τη λογική του παιχνιδιού. Μπορείτε να βρείτε το <a href="http://videogameslab.googlecode.com/files/Arcanoid_part1.zip" target="_blank">κώδικα σε zip μορφή</a> αλλά και μέσω SVN στο <a href="http://videogameslab.wordpress.com/2009/07/23/code-repository-2/" target="_blank">Code Repository</a>.<br />
</span></p>
<p><span style="font-family:Verdana;font-size:9pt;">Επεκτάσεις που μπορείτε να δοκιμάσετε στο παιχνίδι στη μορφή αυτή είναι κάθε γραμμή από τουβλάκια να έχει διαφορετικό χρώμα, ή να προσθέσετε υφές στα τουβλάκια έτσι ώστε να μοιάζουν ξύλινα, ή μεταλλικά κλπ, να κάνετε το ίδιο για την ρακέτα και τη μπάλα, ή να προσθέσετε μια υφή στο φόντο ώστε να μην είναι μαύρο.<br />
</span></p>
<p><span style="font-family:Verdana;font-size:9pt;">Σχόλια, ερωτήσεις και παρατηρήσεις στο γνωστό μέρος! Επίσης μπορείτε να συζητήσετε θέματα σχετικά με την υλοποίηση, το κώδικα, το σχεδιασμό και βελτιώσεις του Arkanoid στο <a href="http://videogameslab.freeforums.org/arkanoid-t14.html" target="_blank">Videogames Laboratory forum</a>.<br />
</span></p>
  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/videogameslab.wordpress.com/399/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/videogameslab.wordpress.com/399/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/videogameslab.wordpress.com/399/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/videogameslab.wordpress.com/399/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/videogameslab.wordpress.com/399/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/videogameslab.wordpress.com/399/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/videogameslab.wordpress.com/399/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/videogameslab.wordpress.com/399/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/videogameslab.wordpress.com/399/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/videogameslab.wordpress.com/399/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=videogameslab.wordpress.com&blog=5040448&post=399&subd=videogameslab&ref=&feed=1" /></div>]]></content:encoded>
			<wfw:commentRss>http://videogameslab.wordpress.com/2009/09/14/arkanoid-part-1/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
	
		<media:content url="http://0.gravatar.com/avatar/4bd00ab99710c6e67ef0a28c68628aad?s=96&#38;d=http%3A%2F%2F0.gravatar.com%2Favatar%2Fad516503a11cd5ca435acc9bb6523536%3Fs%3D96" medium="image">
			<media:title type="html">thinkinggamer</media:title>
		</media:content>

		<media:content url="http://videogameslab.files.wordpress.com/2009/09/091409_0954_1.png" medium="image" />

		<media:content url="http://videogameslab.files.wordpress.com/2009/09/091409_0954_2.png" medium="image" />

		<media:content url="http://videogameslab.files.wordpress.com/2009/09/091409_0954_3.png" medium="image" />

		<media:content url="http://videogameslab.files.wordpress.com/2009/09/091409_0954_4.png" medium="image" />

		<media:content url="http://videogameslab.files.wordpress.com/2009/09/091409_0954_5.png" medium="image" />

		<media:content url="http://videogameslab.files.wordpress.com/2009/09/091409_0954_6.png" medium="image" />
	</item>
		<item>
		<title>Ποια γλώσσα είναι η καλύτερη για τη ανάπτυξη παιχνιδιών;</title>
		<link>http://videogameslab.wordpress.com/2009/08/17/best-language/</link>
		<comments>http://videogameslab.wordpress.com/2009/08/17/best-language/#comments</comments>
		<pubDate>Mon, 17 Aug 2009 08:05:39 +0000</pubDate>
		<dc:creator>Κώστας Αναγνώστου</dc:creator>
				<category><![CDATA[.NET]]></category>
		<category><![CDATA[C#]]></category>
		<category><![CDATA[XNA Game Studio]]></category>
		<category><![CDATA[Ανάπτυξη βιντεοπαιχνιδιών]]></category>
		<category><![CDATA[Προγραμματισμός]]></category>

		<guid isPermaLink="false">http://videogameslab.wordpress.com/?p=370</guid>
		<description><![CDATA[Σε σχετικά forum, επικές είναι οι μάχες που διεξάγονται με αφορμή το ποια γλώσσα είναι η καλύτερη για την ανάπτυξη βιντεοπαιχνιδιών. Τελευταία, με την αυξανόμενη δημοτικότητα του XNA Game Studio, επίθεση δέχεται η C#/.NET, ως μια αργή γλώσσα που δεν μπορεί να υποστηρίξει «σοβαρά» παιχνίδια.

Η διαμάχη αυτή δεν είναι καινούργια. Προς υπενθύμιση των παλιότερων και [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=videogameslab.wordpress.com&blog=5040448&post=370&subd=videogameslab&ref=&feed=1" />]]></description>
			<content:encoded><![CDATA[<div class='snap_preview'><br /><p><span style="font-family:Verdana;font-size:9pt;">Σε σχετικά forum, επικές είναι οι μάχες που διεξάγονται με αφορμή το ποια γλώσσα είναι η καλύτερη για την ανάπτυξη βιντεοπαιχνιδιών. Τελευταία, με την αυξανόμενη δημοτικότητα του XNA Game Studio, επίθεση δέχεται η C#/.NET, ως μια αργή γλώσσα που δεν μπορεί να υποστηρίξει «σοβαρά» παιχνίδια.<br />
</span></p>
<p><span style="font-family:Verdana;font-size:9pt;">Η διαμάχη αυτή δεν είναι καινούργια. Προς υπενθύμιση των παλιότερων και ενημέρωση των νεώτερων (όπως έλεγαν οι παππούδες μας), θα σας πω μια σύντομη ιστορία.</span></p>
<p><span style="font-family:Verdana;font-size:9pt;"><span id="more-370"></span></span><span style="font-family:Verdana;font-size:9pt;">«Πριν, πολλά πολλά χρόνια (τη δεκαετία του &#8216;80 δηλαδή), η ανάπτυξη παιχνιδιών γίνονταν με τη χρήση της γλώσσας Assembly. Η Assembly ήταν μια δύσκολη, δύσχρηστη και δυσνόητη γλώσσα προγραμματισμού. Ήταν εφιάλτης να εντοπίσεις σφάλματα σε κάποιο (μεγάλο) κώδικα παιχνιδιού, και η επαναχρησιμοποίηση κώδικα, καθώς και η συνεργατική ανάπτυξη σε μια σχετικά μεγάλη ομάδα ήταν δύσκολη. Επιπλέον, λόγω της μεγάλης εξάρτησης της γλώσσας από το υλικό κάθε πλατφόρμας, η μεταφορά του κώδικα του παιχνιδιού σε παιχνιδομηχανή διαφορετικού κατασκευαστή ήταν αδύνατη. Όμως στην πενιχρή υπολογιστική ισχύ και μνήμη των πλατφορμών αυτό, η Assembly έδινε τη μέγιστη ταχύτητα. Ενώ την εποχή εκείνη υπήρχε η C που ήταν ευκολότερη στον προγραμματισμό, περισσότερο εύχρηστη και με μεγάλη φορητότητα, οι προγραμματιστές την απέφευγαν με τη δικαιολογία ότι δεν δίνει τη μέγιστη απόδοση στις αργές παιχνιδομηχανές της εποχής (και πράγματι δεν έδινε).<br />
</span></p>
<p><span style="font-family:Verdana;font-size:9pt;">Μέχρι το τέλος της δεκαετίας του &#8216;90, το μέγεθος του κώδικα των παιχνιδιών μεγάλωσε σημαντικά, οι παιχνιδομηχανές έγιναν ισχυρότερες, και οι προϋπολογισμοί και το οικονομικό ρίσκο των παιχνιδιών αυξήθηκαν, με αποτέλεσμα στις εταιρίες ανάπτυξης να δίνεται μεγαλύτερη έμφαση στην αναγνωσιμότητα και στην ευκολία συντήρησης του κώδικα (έτσι ώστε να διευκολύνεται και η ομαδική ανάπτυξη). Το παιχνίδι Doom, το οποίο ήταν γραμμένο σχεδόν εξολοκλήρου σε C, απέδειξε ότι η γλώσσα ήταν ώριμη για μεγάλες παραγωγές. Έτσι, η Assembly σχεδόν εγκαταλείφτηκε (εκτός από μερικές περιπτώσεις που η ταχύτητα εκτέλεσης ήταν κρίσιμη) χάριν της C, που είχε πολύ καλή απόδοση από πλευράς ταχύτητας και υποστήριζε ευκολότερη συντήρηση κώδικα. Την εποχή εκείνη υπήρχε και η C++, μια αντικειμενοστρεφής γλώσσα, επέκταση της C, που έκανε το σχεδιασμό, τη συντήρηση, την επαναχρησιμοποίηση και την επέκταση του κώδικα ακόμα ευκολότερα, όμως οι προγραμματιστές την απέφευγαν διότι θεωρούσαν ότι είναι αργή και ότι δεν δίνει τη μέγιστη απόδοση σε ένα παιχνίδι.<br />
</span></p>
<p><span style="font-family:Verdana;font-size:9pt;">Από το 2005 και μετά το μέγεθος των παιχνιδιών και το κόστος ανάπτυξης έγιναν τεράστια και η μείωση του οικονομικού ρίσκου ακόμα πιο κρίσιμη. Η C πλέον δεν αρκούσε και σταδιακά εγκαταλείφτηκε χάριν της C++, η οποία είναι προς το παρόν η defacto γλώσσα προγραμματισμού στα παιχνίδια. Παράλληλα υπάρχουν σύγχρονες γλώσσες όπως η C# που ελαχιστοποιεί τα σφάλματα στον κώδικα και κάνει τη συντήρηση και επέκτασή του ακόμα πιο εύκολη, και συνεπώς την ανάπτυξη του παιχνιδιού πιο φθηνή (σε σχέση με τη C++). Οι προγραμματιστές όμως την αποφεύγουν διότι δεν δίνει τη μέγιστη απόδοση στην κονσόλα και στον υπολογιστή (και γιατί δεν υποστηρίζεται ακόμα από όλες τις πλατφόρμες).»<br />
</span></p>
<p><span style="font-family:Verdana;font-size:9pt;">Ποια είναι τα ηθικά διδάγματα της ιστορίας;<br />
</span></p>
<p><span style="font-family:Verdana;font-size:9pt;">Πρώτον ότι η διαμάχη για το ποια γλώσσα είναι η καταλληλότερη ξεκινά από τις απαρχές της βιομηχανίας ανάπτυξης βιντεοπαιχνιδιών. Και θα συνεχιστεί πιθανότατα και στο μέλλον. Δεύτερον, όσο περνούν και χρόνια και το κόστος ανάπτυξης βιντεοπαιχνιδιών αυξάνεται, οι εταιρίες αναζητούν τρόπους να μειώσουν το κόστος ανάπτυξης. Ένας τρόπος για να γίνει αυτό είναι με το να χρησιμοποιούν γλώσσες προγραμματισμού που ελαχιστοποιούν την πιθανότητα εμφάνισης σφαλμάτων και κάνουν την ανάπτυξη και επαναχρησιμοποίηση κώδικα ευκολότερη. Τρίτον η ταχύτητα των παιχνιδομηχανών αυξάνεται με ραγδαίους ρυθμούς. Όμως η οπτική ποιότητα των παιχνιδιών δεν αυξάνεται (πλέον) με τον ίδιο ρυθμό. Σταδιακά (ιδίως με την υποστήριξη υψηλής ανάλυσης σε κονσόλες), οι απαιτήσεις σε οπτική ποιότητα και γραφικά έχουν αρχίσει να αγγίζουν ένα άνω όριο. Χαρακτηριστικά όπως τεχνητή νοημοσύνη ίσως, η εύκολη αλληλεπίδραση και γενικότερα η ψυχαγωγία που μπορεί να σου προσφέρει το παιχνίδι είναι περισσότερο κρίσιμα. Αυτό φαίνεται και με τη στροφή των εταιριών σε μεγαλύτερο κοινό με διεπαφές όπως το Wii Remote, Project Natal και τον ανάλογο ανιχνευτή κίνησης της Sony. Η ταχύτητα του τελικού κώδικα σε πολλές περιπτώσεις (αλλά όχι σε όλες), λαμβάνει δεύτερη θέση πίσω από την ευκολία ανάπτυξης. Τρανή απόδειξη για αυτό είναι ο τρόπος προγραμματισμού της GPU (που γενικά απαιτεί την μεγαλύτερη δυνατή ταχύτητα κώδικα), ο οποίος άλλαξε από Assembly στις υψηλού επιπέδου γλώσσες HLSL ή GLSL (που μοιάζουν πολύ με τη C).<br />
</span></p>
<p><span style="font-family:Verdana;font-size:9pt;">Συνεπώς, δεν υπάρχει αυτό που λέμε η καλύτερη γλώσσα για την ανάπτυξη βιντεοπαιχνιδιών, αλλά η καταλληλότερη γλώσσα για το κάθε παιχνίδι/πλατφόρμα. Και η Flash Actionscript είναι αργή, αλλά είναι κατάλληλη για ανάπτυξη web games.<br />
</span></p>
<p><span style="font-family:Verdana;font-size:9pt;">To XNA Game Studio είναι κατάλληλο για ένα μεγάλο εύρος παιχνιδιών, από περιστασιακά μέχρι και μεγάλες παραγωγές. Σου δίνει πλήρη πρόσβαση στον επεξεργαστή γραφικών (GPU), και υποστηρίζει πολυνηματικό προγραμματισμό. Επιπλέον υποστηρίζει και αυτόματη διαχείριση μνήμης. Και είναι λάθος να λέμε ότι το .ΝΕΤ δεν παράγει native κώδικα. Το .</span><span style="font-family:Verdana;font-size:9pt;">ΝΕΤ </span><span style="font-family:Verdana;font-size:9pt;">παράγει τελικό κώδικα στοχευμένο για ένα συγκεκριμένο επεξεργαστή. Στην θεωρία θα μπορούσε να παράξει γρηγορότερο κώδικα από ότι ο compiler της Visual C++, που στοχεύει σε κάποιο γενικό Pentium επεξεργαστή. Ίσως ο compiler του .ΝΕΤ να μην είναι ο βέλτιστος δυνατός (ιδιαίτερα για το Xbox360), αλλά ούτε της C++ ήταν για πολλά χρόνια. Αλλά αυτό είναι κάτι που θα γίνει σίγουρα στο μέλλον.<br />
</span></p>
<p><span style="font-family:Verdana;font-size:9pt;">Δεν βρίσκω το λόγο που δεν θα μπορούσε κανείς να αναπτύξει τα περισσότερα παιχνίδια του Xbox (η προηγούμενη γενιά) με το XNA Game Studio. Αλλά κατά περίπτωση, θα μπορούσε να υποστηρίξει ίσως και μεγάλες παραγωγές του Xbox360. Παιχνίδια που είναι αυτό που λέμε GPU-bound (η CPU περιμένει την GPU να ολοκληρώσει την απεικόνιση πριν της στείλει νέο περιεχόμενο), δεν θα είχαν και πολλά να κερδίσουν από τη χρήση C++ αντί της C#, ακόμα και αν η δεύτερη είναι πιο αργή από τη πρώτη.<br />
</span></p>
<p><span style="font-family:Verdana;font-size:9pt;">Ο στόχος μας ως δημιουργούς βιντεοπαιχνιδιών είναι η ανάπτυξη το δυνατόν καλύτερων παιχνιδιών από άποψη ψυχαγωγικής αξίας. Η γλώσσα, η πλατφόρμα, το API γραφικών είναι απλά εργαλεία για το σκοπό αυτό. Και το XNA Game Studio/C#/.NET είναι απλά είναι ευέλικτο και εύχρηστο εργαλείο, που αναλαμβάνει ένα μεγάλο μέρος των «βαρετών» εργασιών που ενέχει η ανάπτυξη ενός παιχνιδιού και μας επιτρέπει να επικεντρωθούμε στην ανάπτυξη καθ&#8217;αυτή. Και σίγουρα είναι λιγότερο τρομακτικό για τον αρχάριο, ο οποίος θα πρέπει να κολυμπήσει στα βαθιά νερά της C++/DirectX/OpenGL και κατά πάσα πιθανότητα, αν κρίνουμε από το πληθυσμό που αναπτύσσει βιντεοπαιχνίδια για χόμπι, να πνιγεί.<br />
</span></p>
<p><span style="font-family:Verdana;font-size:9pt;">To blog θα επανέλθει στο τέλος Αυγούστου ανανεωμένο όπως λένε. Συνεχίστε να στέλνετε email με τις διορθώσεις του <a href="http://videogameslab.wordpress.com/2009/08/13/squash-the-bugs/" target="_blank">Squash the bugs</a>.<br />
</span></p>
<p><span style="font-family:Verdana;font-size:9pt;"><br />
</span></p>
  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/videogameslab.wordpress.com/370/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/videogameslab.wordpress.com/370/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/videogameslab.wordpress.com/370/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/videogameslab.wordpress.com/370/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/videogameslab.wordpress.com/370/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/videogameslab.wordpress.com/370/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/videogameslab.wordpress.com/370/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/videogameslab.wordpress.com/370/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/videogameslab.wordpress.com/370/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/videogameslab.wordpress.com/370/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=videogameslab.wordpress.com&blog=5040448&post=370&subd=videogameslab&ref=&feed=1" /></div>]]></content:encoded>
			<wfw:commentRss>http://videogameslab.wordpress.com/2009/08/17/best-language/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
	
		<media:content url="http://0.gravatar.com/avatar/4bd00ab99710c6e67ef0a28c68628aad?s=96&#38;d=http%3A%2F%2F0.gravatar.com%2Favatar%2Fad516503a11cd5ca435acc9bb6523536%3Fs%3D96" medium="image">
			<media:title type="html">thinkinggamer</media:title>
		</media:content>
	</item>
		<item>
		<title>Debugging κώδικα με τη Visual C# 2008 Express Edition (μέρος 2ο)</title>
		<link>http://videogameslab.wordpress.com/2009/08/07/debugging-part2/</link>
		<comments>http://videogameslab.wordpress.com/2009/08/07/debugging-part2/#comments</comments>
		<pubDate>Fri, 07 Aug 2009 17:51:47 +0000</pubDate>
		<dc:creator>Κώστας Αναγνώστου</dc:creator>
				<category><![CDATA[.NET]]></category>
		<category><![CDATA[C#]]></category>
		<category><![CDATA[XNA Game Studio]]></category>
		<category><![CDATA[Ανάπτυξη βιντεοπαιχνιδιών]]></category>
		<category><![CDATA[Προγραμματισμός]]></category>

		<guid isPermaLink="false">http://videogameslab.wordpress.com/?p=343</guid>
		<description><![CDATA[Συνεχίζουμε την περιήγηση μας στις δυνατότητες για εκσφαλμάτωση (debugging) κώδικα που μας παρέχει η Visual C# 2008 Express Edition πάνω στην οποία βασίζεται το XNA Game Studio. Στο προηγούμενο tutorial είχαμε μιλήσει για τα breakpoints ως μηχανισμούς που μας επιτρέπουν να σταματάμε τη ροή του προγράμματος σε οποιοδήποτε σημείο και να βλέπουμε τις τιμές των [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=videogameslab.wordpress.com&blog=5040448&post=343&subd=videogameslab&ref=&feed=1" />]]></description>
			<content:encoded><![CDATA[<div class='snap_preview'><br /><p><span style="font-family:Verdana;font-size:9pt;">Συνεχίζουμε την περιήγηση μας στις δυνατότητες για εκσφαλμάτωση (debugging) κώδικα που μας παρέχει η Visual C# 2008 Express Edition πάνω στην οποία βασίζεται το XNA Game Studio. <a href="http://videogameslab.wordpress.com/2009/07/28/debugging-part1/" target="_blank">Στο προηγούμενο tutorial</a> είχαμε μιλήσει για τα breakpoints ως μηχανισμούς που μας επιτρέπουν να σταματάμε τη ροή του προγράμματος σε οποιοδήποτε σημείο και να βλέπουμε τις τιμές των μεταβλητών του. Σήμερα θα δούμε επιπλέον μηχανισμούς που μας παρέχει η C#/.NET για το σκοπό αυτό όπως το αντικείμενο Debug (με τη μέθοδο Assert, και την έξοδο στο παράθυρο Output) και τα Exceptions.</span><br />
<span id="more-343"></span><span style="font-family:Verdana;font-size:9pt;">Πριν δούμε τις επιπλέον δυνατότητες της Visual C# όμως, θα ήθελα να αναφερθώ λίγο στις διαφορές του Debug και Release configuration, το οποίο μπορούμε να καθορίσουμε με το drop down μενού στο πάνω μέρος του παραθύρου:<br />
</span></p>
<p><img src="http://videogameslab.files.wordpress.com/2009/08/080709_1751_debugging1.png" alt="" /><span style="font-family:Verdana;font-size:9pt;"><br />
</span></p>
<p><span style="font-family:Verdana;font-size:9pt;">Το Debug configuration είναι ένα σύνολο οδηγιών που δίνουμε στο compiler του προγράμματος έτσι ώστε να ετοιμάσει το τελικό εκτελέσιμο αρχείο με τέτοιο τρόπο που να υποστηρίζει εντοπισμό σφαλμάτων. Στο configuration αυτό, ο compiler εισάγει επιπλέον πληροφορίες στον εκτελέσιμο κώδικα, όπως ονόματα μεταβλητών και μεθόδων ώστε να μπορούμε να μπούμε σε break-mode και να ελέγξουμε τις τιμές τους. Σε Release configuration, οι έξτρα πληροφορίες αυτές δεν υπάρχουν, ο εκτελέσιμος κώδικας είναι μικρότερος  σε μέγεθος (και κατά συνέπεια πιο γρήγορος), αλλά δεν μπορούμε να κάνουμε debugging με τη μέθοδο των breakpoints και των επιπλέον μεθόδων που θα αναφέρουμε παρακάτω.<br />
</span></p>
<p><span style="font-family:Verdana;font-size:9pt;">Μια παρένθεση εδώ για να επισημάνουμε μια διαφορά της C# σε σχέση με άλλες γλώσσες όπως τη C++. Στη C++ ο compiler σε Release configuration κάνει μια σειρά από βελτιστοποιήσεις έτσι ώστε να παράγει τον αποδοτικότερο δυνατό κώδικα. Αντίθετα, στη C# οι βελτιστοποιήσεις σε Release configuration δεν γίνονται από τον compiler της C# αλλά από τον compiler του .ΝΕΤ σε native κώδικα. Σε Release configuration ο compiler της C# δεν κάνει πολλά περισσότερα από το να αφαιρεί τις πληροφορίες για debugging παράγοντας μικρότερα εκτελέσιμα αρχεία.<br />
</span></p>
<blockquote><p><span style="font-size:9pt;"><span style="font-family:Verdana;">Ο κανόνας (για οποιαδήποτε γλώσσα, όχι μόνο τη C#) είναι ότι αναπτύσσουμε και δοκιμάζουμε το κώδικα σε Debug configuration και χρησιμοποιούμε το Release configuration για να κάνουμε μετρήσεις ταχύτητας του παιχνιδιού  και για το τελικό distribution (αυτό που θα διαθέσουμε δηλαδή στην αγορά! </span><span style="font-family:Wingdings;">J</span><span style="font-family:Verdana;">). Επιπλέον για το λόγο που ανέφερα παραπάνω, ποτέ δεν κάνουμε μετρήσεις ταχύτητας του παιχνιδιού τρέχοντας το από το περιβάλλον της Visual C# 2008 EE γιατί έτσι  δεν θα έχει ο .NET compiler την ευκαιρία να κάνει τις απαραίτητες βελτιστοποιήσεις που θα αυξήσουν την ταχύτητα του προγράμματος.<br />
</span></span></p></blockquote>
<p><span style="font-family:Verdana;font-size:9pt;">Αυτά όσον αφορά τις διαφορές και την χρήση των Debug/Release configuration, επιστρέφουμε στους μηχανισμούς για debugging που παρέχει η C#. H δυνατότητα χρήσης breakpoints είναι σωτήρια για την εκσφαλμάτωση ενός παιχνιδιού όταν γνωρίζουμε που περίπου μπορεί να συμβαίνει το σφάλμα, όπως στην περίπτωση του προηγούμενου tutorial. Υποστηρίζει δηλαδή ένα είδος διερευνητικής εκσφαλμάτωσης.<br />
</span></p>
<p><span style="font-family:Verdana;font-size:9pt;">H μέθοδος Assert του αντικειμένου Debug αντίθετα επιτρέπει μια πιο αμυντική προσέγγιση στην εκσφαλμάτωση εισάγοντας ελέγχους σε καθορισμένα από εμάς σημεία του κώδικα. Όταν ο έλεγχος (μιας συνθήκης) αποτύχει, τότε το πρόγραμμα εισάγεται αυτόματα σε break-mode στο συγκεκριμένο σημείο. Αυτό θα γίνει πιο κατανοητό με ένα παράδειγμα. Στο προηγούμενο tutorial είχαμε «κατά λάθος» δώσει στη ταχύτητα της ρακέτας υπολογιστή τιμή κατά πολύ μεγαλύτερη της ταχύτητας της μπάλας με αποτέλεσμα να παρατηρούμε αυτή τη «σπαστική» κίνηση πάνω-κάτω που έκανε η ρακέτα στην προσπάθεια της να προλάβει την μπάλα (αφότου την έχει προσπεράσει). Αν θέλαμε λοιπόν να είμαστε βέβαιοι ότι κανένας προγραμματιστής δεν θα δώσει τιμή στην ταχύτητα της ρακέτας μεγαλύτερη από αυτή της μπάλας μπορούμε να εισάγουμε τον παρακάτω έλεγχο στην Update:<br />
</span></p>
<pre class="brush: csharp;">
protected override void Update(GameTime gameTime)
{
      Debug.Assert(rightPaddleSpeed &lt;= ballSpeed, &quot;Wrong paddle speed!&quot;, &quot;The computer paddle speed is larger than the ball speed&quot;);
      // υπόλοιπος κώδικας
}
</pre>
<p><span style="font-family:Verdana;font-size:9pt;">Για να μπορέσει η C# να εντοπίσει το αντικείμενο Debug και τις μεθόδους του, θα πρέπει επιπλέον να δηλώσουμε οτι θα χρησιμοποιήσουμε τη βιβλιοθήκη System.Diagnostics. Αυτό γίνεται προσθέτοντας στην κορυφή του αρχείου κώδικα τη γραμμή :</span></p>
<pre class="brush: csharp;">
// υπόλοιπος κώδικας
using Microsoft.Xna.Framework.Media;
using Microsoft.Xna.Framework.Net;
using Microsoft.Xna.Framework.Storage;
using System.Diagnostics;
// υπόλοιπος κώδικας
</pre>
<p><span style="font-family:Verdana;font-size:9pt;">Η Assert δέχεται ως ορίσματα οτιδήποτε επιστρέφει true ή false, μια σύντομη εξήγηση και μια αναλυτικότερη εξήγηση του σφάλματος, σε κείμενο. Με οτιδήποτε επιστρέφει true ή false εννοούμε είτε<br />
</span></p>
<ol>
<li><span style="font-family:Verdana;font-size:9pt;">Μια boolean μεταβλητή πχ Debug.Assert(isSpeedCorrect, &#8220;explanation1&#8243;, &#8220;explanation2&#8243;);<br />
</span></li>
<li><span style="font-family:Verdana;font-size:9pt;">Μια συνθήκη πχ Debug.Assert(speed &gt; 2, &#8220;explanation1&#8243;, &#8220;explanation2&#8243; );<br />
</span></li>
<li><span style="font-family:Verdana;font-size:9pt;">Μια μέθοδο που να επιστρέφει true ή false πχ Debug.Assert(IsSpeedValid(speed), &#8220;explanation1&#8243;, &#8220;explanation2&#8243;);<br />
</span></li>
</ol>
<p><span style="font-family:Verdana;font-size:9pt;">Να θυμίσω ότι στο προηγούμενο tutorial είχαμε θέσει στη rightPaddleSpeed τη τιμή 15.0f και στην ballSpeed τη τιμή 5.0f. Όταν τρέξουμε το παιχνίδι τώρα θα μας υποδεχθεί το εξής pop-up παράθυρο:<br />
</span></p>
<p><img src="http://videogameslab.files.wordpress.com/2009/08/080709_1751_debugging2.png" alt="" /><span style="font-family:Verdana;font-size:9pt;"><br />
</span></p>
<p><span style="font-family:Verdana;font-size:9pt;">Το παράθυρο μας ενημερώνει ότι η συνθήκη που προσδιορίσαμε στην Assert απέτυχε, μας λέει το λόγο (το κείμενο που θέσαμε εμείς στην Assert δηλαδή) και μας λέει που συνέβη το σφάλμα, στην μέθοδο Update, στο αρχείο Game1.cs στην γραμμή 108. Τη πληροφορία για το πού συνέβη το σφάλμα μας τη δίνει το λεγόμενο Call Stack, το οποίο έχω σημειώσει με κόκκινο:<br />
</span></p>
<p><img src="http://videogameslab.files.wordpress.com/2009/08/080709_1751_debugging3.png" alt="" /><span style="font-family:Verdana;font-size:9pt;"><br />
</span></p>
<p><span style="font-family:Verdana;font-size:9pt;">Το Call Stack μας δείχνει όλες τις μεθόδους που κλήθηκαν (η μία κάλεσε την άλλη δηλαδή) μέχρι να φτάσει το πρόγραμμα στο σημείο του σφάλματος. Δηλαδή στην περίπτωση μας, την μέθοδο Update (που εμφανίστηκε το σφάλμα) κάλεσε η μέθοδο Run του αντικειμένου Game1. Το Call Stack είναι πολύ χρήσιμο στο να βλέπουμε την διαδρομή που ακολούθησε το πρόγραμμα μέχρι να φτάσει στο τρέχον σημείο εκτέλεσης. Σε μεγαλύτερα παιχνίδια όπου μια μέθοδος μπορεί να καλεστεί από πολλές διαφορετικές (πχ μια μέθοδος που αναπαράγει ένα ήχο) είναι καλό να ξέρουμε την διαδρομή μέχρι το σφάλμα για να καταλάβουμε ευκολότερα τι το προκάλεσε.<br />
</span></p>
<p><span style="font-family:Verdana;font-size:9pt;">Όταν κάποιο Assert αποτύχει μας δίνει 3 επιλογές, να σταματήσουμε το πρόγραμμα εντελώς (Abort), να εισέλθουμε σε break-mode στο σημείο που εμφανίστηκε το σφάλμα ώστε να κάνουμε debugging (Retry) ή να σφυρίξουμε αδιάφορα και να κάνουμε πως δεν συνέβη τίποτα (Ignore). Στην τελευταία περίπτωση όμως, επειδή είναι λίγο απίθανο να διορθωθεί το πρόγραμμα από μόνο του, το συγκεκριμένο Assert θα αποτυγχάνει συνεχώς (και πιθανώς μερικά άλλα μαζί του που εξαρτώνται από αυτό) και θα βλέπουμε συνέχεια το pop-up παράθυρο. Το break-mode που μας εισάγει η δεύτερη επιλογή δεν διαφέρει από αυτό που γνωρίσαμε στο προηγούμενο tutorial, στο οποίο μπορούμε να ελέγξουμε τιμές μεταβλητών, να θέσουμε breakpoints και να κάνουμε βηματική εκτέλεση κώδικα (step-execution) με το F10.<br />
</span></p>
<p><span style="font-family:Verdana;font-size:9pt;">Είναι καλό να χρησιμοποιούμε την Assert στα παιχνίδια μας όσο γίνεται περισσότερο, προκειμένου να εξασφαλίζουμε την ορθότητα ορισμένων παραμέτρων και το επιτυχές αποτέλεσμα ορισμένων λειτουργιών (αν πχ μια μέθοδο επιστρέφει ένα αποδεκτό αποτέλεσμα). Το μεγάλο της πλεονέκτημα είναι ότι μια Assert εκτελείται μόνο όταν το πρόγραμμα τρέχει σε Debug configuration. Σε Release αυτή αφαιρείται από το κώδικα αυτόματα και δεν εκτελείται ποτέ. Με τον τρόπο αυτό δεν επηρεάζει την ταχύτητα εκτέλεσης του τελικού κώδικα. Δοκιμάστε για παράδειγμα να αλλάξετε το configuration σε Release και πατήστε το F5.<br />
</span></p>
<p><img src="http://videogameslab.files.wordpress.com/2009/08/080709_1751_debugging4.png" alt="" /><span style="font-family:Verdana;font-size:9pt;"><br />
</span></p>
<p><span style="font-family:Verdana;font-size:9pt;">Το παιχνίδι θα τρέξει κανονικά, το pop-up παράθυρο δεν θα εμφανιστεί και η ρακέτα θα συνεχίσει τη «σπαστική» κίνηση πάνω-κάτω.<br />
</span></p>
<blockquote><p><span style="font-family:Verdana;font-size:9pt;">Το γεγονός ότι η Assert δεν εκτελείται σε Release configuration μπορεί να δημιουργήσει αναπάντεχα προβλήματα σε περιπτώσεις μη σωστής χρήσης της. Στην Rare ως νέος προγραμματιστής είχα αναλάβει το σύστημα επεξεργασίας και απεικόνισης κειμένου (font rendering) του παιχνιδιού Conker: Live and Reloaded (Xbox). Την assert την χρησιμοποιούσαμε πάρα πολύ στο κώδικα που αναπτύσσαμε, στη C/C++ είναι ακόμα χρησιμότερη από ότι στη C# (πχ για null pointers). Είχα φτιάξει λοιπόν μια συνάρτηση που υπολόγιζε μερικές παραμέτρους για ένα font (μέγεθος σε pixel κλπ) και επέστρεφε false σε περίπτωση που κάτι δεν πήγαινε καλά με το font. Θεώρησα λοιπόν καλό, ως πρόθυμος αλλά αρχάριος προγραμματιστής, να βάλω την συνάρτηση μέσα σε ένα assert (ως συνθήκη) για να είμαι βέβαιος ότι πάντα εκτελούνταν σωστά. Σε debug configuration έτρεχε σαν όνειρο το παιχνίδι. Όταν έδωσα όμως το κώδικα στους προγραμματιστές του παιχνιδιού έμαθα με έκπληξη ότι ο κώδικας δεν δούλευε, έτρεχε δηλαδή το παιχνίδι αλλά το κείμενο δεν εμφανιζόταν (αυτοί έτρεχαν το παιχνίδι σε Release configuration)… Μου πήρε κάμποσες ώρες να διαπιστώσω γιατί έτρεχε μια χαρά σε debug και όχι σε release configuration, αλλά το πάθημα μου έγινε ένα καλό μάθημα. <strong>Ποτέ δεν βάζεις σε Assert μεθόδους που υπολογίζουν κάτι χρήσιμο. Μόνο μεθόδους που ελέγχουν συνθήκες, πχ αν είναι έγκυρη μια μεταβλητή</strong> κλπ.<br />
</span></p></blockquote>
<p><span style="font-family:Verdana;font-size:9pt;">Αυτά όσον αφορά τη χρήση της Assert. Παρόμοια συμπεριφορά θα μπορούσα να επιτύχω με τη χρήση ενός μηχανισμού που ονομάζεται Exceptions. Τα exceptions είναι ένα μεγάλο κεφάλαιο της C# που είναι αδύνατο έστω και να αγγίξουμε εδώ. Μπορούμε όμως χωρίς πολλές γνώσεις να τα χρησιμοποιήσουμε με τρόπο παρόμοιο με την Assert (για να εξασφαλίσουμε ότι κάποιες συνθήκες είναι αληθής):<br />
</span></p>
<pre class="brush: csharp;">
        protected override void Update(GameTime gameTime)
        {
            if (rightPaddleSpeed &gt; ballSpeed)
            {
                throw new Exception(&quot;The computer paddle speed is larger than the ball speed&quot;);
            }
		// υπόλοιπος κώδικας
        }
</pre>
<p><span style="font-family:Verdana;font-size:9pt;">Εδώ ελέγχουμε με μια if-συνθήκη αν η ταχύτητα της ρακέτας είναι μεγαλύτερη από αυτή της μπάλας. Αν ναι, τότε δημιουργούμε ένα νέο Exception αντικείμενο (new Exception(&#8220;&#8221;)) και το στέλνουμε (throw) προς το CLR του .NET.<br />
</span></p>
<p><span style="font-family:Verdana;font-size:9pt;">Ο παραπάνω κώδικας είναι ισοδύναμος με το κώδικα που χρησιμοποιήσαμε για την Assert. Έχει όμως μερικές διαφορές στη συμπεριφορά του: Πρώτον θα εκτελεστεί και σε Debug και σε Release Configuration. Δεύτερον δεν εμφανίζει pop-up παράθυρο (όταν τρέχουμε το πρόγραμμα μέσω της Visual C#) αλλά μας εισάγει απευθείας σε break-mode στο σημείο που δημιουργήσαμε το Exception. Και τρίτον είναι δυνατόν μέσω ενός μηχανισμού try {}catch {}, να «πιάσουμε» το Exception αυτό στο κώδικα μας και να διορθώσουμε το σφάλμα χωρίς να διακόψουμε την εκτέλεση του παιχνιδιού και χωρίς να το καταλάβει ο χρήστης. Τα Exceptions είναι ένας πολύ δυνατός και ευέλικτος μηχανισμός που δεν ταιριάζει ιδιαίτερα σε μικρά παιχνίδια όπως αυτά που αναπτύσσουμε, αλλά είναι καλό να γνωρίζουμε την ύπαρξη τους.<br />
</span></p>
<p><span style="font-family:Verdana;font-size:9pt;">Θα  κλείσουμε το tutorial με μια αναφορά στα υπόλοιπα παράθυρα που εμφανίζονται στη Visual C# στο κάτω μέρος της οθόνης όταν το παινχίδι τρέχει, και ιδίως όταν αυτό βρίσκεται σε break-mode (έχει σταματήσει η ροή σε κάποιο σημείο δηλαδή). Για το παράθυρο Watch μιλήσαμε ήδη, είναι το παράθυρο στο οποίο εμφανίζονται οι τιμές των μεταβλητών (ή των εκφράσεων) που έχουμε προσθέσει με αριστερό κλικ-Add Watch. Ένα άλλο παράθυρο ονομάζεται Call Stack (αν δεν εμφανίζεται μπορείτε να το εμφανίσετε επιλέγοντας από το μενού Debug/Windows/Call Stack):<br />
</span></p>
<p><img src="http://videogameslab.files.wordpress.com/2009/08/080709_1751_debugging5.png" alt="" /><span style="font-family:Verdana;font-size:9pt;"><br />
</span></p>
<p><span style="font-family:Verdana;font-size:9pt;">To Call Stack το εξηγήσαμε παραπάνω, μας δείχνει την διαδρομή που ακολούθησε το πρόγραμμα (ποια μέθοδο κάλεσε ποιαν δηλαδή) μέχρι να φτάσουμε στο σημείο του breakpoint (ή οποιοδήποτε άλλο σημείο εκτέλεσης του προγράμματος όταν είμαστε σε break-mode). To Call Stack είναι πολύ χρήσιμο ιδιαίτερα για μεγαλύτερα παιχνίδια στα οποία μπορούμε να έχουμε διαφορετικά μονοπάτια εκτέλεσης κώδικα.<br />
</span></p>
<p><span style="font-family:Verdana;font-size:9pt;">Το παράθυρο Locals είναι από τα λιγότερο χρησιμοποιούμενα (τουλάχιστον από εμένα) παράθυρα. Μας δείχνει ποιες μεταβλητές (και τις τιμές τους) είναι ορατές από το τρέχον σημείο εκτέλεσης (πχ αυτές που έχουν οριστεί τοπικά, η global μεταβλητές, αλλά όχι αυτές που έχουν οριστεί σε άλλη μέθοδο). Δεν μπορούμε να προσθέσουμε ή να  αφαιρέσουμε ονόματα μεταβλητών όπως στο παράθυρο Watch.<br />
</span></p>
<p><span style="font-family:Verdana;font-size:9pt;">Τέλος στο παράθυρο Output (αν δεν είναι ορατό: Debug/Windows/Output) εμφανίζεται κείμενο που εμφανίζει το .NET κατά τη φόρτωση και την εκτέλεση του παιχνιδιού. Συνήθως το κείμενο αυτό δεν μας ενδιαφέρει (αν και μερικές φορές μπορεί να μας δώσει χρήσιμες πληροφορίες σχετικά με το γιατί δεν ξεκινά η εκτέλεση – αν κάποια βιβλιοθήκη είναι λάθος κλπ). Όμως στο παράθυρο αυτό μπορούμε να στείλουμε και εμείς κείμενο κατά την εκτέλεση του προγράμματος, προς ενημέρωση του προγραμματιστή. Παράδειγμα αντί να χρησιμοποιήσουμε την Assert για να ελέγξουμε  τη τιμή της ταχύτητας της ρακέτας, και να διακόψουμε τη ροή του προγράμματος, θα μπορούσαμε να ενημερώσουμε το προγραμματιστή μέσω του Output παραθύρου:<br />
</span></p>
<pre class="brush: csharp;">
        protected override void Update(GameTime gameTime)
        {
            Debug.WriteLineIf(rightPaddleSpeed &gt; ballSpeed, &quot;The computer paddle speed is larger than the ball speed&quot;);

		// υπόλοιπος κώδικας
        }
</pre>
<p><span style="font-family:Verdana;font-size:9pt;">H WriteLineIf() ελέγχει τη συνθήκη και αν είναι αληθής, τυπώνει το μήνυμα στο Output παράθυρο. Μόλις τρέξουμε το πρόγραμμα (σε Debug configuration μόνο) θα δούμε λοιπόν:<br />
</span></p>
<p><img src="http://videogameslab.files.wordpress.com/2009/08/080709_1751_debugging6.png" alt="" /><span style="font-family:Verdana;font-size:9pt;"><br />
</span></p>
<p><span style="font-family:Verdana;font-size:9pt;">Δεν χρειάζεται φυσικά να ισχύει κάποια συνθήκη για να τυπώσουμε κείμενο στο παράθυρο, μπορούμε να το κάνουμε οποτεδήποτε με τη χρήση της μεθόδου Debug.WriteLine().<br />
</span></p>
<p><span style="font-family:Verdana;font-size:9pt;">Για όλες τις μεθόδους του αντικειμένου Debug (Assert, WriteLineIf, WriteLine κλπ) ισχύει ότι εκτελούνται μόνο σε Debug configuration και όχι σε Release.<br />
</span></p>
<p><span style="font-family:Verdana;font-size:9pt;">Είδαμε και σήμερα μερικά βασικά εργαλεία που μπορούμε να χρησιμοποιήσουμε για να πιστοποιήσουμε τη καλή λειτουργία του κώδικα των παιχνιδιών που αναπτύσσουμε. Υπάρχουν και άλλοι τρόποι και πολλά εξωτερικά εργαλεία (εκτός Visual C#) που μπορούμε να χρησιμοποιήσουμε για εκσφαλμάτωση, αλλά για τα απλά παιχνίδια που αναπτύσσουμε προς το παρόν οι μηχανισμοί που παρουσιάσαμε αρκούν.</span></p>
  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/videogameslab.wordpress.com/343/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/videogameslab.wordpress.com/343/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/videogameslab.wordpress.com/343/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/videogameslab.wordpress.com/343/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/videogameslab.wordpress.com/343/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/videogameslab.wordpress.com/343/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/videogameslab.wordpress.com/343/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/videogameslab.wordpress.com/343/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/videogameslab.wordpress.com/343/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/videogameslab.wordpress.com/343/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=videogameslab.wordpress.com&blog=5040448&post=343&subd=videogameslab&ref=&feed=1" /></div>]]></content:encoded>
			<wfw:commentRss>http://videogameslab.wordpress.com/2009/08/07/debugging-part2/feed/</wfw:commentRss>
		<slash:comments>5</slash:comments>
	
		<media:content url="http://0.gravatar.com/avatar/4bd00ab99710c6e67ef0a28c68628aad?s=96&#38;d=http%3A%2F%2F0.gravatar.com%2Favatar%2Fad516503a11cd5ca435acc9bb6523536%3Fs%3D96" medium="image">
			<media:title type="html">thinkinggamer</media:title>
		</media:content>

		<media:content url="http://videogameslab.files.wordpress.com/2009/08/080709_1751_debugging1.png" medium="image" />

		<media:content url="http://videogameslab.files.wordpress.com/2009/08/080709_1751_debugging2.png" medium="image" />

		<media:content url="http://videogameslab.files.wordpress.com/2009/08/080709_1751_debugging3.png" medium="image" />

		<media:content url="http://videogameslab.files.wordpress.com/2009/08/080709_1751_debugging4.png" medium="image" />

		<media:content url="http://videogameslab.files.wordpress.com/2009/08/080709_1751_debugging5.png" medium="image" />

		<media:content url="http://videogameslab.files.wordpress.com/2009/08/080709_1751_debugging6.png" medium="image" />
	</item>
		<item>
		<title>Debugging κώδικα με τη Visual C# 2008 Express Edition (μέρος 1ο)</title>
		<link>http://videogameslab.wordpress.com/2009/07/28/debugging-part1/</link>
		<comments>http://videogameslab.wordpress.com/2009/07/28/debugging-part1/#comments</comments>
		<pubDate>Tue, 28 Jul 2009 14:17:05 +0000</pubDate>
		<dc:creator>Κώστας Αναγνώστου</dc:creator>
				<category><![CDATA[.NET]]></category>
		<category><![CDATA[C#]]></category>
		<category><![CDATA[XNA Game Studio]]></category>
		<category><![CDATA[Ανάπτυξη βιντεοπαιχνιδιών]]></category>
		<category><![CDATA[Προγραμματισμός]]></category>

		<guid isPermaLink="false">http://videogameslab.wordpress.com/?p=326</guid>
		<description><![CDATA[Πριν προχωρήσουμε σε περισσότερο σύνθετα παραδείγματα παιχνιδιών, καλό θα ήταν να κάνουμε σήμερα μια παύση και να αναφερθούμε λίγο σε μερικά εργαλεία που μας παρέχει το περιβάλλον της Visual C# 2008 EE, πάνω στο οποίο βασίζεται το XNA Game Studio, για debugging κώδικα. Είναι βασικό για κάθε προγραμματιστή να έχει καλή γνώση του περιβάλλοντος στο [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=videogameslab.wordpress.com&blog=5040448&post=326&subd=videogameslab&ref=&feed=1" />]]></description>
			<content:encoded><![CDATA[<div class='snap_preview'><br /><p><span style="font-family:Verdana;font-size:9pt;">Πριν προχωρήσουμε σε περισσότερο σύνθετα παραδείγματα παιχνιδιών, καλό θα ήταν να κάνουμε σήμερα μια παύση και να αναφερθούμε λίγο σε μερικά εργαλεία που μας παρέχει το περιβάλλον της Visual C# 2008 EE, πάνω στο οποίο βασίζεται το XNA Game Studio, για debugging κώδικα. Είναι βασικό για κάθε προγραμματιστή να έχει καλή γνώση του περιβάλλοντος στο οποίο αναπτύσσει μια εφαρμογή και ιδιαίτερα την υποστήριξη για debugging που του προσφέρει. Χρόνος που δαπανάται για τον εντοπισμό ενός σφάλματος, πολλά από τα οποία είναι ανόητες παραλήψεις εκ μέρους του προγραμματιστή (πιστέψτε με, έχω μεγάλη εμπειρία σε αυτό!), είναι χρόνος που αφαιρείται από την ανάπτυξη κώδικα. Οπότε ο χρόνος που σπαταλάμε στο debugging πρέπει να είναι το δυνατόν σύντομος.</span></p>
<p><span style="font-family:Verdana;font-size:9pt;"><span id="more-326"></span></span><span style="font-family:Verdana;font-size:9pt;">Σε σχέση με παλαιότερες γλώσσες όπως τη C/C++, η C#/.NET παρέχει εκ σχεδιασμού πολλές δικλείδες ασφαλείας που αποτρέπουν πολλά από τα κοινά σφάλματα που βρίσκουν το δρόμο τους στο κώδικα, όπως για παράδειγμα η χρήση μιας μεταβλητής που δεν έχει αρχικοποιηθεί (στη C/C++ ιδίως αν η μεταβλητή αυτή είναι pointer μπορεί να οδηγηθεί ο προγραμματιστής σε πολλές άυπνες νύχτες αναζήτησης). Στα σφάλματα λογικής όμως δεν μπορεί να βοηθήσει και πολύ το περιβάλλον, για το λόγο αυτό παρέχει στο προγραμματιστή μηχανισμούς με τους οποίους μπορεί να σταματήσει τη ροή εκτέλεσης και να δει βήμα-βήμα τι λειτουργίες πραγματοποιούνται και τις ενδιάμεσες τιμές των μεταβλητών του προγράμματος. Ένας χρήσιμος μηχανισμός για την εργασία αυτή είναι τα breakpoints.<br />
</span></p>
<p><span style="font-family:Verdana;font-size:9pt;">Θα δούμε τη χρήση των μηχανισμών αυτών με ένα παράδειγμα. Τρέχουμε τη Visual C# και φορτώνουμε <a href="http://videogameslab.googlecode.com/files/Pong_part4.zip" target="_blank">την έκδοση του παιχνιδιού Pong</a> που περιγράψαμε στο <a href="http://videogameslab.wordpress.com/2009/07/17/hello-pong-part4/" target="_blank">4<sup>ο</sup> μέρος του tutorial</a>. Στην συνέχεια, στη μέθοδο Initialise(), αλλάζουμε τη τιμή της μεταβλητής rightPaddleSpeed σε 15.0f:<br />
</span></p>
<pre class="brush: csharp;">
        protected override void Initialize()
        {
            //υπόλοιπος κώδικας

            rightPaddleSpeed = 15.0f;
            base.Initialize();
        }
</pre>
<p><span style="font-family:Verdana;font-size:9pt;">Τρέχουμε το παιχνίδι με F5 και παρατηρούμε ότι η κίνηση της ρακέτας του υπολογιστή είναι κάπως περίεργη, κάνει μια «σπαστική» κίνηση πάνω-κάτω. Έχουμε εξηγήσει γιατί συμβαίνει αυτό, αλλά ας υποθέσουμε ότι δεν ξέρουμε και ότι θέλουμε να το διαπιστώσουμε. Εφόσον το σφάλμα αφορά τη κίνηση της ρακέτας, εντοπίζουμε στην μέθοδο Update το κομμάτι κώδικα που υπολογίζει την κίνηση της και εστιάζουμε εκεί. Ο υπολογισμός της μεταβλητής rightPaddle.Y που καθορίζει τη θέσης ρακέτας του υπολογιστή γίνεται στην γραμμή 137 (περίπου). Τοποθετώντας το κέρσορα στην αμέσως επόμενη γραμμή αυτή και πατώντας F9, ή εναλλακτικά κάνοντας αριστερό κλικ στη μπεζ στα αριστερά της εντολής λωρίδα (στη περιοχή που έχουμε μαρκάρει με κόκκινο στην παρακάτω εικόνα) δημιουργούμε ένα breakpoint στο σημείο αυτό.<br />
</span></p>
<p><img src="http://videogameslab.files.wordpress.com/2009/07/072809_1416_debugging1.png" alt="" /><span style="font-family:Verdana;font-size:9pt;"><br />
</span></p>
<p><span style="font-family:Verdana;font-size:9pt;"><em>Σημείωση: τοποθετήσαμε το breakpoint στην αμέσως επόμενη γραμμή από αυτή που μας ενδιαφέρει, γιατί θέλουμε να μάθουμε τη τιμή της rightPaddle.Y, αφότου η εντολή υπολογισμού της έχει εκτελεστεί.<br />
</em></span></p>
<p><span style="font-family:Verdana;font-size:9pt;">Το breakpoint συμβολίζεται με ένα κόκκινο κύκλο στο ύψος της γραμμής που επιθυμούμε να σταματήσει η εκτέλεση του προγράμματος (το πρόγραμμα θα εισέλθει σε κατάσταση break mode):<br />
</span></p>
<p><img src="http://videogameslab.files.wordpress.com/2009/07/072809_1416_debugging2.png" alt="" /><span style="font-family:Verdana;font-size:9pt;"><br />
</span></p>
<p><span style="font-family:Verdana;font-size:9pt;">Αν το πρόγραμμα εκτελείται την στιγμή που το κάνουμε αυτό, τότε η εκτέλεση θα σταματήσει στο σημείο αυτό, και ένα κίτρινο βέλος θα εμφανιστεί πάνω στο breakpoint. Αν δεν τρέχουμε το πρόγραμμα μπορούμε και πάλι να τοποθετήσουμε το breakpoint στο σημείο αυτό με τον τρόπο που περιγράψαμε και να πατήσουμε F5 για να αρχίσει η εκτέλεση.<br />
</span></p>
<p><img src="http://videogameslab.files.wordpress.com/2009/07/072809_1416_debugging3.png" alt="" /><span style="font-family:Verdana;font-size:9pt;"><br />
</span></p>
<p><span style="font-family:Verdana;font-size:9pt;">Από τη στιγμή που το πρόγραμμα μπει σε break mode, έχουμε τη δυνατότητα να ελέγξουμε τις τιμές των μεταβλητών του. Στην συγκεκριμένη περίπτωση, αν τοποθετήσουμε το κέρσορα πάνω από το όνομα «rightPaddle.Y», θα μάθουμε την τιμή της μεταβλητής αυτής. Το να τοποθετούμε το κέρσορα πάνω από το όνομα της μεταβλητής για να μάθουμε τη τιμή της είναι ένας έγκυρος τρόπος, αλλά όχι ο πιο εύχρηστος. Υπάρχουν και άλλοι τρόποι που διευκολύνουν την εργασία αυτή, ιδιαίτερα αν πρέπει να ελέγχουμε τις τιμές μιας μεταβλητής σε πολλές επαναλήψεις του προγράμματος. Επιλέγουμε/μαρκάρουμε λοιπόν το όνομα της μεταβλητής rightPaddle.Y και πατάμε το δεξί-κλικ επάνω της </span><span style="font-family:Verdana;font-size:9pt;">(ΠΡΟΣΟΧΗ! Επιλέγουμε όλο το όνομα και όχι μόνο το Y. To Y χωρίς το πρόθεμα rightPaddle δεν έχει νόημα)</span><span style="font-family:Verdana;font-size:9pt;">. Στο μενού που εμφανίζεται επιλέγουμε Add Watch.<br />
</span></p>
<p><img src="http://videogameslab.files.wordpress.com/2009/07/072809_1416_debugging4.png" alt="" /><span style="font-family:Verdana;font-size:9pt;"><br />
</span></p>
<p><span style="font-family:Verdana;font-size:9pt;">Ένα νέο παράθυρο εμφανίζεται στο κάτω μέρος της οθόνης, με το όνομα Watch (αν δεν υπάρχει ήδη, μπορεί να γίνει ορατό επιλέγοντας από το κυρίως μενού Debug/Windows/Watch).<br />
</span></p>
<p><img src="http://videogameslab.files.wordpress.com/2009/07/072809_1416_debugging5.png" alt="" /><span style="font-family:Verdana;font-size:9pt;"><br />
</span></p>
<p><span style="font-family:Verdana;font-size:9pt;">Στο παράθυρο αυτό βλέπουμε τώρα στη δεξιά στήλη το όνομα (Name) της μεταβλητής στο μεσαίο την τιμή της (Value) και στο αριστερό το τύπο της μεταβλητής (Type). Η μεταβλητή αυτή θα μείνει μόνιμα στη λίστα μέχρι να την αφαιρέσουμε εμείς. Στο παράθυρο Watch μπορούμε να προσθέσουμε όσες μεταβλητές θέλουμε εμείς, με τον τρόπο που περιγράψαμε παραπάνω. Σε περίπτωση που κάποια μεταβλητή δεν εμφανίζει την τιμή της αυτό σημαίνει ότι δεν είναι ορατή σε αυτό το σημείο και ότι έχει οριστεί αλλού, σε κάποια άλλη μέθοδο ή και αντικείμενο.<br />
</span></p>
<p><span style="font-family:Verdana;font-size:9pt;">Από τη στιγμή που βρισκόμαστε σε break mode, αν πατήσουμε το πλήκτρο F5 η εκτέλεση του κώδικα θα συνεχιστεί μέχρις ότου να συναντήσει το επόμενο breakpoint (αν υπάρχει). Στην περίπτωση μας που έχουμε ορίσει μόνο ένα breakpoint, το πρόγραμμα θα κάνει μια πλήρη επανάληψη και θα καταλήξει στο ίδιο σημείο και πάλι (το ΧΝΑ θα καλέσει ξανά την Update δηλαδή και θα σταματήσει στο breakpoint). Αυτή τη φορά η τιμή της rightPaddle.Y όπως τη βλέπουμε στο παράθυρο Watch είναι διαφορετική. Δοκιμάστε να πατήσετε το F5 μερικές φορές ακόμα να δείτε πως αλλάζει η τιμή της στη πάροδο του χρόνου. Παρατηρούμε ότι η τιμή της αυξάνει για μερικές επαναλήψεις, μειώνεται για μια επανάληψη και συνεχίζει να αυξάνεται πάλι. Αυτό συμβαίνει περιοδικά και δικαιολογεί τη «σπαστική» κίνηση της ρακέτας πάνω-κάτω. Για να καταλάβουμε γιατί συμβαίνει αυτό πρέπει συγκρίνουμε τις Υ τιμές των κέντρων της μπάλας και της ρακέτας, μιας και η διαφορά τους καθορίζει τη τιμή της μεταβλητής sign και το αν θα αυξηθεί ή θα μειωθεί η rightPaddle.Y.<br />
</span></p>
<pre class="brush: csharp;">
            //κινηση ρακέτας υπολογιστή
            int sign = Math.Sign((ball.Top + ball.Height / 2) - (rightPaddle.Top + rightPaddle.Height / 2));
            rightPaddle.Y += (int)(sign*rightPaddleSpeed);
</pre>
<p><span style="font-family:Verdana;font-size:9pt;">Στο παράθυροo Watch μπορώ να προσθέσω εκτός από ονόματα μεταβλητών, και εκφράσεις. Το Visual  Studio θα υπολογίσει τη τιμή τους και θα την απεικονίσει στο παράθυρο. Επιλέγω λοιπόν τις εκφράσεις <strong>ball.Top + ball.Height / 2</strong> και <strong>rightPaddle.Top + rightPaddle.Height / 2</strong> και τις κάνω κανονικά Add Watch (ή με drag and drop στο παράθυρο Watch) κανονικά σαν να ήταν μεταβλητές. Στο παράθυρο βλέπω τώρα τις τιμές των εκφράσεων αυτών.<br />
</span></p>
<p><span style="font-family:Verdana;font-size:9pt;"><br />
<img src="http://videogameslab.files.wordpress.com/2009/07/072809_1416_debugging6.png" alt="" /><br />
</span></p>
<p><span style="font-family:Verdana;font-size:9pt;">Πατώντας τώρα μερικές φορές το F5 και παρατηρώντας τις τιμές των εκφράσεων (τη Υ συνταταγμένη των αντίστοιχων κέντρων δηλαδή) σε κάθε επανάληψη βλέπουμε ότι το κέντρο της ρακέτας <strong>rightPaddle.Top + rightPaddle.Height / 2</strong> αυξάνει σε τιμή γρηγορότερα από το κέντρο της μπάλας <strong>ball.Top + ball.Height / 2</strong>, με αποτέλεσμα η ρακέτα να προσπερνά την μπάλα και να προσπαθεί να επιστρέψει ώστε να έρθει στο σωστό ύψος σε σχέση με αυτή.<br />
</span></p>
<p><span style="font-family:Verdana;font-size:9pt;">Παρατηρώντας λοιπόν τις τιμές των μεταβλητών με κατάλληλα τοποθετημένα breakpoints μπορούμε να εντοπίσουμε προβλήματα «λογικής» σαν και αυτά. Όντας σε break-mode (η εκτέλεση του προγράμματος έχει παγώσει δηλαδή), μπορούμε εκτός του F5 να χρησιμοποιήσουμε και το πλήκτρο F10, το οποίο θα μεταφέρει την εκτέλεση στην επόμενη εντολή, δίνοντας μας την δυνατότητα να τρέξουμε το πρόγραμμα γραμμή-γραμμή παρατηρώντας την αλλαγή των τιμών διάφορων μεταβλητών (step execution). Τέλος ένα άλλο χρήσιμο πλήκτρο όσο κάνουμε debugging το πρόγραμμα είναι και το F9 το οποίο, αν η επόμενη εντολή είναι μέθοδος, θα προσπαθήσει να «μπει» μέσα σε αυτή και θα μας δείξει ποιες εντολές εκτελούνται εκεί. Στη συγκεκριμένη περίπτωση δεν έχει εφαρμογή αλλά είναι χρήσιμο να γνωρίζουμε για αυτή.<br />
</span></p>
<p><span style="font-family:Verdana;font-size:9pt;">Δυστυχώς η Express έκδοση του Visual Studio (που χρησιμοποιούμε εμείς) δεν δίνει επιπλέον ευελιξία στα breakpoints. Η κανονική (εμπορική) έκδοση του Visual Studio επιτρέπει τον ορισμό συνθηκών για το πότε θα σταματά η εκτέλεση σε ένα breakpoint όπως για παράδειγμα ένα μετρητή που να ορίζει πόσες επαναλήψεις πρέπει να πραγματοποιηθούν μέχρι να σταματήσει η εκτέλεση στο σημείο αυτό, ή ακόμα και if-συνθήκες που καθορίζουν πότε θα ενεργοποιηθεί το breakpoint και πότε όχι. Αλλά ακόμα και έτσι, η δυνατότητα να σταματώ την εκτέλεση του προγράμματος και να ελέγχω βήμα-βήμα το τι λειτουργίες εκτελούνται και ποιο το αποτέλεσμα τους είναι σημαντικό εργαλείο ενάντια στο πόλεμο με τα σφάλματα κώδικα.<br />
</span></p>
<p><span style="font-family:Verdana;font-size:9pt;">Στο επόμενο tutorial θα συνεχίσουμε το debugging του προγράμματος με επιπλέον (των breakpoints) μηχανισμών που παρέχει η C#/.NET.<br />
</span></p>
  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/videogameslab.wordpress.com/326/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/videogameslab.wordpress.com/326/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/videogameslab.wordpress.com/326/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/videogameslab.wordpress.com/326/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/videogameslab.wordpress.com/326/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/videogameslab.wordpress.com/326/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/videogameslab.wordpress.com/326/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/videogameslab.wordpress.com/326/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/videogameslab.wordpress.com/326/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/videogameslab.wordpress.com/326/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=videogameslab.wordpress.com&blog=5040448&post=326&subd=videogameslab&ref=&feed=1" /></div>]]></content:encoded>
			<wfw:commentRss>http://videogameslab.wordpress.com/2009/07/28/debugging-part1/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
	
		<media:content url="http://0.gravatar.com/avatar/4bd00ab99710c6e67ef0a28c68628aad?s=96&#38;d=http%3A%2F%2F0.gravatar.com%2Favatar%2Fad516503a11cd5ca435acc9bb6523536%3Fs%3D96" medium="image">
			<media:title type="html">thinkinggamer</media:title>
		</media:content>

		<media:content url="http://videogameslab.files.wordpress.com/2009/07/072809_1416_debugging1.png" medium="image" />

		<media:content url="http://videogameslab.files.wordpress.com/2009/07/072809_1416_debugging2.png" medium="image" />

		<media:content url="http://videogameslab.files.wordpress.com/2009/07/072809_1416_debugging3.png" medium="image" />

		<media:content url="http://videogameslab.files.wordpress.com/2009/07/072809_1416_debugging4.png" medium="image" />

		<media:content url="http://videogameslab.files.wordpress.com/2009/07/072809_1416_debugging5.png" medium="image" />

		<media:content url="http://videogameslab.files.wordpress.com/2009/07/072809_1416_debugging6.png" medium="image" />
	</item>
		<item>
		<title>Εισαγωγή στη C#/.NET μέρος 3ο</title>
		<link>http://videogameslab.wordpress.com/2009/06/29/intro-csharp-part3/</link>
		<comments>http://videogameslab.wordpress.com/2009/06/29/intro-csharp-part3/#comments</comments>
		<pubDate>Mon, 29 Jun 2009 07:22:08 +0000</pubDate>
		<dc:creator>Κώστας Αναγνώστου</dc:creator>
				<category><![CDATA[.NET]]></category>
		<category><![CDATA[C#]]></category>
		<category><![CDATA[Προγραμματισμός]]></category>

		<guid isPermaLink="false">http://videogameslab.wordpress.com/?p=192</guid>
		<description><![CDATA[Είχαμε ξεκινήσει σε προηγούμενα άρθρα μια εισαγωγή στην C# και στο .NET ως υπόβαθρο για την μετέπειτα χρήση του XNA Game Studio. Αρκετούς μήνες μετά συνεχίζουμε την περιήγηση μας στο κόσμο της C#.

Στο προηγούμενο άρθρο ως γνωριμία με την C# και το περιβάλλον του Visual C# Express 2008, είχαμε δημιουργήσει ένα απλό πρόγραμμα που εμφάνιζε [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=videogameslab.wordpress.com&blog=5040448&post=192&subd=videogameslab&ref=&feed=1" />]]></description>
			<content:encoded><![CDATA[<div class='snap_preview'><br /><p><span style="font-family:Verdana;font-size:9pt;">Είχαμε ξεκινήσει σε <a href="http://videogameslab.wordpress.com/2009/01/08/intro-csharp-net/" target="_blank">προηγούμενα</a> <a href="http://videogameslab.wordpress.com/2009/01/09/intro-csharp-part2/" target="_blank">άρθρα </a>μια εισαγωγή στην C# και στο .NET ως υπόβαθρο για την μετέπειτα χρήση του XNA Game Studio. Αρκετούς μήνες μετά συνεχίζουμε την περιήγηση μας στο κόσμο της C#.<br />
</span></p>
<p><span style="font-family:Verdana;font-size:9pt;">Στο <a href="http://videogameslab.wordpress.com/2009/01/09/intro-csharp-part2/" target="_blank">προηγούμενο άρθρο</a> ως γνωριμία με την C# και το περιβάλλον του Visual C# Express 2008, είχαμε δημιουργήσει ένα απλό πρόγραμμα που εμφάνιζε μια πρόταση σε ένα παράθυρο. Σήμερα συνεχίζουμε με το πώς αναπαριστά και διαχειρίζεται η C# δεδομένα. Σκοπός αυτού του άρθρου δεν είναι η πλήρης και εξονυχιστική παρουσίαση της γλώσσας, μιας και κάτι τέτοιο θα μπορούσε να γίνει μόνο στα πλαίσια ενός βιβλίου.<br />
</span></p>
<p><span style="font-family:Verdana;font-size:9pt;">Σε γενικές γραμμές η C#, όσον αφορά τις μεταβλητές και τους τύπους δεδομένων της, δεν διαφέρει δραματικά από γλώσσες όπως η Java και η C++. Κάποιος με εμπειρία σε άλλες (σχετικά σύγχρονες) γλώσσες θα βρεθεί σε ένα οικείο περιβάλλον κατά την ανάπτυξη ενός προγράμματος σε C#. Ξεκινάμε με μια γρήγορη ανασκόπηση των τύπων δεδομένων που υποστηρίζει η C#.</span></p>
<p><span style="font-family:Verdana;font-size:9pt;"><span id="more-192"></span></span><span style="font-family:Verdana;font-size:9pt;"><strong>Μεταβλητές<br />
</strong></span></p>
<p><span style="font-family:Verdana;font-size:9pt;">Η C# υποστηρίζει τους παραδοσιακούς τύπους δεδομένων όπως <strong>int</strong> για ακέραιους αριθμούς, <strong>float</strong> για αριθμούς κινητής υποδιαστολής, <strong>string</strong> για κείμενο, <strong>char</strong> για χαρακτήρες. Επιπλέον υποστηρίζει του τύπους <strong>class</strong> και <strong>struct </strong>οι οποίοι επιτρέπουν στο χρήστη να ορίσει δικά του αντικείμενα.<br />
</span></p>
<p><span style="font-family:Verdana;font-size:9pt;">Ο παρακάτω πίνακας περιλαμβάνει τους πιο κοινούς τύπους δεδομένων που χρησιμοποιούμε κατά το προγραμματισμό με C#<br />
</span></p>
<div>
<table style="border-collapse:collapse;" border="0">
<col></col>
<col></col>
<col></col>
<tbody>
<tr>
<td style="padding-left:7px;padding-right:7px;border-top:solid black .5pt;border-left:solid black .5pt;border-bottom:solid black .5pt;border-right:solid black .5pt;"><span style="font-family:Courier New;font-size:8pt;"><strong>Τύπος</strong></span></td>
<td style="padding-left:7px;padding-right:7px;border-top:solid black .5pt;border-left:none;border-bottom:solid black .5pt;border-right:solid black .5pt;"><span style="font-family:Courier New;font-size:8pt;"><strong>Δεδομένα</strong></span></td>
<td style="padding-left:7px;padding-right:7px;border-top:solid black .5pt;border-left:none;border-bottom:solid black .5pt;border-right:solid black .5pt;"><span style="font-family:Courier New;font-size:8pt;"><strong>Παράδειγμα χρήσης</strong></span></td>
</tr>
<tr>
<td style="padding-left:7px;padding-right:7px;border-top:none;border-left:solid black .5pt;border-bottom:solid black .5pt;border-right:solid black .5pt;"><span style="font-family:Courier New;font-size:8pt;">bool</span></td>
<td style="padding-left:7px;padding-right:7px;border-top:none;border-left:none;border-bottom:solid black .5pt;border-right:solid black .5pt;"><span style="font-family:Courier New;font-size:8pt;">true ή false</span></td>
<td style="padding-left:7px;padding-right:7px;border-top:none;border-left:none;border-bottom:solid black .5pt;border-right:solid black .5pt;"><span style="font-family:Courier New;font-size:8pt;">bool isRaining = false; </span></td>
</tr>
<tr>
<td style="padding-left:7px;padding-right:7px;border-top:none;border-left:solid black .5pt;border-bottom:solid black .5pt;border-right:solid black .5pt;"><span style="font-family:Courier New;font-size:8pt;">byte</span></td>
<td style="padding-left:7px;padding-right:7px;border-top:none;border-left:none;border-bottom:solid black .5pt;border-right:solid black .5pt;"><span style="font-family:Courier New;font-size:8pt;">Ακέραιος αριθμός από 0 μέχρι 255</span></td>
<td style="padding-left:7px;padding-right:7px;border-top:none;border-left:none;border-bottom:solid black .5pt;border-right:solid black .5pt;"><span style="font-family:Courier New;font-size:8pt;">byte counter=4; </span></td>
</tr>
<tr>
<td style="padding-left:7px;padding-right:7px;border-top:none;border-left:solid black .5pt;border-bottom:solid black .5pt;border-right:solid black .5pt;"><span style="font-family:Courier New;font-size:8pt;">short</span></td>
<td style="padding-left:7px;padding-right:7px;border-top:none;border-left:none;border-bottom:solid black .5pt;border-right:solid black .5pt;"><span style="font-family:Courier New;font-size:8pt;">Ακέραιος αριθμός από –32,768 μέχρι 32,767</span></td>
<td style="padding-left:7px;padding-right:7px;border-top:none;border-left:none;border-bottom:solid black .5pt;border-right:solid black .5pt;"><span style="font-family:Courier New;font-size:8pt;">short myNumber = -3442;</span></td>
</tr>
<tr>
<td style="padding-left:7px;padding-right:7px;border-top:none;border-left:solid black .5pt;border-bottom:solid black .5pt;border-right:solid black .5pt;"><span style="font-family:Courier New;font-size:8pt;">int</span></td>
<td style="padding-left:7px;padding-right:7px;border-top:none;border-left:none;border-bottom:solid black .5pt;border-right:solid black .5pt;"><span style="font-family:Courier New;font-size:8pt;">Ακέραιος αριθμός 32 bit</span></td>
<td style="padding-left:7px;padding-right:7px;border-top:none;border-left:none;border-bottom:solid black .5pt;border-right:solid black .5pt;"><span style="font-family:Courier New;font-size:8pt;">int largeNumber = 1234223;</span></td>
</tr>
<tr>
<td style="padding-left:7px;padding-right:7px;border-top:none;border-left:solid black .5pt;border-bottom:solid black .5pt;border-right:solid black .5pt;"><span style="font-family:Courier New;font-size:8pt;">double</span></td>
<td style="padding-left:7px;padding-right:7px;border-top:none;border-left:none;border-bottom:solid black .5pt;border-right:solid black .5pt;"><span style="font-family:Courier New;font-size:8pt;">Αριθμός κινητής υποδιαστολής μεγάλης ακρίβειας</span></td>
<td style="padding-left:7px;padding-right:7px;border-top:none;border-left:none;border-bottom:solid black .5pt;border-right:solid black .5pt;"><span style="font-family:Courier New;font-size:8pt;">double stockValue = 2342.23332; </span></td>
</tr>
<tr>
<td style="padding-left:7px;padding-right:7px;border-top:none;border-left:solid black .5pt;border-bottom:solid black .5pt;border-right:solid black .5pt;"><span style="font-family:Courier New;font-size:8pt;">float</span></td>
<td style="padding-left:7px;padding-right:7px;border-top:none;border-left:none;border-bottom:solid black .5pt;border-right:solid black .5pt;"><span style="font-family:Courier New;font-size:8pt;">Αριθμός κινητής υποδιαστολής</span></td>
<td style="padding-left:7px;padding-right:7px;border-top:none;border-left:none;border-bottom:solid black .5pt;border-right:solid black .5pt;"><span style="font-family:Courier New;font-size:8pt;">float exchangeRate = 233.23f;</span></td>
</tr>
<tr>
<td style="padding-left:7px;padding-right:7px;border-top:none;border-left:solid black .5pt;border-bottom:solid black .5pt;border-right:solid black .5pt;"><span style="font-family:Courier New;font-size:8pt;">char</span></td>
<td style="padding-left:7px;padding-right:7px;border-top:none;border-left:none;border-bottom:solid black .5pt;border-right:solid black .5pt;"><span style="font-family:Courier New;font-size:8pt;">Χαρακτήρας ASCII 8 bit</span></td>
<td style="padding-left:7px;padding-right:7px;border-top:none;border-left:none;border-bottom:solid black .5pt;border-right:solid black .5pt;"><span style="font-family:Courier New;font-size:8pt;">char myChar = &#8216;a&#8217;;</span></td>
</tr>
<tr>
<td style="padding-left:7px;padding-right:7px;border-top:none;border-left:solid black .5pt;border-bottom:solid black .5pt;border-right:solid black .5pt;"><span style="font-family:Courier New;font-size:8pt;">string</span></td>
<td style="padding-left:7px;padding-right:7px;border-top:none;border-left:none;border-bottom:solid black .5pt;border-right:solid black .5pt;"><span style="font-family:Courier New;font-size:8pt;">Κείμενο</span></td>
<td style="padding-left:7px;padding-right:7px;border-top:none;border-left:none;border-bottom:solid black .5pt;border-right:solid black .5pt;"><span style="font-family:Courier New;font-size:8pt;">string username = &#8220;Kostas&#8221;; </span></td>
</tr>
</tbody>
</table>
</div>
<p><span style="font-family:Verdana;font-size:9pt;">Μερικές παρατηρήσεις πάνω στους τύπους δεδομένων: Οι τύποι short και int έχουν παρόμοια χρήση, μόνο που ο int έχει μεγαλύτερο εύρος, δηλαδή μπορεί να αποθηκεύσει μεγαλύτερο εύρος (περισσότερους) αριθμούς από ότι ο short. Αυτό συμβαίνει γιατί μια μεταβλητής τύπου <strong>short</strong> χρησιμοποιεί 16 bit στην μνήμη ενώ μια <strong>int</strong> 32 bit. Το ίδιο ισχύει για τους τύπους <strong>float</strong> (32bit) και <strong>double</strong> (64bit). Ο χαρακτήρας f στο τέλος του αριθμού στο παράδειγμα για το τύπο float σηματοδοτεί ότι ο αριθμός αυτός είναι πράγματι τύπου float (και συνεπώς απαιτεί λιγότερο χώρο για να αποθηκευτεί). Τέλος ένας χαρακτήρας (char) ορίζεται με μονά εισαγωγικά και ένα κείμενο (string) με διπλά.<br />
</span></p>
<p><span style="font-family:Verdana;font-size:9pt;"><strong>Class και αντικείμενα<br />
</strong></span></p>
<p><span style="font-family:Verdana;font-size:9pt;">Πέρα από αυτούς τους βασικούς τύπους δεδομένων, η C# υποστηρίζει και το τύπο <strong>class</strong>. H <strong>class</strong> μας επιτρέπει να ορίσουμε δικά μας αντικείμενα. Εν συντομία για όσους δεν γνωρίζουν τι είναι, ένα αντικείμενο σε μια αντικειμενοστραφή γλώσσα προγραμματισμού (όπως η C#, C++, Java κλπ), είναι μια οντότητα που χαρακτηρίζεται από δεδομένα και συμπεριφορά. Τα αντικείμενα αυτά έχουν άμεση αντιστοίχιση με αντικείμενα του πραγματικού κόσμου. Για παράδειγμα ένα αυτοκίνητο σε ένα παιχνίδι αγώνων ράλι χαρακτηρίζεται από το χρώμα του, το πόσες πόρτες έχει, την ταχύτητα του, την κατεύθυνση του, αν έχει ταχύτητες ή είναι αυτόματο, το ποσοστό ζημίας από τρακαρίσματα που έχει υποστεί. Αυτά είναι τα δεδομένα που περιγράφουν το αντικείμενο του αυτοκινήτου. Επιπλέον μπορούμε να ορίσουμε και κάποιες «λειτουργίες» που επιδρούν και διαχειρίζονται τα δεδομένα αυτά. Μια λειτουργία θα μπορούσε να είναι η «αλλαγή ταχύτητας». Μια άλλη «πάτημα γκαζιού». Οι λειτουργίες αυτές αλλάζουν τις τιμές των δεδομένων του αντικειμένου.<br />
</span></p>
<p><span style="font-family:Verdana;font-size:9pt;">Στην C# το αντικείμενο του αυτοκινήτου μεταφέρεται ως</span></p>
<pre class="brush: csharp;">
class Car
{
    private float speed;
    private int gear;

    public Car()
    {
        speed = 0;
        gear = 0;
    }

    public void IncreaseSpeed(float amount)
    {
        speed = speed + amount;
    }

    public void DecreaseSpeed(float amount)
    {
        speed = speed - amount;
    }

    public void ChangeGear(int newGear)
    {
        gear = newGear;
    }
}
</pre>
<p><span style="font-family:Verdana;font-size:9pt;">Με το τρόπο αυτό ορίζουμε ένα νέο τύπο δεδομένων, το αντικείμενο Car το οποίο περιγράφει με απλοϊκό τρόπο μια οντότητα αυτοκινήτου και διάφορες λειτουργίες πάνω σε αυτό (με επίσης απλοϊκό τρόπο). To αντικείμενο περιλαμβάνει 2 μεταβλητές speed και gear περιέχουν την τρέχουσα ταχύτητα και ταχύτητα (δεν είναι φοβερά τα νέο-ελληνικά όσον αφορά τους τεχνολογικούς όρους;) του αυτοκινήτου, συναρτήσεις (μεθόδους) για αύξηση και μείωση της ταχύτητας και μια ειδική μέθοδο (Car()) τη οποίας την ύπαρξη θα εξηγήσω σε λίγο.<br />
</span></p>
<p><span style="font-family:Verdana;font-size:9pt;">Για να ορίσουμε ένα αυτοκίνητο με βάση το πρότυπο αυτό το δηλώνουμε ως εξής:<br />
</span></p>
<pre class="brush: csharp;">
Car audiQuattro;
</pre>
<p><span style="font-family:Verdana;font-size:9pt;">Η παραπάνω δήλωση δημιουργεί μια μεταβλητή τύπου Car, αλλά δεν δεσμεύει μνήμη για το αντικείμενο αυτό καθ&#8217;αυτό. Αυτό πρέπει να γίνει ως εξής:<br />
</span></p>
<pre class="brush: csharp;">
audiQuattro = new Car();
</pre>
<p><span style="font-family:Verdana;font-size:9pt;">Ο τελεστής new δεσμεύει όση ακριβώς μνήμη χρειάζεται για να αποθηκευτεί ένα αντικείμενο τύπου Car. Το audiQuattro είναι τώρα ένα νέο αντικείμενο τύπου Car. Για να αλλάξω τις ιδιότητες (μεταβλητές) του νέου αυτοκινήτου καλώ απλά τις μεθόδους του:<br />
</span></p>
<pre class="brush: csharp;">
audiQuattro.ChangeGear(1);
audiQuattro.IncreaseSpeed(20);
</pre>
<p><span style="font-family:Verdana;font-size:9pt;">Παρατηρούμε ότι οι μεταβλητές δηλώνονται ως private και οι μέθοδοι ως public. Σε ένα αντικείμενο, οτιδήποτε δηλώνεται ως private δεν είναι ορατό και προσπελάσιμο εκτός του αντικειμένου. Αντίθετα, οτιδήποτε δηλώνουμε ως public είναι. Για παράδειγμα η παρακάτω χρήση δεν είναι επιτρεπτή:<br />
</span></p>
<pre class="brush: csharp;">
audiQuattro.speed = 15.0f;
</pre>
<p><span style="font-family:Verdana;font-size:9pt;">Αυτό συμβαίνει γιατί η speed έχει δηλωθεί ως private. Ο μεταγλωττιστής της C# δεν θα επιτρέψει την ολοκλήρωση της δημιουργίας του εκτελέσιμου κώδικα και θα επισημάνει το λάθος.<br />
</span></p>
<p><span style="font-family:Verdana;font-size:9pt;">Ο χαρακτηρισμός private/public δεν ανήκει αποκλειστικά σε μεταβλητές/μέθοδους αλλά σε οτιδήποτε περιέχει ένα αντικείμενο. Θα μπορούσε για παράδειγμα η μεταβλητή speed να είναι public.<br />
</span></p>
<p><span style="font-family:Verdana;font-size:9pt;">Τέλος θέλω να αναφερθώ στη μέθοδο <strong>Car()</strong>. Η μέθοδος αυτή, που έχει πάντα το ίδιο όνομα με το <strong>class</strong> που τη περιέχει ονομάζεται <strong>constructor</strong> και καλείται <strong>πάντα</strong> όταν δεσμεύουμε μνήμη για ένα αντικείμενο του αντίστοιχου τύπου με τη χρήση του τελεστή <strong>new</strong>. Σκοπός της είναι η αρχικοποίηση του αντικειμένου δίνοντας για παράδειγμα κάποια αρχική τιμή στις μεταβλητές του. Στο συγκεκριμένο παράδειγμα τη χρησιμοποιούμε για να θέσουμε αρχικές τιμές 0 στις μεταβλητές speed και gear (κάτι που δεν είναι απολύτως απαραίτητο, καθώς γίνεται αυτόματα όπως θα δούμε σε άλλο άρθρο).<br />
</span></p>
<p><span style="font-family:Verdana;font-size:9pt;">Εκτός της <strong>class</strong>, η C# υποστηρίζει τη δημιουργία νέων τύπων δεδομένων με τη χρήση της <strong>struct</strong>. Η <strong>struct</strong> είναι παρόμοια σε χρήση με τη <strong>class</strong>, διαφέρει όμως σε μερικά σημεία τα οποία θα αναλύσουμε σε επόμενο άρθρο.<br />
</span></p>
<p><span style="font-family:Verdana;font-size:9pt;">Ανακεφαλαιώνοντας, η C# υποστηρίζει βασικούς τύπους δεδομένων (primitive types), όπως ο <strong>int</strong>, <strong>short</strong>, <strong>char</strong> κλπ, και πιο σύνθετους όπως η <strong>class </strong>(reference types). Μια βασική διαφορά τους είναι ότι ένα βασικό τύπο μπορώ να τον ορίσω απευθείας:<br />
</span></p>
<pre class="brush: csharp;">
int value = 22;
</pre>
<p><span style="font-family:Verdana;font-size:9pt;">ενώ ένα πιο σύνθετο τύπου (class) πρέπει να χρησιμοποιήσω το τελεστή new για να δεσμεύσω μνήμη για αυτό:<br />
</span></p>
<pre class="brush: csharp;">
Car fiat = new Car();
</pre>
<p><span style="font-family:Verdana;font-size:9pt;">Αυτή η διαφορά έχει μεγάλη επίπτωση στη χρήση τους και σε τι είδους μνήμη αποθηκεύονται, κάτι που έχει με την σειρά του επίπτωση στην ανάπτυξη βιντεοπαιχνιδιών με το XNA Game Studio.<br />
</span></p>
<p><span style="font-family:Verdana;font-size:9pt;">Η σύντομη αυτή αναφορά στους τύπους δεδομένων της C# μόλις που άγγιξε την επιφάνεια. Στο επόμενο άρθρο θα συνεχίσουμε με τους τύπους δεδομένων και τα διάφορα είδη μνήμης που χρησιμοποιεί το .NET.<br />
</span></p>
<p><span style="font-family:Verdana;font-size:9pt;">Αν κάποιος αναγνώστης δεν κατανόησε κάτι που συζητήσαμε στο άρθρο αυτό και επιθυμεί επιπλέον εξήγηση ας το αναφέρει στα σχόλια.<br />
</span></p>
  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/videogameslab.wordpress.com/192/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/videogameslab.wordpress.com/192/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/videogameslab.wordpress.com/192/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/videogameslab.wordpress.com/192/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/videogameslab.wordpress.com/192/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/videogameslab.wordpress.com/192/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/videogameslab.wordpress.com/192/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/videogameslab.wordpress.com/192/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/videogameslab.wordpress.com/192/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/videogameslab.wordpress.com/192/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=videogameslab.wordpress.com&blog=5040448&post=192&subd=videogameslab&ref=&feed=1" /></div>]]></content:encoded>
			<wfw:commentRss>http://videogameslab.wordpress.com/2009/06/29/intro-csharp-part3/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
	
		<media:content url="http://0.gravatar.com/avatar/4bd00ab99710c6e67ef0a28c68628aad?s=96&#38;d=http%3A%2F%2F0.gravatar.com%2Favatar%2Fad516503a11cd5ca435acc9bb6523536%3Fs%3D96" medium="image">
			<media:title type="html">thinkinggamer</media:title>
		</media:content>
	</item>
		<item>
		<title>Dream Build Play 2009</title>
		<link>http://videogameslab.wordpress.com/2009/05/14/dream-build-play-2009/</link>
		<comments>http://videogameslab.wordpress.com/2009/05/14/dream-build-play-2009/#comments</comments>
		<pubDate>Thu, 14 May 2009 18:29:35 +0000</pubDate>
		<dc:creator>Κώστας Αναγνώστου</dc:creator>
				<category><![CDATA[.NET]]></category>
		<category><![CDATA[C#]]></category>
		<category><![CDATA[XNA Game Studio]]></category>
		<category><![CDATA[Ανάπτυξη βιντεοπαιχνιδιών]]></category>

		<guid isPermaLink="false">http://videogameslab.wordpress.com/?p=190</guid>
		<description><![CDATA[Η άκρα του τάφου σιωπή συνεχίζεται εδώ γύρω… Διάφορες υποχρεώσεις και πολλή δουλειά στο πανεπιστήμιο μειώνουν δραματικά το διαθέσιμο χρόνο. Όμως το blog θα επανέρθει δυναμικά σύντομα.
Μέχρι τότε μπορείτε να απασχοληθείτε με το διαγωνισμό Dream Build Play 2009 της Microsoft. Πρόκειται για διαγωνισμό ανάπτυξης βιντεοπαιχνιδιού στην πλατφόρμα XNA Game Studio με χρηματικό έπαθλο. Είναι διεθνής [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=videogameslab.wordpress.com&blog=5040448&post=190&subd=videogameslab&ref=&feed=1" />]]></description>
			<content:encoded><![CDATA[<div class='snap_preview'><br /><p>Η άκρα του τάφου σιωπή συνεχίζεται εδώ γύρω… Διάφορες υποχρεώσεις και πολλή δουλειά στο πανεπιστήμιο μειώνουν δραματικά το διαθέσιμο χρόνο. Όμως το blog θα επανέρθει δυναμικά σύντομα.</p>
<p>Μέχρι τότε μπορείτε να απασχοληθείτε με το διαγωνισμό <a href="http://www.dreambuildplay.com/main/default.aspx" target="_blank">Dream Build Play 2009</a> της Microsoft. Πρόκειται για διαγωνισμό ανάπτυξης βιντεοπαιχνιδιού στην πλατφόρμα XNA Game Studio με χρηματικό έπαθλο. Είναι διεθνής διαγωνισμός και ανοικτός και σε Έλληνες. Πέρυσι έλαβε 350 συμμετοχές από 100 χώρες.</p>
<p>Περισσότερο από όλα μετράει η καινοτομία και η ψυχαγωγική αξία του παιχνιδιού και όχι απαραίτητα τα εντυπωσιακά και τριδιάστατα γραφικά. Απόδειξη αποτελεί το γεγονός ότι πέρυσι το πρώτο βραβείο δόθηκε σε ένα 2διάστατο παιχνίδι, το <a href="http://www.1up.com/do/newsStory?cId=3171019" target="_blank">CarnyVale: Showtime</a>.</p>
<p>Μια καλή ιδέα μπορεί να έχει ο οποιοσδήποτε, οπότε αξίζει να συμμετάσχετε!</p>
  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/videogameslab.wordpress.com/190/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/videogameslab.wordpress.com/190/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/videogameslab.wordpress.com/190/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/videogameslab.wordpress.com/190/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/videogameslab.wordpress.com/190/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/videogameslab.wordpress.com/190/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/videogameslab.wordpress.com/190/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/videogameslab.wordpress.com/190/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/videogameslab.wordpress.com/190/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/videogameslab.wordpress.com/190/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=videogameslab.wordpress.com&blog=5040448&post=190&subd=videogameslab&ref=&feed=1" /></div>]]></content:encoded>
			<wfw:commentRss>http://videogameslab.wordpress.com/2009/05/14/dream-build-play-2009/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
	
		<media:content url="http://0.gravatar.com/avatar/4bd00ab99710c6e67ef0a28c68628aad?s=96&#38;d=http%3A%2F%2F0.gravatar.com%2Favatar%2Fad516503a11cd5ca435acc9bb6523536%3Fs%3D96" medium="image">
			<media:title type="html">thinkinggamer</media:title>
		</media:content>
	</item>
	</channel>
</rss>