Προγραμματισμός

Κινούμενα σχέδια σε μικροεφαρμογές Java

Αυτό το άρθρο περιγράφει τον τρόπο εφαρμογής κινούμενων σχεδίων χρησιμοποιώντας το Java applet API. Περιγράφει τεχνικές που χρησιμοποιούνται συνήθως και δίνει ένα απλό παράδειγμα για την απεικόνιση κάθε τεχνικής.

Βασικές τεχνικές κινουμένων σχεδίων

Πολλές μορφές κινούμενων σχεδίων είναι δυνατές στην Java. Αυτό που όλα έχουν κοινό είναι ότι δημιουργούν κάποιο είδος κίνησης στην οθόνη σχεδιάζοντας διαδοχικά καρέ με σχετικά υψηλή ταχύτητα (συνήθως περίπου 10-20 φορές ανά δευτερόλεπτο).

Θα ξεκινήσουμε δημιουργώντας μια απλή μικροεφαρμογή προτύπου για να κάνουμε κινούμενα σχέδια και να την επεξεργαστούμε αργά μέχρι να φτάσουμε σε μια αρκετά ολοκληρωμένη μικροεφαρμογή.

Χρησιμοποιώντας ένα νήμα

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

Ένα συνηθισμένο λάθος είναι να βάλεις το βρόχο animation στο χρώμα() μέθοδος μιας μικροεφαρμογής. Κάτι τέτοιο θα έχει παράξενες παρενέργειες, επειδή κρατά το κύριο νήμα AWT, το οποίο είναι υπεύθυνο για όλα τα σχέδια και το χειρισμό συμβάντων.

Για παράδειγμα, έχω γράψει μια μικρή μικροεφαρμογή προτύπου, που ονομάζεται Example1Applet, η οποία απεικονίζει το γενικό περίγραμμα μιας μικροεφαρμογής κινούμενων σχεδίων. Το παράδειγμα1Applet δείχνει πώς να δημιουργήσετε ένα νήμα και να καλέσετε το χρωματίζω πάλι() μέθοδο σε σταθερά διαστήματα. Ο αριθμός των καρέ ανά δευτερόλεπτο καθορίζεται μεταβιβάζοντας μια παράμετρο applet. Ακολουθεί ένα παράδειγμα αυτού που θα βάλατε στο έγγραφο HTML:

Εδώ είναι το παράδειγμα1Applet.

Σημείωση:

Αυτή η μικροεφαρμογή δεν τραβάει ακόμα τίποτα στην οθόνη. Το σχέδιο στην οθόνη εξηγείται αργότερα. Σημειώστε επίσης ότι η μικροεφαρμογή καταστρέφει το νήμα κινούμενης εικόνας κάθε φορά που ο χρήστης φεύγει από τη σελίδα (η οποία οδηγεί στη μικροεφαρμογή να σταματήσει() μέθοδος που καλείται). Αυτό διασφαλίζει ότι η μικροεφαρμογή δεν θα σπαταλήσει χρόνο CPU ενώ η σελίδα της δεν είναι ορατή.

Διατηρώντας σταθερό ρυθμό καρέ

Στο παραπάνω παράδειγμα, η μικροεφαρμογή κοιμάται απλά για ένα σταθερό χρονικό διάστημα μεταξύ των καρέ. Αυτό έχει το μειονέκτημα που μερικές φορές περιμένετε πολύ καιρό. Για να λάβετε 10 καρέ ανά δευτερόλεπτο, δεν πρέπει να περιμένετε 100 χιλιοστά του δευτερολέπτου μεταξύ των καρέ, επειδή χάνετε λίγο χρόνο μόλις τρέξετε το νήμα.

Η ακόλουθη μικροεφαρμογή, το παράδειγμα 2Applet, δείχνει πώς να διατηρείτε καλύτερο χρόνο. Υπολογίζει απλώς τη σωστή καθυστέρηση μεταξύ των καρέ παρακολουθώντας την ώρα έναρξης. Υπολογίζει την εκτιμώμενη απαιτούμενη καθυστέρηση μεταξύ των καρέ με βάση την τρέχουσα ώρα.

