Η ανάπτυξη παιχνιδιών είναι μια από τις πιο ενδιαφέρουσες, προηγμένες τεχνικές προγραμματισμού που προκαλούν συνεχώς τη βιομηχανία ανάπτυξης λογισμικού.
Υπάρχουν πολλές πλατφόρμες προγραμματισμού που χρησιμοποιούνται για την ανάπτυξη παιχνιδιών και υπάρχει μια πληθώρα συσκευών για να τα παίξετε, αλλά όταν πρόκειται για παιχνίδια σε ένα πρόγραμμα περιήγησης στο Web, η ανάπτυξη με βάση το Flash εξακολουθεί να οδηγεί στο δρόμο.
Επανεγγραφή παιχνιδιών που βασίζονται σε Flash σε HTML5 Η τεχνολογία Canvas θα μας επέτρεπε να τα παίξουμε και σε προγράμματα περιήγησης για κινητά. Και, με την Apache Cordova, ειδικευμένοι προγραμματιστές ιστού θα μπορούσε εύκολα να τα τυλίξει σε εφαρμογές παιχνιδιών για κινητές συσκευές πολλαπλών πλατφορμών.
Οι άνθρωποι στο Δημιουργία JS ξεκίνησε να κάνει αυτό και πολλά άλλα.
EaselJS , μέρος της σουίτας του CreateJS, απλοποιεί το σχέδιο σε καμβά HTML5. Φανταστείτε να δημιουργήσετε προσαρμοσμένη οπτικοποίηση δεδομένων με υψηλή απόδοση και χιλιάδες στοιχεία. Το Scalable Vector Graphic (SVG) δεν είναι η σωστή επιλογή, επειδή χρησιμοποιεί στοιχεία DOM. Τα προγράμματα περιήγησης κατακλύζονται όταν, σε περίπου 600 στοιχεία DOM, οι αρχικές αποδόσεις, οι επαναλήψεις και οι κινούμενες εικόνες γίνονται ακριβές. Με το HTML5 Canvas, μπορούμε εύκολα να αντιμετωπίσουμε αυτά τα προβλήματα. Τα σχέδια καμβά είναι σαν μελάνι σε χαρτί, χωρίς στοιχεία DOM και το σχετικό κόστος.
Αυτό σημαίνει ότι η ανάπτυξη που βασίζεται σε καμβά χρειάζεται περισσότερη προσοχή όσον αφορά το διαχωρισμό στοιχείων και την προσάρτηση συμβάντων και συμπεριφορών σε αυτά. Το EaselJS έρχεται στη διάσωση. μπορούμε να κωδικοποιήσουμε σαν να ασχολούμαστε με μεμονωμένα στοιχεία, επιτρέποντας στη βιβλιοθήκη EaselJS να χειρίζεται τα ποντίκια, τα κλικ και τις συγκρούσεις σας.
Η κωδικοποίηση με βάση το SVG έχει ένα μεγάλο πλεονέκτημα: Το SVG έχει μια παλιά προδιαγραφή και υπάρχουν πολλά εργαλεία σχεδίασης που εξάγουν στοιχεία SVG για χρήση στην ανάπτυξη, έτσι ώστε η συνεργασία μεταξύ σχεδιαστών και προγραμματιστών να λειτουργεί καλά. Δημοφιλείς βιβλιοθήκες, όπως D3.JS και νεότερες, πιο ισχυρές βιβλιοθήκες SnapSVG , φέρτε πολλά στο τραπέζι.
Εάν η ροή εργασίας σχεδιαστής-προς-προγραμματιστή είναι ο μόνος λόγος που θα χρησιμοποιούσατε SVG, σκεφτείτε τις επεκτάσεις για Adobe Illustrator (AI) που δημιουργούν κώδικα από σχήματα που δημιουργούνται στο AI. Στο πλαίσιο μας, τέτοιες επεκτάσεις δημιουργούν κώδικα EaselJS ή κώδικα ProcessingJS, και οι δύο είναι βιβλιοθήκες που βασίζονται σε καμβά HTML5
Κατώτατη γραμμή, εάν ξεκινάτε ένα νέο έργο, δεν υπάρχει κανένας λόγος να χρησιμοποιήσετε πια SVG!
SoundJS είναι μέρος της σουίτας CreateJS. Παρέχει ένα απλό API για προδιαγραφές ήχου HTML5.
δωρεάν χακαρισμένοι αριθμοί πιστωτικών καρτών με cvv
PreloadJS χρησιμοποιείται για την προφόρτωση στοιχείων όπως bitmap, αρχεία ήχου και τα παρόμοια. Λειτουργεί καλά σε συνδυασμό με άλλες βιβλιοθήκες CreateJS.
Τα EaselJS, SoundJS και PreloadJS κάνουν την ανάπτυξη παιχνιδιών εξαιρετικά εύκολη για κάθε ninja JavaScript. Οι μέθοδοι API του είναι γνωστές σε οποιονδήποτε χρησιμοποίησε την ανάπτυξη παιχνιδιών με βάση το Flash.
«Όλα αυτά είναι υπέροχα. Τι γίνεται όμως αν έχουμε μια ομάδα προγραμματιστών που μετατρέπουν μια σειρά παιχνιδιών από το Flash σε HTML5; Είναι δυνατόν να το κάνετε αυτό με αυτή τη σουίτα; '
Η απάντηση: 'Ναι, αλλά μόνο εάν όλοι οι προγραμματιστές σας είναι σε επίπεδο Jedi!'.
Εάν έχετε μια ομάδα διαφορετικών προγραμματιστών σετ δεξιοτήτων, κάτι που συμβαίνει συχνά, μπορεί να είναι λίγο τρομακτικό να χρησιμοποιήσετε το CreateJS και να περιμένετε έναν επεκτάσιμο και αρθρωτό κώδικα. Τι γίνεται αν φέρουμε μαζί τη σουίτα CreateJS με Γωνιακό JS ; Μπορούμε να μετριάσουμε αυτόν τον κίνδυνο φέρνοντας το καλύτερο και πιο υιοθετημένο πλαίσιο JS front-end;
Ναί , και αυτό το σεμινάριο παιχνιδιών HTML5 Canvas θα σας διδάξει πώς να δημιουργήσετε ένα βασικό παιχνίδι με το CreateJS και το AngularJS!
από την πλευρά του πελάτη έναντι της απόδοσης από την πλευρά του διακομιστή
Το AngularJS μειώνει σημαντικά την πολυπλοκότητα επιτρέποντας στην ομάδα ανάπτυξής σας τα εξής:
Εάν, όπως εγώ, είστε «μάθημα» ή μαθητής αφής, θα πρέπει να λάβετε τον κωδικό από GitHub και αρχίστε να μαθαίνετε. Η πρότασή μου είναι να κοιτάξω τα check-in μου και να κατανοήσω τα βήματα που έκανα για να κερδίσω οφέλη από την προσθήκη του AngularJS καλοσύνη στον κώδικα CreateJS.
Εάν δεν το έχετε κάνει ήδη, πρέπει να το εγκαταστήσετε nodeJS πριν μπορέσετε να εκτελέσετε αυτό το demo.
Αφού δημιουργήσετε ένα έργο AngularJS seed ή κατεβάστε το από GitHub , τρέξτε npm install
για λήψη όλων των εξαρτήσεων στο φάκελο της εφαρμογής σας.
Για να εκτελέσετε την εφαρμογή σας, εκτελέστε npm start
από τον ίδιο φάκελο και μεταβείτε στο http://localhost:8000/app/#/view1
στο πρόγραμμα περιήγησής σας. Η σελίδα σας θα πρέπει να μοιάζει με την παρακάτω εικόνα.
Προσθέστε αναφορά βιβλιοθήκης CreateJS στο έργο σας AngularJS seed. Βεβαιωθείτε ότι το σενάριο CreateJS περιλαμβάνεται μετά το AngularJS.
Στη συνέχεια, καθαρίστε την εφαρμογή:
… Angular seed app: v … Κατάργηση view2
ενότητα από app.js
, διαγράφοντας την ακόλουθη γραμμή
myApp.view2,
Εάν δεν έχετε χρησιμοποιήσει το AngularJS στο παρελθόν και δεν είστε εξοικειωμένοι με τις οδηγίες του AngularJS, ελέγξτε αυτό το σεμινάριο . Οι οδηγίες στο AngularJS είναι ένας τρόπος για να διδάξετε HTML μερικά νέα κόλπα. Είναι το πιο καλά μελετημένο χαρακτηριστικό στο πλαίσιο και καθιστούν το AngularJS ισχυρό και επεκτάσιμο.
Όποτε χρειάζεστε μια εξειδικευμένη λειτουργικότητα DOM ή ένα στοιχείο, αναζητήστε το στο διαδίκτυο. υπάρχει μια καλή πιθανότητα να είναι ήδη διαθέσιμο σε μέρη όπως Γωνιακές ενότητες .
Το επόμενο πράγμα που πρέπει να κάνουμε είναι να δημιουργήσουμε μια νέα οδηγία AngularJS που θα εφαρμόσει το παράδειγμα από το EaselJS. Δημιουργήστε μια νέα οδηγία που ονομάζεται spriteSheetRunner σε ένα νέο αρχείο που βρίσκεται στο /app/view1/directives/spriteSheetRunner.js
.
angular.module('myApp.directives', []) .directive('spriteSheetRunner', function () { 'use strict'; return { restrict : 'EAC', replace : true, scope :{ }, template: '', link: function (scope, element, attribute) { var w, h, loader, manifest, sky, grant, ground, hill, hill2; drawGame(); function drawGame() { //drawing the game canvas from scratch here //In future we can pass stages as param and load indexes from arrays of background elements etc if (scope.stage) { scope.stage.autoClear = true; scope.stage.removeAllChildren(); scope.stage.update(); } else { scope.stage = new createjs.Stage(element[0]); } w = scope.stage.canvas.width; h = scope.stage.canvas.height; manifest = [ {src: 'spritesheet_grant.png', id: 'grant'}, {src: 'sky.png', id: 'sky'}, {src: 'ground.png', id: 'ground'}, {src: 'hill1.png', id: 'hill'}, {src: 'hill2.png', id: 'hill2'} ]; loader = new createjs.LoadQueue(false); loader.addEventListener('complete', handleComplete); loader.loadManifest(manifest, true, '/app/assets/'); } function handleComplete() { sky = new createjs.Shape(); sky.graphics.beginBitmapFill(loader.getResult('sky')).drawRect(0, 0, w, h); var groundImg = loader.getResult('ground'); ground = new createjs.Shape(); ground.graphics.beginBitmapFill(groundImg).drawRect(0, 0, w groundImg.width, groundImg.height); ground.tileW = groundImg.width; ground.y = h - groundImg.height; hill = new createjs.Bitmap(loader.getResult('hill')); hill.setTransform(Math.random() * w, h - hill.image.height * 4 - groundImg.height, 4, 4); hill.alpha = 0.5; hill2 = new createjs.Bitmap(loader.getResult('hill2')); hill2.setTransform(Math.random() * w, h - hill2.image.height * 3 - groundImg.height, 3, 3); var spriteSheet = new createjs.SpriteSheet({ framerate: 30, 'images': [loader.getResult('grant')], 'frames': {'regX': 82, 'height': 292, 'count': 64, 'regY': 0, 'width': 165}, // define two animations, run (loops, 1.5x speed) and jump (returns to run): 'animations': { 'run': [0, 25, 'run', 1.5], 'jump': [26, 63, 'run'] } }); grant = new createjs.Sprite(spriteSheet, 'run'); grant.y = 35; scope.stage.addChild(sky, hill, hill2, ground, grant); scope.stage.addEventListener('stagemousedown', handleJumpStart); createjs.Ticker.timingMode = createjs.Ticker.RAF; createjs.Ticker.addEventListener('tick', tick); } function handleJumpStart() { grant.gotoAndPlay('jump'); } function tick(event) { var deltaS = event.delta / 1000; var position = grant.x 150 * deltaS; var grantW = grant.getBounds().width * grant.scaleX; grant.x = (position >= w grantW) ? -grantW : position; ground.x = (ground.x - deltaS * 150) % ground.tileW; hill.x = (hill.x - deltaS * 30); if (hill.x hill.image.width * hill.scaleX <= 0) { hill.x = w; } hill2.x = (hill2.x - deltaS * 45); if (hill2.x hill2.image.width * hill2.scaleX <= 0) { hill2.x = w; } scope.stage.update(event); } } } });
Μόλις δημιουργηθεί η οδηγία σας, προσθέστε μια εξάρτηση στην εφαρμογή ενημερώνοντας /app/app.js
ως κατωτέρω:
'use strict'; // Declare app level module which depends on views, and components angular.module('myApp',[ 'ngRoute', 'myApp.view1', 'myApp.version', 'myApp.services', 'myApp.uiClasses', 'myApp.directives']) .config(['$routeProvider', function($routeProvider) { $routeProvider.otherwise({redirectTo: '/view1'}); }]);
Συμπεριλάβετε τον κωδικό οδηγίας στο index.html
προσθέτοντας μια αναφορά στο spriteSheetRunner.js
.
app/view/view1.html
Είμαστε σχεδόν έτοιμοι! Αντιγράψτε τα στοιχεία παιχνιδιού στο φάκελο της εφαρμογής σας. Έχω ετοιμάσει τις εικόνες, οπότε μη διστάσετε να τις κατεβάσετε και να τις αποθηκεύσετε στο φάκελο της εφαρμογής / στοιχείων σας.
ερωτήματα πολυμέσων για τυπικές συσκευές
Ως τελικό βήμα, προσθέστε τη νέα μας οδηγία στη σελίδα. Για να το αλλάξετε, αλλάξτε το loaderSvc.js
αρχείο, και να το κάνουμε με ένα επένδυση:
/app/view1/services
Ξεκινήστε την αίτησή σας και θα ξεκινήσετε τον δρομέα σας :)
Εάν αυτή είναι η πρώτη σας εφαρμογή AngularJS ή CreateJS, γιορτάστε, κάνατε κάτι πολύ ωραίο!
Οι υπηρεσίες στο AngularJS είναι απλές που χρησιμοποιούνται κυρίως για την κοινή χρήση του κώδικα και των δεδομένων. Θα χρησιμοποιήσουμε μια υπηρεσία για να μοιραστούμε τα «στοιχεία παιχνιδιού» σε ολόκληρη την εφαρμογή. Για να μάθετε περισσότερα σχετικά με τις υπηρεσίες AngularJS, ελέγξτε το Τεκμηρίωση AngularJS .
Υπηρεσίες ανάπτυξης AngularJS παρέχει έναν αποτελεσματικό μηχανισμό φόρτωσης και διαχείρισης όλων των περιουσιακών στοιχείων σε ένα μέρος. Οι αλλαγές στοιχείων μεταδίδονται σε κάθε μεμονωμένη παρουσία μιας υπηρεσίας, κάνοντας τον κώδικά μας πολύ πιο εύκολο να διατηρηθεί.
Δημιουργήστε νέο αρχείο JS με όνομα //app/view1/services/loaderSvc.js myServices.service('loaderSvc', function () { var manifest = [ {src: 'spritesheet_grant.png', id: 'grant'}, {src: 'sky.png', id: 'sky'}, {src: 'ground.png', id: 'ground'}, {src: 'hill1.png', id: 'hill'}, {src: 'hill2.png', id: 'hill2'} ], loader = new createjs.LoadQueue(true); this.getResult = function (asset) { return loader.getResult(asset); }; this.getLoader = function () { return loader; }; this.loadAssets = function () { loader.loadManifest(manifest, true, '/app/assets/'); }; });
στο app.js
ντοσιέ.
myApp.services
Το AngularJS απαιτεί από εμάς να καταχωρήσουμε οποιαδήποτε υπηρεσία χρησιμοποιούμε. Για να το κάνετε αυτό, ενημερώστε το 'use strict'; // Declare app level module which depends on views, and components angular.module('myApp',[ 'ngRoute', 'myApp.view1', 'myApp.version', 'myApp.services', 'myApp.directives']) .config(['$routeProvider', function($routeProvider) { $routeProvider.otherwise({redirectTo: '/view1'}); }]); var myServices = angular.module('myApp.services', []);
αρχείο για να συμπεριληφθεί αναφορά στο app/view1/directives/spriteSheetRunner.js
.
angular.module('myApp.directives', []) .directive('spriteSheetRunner', ['loaderSvc', function (loaderSvc) { 'use strict'; return { restrict : 'EAC', replace : true, scope :{ }, template: '', link: function (scope, element, attribute) { var w, h, manifest, sky, grant, ground, hill, hill2; drawGame(); function drawGame() { //drawing the game canvas from scratch here //In future we can pass stages as param and load indexes from arrays of background elements etc if (scope.stage) { scope.stage.autoClear = true; scope.stage.removeAllChildren(); scope.stage.update(); } else { scope.stage = new createjs.Stage(element[0]); } w = scope.stage.canvas.width; h = scope.stage.canvas.height; loaderSvc.getLoader().addEventListener('complete', handleComplete); loaderSvc.loadAssets(); } function handleComplete() { sky = new createjs.Shape(); sky.graphics.beginBitmapFill(loaderSvc.getResult('sky')).drawRect(0, 0, w, h); var groundImg = loaderSvc.getResult('ground'); ground = new createjs.Shape(); ground.graphics.beginBitmapFill(groundImg).drawRect(0, 0, w + groundImg.width, groundImg.height); ground.tileW = groundImg.width; ground.y = h - groundImg.height; hill = new createjs.Bitmap(loaderSvc.getResult('hill')); hill.setTransform(Math.random() * w, h - hill.image.height * 4 - groundImg.height, 4, 4); hill.alpha = 0.5; hill2 = new createjs.Bitmap(loaderSvc.getResult('hill2')); hill2.setTransform(Math.random() * w, h - hill2.image.height * 3 - groundImg.height, 3, 3); var spriteSheet = new createjs.SpriteSheet({ framerate: 30, 'images': [loaderSvc.getResult('grant')], 'frames': {'regX': 82, 'height': 292, 'count': 64, 'regY': 0, 'width': 165}, // define two animations, run (loops, 1.5x speed) and jump (returns to run): 'animations': { 'run': [0, 25, 'run', 1.5], 'jump': [26, 63, 'run'] } }); grant = new createjs.Sprite(spriteSheet, 'run'); grant.y = 35; scope.stage.addChild(sky, hill, hill2, ground, grant); scope.stage.addEventListener('stagemousedown', handleJumpStart); createjs.Ticker.timingMode = createjs.Ticker.RAF; createjs.Ticker.addEventListener('tick', tick); } function handleJumpStart() { grant.gotoAndPlay('jump'); } function tick(event) { var deltaS = event.delta / 1000; var position = grant.x + 150 * deltaS; var grantW = grant.getBounds().width * grant.scaleX; grant.x = (position >= w + grantW) ? -grantW : position; ground.x = (ground.x - deltaS * 150) % ground.tileW; hill.x = (hill.x - deltaS * 30); if (hill.x + hill.image.width * hill.scaleX <= 0) { hill.x = w; } hill2.x = (hill2.x - deltaS * 45); if (hill2.x + hill2.image.width * hill2.scaleX <= 0) { hill2.x = w; } scope.stage.update(event); } } } }]);
Ενημερώστε τον κωδικό της οδηγίας σας, σε 'use strict'; // Declare app level module which depends on views, and components angular.module('myApp',[ 'ngRoute', 'myApp.view1', 'myApp.version', 'myApp.services', 'myApp.uiClasses', 'myApp.directives']) .config(['$routeProvider', function($routeProvider) { $routeProvider.otherwise({redirectTo: '/view1'}); }]); var uiClasses = angular.module('myApp.uiClasses', []); var myServices = angular.module('myApp.services', []);
αρχείο, για να καταργήσετε τον κωδικό προφόρτωσης και να χρησιμοποιήσετε την υπηρεσία αντ 'αυτού.
uiClasses.factory('Sky', [ 'loaderSvc', function (loaderSvc) { function Sky(obj) { this.sky = new createjs.Shape(); this.sky.graphics.beginBitmapFill(loaderSvc.getResult('sky')).drawRect(0, 0, obj.width, obj.height); } Sky.prototype = { addToStage: function (stage) { stage.addChild(this.sky); }, removeFromStage: function (stage) { stage.removeChild(this.sky); } }; return (Sky); }]);
Η επαναχρησιμοποίηση και η επανάληψη των sprite στην ανάπτυξη παιχνιδιών είναι πολύ σημαντική. Προκειμένου να ενεργοποιήσουμε το instantiation των κατηγοριών UI (που είναι sprites στην περίπτωσή μας) θα χρησιμοποιήσουμε το AngularJS Factories.
Το εργοστάσιο είναι εγγεγραμμένο στην εφαρμογή όπως και κάθε άλλη μονάδα AngularJS. Για να δημιουργήσετε το εργοστάσιο uiClasses, τροποποιήστε το αρχείο app.js για να μοιάζει με αυτό:
uiClasses.factory('Hill', [ 'loaderSvc', function (loaderSvc) { function Hill(obj) { this.hill = new createjs.Bitmap(loaderSvc.getResult(obj.assetName)); this.hill.setTransform(Math.random() * obj.width, obj.height - this.hill.image.height * obj.scaleFactor - obj.groundHeight, obj.scaleFactor, obj.scaleFactor); } Hill.prototype = { addToStage: function (stage) { stage.addChild(this.hill); }, removeFromStage: function (stage) { stage.removeChild(this.hill); }, setAlpha: function (val) { this.hill.alpha = val; }, getImageWidth: function () { return this.hill.image.width; }, getScaleX: function () { return this.hill.scaleX; }, getX: function () { return this.hill.x; }, getY: function () { return this.hill.y; }, setX: function (val) { this.hill.x = val; }, move: function (x, y) { this.hill.x = this.hill.x + x; this.hill.y = this.hill.y + y; } }; return (Hill); }]);
Ας χρησιμοποιήσουμε το νέο εργοστάσιο για να δημιουργήσουμε ουρανό, λόφο, έδαφος και τον δρομέα μας. Για να το κάνετε αυτό, δημιουργήστε αρχεία JavaScript όπως αναφέρονται παρακάτω.
uiClasses.factory('Ground', [ 'loaderSvc', function (loaderSvc) { function Ground(obj) { var groundImg = loaderSvc.getResult('ground'); this.ground = new createjs.Shape(); this.ground.graphics.beginBitmapFill(groundImg).drawRect(0, 0, obj.width + groundImg.width, groundImg.height); this.ground.tileW = groundImg.width; this.ground.y = obj.height - groundImg.height; this.height = groundImg.height; } Ground.prototype = { addToStage: function (stage) { stage.addChild(this.ground); }, removeFromStage: function (stage) { stage.removeChild(this.ground); }, getHeight: function () { return this.height; }, getX: function () { return this.ground.x; }, setX: function (val) { this.ground.x = val; }, getTileWidth: function () { return this.ground.tileW; }, move: function (x, y) { this.ground.x = this.ground.x + x; this.ground.y = this.ground.y + y; } }; return (Ground); }]);
uiClasses.factory('Character', [ 'loaderSvc', function (loaderSvc) { function Character(obj) { var spriteSheet = new createjs.SpriteSheet({ framerate: 30, 'images': [loaderSvc.getResult(obj.characterAssetName)], 'frames': {'regX': 82, 'height': 292, 'count': 64, 'regY': 0, 'width': 165}, // define two animations, run (loops, 1.5x speed) and jump (returns to run): 'animations': { 'run': [0, 25, 'run', 1.5], 'jump': [26, 63, 'run'] } }); this.grant = new createjs.Sprite(spriteSheet, 'run'); this.grant.y = obj.y; } Character.prototype = { addToStage: function (stage) { stage.addChild(this.grant); }, removeFromStage: function (stage) { stage.removeChild(this.grant); }, getWidth: function () { return this.grant.getBounds().width * this.grant.scaleX; }, getX: function () { return this.grant.x; }, setX: function (val) { this.grant.x = val; }, playAnimation: function (animation) { this.grant.gotoAndPlay(animation); } }; return (Character); }]);
index.html
myDirectives.directive('spriteSheetRunner', ['loaderSvc','Sky', 'Ground', 'Hill', 'Character', function (loaderSvc, Sky, Ground, Hill, Character) { 'use strict'; return { restrict : 'EAC', replace : true, scope :{ }, template: '', link: function (scope, element, attribute) { var w, h, sky, grant, ground, hill, hill2; drawGame(); function drawGame() { //drawing the game canvas from scratch here if (scope.stage) { scope.stage.autoClear = true; scope.stage.removeAllChildren(); scope.stage.update(); } else { scope.stage = new createjs.Stage(element[0]); } w = scope.stage.canvas.width; h = scope.stage.canvas.height; loaderSvc.getLoader().addEventListener('complete', handleComplete); loaderSvc.loadAssets(); } function handleComplete() { sky = new Sky({width:w, height:h}); sky.addToStage(scope.stage); ground = new Ground({width:w, height:h}); hill = new Hill({width:w, height:h, scaleFactor: 4, assetName: 'hill', groundHeight: ground.getHeight()}); hill.setAlpha(0.5); hill.addToStage(scope.stage); hill2 = new Hill({width:w, height:h, scaleFactor: 3, assetName: 'hill2', groundHeight: ground.getHeight()}); hill2.addToStage(scope.stage); ground.addToStage(scope.stage); grant = new Character({characterAssetName: 'grant', y: 34}) grant.addToStage(scope.stage); scope.stage.addEventListener('stagemousedown', handleJumpStart); createjs.Ticker.timingMode = createjs.Ticker.RAF; createjs.Ticker.addEventListener('tick', tick); } function handleJumpStart() { grant.playAnimation('jump'); } function tick(event) { var deltaS = event.delta / 1000; var position = grant.getX() + 150 * deltaS; grant.setX((position >= w + grant.getWidth()) ? -grant.getWidth() : position); ground.setX((ground.getX() - deltaS * 150) % ground.getTileWidth()); hill.move(deltaS * -30, 0); if (hill.getX() + hill.getImageWidth() * hill.getScaleX() <= 0) { hill.setX(w); } hill2.move(deltaS * -45, 0); if (hill2.getX() + hill2.getImageWidth() * hill2.getScaleX() <= 0) { hill2.setX(w); } scope.stage.update(event); } } } }]);
Μην ξεχάσετε να προσθέσετε όλα αυτά τα νέα αρχεία JS στο uiClasses
.
Τώρα, πρέπει να ενημερώσουμε την οδηγία για τα παιχνίδια.
keyDown
Σημειώστε ότι η μετακίνηση handleComplete()
από την οδηγία μείωσε το μέγεθος της οδηγίας κατά 20%, από 91 σε 65 γραμμές.
Επιπλέον, μπορούμε να γράψουμε ανεξάρτητα δοκιμές για κάθε κατηγορία εργοστασίων για να απλοποιήσουμε τη συντήρησή του.
πώς να ερμηνεύσετε τα αποτελέσματα της προσομοίωσης Monte Carlo
Σημείωση: Η δοκιμή είναι ένα θέμα που δεν καλύπτεται σε αυτήν την ανάρτηση αλλά εδώ είναι ένα καλό μέρος για να ξεκινήσετε.
Σε αυτό το σημείο στο σεμινάριο παιχνιδιών HTML5 Canvas, το κλικ ή το πάτημα του ποντικιού σε ένα κινητό θα κάνει τον άντρα μας να πηδήξει και δεν μπορούμε να τον σταματήσουμε. Ας προσθέσουμε τα πλήκτρα βέλους:
Για να το κάνετε αυτό, δημιουργήστε το function keydown(event) { if (event.keyCode === 38) {//if keyCode is 'Up' handleJumpStart(); } if (event.keyCode === 39) {//if keyCode is 'Right' if (scope.status === 'paused') { createjs.Ticker.addEventListener('tick', tick); scope.status = 'running'; } } if (event.keyCode === 37) {//if keyCode is 'Left' createjs.Ticker.removeEventListener('tick', tick); scope.status = 'paused'; } } window.onkeydown = keydown;
λειτουργία και προσθέστε ένα πρόγραμμα ακρόασης ως τελευταία γραμμή loadQueue
λειτουργία.
PreloaderJS
Δοκιμάστε να εκτελέσετε ξανά το παιχνίδι σας και ελέγξτε τα στοιχεία ελέγχου πληκτρολογίου.
Τα παιχνίδια δεν είναι διασκεδαστικά χωρίς μουσική, οπότε ας παίξουμε κάποια μουσική.
Πρώτα θα πρέπει να προσθέσουμε αρχεία MP3 στο φάκελο της εφαρμογής / στοιχείων. Μπορείτε να τα κατεβάσετε από τις διευθύνσεις URL που παρέχονται παρακάτω.
Τώρα, πρέπει να προφορτώσουμε αυτά τα αρχεία ήχου χρησιμοποιώντας την υπηρεσία φόρτωσης. Θα χρησιμοποιήσουμε app/view1/services/loaderSvc.js
από myServices.service('loaderSvc', function () { var manifest = [ {src: 'spritesheet_grant.png', id: 'grant'}, {src: 'sky.png', id: 'sky'}, {src: 'ground.png', id: 'ground'}, {src: 'hill1.png', id: 'hill'}, {src: 'hill2.png', id: 'hill2'}, {src: 'runningTrack.mp3', id: 'runningSound'}, {src: 'jump.mp3', id: 'jumpingSound'} ], loader = new createjs.LoadQueue(true); // need this so it doesn't default to Web Audio createjs.Sound.registerPlugins([createjs.HTMLAudioPlugin]); loader.installPlugin(createjs.Sound); this.getResult = function (asset) { return loader.getResult(asset); }; this.getLoader = function () { return loader; }; this.loadAssets = function () { loader.loadManifest(manifest, true, '/app/assets/'); }; });
βιβλιοθήκη. Ενημερώστε το myDirectives.directive('spriteSheetRunner', [ 'loaderSvc', 'Sky', 'Ground', 'Hill', 'Character', function (loaderSvc, Sky, Ground, Hill, Character) { 'use strict'; return { restrict : 'EAC', replace : true, scope :{ }, template: '', link: function (scope, element, attribute) { var w, h, sky, grant, ground, hill, hill2, runningSoundInstance, status; drawGame(); function drawGame() { //drawing the game canvas from scratch here if (scope.stage) { scope.stage.autoClear = true; scope.stage.removeAllChildren(); scope.stage.update(); } else { scope.stage = new createjs.Stage(element[0]); } w = scope.stage.canvas.width; h = scope.stage.canvas.height; loaderSvc.getLoader().addEventListener('complete', handleComplete); loaderSvc.loadAssets(); } function handleComplete() { sky = new Sky({width:w, height:h}); sky.addToStage(scope.stage); ground = new Ground({width:w, height:h}); hill = new Hill({width:w, height:h, scaleFactor: 4, assetName: 'hill', groundHeight: ground.getHeight()}); hill.setAlpha(0.5); hill.addToStage(scope.stage); hill2 = new Hill({width:w, height:h, scaleFactor: 3, assetName: 'hill2', groundHeight: ground.getHeight()}); hill2.addToStage(scope.stage); ground.addToStage(scope.stage); grant = new Character({characterAssetName: 'grant', y: 34}); grant.addToStage(scope.stage); scope.stage.addEventListener('stagemousedown', handleJumpStart); createjs.Ticker.timingMode = createjs.Ticker.RAF; createjs.Ticker.addEventListener('tick', tick); // start playing the running sound looping indefinitely runningSoundInstance = createjs.Sound.play('runningSound', {loop: -1}); scope.status = 'running'; window.onkeydown = keydown; } function keydown(event) { if (event.keyCode === 38) {//if keyCode is 'Up' handleJumpStart(); } if (event.keyCode === 39) {//if keyCode is 'Right' if (scope.status === 'paused') { createjs.Ticker.addEventListener('tick', tick); runningSoundInstance = createjs.Sound.play('runningSound', {loop: -1}); scope.status = 'running'; } } if (event.keyCode === 37) {//if keyCode is 'Left' createjs.Ticker.removeEventListener('tick', tick); createjs.Sound.stop(); scope.status = 'paused'; } } function handleJumpStart() { if (scope.status === 'running') { createjs.Sound.play('jumpingSound'); grant.playAnimation('jump'); } } function tick(event) { var deltaS = event.delta / 1000; var position = grant.getX() + 150 * deltaS; grant.setX((position >= w + grant.getWidth()) ? -grant.getWidth() : position); ground.setX((ground.getX() - deltaS * 150) % ground.getTileWidth()); hill.move(deltaS * -30, 0); if (hill.getX() + hill.getImageWidth() * hill.getScaleX() <= 0) { hill.setX(w); } hill2.move(deltaS * -45, 0); if (hill2.getX() + hill2.getImageWidth() * hill2.getScaleX() <= 0) { hill2.setX(w); } scope.stage.update(event); } } } }]);
για να προφορτώσετε αυτά τα αρχεία.
index.html
Τροποποιήστε την οδηγία παιχνιδιού σας για να παίξετε ήχους σε εκδηλώσεις παιχνιδιών.
app/view1/view1.html
Σχετίζεται με: Βέλτιστες πρακτικές και συμβουλές του AngularJS από τους ApeeScape Developers Ας προσθέσουμε τους δείκτες σκορ και ζωής (καρδιά) στο παιχνίδι HTML5 Canvas. Το σκορ θα εμφανίζεται ως αριθμός στην επάνω αριστερή γωνία και τα σύμβολα καρδιάς, στην επάνω δεξιά γωνία, θα υποδεικνύουν τον αριθμό ζωής.
Θα χρησιμοποιήσουμε μια εξωτερική βιβλιοθήκη γραμματοσειρών για να αποδώσουμε καρδιές, οπότε προσθέστε την ακόλουθη γραμμή στο
αρχείο:Score: {{score}}
Life: 1' class='fa fa-heart'> 2' class='fa fa-heart'> .top-left { position: absolute; left: 30px; top: 10px; } .top-right { position: absolute; right: 100px; top: 10px; float: right; }
lifesCount
Για να τοποθετήσουμε σωστά τους δείκτες μας, πρέπει να προσθέσουμε τάξεις CSS για πάνω-αριστερά και πάνω-δεξιά στο app/view1/view1.js
αρχείο.
'use strict'; angular.module('myApp.view1', ['ngRoute']) .config(['$routeProvider', function($routeProvider) { $routeProvider.when('/view1', { templateUrl: 'view1/view1.html', controller: 'View1Ctrl' }); }]) .controller('View1Ctrl', ['$scope', function($scope) { $scope.score = 0; $scope.lifesCount = 3; }]);
Αρχικοποιήστε το σκορ και ... replace : true, scope :{ score: '=score', lifesCount: '=lifesCount' }, template: ...
μεταβλητές σε handleComplete()
ελεγκτής.
scope.score = 10; scope.lifesCount = 2; scope.$apply();
Για να βεβαιωθείτε ότι οι δείκτες ενημερώνονται σωστά, τροποποιήστε την κύρια οδηγία παιχνιδιού για να χρησιμοποιήσετε τις μεταβλητές πεδίου.
app/view1/view1.js
Για να δοκιμάσετε τη δέσμευση πεδίου, προσθέστε αυτές τις τρεις γραμμές στο τέλος του $window
μέθοδος.
'use strict'; angular.module('myApp.view1', ['ngRoute']) .config(['$routeProvider', function($routeProvider) { $routeProvider.when('/view1', { templateUrl: 'view1/view1.html', controller: 'View1Ctrl' }); }]) .controller('View1Ctrl', ['$scope', '$window', function($scope, $window) { $scope.windowWidth = $window.innerWidth; $scope.gameHeight = 400; $scope.score = 0; $scope.lifesCount = 3; }]);
Όταν εκτελείτε την εφαρμογή θα πρέπει να δείτε τους δείκτες βαθμολογίας και ζωής.
Πρόσθετος λευκός χώρος, στα δεξιά της σελίδας, θα συνεχίσει να υπάρχει επειδή εξακολουθούμε να κωδικοποιούμε το πλάτος και το ύψος του παιχνιδιού σε αυτό το σημείο στο σεμινάριο προγραμματισμού παιχνιδιών HTML5.
Το AngularJS είναι γεμάτο με χρήσιμες μεθόδους και υπηρεσίες. Ένα από αυτά είναι $ window, το οποίο παρέχει μια ιδιότητα innerWidth που θα χρησιμοποιήσουμε για τον υπολογισμό της θέσης των στοιχείων μας.
Τροποποιήστε το ... scope :{ width: '=width', height: '=height', score: '=score', lifesCount: '=lifesCount' }, ... drawGame(); element[0].width = scope.width; element[0].height = scope.height; w = scope.width; h = scope.height; function drawGame() { ...
για ένεση
|_+_|υπηρεσία.
|_+_|
Επεκτείνετε την κύρια οδηγία παιχνιδιού με ιδιότητες πλάτους και ύψους και αυτό είναι!
|_+_|
Τώρα έχετε το παιχνίδι να προσαρμόζεται στο πλάτος του παραθύρου του προγράμματος περιήγησης.
Εάν θέλετε να το μεταφέρετε σε μια εφαρμογή για κινητά, προτείνω να διαβάσετε το άλλο εκπαιδευτικό πρόγραμμα για την εφαρμογή για κινητά χρησιμοποιώντας το Ionic framework για τη δημιουργία εφαρμογών για κινητά . Θα πρέπει να μπορείτε να δημιουργήσετε μια εφαρμογή ιονικού σπόρου, να αντιγράψετε όλο τον κώδικα από αυτό το έργο και να ξεκινήσετε να παίζετε το παιχνίδι στην κινητή συσκευή σας σε λιγότερο από μία ώρα.
Το μόνο πράγμα που δεν καλύπτω εδώ είναι η ανίχνευση σύγκρουσης. Για να μάθω περισσότερα γι 'αυτό, διάβασα αυτό το άρθρο .
Πιστεύω ότι κατά τη διάρκεια αυτού του σεμιναρίου ανάπτυξης παιχνιδιών το καταλάβατε Γωνιακό JS και το CreateJS είναι ένα νικηφόρο δίδυμο για ανάπτυξη παιχνιδιών με βάση το HTML5. Έχετε όλα τα βασικά και είμαι βέβαιος ότι αναγνωρίσατε τα οφέλη από το συνδυασμό αυτών των δύο πλατφορμών.
αναφέρετε τρεις από τις πιο κοινές επιθέσεις διαδικτυακών εφαρμογών
Μπορείτε να κατεβάσετε τον κωδικό για αυτό το άρθρο από GitHub , μη διστάσετε να χρησιμοποιήσετε, να μοιραστείτε και να το κάνετε δικό σας.
Σχετίζεται με: Κορυφαία 18 πιο κοινά λάθη AngularJS που κάνουν οι προγραμματιστές