Ich habe schon einmal in Donnets DEMO ein Masturbationsspiel gesehen und dann die Bilder und den Ton davon heruntergenommen. . . . Ich habe es nur zum Spaß umgeschrieben. Nur zur Unterhaltung. . . . . . Ich verwende kein Framework, ich schreibe alle JS selbst. . . . . . Dies ist also ein einfaches Tutorial, das für diejenigen hilfreich sein kann, die noch keine Erfahrung mit Canvas haben. Bitte verzeihen Sie mir.
Beginnen wir ohne weitere Umschweife mit der DEMO: Airplane Game. Der Originalposter hat dies nur zum Spaß geschrieben und hatte nicht die Absicht, daraus ein ernstes Spiel zu machen.
Kommen wir zum Thema: Die Masturbationsspieldatei enthält die Index.html-Eintragsdatei, die Logikverarbeitungsdatei des Sprites allSprite.js, die Loading.js-Ladeverarbeitungsdatei und data.js (einige initialisierte Daten).
Zunächst einmal erfordern normale Spiele grundsätzlich ein Laden. Die Ladeseite wird zum Vorladen von Daten verwendet, einschließlich Sprite-Sheet-Bildern, Audio usw. Da es sich um ein kleines Spiel handelt, müssen nur einige Audio- und Bilddateien geladen werden. Der darin enthaltene Ladecode dient hauptsächlich der Erstellung von Ladeanimationen. Wenn Sie interessiert sind, schauen Sie sich einfach die Konsole in der DEMO an >
XML/HTML-Code
Inhalt in die Zwischenablage kopieren
- loadImg:function(datas){
-
var _this = this;
-
var dataIndex = 0;
- li();
- function li(){
-
if(datas[dataIndex].indexOf("mp3")>=0){
-
var audio = document.createElement("audio");
- document.body.appendChild(audio);
-
-
dataIndex ;
if(dataIndex
===datas.length){ -
}else {
-
li.call(_this);
}
} -
}sonst {
- preLoadImg(datas[dataIndex] , function(){
- dataIndex ;
-
if(dataIndex===datas.length){
-
} else {
- li.call(_this);
-
}
})
}
- }
- },
-
- //再贴出preLoadImg的方法
- function preLoadImg(src , callback){
- var
img- =
neu- Image();
-
img.src-
= src;
if(img.complete){
callback.call(img);
-
}sonst {
img.onload- =
function- (){
- callback.call(img);
-
}
}
}
-
-
Ich verwende zuerst ein Array, um die Links zu den Dateien in data.js zu speichern, und bestimme dann, ob es sich bei diesen Links um Bilder oder Audios handelt, um sie mit preLoadImg zu laden ist sehr einfach: Erstellen Sie einfach ein neues Objekt, weisen Sie ihm den Link zu und rufen Sie es nach dem Laden wieder auf. Audio wird geladen, indem ein HTML5-Audio-Dom-Objekt generiert und ihm der Link zugewiesen wird. Wenn der Browser erwartet, dass er die angegebene Audio-/Videowiedergabe fortsetzen kann, ohne ihn zum Puffern anzuhalten, tritt das Ereignis „canplaythrough“ auf , was bedeutet, dass beim Aufruf von canplaythrough das Audio fast geladen wurde und das nächste Audio geladen werden kann. Einfach so: Nachdem alles geladen ist, erfolgt der Rückruf und das Spiel beginnt.
Das Spiel erfordert viele Objekte, daher habe ich sie in einem Sprite-Objekt zusammengefasst. Die Bewegung jedes Frames zwischen verschiedenen Objekten kann mithilfe des Verhaltens separat geschrieben werden.
XML/HTML-CodeInhalt in die Zwischenablage kopieren
- W.Sprite = Funktion(Name , Maler , Verhalten , Argumente){
-
if(name !== undefiniert) this.name = name;
-
if(maler !== undefiniert) this.painter = maler;
-
this.top = 0;
-
this.left = 0;
-
this.width = 0;
-
this.height = 0;
-
this.velocityX = 3;
-
this.velocityY = 2;
-
this.visible = true;
-
this.animating = false;
-
this.behaviors = behaviors;
-
this.rotateAngle = 0;
-
this.blood = 50;
-
this.fullBlood = 50;
-
if(name==="plan"){
-
this.rotateSpeed = 0.05;
-
this.rotateLeft = false;
-
this.rotateRight = false;
-
this.fire = false;
-
this.firePerFrame = 10;
-
this.fireLevel = 1;
-
}else if(name==="star"){
-
this.width = Math.random()*2;
-
this.speed = 1*this.width/2;
-
this.lightLength = 5;
-
this.cacheCanvas = document.createElement("canvas");
-
thisthis.cacheCtx = this.cacheCanvas.getContext('2d');
-
thisthis.cacheCanvas.width = this.width this.lightLength*2;
-
thisthis.cacheCanvas.height = this.width this.lightLength*2;
- this.painter.cache(this);
-
}else if(name==="badPlan"){
-
this.badKind = 1;
-
this.speed = 2;
-
this.rotateAngle = Math.PI;
-
}else if(name==="missle"){
-
this.width = missleWidth;
-
}else if(name==="boom"){
-
this.width = boomWidth;
-
}else if(name==="food"){
-
this.width = 40;
-
this.speed = 3;
-
this.kind = "LevelUP"
- }
-
this.toLeft = false;
-
this.toTop = false;
-
this.toRight = false;
-
this.toBottom = false;
-
-
this.outArcRadius = Math.sqrt((this.width/2*this.width/2 )*2);
-
- if(args){
- for(var arg in args){
- this[arg] = args[arg];
- }
- }
- }
-
Sprite.prototype = {
- constructor:Sprite,
- paint:function(){
-
if(this.name==="badPlan"){this.update();}
-
- if(this.painter !== undefiniert && this.visible){
- if(this.name!=="badPlan") {
- this.update();
- }
-
if(this.name==="plan"||this.name===" missle"||this.name==="badPlan"){
- ctx.save();
- ctx.translate(this.left , this.top);
- ctx.rotate(this.rotateAngle);
- this.painter.paint(this);
- ctx.restore();
- }else {
- this.painter.paint(this);
- }
- }
- },
- update:function(time){
- if(this.behaviors){
-
for(var i=0;i<this.behaviors.length;i ){
- this.behaviors[i].execute(this,time);
-
- }
- }
-
Nachdem Sie die Elf-Klasse geschrieben haben, können Sie verschiedene Objekte generieren, indem Sie jeden Maler und jedes Verhalten schreiben. Der nächste Schritt besteht darin, Maler zu schreiben. Der eine ist der normale Maler und der andere der Sprite-Sheet-Maler. Da Explosionsanimationen und Flugzeugschießanimationen nicht mit nur einem Bild erstellt werden können, müssen Sie es verwenden zum Spritesheet:
Um diese zu zeichnen, müssen Sie einen Sprite-Sheet-Maler anpassen. Je nach Komplexität des Spiels kann die Sprite-Sheet-Schreibmethode jedoch entsprechend geändert werden , die Prinzipien sind ähnlich, das heißt nur geringfügige Änderungen:
XML/HTML-Code
Inhalt in die Zwischenablage kopieren
- var SpriteSheetPainter = Funktion(Zellen){
- this.cells = Zellen || [];
- this.cellIndex = 0;
- }
- SpriteSheetPainter.prototype = {
- advance:function(){
- if(this.cellIndex === this.cells.length-1){
-
}
else this.cellIndex ;
- },
- paint:function(sprite){
- var
cell- =
this- .cells[this.cellIndex];
context.drawImage(spritesheet , cell.x , cell.y , cell.w , cell.h , sprite.left , sprite.top , cell.w , cell.h);
}
- }
-
-
而普通的绘制器就更简单了,直接写一个painter,把要画的什么东西都写进去就行了.
有了精灵类和精灵表绘制器后, 我们就可以把星星, 飞机, 子弹, 爆炸对象都写出来了:下面是整个allSprite.js的代码:
JavaScript-Code
复制内容到剪贴板
- (Funktion(W){
- "strikt verwenden"
- var planWidth = 24,
- planHeight = 24,
- missleWidth = 70,
- missleHeight = 70,
- boomWidth = 60;
-
- W.Sprite = Funktion(Name , Maler , Verhalten , Argumente){
- if(name !== undefiniert) this.name = name;
- if(painter !== undefiniert) this.painter = painter;
- dieses.top = 0;
- dieses.left = 0;
- dieses.width = 0;
- this.height = 0;
- dieses.velocityX = 3;
- this.velocityY = 2;
- this.visible = true;
- this.animating = false;
- dies.behaviors = behaviors;
- this.rotateAngle = 0;
- dieses.blood = 50;
- dieses.fullBlood = 50;
- if(name==="plan"){
- dies.rotateSpeed = 0.05;
- this.rotateLeft = false;
- this.rotateRight = false;
- this.fire = false;
- dieses.firePerFrame = 10;
- dieses.fireLevel = 1;
- }else if(name==="star" ){
- dieses.width = Math.random()*2;
- this.speed = 1*this.width/2;
- dieses.lightLength = 5;
- this.cacheCanvas = document.createElement("canvas");
- this.cacheCtx = this.cacheCanvas.getContext('2d');
- this.cacheCanvas.width = this.width this.lightLength*2;
- this.cacheCanvas.height = this.width this.lightLength*2;
- this.painter.cache(this);
- }else if(name==="badPlan" ){
- dieses.badKind = 1;
- dieses.speed = 2;
- this.rotateAngle = Math.PI;
- }else if(name==="missle" ){
- dieses.width = missleWidth;
- }else if(name==="boom" ){
- dieses.width = boomWidth;
- }else if(name==="food"){
- dieses.width = 40;
- dieses.speed = 3;
- dies.kind = "LevelUP"
- }
- this.toLeft = false;
- this.toTop = false;
- this.toRight = false;
- this.toBottom = false;
-
- this.outArcRadius = Math.sqrt((this.width/2*this.width/2)*2);
-
- if(args){
- for(var arg in args){
- dies[arg] = args[arg];
- }
- }
- }
- Sprite.prototype = {
- constructor:Sprite,
- paint:function(){
- if(this.name==="badPlan" ){this.update();}
-
- if(this.painter !== undefined && this .sichtbar){
- ) {
this.update();
}
- ||dieses.name==="missle"||dieses .name==="badPlan"){
ctx.save();
ctx.translate(this.left ,
- this.top);
-
ctx.rotate(this.rotateAngle);
-
ctx.restore();
}
- else {
}
-
}
-
},
Update:
- Funktion(Zeit){
if(
- this.behaviors){
-
🎜>.behaviors.length;i ){
-
-
}
}
-
}
}
-
-
- W.SpriteSheetPainter = fonction(cellules , isloop , endCallback , spritesheet){
- ce.cells = cells || [] ;
- ce.cellIndex = 0 ;
- this.dateCount = null;
- ce.isloop = isloop;
- ce.endCallback = endCallback ;
- this.spritesheet = spritesheet ;
- }
- SpriteSheetPainter.prototype = {
- avance :fonction(){
- ce.cellIndex = ce.isloop?(ce.cellIndex===ce.cells.length-1?0:ce.cellIndex 1):(ce.cellIndex 1);
- },
- peinture :fonction(sprite){
- if(this.dateCount===null){
- this.dateCount = new Date();
- }autre {
- var newd = nouveau Date();
- var tc = newd-this.dateCount;
- si(tc>40){
-
ceci.advance();
-
ce.dateCount = newd;
- }
- }
-
if(this.cellIndex<this. cellules.longueur || ce.isloop){
- var cell = ceci.cells[ceci .cellIndex];
- ctx.drawImage(this.spritesheet , cell.x , cell.y , cell.w , cell.h , sprite.left-sprite.width/ 2 , sprite.top-sprite.width/2 , cell.w , cell.h);
- } else si(this.endCallback) {
- ceci.endCallback.call(sprite);
- ceci.cellIndex = 0 ;
- }
- }
- }
-
-
- W.controllSpriteSheetPainter = fonction(cellules , spritesheet){
- ce.cells = cells || [] ;
- ce.cellIndex = 0 ;
- this.dateCount = null;
- this.isActive = false;
- ce.derection = vrai;
- this.spritesheet = spritesheet ;
- }
- controllSpriteSheetPainter.prototype = {
- avance :fonction(){
- si(this.isActive){
- ceci.cellIndex ;
- si(ce.cellIndex === ce.cells.length){
- ce.cellIndex = 0 ;
- this.isActive = false;
- }
- }
- },
- peinture :fonction(sprite){
- if(this.dateCount===null){
- this.dateCount = new Date();
- }autre {
- var newd = nouveau Date();
- var tc = newd-this.dateCount;
- if(tc>sprite.firePerFrame){
-
ceci.advance();
-
ce.dateCount = newd;
- }
- }
-
var cell = ceci.cells[ceci .cellIndex];
-
ctx.drawImage(this.spritesheet , cell.x , cell.y , cell.w , cell.h , -planWidth/2 , -planHeight/ 2 , cellule.w , cellule.h);
- }
- }
-
- W.planBehavior = [
-
{exécuter :fonction(sprite,heure){
-
if(sprite.toTop){
- sprite.top = sprite.top
- }
- if(sprite.toLeft){
- sprite.left = sprite.left
- }
- si(sprite.toRight){
- sprite.left = sprite.left>canvas.width-planWidth/2? sprite.left : sprite.left sprite.velocityX ;
- }
-
si(sprite.toBottom){
- sprite.top = sprite.top>canvas.height-planHeight/2? sprite.top : sprite.top sprite.velocityY ;
- }
-
if(sprite.rotateLeft){
- sprite.rotateAngle -= sprite.rotateSpeed;
- }
-
if(sprite.rotateRight){
- sprite.rotateAngle = sprite.rotateSpeed;