Εδώ είναι το Example2Applet.

Ζωγραφική κάθε πλαισίου

Αυτό που μένει είναι να βάψουμε κάθε πλαίσιο. Στα προηγούμενα παραδείγματα, καλούμε χρωματίζω πάλι() για κάθε πλαίσιο, το οποίο προκαλεί το applet χρώμα() μέθοδος που καλείται. Το Example3Applet έχει ένα χρώμα() μέθοδος που τραβά τον αριθμό του τρέχοντος καρέ στην οθόνη.

Εδώ είναι το Action3Applet σε δράση, ακολουθούμενο από μια λίστα κωδικών.

Σημείωση:

Εάν καθορίσετε το ρυθμό καρέ να είναι πολύ υψηλό (ας πούμε 100 καρέ ανά δευτερόλεπτο), το τρέξιμο() η μέθοδος θα καλέσει χρωματίζω πάλι() 100 φορές το δευτερόλεπτο. Ωστόσο, αυτό δεν θα έχει ως αποτέλεσμα 100 κλήσεις προς χρώμα() ανά δευτερόλεπτο, επειδή όταν εκδίδετε αίτημα επαναβαφής πολύ γρήγορα, θα συμπτυχθούν σε μια ενημέρωση μίας οθόνης. Γι 'αυτό παρακολουθούμε τον τρέχοντα αριθμό καρέ στο τρέξιμο() μέθοδο μάλλον στη συνέχεια στο χρώμα() μέθοδος.

Δημιουργία γραφικών

Τώρα ας ζωντανεύσουμε κάτι που είναι λίγο πιο δύσκολο να σχεδιαστεί. Το Example4Applet σχεδιάζει έναν συνδυασμό ημιτονοειδών κυμάτων. Για κάθε συντεταγμένη x, σχεδιάζει μια μικρή κάθετη γραμμή. Όλες αυτές οι γραμμές μαζί σχηματίζουν ένα απλό γράφημα που αλλάζει για κάθε πλαίσιο. Δυστυχώς, θα διαπιστώσετε ότι αυτή η προσέγγιση προκαλεί πολλή αναλαμπή. Θα εξηγήσουμε την αιτία της αναβοσβήνει και μερικές θεραπείες στην επόμενη ενότητα.

Εδώ είναι το Action4Applet σε δράση, ακολουθούμενο από μια λίστα κωδικών.

Αποφυγή υπερβολικής αναλαμπής

Η αναβοσβήνει που βλέπετε στο παράδειγμα4Applet έχει δύο αιτίες: η βαφή κάθε πλαισίου διαρκεί πολύ (λόγω του ποσού υπολογισμού που απαιτείται κατά τη διάρκεια της βαφής) και ολόκληρο το φόντο καθαρίζεται πριν χρώμα() λέγεται. Ενώ ο υπολογισμός του επόμενου καρέ συνεχίζεται, ο χρήστης βλέπει το φόντο της κινούμενης εικόνας.

Αυτό το σύντομο χρονικό διάστημα μεταξύ της εκκαθάρισης του φόντου και της ζωγραφικής του ημιτονοειδούς κύματος θεωρείται ως φλας. Σε ορισμένες πλατφόρμες όπως ο υπολογιστής, η αναβοσβήνει είναι πιο εμφανής από ότι σε X Windows. Ο λόγος είναι ότι τα γραφικά X Windows είναι buffered, γεγονός που καθιστά το φλας λίγο μικρότερο.

Μπορείτε να μειώσετε πολύ το flashing χρησιμοποιώντας δύο απλά κόλπα: την εφαρμογή του εκσυγχρονίζω() μέθοδος και χρήση διπλού buffering (μερικές φορές γνωστό ως χρησιμοποιώντας ένα backbuffer).

Παράκαμψη της μεθόδου ενημέρωσης ()

