Το προφίλ μας στο Google Plus
0

Python Game Programming (Part 5.5)

Όπως λέει και ο καλός μας αρχισυντάκτης, στη βράση κολλάει το σίδερο κι εσείς τώρα έχετε κολλήσει για τα καλά. Όχι στο σίδερο, αλλά στο pygame βέβαια. Σας υποσχεθήκαμε space shooter και ξέρουμε πολύ καλά ότι αδημονείτε να το δείτε να παίζει. Εμείς πάλι αδημονούμε να σας δούμε να γράφετε δικό σας κώδικα! Και όχι, δεν έχει σημασία αν έχει λάθη ή δεν είναι βέλτιστος (ούτε ο δικός μας είναι άλλωστε). Το παρόν άρθρο θα σας δώσει μερικές από τις λύσεις των προβλημάτων του άρθρου μας από το deltaHacker 009, χωρίς να ωστόσο αυτές να αποτελούν το μοναδικό ή το Σωστό Τρόπο (ΤΜ) επίλυσης. Αυτοσχεδιάστε και δημιουργήστε!

Κίνηση προς όλες τις κατευθύνσεις
Αρχίζουμε με το δεύτερο ερώτημα που σας θέσαμε στο άρθρο 5: Πώς θα κάνουμε το διαστημόπλοιο να κινείται και πάνω-κάτω, εκτός από αριστερά-δεξιά. Καθώς φαντάζεστε αυτό είναι αρκετά εύκολο. Αρκεί να προσθέσετε τις παρακάτω γραμμές σε εντελώς προφανές σημείο μέσα στον κύριο βρόχο:

if key[K_UP]:
	shipspeed_y = -300
if key[K_DOWN]:
	shipspeed_y = 300

Ναι, δεν θέλει τίποτε άλλο! Γιατί φυσικά τη ρουτίνα κίνησης την έχουμε ήδη. Το μόνο που χρειάζεται είναι να διαβάσουμε το πληκτρολόγιο και για τα πάνω-κάτω βελάκια.

Εδώ όμως μπαίνει το πρόβλημα του πρώτου ερωτήματος: Πώς θα περιορίσουμε την κίνηση του διαστημοπλοίου, το οποίο εκτός ότι έχει ήδη την κακή συνήθεια να ξεφεύγει αριστερά/δεξιά, ξεφεύγει πλέον και πάνω-κάτω;

Όπως φαντάζεστε, οι συντεταγμένες που έχουμε για τη θέση του διαστημοπλοίου, αυτή τη στιγμή δείχνουν στην πάνω αριστερή γωνία του. Με την ευκαιρία, αυτό δεν είναι απαραίτητο στο pygame. Μπορούμε να ορίσουμε κάποιο άλλο σημείο ως κέντρο του αντικειμένου. Αλλά μιας και το έχουμε συνηθίσει, ας συνεχίσουμε έτσι.

Είναι μάλλον εμφανές ότι οι συντεταγμένες αυτές δεν θα πρέπει να γίνουν “μικρότερες” από (0, 0), το οποίο αντιπροσωπεύει την πάνω αριστερή γωνία της οθόνης. Αλλά τι έχουμε να πούμε για τις “μέγιστες” συντεταγμένες;

Αν είστε λίγο βιαστικοί θα πείτε ότι οι μέγιστες είναι (480, 640) ή, αν το εκφράσετε με τα δεδομένα του προγράμματος, (screenwidth, screenheight). Δεν θα έχετε πολύ άδικο αλλά, όπως είπα μόλις, είστε λίγο βιαστικοί :)

Βλέπετε, το σημείο (480, 640) αντιπροσωπεύει το κάτω δεξιά άκρο του παραθύρου, ενώ το σημείο αναφοράς για το διαστημόπλοιο είναι πάνω αριστερά. Βέβαια και στο bouncing ball έχουμε κάνει κάτι αντίστοιχο: Αφαιρούμε το πλάτος και το ύψος του αντικειμένου και προσαρμόζουμε κατάλληλα. Στην πραγματικότητα, λοιπόν, οι “μέγιστες” συντεταγμένες θα είναι (480 – πλάτος_διαστημοπλοίου, 640 – ύψος_διαστημοπλοίου).

Τώρα, το ωραίο με τα αντικείμενα είναι ότι μπορούμε να φτιάξουμε την κλάση μας με τέτοιο τρόπο, ώστε να φροντίζει αυτές τις μικρές αλλά ενοχλητικές λεπτομέρειες εσωτερικά. Δεν υπάρχει λόγος, όταν στο κύριο πρόγραμμα δημιουργούμε το περίφημο SpaceShip object, να μην του δώσουμε σαν μέγιστες συντεταγμένες το (480, 640) και να το αφήσουμε να καταλάβει μόνο του ότι πρέπει να αναλάβει να κάνει αυτές τις πράξεις, ανάλογα με το μέγεθος του. Το μόνο του βέβαια είναι τρόπος του λέγειν, καθώς φυσικά πάλι εμείς θα γράψουμε τον κώδικα.

Πώς όμως θα περάσουμε αυτούς τους περιορισμούς; Μια ιδέα είναι να τους δίνουμε ως παραμέτρους κατά τη δημιουργία του αντικειμένου. Τη δεδομένη στιγμή, το αντικείμενό μας δημιουργείται με την παρακάτω εντολή:

SpaceShip = SpaceCraft("spaceship2.png",spaceship_pos)

Μάλλον τώρα θέλουμε κάτι τέτοιο:

spaceship_low = (0,0)
spaceship_high = (screenwidth, screenheight)
SpaceShip = SpaceCraft("spaceship2.png", spaceship_pos, spaceship_low, spaceship_high)

