<?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; XNA Game Studio</title>
	<atom:link href="http://videogameslab.wordpress.com/category/xna-game-studio/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; XNA Game Studio</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>Arkanoid: Σχεδιασμός πίστας</title>
		<link>http://videogameslab.wordpress.com/2009/12/07/arkanoid-level-design/</link>
		<comments>http://videogameslab.wordpress.com/2009/12/07/arkanoid-level-design/#comments</comments>
		<pubDate>Mon, 07 Dec 2009 08:02:23 +0000</pubDate>
		<dc:creator>Κώστας Αναγνώστου</dc:creator>
				<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=473</guid>
		<description><![CDATA[Κοιτάζοντας το πότε ανέβασα το τελευταίο άρθρο στο blog διαπιστώνω ότι έχει περάσει πάνω από ένας μήνας! Ακόμα περισσότερο έχουμε να ασχοληθούμε με το Arkanoid. Ήταν δύσκολες οι προηγούμενες εβδομάδες στο Πανεπιστήμιο με τις προθεσμίες για προτάσεις χρηματοδότησης και άρθρα  σε περιοδικά να διαδέχονται η μία την άλλη. Και ενώ είχα γράψει το κώδικα [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=videogameslab.wordpress.com&blog=5040448&post=473&subd=videogameslab&ref=&feed=1" />]]></description>
			<content:encoded><![CDATA[<div class='snap_preview'><br /><p><span style="font-family:Verdana;font-size:9pt;">Κοιτάζοντας το πότε ανέβασα το τελευταίο άρθρο στο blog διαπιστώνω ότι έχει περάσει πάνω από ένας μήνας! Ακόμα περισσότερο έχουμε να ασχοληθούμε με το Arkanoid. Ήταν δύσκολες οι προηγούμενες εβδομάδες στο Πανεπιστήμιο με τις προθεσμίες για προτάσεις χρηματοδότησης και άρθρα  σε περιοδικά να διαδέχονται η μία την άλλη. Και ενώ είχα γράψει το κώδικα για το σχεδιασμό πίστας στο Arkanoid δεν έβρισκα το χρόνο να γράψω το κείμενο. Τώρα όμως χαλάρωσαν λίγο τα πράγματα και επανερχόμαστε στην ενεργό δράση!<br />
</span></p>
<p><span style="font-family:Verdana;font-size:9pt;">Είχαμε αφήσει το Arkanoid σε μια σχετικά πλήρη μορφή με <a href="http://videogameslab.wordpress.com/category/arkanoid/" target="_blank">ανίχνευση συγκρούσεων, κίνηση μπάλας και ρακέτας, καταγραφή σκορ και απώλειας ζωής του παίκτη</a>. Επιπλέον είχαμε υλοποιήσει game state management με τις διάφορες οθόνες και καταστάσεις του παιχνιδιού (εισαγωγή, παιχνίδι, παύση, νίκη και αποτυχία παίκτη). Αυτό που λείπει είναι η δυνατότητα να σχεδιάζουμε τη πίστα του παιχνιδιού με περισσότερο φιλικό και εύχρηστο τρόπο, καθώς και η προσθήκη πολλών επιπέδων στο παιχνίδι.</span><br />
<span id="more-473"></span><br />
<span style="font-family:Verdana;font-size:9pt;">Μέχρι στιγμής στο Arkanoid χρησιμοποιούμε το παρακάτω κώδικα για να σχεδιάσουμε τη πίστα και να τοποθετήσουμε τα τουβλάκια στην οθόνη:<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;">Στο <a href="http://videogameslab.wordpress.com/2009/10/29/videogames-laboratory-challenge-2/" target="_blank">2<sup>ο</sup> Videogames Laboratory Challenge</a> είχα ζητήσει από τους αναγνώστες του blog να προτείνουν βελτιώσεις στο τρόπο αυτό σχεδιασμού της πίστας. Προτάθηκαν διάφορες λύσεις, από εύκολες, όπως να διαβάζουμε τις θέσεις των τούβλων από αρχείο μέχρι πιο πολύπλοκες, όπως ένα εξειδικευμένο πρόγραμμα που να επιτρέπει το σχεδιασμό της πίστας με οπτικό τρόπο (visual editor). Στα πλαίσια του άρθρου θα υλοποιήσουμε την απλούστερη λύση, δηλαδή να διαβάζει το παιχνίδι τη θέση των τούβλων από αρχείο. Στο μέλλον θα κάνουμε μια παρουσίαση πιο ολοκληρωμένων προτάσεων που βασίζονται σε editor.<br />
</span></p>
<p><span style="font-family:Verdana;font-size:9pt;">Δεν είναι πολλές οι αλλαγές που πρέπει να κάνουμε στον υπάρχοντα κώδικα για να υλοποιήσουμε τη λειτουργία αυτή. Καταρχάς πρέπει να καθορίσουμε τη μορφή και το περιεχόμενο του αρχείου κειμένου που θα περιέχει το σχέδιο της πίστας. Κάνουμε τις εξής παραδοχές:<br />
</span></p>
<ul>
<li><span style="font-family:Verdana;font-size:9pt;">Μια γραμμή κειμένου στο αρχείο θα αντιστοιχεί σε μια γραμμή τούβλων στην οθόνη<br />
</span></li>
<li><span style="font-family:Verdana;font-size:9pt;">Οι γραμμές τούβλων στην οθόνη αρχίζουν από το πάνω μέρος (Υ=0)<br />
</span></li>
<li><span style="font-family:Verdana;font-size:9pt;">Χρησιμοποιούμε τους χαρακτήρες R, G, B, Y, W για να δηλώσουμε τη θέση τούβλων χρώματος κόκκινο, πράσινο, μπλε, κίτρινο και άσπρο<br />
</span></li>
<li><span style="font-family:Verdana;font-size:9pt;">Ο χαρακτήρας &#8216;.&#8217; υποδηλώνει κενό τούβλο<br />
</span></li>
<li><span style="font-family:Verdana;font-size:9pt;">Οι γραμμές κειμένου στο αρχείο πρέπει να έχουν όλες το ίδιο μέγεθος<br />
</span></li>
</ul>
<p><span style="font-family:Verdana;font-size:9pt;">Με βάση τις παραδοχές αυτές το αρχείο που περιγράφει μια πίστα στο παιχνίδι θα μπορούσε να είναι:<br />
</span></p>
<p><span style="font-family:Courier New;font-size:10pt;">&#8230;&#8230;&#8230;&#8230;.</span><br />
<span style="font-family:Courier New;font-size:10pt;">&#8230;&#8230;&#8230;&#8230;.</span><br />
<span style="font-family:Courier New;font-size:10pt;">..RRRRRRRRR..</span><br />
<span style="font-family:Courier New;font-size:10pt;">..GGGGGGGGG..</span><br />
<span style="font-family:Courier New;font-size:10pt;">&#8230;.BBBBB&#8230;.</span><br />
<span style="font-family:Courier New;font-size:10pt;">..BYBBBBBYB..</span><br />
<span style="font-family:Courier New;font-size:10pt;">..YY&#8230;..YY..</span><br />
<span style="font-family:Courier New;font-size:10pt;">..GGGGGGGGG..</span></p>
<p><span style="font-family:Verdana;font-size:9pt;">Θα αφήσουμε ελεύθερο τον αριθμό των τούβλων σε μια γραμμή (επιλογή σχεδιαστή) και θα προσαρμόζουμε το πλάτος του κάθε τούβλου ανάλογα. Με κάποιο πρόγραμμα επεξεργασίας κειμένου (καλύτερη επιλογή μάλλον το Notepad), φτιάχνουμε ένα αρχείο με το όνομα Level01.txt και σχεδιάζουμε τη πίστα με τις παραπάνω προδιαγραφές. Μπορείτε να κάνετε copy-paste το παραπάνω σχέδιο επίσης. Προσοχή, το αρχείο πρέπει να είναι απλό ASCII και όχι κάποιο άλλο format.<br />
</span></p>
<p><span style="font-family:Verdana;font-size:9pt;">Στην συνέχεια, στο Content project του Arkanoid, επιλέγουμε δεξί-κλικ Add/Existing Item και επιλέγουμε το Level01.txt. Όταν το αρχείο εμφανιστεί στη λίστα του Content κάνουμε δεξί κλικ και επιλέγουμε Properties από το μενού. Στις ιδιότητες του αρχείου αυτού επιλέγουμε <strong>Build Action: None</strong> και <strong>Copy to Output: Copy if newer</strong>.<br />
</span></p>
<p><img src="http://videogameslab.files.wordpress.com/2009/12/120709_0802_arkanoid1.png" alt="" /><span style="font-family:Verdana;font-size:9pt;"><br />
</span></p>
<p><span style="font-family:Verdana;font-size:9pt;">Ο λόγος που το κάνουμε αυτό είναι γιατί δεν θέλουμε να επεξεργαστεί το αρχείο αυτό το Content Pipeline του XNA, το οποίο θα του αλλάξει μορφοποίηση και θα συμπιέσει το περιεχόμενο του. Το θέλουμε ως απλό αρχείο κειμένου για να το διαβάσουμε κατά την αρχικοποίηση του παιχνιδιού. Είμαστε έτοιμη να φορτώσουμε το αρχείο με το σχέδιο πίστας.<br />
</span></p>
<p><span style="font-family:Verdana;font-size:9pt;">Θα κάνουμε αρχικά μερικές μικρές αλλαγές στο κώδικα. Καταρχάς θα χρησιμοποιήσουμε ένα List για να αποθηκεύσουμε στη μνήμη τα τουβλάκια και όχι ένα πίνακα. Οι διαφορές μεταξύ των δύο είναι μικρές όσον αφορά τη λειτουργικότητα. Στην περίπτωση μας βολεύει η List γιατί δεν απαιτεί να ορίσω το μέγεθος της εκ των προτέρων όπως πρέπει σε ένα πίνακα. Μπορεί να δεσμεύσει περισσότερη μνήμη μόνη της αν χρειαστεί σύμφωνα με τον αριθμό των τούβλων που ορίζει το αρχείο.<br />
</span></p>
<pre class="brush: csharp;">
    public class Game1 : Microsoft.Xna.Framework.Game
    {
//υπόλοιπος κωδικας
        List&lt;string&gt; lines;
        List&lt;Brick&gt; bricks;
</pre>
<p><span style="font-family:Verdana;font-size:9pt;">Στην αρχή της κλάσης Game1 ορίζω 2 μεταβλητές List μια για τις γραμμές κειμένου του αρχείου (lines) και μια για τα τουβλάκια που θα αποθηκεύσω στη μνήμη. Στην Initialize(), δημιουργώ τα αντίστοιχα αντικείμενα List για τα lines και bricks. Οι λίστες είναι κενές σε αυτό το σημείο.<br />
</span></p>
<pre class="brush: csharp;">
        protected override void Initialize()
        {
		//υπόλοιπος κωδικας
            lines = new List&lt;string&gt;();
            bricks = new List&lt;Brick&gt;();

            base.Initialize();
        }
</pre>
<p><span style="font-family:Verdana;font-size:9pt;">Το αρχείο θα το διαβάσουμε στην LoadContent, όπως όλα τα αρχεία περιεχομένου (τεχνικά δεν χρειάζεται εδώ αλλά είναι καλή πρακτική).<br />
</span></p>
<pre class="brush: csharp;">
        protected override void LoadContent()
        {
		//υπόλοιπος κωδικας

            string path = Path.Combine(StorageContainer.TitleLocation, &quot;Content/Level01.txt&quot;);

            StreamReader reader = new StreamReader(path);
            string line = reader.ReadLine();
            while (line != null)
            {
                lines.Add(line);
                line = reader.ReadLine();
            }
            reader.Close();
        }
</pre>
<p><span style="font-family:Verdana;font-size:9pt;">Καταρχάς συνθέτουμε τη διαδρομή που βρίσκεται το αρχείο level01.txt. Αυτό το κάνουμε προσθέτοντας το όνομα του αρχείου &#8220;Content/Level01.txt&#8221; στην εξορισμού τοποθεσία στην οποία αποθηκεύει το περιεχόμενο το XNA, StorageContainer.TitleLocation. Το αποτέλεσμα το κρατάμε σε μια μεταβλητή path.<br />
</span></p>
<p><span style="font-family:Verdana;font-size:9pt;">Για να φορτώσουμε ένα αρχείο με τη χρήση C#/.NET θα χρησιμοποιήσουμε ένα αντικείμενο reader τύπου StreamReader το οποίο μπορεί να διαβάσει χαρακτήρες κειμένου. Το StreamReader παίρνει ως όρισμα το (πλήρες) όνομα του αρχείου κειμένου. Στην συνέχεια διαβάζουμε το αρχείο γραμμή-γραμμή (reader.ReadLine()) και προσθέτουμε τη κάθε γραμμή στη λίστα lines. Όταν διαβάσουμε όλο το αρχείο (line==null), τότε κλείνουμε το reader καλώντας τη μέθοδο του Close(), για να αποδεσμεύσουμε τους πόρους του συστήματος. Κατά την ανάγνωση του αρχείου δεν κάνουμε καμιά προσπάθεια να εξασφαλίσουμε το ότι ο αριθμός τούβλων είναι ίδιος σε κάθε γραμμή, χάριν ευκολίας, είναι όμως κάτι το οποίο θα πρέπει να έχουμε υπόψη μας.<br />
</span></p>
<p><span style="font-family:Verdana;font-size:9pt;">Για να ολοκληρώσουμε το κώδικα πρέπει να αξιοποιήσουμε τη λίστα lines για να τοποθετήσουμε τα τουβλάκια στην οθόνη. Αυτό γίνεται στην resetGame().<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;

            bricksPerRow = lines[0].Length;
            brickWidth = (viewWidth - (bricksPerRow - 1) * brickSpacing) / bricksPerRow;

            bricks.Clear();

            for (int j = 0; j &lt; lines.Count; j++)
            {
                for (int i = 0; i &lt; lines[j].Length; i++)
                {
                    Rectangle rect = new Rectangle(i * (brickWidth + brickSpacing),
                                                   j * (brickHeight + brickSpacing),
                                                   brickWidth, brickHeight);
                    switch (lines[j][i])
                    {
                        case 'R':
                            bricks.Add(new Brick(rect, Color.Red, whiteTile));
                            break;
                        case 'G':
                            bricks.Add(new Brick(rect, Color.Green, whiteTile));
                            break;
                        case 'B':
                            bricks.Add(new Brick(rect, Color.Blue, whiteTile));
                            break;
                        case 'Y':
                            bricks.Add(new Brick(rect, Color.Yellow, whiteTile));
                            break;
                        case 'W':
                            bricks.Add(new Brick(rect, Color.White, whiteTile));
                            break;

                    }
                }
            }
            numOfVisibleBricks = bricks.Count;
        }
</pre>
<p><span style="font-family:Verdana;font-size:9pt;">Ο αριθμός των τούβλων ανά γραμμή καθορίζεται από το μήκος της πρώτης γραμμής κειμένου της λίστας list (list[0].Length). Το πλάτος κάθε τούβλου καθορίζεται τώρα με βάση αυτό. Στην συνέχεια, σε ένα διπλό for-loop, διατρέχουμε όλες τις γραμμές τις λίστας list και για κάθε γραμμή εξετάζουμε το κάθε χαρακτήρα της με ένα switch-statement. Αν ο χαρακτήρας είναι κάποιος από τους R, G, B, Y, W, τότε προσθέτουμε ένα τουβλάκι αντίστοιχου χρώματος στη λίστα bricks. Στην ουσία το αρχείο κειμένου με το σχέδιο της πίστας ουσιαστικά δημιουργεί ένα πλέγμα (grid), σε κάθε κελί του οποίου μπορεί να υπάρχει ή όχι ένα τουβλάκι. Επιπλέον το γεγονός ότι δημιουργούμε ένα Rectangle για κάθε θέση του πλέγματος, ανεξάρτητα από το αν αυτό περιέχει τουβλάκι ή όχι δεν είναι και πολύ αποδοτικό. Ο αριθμός numOfVisibleBricks τον οποίο χρησιμοποιούμε για να διαπιστώσουμε αν ο παίκτης έχει χτυπήσει όλα τα τουβλάκια στην οθόνη (μειώνοντας τον κατά ένα με κάθε σύγκρουση) είναι τώρα ίσος με τον αριθμό των τούβλων στη λίστα bricks. Τέλος μια παρατήρηση, ο χαρακτήρας &#8216;.&#8217; που θέσαμε ως κενό χαρακτήρα δεν χρησιμοποιείται στην πραγματικότητα είναι περισσότερο «οπτική διευκόλυνση» για εμάς που σχεδιάζουμε τη πίστα.<br />
</span></p>
<p><span style="font-family:Verdana;font-size:9pt;">Τρέχοντας το παιχνίδι βλέπουμε τη νέα πίστα στην οθόνη μας όπως τη σχεδιάσαμε.<br />
</span></p>
<p><img src="http://videogameslab.files.wordpress.com/2009/12/120709_0802_arkanoid2.png" alt="" /><span style="font-family:Verdana;font-size:9pt;"><br />
</span></p>
<p><span style="font-family:Verdana;font-size:9pt;">Ο κώδικας του παιχνιδιού είναι διαθέσιμος μέσω SVN από το <a href="http://code.google.com/p/videogameslab/" target="_blank">Code Repository</a> καθώς και σε <a href="http://videogameslab.googlecode.com/files/Arcanoid_part5.zip" target="_blank">zip μορφή</a>.</span></p>
<p><span style="font-family:Verdana;font-size:9pt;">Στο επόμενο και τελευταίο άρθρο στη σειρά ανάπτυξης του Arkanoid θα προσθέσουμε τη δυνατότητα για διαφορετικά επίπεδα (πίστες) στο παιχνίδι.<br />
</span></p>
<p><span style="font-family:Verdana;font-size:9pt;">Μέχρι τότε μπορείτε να ανεβάσετε τα δικά σας ευφάνταστα σχέδια πίστας του Arkanoid στο <a href="http://videogameslab.freeforums.org/arkanoid-t14.html" target="_blank">forum</a>. Τα πιο πρωτότυπα θα χρησιμοποιηθούν ως πίστες στη τελική έκδοση του Arkanoid που θα δημιουργήσουμε στο επόμενο tutorial.<br />
</span></p>
  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/videogameslab.wordpress.com/473/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/videogameslab.wordpress.com/473/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/videogameslab.wordpress.com/473/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/videogameslab.wordpress.com/473/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/videogameslab.wordpress.com/473/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/videogameslab.wordpress.com/473/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/videogameslab.wordpress.com/473/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/videogameslab.wordpress.com/473/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/videogameslab.wordpress.com/473/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/videogameslab.wordpress.com/473/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=videogameslab.wordpress.com&blog=5040448&post=473&subd=videogameslab&ref=&feed=1" /></div>]]></content:encoded>
			<wfw:commentRss>http://videogameslab.wordpress.com/2009/12/07/arkanoid-level-design/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/12/120709_0802_arkanoid1.png" medium="image" />

		<media:content url="http://videogameslab.files.wordpress.com/2009/12/120709_0802_arkanoid2.png" medium="image" />
	</item>
		<item>
		<title>Προγραμματίστε το δικό σας παιχνίδι</title>
		<link>http://videogameslab.wordpress.com/2009/11/05/pong-konsnos/</link>
		<comments>http://videogameslab.wordpress.com/2009/11/05/pong-konsnos/#comments</comments>
		<pubDate>Thu, 05 Nov 2009 07:20:23 +0000</pubDate>
		<dc:creator>Κώστας Αναγνώστου</dc:creator>
				<category><![CDATA[C#]]></category>
		<category><![CDATA[XNA Game Studio]]></category>
		<category><![CDATA[Ανάπτυξη βιντεοπαιχνιδιών]]></category>
		<category><![CDATA[Προγραμματισμός]]></category>
		<category><![CDATA[Στο Τύπο]]></category>

		<guid isPermaLink="false">http://videogameslab.wordpress.com/?p=466</guid>
		<description><![CDATA[Ο αναγνώστης του Videogames Laboratory konsnos έγραψε ένα πολύ καλό και πολύ επεξηγηματικό άρθρο στο PC WORLD σχετικά με την ανάπτυξη του Pong, βασισμένος στο κώδικα του παιχνιδιού που αναπτύξαμε στη πρώτη σειρά tutorial. Αν για κάποιο λόγο σας φάνηκαν τα tutorial εκείνα δύσκολα ή δυσνόητα αξίζει να ρίξετε μια ματιά στο άρθρο αυτό καθώς [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=videogameslab.wordpress.com&blog=5040448&post=466&subd=videogameslab&ref=&feed=1" />]]></description>
			<content:encoded><![CDATA[<div class='snap_preview'><br /><p><span style="font-family:Verdana;font-size:9pt;">Ο αναγνώστης του Videogames Laboratory konsnos έγραψε ένα πολύ καλό και πολύ επεξηγηματικό άρθρο στο PC WORLD σχετικά με την ανάπτυξη του Pong, βασισμένος στο κώδικα του παιχνιδιού που αναπτύξαμε στη <a href="http://videogameslab.wordpress.com/category/pong/" target="_blank">πρώτη σειρά tutorial</a>. Αν για κάποιο λόγο σας φάνηκαν τα tutorial εκείνα δύσκολα ή δυσνόητα αξίζει να ρίξετε μια ματιά στο άρθρο αυτό καθώς ο συγγραφέας παρουσιάζει το θέμα ακόμα πιο απλά και κατανοητά.<br />
</span></p>
<p><span style="font-family:Verdana;font-size:9pt;">Μπορείτε να βρείτε το σχετικό άρθρο <a href="http://www.pcw.gr/Article/Latest/program_computer_game_pong_DIY_/179-4703.html" target="_blank">εδώ</a>.</span></p>
<p><span style="font-family:Verdana;font-size:9pt;">ΥΓ: Υπάρχουν άλλες προτάσεις για το Videogames Laboratory Challenge #2;</span></p>
  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/videogameslab.wordpress.com/466/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/videogameslab.wordpress.com/466/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/videogameslab.wordpress.com/466/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/videogameslab.wordpress.com/466/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/videogameslab.wordpress.com/466/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/videogameslab.wordpress.com/466/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/videogameslab.wordpress.com/466/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/videogameslab.wordpress.com/466/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/videogameslab.wordpress.com/466/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/videogameslab.wordpress.com/466/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=videogameslab.wordpress.com&blog=5040448&post=466&subd=videogameslab&ref=&feed=1" /></div>]]></content:encoded>
			<wfw:commentRss>http://videogameslab.wordpress.com/2009/11/05/pong-konsnos/feed/</wfw:commentRss>
		<slash:comments>1</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>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>Διαγωνισμός Imagine Cup 2010</title>
		<link>http://videogameslab.wordpress.com/2009/10/20/imaginecup/</link>
		<comments>http://videogameslab.wordpress.com/2009/10/20/imaginecup/#comments</comments>
		<pubDate>Tue, 20 Oct 2009 07:18:15 +0000</pubDate>
		<dc:creator>Κώστας Αναγνώστου</dc:creator>
				<category><![CDATA[XNA Game Studio]]></category>
		<category><![CDATA[Ανάπτυξη βιντεοπαιχνιδιών]]></category>
		<category><![CDATA[Νέα]]></category>

		<guid isPermaLink="false">http://videogameslab.wordpress.com/?p=460</guid>
		<description><![CDATA[Ξεκίνησε και φέτος ο διεθνής διαγωνισμός της Microsoft Imagine Cup ο οποίος έχει 4 κατηγορίες: Ανάπτυξη Λογισμικού, Προγραμματισμό Βιντεοπαιχνιδιών, Διαχείριση Συστημάτων και Δικτύων και Δημιουργία Ψηφιακού Βίντεο. Σύμφωνα με τη Microsoft, σκοπός του διαγωνισμού είναι να βοηθήσει τους φοιτητές να βελτιώσουν τον κόσμο μέσω τεχνολογικών λύσεων. Φέτος είναι η έβδομη χρονιά του διαγωνισμού.

Κάθε χρονιά ο [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=videogameslab.wordpress.com&blog=5040448&post=460&subd=videogameslab&ref=&feed=1" />]]></description>
			<content:encoded><![CDATA[<div class='snap_preview'><br /><p><span style="color:black;font-family:Verdana;font-size:9pt;">Ξεκίνησε και φέτος ο διεθνής διαγωνισμός της Microsoft Imagine Cup ο οποίος έχει 4 κατηγορίες: Ανάπτυξη Λογισμικού, <strong>Προγραμματισμό Βιντεοπαιχνιδιών</strong>, Διαχείριση Συστημάτων και Δικτύων και Δημιουργία Ψηφιακού Βίντεο. Σύμφωνα με τη Microsoft, σκοπός του διαγωνισμού είναι να βοηθήσει τους φοιτητές να βελτιώσουν τον κόσμο μέσω τεχνολογικών λύσεων. Φέτος είναι η έβδομη χρονιά του διαγωνισμού.<br />
</span></p>
<p><span style="color:black;font-family:Verdana;font-size:9pt;">Κάθε χρονιά ο διαγωνισμός έχει διαφορετικό θέμα, φέτος είναι: «Φανταστείτε έναν κόσμο όπου η τεχνολογία μας βοηθάει να λύσουμε τα μεγαλύτερα προβλήματα που αντιμετωπίζει ο κόσμος μας σήμερα». Τα Ηνωμένα Έθνη έχουν προσδιορίσει τα προβλήματα αυτά σαν τους «Στόχους της Χιλιετίας». Περισσότερες πληροφορίες σχετικά με τους στόχους της χιλιετίας, μπορείτε να βρείτε <a href="http://www.un.org/millenniumgoals/" target="_blank"><span style="text-decoration:underline;">εδώ</span></a>.<br />
</span></p>
<p><span style="color:black;font-family:Verdana;font-size:9pt;">Η χώρα μας έχει πετύχει στο παρελθόν σημαντικές διακρίσεις στο διαγωνισμό, με ομάδες να κατακτούν ακόμα και τη δεύτερη θέση στους παγκόσμιους τελικούς, οι οποίοι φέτος θα διεξαχθούν στην Πολωνία.<br />
</span></p>
<p><span style="font-family:Verdana;font-size:9pt;"><span style="color:black;">Οι κατηγορίες του διαγωνισμού είναι 4:</span><br />
</span></p>
<ul>
<li><a href="http://imaginecup.com/Competition/mycompetitionportal.aspx?competitionId=37" target="_blank"><span style="color:black;font-family:Verdana;font-size:9pt;text-decoration:underline;">Software Design</span></a><span style="font-family:Verdana;font-size:9pt;"><span style="color:black;"> – Σχεδίαση/κατασκευή λογισμικού</span><br />
</span></li>
<li><a href="http://imaginecup.com/Competition/mycompetitionportal.aspx?competitionId=39" target="_blank"><span style="color:black;font-family:Verdana;font-size:9pt;text-decoration:underline;">Digital Media</span></a><span style="font-family:Verdana;font-size:9pt;"><span style="color:black;"> – Δημιουργία Animation/video</span><br />
</span></li>
<li><a href="http://imaginecup.com/Competition/mycompetitionportal.aspx?competitionId=38" target="_blank"><span style="color:black;font-family:Verdana;font-size:9pt;text-decoration:underline;">Game Design</span></a><span style="font-family:Verdana;font-size:9pt;"><span style="color:black;"> – προγραμματισμός παιχνιδιού </span><br />
</span></li>
<li>
<div><a href="http://imaginecup.com/Competition/mycompetitionportal.aspx?competitionId=41" target="_blank"><span style="color:black;font-family:Verdana;font-size:9pt;text-decoration:underline;">IT Challenge</span></a><span style="font-family:Verdana;font-size:9pt;"><span style="color:black;"> – Ανάπτυξη IT συστημάτων</span><br />
</span></div>
</li>
</ul>
<p><span style="color:black;font-family:Verdana;font-size:9pt;">Ειδικότερα, στόχος της κατηγορίας Game Design είναι η ανάπτυξη ενός παιχνιδιού χρησιμοποιώντας τόσο το XNA Game Studio όσο και το Visual Studio. Είναι μια ευκαιρία για τους συμμετέχοντες που ασχολούνται με game development να κατασκευάσουν ένα παιχνίδι το οποίο συμβάλλει στην ενημέρωση του πληθυσμού για τα προβλήματα του πλανήτη. Μπορείτε να δείτε παραδείγματα τέτοιων παιχνιδιών, τα επονομαζόμενα serious games <a href="http://www.gamesforchange.org/" target="_blank">εδώ</a>.<br />
</span></p>
<p><span style="font-family:Verdana;font-size:9pt;">Δικαίωμα  συμμετοχής έχουν ομάδες από 1 μέχρι 4 άτομα και έναν υπεύθυνο καθηγητή. <span style="color:black;">Περισσότερες πληροφορίες για το διαγωνισμό μπορείτε να δείτε <a href="http://www.imaginecup.com/" target="_blank"><span style="text-decoration:underline;">εδώ</span></a>.<br />
</span></span></p>
<p><span style="color:black;font-family:Verdana;font-size:9pt;">Αν έχετε κάποια ιδέα για παιχνίδι σχετικό με το θέμα του διαγωνισμού αλλά δεν είστε μέλος ομάδας ανάπτυξης μπορείτε να <a href="http://videogameslab.wordpress.com/contact/" target="_blank">επικοινωνήσετε μαζί μου</a>. Επιπλέον αν θέλετε να συμμετάσχετε στην ανάπτυξη ενός τέτοιου παιχνιδιού ακόμα και αν δεν έχετε κάποια συγκεκριμένη ιδέα, μπορείτε και πάλι να επικοινωνήσετε μαζί μου. Ίσως μπορέσουμε να συγκεντρώσουμε ικανό αριθμό ατόμων για να φτιάξουμε μια ομάδα ανάπτυξης βιντεοπαιχνιδιού για το διαγωνισμό αυτό.</span></p>
  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/videogameslab.wordpress.com/460/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/videogameslab.wordpress.com/460/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/videogameslab.wordpress.com/460/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/videogameslab.wordpress.com/460/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/videogameslab.wordpress.com/460/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/videogameslab.wordpress.com/460/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/videogameslab.wordpress.com/460/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/videogameslab.wordpress.com/460/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/videogameslab.wordpress.com/460/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/videogameslab.wordpress.com/460/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=videogameslab.wordpress.com&blog=5040448&post=460&subd=videogameslab&ref=&feed=1" /></div>]]></content:encoded>
			<wfw:commentRss>http://videogameslab.wordpress.com/2009/10/20/imaginecup/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>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>Squash the bugs</title>
		<link>http://videogameslab.wordpress.com/2009/08/13/squash-the-bugs/</link>
		<comments>http://videogameslab.wordpress.com/2009/08/13/squash-the-bugs/#comments</comments>
		<pubDate>Thu, 13 Aug 2009 08:24:15 +0000</pubDate>
		<dc:creator>Κώστας Αναγνώστου</dc:creator>
				<category><![CDATA[C#]]></category>
		<category><![CDATA[XNA Game Studio]]></category>
		<category><![CDATA[Ανάπτυξη βιντεοπαιχνιδιών]]></category>
		<category><![CDATA[Προγραμματισμός]]></category>

		<guid isPermaLink="false">http://videogameslab.wordpress.com/?p=352</guid>
		<description><![CDATA[Η καρδιά του Αυγούστου, με το περισσότερο κόσμο στις παραλίες και το μυαλό όλων στις διακοπές, δεν είναι η κατάλληλη εποχή για θεωρίες και μεγάλα κείμενα. Γι αυτό σκέφτηκα να φτιάξω ένα απλό παιχνιδάκι, απλά για διασκέδαση. Βασιζόμενος στο Pong που αναπτύξαμε σε προηγούμενα tutorial ξεκίνησα  να φτιάχνω το Squash. Για όσους δεν το [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=videogameslab.wordpress.com&blog=5040448&post=352&subd=videogameslab&ref=&feed=1" />]]></description>
			<content:encoded><![CDATA[<div class='snap_preview'><br /><p><span style="font-family:Verdana;font-size:9pt;">Η καρδιά του Αυγούστου, με το περισσότερο κόσμο στις παραλίες και το μυαλό όλων στις διακοπές, δεν είναι η κατάλληλη εποχή για θεωρίες και μεγάλα κείμενα. Γι αυτό σκέφτηκα να φτιάξω ένα απλό παιχνιδάκι, απλά για διασκέδαση. Βασιζόμενος στο Pong που αναπτύξαμε σε <a href="http://videogameslab.wordpress.com/2009/07/23/hello-pong-part5/" target="_blank">προηγούμενα tutorial</a> ξεκίνησα  να φτιάχνω το Squash. Για όσους δεν το ξέρουν, το <a href="http://www.youtube.com/watch?v=-to_ZohAer4" target="_blank">Squash</a> είναι ένα παιχνίδι με ρακέτες, σε ένα κλειστό δωμάτιο, στο οποίο και οι δύο παίκτες βρίσκονται στην ίδια πλευρά του γηπέδου.<br />
</span></p>
<p><span style="font-family:Verdana;font-size:9pt;">Ήταν εύκολη η μετατροπή του Pong σε Squash, απλά μετέφερα τη ρακέτα του υπολογιστή στα αριστερά, έδωσα στις ρακέτες διαφορετικό χρώμα ώστε να ξεχωρίζουν και άλλαξα λίγο το τεστ σύγκρουσης της μπάλας με τη ρακέτα του υπολογιστή. Επιπλέον άλλαξα και τη λογική υπολογισμού σκορ.<br />
</span></p>
<p><span style="font-family:Verdana;font-size:9pt;">Κάτι πρέπει να πήγε στραβά όμως κατά τη διαδικασία μετατροπής, γιατί όταν έτρεξα το παιχνίδι είδα αυτό:<br />
</span></p>
<p><img src="http://videogameslab.files.wordpress.com/2009/08/081309_0824_squashthebu1.png" alt="" /></p>
<p><span style="font-family:Verdana;font-size:9pt;">Με τις γνώσεις που αποκτήσαμε στα <a href="http://videogameslab.wordpress.com/2009/07/28/debugging-part1/" target="_blank">προηγούμενα </a><a href="http://videogameslab.wordpress.com/2009/08/07/debugging-part2/" target="_blank">tutorial </a>πάνω στο debugging, μήπως θα μπορούσατε να βρείτε τι πήγε στραβά; Αναζητάμε λάθη προγραμματιστικά και όχι σχεδιασμού. Το παιχνίδι βασίζεται στο Pong και έχει τις  σχεδιαστικές ατέλειες του, δεν είναι όμως αυτό το πρόβλημα. Ο κώδικας του παιχνιδιού είναι διαθέσιμος στο Code Repository, <a href="http://videogameslab.googlecode.com/files/Squash.zip" target="_blank">σε zip μορφή</a> προς το παρόν.<br />
</span></p>
<p><span style="font-family:Verdana;font-size:9pt;">Όποιος εντοπίσει τα λάθη και διορθώσει το παιχνίδι, ας επικοινωνήσει μαζί μου μέσω της <a href="http://videogameslab.wordpress.com/contact/" target="_blank">φόρμας επικοινωνίας</a>. Σε μερικές εβδομάδες θα κάνω μια αναφορά στα άτομα που κατάφεραν να βρουν τα σφάλματα του παιχνιδιού.<br />
</span></p>
<p><span style="font-family:Verdana;font-size:9pt;">Καλό debugging!</span></p>
  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/videogameslab.wordpress.com/352/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/videogameslab.wordpress.com/352/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/videogameslab.wordpress.com/352/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/videogameslab.wordpress.com/352/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/videogameslab.wordpress.com/352/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/videogameslab.wordpress.com/352/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/videogameslab.wordpress.com/352/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/videogameslab.wordpress.com/352/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/videogameslab.wordpress.com/352/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/videogameslab.wordpress.com/352/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=videogameslab.wordpress.com&blog=5040448&post=352&subd=videogameslab&ref=&feed=1" /></div>]]></content:encoded>
			<wfw:commentRss>http://videogameslab.wordpress.com/2009/08/13/squash-the-bugs/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/08/081309_0824_squashthebu1.png" medium="image" />
	</item>
	</channel>
</rss>