Όταν το AWT λαμβάνει ένα αίτημα επαναβαφής για ένα applet, καλεί το applet εκσυγχρονίζω() μέθοδος. Από προεπιλογή, το εκσυγχρονίζω() Η μέθοδος καθαρίζει το φόντο της εφαρμογής και στη συνέχεια καλεί το χρώμα() μέθοδος. Παρακάμπτοντας το εκσυγχρονίζω() μέθοδος για να συμπεριλάβετε τον κώδικα σχεδίασης που ήταν στο χρώμα() μέθοδος, αποφεύγουμε να καθαρίσει ολόκληρη την περιοχή της μικροεφαρμογής με κάθε βαφή.

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

Εδώ είναι το παράδειγμα5Applet σε δράση, ακολουθούμενο από μια λίστα κωδικών.

Σημείωση:

Κάθε φορά που παρακάμπτετε το εκσυγχρονίζω() μέθοδος, πρέπει ακόμα να εφαρμόσετε χρώμα(). Αυτό συμβαίνει επειδή το χρώμα() Η μέθοδος καλείται απευθείας από το σύστημα σχεδίασης AWT κάθε φορά που εμφανίζεται "ζημιά" στην περιοχή σχεδίασης της εφαρμογής - για παράδειγμα, όταν ένα παράθυρο που καλύπτει μέρος της περιοχής σχεδίασης της εφαρμογής αφαιρείται από την οθόνη. Τα δικα σου χρώμα() η εφαρμογή μπορεί απλώς να καλέσει εκσυγχρονίζω().

Διπλό buffering

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

Η γενική αρχή είναι ότι δημιουργείτε μια εικόνα εκτός οθόνης, τραβάτε ένα πλαίσιο στην εικόνα και μετά χτυπάτε ολόκληρη την εικόνα στην οθόνη με μία κλήση προς drawImage (). Το πλεονέκτημα είναι ότι το μεγαλύτερο μέρος του σχεδίου γίνεται εκτός οθόνης. Ο τελικός χρωματισμός της εικόνας εκτός οθόνης στην οθόνη είναι συνήθως πολύ πιο αποτελεσματικός από το να βάψετε το πλαίσιο απευθείας στην οθόνη.

Η μικροεφαρμογή ημιτονοειδούς κύματος με διπλό buffering εμφανίζεται στο Παράδειγμα 6Applet. Θα δείτε ότι το κινούμενο σχέδιο είναι αρκετά ομαλό και δεν χρειάζεστε ειδικά κόλπα όταν σχεδιάζετε το πλαίσιο. Το μόνο μειονέκτημα είναι ότι πρέπει να εκχωρήσετε μια εικόνα εκτός οθόνης που είναι τόσο μεγάλη όσο η περιοχή σχεδίασης. Εάν η περιοχή σχεδίασης είναι πολύ μεγάλη, αυτό μπορεί να απαιτεί αρκετή μνήμη.

Εδώ είναι το παράδειγμα6Applet σε δράση, ακολουθούμενο από μια λίστα κωδικών.

Σημείωση:

Όταν χρησιμοποιείτε διπλό buffering, πρέπει να παρακάμψετε το εκσυγχρονίζω() μέθοδος, καθώς δεν θέλετε να καθαριστεί το φόντο της εφαρμογής πριν βάψετε το πλαίσιο. (Καθαρίζετε μόνοι σας το φόντο τραβώντας την εικόνα εκτός οθόνης.)

Χρήση εικόνων

Τώρα θα ξαναγράψουμε το paintFrame () μέθοδο με μια μέθοδο που ζωντανεύει μερικές εικόνες. Αυτό προσθέτει μερικές μικρές επιπλοκές στο πρόβλημα. Οι εικόνες είναι αρκετά μεγάλες και φορτώνονται σταδιακά. Μπορεί να χρειαστεί πολύς χρόνος για την πλήρη σχεδίαση των εικόνων, ειδικά όταν τις φορτώνετε σε αργή σύνδεση. Αυτός είναι ο λόγος για τον οποίο drawImage () Η μέθοδος παίρνει ένα τέταρτο όρισμα, ένα αντικείμενο ImageObserver. Ο παρατηρητής εικόνας είναι ένα αντικείμενο που ειδοποιείται όταν έχουν φτάσει περισσότερα από τα δεδομένα εικόνας. Για να πάρουμε τις εικόνες χρησιμοποιούμε το getImage () μέθοδος.

