MitsakosGR Δημοσ. 21 Ιανουαρίου 2013 Δημοσ. 21 Ιανουαρίου 2013 Εννοείς να δείχνεις το ζάρι καθώς ρολάρει μέχρι να καταλήξει στην τελική του θέση; Αν ναι, νομίζω πως δεν είναι και τόσο εύκολο, και προσωπικά δεν μπορώ κιόλας να σου υποδείξω κάποιον εύκολο τρόπο να κάνεις κάτι τέτοιο. Δεν έχω εξειδίκευση στα γραφικά (και ιδίως στα 3Δ γραφικά) αλλά υπάρχουν νομίζω παιδιά στο φόρουμ που ίσως μπορούν να σε καθοδηγήσουν (π.χ. πάπι). Ένας εύκολος τρόπος που μου έρχεται εμένα στο μυαλό αυτή τη στιγμή (χωρίς δηλαδή ιδιαίτερα γραφικά) είναι να έχεις 6 εικόνες του ζαριού, μια για κάθε πλευρά του. Όταν θέλεις να δείχνεις ότι και καλά ρολάρει το ζάρι, μπορείς να εναλλάσσεις τυχαία αυτές τις εικόνες στο object που φιλοξενεί το ζάρι στο στιγμιότυπο που έχεις ποστάρει. Ας πούμε για παράδειγμα έχεις ένα loop που του λες επί 50 φορές να σου βγάζει ένα τυχαίο νούμερο από το 1 έως το 6 (οι πιθανές πλευρές του ζαριού σου). Όταν σου βγάλει ας πούμε το 3 θα φορτώνεις στο object την εικόνα που αντιστοιχεί στο 3 του ζαριού. Οπότε και έχεις ένα υποτυπώδες εφέ, και ξέρεις ποια ζαριά έκατσε Μπορείς επίσης να φτιάξεις αυτό το εφέ σε μια κινούμενη εικόνα για να μην χρειάζεται να το δημιουργείς συνέχεια. Απλά θα το κάνεις πολύ γρήγορο (τις εναλλαγές από την μία πλευρά στην άλλη) για να μην ξεχωρίζει ο χρήστης ότι είναι συνέχεια το ίδιο.
lion2486 Δημοσ. 21 Ιανουαρίου 2013 Δημοσ. 21 Ιανουαρίου 2013 Εδώ και καιρό τριγυρνάει στο μυαλό μου μια ιδέα για ένα επιτραπέζιο με κάρτες να το κάνω σε υπολογιστή, αλλά δεν έχω κάτσει να το ξεκινήσω ούτε να πολύ σκεφτώ την υλοποίηση (λογικά θα πήγαινα σε webapp εγώ και με δυνατότητα για πολλούς παίχτες, σε γραφικά εφαρμογών μόνο πολύ λίγο με OpenGL έχω ασχοληθεί στη σχολή μου και δεν νομίζω να έχω τη δυνατότητα). Το παιχνίδι το διανέμει η ΚΑΙΣΣΑ, λέτε να έκανα μια επικοινωνία μήπως μου το κάψουν από την αρχή; (Φαντάζομαι ότι μπορώ να αλλάξω εικόνες-ονόματα και κάποιες περιγραφές και να δηλώσω ότι αφού είναι αλλαγμένο δεν είναι δικό τους αλλά δεν έχω ιδέα..)
Directx Δημοσ. 21 Ιανουαρίου 2013 Δημοσ. 21 Ιανουαρίου 2013 (επεξεργασμένο) Πχ ψάχνω να βρω (πάντα google) τρόπο για να προσομοιώσω το ζάρι που πέφτει κλπ. και όχι όπως τώρα που απλά το button παίρνει ένα image ανάλογα με το αποτέλεσμα του ζαριού.Για 3D δεν μπορώ να προτείνω κάτι, αλλά για 2D θα μπορούσες να γράψεις μια ρουτίνα που θα γύριζε τα ζάρια μέχρι τον επιθυμητό αριθμό με σταδιακή ελάττωση της ταχύτητας τους, σαν ένα μικρό εφέ (ώστε να μην είναι μια ξερή αλλαγή εικόνας). Για παράδειγμα θα μπορούσε να είναι κάτι τέτοιο.. http://www.youtube.com/watch?v=awCbPTOEgs4 Υ.Γ. Τα ζάρια τα έχω πάρει από εδώ (η εικόνα δεν τα έχει σωστά ευθυγραμμισμένα) Επεξ/σία 27 Ιανουαρίου 2013 από Directx
BonJovi Δημοσ. 21 Ιανουαρίου 2013 Δημοσ. 21 Ιανουαρίου 2013 Ίσως μπορείς να χρησιμοποιήσεις και τα ζάρια που βρίσκονται στο link http://opengameart.org/content/dice-1. Θα προσπαθήσω να τα βάλω κι εγώ στο δικό μου. Αν κατεβάσεις το zip αρχείο, θα δεις ότι περιέχει και εικόνες των ζαριών την ώρα που γυρίζουν. Όλα αυτά μπορείς να τα βάλεις σε ένα αρχείο εικόνας χωρισμένο σε ίσα νοητά κουτάκια. Κάθε νοητό κουτάκι θα περιέχει και ένα ζάρι ενώ μπορείς να τους αντιστοιχείς και ένα μοναδικό αριθμό. Στη συνέχεια, μια και το παιχνίδι είναι 2d, μπορείς να ψάξεις στο google για τη μέθοδο blitting. Σύμφωνα με αυτή, επιλέγεις την περιοχή που θέλεις από τη συνολική εικόνα και την αντιγράφεις στη μικρή περιοχή που θα αποτελεί την εικόνα του ζαριού. Επομένως, τρέχοντας ένα loop, μπορείς κάθε φορά με τη χρήση της παραπάνω αρίθμησης, να εμφανίζεις το ζάρι που θες. Η συνεχόμενη εναλλαγή εικόνων θα έχει σαν αποτέλεσμα το animation του ζαριού, το οποίο θα φαίνεται ότι πραγματικά γυρίζει. Δεν ξέρω αν το εξήγησα καλά ούτε αν αυτή η μέθοδος είναι η ιδανική. Κι εγώ είμαι αρκετά αρχάριος. Αλλά κάπως έτσι το έχω στο μυαλό μου και κάπως έτσι θα προσπαθήσω να το βάλω κι εγώ τα rolling dice στο παιχνίδι μου. 1
Directx Δημοσ. 21 Ιανουαρίου 2013 Δημοσ. 21 Ιανουαρίου 2013 (επεξεργασμένο) Ίσως μπορείς να χρησιμοποιήσεις και τα ζάρια που βρίσκονται στο link http://opengameart.org/content/dice-1. Θα προσπαθήσω να τα βάλω κι εγώ στο δικό μου. Αν κατεβάσεις το zip αρχείο, θα δεις ότι περιέχει και εικόνες των ζαριών την ώρα που γυρίζουν. Όλα αυτά μπορείς να τα βάλεις σε ένα αρχείο εικόνας χωρισμένο σε ίσα νοητά κουτάκια. Κάθε νοητό κουτάκι θα περιέχει και ένα ζάρι ενώ μπορείς να τους αντιστοιχείς και ένα μοναδικό αριθμό. Πολύ όμορφο photorealistic 2D animation (& εξαιρετικό site!) κρίμα όμως που δεν περιλαμβάνει στα καρέ της περιστροφής όλες τις πλευρές του ζαριού, αν τις είχε θα ήταν υπέροχο για ένα ποιοτικό παιχνίδι!http://www.youtube.com/watch?v=YVxQLIaQPXw Επεξ/σία 27 Ιανουαρίου 2013 από Directx 2
geo1st487 Δημοσ. 21 Ιανουαρίου 2013 Δημοσ. 21 Ιανουαρίου 2013 Εναλλακτικα απο αυτο που λεει ο BonJovi μπορεις να χρησιμοποιησεις ενα animation gif οπως αυτο που επισυναπτω για να φαινεται οτι το ζαρι γυριζει και θα το σταματας εσυ σε καποιο random frame (το οποιο θα πρεπει να δειχνει ολοκληρη τη πλευρα του ζαριου). Επισης μπορεις να ρυθμισεις και την ταχυτητα εναλλαγης των frames κατα τον χρονο εκτελεσης ωστε να υπαρχει μια σταδιακή ελάττωση της ταχύτητας τους, σαν ένα μικρό εφέ (οπως λεει και ο DirectX). Δεν ξερω στη java τι παιζει αλλα αυτα που χρειαζεσαι για να πετυχεις τα παραπανω ειναι ενα component το οποιο θα εχει τη δυνατοτητα οχι απλως να παιζει ενα animation gif αρχειο αλλα να μπορει να δειχνει μεμονωμενα ενα συγκεκριμενο frame και επισης να μπορεις να οριζεις την ταχυτητα εναλλαγης των frames. Παντως το πιο ρεαλιστικο rolling φαινεται στο παρακατω βιντεο http://www.youtube.com/watch?v=1_9TDKmUYH0
Lanike71 Δημοσ. 22 Ιανουαρίου 2013 Μέλος Δημοσ. 22 Ιανουαρίου 2013 Για 3D δεν μπορώ να προτείνω κάτι, αλλά για 2D θα μπορούσες να γράψεις μια ρουτίνα που θα γύριζε τα ζάρια μέχρι τον επιθυμητό αριθμό με σταδιακή ελάττωση της ταχύτητας τους, σαν ένα μικρό εφέ (ώστε να μην είναι μια ξερή αλλαγή εικόνας). Για παράδειγμα θα μπορούσε να είναι κάτι τέτοιο.. http://www.youtube.com/watch?v=awCbPTOEgs4Υ.Γ. Τα ζάρια τα έχω πάρει από εδώ (η εικόνα δεν τα έχει σωστά ευθυγραμμισμένα) Πήρα από την αρχή που ξεκίνησα τα συγκεκριμένα ζάρια,αλλά δε μπορώ να το υλοποιήσω(δεν κάνει repaint τα images). Μάλλον θα πρέπει να υλοποιηθεί με ξεχωριστό thread (αν δεν κάνω λάθος). Είπαμε,αρχάριος... Ευχαριστώ όλους για τις βοήθειες για το ζάρι.
lion2486 Δημοσ. 24 Ιανουαρίου 2013 Δημοσ. 24 Ιανουαρίου 2013 Εγώ έκανα την επικοινωνία για αυτό που ενδιαφερόμουν. Πρόκειται για το Manchkin, διανέμεται στην Ελλάδα από την ΚΑΙΣΣΑ και κατασκευάζεται από την sjgames. Μίλησα αρχικά με την ΚΑΙΣΣΑ και μου είπαν να απευθυνθώ στον κατασκευαστή. Επικοινώνησα και μου είπαν ότι δεν μου επιτρέπουν να χρησιμοποιήσω τα γραφικά τους και γενικά το όνομα και το παιχνίδι τους με ευγενικό τρόπο. Η Επικοινωνίες έγιναν σε 2 μέρες, που με εντυπωσίασε πολύ!
geo1st487 Δημοσ. 24 Ιανουαρίου 2013 Δημοσ. 24 Ιανουαρίου 2013 Εγώ έκανα την επικοινωνία για αυτό που ενδιαφερόμουν. Πρόκειται για το Manchkin, διανέμεται στην Ελλάδα από την ΚΑΙΣΣΑ και κατασκευάζεται από την sjgames. Μίλησα αρχικά με την ΚΑΙΣΣΑ και μου είπαν να απευθυνθώ στον κατασκευαστή. Επικοινώνησα και μου είπαν ότι δεν μου επιτρέπουν να χρησιμοποιήσω τα γραφικά τους και γενικά το όνομα και το παιχνίδι τους με ευγενικό τρόπο. Η Επικοινωνίες έγιναν σε 2 μέρες, που με εντυπωσίασε πολύ! Φτιαξε ενα δικο σου επιτραπεζιο με δικα σου γραφικα και κατοχυρωσε τα πνευματικα δικαιωματα.
migf1 Δημοσ. 26 Ιανουαρίου 2013 Δημοσ. 26 Ιανουαρίου 2013 Πήρα από την αρχή που ξεκίνησα τα συγκεκριμένα ζάρια,αλλά δε μπορώ να το υλοποιήσω(δεν κάνει repaint τα images). Μάλλον θα πρέπει να υλοποιηθεί με ξεχωριστό thread (αν δεν κάνω λάθος). Είπαμε,αρχάριος... Ευχαριστώ όλους για τις βοήθειες για το ζάρι. Λογικά δεν χρειάζεσαι ξεχωριστό thread (εκτός αν π.χ. θέλεις να κάνεις κι άλλες δουλειές την ώρα που ρολάρουν τα ζάρια ή π.χ. να θες να τα σταματήσεις... δεν ξέρω πως συμπεριφέρεται το Swing, αν π.χ. σε αφήνει να χρησιμοποιήσεις τίποτα hooks, interrupts, κλπ). Μου άρεσαν τα βιντεάκια του DirectX και έφτιαξα κι εγώ κάτι παραπλήσιο, που συνδυάζει 2D και 3D pseudo-animation, με παραπάνω επιλογές... http://youtu.be/ckX1UJpYlUQ Είναι σε C βέβαια, με GTK+2, αλλά έχω χρησιμοποιήσει μονάχα ένα thread (δηλαδή μπλοκάρει όταν είναι σε εξέλιξη το rolling). Θα σουλουπώσω λίγο τον κώδικα και θα τον ανεβάσω, είτε εδώ, είτε στο ideone.com, είτε στο site μου (είτε και στα 3 ). 1
Lanike71 Δημοσ. 28 Ιανουαρίου 2013 Μέλος Δημοσ. 28 Ιανουαρίου 2013 Λογικά δεν χρειάζεσαι ξεχωριστό thread (εκτός αν π.χ. θέλεις να κάνεις κι άλλες δουλειές την ώρα που ρολάρουν τα ζάρια ή π.χ. να θες να τα σταματήσεις... δεν ξέρω πως συμπεριφέρεται το Swing, αν π.χ. σε αφήνει να χρησιμοποιήσεις τίποτα hooks, interrupts, κλπ). Δεν κατάφερα να το κάνω κάπως αλλιώς,τελικά το έκανα σε 2d,όπως το δικό σου. Και άλλες φορές μόνο με thread το έκανα,πχ ένα progressbar να αλλάζει την τιμή του δυναμικά. Απλά σε ένα for loop, δεν κάνει τίποτα. Αν ξέρει κάποιος,ας πει.
migf1 Δημοσ. 30 Ιανουαρίου 2013 Δημοσ. 30 Ιανουαρίου 2013 Δεν κατάφερα να το κάνω κάπως αλλιώς,τελικά το έκανα σε 2d,όπως το δικό σου. Και άλλες φορές μόνο με thread το έκανα,πχ ένα progressbar να αλλάζει την τιμή του δυναμικά. Απλά σε ένα for loop, δεν κάνει τίποτα. Αν ξέρει κάποιος,ας πει. Όπως έγραψα από την αρχή έχουν περάσει αιώνες από τότε που είχα ασχοληθεί με Swing, χώρια ότι και η τότε επαφή μου ήταν επιφανειακή. Ρίχνοντας όμως μια ματιά εδώ: http://www.oracle.com/technetwork/java/painting-140037.html#awt νομίζω πως το μόνο που χρειάζεσαι είναι να κάνεις ένα repaint() στο JComponent που κρατάει τις εικόνες του animation (π.χ. Anim.repaint()) μετά από κάθε φόρτωμα της επόμενης εικόνας. Πάραυτα, αντιμετώπισα κι εγώ ένα παραπλήσιο πρόβλημα στο GTK+2 με τη C. Εκεί μια παραπλήσια συνάρτηση της repaint() είναι η gtk_widget_queue_draw_area(). Αν διαβάσεις την τεκμηρίωση τους, θα δεις πως δεν κάνουν άμεσα redraw αλλά το κάνουν schedule για όταν τελειώσουν όλα τα pending-events (στο GTK+2 υπήρχε και η gtk_widget_draw() η οποία έκανε άμεσα redraw το widget, αλλά είναι depreciated... εμφανίστηκε ξανά στο GTK+3 αλλά νομίζω με διαφορετικό signature). Αυτό λοιπόν στην πράξη σημαίνει, πως ενδέχεται να μεσολαβούν άλλα events πριν γίνει το redraw που θέλεις, τα οποία αν δεν ικανοποιηθούν πρώτα αυτά δεν θα γίνει το redraw που αιτήθηκες. Αυτό είχα πάθει κι εγώ, αν και δεν θυμάμαι τώρα σε ποιο ακριβώς σημείο του κώδικα. Θυμάμαι όμως πως δεν χρησιμοποιώ την gtk_widget_queue_draw_area(), αλλά την πιο high-level gtk_widget_show() (η οποία υποθέτω καλεί την gtk_widget_queue_draw_area() ή εν πάσει περιπτώση κάποιον κοινό μηχανισμό του GDK). Η λύση λοιπόν για να αποφύγω ξεχωριστό thread ειδικά για άμεσο redrawing, ήταν 2 χρησιμότατες συναρτήσεις: gtk_events_pending() και gtk_main_iteration() Έφτιαξα λοιπόν μια δική μου συνάρτηση... static void myGtk_widget_refresh( GtkWidget *widget ) { /* sanity check */ if ( !widget ) return; gtk_widget_show( widget ); while( gtk_events_pending() ) gtk_main_iteration(); return; } την οποία την καλώ όταν θέλω να κάνω άμεσο redraw ενός widget. Η gtk_widget_show( widget ) το κάνει schedule για redraw (στέλνει δηλαδή το σχετικό event) και το loop εξασφαλίζει πως θα γίνουν served ΟΛΑ τα pending-events (άρα και αυτό που έστειλα ). Ίσως λοιπόν χρειάζεται να κάνεις κάτι παραπλήσιο κι εσύ, για να μην κάνεις spawn καινούριο thread μόνο και μόνο για το redraw. Βέβαια δεν ξέρω καν αν υπάρχει κάτι αντίστοιχο στη Swing, ή αν χρειάζεται καν να υπάρχει... αξίζει όμως τον κόπο νομίζω να το ψάξεις λιγάκι. ΥΓ1. Widgets είναι κάτι σαν τα Components της Java ή τα Controls του Win32 API ΥΓ2. Τον κώδικα θα τον ποστάρω, δεν το έχω ξεχάσει, αλλά του έχω βάλει κι άλλα πράγματα για να γίνει κάτι σαν πιο γενικό παράδειγμα για GTK+2 programming σε C, οπότε ίσως καθυστερήσω να το ποστάρω (π.χ. κατάφερα on-the-fly αλλαγή της γλώσσας του GUI, κάτι που δεν είναι καθόλου συνηθισμένο σε εφαρμογές GTK+2)
migf1 Δημοσ. 30 Ιανουαρίου 2013 Δημοσ. 30 Ιανουαρίου 2013 Διαβάζοντας λίγο παρακάτω στο λινκ που έδωσα για το Java Painting Scheme, βλέπω πως η repaint() είναι έτσι κι αλλιώς ασύγχρονη, και μάλιστα multiple-requests γίνονται αυτόματα merged σε μονάχα, ένα, άρα πρέπει να είσαι οκ με αυτήν (καθώς κι efficient). Αλλιώς μπορείς να δοκιμάσεις με την paintImmediately(), παρόλο που γράφει πως συνήθως δεν χρειάζεται (δεν είναι κι ασύγχρονη).
migf1 Δημοσ. 1 Φεβρουαρίου 2013 Δημοσ. 1 Φεβρουαρίου 2013 Καλημέρα, δεν γνωρίζω αν ο ts εξακολουθεί να ενδιαφέρεται για το θέμα με το ζάρι, αλλά μιας και "υποσχέθηκα" να δώσω και κώδικα για την πρόταση που εισηγήθηκα και το υποστηρικτικό βιντεάκι κι επειδή ο συνολικός κώδικας πλέον ξεφεύγει από τα στενά πλαίσια της ερώτησης (συν ότι μάλλον θα αργήσει αρκετά η συνολική του δημοσίευση) αποφάσισα να ποστάρω μονάχα εκείνο το απόσπασμα που ασχολείται με το εφέ της κίνησης του ζαριού, ελπίζοντας πως θα βοηθήσει είτε τον ts είτε κάποιον άλλον. Είναι σε C χρησιμοποιώντας ως GUI το GTK+2.24, αλλά θέλω να πιστεύω πως μπορεί να φανεί χρήσιμος και σε language/GUI agnostic context. Η κυρίως συνάρτηση είναι η on_clicked_btnRoll(), και είναι μεγαλούτσικη. Της έχω βάλει όμως πολλά σχόλια, ελπίζοντας πως θα διευκολύνουν όποιον θελήσει να ασχοληθεί. Εισαγωγικά Σχόλια της Συνάρτησης /*************************************************//** * Callback function connected to the GTK+ "clicked" signal, * for the button "Roll". * * This function impelements the animation of the die, * and it is called when the user clicks on the button * "Roll" (or anywhere inside the event-box that hosts * the animation's image-widget). * * The basic idea is to have a loop of user-defined 'maxSteps' * iterations. Within each iteration we produce a random integer * from 1 to 6, we load the corresponding image into the * image-widget and we redraw the widget. Then we add some * delay (sleep) until the next iteration. The latest generated * random integer is the final result of the whole roll. * * However, the code gets much more involved, because we * implement enhanced functionality compared to the basic * one described above. * * Besides 'maxSteps', we also let the user to decide the * 'baseDelay' to be applied between iterations (steps), * along with an additional 'stepDelay' that gets added * to the 'baseDelay' after every loop iteration, thus * producing a progressive slow-down to the animation * which can be thought as a naive friction-effect. * * We also let the user decide whether we should use * flat 2d or (pseudo) 3d images for the animation-effect. * However, first & last frames are always flat 2d images. * * I've put quite a few comments inside the function, hoping * they will make it easier to follow the code. Let me add * though that, since this is not a true animation, the term * "Frames" is used in a rough context. * * A complete 3d effect uses NFRAMES_3D images (currently 32) * while a complete 2d effect uses NFRAMES_2D images (currently 6). * So, depending on the current value of the "Use 2D rolling-effect" * setting, if 'maxSteps' exceeds the frames limit, the animation * reverses its direction as soon as it reaches the last frame. * When reversed, if it reaches the first frame it changes its * direction again, and so on. ***************************************************** */ Κώδικας της Συνάρτησης: static void on_clicked_btnRoll( GtkWidget *button, Gui *gui ) { gchar *fmtText = NULL; /* for creating formatted text via snprintf() */ gchar msgStatusbar[MAXSIZ_FNAME] = {'\0'}; /* msg displayed on status-bar */ gchar fnameFrame[MAXSIZ_FNAME] = {'\0'}; /* next image-frame to load */ gboolean isAnim2d = FALSE; /* are we currently in 2d or 3d animation mode? */ gboolean hasNextFrame = TRUE; /* are images of current animation exhausted? */ gint maxFrames; /* 3d uses NFRAMES_3D images, 2d uses NFRAMES_2D */ gint i = 0, iFrame = 0; /* current step & image-frame during animation */ gint maxSteps = 32; /* max number of moving-steps per roll */ gulong baseDelay = 500; /* standard delay between steps (microsecs) */ gulong stepDelay = 500; /* step for progressive friction (microsecs)*/ GuiSettings *settings = NULL; /* just to save us some typing later on */ /* sanity checks */ if ( !gui ) { DBG_GUI_ERRMSG( NULL, _("Invalid pointer arg (gui)") ); return; } if ( !gui->linkToCoreData ) { DBG_GUI_ERRMSG( gui->appWindow, _("GUI is not linked to Core") ); return; } settings = &gui->settings; if ( !settings->chkbtnDebugInfoWidget || !settings->chkbtnRollEffectWidget || !settings->hsliderMaxSpins.widget || !settings->hsliderMaxSpins.adjustment || !settings->hsliderBaseDelay.widget || !settings->hsliderBaseDelay.adjustment || !settings->hsliderStepDelay.widget || !settings->hsliderStepDelay.adjustment ){ DBG_GUI_ERRMSG( gui->appWindow, _("Found invalid GUI elements") ); return; } dbg_print_info( "Roll button clicked\n" ); /* get current animation settings from GUI */ maxSteps = (gint)settings->hsliderMaxSpins.value; baseDelay = (gulong)settings->hsliderBaseDelay.value; stepDelay = (gulong)settings->hsliderStepDelay.value; isAnim2d = gtk_toggle_button_get_active( GTK_TOGGLE_BUTTON(settings->chkbtnRollEffectWidget) ); /* depending on the current 2d/3d mode, init max number of image-frames * for the animation, and decide on the filename template to be used for * loading image-frames during the animation */ maxFrames = isAnim2d ? NFRAMES_2D : NFRAMES_3D; fmtText = isAnim2d ? "%s2d_%02d.png" : "%s3d_%02d.png"; /* clear statusbar, disable roll-button, update button's text */ gtk_widget_set_sensitive( gui->statusBar.widget, FALSE ); gtk_statusbar_pop( GTK_STATUSBAR(gui->statusBar.widget), gui->statusBar.contextId ); gtk_widget_set_sensitive( button, FALSE ); gtk_button_set_label( GTK_BUTTON(button), TXT_BUTTON_ROLLING ); myGtk_widget_refresh( button ); /* main loop of the animation effect * NOTE:iFrame starts with 1 instead of 0, because the first image-frame * is already displayed (when GUI was initially loaded from the * Glade file) */ iFrame = 1; for (i=0; i < maxSteps; i++) { /* show progress in status-bar */ g_snprintf( msgStatusbar, MAXSIZ_FNAME, TXTF_STATUSBAR_ONROLL, i, /* current step */ iFrame, /* current image-frame */ baseDelay /* current base-delay + friction */ ); gtk_statusbar_push( GTK_STATUSBAR(gui->statusBar.widget), gui->statusBar.contextId, msgStatusbar ); /* produce & save a random integer between 1 and 6, inclusive * and then depending on the currently displayed image-frame * decide whether the animation should change its direction */ gui->linkToCoreData->resultRolled = g_rand_int_range( gui->linkToCoreData->randGen, 1, 7 ); if ( iFrame > maxFrames-1 ) hasNextFrame = FALSE; if ( iFrame < 2 ) hasNextFrame = TRUE; iFrame = hasNextFrame ? iFrame+1 : iFrame-1; /* construct the filename of the next image-frame to be displayed, * load it into the GUI image-widget & refresh the widget */ g_snprintf( fnameFrame, MAXSIZ_FNAME, fmtText, DIR_GUI, iFrame ); dbg_print_info( "Frame Image: %s\n", fnameFrame ); gtk_image_set_from_file( GTK_IMAGE(gui->dieArea.imgWidget), fnameFrame ); myGtk_widget_refresh( gui->dieArea.imgWidget ); /* apply baseDelay + friction until next step */ g_usleep( baseDelay ); baseDelay += stepDelay; /* clear the status-bar */ gtk_statusbar_pop( GTK_STATUSBAR(gui->statusBar.widget), gui->statusBar.contextId ); } /* display the final image-frame which is always a 2d image, * reflecting the last random number picked inside the loop */ g_snprintf( fnameFrame, MAXSIZ_FNAME, "%s2d_d.png", DIR_GUI, gui->linkToCoreData->resultRolled ); gtk_image_set_from_file( GTK_IMAGE(gui->dieArea.imgWidget), fnameFrame ); myGtk_widget_refresh( gui->dieArea.imgWidget ); /* enable roll-button & update its text */ gtk_widget_set_sensitive( button, TRUE ); gtk_button_set_label( GTK_BUTTON(button), TXT_BUTTON_ROLL2D ); /* display in the status-bar the last generated random number */ gtk_widget_set_sensitive( gui->statusBar.widget, TRUE ); g_snprintf( msgStatusbar, MAXSIZ_FNAME, TXTF_STATUSBAR_RESULT, gui->linkToCoreData->resultRolled ); gtk_statusbar_push( GTK_STATUSBAR(gui->statusBar.widget), gui->statusBar.contextId, msgStatusbar ); return; } Συμπληρωματικές Πληροφορίες Τον ρόλο και τον κώδικα της συνάρτησης myGtk_widget_refresh() τα εξηγώ στο προηγούμενο post. Η συνάρτηση dbg_print_info() είναι απλώς ένας wrapper της στάνταρ C89/C90 variadic συνάρτησης vprintf() που τυπώνει στην κονσόλα τα ορίσματά της, με μόνη διαφορά πως εκτελεί το τύπωμα μονάχα αν είναι TRUE η global μεταβλητή gboolean global_debugOn; (ουσιαστικά μας δίνει τη δυνατότητα να ελέγξουμε μέσω αυτής της μεταβλητής αν θέλουμε να τυπώνονται στην κονσόλα έξτρα πληροφορίες για διευκόλυνση του debugging). static void dbg_print_info( char *fmtxt, ... ) { va_list args; if ( !global_debugOn || !fmtxt ) return; va_start(args, fmtxt); vprintf( fmtxt, args ); va_end( args ); } Το πρόθεμα g και το πρόθεμα g_ χαρακτηρίζουν τύπους και συναρτήσεις της GLib. Το πρόθεμα gtk_ χαρακτηρίζει συναρτήσεις του GTK+2. Το πρόθεμα Gui χαρακτηρίζει δικούς μου τύπους για το GUI abstraction που χρησιμοποιώ μέσα στο πρόγραμμα (περισσότερο για καλύτερη ομαδοποίηση των widgets, παρά για πρόβλεψη χρήσης διαφορετικού GUI toolkit... αυτό το τελευταίο θα απαιτούσε πολύ μεγαλύτερο εύρος του custom abstraction). Το παραθέτω παρακάτω αυτούσιο, για όποιον ενδιαφέρεται... /* core data of the application (e.g. separated from the GUI ) */ typedef struct Core { GRand *randGen; gint32 resultRolled; }Core; /* alias of some GTK+2 widget types (just for consistency reasons) */ typedef GtkWidget GuiWindow, GuiDialog; /* a bit more convenient GUI representation of the menus */ typedef struct GuiMenus { GtkWidget *titleFile; GtkWidget *itemQuit; GtkWidget *titleLang; GtkWidget *lang; GtkWidget *itemEnglish; GtkWidget *itemGreek; GtkWidget *itemEnvLang; GtkWidget *titleHelp; GtkWidget *itemAbout; }GuiMenus; /* more convenient GUI representation of the "Die area". * The GUI "Die area" consists of an event-box, an image & a "Roll" button. * Since in GTK+2 image-widgets are not clickable, we create an event-box * as their parent, and then we catch the signals emitted by that event-box * (see the file: dice.glade, preferably with Glade). */ typedef struct GuiDieArea { GtkWidget *evboxWidget; GtkWidget *imgWidget; GtkWidget *btnWidget; }GuiDieArea; /* a bit more convenient GUI representation of an horizontal slider */ typedef struct GuiHorzSlider { GtkWidget *widget; GtkAdjustment *adjustment; gdouble minVal, maxVal, value; gdouble stepInc, pageInc; gint digits; /* non-critical fields, let them be as defined in Glade gdouble pageSize; gboolean drawValue; GtkPositionType valuePos; */ }GuiHorzSlider; /* more convenient GUI representation of the "Settings area" */ typedef struct GuiSettings { GtkWidget *chkbtnDebugInfoWidget; GtkWidget *chkbtnRollEffectWidget; GtkWidget *labelMaxSpinsWidget; GuiHorzSlider hsliderMaxSpins; GtkWidget *labelBaseDelayWidget; GuiHorzSlider hsliderBaseDelay; GtkWidget *labelStepDelayWidget; GuiHorzSlider hsliderStepDelay; GtkWidget *btnDefault3dWidget; GtkWidget *btnDefault2dWidget; }GuiSettings; /* a bit more convenient GUI representation of the status-bar */ typedef struct GuiStatusBar { GtkWidget *widget; guint contextId; guint currMessageId; }GuiStatusBar; /* convenient representation of the application's GUI * consists of the smaller structs defined above, along * with a pointer that links the GUI with the core-data. */ typedef struct Gui { gboolean quitOnDestroyAppWindow; gchar *envLang; GuiWindow *appWindow; GuiDialog *dlgAbout; GuiMenus menu; GuiDieArea dieArea; GuiDieArea3d dieArea3d; GuiSettings settings; GuiStatusBar statusBar; Core *linkToCoreData; }Gui; Το τελευταίο struct είναι το τελικό GUI abstraction που περιέχει όλα τα επιμέρους, και το οποίο χρησιμοποιείται μέσα στο πρόγραμμα υπό τη μορφή της μεταβλητής... Gui gui;η οποία περνιέται by-reference σχεδόν σε όλες τις συναρτήσεις. Ενδιαφέρον παρουσιάζει και το τελευταίο πεδίο στο struct Gui, δηλαδή το Core *linkToCoreDataτο οποίο ουσιαστικά αποτελεί τον "σύνδεσμο" του GUI με τα core data του προγράμματος. Στο συγκεκριμένο πρόγραμμα τα core data είναι ελάχιστα, βασικά είναι μονάχα ένας random-generator της GLib καθώς και το αποτέλεσμα της ζαριάς, εκφρασμένα μέσω του struct Core (είναι το 1ο struct στο προηγούμενο spoiler). Ως core data ορίζω τις ελάχιστα απαιτούμενες πληροφορίες που χρειάζεται το πρόγραμμα για να είναι λειτουργικό και χωρίς GUI, αν για παράδειγμα υλοποιηθεί μονάχα για κονσόλα (ή αν θελήσουμε για παράδειγμα να κάνουμε fallback σε ρυθμό κονσόλας αν αποτύχει η αρχικοποίηση του GUI). Τέλος, αυτό το "Glade file" που αναφέρεται συχνά-πυκνά στα σχόλια, είναι ένα XML αρχείο που το δημιουργεί ο visual-editor του GTK+, το Glade. Αντί να δημιουργώ το GUI δυναμικά μέσα στο πρόγραμμα με τις διαθέσιμες ρουτίνες του GTK+2, το έχω σχεδιάσει με το Glade, και κατόπιν μέσα στο πρόγραμμα το φορτώνω μέσα στην μεταβλητή gui, στην αρχή της main() μέσω ενός GTK+2 builder object. Το παραπάνω δεν το δείχνει ο κώδικας που έχω ποστάρει εδώ, αλλά θεώρησα καλό να το εξηγήσω επιγραμματικά για να μην μείνει σαν απορία. Αποτελεί μάλιστα και "κλειδί" για την διευκόλυνση στην on-the-fly αλλαγή της γλώσσας του GUI (μέσω του GNU-gettext API). ΥΓ. Ολοκληρωμένο το πρόγραμμα θα το ποστάρω κάποια στιγμή σε κάποιο άλλο νήμα, μιας και οι υπόλοιπες λειτουργίες του δεν αφορούν το παρόν νήμα. EDIT: Έχω αφήσει άνευ εξήγησης μερικά ακόμα που χρησιμοποιούνται στον κώδικα παραπάνω... Το macro DBG_GUI_ERRMSG() είναι κάτι σαν την dbg_print_info() με δυο διαφορές: Δεν είναι variadic (δυστυχώς τα variadic macros εισήχθησαν στην C99, και τον κώδικα τον έγραψα να είναι συμβατός με την C89/C90) Το τύπωμα γίνεται με το GUI μέσα σε alert-box, το οποίο υλοποιείται με την custom συνάρτηση myGtk_alert_box() Παραθέτω σε spoiler τον κώδικα και των δυο... Συνάρτηση: myGtk_alert_box(): /*************************************************//** * Display the specified message inside a simple modal dialog. * * The owner of the dialog is the window specified in * the first argument, which usually is the main window * of the application (if passed as NULL, the alert-box * will not have an owner, which is fine but a bit odd). ***************************************************** */ static void myGtk_alert_box( GtkWidget *appMainWindow, gchar *message ) { GtkWidget *alertBox = NULL; if ( appMainWindow ) gtk_widget_set_sensitive( appMainWindow, FALSE ); alertBox = gtk_message_dialog_new( GTK_WINDOW(appMainWindow), GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_INFO, GTK_BUTTONS_OK, message ); gtk_window_set_title( GTK_WINDOW(alertBox), TXT_WTITLE_ALERT_BOX ); gtk_dialog_run( GTK_DIALOG(alertBox) ); gtk_widget_destroy( alertBox ); if ( appMainWindow ) gtk_widget_set_sensitive( appMainWindow, TRUE ); } Macro: DBG_GUI_ERRMSG(): #define DBG_GUI_ERRMSG( appWindow, errmsg ) \ do { \ gchar dbgMsgOut[MAXSIZ_DBGMSG] = {'\0'}; \ if ( !global_debugOn ) \ break; \ g_snprintf( \ dbgMsgOut, \ MAXSIZ_DBGMSG, \ _("File\t: %s\nFunc\t: %s\nLine\t: %d\n\n%s"), \ __FILE__, __func__, __LINE__, \ (const gchar *)(errmsg) ? errmsg : "\0" \ ); \ myGtk_alert_box( GTK_WIDGET(appWindow), dbgMsgOut ); \ } while(0) Επίσης, όσα string βρίσκονται μέσα σε _() ή N_() σημαίνει πως είναι translatable μέσω της GNU-gettetxt library. 1
BonJovi Δημοσ. 22 Απριλίου 2013 Δημοσ. 22 Απριλίου 2013 Επαναφέρω το θέμα που άνοιξε ο Lanike71. Έκανα κι εγώ ένα flash game βασισμένο σε κάποιο παιχνίδι της εταρείας Desyllas Games. Είχα επικοινωνήσει πριν καιρό μαζί τους (πριν περάσω γραφικά στο παιχνίδι) και μου ζήτησαν στοιχεία επικοινωνίας για να συζητήσουμε για το συγκεκριμένο θέμα. Δε με πήραν ποτέ όμως τηλέφωνο. Παρ' όλα αυτά συνέχισα την υλοποίηση του παιχνιδιού και πριν καμιά βδομάδα, τους ξαναέστειλα mail και μου απάντησαν άμεσα αφήνοντας ένα τηλέφωνο να τους καλέσω ο ίδιος και να κλείσουμε ραντεβού για να δούμε για το πώς μπορούμε να συνεργαστούμε. Πράγματι τους κάλεσα και είπαμε να συναντηθούμε μέσα στη βδομάδα.Από εκεί και πέρα, θα δούμε τι θα συζητήσουμε. Αν είναι όλα οκ, θα το ανεβάσω... διαφορετικά θα αλλάξω κάποια πράγματα και θα το παρουσιάσω σαν ένα διαφορετικό παιχνίδι. Lanike71, εσύ έκανες προσπάθεια να επικοινωνήσεις με το δημιουργο του Ταχυδρόμου?
Προτεινόμενες αναρτήσεις
Δημιουργήστε ένα λογαριασμό ή συνδεθείτε για να σχολιάσετε
Πρέπει να είστε μέλος για να αφήσετε σχόλιο
Δημιουργία λογαριασμού
Εγγραφείτε με νέο λογαριασμό στην κοινότητα μας. Είναι πανεύκολο!
Δημιουργία νέου λογαριασμούΣύνδεση
Έχετε ήδη λογαριασμό; Συνδεθείτε εδώ.
Συνδεθείτε τώρα