<?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</title>
	<atom:link href="http://videogameslab.wordpress.com/feed/" rel="self" type="application/rss+xml" />
	<link>http://videogameslab.wordpress.com</link>
	<description>O συναρπαστικός κόσμος της ανάπτυξης βιντεοπαιχνιδιών</description>
	<lastBuildDate>Thu, 05 Nov 2009 07:27:51 +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</title>
		<link>http://videogameslab.wordpress.com</link>
	</image>
			<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>Τα πρώτα του γενέθλια!</title>
		<link>http://videogameslab.wordpress.com/2009/10/01/birthday/</link>
		<comments>http://videogameslab.wordpress.com/2009/10/01/birthday/#comments</comments>
		<pubDate>Thu, 01 Oct 2009 06:01:16 +0000</pubDate>
		<dc:creator>Κώστας Αναγνώστου</dc:creator>
				<category><![CDATA[Νέα]]></category>

		<guid isPermaLink="false">http://videogameslab.wordpress.com/?p=433</guid>
		<description><![CDATA[Το Videogames Laboratory κλείνει σήμερα ένα χρόνος ζωής! Ξεκίνησε πριν ακριβώς από ένα χρόνο με σκοπό να παρουσιάζει θέματα που αφορούν την ανάπτυξη βιντεοπαιχνιδιών. Είχε κάποια βρεφικά προβλήματα, λόγω του τεράστιου φόρτου εργασίας που προκάλεσε η συγγραφή του βιβλίου και η δουλειά στο Πανεπιστήμιο, αλλά από το καλοκαίρι έχει βρει το ρυθμό του, θέλω να [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=videogameslab.wordpress.com&blog=5040448&post=433&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 κλείνει σήμερα ένα χρόνος ζωής! Ξεκίνησε πριν ακριβώς από ένα χρόνο με σκοπό να παρουσιάζει θέματα που αφορούν την ανάπτυξη βιντεοπαιχνιδιών. Είχε κάποια βρεφικά προβλήματα, λόγω του τεράστιου φόρτου εργασίας που προκάλεσε η συγγραφή του βιβλίου και η δουλειά στο Πανεπιστήμιο, αλλά από το καλοκαίρι έχει βρει το ρυθμό του, θέλω να ελπίζω, με τις σειρές άρθρων που παρουσιάζει σχετικά με την δημιουργία απλών (αρχικά) βιντεοπαιχνιδιών.</span></p>
<p><span style="font-family:Verdana;font-size:9pt;">Έχω δεχτεί κατά καιρούς διάφορες προτάσεις-παρατηρήσεις να παρουσιάζω θέματα περισσότερο προχωρημένα, σχετικά με τα τριδιάστατα γραφικά και τις σύγχρονες μεθόδους απεικόνισης. Όμως πιστεύω ακράδαντα ότι τα βιντεοπαιχνίδια είναι κάτι περισσότερο από τα γραφικά που απεικονίζουν, είναι ολόκληρα συστήματα τα οποία πρέπει να κατανοήσεις και να χτίσεις σταδιακά έτσι ώστε να φτάσεις σε κάτι λειτουργικό και ψυχαγωγικό. Κατά τη γνώμη μου η δημιουργία του ταπεινού Pong και Arkanoid έχει να διδάξει περισσότερα από ένα tutorial για το πώς εφαρμόζουμε parallax mapping σε ένα τριδιάστατο μοντέλο (όχι ότι δεν θα το δούμε και αυτό στο μέλλον). Σκοπός μου είναι περάσουμε και σε πιο σύνθετα παιχνίδια με τριδιάστατα γραφικά, αφότου όμως έχουν γίνει κατανοητές οι βασικές αρχές ανάπτυξης βιντεοπαιχνιδιών.</span></p>
<p><span style="font-family:Verdana;font-size:9pt;">Το <a href="http://code.google.com/p/videogameslab/" target="_blank">Code Repository</a> είναι ένα άλλο μεγάλο κεφάλαιο του Videogames Laboratory το οποίο πιστεύω ότι θα μπορέσουμε να αξιοποιήσουμε ακόμα περισσότερο στο μέλλον. Προς το παρόν οι αναγνώστες του blog, <a href="http://videogameslab.wordpress.com/2009/07/23/code-repository-2/" target="_blank">μετά από σχετική εγγραφή</a>, μπορούν να βελτιώνουν και να ανεβάζουν την δική τους έκδοση ενός βιντεοπαιχνιδιού που αναπτύσσουμε στα πλαίσια των tutorial. Ήδη υπάρχουν άτομα που βελτιώνουν και κάνουν προσθήκες στο Pong και Arkanoid. Αυτό που ελπίζω να γίνει στο μέλλον είναι να συγκεντρωθεί ένας ικανός αριθμός ατόμων, τα οποία επιθυμούν να αναπτύσσουν βιντεοπαιχνίδια, έτσι ώστε να μπορέσουμε να αναπτύξουμε ένα μεγαλύτερο παιχνίδι συνεργατικά, δηλαδή κάποιος να αναλάβει τα γραφικά, κάποιος την φυσική, κάποιος τον ήχο, κάποιος το gameplay κλπ.</span></p>
<p><span style="font-family:Verdana;font-size:9pt;">Παράλληλα δημιουργήθηκε και ένα <a href="http://videogameslab.freeforums.org/" target="_blank">forum</a>, συνοδευτικό του Videogames Laboratory, το οποίο έχει ως σκοπό την μεγαλύτερη ελευθερία στην συζήτηση πάνω σε θέματα που αφορούν τα παιχνίδια και τις τεχνικές που μελετάμε στο blog, όπως και άλλα θέματα που αφορούν την ανάπτυξη βιντεοπαιχνιδιών γενικότερα.</span></p>
<p><span style="font-family:Verdana;font-size:9pt;">Αρχίζουμε λοιπόν το δεύτερο χρόνο ζωής του blog, με ακόμα μεγαλύτερη συμμετοχή και διάθεση για ανάπτυξη βιντεοπαιχνιδιών θέλω να ελπίζω.</span></p>
<p><span style="font-family:Verdana;font-size:9pt;">Αν έχετε προτάσεις για βελτίωση του Videogames Laboratory, ή για κάποια κατεύθυνση που θα θέλατε να πάρει ή κάποιο στοιχείο που νομίζετε ότι του λείπει θα ήθελα να τις ακούσω (στα σχόλια ή <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/433/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/videogameslab.wordpress.com/433/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/videogameslab.wordpress.com/433/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/videogameslab.wordpress.com/433/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/videogameslab.wordpress.com/433/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/videogameslab.wordpress.com/433/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/videogameslab.wordpress.com/433/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/videogameslab.wordpress.com/433/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/videogameslab.wordpress.com/433/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/videogameslab.wordpress.com/433/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=videogameslab.wordpress.com&blog=5040448&post=433&subd=videogameslab&ref=&feed=1" /></div>]]></content:encoded>
			<wfw:commentRss>http://videogameslab.wordpress.com/2009/10/01/birthday/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>
	</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>Videogames Laboratory Forum II</title>
		<link>http://videogameslab.wordpress.com/2009/09/01/videogames-laboratory-forum-ii/</link>
		<comments>http://videogameslab.wordpress.com/2009/09/01/videogames-laboratory-forum-ii/#comments</comments>
		<pubDate>Tue, 01 Sep 2009 15:09:57 +0000</pubDate>
		<dc:creator>Κώστας Αναγνώστου</dc:creator>
				<category><![CDATA[Forum]]></category>
		<category><![CDATA[Βιομηχανία βιντεοπαιχνιδιών]]></category>
		<category><![CDATA[Νέα]]></category>

		<guid isPermaLink="false">http://videogameslab.wordpress.com/?p=390</guid>
		<description><![CDATA[Αποφάσισα να δώσω μια δεύτερη ευκαιρία στο host του forum για μερικές μέρες πριν το μεταφέρω σε άλλο host. Παράλληλα δημιούργησα και ένα poll (στην δεξιά στήλη του blog) στο οποίο μπορούν οι χρήστες του forum να καταγράφουν την εμπειρία τους από την χρήση του. Αν τα αρνητικά σχόλια είναι πολλά, τότε θα αναζητηθεί άλλος [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=videogameslab.wordpress.com&blog=5040448&post=390&subd=videogameslab&ref=&feed=1" />]]></description>
			<content:encoded><![CDATA[<div class='snap_preview'><br /><p><span style="font-family:Verdana;font-size:9pt;">Αποφάσισα να δώσω μια δεύτερη ευκαιρία στο host του forum για μερικές μέρες πριν το μεταφέρω σε άλλο host. Παράλληλα δημιούργησα και ένα poll (στην δεξιά στήλη του blog) στο οποίο μπορούν οι χρήστες του forum να καταγράφουν την εμπειρία τους από την χρήση του. Αν τα αρνητικά σχόλια είναι πολλά, τότε θα αναζητηθεί άλλος host.</span></p>
<p><span style="font-family:Verdana;font-size:9pt;">Μέχρι τότε μπορείτε να στέλνετε τις ερωτήσεις, τα σχόλια σας, νέα από την βιομηχανία και την ανάπτυξη βιντεοπαιχνιδιών σας στο <a href="http://videogameslab.freeforums.org/" target="_blank">Videogames Laboratory forum</a> ως συνήθως.</span></p>
  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/videogameslab.wordpress.com/390/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/videogameslab.wordpress.com/390/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/videogameslab.wordpress.com/390/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/videogameslab.wordpress.com/390/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/videogameslab.wordpress.com/390/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/videogameslab.wordpress.com/390/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/videogameslab.wordpress.com/390/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/videogameslab.wordpress.com/390/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/videogameslab.wordpress.com/390/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/videogameslab.wordpress.com/390/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=videogameslab.wordpress.com&blog=5040448&post=390&subd=videogameslab&ref=&feed=1" /></div>]]></content:encoded>
			<wfw:commentRss>http://videogameslab.wordpress.com/2009/09/01/videogames-laboratory-forum-ii/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>
	</item>
		<item>
		<title>Προβλήματα πρόσβασης στο forum</title>
		<link>http://videogameslab.wordpress.com/2009/08/30/forum-problems/</link>
		<comments>http://videogameslab.wordpress.com/2009/08/30/forum-problems/#comments</comments>
		<pubDate>Sun, 30 Aug 2009 08:44:02 +0000</pubDate>
		<dc:creator>Κώστας Αναγνώστου</dc:creator>
				<category><![CDATA[Forum]]></category>
		<category><![CDATA[Νέα]]></category>

		<guid isPermaLink="false">http://videogameslab.wordpress.com/?p=386</guid>
		<description><![CDATA[Τελικά φαίνεται ότι η υπηρεσία freeforums.org που επέλεξα για να κάνω host το Videogames Laboratory forum δεν είναι και πλέον αξιόπιστη&#8230; παρατήρησα αρκετά προβληματάκια με αποκορύφωμα σήμερα που δεν δίνει πρόσβαση στο forum με τίποτα. 
Αν έχετε καμιά προτάση για κάποια πιο αξιόπιστη (και δωρεάν) υπηρεσία hosting για forum θα ήθελα να την ακούσω.
  [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=videogameslab.wordpress.com&blog=5040448&post=386&subd=videogameslab&ref=&feed=1" />]]></description>
			<content:encoded><![CDATA[<div class='snap_preview'><br /><p>Τελικά φαίνεται ότι η υπηρεσία freeforums.org που επέλεξα για να κάνω host το Videogames Laboratory forum δεν είναι και πλέον αξιόπιστη&#8230; παρατήρησα αρκετά προβληματάκια με αποκορύφωμα σήμερα που δεν δίνει πρόσβαση στο forum με τίποτα. </p>
<p>Αν έχετε καμιά προτάση για κάποια πιο αξιόπιστη (και δωρεάν) υπηρεσία hosting για forum θα ήθελα να την ακούσω.</p>
  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/videogameslab.wordpress.com/386/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/videogameslab.wordpress.com/386/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/videogameslab.wordpress.com/386/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/videogameslab.wordpress.com/386/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/videogameslab.wordpress.com/386/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/videogameslab.wordpress.com/386/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/videogameslab.wordpress.com/386/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/videogameslab.wordpress.com/386/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/videogameslab.wordpress.com/386/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/videogameslab.wordpress.com/386/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=videogameslab.wordpress.com&blog=5040448&post=386&subd=videogameslab&ref=&feed=1" /></div>]]></content:encoded>
			<wfw:commentRss>http://videogameslab.wordpress.com/2009/08/30/forum-problems/feed/</wfw:commentRss>
		<slash:comments>5</slash:comments>
	
		<media:content url="http://0.gravatar.com/avatar/4bd00ab99710c6e67ef0a28c68628aad?s=96&#38;d=http%3A%2F%2F0.gravatar.com%2Favatar%2Fad516503a11cd5ca435acc9bb6523536%3Fs%3D96" medium="image">
			<media:title type="html">thinkinggamer</media:title>
		</media:content>
	</item>
	</channel>
</rss>