Μετακίνηση εικόνας σε όλη την οθόνη

Αυτή η πρώτη μικροεφαρμογή εικόνας, Contoh7Applet, χρησιμοποιεί τις ακόλουθες δύο εικόνες:

world.gif: car.gif:

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

Εδώ είναι το παράδειγμα7Applet σε δράση, ακολουθούμενο από μια λίστα κωδικών.

Εμφάνιση ακολουθίας εικόνων

Παράδειγμα8 Το Applet δείχνει πώς να δημιουργήσετε μια κινούμενη εικόνα χρησιμοποιώντας ξεχωριστές εικόνες για κάθε καρέ. Εδώ είναι τα 10 καρέ που χρησιμοποιούνται:

T1.gif: T2.gif: T3.gif: T4.gif: T5.gif:

T6.gif:

T7.gif:

T8.gif:

T9.gif:

T10.gif:

Εξακολουθούμε να χρησιμοποιούμε διπλό buffering για να εξαλείψουμε το flash. Ο λόγος είναι ότι κάθε εικόνα που αποδίδουμε είναι μερικώς διαφανής και επομένως πρέπει να διαγράψουμε κάθε πλαίσιο πριν σχεδιάσουμε το επόμενο. Αυτό θα προκαλούσε αναβοσβήνει χωρίς διπλό buffering.

Εδώ είναι το παράδειγμα8Applet σε δράση, ακολουθούμενο από μια λίστα κωδικών.

Σημείωση:

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

Χρησιμοποιώντας το MediaTracker για να αποφύγετε τη σταδιακή εμφάνιση

Όταν ένα πρόγραμμα Java φορτώνει μια εικόνα, μπορεί να εμφανίσει την εικόνα πριν από την πλήρη φόρτωση της εικόνας. Ο χρήστης βλέπει την εικόνα να αποδίδεται πρώτα ατελή και, στη συνέχεια, σταδιακά όλο και πιο ολοκληρωμένα, καθώς η εικόνα φορτώνεται. Αυτή η σταδιακή οθόνη δίνει στο χρήστη σχόλια (βελτιώνοντας την αντιληπτή απόδοση) και επιτρέπει στο πρόγραμμα να εκτελεί εύκολα άλλες εργασίες κατά τη φόρτωση της εικόνας.

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

Μπορείτε να χρησιμοποιήσετε το Jim Graham's MediaTracker τάξη για παρακολούθηση της λήψης εικόνων, καθυστέρηση της οθόνης κινουμένων σχεδίων έως ότου ολοκληρωθεί η λήψη ολόκληρου του συνόλου εικόνων. Το παράδειγμα9Applet δείχνει τον τρόπο χρήσης του MediaTracker τάξη για λήψη εικόνων για το κινούμενο Duke animation.

Εδώ είναι το παράδειγμα9Applet σε δράση, ακολουθούμενο από μια λίστα κωδικών.

Προσθήκη ήχου

Είναι εύκολο να προσθέσετε ήχο σε μια κινούμενη εικόνα. Μπορείτε να χρησιμοποιήσετε το getAudioClip () μέθοδος για να λάβετε ένα αντικείμενο AudioClip. Αργότερα, μπορείτε να παίξετε το κλιπ είτε ως συνεχής βρόχος είτε ως ένας ήχος. Παράδειγμα 10 Το Applet δείχνει τον τρόπο αναπαραγωγής ενός συνεχούς ήχου φόντου καθώς και ενός επαναλαμβανόμενου ήχου κατά τη διάρκεια της κινούμενης εικόνας.

Εδώ είναι το παράδειγμα10Applet σε δράση, ακολουθούμενο από μια λίστα κωδικών.

Σημείωση:

Κατά την αναπαραγωγή ενός συνεχούς ήχου, πρέπει να θυμάστε να τον σταματήσετε όταν ο χρήστης φεύγει από τη σελίδα (δηλαδή, κάντε το στο applet σας να σταματήσει() μέθοδος).

