Ανάπτυξη δικτυακού παιχνιδιού με δυνατότητα συμμετοχής ακροατηρίου.



Σχετικά έγγραφα
74 η ΣΥΝΟΔΟΣ ΠΡΥΤΑΝΕΩΝ & ΠΡΟΕΔΡΩΝ Δ.Ε. ΤΩΝ ΕΛΛΗΝΙΚΩΝ ΠΑΝΕΠΙΣΤΗΜΙΩΝ Αριστοτέλειο Πανεπιστήμιο Θεσσαλονίκης Θεσσαλονίκη, Δεκεμβρίου 2013

ΜΕΛΕΤΗ ΚΑΙ ΑΠΟΚΑΤΑΣΤΑΣΗ ΤΗΣ ΧΩΜΑΤΕΡΗΣ «ΑΣΤΙΜΙΤΣΙ» ΣΤΗΝ ΠΕΡΙΟΧΗ ΚΟΡΥΤΙΑΝΗΣ ΤΟΥ ΝΟΜΟY ΘΕΣΠΡΩΤΙΑΣ

ΥΠΟΣΤΗΡΙΖΟΜΕΝΗ ΑΠΑΣΧΟΛΗΣΗ ΣΤΗΝ ΕΛΕΥΘΕΡΗ ΑΓΟΡΑ ΕΡΓΑΣΙΑΣ

ΕΡΕΥΝΗΤΙΚΗ ΕΡΓΑΣΙΑ Β ΛΥΚΕΙΟΥ ΘΕΜΑ: ΤΑ ΠΕΤΡΙΝΑ ΓΕΦΥΡΙΑ ΤΗΣ ΗΠΕΙΡΟΥ

ΥΠΟΜΝΗΜΑ ΘΕΣΕΙΣ ΤΗΣ ΟΒΕΣ ΓΙΑ ΤΟ ΣΧΕΔΙΟ ΤΟΥ ΝΕΟΥ ΝΟΜΟΥ ΓΙΑ ΤΑ ΕΥΡΩΠΑΙΚΑ ΣΥΜΒΟΥΛΙΑ ΕΡΓΑΖΟΜΕΝΩΝ

Project «Διατροφή μέσω των αιώνων»

72(Ι)/2014 Ο ΠΕΡΙ ΙΔΡΥΣΕΩΣ ΚΑΙ ΛΕΙΤΟΥΡΓΙΑΣ ΣΥΝΔΕΣΜΩΝ ΠΡΟΣΤΑΣΙΑΣ ΦΥΤΩΝ ΝΟΜΟΣ ΤΟΥ 2014

ΑΝΩΤΑΤΟ ΤΕΧΝΟΛΟΓΙΚΟ ΙΔΡΥΜΑ ΚΡΗΤΗΣ ΣΧΟΛΗ ΤΕΧΝΟΛΟΓΙΑΣ ΓΕΩΠΟΝΙΑΣ ΤΜΗΜΑ ΦΥΤΙΚΗΣ ΠΑΡΑΓΩΓΗΣ ΠΤΥΧΙΑΚΗ ΕΡΓΑΣΙΑ

Κοινωνική Οικονομία: Μια βιώσιμη εναλλακτική?

ΠΕΡΙΦΕΡΕΙΑ ΑΝΑΤΟΛΙΚΗΣ ΜΑΚΕΔΟΝΙΑΣ ΘΡΑΚΗΣ. Πρόταση σχεδιασμού και κατάρτισης αναπτυξιακού προγραμματισμού περιόδου


ΘΕΜΑ: «Συζήτηση και λήψη αποφάσεων για τη διαθεσιμότητα υπαλλήλων, περικοπή πόρων, και δημιουργία Παρατηρητηρίου στον Δήμο μας».

ΕΚΠΑΙΔΕΥΤΙΚΑ ΠΡΟΓΡΑΜΜΑΤΑ ΜΟΥΣΕΙΟΥ ΣΧΟΛΙΚΗΣ ΖΩΗΣ ΚΑΙ ΕΚΠΑΙΔΕΥΣΗΣ ΠΡΟΓΡΑΜΜΑΤΑ ΓΙΑ ΠΑΙΔΙΑ ΚΑΙ ΓΟΝΕΙΣ

ΠΕΡΙΕΧΟΜΕΝΑ. Πρόλογος

18 ος Πανελλήνιος Μαθητικός

ΑΝΩΤΑΤΟ ΤΕΧΝΟΛΟΓΙΚΟ ΕΚΠΑΙΔΕΥΤΙΚΟ ΙΔΡΥΜΑ ΤΕΙ ΣΕΡΡΩΝ ΣΧΟΛΗ ΔΙΟΙΚΗΣΗΣ ΚΑΙ ΟΙΚΟΝΟΜΙΑΣ ΤΜΗΜΑ ΛΟΓΙΣΤΙΚΗΣ

591 Κ.Ι\ ΘΕΜΑ: ΚΑΩΣΤΟΥΦΑΝΤΟΥΡΓΙΑ & ΠΕΡΙΒΑλλΟΝ ΕΙΣΗΓΗΤΗΣ: ΤΜΗΜΑ ΚΛΩΣΤΟΥΦΑΝΤΟΥΡΓΙΑΣ. Τ.Ε.Ι Πειραιά για την απόκτηση του πτυχίου.

ΕΣΩΤΕΡΙΚΟΙ ΚΑΝΟΝΙΣΜΟΙ ΛΕΙΤΟΥΡΓΙΑΣ ΤΟΥ ΣΧΟΛΕΙΟΥ

Μ. Ασία, Καππαδοκία,Πόντος, Κρήτη. Θράκη, Μακεδονία, Ήπειρος, Νησιά Ιονίου. Θεσσαλία, Στερεά Ελλάδα, Πελοπόννησος, Νησιά Αιγαίου

FORUM ΣΥΝΕΡΓΑΣΙΑ ΑΡΙΣΤΕΡΩΝ ΑΡΧΙΤΕΚΤΟΝΩΝ

Εισήγηση για τον Προϋπολογισμό 2011 του Δήμου Κηφισιάς

Η ΚΥΒΕΡΝΗΤΙΚΗ ΠΟΛΙΤΙΚΗ ΤΟΥ ΣΥΡΙΖΑ ΓΙΑ ΤΟΝ ΑΓΡΟΤΙΚΟ ΤΟΜΕΑ ΣΤΙΣ ΣΗΜΕΡΙΝΕΣ ΣΥΝΘΗΚΕΣ.

Στον Πανούλη. Γιάννης

κ.ο. ΑΝΑΣΥΝΤΑΞΗ Θέσεις της Πολιτικής Επιτροπής

ΟΔΗΓΟΣ ΜΕΛΕΤΗΣ ΕΝΝΟΙΩΝ επιμέλεια: Μαρία Κάππου ΕΝΝΟΙΕΣ Γ ΛΥΚΕΙΟΥ. Οδηγός μελέτης και επανάληψης. Επιμέλεια: Μαρία Κάππου [1]

ΑΝΑΠΛΑΣΗ ΠΛΑΤΕΙΑΣ ΧΡΥΣΟΣΤΟΜΟΥ ΣΜΥΡΝΗΣ

Η παρούσα πτυχικακή εργασία έρχεται μετά από λίγα χρόνια να συμπληρώσει μία ακόμη σχεδιαστική πρόταση για την «Ανάπλαση της Αλάνας της Τούμπας», θέμα