Βλέπετε ότι περνάμε τις συντεταγμένες ως δύο tuples (δεν είναι κάτι που θα αλλάξουμε) απευθείας στον constructor του SpaceCraft class. Για μισό λεπτό, όμως. Το SpaceCraft class δεν έχει constructor! Για την ακρίβεια, δεν έχει τίποτα εκτός από ένα απλό pass. Έτσι, απλά εκτελείται ο constructor του Craft, ο οποίος δεν γνωρίζει τίποτα για συντεταγμένες low και high! Μάλλον ήρθε η ώρα να γράψουμε κάτι στην κλάση SpaceCraft, δε νομίζετε; Σβήστε λοιπόν το pass και πάμε να φτιάξουμε τον constructor:

class SpaceCraft(Craft):
	def __init__ (self, imagefile, coord, min_coord, max_coord):
		super(SpaceCraft,self).__init__(imagefile,coord)
		self.min_coord = min_coord
		self.max_coord = (max_coord[0]-self.ship_width, max_coord[1]-self.ship_height)

Όπως βλέπετε, το πρώτο πράγμα που θα κάνει ο constructor του SpaceCraft είναι να καλέσει τον αντίστοιχο της γονικής κλάσης Craft με την εντολή

super(SpaceCraft,self).__init__(imagefile,coord)

Θυμηθείτε ότι για να δουλέψει αυτό, η γονική κλάση θα πρέπει να προέρχεται από την κλάση object — όπως και πράγματι συμβαίνει:

class Craft(object):

Για να θυμηθείτε καλύτερα ανατρέξτε στο άρθρο 3.5 της σειράς, όπου στην επίδειξή μας χρησιμοποιήσαμε κι εκμεταλλευτήκαμε εντελώς αθώα ζωάκια! (Στα οποία δε ρίχναμε με LASER, όπως θα κάνουμε εδώ σε λίγο :D)

Τα δεδομένα που δίνουμε για τις ελάχιστες και μέγιστες συντεταγμένες αποθηκεύονται στις μεταβλητές (tuple) self.min_coord και self.max_coord. Για τις ελάχιστες δεν απαιτείται καμιά διόρθωση, ενώ για τις μέγιστες φυσικά γίνεται το γνωστό κόλπο με το πλάτος και το ύψος του αντικειμένου. Αυτά τα έχει ήδη υπολογίσει για εμάς ο constructor του Craft!

Το γεγονός βέβαια ότι δώσαμε περιορισμούς δεν σημαίνει ότι το διαστημόπλοιό μας τις τηρεί κιόλας. Γιατί θα πρέπει να κάνουμε κάτι *και* στην Move, η οποία δεν ελέγχει αν οι τρέχουσες συντεταγμένες είναι εκτός ορίων. Και πώς να το κάνει, άλλωστε; Μην ξεχνάτε ότι αναφερόμαστε στη βασική Move, που έχουμε γράψει για το Craft superclass. Ώρα λοιπόν να φτιάξουμε μια Move και στο SpaceCraft:

def Move(self, speed_x, speed_y, time): 
    super(SpaceCraft, self).Move(speed_x, speed_y, time)
    for k in (0, 1): 
        if self.rect[k] < self.min_coord[k]:
            self.rect[k] = self.min_coord[k] 
        if self.rect[k] > self.max_coord[k]:
            self.rect[k] = self.max_coord[k]

Τι κάνουμε εδώ; Μα κάτι πολύ απλό στα αλήθεια. Αφήνουμε τη Move της γονικής κλάσης να κάνει τη δουλειά της κι έπειτα βλέπουμε τις συντεταγμένες που προέκυψαν: Αν είναι μικρότερες ή μεγαλύτερες από το όριο, απλά τις φέρνουμε ακριβώς στο όριο. Πολύ απλά, αν πάτε σε μια άκρη της οθόνης και συνεχίζετε να πιέζετε το βελάκι, το διαστημόπλοιο θα μείνει εκεί, ακίνητο. No motion. No sir. Nada, nope.

Έχοντας ολοκληρώσει τη βασική κίνηση του σκάφους μας, μας μένουν ακόμα:

– Οι βολές
– Κάποιο εφέ που να δείχνει ότι έχουμε χτυπηθεί (ηχητικό και οπτικό)
– Η ασπίδα και η μέτρηση του score

Ακόμα δεν έχουμε αγγίξει τους εξωγήινους! Καθώς φαντάζεστε έχουμε αρκετή δουλειά για το άρθρο 6, πουθα δημοσιευτεί στο deltaHacker 010.

Μια συνάρτηση για τον ήχο
Πιστεύουμε ότι αυτό δεν σας δυσκόλεψε:

def PrepareSound(filename):
    sound = pygame.mixer.Sound(filename)
    return sound

Θα μπορείτε να το καλείτε κάπως έτσι:

explosion = PrepareSound("explosion.wav")

Και φυσικά ο ήχος θα είναι διαθέσιμος για χρήση σε οποιοδήποτε σημείο του προγράμματος τον χρειάζεστε:

explosion.play()

Φυσικά, σας ζητήσαμε κι άλλες ασκήσεις. Αλλά δεν θα σας δείξουμε εδώ περισσότερα. Θα χαρούμε ωστόσο να μας στείλετε τις δικές σας εκδοχές και –γιατί όχι– βελτιώσεις, είτε ως σχόλια σ’ αυτό το άρθρο είτε ως posts στο φόρουμ. Και μέχρι το επόμενο άρθρο μας, may the Python source be with you!

Leave a Reply

You must be logged in to post a comment.

Σύνδεση

Αρχείο δημοσιεύσεων