Μια άλλη σημείωση:

Ο συνεχής ήχος μπορεί να είναι πολύ ενοχλητικός. Είναι καλή ιδέα να παρέχετε στον χρήστη έναν τρόπο απενεργοποίησης του ήχου χωρίς έξοδο από τη σελίδα. Μπορείτε να παρέχετε ένα κουμπί ή απλώς να απενεργοποιήσετε τον ήχο όταν ο χρήστης κάνει κλικ στη μικροεφαρμογή.

Συμβουλές για ταχύτερη φόρτωση εικόνων

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

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

Χρησιμοποιώντας μια ταινία εικόνας

Μπορείτε να βελτιώσετε την απόδοση λήψης χρησιμοποιώντας μία εικόνα που περιέχει πολλά καρέ κινούμενων σχεδίων. Μπορείτε να αποδώσετε ένα μόνο πλαίσιο από την εικόνα χρησιμοποιώντας το clipRect () χειριστής. Ακολουθεί ένα παράδειγμα λωρίδας εικόνας που χρησιμοποιείται στην εφαρμογή UnderConstruction.

Η μικροεφαρμογή δημιουργεί ένα αποτέλεσμα γεώτρησης χωρίς να διαγράφει τα προηγούμενα καρέ. Το φόντο διαγράφεται μόνο τόσο συχνά.

Εδώ είναι το UnderConstruction σε δράση, με έναν σύνδεσμο προς τον πηγαίο κώδικα.

Συμπίεση μεταξύ πλαισίων χρησιμοποιώντας Flic

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

Εργαλεία κινουμένων σχεδίων

Αυτή τη στιγμή (Ιανουάριος 1996), λίγα εργαλεία είναι διαθέσιμα για να σας βοηθήσουν να δημιουργήσετε κινούμενες εικόνες με Java. Το καλύτερο εργαλείο που θα μπορούσα να βρω είναι το DimensionX's The Easy Animator (TEA) (παλαιότερα γνωστό ως JAM). Σας επιτρέπει να δημιουργείτε κινούμενα σχέδια διαδραστικά. Θα θέλαμε να ενθαρρύνουμε τους προγραμματιστές να γράψουν περισσότερα εργαλεία για τη δημιουργία κινούμενων σχεδίων στην Java.

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

Θα πρέπει επίσης να δείτε τη σελίδα Animation Gamelan για να βρείτε πολλές μικροεφαρμογές που χρησιμοποιούν κινούμενα σχέδια.

συμπέρασμα

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

Ο Arthur van Hoff ήταν, μέχρι πρόσφατα, ανώτερος μηχανικός προσωπικού της Sun Microsystems και ασχολείται με την ανάπτυξη της γλώσσας Java από το 1993. Είναι ο συγγραφέας του πρώτου μεταγλωττιστή Java γραμμένο εξ ολοκλήρου στην Java. Έφυγε πρόσφατα από τη Sun για να δημιουργήσει μια νέα εταιρεία μαζί με τους Sami Shaio, Kim Polese και Jonathan Payne. Η νέα εταιρεία θα επικεντρωθεί στην κατασκευή εφαρμογών Java. Η Kathy Walrath είναι τεχνική συγγραφέας της Sun Microsystems. Είναι μέλος της ομάδας Java από το 1993. Επί του παρόντος, συνεργάζεται με τη Mary Campione στο The Java Tutorial: Object-Oriented Programming για το Διαδίκτυο, ένα βοηθητικό πρόγραμμα για την εκμάθηση της γλώσσας Java, τον προγραμματισμό applet και τον προγραμματισμό Java GUI . Εκτός από το ότι είναι διαθέσιμο στο διαδίκτυο, το Java Tutorial θα δημοσιευτεί επίσης αυτό το καλοκαίρι ως μέρος της σειράς Addison-Wesley Java.

Αυτή η ιστορία, "Animation in Java applets" δημοσιεύθηκε αρχικά από το JavaWorld.