Ο ΝΟΜΟΣ 1963/91 ΓΙΑ ΤΗΝ Ι ΡΥΣΗ ΚΑΙ ΛΕΙΤΟΥΡΓΙΑ ΤΩΝ ΦΑΡΜΑΚΕΙΩΝ (ΝΟΜΟΣ 1963/91 ΦΕΚ. ΤΡΟΠΟΠΟΙΗΣΗ ΚΑΙ ΣΥΜΠΛΗΡΩΣΗ ΤΗΣ ΦΑΡΜΑΚΕΥΤΙΚΗΣ ΝΟΜΟΘΕΣΙΑΣ ΚΑΙ ΑΛΛΕΣ

ΓΙΑ ΤΑ ΕΠΑΓΓΕΛΜΑΤΙΚΑ ΔΙΚΑΙΩΜΑΤΑ ΤΩΝ ΜΗΧΑΝΙΚΩΝ ΚΑΙ ΤΟΝ ΠΟΛΥΝΟΜΟ ΤΟΥ ΑΠΡΙΛΗ

ΚΑΤΑΣΤΑΤΙΚΟ ΕΤΑΙΡΕΙΑ ΠΟΛΙΤΙΣΤΙΚΗΣ ΚΛΗΡΟΝΟΜΙΑΣ ΚΑΤΩΚΟΠΙΑΣ (KATOKOPIA CULTURAL HERITAGE ASSOCIATION)

ΠΑΓΚΥΠΡΙΑ ΟΡΓΑΝΩΣΗ ΕΛΛΗΝΩΝ ΔΑΣΚΑΛΩΝ (ΠΟΕΔ) ΟΔΗΓΙΕΣ ΠΡΟΣ ΤΑ ΜΕΛΗ ΜΕ ΤΗΝ ΕΝΑΡΞΗ ΤΗΣ ΝΕΑΣ ΣΧΟΛΙΚΗΣ ΧΡΟΝΙΑΣ

Τεχνικογεωλογικά χαρακτηριστικά των σχηματισμών του Ελλαδικού χώρου

Κεφάλαιο 6 Συνολικές Μεταολυμπιακές Οικονομικές και Κοινωνικές Επιδράσεις

ΠΟΛΥΤΕΧΝΕΙΟ 73. Η λάμψη της εξέγερσης είναι παντοτινή...

«ΕΥΡΩΠΑΪΚΕΣ ΠΡΟΓΡΑΜΜΑΤΙΚΕΣ ΠΕΡΙΟΔΟΙ ΚΑΙ ΣΥΜΒΟΛΗ ΤΟΥΣ ΣΤΑ ΕΡΓΑ ΥΠΟΔΟΜΗΣ ΣΤΗΝ ΕΛΛΑΔΑ. ΤΙ

1 Εισαγωγή στην Ανάλυση των Κατασκευών 1.1 Κατασκευές και δομοστατική

ΠΡΟΛΟΓΟΣ ΑΚΙΝΗΤΗ ΑΞΙΑ

Σεισμοί και Σχολεία. ΤΑ ΕΚΠΑΙΔΕΥΤΙΚΑ τεύχος

ΔΕΚΑΕΞΙ ΜΑΘΗΜΑΤΑ ΠΑΓΚΟΣΜΙΑΣ ΙΣΤΟΡΙΑΣ

«ΑΝΑΠΤΥΞΙΑΚΕΣ ΠΡΟΟΠΤΙΚΕΣ ΣΤΑΘΜΟΥ ΕΜΠΟΡΕΥΜΑΤΟΚΙΒΩΤΙΩΝ Σ.ΕΜΠΟ Ο.Λ.Π.» Η ΔΙΑΧΕΙΡΙΣΗ ΤΩΝ ΛΙΜΕΝΩΝ ΣΤΗΝ ΕΛΛΑΔΑ

ΕΠΙΣΗΜΗ ΕΦΗΜΕΡΙΔΑ ΤΗΣ ΚΥΠΡΙΑΚΗΣ ΔΗΜΟΚΡΑΤΙΑΣ ΚΥΡΙΟ ΜΕΡΟΣ ΤΜΗΜΑ Α

ΔΕΗ Ανανεώσιμες: Το μέλλον της ΔΕΗ Ομιλία του κ. Τάκη Αθανασόπουλου Προέδρου & Διευθύνοντος Συμβούλου ΔΕΗ Α.Ε

ΙΣΤΟΡΙΚΟ ΛΕΞΙΚΟ ΕΠΙΣΤΗΜΟΝΙΚΩΝ ΟΡΩΝ

Α Π Ο Σ Π Α Σ Μ Α. ΕΛΛΗΝΙΚΗ ΔΗΜΟΚΡΑΤΙΑ ΝΟΜΟΣ ΒΟΙΩΤΙΑΣ ΔΗΜΟΣ ΟΡΧΟΜΕΝΟΥ Αρ.Πρωτ.: 298/

ΤΟ ΤΑΞΙΔΙ ΕΙΝΑΙ Η ΑΦΟΡΜΗ

Η Πρόταση του ΣΥΡΙΖΑ-ΕΚΜ για τη ΔΙΑΧΕΙΡΙΣΗ ΑΠΟΡΡΙΜΜΑΤΩΝ Βιώσιμη και δίκαιη οικονομικά και οικολογικά λύση

Νέες συνθήκες στην αγορά εργασίας και κυρίως από που προέρχονται αυτές οι αλλαγές

ΜΑΝΟΛΗΣ ΚΑΛΟΜΟΙΡΗΣ, ΚΥΚΛΟΣ ΤΡΑΓΟΥΔΙΩΝ ΜΑΓΙΟΒΟΤΑΝΑ. Πτυχιακή εργασία της Άλμας Τότσκα 25/04

στο σχέδιο νόµου «Άσκηση εµπορικών δραστηριοτήτων εκτός καταστήµατος» Γενικό Μέρος ΑΙΤΙΟΛΟΓΙΚΗ ΕΚΘΕΣΗ

ΘΕΜΑ: Κάλυψη κενών θέσεων τακτικού προσωπικού σε νησιωτικούς δήμους. Δυόμισι χρόνια μετά την εφαρμογή του Προγράμματος Καλλικράτης και την

ΚΩΔΙΚΑΣ ΔΕΟΝΤΟΛΟΓΙΑΣ ΤΗΣ ΕΡΕΥΝΑΣ ΠΑΝΕΠΙΣΤΗΜΙΟ ΚΡΗΤΗΣ. (Εγκρίθηκε στη 299/ Συνεδρίαση της Συγκλήτου)

Τέλος, θα ήθελα να ευχαριστήσω την οικογένειά μου και τους φίλους που με στήριξαν στην προσπάθειά μου αυτή.

ΕΙΔΙΚΑ ΘΕΜΑΤΑ ΠΕΡΙΒΑΛΛΟΝΤΟΣ 7 ο Εξάμηνο

Οδηγίες χρήσης και τοποθέτησης

ΠΡΟΟΔΟΣ ΠΡΟΣΚΟΠΟΥ. Οι διακρίσεις αυτές συνοδεύονται από αντίστοιχο διακριτικό για τη στολή, όπως αυτά

Θέσεις ΤΕΕ για τα Δημόσια Έργα και τις υποδομές τους

ΕΦΗΜΕΡΙΣΤΗΣ ΚΥΒΕΡΝΗΣΕΩΣ

Φυσικό αέριο, χρήσεις, ασφάλεια και οικονομία Ομάδα Μαθητών: Συντονιστές Καθηγητές: Λύκειο Αγίου Αντωνίου Θεωρητικό υπόβαθρο Το Φυσικό αέριο

Καταστατικό του επιστημονικού σωματείου με την επωνυμία ΕΝΤΟΜΟΛΟΓΙΚΗ ΕΤΑΙΡΕΙΑ ΕΛΛΑΔΟΣ. Άρθρο 1 ο Ίδρυση Επωνυμία Έδρα

Βιογραφικό Σημείωμα ΝΙΚΟΣ ΚΟΥΝΔΟΥΡΟΣ

Ξεκινώντας τον απολογισμό της χρήσης του 2014 θα εξετάσουμε ορισμένα θεμελιώδη μεγέθη των Οικονομικών Καταστάσεων στα οποία παρατηρούνται τα εξής:

ΥΠΟΜΝΗΜΑ. Στην Επιτροπή Κρίσεως Βαρέων και Ανθυγιεινών επαγγελμάτων του άρθρου 20 ν.3790/2009

Μπορούμε να πούμε ότι η δεύτερη δύναμη είναι πολύ πιο ισχυρή από την πρώτη.

Εκπαίδευση Ατόμων με Ειδικές Εκπαιδευτικές Ανάγκες Σπονδυλωτό Εξ Αποστάσεως Πρόγραμμα Εξειδίκευσης

Αρχαίοι Έλληνες μαθηματικοί. τους στη θετική σκέψη. Ερευνητική εργασία (Project)

ΔΕΥΤΕΡΟΣ ΕΠΕΡΩΤΩΝ ΕΥΑΓΓΕΛΟΣ ΜΠΑΣΙΑΚΟΣ (ΑΓΡΟΤΙΚΟ ΕΙΣΟΔΗΜΑ)

Ε.Ε. Π α ρ.ι(i), Α ρ.4083, 20/4/2006 ΝΟΜΟΣ ΠΟΥ ΠΡΟΝΟΕΙ ΓΙΑ ΤΗΝ ΕΓΚΑΘΙΔΡΥΣΗ ΑΝΕΞΑΡΤΗΤΗΣ ΕΠΙΤΡΟΠΗΣ ΓΙΑ

ΣΧΟΛΗ ΔΙΟΙΚΗΣΗΣ ΟΙΚΟΝΟΜΙΑΣ. Πτυχια<η Εργασία. του σπουδαστή ΚΟΥΓΙΟΥΜΤΖΙΔΗ ΠΑΝΑΓΙΩΤΗ. Εισηγητής

Πρόταση εκδηλώσεων τουριστικής προβολής

ΥΠΟΥΡΓΟΣ: Καληµέρα σε όλους, καλή χρονιά, να είµαστε καλά, µε υγεία πάνω απ όλα, προσωπική για τον καθένα µας, συλλογική για τη χώρα µας και να

Πρόγραμμα Σπουδών για τα Μαθηματικά στην Υποχρεωτική Εκπαίδευση

ΑΙΤΙΟΛΟΓΙΚΗ ΕΚΘΕΣΗ ΣΤΟ ΣΧΕ ΙΟ ΝΟΜΟΥ «για τη δίκαιη δίκη και την αντιµετώπιση φαινοµένων αρνησιδικίας» Α. ΓΕΝΙΚΟ ΜΕΡΟΣ

ΠΤΥΧΙΑΚΗ ΕΡΓΑΣΙΑ. «Η ΟΡΓΑΝΩΣΕ ΤΟΥ ΤΜΙΙΜΑΤΟΣ ΠΡΟΜΗΘΕΙΩΝ ΣΕ ΜΙΑ ΕΠΙΧΕΙΡΗΣΗ i

Παρράσιο Πάρκο Πολιτιστικής Κληρονομιάς: Σχέδιο της Πρότασης

ME TO ΒΛΕΜΜΑ ΣΤΡΑΜΜΕΝΟ ΣΤΟ ΜΕΛΛΟΝ. ΟΡΙΖΟΥΣΕΣ ΚΑΙ ΠΡΟΣΑΝΑΤΟΛΙΣΜΟΙ ΓΙΑ ΤΗΝ ΕΚΠΑΙΔΕΥΣΗ ΣΤΟΝ 21 ο ΑΙΩΝΑ

Μπάτλερ: Φύλο, εξουσία, ηθική 1/10

Η ΕΡΤ ΤΗΣ ΕΠΟΜΕΝΗΣ ΗΜΕΡΑΣ «ΠΟΙΑ ΕΡΤ ΘΕΛΟΥΜΕ»

ΕΥΡΩΠΑΪΚΟ ΔΙΚΤΥΟ ΣΧΟΛΕΙΩΝ ΠΡΟΑΓΩΓΗΣ ΥΓΕΙΑΣ ΣΧΕΔΙΟ ΔΡΑΣΗΣ

3966/2011 (Φ.Ε.Κ. 118 Α

ΕΠΤΑ ΕΡΩΤΗΣΕΙΣ ΠΡΟΣ ΥΠΟΨΗΦΙΟΥΣ ΕΥΡΩΒΟΥΛΕΥΤΕΣ

ΑΣΠΙΔΑ ΕΝΕΡΓΕΙΑΚΩΝ ΣΥΜΦΕΡΟΝΤΩΝ ΓΥΡΩ ΑΠΟ ΤΗΝ ΚΥΠΡΟ ΑΣΦΑΛΕΙΑ ΝΕΟ ΓΕΩΠΟΛΙΤΙΚΟ ΠΕΡΙΒΑΛΛΟΝ ΕΝΕΡΓΕΙΑΚΗ ΠΡΟΜΗΘΕΙΑ ΕΕ ΕΛΕΝΗ ΘΕΟΧΑΡΟΥΣ

Μάιος 2010 Ο ΗΓΟΣ ΠΡΟΓΡΑΜΜΑΤΟΣ ΠΡΟΓΡΑΜΜΑ ΠΟΛΙΤΙΣΜΟΣ ( ) Γενική ιεύθυνση Εκπαίδευσης και Πολιτισµού

Εκατοστή τριακοστή τρίτη ηλεκτρονική έκδοση εβδομαδιαίας εφημερίδας του Υπουργείου Διοικητικής Μεταρρύθμισης και Ηλεκτρονικής Διακυβέρνησης

2 Η απασχόληση στον τομέα του εμπορίου: Διάρθρωση και εξελίξεις

Περιεχόμενα ΕΙΣΑΓΩΓΗ ΕΙΔΟΠΟΙΗΣΗ ΜΕΣΩ ΗΛΕΚΤΡΟΝΙΚΟΥ ΤΑΧΥΔΡΟΜΕΙΟΥ... 3

ΚΟΙΝΗ ΑΓΡΟΤΙΚΗ ΠΟΛΙΤΙΚΗ

ΝΕΟΕΛΛΗΝΙΚΗ ΙΣΤΟΡΙΑ ΘΕΩΡΗΤΙΚΗΣ ΚΑΤΕΥΘΥΝΣΗΣ Γ ΤΑΞΗΣ ΕΝΙΑΙΟΥ ΛΥΚΕΙΟΥ 2002

Θα ήθελα να συγχαρώ καταρχήν τους διοργανωτές της σημερινής ημερίδας για την πρωτοβουλία που ανέλαβαν. σε ένα ζήτημα που μας αφορά όλους.

ΘΕΜΑ : ΑΝΑΠΤΥΞΗ ΕΦΑΡΜΟΓΗΣ ΒΑΣΗΣ ΔΕΔΟΜΕΝΩΝ ΓΙΑ ΤΟΝ ΥΠΕΥΘΥΝΟ ΣΙΤΙΣΗΣ ΚΑΙ ΣΤΕΓΑΣΗΣ ΤΟΥ Α.Τ.Ε.Ι. ΚΑΒΑΛΑΣ

ΕΛΛΗΝΙΚΗ ΔΗΜΟΚΡΑΤΙΑ ΑΘΗΝΑ,

ΔΙΑΔΙΚΑΣΙΑ ΣΥΜΒΟΥΛΟΙ ΕΠΙΧΕΙΡΗΣΕΩΝ Α.Ε. ΟΙΚΟΝΟΜΙΚΕΣ ΚΑΤΑΣΤΑΣΕΙΣ της χρήσης. 1η Ιανουαρίου 2012 έως 31η Δεκεμβρίου 2012

ΕΡΩΤΗΣΕΙΣ ΕΞΕΤΑΣΕΩΝ ΧΕΙΡΙΣΤΗ ΤΑΧΥΠΛΟΟΥ ΣΚΑΦΟΥΣ

ΔΙΑΚΗΡΥΞΗ ΠΡΟΧΕΙΡΟΥ ΔΙΑΓΩΝΙΣΜΟΥ ΓΙΑ ΤΗΝ ΠΡΟΜΗΘΕΙΑ ΗΛΕΚΤΡΟΝΙΚΩΝ ΥΠΟΛΟΓΙΣΤΩΝ ΚΑΙ ΠΕΡΙΦΕΡΕΙΑΚΩΝ ΣΥΣΚΕΥΩΝ

Ένας πρακτικός οδηγός για επενδύσεις στα φωτοβολταϊκά μετά την ψήφιση του νέου νόμου (Ν.3851/2010) για τις ΑΠΕ

Επιμέλεια εργασίας: Ιωάννης Τραγουδάρας Αριθμός Μητρώου

ΠΑΝΕΠΙΣΤΗΜΙΟ ΠΕΛΟΠΟΝΝΗΣΟΥ ΤΜΗΜΑ ΠΟΛΙΤΙΚΗΣ ΕΠΙΣΤΗΜΗΣ & ΔΙΕΘΝΩΝ ΣΧΕΣΕΩΝ ΕΡΓΑΣΙΑ ΜΑΘΗΜΑ: ΕΛΛΗΝΙΚΟ ΠΟΛΙΤΙΚΟ ΣΥΣΤΗΜΑ

ΔΗΛΩΣΗ ΤΗΣ ΟΛΓΑΣ ΜΟΥΣΙΟΥ-ΜΥΛΩΝΑ ΓΙΑ ΤΗ ΣΥΝΕΝΤΕΥΞΗ ΤΟΥ ΠΡΟΕΔΡΟΥ ΤΗΣ ΜΕΛΙΤΗΣ κ. Π. ΑΝΑΣΤΑΣΙΑΔΗ

Τεύχος 24 / Φεβρουάριος Ηλεκτρονική Έκδοση ΕΡΓΑΤΙΚΗ & ΑΣΦΑΛΙΣΤΙΚΗ ΕΝΗΜΕΡΩΣΗ ΒΙΒΛΙΟ ΤΡΟΠΟΠΟΙΗΣΗΣ ΩΡΑΡΙΟΥ ΚΑΙ ΥΠΕΡΩΡΙΩΝ.

Κώδικας Δεοντολογίας ΜΔΜ και ΗΠΔΜ Έκδοση 1 ΕΛΛΗΝΙΚΟ ΑΝΟΙΚΤΟ ΠΑΝΕΠΙΣΤΗΜΙΟ ΟΛΥΜΠΙΑΚΗ ΕΚΠΑΙΔEYTIKH ΚΑΙ ΣΥΜΒΟΥΛΕΥΤΙΚΗ Ε.Π.Ε.

ΕΛΛΗΝΙΚΗ ΔΗΜΟΚΡΑΤΙΑ ΥΦΥΠΟΥΡΓΟΣ ΠΑΡΑ ΤΩ ΠΡΩΘΥΠΟΥΡΓΩ ΚΥΒΕΡΝΗΤΙΚΗ ΕΚΠΡΟΣΩΠΟΣ

Transcript:

ΠΑΝΕΠΙΣΤΗΜΙΟ ΠΕΙΡΑΙΩΣ ΤΜΗΜΑ ΨΗΦΙΑΚΩΝ ΣΥΣΤΗΜΑΤΩΝ ΠΜΣ ΔΙΔΑΚΤΙΚΗΣ ΤΗΣ ΤΕΧΝΟΛΟΓΙΑΣ ΚΑΙ ΨΗΦΙΑΚΑ ΣΥΣΤΗΜΑΤΑ Κατεύθυνση: Δικτυοκεντρικά Συστήματα Μάθημα: Δικτυακός Προγραμματισμός Ακαδημαϊκό έτος: 2011-2012 Διδάσκων: Νικήτας-Μαρίνος Σγούρος Ανάπτυξη δικτυακού παιχνιδιού με δυνατότητα συμμετοχής ακροατηρίου. Μεταπτυχιακοί Φοιτητές Κυριάζος Σπυρίδων Τσιτσιπάς Αθανάσιος Αριθμός Μητρώου ΜΕ/11060 ΜΕ/11072 ΠΕΙΡΑΙΑΣ Ιούνιος 2012

Πίνακας περιεχομένων 1. Εισαγωγή... 3 2. Java... 4 2.1 Εισαγωγή... 4 2.2 Η Java Πλατφόρμα... 5 2.3 Threads... 6 2.4 Sockets - Το μοντέλο Client - Server και μερικοί ορισμοί... 7 3. Αρχιτεκτονική Εφαρμογής... 10 4. Υλοποίηση... 11 5. Εγχειρίδιο Χρήστη (User Manual)... 27 6. Βιβλιογραφία... 29 2

1. Εισαγωγή Η παρούσα εργασία αναφέρεται στην ανάπτυξη δικτυακής εφαρμογής με την δυνατότητα συμμετοχής ακροατηρίου. Δίνει την δυνατότητα στο χρήστη να φιλοξενήσει ένα παιχνίδι είτε να μπεί σε ένα παιχνίδι δίνοντας και την IP στην οποία θέλει να συνδεθεί. Αφού έχει σηκωθεί ο server του παιχνιδιού και μπει ο client θα εμφανιστούν δύο παράθυρα, ένα που αφορά το παιχνίδι και ένα για περιοχή άμεσων συζητήσεων( chat ). Για την ανάπτυξη της εφαρμογής χρησιμοποιήθηκε η γλώσσα προγραμματισμού JAVA. 3

2. Java 2.1 Εισαγωγή Η ραγδαία εξάπλωση του Internet και του World-Wide Web δημιούργησαν την ανάγκη νέων τρόπων ανάπτυξης και διανομής του λογισμικού. Οι απαιτήσεις αυτές οδήγησαν στην δημιουργία της γλώσσας προγραμματισμού Java, από την εταιρία Sun microsystems TM. Η Java σχεδιάστηκε με σκοπό την ανάπτυξη εφαρμογών που θα τρέχουν σε ετερογενή δικτυακά περιβάλλοντα. Η Java έχει τα ακόλουθα χαρακτηριστικά Αντικειμενοστραφής (ομοιότητες εντολών με τη C++). Δημιουργία ανεξάρτητων εφαρμογών και applets (applet = προγράμματα που περιλαμβάνονται σε HTML σελίδες και εκτελούνται από τον Web Browser). Είναι Interpreted γλώσσα. Αυτό σημαίνει ότι ο java compiler δεν παράγει εκτελέσιμο κώδικα αλλά μια μορφή ψευδοκώδικα (bytecode) το οποίο από μόνο του δεν τρέχει σε καμία μηχανή. Προκειμένου λοιπόν να εκτελεστεί απαιτείται η χρήση ενός interpreter (=διερμηνέα) για να μετατρέψει το bytecode σε πραγματικό εκτελέσιμο κώδικα. Αυτό το χαρακτηριστικό δίνει τη δυνατότητα στα java bytecodes να μπορούν να τρέξουν σε οποιοδήποτε μηχάνημα, κάτω από οποιοδήποτε λειτουργικό, αρκεί να έχει εγκατασταθεί ένας java interpreter. Επίσης ένα άλλο χαρακτηριστικό του java bytecode είναι το μικρό του μέγεθος, (μόλις λίγα Kilobytes). Αυτό το κάνει ιδανικό για μετάδοση μέσω του δικτύου. Κατανεμημένη (distributed). Δηλαδή ένα πρόγραμμα σε Java είναι δυνατό να το φέρουμε από το δίκτυο και να το τρέξουμε. Επίσης είναι δυνατό διαφορετικά κομμάτια του προγράμματος να έρθουν από διαφορετικά sites. Ασφαλής (secure). Στο δίκτυο όμως ελλοχεύουν πολλοί κίνδυνοι για τον χρήστη - παραλήπτη μιας δικτυακής εφαρμογής, γι' αυτό η Java έχει σχεδιαστεί έτσι ώστε να ελαχιστοποιείται η πιθανότητα προσβολής του συστήματος του χρήστη από κάποιο applet γραμμένο για τέτοιο σκοπό. Είναι multithreaded. Η Java υποστηρίζει εγγενώς την χρήση πολλών threads. Προκειμένου να το επιτύχει αυτό σε συστήματα με έναν επεξεργαστή, το Java runtime system (interpreter) υλοποιεί ένα δικό χρονοδρομολογητή (scheduler), ενώ σε συστήματα που υποστηρίζουν πολυεπεξεργασία η δημιουργία των threads 4

ανατίθεται στο λειτουργικό σύστημα. Φυσικά όλα αυτά είναι αόρατα τόσο στον προγραμματιστή όσο και στον χρήστη. Υποστηρίζει multimedia εφαρμογές. Με αυτό εννοούμε ότι η Java παρέχει ευκολίες στη δημιουργία multimedia εφαρμογών. Αυτό επιτυγχάνεται τόσο με την ευελιξίας της σαν γλώσσα όσο και με τις πλούσιες και συνεχώς εμπλουτιζόμενες βιβλιοθήκες της. 2.2 Η Java Πλατφόρμα Πλατφόρμα είναι το hardware ή software περιβάλλον όπου τρέχει ένα πρόγραμμα. Η Java πλατφόρμα διαφέρει από τις άλλες πλατφόρμες, γιατί είναι μία software-only πλατφόρμα που τρέχει πάνω από άλλες hardware πλατφόρμες. Οι υπόλοιπες πλατφόρμες περιγράφονται σαν συνδυασμός hardware και software.η Java πλατφόρμα έχει δύο στοιχεία: την Java Virtual Machine (JVM) και το Java Application Programming Interface (JavaAPI).Java Virtual Machine (JVM): Η Java παρέχει την δυνατότητα "write once, run everywhere" μέσω της JVM. Η JVM εφαρμόζεται πάνω από το λειτουργικό σύστημα της μηχανής και τα προγράμματα σε Java τρέχουν πάνω από την virtual machine. Σκοπός της JVM είναι η απομόνωση του προγράμματος από τις διαφορές μεταξύ των υποκείμενων λειτουργικών συστημάτων και CPUs. Η JVM ήταν αρχικά διαθέσιμη σε Web browsers και αυτήν την στιγμή υπάρχουν εκδόσεις για τα περισσότερα λειτουργικά συστήματα, όπως Windows 3.1/95/98/NT, MacOS και OS/2 Warp. Εικόνα 1 Java Virual Machine 5

JavaApplication Programming Interface (JavaAPI): Είναι μια συλλογή από έτοιμα λογισμικά εργαλεία που προσφέρουν πολλές χρήσιμες δυνατότητες (π.χ. Graphical User Interface GUI). Το Java API είναι ομαδοποιημένο σε βιβλιοθήκες συσχετιζόμενων εργαλείων. Τα προγράμματα σε Java, λόγω της συμβατότητας τους με όλα είδη υπολογιστών, μπορεί να είναι λίγο πιο αργά σε εκτέλεση από ότι τα προγράμματα σε τοπική γλώσσα μηχανής. Η χρήση, όμως, just-in-time-compilers εξαλείφει και αυτό το πρόβλημα. 2.3 Threads Πολλές γλώσσες προγραμματισμού όπως και η Java διαθέτουν εργαλεία για την υλοποίηση threads στα προγράμματά τους. Αυτές οι γλώσσες καλούνται multithreading languages. Στον παραδοσιακό προγραμματισμό όταν ένα πρόγραμμα εκτελείται ονομάζεται process (διεργασία) και οι εντολές του εκτελούνται σειριακά η μία μετά την άλλη μέχρι το τέλος του. Σ αυτή την περίπτωση μπορούμε να πούμε οτι το συγκεκριμένο process διαθέτει μόνο ένα thread που εκτελεί τις εντολές του προγράμματος. Στις multithreading γλώσσες προγραμματισμού μπορούμε να ορίσουμε σε κάποιο process να περιέχει ένα ή και περισσότερα threads (ονομάζονται και lightweight processes) οι οποίες εκτελούν κάθε μια ξεχωριστά τον κώδικα του προγράμματος. processes που εκτελούνται παράλληλα μέσα στο αρχικό process. Είναι δηλαδή σαν να έχουμε πολλά Οι ενέργειες που λαμβάνουν χώρα κατά την εκτέλεση ενός Thread ορίζονται στη μέθοδο run του Thread. Μετά από την δημιουργία και την αρχικοποίηση ενός Thread το σύστημα εκτελεί αυτόματα τον κώδικα που υπάρχει στη μέθοδο run. Συνήθως η μέθοδος αυτή περιέχει κάποια επαναληπτική δομή δημιουργούμε: Υπάρχουν δυο τρόποι για τον ορισμό της run μεθόδου κάποιας Thread που Δημιουργία υποκλάσης της κλάσης Thread και υπερκάλυψη (overriding) της run μεθόδου που υπάρχει στην Thread κλάση. Δημιουργία κλάσης που υλοποιεί το Runnable interface. Σ αυτή την περίπτωση όταν δημιουργούμε την Thread πρέπει να της δώσουμε και μια αναφορά-δείκτη σε στιγμιότυπο της κλάσης που υλοποιεί το interface. Runnable 6

H java χρησιμοποιεί τα monitors για να παρέχει συγχρονισμό στα αντικείμενά της. Ένα αντικείμενο που περιέχει synchnonized μεθόδους θεωρείται αντικείμενο τύπου monitor. Ένα αντικείμενο τύπου monitor επιτρέπει σε ένα μόνο thread κάθε στιγμή να εκτελεί μια synchronized μέθοδο αυτού του αντικειμένου. Έτσι όταν καλείται κάποια synchronized μέθοδος ενός αντικειμένου τότε το αντικείμενο κλειδώνεται για αυτό το thread και δεν μπορεί να κληθεί καμία άλλη synchronized μέθοδος στο συγκεκριμένο αντικείμενο από κάποιο άλλο thread. Μη-synchronized μέθοδοι μπορούν να κληθούν κανονικά. Μετά το τέλος της εκτέλεσης μιας synchronized μεθόδου το αντικείμενο ξεκλειδώνεται. Μια thread που εκτελεί μια synchronized μέθοδο μπορεί να σταματήσει την εκτέλεσή της μόνο στην περίπτωση που από τον κώδικα της μεθόδου κληθεί η wait(). Σε μια τέτοια περίπτωση το thread μπαίνει σε κατάσταση wait για το συγκεκριμένο monitor αντικείμενο ενώ το αντικείμενο ξεκλειδώνεται. Όταν ένα thread εκτελέσει από τον κώδικα μιας synchronized μεθόδου, την μέθοδο notify(), τότε ξυπνά ένα thread που βρισκόταν σε κατάσταση wait για το monitor αντικείμενο. Το ξυπνημένο thread, δεν θα είναι σε θέση να εκτελεσθεί, έως ότου το τρέχον thread τελειώσει την εκτέλεση της synchronized μεθόδου - δηλαδή ξεκλειδώσει το monitor αντικείμενο. Εάν πολλά thread περιμένουν σε αυτό το αντικείμενο, ένα μόνο από αυτά επιλέγεται για να ξυπνήσει - η επιλογή γίνεται αυθαίρετα από το σύστημα. Η μέθοδος notifyall(), ξυπνά όλα τα threads που βρίσκονται σε κατάσταση wait για το συγκεκριμένο monitor αντικείμενο. Οι μέθοδοι wait(), notify(), notifyall() ορίζονται στην κλάση java.lang.object. 2.4 Sockets - Το μοντέλο Client - Server και μερικοί ορισμοί Το ευρύτερα διαδεδομένο μοντέλο ανάπτυξης δικτυακών εφαρμογών είναι το μοντέλο του πελάτη - εξυπηρετητή ( client - server ). Ο εξυπηρετητής είναι μια διεργασία, η οποία εκτελείται σε έναν υπολογιστή και αναμένει να συνδεθεί σε αυτήν κάποιο πρόγραμμα - ο πελάτης, όπως ονομάζεται -, για να του παράσχει υπηρεσίες. Ένα τυπικό σενάριο που ακολουθείται συνήθως, είναι το εξής : 7

Η διεργασία - εξυπηρετητής αρχίζει να εκτελείται σε κάποιον υπολογιστή. Μετά την αρχικοποίησή της, πέφτει σε λήθαργο, αναμένοντας μία διεργασία - πελάτη να επικοινωνήσει μαζί της και να της ζητήσει κάποια υπηρεσία. Μία διεργασία - πελάτης αρχίζει να εκτελείται, είτε στο ίδιο σύστημα, είτε σε κάποιο απομακρυσμένο, το οποίο συνδέεται με τον υπολογιστή στον οποίο τρέχει ο εξυπηρετητής μέσω δικτύου. Η διεργασία πελάτης στέλνει μια αίτηση, μέσω του δικτύου, στον εξυπηρετητή, ζητώντας του κάποιου είδους υπηρεσία ( π.χ. μεταφορά αρχείου, απομακρυσμένη εκτύπωση, ανάγνωση και αποστολή mail και άλλες ). Ταυτόχρονα με την εξυπηρέτηση κάποιου πελάτη, ο server έχει την δυνατότητα να δέχεται και αιτήσεις άλλων πελατών προς εξυπηρέτηση. Όταν ο εξυπηρετητής τελειώσει με όλους τους πελάτες, τότε ξαναπέφτει σε λήθαργο, περιμένοντας για μια καινούργια αίτηση και η διαδικασία ξαναρχίζει από την αρχή. Ορίζουμε ως σύνδεση, τον επικοινωνιακό δίαυλο μεταξύ δύο διεργασιών. Την σύνδεση μπορούμε να την θεωρήσουμε ως μία πεντάδα, που περιγράφεται ως εξής : { πρωτόκολλο, τοπική-διεύθυνση, τοπική-διεργασία, απομακρυσμένη-διεύθυνση, απομακρυσμένη-διεργασία Το πρωτόκολλο αναφέρεται στο σύνολο των κανόνων που διέπουν την επικοινωνία. Η τοπική-διεύθυνση και απομακρυσμένη-διεύθυνση, προσδιορίζουν την ταυτότητα των υποδικτύων και των υπολογιστών, στους οποίους εκτελούνται οι επικοινωνούσες διεργασίες. Η τοπική-διεργασία και απομακρυσμένη-διεργασία, προσδιορίζουν την ταυτότητα των διεργασιών που θα επικοινωνούν, καθώς σε έναν υπολογιστή, μπορούν να εκτελούνται περισσότερες της μιας διεργασίες. Κάθε μία από αυτές τις διεργασίες που εκτελούνται στον ίδιο host και που χρειάζονται επικοινωνία μέσω δικτύου, λαμβάνει έναν 16-bit ακέραιο αριθμό, ο οποίος αναπαριστά την θύρα ( port number ) της διεργασίας και κατ επέκταση, της υπηρεσίας. Ορίζουμε, επίσης ως μισή σύνδεση ( half association ), είτε το σύνολο { πρωτόκολλο, τοπική- διεύθυνση, τοπική-διεργασία, είτε το σύνολο { πρωτόκολλο, απομακρυσμένηδιεύθυνση, απομακρυσμένη-διεργασία. Η μισή σύνδεση ονομάζεται αλλιώς και socket. 8

Oρισμός : Socket είναι το ένα άκρο, από έναν επικοινωνιακό δίαυλο διπλής κατεύθυνσης, μεταξύ δύο προγραμμάτων που εκτελούνται στο δίκτυο. Περιλαμβάνει το πρωτόκολλο, την διεύθυνση και τον αριθμό θύρας του άκρου. Κάθε πρόγραμμα διαβάζει από και γράφει σε ένα socket, με τρόπο παρόμοιο της εγγραφής και ανάγνωσης αρχείων του file system. Υπάρχουν δύο είδη sockets : Tο πρώτο ονομάζεται TCP ( Transmission Control Protocol ) socket και είναι μια υπηρεσία προσανατολισμένη στην σύνδεση ( connection-oriented service ). Μπορούμε να το θεωρήσουμε ανάλογο της τηλεφωνικής υπηρεσίας, στην οποία, μετά την εγκαθίδρυση μιας σύνδεσης μεταξύ δύο συνομιλητών, αυτή χρησιμοποιείται μέχρι το πέρας της συζητήσεως τους. Το άλλο είδος ονομάζεται UDP (Unreliable Datagram Protocol ) socket και είναι μια υπηρεσία χωρίς σύνδεση ( connectionless service ). To ανάλογο, σε αυτήν την περίπτωση, είναι το ταχυδρομείο : μπορούμε να στείλουμε πολλά πακέτα στον ίδιο παραλήπτη, αλλά δεν είναι σίγουρο ότι όλα θα ακολουθήσουν την ίδια διαδρομή ( σύνδεση ) για να φτάσουν στον προορισμό τους. Μία ακόμη σημαντική διαφορά, μεταξύ των παραπάνω δύο ειδών, είναι ότι τα TCP sockets εξασφαλίζουν μια αξιόπιστη μεταφορά της πληροφορίας : ότι αποστέλλεται από το ένα άκρο είναι σίγουρο ότι θα φτάσει στο άλλο. Στο UDP socket όμως δεν συμβαίνει αυτό. Είναι στην ευθύνη του αποστολέα να ελέγξει ότι αυτό που έστειλε, το έλαβε τελικά ο παραλήπτης και δεν χάθηκε στον δρόμο. Από την άλλη, η σύνδεση με TCP socket απαιτεί την ανταλλαγή τριών πακέτων χειραψίας ( handshake packets ) και είναι πιο χρονοβόρα στην αρχικοποίησή της από την αντίστοιχη με UDP datagrams. Οι προηγούμενες δύο διαφορές καθορίζουν τελικά και την χρήση των δύο αυτών ειδών. Για την αποφυγή σύγχυσης, να σημειώσουμε ότι ειδικά στην Java, ο όρος Socket χρησιμοποιείται για τα TCP sockets, στην ονοματολογία των κλάσεων και των μεθόδων, ενώ για την δήλωση των UDP sockets, χρησιμοποιείται ο όρος Datagram. 9

3. Αρχιτεκτονική Εφαρμογής Στο κεφάλαιο αυτό θα αναλύσουμε την αρχιτεκτονική της εφαρμογής, δηλαδή το μοντέλο και πως έχει δομηθεί σε διάφορες κλάσεις. Υπάρχουν κλάσεις βασικές για το παιχνίδι όπως η κλαση Entity η οποία περιλαμβάνει παραμέτρους και μεθόδους που κληρονομεί η κλάση FighterEntity. Για την προβολή και τα γραφικά του μαχητή χρησιμοποιούνται Sprites το οποίο είναι ένα βασικό οπτικό στοιχείο που μπορεί να αποδίδεται με ένα από τα πολλά καρέ τα οποία αποθηκεύονται σε μια εικόνα. Στην κλάση Client περιλαμβάνονται μέθοδοι που αναγνωρίζουν τον κάθε ένα ξεχωριστά με τρόπους αν φαίνεται οτι παίζει στο παιχνίδι αν βρίσκεται στην ουρά για να παίξει ή αν είναι δεύτερος παίχτης στο παιχνίδι ώστε να οριστεί οτι θα είναι απο τα δεξιά για να αλλάξει και το Sprite ανάλογα. Απο την μερία του Client περιλαμβάνει τις κλάσεις ClientApp, ClientReceiveThread, ClientGameLoop. Στην ClientReceiveThread δέχεται τα δεδομένα που αφορούν τον συγχρονισμό των threads των παικτών του παιχνιδιού. Επίσης στην κλάση ClientGameLoop ζωγραφίζει στο χώρο τους παικτες και τις θέσεις τους και τα στέλνει στο server. 10

Στον server υπάρχουν οι κλάσεις ServerApp, ServerReceiveThread, ServerGameLoop, ServerSyncThread. Στην κλάση ServerGameLoop υπάρχει όλη η λογική του παιχνιδιου που υπολογίζονται οι θέσεις, ο τρόπος που κινούνται και κάνουν χτυπήματα. Στην ServerSyncThread δέχεται ώς είσοδο τιμές που εξάγονται απο την κλάση ServerGameLoop και τα στέλνει ώς είσοδο στους clients. Και στην ServerReceiveThread δέχεται είσοδο απο τον client και τα δίνει ώς είσοδο στην ServerGameLoop ξεκινήσει η επεξεργασία για την λογική του παιχνιδιού για τον client. για να 4. Υλοποίηση Στο κεφάλαιο αυτό θα παρουσιάζεται ο κώδικας υλοποιήσης με τα κατάλληλα σχόλια για κατανόηση του κώδικα. Παρουσιάζονται 9 βασικές κλάσεις της εφαρμογής. GameMain public class GameMain { public static void main(string[] args) { int choice = JOptionPane.showOptionDialog(null, "Host a game or join an existing one?", "Msc Fighter Game", JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE, null, new Object[]{"Host", "Join", null); if (choice == JOptionPane.YES_OPTION) { JFrame jframe = new JFrame(); jframe.setsize(150, 100); jframe.setvisible(true); Button stopbutton = new Button("stop"); final ChatServer cs = new ChatServer(); Thread t1 = new Thread() { /* * Initialize the chat Server public void run() { cs.init(); ; final ServerApp app = new ServerApp(); Thread t2 = new Thread() { /* * Initialize the game Server public void run() { app.init(); app.start(); ; 11

t1.start(); t2.start(); stopbutton.addactionlistener(new ActionListener() { public void actionperformed(actionevent e) { System.out.println("stop?"); // cs.stop(); app.stop(); System.exit(0); ); jframe.add(stopbutton); jframe.addwindowlistener(new WindowAdapter() { public void windowclosing(windowevent e) { System.exit(0); ); else if (choice == JOptionPane.NO_OPTION) { final String ip = JOptionPane.showInputDialog("Host IP:", "127.0.0.1"); Thread t1 = new Thread() { /* * Initialize the chat client public void run() { ChatClientGUI chatclientgui = new ChatClientGUI(ip); chatclientgui.init(); ; Thread t2 = new Thread() { /* * Initialize the game client public void run() { ClientApp app = new ClientApp(); app.init(globalstatics.port, ip); ; t1.start(); t2.start(); Client public class Client { private String username; private boolean isplaying;//is in match private boolean isinqueue = true;//waiting to play private int id; private Socket socket; private FighterEntity fighterentity; private boolean isright; public Client(String username, int id, Socket socket) { this.username = username; this.id = id; this.socket = socket; 12

//<editor-fold defaultstate="collapsed" desc="getters setters"> public int getid() { return id; public void setid(int id) { this.id = id; public boolean isinqueue() { return isinqueue; public void setisinqueue(boolean isinqueue) { this.isinqueue = isinqueue; public boolean isisplaying() { return isplaying; public void setisplaying(boolean isplaying) { this.isplaying = isplaying; public String getusername() { return username; public void setusername(string username) { this.username = username; public Socket getsocket() { return socket; public void setsocket(socket socket) { this.socket = socket; public FighterEntity getfighterentity() { return fighterentity; public void setfighterentity(fighterentity fighterentity) { this.fighterentity = fighterentity; public boolean isisright() { return isright; public void setisright(boolean isright) { this.isright = isright; //</editor-fold> ClientApp /** * connect to server and initialize threads public class ClientApp { //default ip public static String servername = "127.0.0.1"; public void init(int port, String servername){ // connecting to server System.out.println("Establishing connection. Please wait..."); Socket socket = new Socket(serverName, port); System.out.println("Connected: " + socket); // initialize game loop thread ClientGameLoop clientgameloop = new ClientGameLoop(socket); 13

clientgameloop.start(); // initialize thread tha receives from input from server ClientReceiveThread clientreceivethread = new ClientReceiveThread(socket, clientgameloop); clientreceivethread.start(); catch (Exception ex) { Logger.getLogger(ClientApp.class.getName()).log(Level.SEVERE, null, ex); public static void main(string[] args) { ClientApp app = new ClientApp(); app.init(globalstatics.port, servername); ClientGameLoop /** * receive input, send input, paint public class ClientGameLoop extends Canvas implements Runnable { private Socket socket; private ObjectOutputStream objectoutputstream; private boolean running = true; //movement booleans private boolean leftclickpressed = false; private boolean rightclickpressed = false; private boolean leftpressed = false; private boolean rightpressed = false; private boolean jumppressed = false; private int id; //fighter entities private FighterEntity leftfighter; private FighterEntity rightfighter; //health bars private Rectangle lefthealthbar; private Rectangle righthealthbar; //used for drawing private BufferStrategy strategy; //window private JFrame container; //contains received messages from server per client id private HashMap<Integer, SyncMessage> syncmap; private final int healthbarheight = 20; public ClientGameLoop(Socket socket) { this.socket = socket; /* * initialize output stream, window, key and mouse listeners, graphics * and entities objectoutputstream = new ObjectOutputStream(socket.getOutputStream()); catch (IOException ex) { Logger.getLogger(ClientGameLoop.class.getName()).log(Level.SEVERE, null, ex); initwindow(); addkeylistener(new KeyInputHandler()); addmouselistener(new MouseInputAdapter()); requestfocus(); initgraphics(); 14

initentities(); syncmap = new HashMap<Integer, SyncMessage>(); public void setsyncmessage(syncmessage sm) { syncmap.put(sm.getid(), sm); /** * used in new match public void resetsyncmap() { syncmap = new HashMap<Integer, SyncMessage>(); public void setid(int id) { this.id = id; private void initwindow() { container = new JFrame("New Game!!!!!"); JPanel panel = (JPanel) container.getcontentpane(); panel.setpreferredsize(new Dimension(GlobalStatics.W_WIDTH + 10, GlobalStatics.W_HEIGHT)); panel.setlayout(null); setbounds(0, 0, GlobalStatics.W_WIDTH, GlobalStatics.W_HEIGHT); panel.add(this); panel.setalignmentx(center_alignment); panel.setalignmenty(center_alignment); setignorerepaint(true); container.setlocation(100, 150); container.pack(); container.setresizable(false); container.setvisible(true); container.addwindowlistener(new WindowAdapter() { public void windowclosing(windowevent e) { System.exit(0); ); private void initgraphics() { createbufferstrategy(2); strategy = getbufferstrategy(); public final void initentities() { // initialize and set positions to entities and health bars leftfighter = new FighterEntity(null, 50, 50, false); rightfighter = new FighterEntity(null, GlobalStatics.W_WIDTH - 50-60, 50, true); lefthealthbar = new Rectangle(GlobalStatics.maxHealthPoints * 9, healthbarheight); lefthealthbar.setlocation(5, 5); righthealthbar = new Rectangle(GlobalStatics.maxHealthPoints * 9, healthbarheight); righthealthbar.setlocation(globalstatics.w_width - (GlobalStatics.maxHealthPoints * 9) - 5, 5); public void run() { long lastlooptime = System.currentTimeMillis(); while (running) { 15

long delta = System.currentTimeMillis() - lastlooptime; lastlooptime = System.currentTimeMillis(); Graphics2D g2d = (Graphics2D) strategy.getdrawgraphics(); //bg color g2d.setcolor(color.white); g2d.fillrect(0, 0, GlobalStatics.W_WIDTH, GlobalStatics.W_HEIGHT); //send to server InputMessage im = new InputMessage( leftclickpressed, rightclickpressed, leftpressed, rightpressed, jumppressed, delta); // System.out.println(id + " sending: " + leftpressed + rightpressed); objectoutputstream.writeobject(im); objectoutputstream.flush(); catch (IOException ex) { Logger.getLogger(ClientGameLoop.class.getName()).log(Level.SEVERE, null, ex); // iterate sync messages and set values in entities for (Iterator<SyncMessage> it = syncmap.values().iterator(); it.hasnext();) { SyncMessage sm = it.next(); if (sm.getisright()) { rightfighter.setx(sm.getx()); rightfighter.sety(sm.gety()); if (sm.getisatk()) { rightfighter.setisatk(true); rightfighter.attack(); else { rightfighter.setisatk(false); rightfighter.look(); rightfighter.setisdef(sm.getisdef()); rightfighter.sethealthpoints(sm.gethealth()); else { leftfighter.setx(sm.getx()); leftfighter.sety(sm.gety()); if (sm.getisatk()) { leftfighter.setisatk(true); leftfighter.attack(); else { leftfighter.setisatk(false); leftfighter.look(); leftfighter.setisdef(sm.getisdef()); leftfighter.sethealthpoints(sm.gethealth()); //paint leftfighter.draw(g2d); rightfighter.draw(g2d); g2d.setcolor(color.red); lefthealthbar.setsize((leftfighter.gethealthpoints() * 9), (int) lefthealthbar.getheight()); righthealthbar.setsize((rightfighter.gethealthpoints() * 9), (int) lefthealthbar.getheight()); righthealthbar.setlocation(globalstatics.w_width - ((rightfighter.gethealthpoints() * 9)) - 5, 5); g2d.fill(lefthealthbar); g2d.fill(righthealthbar); 16

// clear up the graphics // and flip the buffer over g2d.dispose(); strategy.show(); //finally pause for a bit Thread.sleep(GlobalStatics.gameTick); catch (Exception e) { public void stop() { running = false; public void start() { Thread t = new Thread(this); t.start(); //<editor-fold defaultstate="collapsed" desc="input handling"> private class MouseInputAdapter extends MouseAdapter { public void mousepressed(mouseevent e) { super.mousepressed(e); if (e.getbutton() == MouseEvent.BUTTON1) { leftclickpressed = true; else if (e.getbutton() == MouseEvent.BUTTON2) { rightclickpressed = true; public void mousereleased(mouseevent e) { super.mousereleased(e); if (e.getbutton() == MouseEvent.BUTTON1) { leftclickpressed = false; else if (e.getbutton() == MouseEvent.BUTTON2) { rightclickpressed = false; private class KeyInputHandler extends KeyAdapter { public void keypressed(keyevent e) { super.keypressed(e); if (e.getkeycode() == KeyEvent.VK_A) { leftpressed = true; if (e.getkeycode() == KeyEvent.VK_D) { rightpressed = true; if (e.getkeycode() == KeyEvent.VK_SPACE) { jumppressed = true; if (e.getkeycode() == KeyEvent.VK_W) { jumppressed = true; public void keyreleased(keyevent e) { super.keyreleased(e); 17

if (e.getkeycode() == KeyEvent.VK_A) { leftpressed = false; if (e.getkeycode() == KeyEvent.VK_D) { rightpressed = false; if (e.getkeycode() == KeyEvent.VK_SPACE) { jumppressed = false; if (e.getkeycode() == KeyEvent.VK_W) { jumppressed = false; public void keytyped(keyevent e) { super.keytyped(e); if (e.getkeychar() == 27) {//esc System.exit(0); //</editor-fold> ClientReceiveThread /** * waits for sync from server public class ClientReceiveThread implements Runnable { private ClientGameLoop clientgameloop; private Socket socket; private boolean receiverunning = true; private ObjectInputStream ois; private int id; public ClientReceiveThread(Socket socket, ClientGameLoop clientgameloop) { this.socket = socket; this.clientgameloop = clientgameloop; ois = new ObjectInputStream(socket.getInputStream()); catch (IOException ex) { Logger.getLogger(ClientReceiveThread.class.getName()).log(Level.SEVERE, null, ex); public void run() { /* * receive id IdMessage idmessage = (IdMessage) ois.readobject(); id = idmessage.getid(); clientgameloop.setid(id); while (receiverunning) { Message m = (Message) ois.readobject(); /* * read message and sync or reset according to message type if (m instanceof SyncMessage) { SyncMessage sm = (SyncMessage) m; // System.out.println("receiving " + sm.getid() + " - " + sm.getx() + "," + sm.gety()); 18

clientgameloop.setsyncmessage(sm); else if (m instanceof SimpleStringMessage){ SimpleStringMessage ssm = (SimpleStringMessage) m; if (ssm.gets().equals("reset")){ clientgameloop.resetsyncmap(); catch (Exception ex) { Logger.getLogger(ClientReceiveThread.class.getName()).log(Level.SEVERE, null, ex); public void start() { Thread t = new Thread(this); t.start(); public void stop() { receiverunning = false; ServerApp /** * wait for clients to connect and initalize threads public class ServerApp { private ServerSocket server; private boolean waitingconnections = true; private ServerSyncThread serversyncthread; private ServerGameLoop servergameloop; public void init() { initializesockets(); initializegameloop(); initializesyncthread(); public void start() { while (waitingconnections) { System.out.println("waiting connection..."); Socket s = server.accept(); /* * receive new connection calculate and id and send it int id = servergameloop.getclientslist().size() + 1; Client client = new Client("player " + id, id, s); servergameloop.getclientslist().add(client); System.out.println("Client " + id + " connected: " + s); ObjectOutputStream oos = new ObjectOutputStream(s.getOutputStream()); serversyncthread.setoutputstream(id, oos); IdMessage idmessage = new IdMessage(); idmessage.setid(id); oos.writeobject(idmessage); oos.flush(); /* * a new thread for each client to receive its input initializereceivethread(client); 19

catch (IOException ex) { Logger.getLogger(ServerApp.class.getName()).log(Level.SEVERE, "connection fail", ex); public void stop() { servergameloop.stop(); serversyncthread.stop(); waitingconnections = false; server.close(); catch (IOException ex) { Logger.getLogger(ServerApp.class.getName()).log(Level.SEVERE, "server close fail", ex); private void initializesockets() { System.out.println("Binding to port " + GlobalStatics.port + ", please wait..."); server = new ServerSocket(GlobalStatics.port); System.out.println("Server started: " + server); catch (IOException ex) { Logger.getLogger(ServerApp.class.getName()).log(Level.SEVERE, "server start fail", ex); private void initializesyncthread() { serversyncthread = new ServerSyncThread(serverGameLoop); serversyncthread.start(); private void initializegameloop() { servergameloop = new ServerGameLoop(); servergameloop.start(); private void initializereceivethread(client client) { ServerReceiveThread receivethread = new ServerReceiveThread(client, servergameloop); receivethread.start(); public static void main(string[] args) { ServerApp app = new ServerApp(); app.init(); app.start(); ServerGameLoop /** * all game logic, calculate positions etc public class ServerGameLoop implements Runnable { private ArrayList<Client> clients; private ArrayList<Client> players; // contains input message per client id used for calculations private HashMap<Integer, InputMessage> inputmap; private boolean running = true; private boolean ismatch = false; 20

private boolean matchstarting; private boolean sendreset; private int matchtimer; // used for jumping physics calculations per player private HashMap<Integer, Boolean> isjumping; private HashMap<Integer, Integer> jumpingsteps; public ServerGameLoop() { // initialize maps and lists inputmap = new HashMap<Integer, InputMessage>(); clients = new ArrayList<Client>(); players = new ArrayList<Client>(); isjumping = new HashMap<Integer, Boolean>(); jumpingsteps = new HashMap<Integer, Integer>(); //<editor-fold defaultstate="collapsed" desc="getters setters"> public boolean getismatch() { return ismatch; public boolean getmatchstarting() { return matchstarting; public boolean getsendreset() { return sendreset; public void setsendreset(boolean sendreset) { this.sendreset = sendreset; public ArrayList<Client> getclientslist() { return clients; public ArrayList<Client> getplayers() { return players; public void removeclient(client client) { players.remove(client); clients.remove(client); public void setinputmap(int i, InputMessage inputmessage) { inputmap.put(i, inputmessage); //</editor-fold> public void run() { while (running) { //TODO game rules managematch(); /* 21

* if is match get input and calculate movement else ignore if (ismatch) { for (Iterator<Client> it = players.iterator(); it.hasnext();) { Client player = it.next(); /* * for each player move according to input and simulate * gravity forces moveplayer(player); simulategravity(player.getfighterentity()); resolvecollisions(); //finally pause for a bit Thread.sleep(GlobalStatics.gameTick); catch (Exception e) { private void moveplayer(client player) { InputMessage im = inputmap.get(player.getid()); player.getfighterentity().move(im.getdelta()); boolean leftclickpressed = im.isleftclickpressed(); boolean rightclickpressed = im.isrightclickpressed(); boolean leftpressed = im.isleftpressed(); boolean rightpressed = im.isrightpressed(); boolean jumppressed = im.isjumppressed(); player.getfighterentity().setisatk(leftclickpressed); player.getfighterentity().setisdef(rightclickpressed); player.getfighterentity().sethorizontalmovement(0); if ((leftpressed) && (!rightpressed)) { player.getfighterentity().sethorizontalmovement(-globalstatics.movespeed); else if ((rightpressed) && (!leftpressed)) { player.getfighterentity().sethorizontalmovement(globalstatics.movespeed); player.getfighterentity().setverticalmovement(0); if (jumppressed && isonfloor(player.getfighterentity())) { player.getfighterentity().setverticalmovement(-globalstatics.jumpspeed); isjumping.put(player.getid(), true); if (isjumping.get(player.getid()) == null) { jumpingsteps.put(player.getid(), 0); isjumping.put(player.getid(), false); if (isjumping.get(player.getid())) { player.getfighterentity().setverticalmovement(-globalstatics.jumpspeed); if (jumpingsteps.get(player.getid()) < GlobalStatics.maxJumpingSteps) { jumpingsteps.put(player.getid(), jumpingsteps.get(player.getid()) + 1); else { 22

jumpingsteps.put(player.getid(), 0); isjumping.put(player.getid(), false); private void simulategravity(entity player) { if (!isonfloor(player)) { player.setverticalmovement(player.getverticalmovement() + GlobalStatics.gravitySpeed); private boolean isonfloor(entity e) { return (e.gety() >= (GlobalStatics.W_HEIGHT - GlobalStatics.floorHeight)); private void resolvecollisions() { //resolve positions FighterEntity leftplayer; FighterEntity rightplayer; if (players.get(0).isisright()) { rightplayer = players.get(0).getfighterentity(); leftplayer = players.get(1).getfighterentity(); else { rightplayer = players.get(1).getfighterentity(); leftplayer = players.get(0).getfighterentity(); //ifs if (leftplayer.collideswith(rightplayer)) { if (leftplayer.getisatk() && (rightplayer.getisatk() rightplayer.getisdef())) { leftplayer.sethorizontalmovement(-globalstatics.recoilspeed * 2); rightplayer.sethorizontalmovement(globalstatics.recoilspeed * 2); else if (leftplayer.getisatk() &&!rightplayer.getisatk() &&!rightplayer.getisdef()) { rightplayer.sethorizontalmovement(globalstatics.recoilspeed); rightplayer.removehp(1); else if (leftplayer.getisdef() && rightplayer.getisatk()) { leftplayer.sethorizontalmovement(-globalstatics.recoilspeed * 2); else if (!leftplayer.getisdef() && rightplayer.getisatk()) { leftplayer.sethorizontalmovement(-globalstatics.recoilspeed); leftplayer.removehp(1); else { leftplayer.sethorizontalmovement(-globalstatics.recoilspeed / 2); rightplayer.sethorizontalmovement(globalstatics.recoilspeed / 2); private void managematch() { if (!ismatch &&!matchstarting) { if (clients.size() > 1) { shiftplayers(); matchstarting = true; matchtimer = GlobalStatics.matchCountDown; sendreset = false; else if (ismatch) { if (players.size() > 1) { checkfighterslives(); else { ismatch = false; 23

else if (matchstarting) { matchtimer--; if (matchtimer == 0) { ismatch = true; matchstarting = false; private void checkfighterslives() { if (players.get(0).getfighterentity().gethealthpoints() < 0) { ismatch = false; else if (players.get(1).getfighterentity().gethealthpoints() < 0) { ismatch = false; /** * change player for new match private void shiftplayers() { int i; i = players.get(1).getid(); catch (Exception e) { i = 0; players.clear(); for (int j = 0; j < 2; j++) { i = getnextclientid(i); Client c = clients.get(i - 1); while (!c.isinqueue()) { i = getnextclientid(i); c = clients.get(i); if (j == 0) { c.setisright(false); c.setfighterentity(new FighterEntity(null, 50, 50, false)); else if (j == 1) { c.setisright(true); c.setfighterentity(new FighterEntity(null, GlobalStatics.W_WIDTH - 50-60, 50, true)); players.add(c); System.out.println("new player " + c.getid()); private int getnextclientid(int i) { i++; if (i > clients.size()) { i = 1; return i; public void start() { Thread t = new Thread(this); t.start(); 24

public void stop() { running = false; ServerReceiveThread /** * receive input from client and set to loop public class ServerReceiveThread implements Runnable { private ServerGameLoop gameloop; private Client client; private boolean running = true; private ObjectInputStream inputstream; public ServerReceiveThread(Client client, ServerGameLoop gameloop) { this.gameloop = gameloop; this.client = client; inputstream = new ObjectInputStream(client.getSocket().getInputStream()); catch (IOException ex) { Logger.getLogger(ServerReceiveThread.class.getName()).log(Level.SEVERE, "init input stream fail", ex); public void run() { while (running) { //forward input message to game loop Message m = (Message) inputstream.readobject(); if (m instanceof InputMessage) { gameloop.setinputmap(client.getid(), (InputMessage) m); catch (SocketException ex) { stop(); catch (IOException ex) { Logger.getLogger(ServerReceiveThread.class.getName()).log(Level.SEVERE, null, ex); catch (ClassNotFoundException ex) { Logger.getLogger(ServerReceiveThread.class.getName()).log(Level.SEVERE, null, ex); public void start() { Thread t = new Thread(this); t.start(); public void stop() { running = false; inputstream.close(); catch (IOException ex) { Logger.getLogger(ServerReceiveThread.class.getName()).log(Level.SEVERE, "stream close fail", ex); 25

ServerSyncThread /** * get data from loop and sent to client public class ServerSyncThread implements Runnable { private boolean running = true; private ServerGameLoop servergameloop; private HashMap<Integer, ObjectOutputStream> streams; public ServerSyncThread(ServerGameLoop servergameloop) { this.servergameloop = servergameloop; streams = new HashMap<Integer, ObjectOutputStream>(); public void setoutputstream(integer id, ObjectOutputStream oos) { streams.put(id, oos); public void run() { while (running) { if (!servergameloop.getsendreset()) {// if match is over and needs reset SimpleStringMessage simplestringmessage = new SimpleStringMessage("reset"); for (Iterator<Client> cit = servergameloop.getclientslist().iterator(); cit.hasnext();) { Client client = cit.next(); ObjectOutputStream oos = streams.get(client.getid()); oos.writeobject(simplestringmessage); servergameloop.setsendreset(true); catch (IOException ex) { Logger.getLogger(ServerSyncThread.class.getName()).log(Level.SEVERE, null, ex); // for each client(spectator or player) and for each entity for (Iterator<Client> cit = servergameloop.getclientslist().iterator(); cit.hasnext();) { Client client = cit.next(); ObjectOutputStream oos = streams.get(client.getid()); for (Iterator<Client> pit = servergameloop.getplayers().iterator(); pit.hasnext();) { Client player = pit.next(); /* * build sync message and send SyncMessage sm = new SyncMessage(); sm.setid(player.getid()); sm.setx(player.getfighterentity().getx()); sm.sety(player.getfighterentity().gety()); sm.setisatk(player.getfighterentity().getisatk()); sm.setisdef(player.getfighterentity().getisdef()); sm.setisright(player.isisright()); sm.sethealth(player.getfighterentity().gethealthpoints()); oos.writeobject(sm); catch (SocketException ex) { servergameloop.removeclient(player); catch (IOException ex) { Logger.getLogger(ServerSyncThread.class.getName()).log(Level.SEVERE, "write message fail", ex); catch (Exception e) { 26

System.err.println("Message not sent " + e.getmessage() + " continuing..."); Thread.sleep(GlobalStatics.syncTick); catch (InterruptedException ex) { public void start() { Thread t = new Thread(this); t.start(); public void stop() { running = false; for (Iterator<ObjectOutputStream> it = streams.values().iterator(); it.hasnext();) { ObjectOutputStream objectoutputstream = it.next(); objectoutputstream.close(); catch (IOException ex) { Logger.getLogger(ServerSyncThread.class.getName()).log(Level.SEVERE, "stream close fail", ex); 5. Εγχειρίδιο Χρήστη (User Manual) Εκκινώντας το παιχνίδι ο χρήστης θα εμφανιστεί παράθυρο διαλόγου που παριλαμβάνει ερώτηση αν θέλει να φιλοξενίσει ένα παιχνίδι ή να συμμετάσχει σε ένα υπάρχον. Αφού ήδη έχει ξεκινήσει κάποιος ένα παιχνίδι και ένας δεύτερος χρήστης επιλέξει να συμμετάσχει σε ένα παιχνίδι θα πρέπει να καταχωρήσει στο παράθυρο πού φαίνεται παραπάνω την IP του server για να συνδεθεί σε αυτόν. 27

Αφού περάσει και απο το στάδιο καταχώρησης της IP θα φαίνεται στο παρασκήνιο στην αριστερή μερία το παραθυρο με το ίδιο το παιχνίδι και δεξιά το παράθυρο του chat. Υπάρχει παράθυρο διαλόγου για να δώσει ο χρήστης του username του για να φαίνεται στο παράθυρο του chat. Αφού το καταχωρήσει θα υπάρχει μια κατασταση όπως φαίνεται στην εικόνα απο κάτω που θα εμφανίζεται το username του στην περιοχή των συνδεδεμένων χρηστών και σε πεδιο που φαίνεται ως ποιος χρήστης έχει συνδεθεί. Όταν συνδεθεί και δεύτερος παίχτης θα ξεκινήσει το παιχνίδι, στο οποίο όπως φαίνεται στην επόμενη εικόνα έχει μπάρες ζωής και για τους δύο παίκτες. Κουμπία χειρισμού A(ΑΡΙΣΤΕΡΑ), W(ΠΑΝΩ), S(ΚΑΤΩ), D(ΔΕΞΙΆ) SPACE JUMP ΑΡΙΣΤΕΡΟ ΚΛΙΚ ΕΠΙΘΕΣΗ ΔΕΞΙ ΚΛΙΚ ΑΜΥΝΑ Όταν κάποιος χάσει ξεκινάει πάλι το παιχνίδι απο την αρχή. 28

Παράλληλα στα δεξιά υπάρχει παράθυρο με το chat όπου μπορούν και οι παίκτες να σχολιάζουν αλλά και οι παρατηρητές να είναι ακροατήριο στον αγώνα. 6. Βιβλιογραφία Ευθυµίου Αφροδίτη, JAVA, Επισκόπηση γλώσσας προγραµµατισµού, ΑΡΙΣΤΟΤΕΛΕΙΟ ΠΑΝΕΠΙΣΤΗΜΙΟ ΘΕΣΣΑΛΟΝΙΚΗΣ ΣΧΟΛΗ ΘΕΤΙΚΩΝ ΕΠΙΣΤΗΜΩΝ ΤΜΗΜΑ ΠΛΗΡΟΦΟΡΙΚΗΣ, http://invenio.lib.auth.gr/record/114624/files/ptuxiaki.pdf?version=1 29