search
HomeWeb Front-endH5 TutorialUsing HTML5 Canvas to realize masturbation game

This article mainly introduces the use of HTML5 Canvas to create a simple masturbation game. The author also provides the relevant Javascript code. Friends who need it can refer to

which was previously posted in Dang Knight’s DEMO. I saw a masturbation game and pulled down its pictures and audio. . . . I re-wrote it just for fun. Just for entertainment. . . . . . I don't use a framework, I write all the js myself. . . . . . So this is a simple tutorial. It may be helpful to those who are new to canvas. The author has not been playing canvas for a long time and his skills are not very good. Please forgive me.

Without further ado, let’s start with the DEMO: Airplane Game. The original poster wrote this purely for entertainment and did not intend to write it into a formal game.

Let’s get into the topic: The masturbation game files include the index.html entry file, the logic processing file of allSprite.js sprite, the loading.js loading processing file and data.js (some initialized data).

First of all, normal games basically require a loading. The loading page is used to preload data, including sprite sheet images, audio, etc. Because this is a small game, the only things that need to be loaded are some audio and picture. The loading code inside is mainly the following. The others are for making loading animations. The one is relatively simple, so I won’t post it. If you are interested, just look at the console in the DEMO:

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);   
                    audio.preload = "auto";   
                    audio.src = datas[dataIndex];   
                    audio.oncanplaythrough = function(){   
                        this.oncanplaythrough = null;   
                        dataIndex++;   
                        if(dataIndex===datas.length){   
                            _this.percent = 100;   
                        }else {   
                            _this.percent = parseInt(dataIndex/datas.length*100);   
                            li.call(_this);   
                        }   
                    }   
                }else {   
                    preLoadImg(datas[dataIndex] , function(){   
                        dataIndex++;   
                        if(dataIndex===datas.length){   
                            _this.percent = 100;   
                        } else {   
                            _this.percent = parseInt(dataIndex/datas.length*100);   
                            li.call(_this);   
                        }   
                    })   
                }   
            }   
        },   
//再贴出preLoadImg的方法   
function preLoadImg(src , callback){   
    var img = new Image();   
    img.src = src;   
    if(img.complete){   
        callback.call(img);   
    }else {   
        img.onload = function(){   
            callback.call(img);   
        }   
    }   
}

I first use an array to save links to files in data.js, and then determine whether these links are pictures or audios. If they are pictures, use preLoadImg to load them. The code for preloading pictures is very simple. It is a new picture object, and then The link is assigned to it and called back after loading. Audio is loaded by generating an HTML5 audio dom object and assigning the link to it. Audio has an event "canplaythrough". When the browser expects to be able to continue playing the specified audio/video without stopping for buffering, The canplaythrough event will occur, which means that when canplaythrough is called, the audio has almost been loaded and the next audio can be loaded. Just like this, after everything is loaded, the callback is made and the game starts.

The game started. A game will require a lot of objects, so I unified it into a sprite object. The movement of each frame between different objects can be written separately using behavior. .

W.Sprite = function(name , painter , behaviors , args){   
    if(name !== undefined) this.name = name;   
    if(painter !== undefined) this.painter = painter;   
    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 !== undefined && 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);   
            }   
        }   
    }   
}

After writing the elf class, you can generate different objects by writing each painter and behavior. The next step is to write painters. Painters are divided into two types, one is ordinary painter, and the other is sprite sheet painter. Because explosion animations and airplane shooting animations cannot be done with just one picture, so you need to use It’s time for the sprite sheet:
2015511181456172.png (168×24)

2015511181533636.png (896×64)

To draw these, you need to customize a sprite sheet painter for them. The following is the simplest sprite. Table renderer, according to the complexity of the game, you can relatively modify the sprite sheet writing method until it is suitable, but the principles are similar, just minor modifications:

var SpriteSheetPainter = function(cells){   
            this.cells = cells || [];   
            this.cellIndex = 0;   
        }   
        SpriteSheetPainter.prototype = {   
            advance:function(){   
                if(this.cellIndex === this.cells.length-1){   
                    this.cellIndex = 0;   
                }   
                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);   
            }   
        }

And the ordinary renderer is It’s even simpler, just write a painter and write everything you want to paint.

With the sprite class and sprite sheet renderer, we can write stars, planes, bullets, and explosion objects: The following is the code of the entire allSprite.js:

(function(W){   
    "use strict"
    var planWidth = 24,   
        planHeight = 24,   
        missleWidth = 70,   
        missleHeight = 70,   
        boomWidth = 60;   
    //精灵类 
    W.Sprite = function(name , painter , behaviors , args){   
        if(name !== undefined) this.name = name;   
        if(painter !== undefined) this.painter = painter;   
        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");   
            this.cacheCtx = this.cacheCanvas.getContext(&#39;2d&#39;);   
            this.cacheCanvas.width = this.width+this.lightLength*2;   
            this.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 !== undefined && 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);   
                }   
            }   
        }   
    }   
    // 精灵表绘制器 
    W.SpriteSheetPainter = function(cells , isloop , endCallback , spritesheet){   
        this.cells = cells || [];   
        this.cellIndex = 0;   
        this.dateCount = null;   
        this.isloop = isloop;   
        this.endCallback = endCallback;   
        this.spritesheet = spritesheet;   
    }   
    SpriteSheetPainter.prototype = {   
        advance:function(){   
            this.cellIndex = this.isloop?(this.cellIndex===this.cells.length-1?0:this.cellIndex+1):(this.cellIndex+1);   
        },   
        paint:function(sprite){   
            if(this.dateCount===null){   
                this.dateCount = new Date();   
            }else {   
                var newd = new Date();   
                var tc = newd-this.dateCount;   
                if(tc>40){   
                    this.advance();   
                    this.dateCount = newd;   
                }   
            }   
            if(this.cellIndex<this.cells.length || this.isloop){   
                var cell = this.cells[this.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 if(this.endCallback){   
                this.endCallback.call(sprite);   
                this.cellIndex = 0;   
            }   
        }   
    }   
    //特制飞机精灵表绘制器 
    W.controllSpriteSheetPainter = function(cells , spritesheet){   
        this.cells = cells || [];   
        this.cellIndex = 0;   
        this.dateCount = null;   
        this.isActive = false;   
        this.derection = true;   
        this.spritesheet = spritesheet;   
    }   
    controllSpriteSheetPainter.prototype = {   
        advance:function(){   
            if(this.isActive){   
                this.cellIndex++;   
                if(this.cellIndex === this.cells.length){   
                    this.cellIndex = 0;   
                    this.isActive = false;   
                }   
            }   
        },   
        paint:function(sprite){   
            if(this.dateCount===null){   
                this.dateCount = new Date();   
            }else {   
                var newd = new Date();   
                var tc = newd-this.dateCount;   
                if(tc>sprite.firePerFrame){   
                    this.advance();   
                    this.dateCount = newd;   
                }   
            }   
            var cell = this.cells[this.cellIndex];   
            ctx.drawImage(this.spritesheet , cell.x , cell.y , cell.w , cell.h , -planWidth/2 , -planHeight/2 , cell.w , cell.h);   
        }   
    }   
    W.planBehavior = [   
        {execute:function(sprite,time){   
            if(sprite.toTop){   
                sprite.top = sprite.top<planHeight/2? sprite.top : sprite.top-sprite.velocityY;   
            }   
            if(sprite.toLeft){   
                sprite.left = sprite.left<planWidth/2? sprite.left : sprite.left-sprite.velocityX;   
            }   
            if(sprite.toRight){   
                sprite.left = sprite.left>canvas.width-planWidth/2? sprite.left : sprite.left+sprite.velocityX;   
            }   
            if(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;   
            }   
            if(sprite.fire&&!sprite.painter.isActive){   
                sprite.painter.isActive = true;   
                this.shot(sprite);   
            }   
        },   
        shot:function(sprite){   
            this.addMissle(sprite , sprite.rotateAngle);   
            var missleAngle = 0.1   
            for(var i=1;i<sprite.fireLevel;i++){   
                this.addMissle(sprite , sprite.rotateAngle-i*missleAngle);   
                this.addMissle(sprite , sprite.rotateAngle+i*missleAngle);   
            }   
            var audio = document.getElementsByTagName("audio");   
            for(var i=0;i<audio.length;i++){   
                console.log(audio[i].paused)   
                if(audio[i].src.indexOf("shot")>=0&&audio[i].paused){   
                    audio[i].play();   
                    break;   
                }   
            }   
        },   
        addMissle:function(sprite , angle){   
                for(var j=0;j<missles.length;j++){   
                    if(!missles[j].visible){   
                        missles[j].left = sprite.left;   
                        missles[j].top = sprite.top;   
                        missles[j].rotateAngle = angle;   
                        var missleSpeed = 20;   
                        missles[j].velocityX = missleSpeed*Math.sin(-missles[j].rotateAngle);   
                        missles[j].velocityY = missleSpeed*Math.cos(-missles[j].rotateAngle);   
                        missles[j].visible = true;   
                        break;   
                    }   
                }   
            }   
        }   
    ]   
    W.starBehavior = [   
        {execute:function(sprite,time){   
            if(sprite.top > canvas.height){   
                sprite.left = Math.random()*canvas.width;   
                sprite.top = Math.random()*canvas.height - canvas.height;   
            }   
            sprite.top += sprite.speed;   
        }}   
    ]   
    W.starPainter = {   
        paint:function(sprite){   
            ctx.drawImage(sprite.cacheCanvas , sprite.left-sprite.width/2-sprite.lightLength , sprite.top-sprite.width/2-sprite.lightLength)   
        },   
        cache:function(sprite){   
            sprite.cacheCtx.save();   
            var opacity = 0.5,addopa = 1/sprite.lightLength;   
            sprite.cacheCtx.fillStyle = "rgba(255,255,255,0.8)";   
            sprite.cacheCtx.beginPath();   
            sprite.cacheCtx.arc(sprite.width/2+sprite.lightLength , sprite.width/2+sprite.lightLength , sprite.width/2 , 0 , 2*Math.PI);   
            sprite.cacheCtx.fill();   
            for(var i=1;i<=sprite.lightLength;i+=2){   
                opacity-=addopa;   
                sprite.cacheCtx.fillStyle = "rgba(255,255,255,"+opacity+")";   
                sprite.cacheCtx.beginPath();   
                sprite.cacheCtx.arc(sprite.width/2+sprite.lightLength , sprite.width/2+sprite.lightLength , sprite.width/2+i , 0 , 2*Math.PI);   
                sprite.cacheCtx.fill();   
            }   
        }   
    }   
    W.foodBehavior = [   
        {execute:function(sprite,time){   
            sprite.top += sprite.speed;   
            if(sprite.top > canvas.height+sprite.width){   
                sprite.visible = false;   
            }   
        }}   
    ]   
    W.foodPainter = {   
        paint:function(sprite){   
            ctx.fillStyle = "rgba("+parseInt(Math.random()*255)+","+parseInt(Math.random()*255)+","+parseInt(Math.random()*255)+",1)"
            ctx.font="15px 微软雅黑"
            ctx.textAlign = "center";   
            ctx.textBaseline = "middle";   
            ctx.fillText(sprite.kind , sprite.left , sprite.top);   
        }   
    }   
    W.missleBehavior = [{   
        execute:function(sprite,time){   
            sprite.left -= sprite.velocityX;   
            sprite.top -= sprite.velocityY;   
            if(sprite.left<-missleWidth/2||sprite.top<-missleHeight/2||sprite.left>canvas.width+missleWidth/2||sprite.top<-missleHeight/2){   
                sprite.visible = false;   
            }   
        }   
    }];   
    W.misslePainter = {   
        paint:function(sprite){   
            var img = new Image();   
            img.src="../planGame/image/plasma.png"
            ctx.drawImage(img , -missleWidth/2+1 , -missleHeight/2+1 , missleWidth , missleHeight);   
        }   
    }   
    W.badPlanBehavior = [{   
        execute:function(sprite,time){   
            if(sprite.top > canvas.height || !sprite.visible){   
                var random = Math.random();   
                if(point>=200&&point<400){   
                    sprite.fullBlood = 150;   
                    if(random<0.1){   
                        sprite.badKind = 2;   
                        sprite.fullBlood = 250;   
                    }   
                }else if(point>=400&&point<600){   
                    sprite.fullBlood = 250;   
                    if(random<0.2){   
                        sprite.badKind = 2;   
                        sprite.fullBlood = 400;   
                    }   
                    if(random<0.1){   
                        sprite.badKind = 3;   
                        sprite.fullBlood = 600;   
                    }   
                }else if(point>=600){   
                    sprite.fullBlood = 500;   
                    if(random<0.4){   
                        sprite.badKind = 2;   
                        sprite.fullBlood = 700;   
                    }   
                    if(random<0.2){   
                        sprite.badKind = 3;   
                        sprite.fullBlood = 1000;   
                    }   
                }   
                sprite.visible = true;   
                sprite.blood = sprite.fullBlood;   
                sprite.left = Math.random()*(canvas.width-2*planWidth)+planWidth;   
                sprite.top = Math.random()*canvas.height - canvas.height;   
            }   
            sprite.top += sprite.speed;   
        },   
        shot:function(sprite){   
            this.addMissle(sprite , sprite.rotateAngle);   
            var missleAngle = 0.1   
            for(var i=1;i<sprite.fireLevel;i++){   
                this.addMissle(sprite , sprite.rotateAngle-i*missleAngle);   
                this.addMissle(sprite , sprite.rotateAngle+i*missleAngle);   
            }   
        },   
        addMissle:function(sprite , angle){   
            for(var j=0;j<missles.length;j++){   
                if(!missles[j].visible){   
                    missles[j].left = sprite.left;   
                    missles[j].top = sprite.top;   
                    missles[j].rotateAngle = angle;   
                    var missleSpeed = 20;   
                    missles[j].velocityX = missleSpeed*Math.sin(-missles[j].rotateAngle);   
                    missles[j].velocityY = missleSpeed*Math.cos(-missles[j].rotateAngle);   
                    missles[j].visible = true;   
                    break;   
                }   
            }   
        }   
    }];   
    W.badPlanPainter = {   
        paint:function(sprite){   
            var img = new Image();   
            img.src="../planGame/image/ship.png"
            switch(sprite.badKind){   
                case 1:ctx.drawImage(img , 96 , 0 , planWidth , planWidth , -planWidth/2 , -planHeight/2 , planWidth , planWidth);   
                break;   
                case 2:ctx.drawImage(img , 120 , 0 , planWidth , planWidth , -planWidth/2 , -planHeight/2 , planWidth , planWidth);   
                break;   
                case 3:ctx.drawImage(img , 144 , 0 , planWidth , planWidth , -planWidth/2 , -planHeight/2 , planWidth , planWidth);   
                break;   
            }   
            ctx.strokeStyle = "#FFF";   
            ctx.fillStyle = "#F00";   
            var bloodHeight = 1;   
            ctx.strokeRect(-planWidth/2-1 , planHeight+bloodHeight+3 , planWidth+2 , bloodHeight+2);   
            ctx.fillRect(planWidth/2-planWidth*sprite.blood/sprite.fullBlood , planHeight+bloodHeight+3 , planWidth*sprite.blood/sprite.fullBlood , bloodHeight);   
        }   
    }   
    W.planSize = function(){   
        return {   
            w:planWidth,   
            h:planHeight   
        }       
    }   
})(window);

These drawing methods are relatively simple.

Mainly talk about the movement of the aircraft and the control of the number of objects. How does the aircraft move? There is no doubt that by controlling its movement through the keyboard, many people may think of making the aircraft continue to move by judging the keyCode when pressing the keydown method. But there is a problem. The keydown event does not support multiple key presses. That is to say, when you press the X key, the keyCode is 88. At the same time, when you press the direction key, the keyCode will instantly become 37, that is , if you simply want to control the movement of the aircraft with keydown, the aircraft can only do one thing, either it can only move in a certain direction, or it can only shoot.

Therefore, we need to realize the movement of the aircraft through keydown and keyup. The principle is easy to understand: when we press the left direction key, we give the aircraft a left state, which means that the aircraft The toLeft attribute is true, and in the animation loop, the status of the aircraft is judged. If toLeft is true, the x value of the aircraft will continue to decrease, and the aircraft will continue to move to the left, and then the keyup will be triggered when we lift our finger. event, we will release the left state of the aircraft in the keyup event. The plane stopped moving to the left. The same principle applies to other states. If you write it like this, you can make the aircraft have multiple states throughout its life. You can shoot and run around at the same time.

The implemented code is as follows:

//keydown/keyup事件的绑定     
  window.onkeydown = function(event){   
            switch(event.keyCode){   
                case 88:myplan.fire = true;   
                break;   
                case 90:myplan.rotateLeft=true;   
                break;   
                case 67:myplan.rotateRight=true;   
                break;   
                case 37:myplan.toLeft = true;   
                break;   
                case 38:myplan.toTop = true;   
                break;   
                case 39:myplan.toRight = true;   
                break;   
                case 40:myplan.toBottom = true;   
                break;   
            }   
        }   
        window.onkeyup = function(event){   
            switch(event.keyCode){   
                case 88:myplan.fire = false;   
                break;   
                case 90:myplan.rotateLeft=false;   
                break;   
                case 67:myplan.rotateRight=false;   
                break;   
                case 37:myplan.toLeft = false;   
                break;   
                case 38:myplan.toTop = false;   
                break;   
                case 39:myplan.toRight = false;   
                break;   
                case 40:myplan.toBottom = false;   
                break;   
            }   
        }       
//飞机每一帧的状态更新处理代码   
execute:function(sprite,time){   
            if(sprite.toTop){   
                spritesprite.top = sprite.top<planHeight/2? sprite.top : sprite.top-sprite.velocityY;   
            }   
            if(sprite.toLeft){   
                spritesprite.left = sprite.left<planWidth/2? sprite.left : sprite.left-sprite.velocityX;   
            }   
            if(sprite.toRight){   
                spritesprite.left = sprite.left>canvas.width-planWidth/2? sprite.left : sprite.left+sprite.velocityX;   
            }   
            if(sprite.toBottom){   
                spritesprite.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;   
            }   
            if(sprite.fire&&!sprite.painter.isActive){   
                sprite.painter.isActive = true;   
                this.shot(sprite);   
            }

It’s that simple.

  然后说下对象控制,打飞机游戏,会发射大量子弹,产生大量对象,包括爆炸啊,飞机啊,子弹等,如果不停地进行对象的生成和销毁,会让浏览器的负荷变得很大,运行了一段时间后就会卡出翔了。所以,我们要用可以循环利用的对象来解决这个问题,不进行对象的销毁,对所有对象进行保存,循环利用。

  我的做法就是,在游戏初始化的时候,直接生成一定数量的对象,存放在数组里面。当我们需要一个对象的时候,就从里面取,当用完后,再放回数组里面。数组里的所有对象都有一个属性,visible,代表对象当前是否可用。

  举个例子,当我的飞机发射一发炮弹,我需要一发炮弹,所以我就到炮弹数组里遍历,如果遍历到的炮弹visible为true,也就说明该对象正在使用着,不能拿来用,所以继续遍历,直到遍历到visible为false的炮弹对象,说明这个对象暂时没人用。然后就可以拿过来重新设置属性,投入使用了。当炮弹击中敌人或者打出画布外的时候,把炮弹的visible设成false,又成了一个没人用的炮弹在数组里存放起来等待下一次调用。

  所以,我们要预算算好页面大概要用到多少个对象,然后就预先准备好对象,这样,在游戏进行中,不会有对象进行生成和销毁,对游戏性能方面就有了提升了。

    最后再说下音频,游戏里面要用到多个同样的audio才能保证音效的不间断性:

var audio = document.getElementsByTagName("audio");   
                                            for(var i=0;i<audio.length;i++){   
                                                console.log(audio[i].paused)   
                                                if(audio[i].src.indexOf("boom")>=0&&audio[i].paused){   
                                                    audio[i].play();   
                                                    break;   
                                                }   
                                            }

好吧,基本上就这样了。技术或许还不够好,纯碎做个记录,如果代码有不当正处,欢迎指出,共同学习。

以上就是本文的全部内容,希望对大家的学习有所帮助,更多相关内容请关注PHP中文网!

相关推荐:

html5和css3 动态气泡按钮的实现

如何使用jQuery和HTML5实现手机摇一摇的换衣特效

The above is the detailed content of Using HTML5 Canvas to realize masturbation game. For more information, please follow other related articles on the PHP Chinese website!

Statement
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn
HTML5 and H5: Understanding the Common UsageHTML5 and H5: Understanding the Common UsageApr 22, 2025 am 12:01 AM

There is no difference between HTML5 and H5, which is the abbreviation of HTML5. 1.HTML5 is the fifth version of HTML, which enhances the multimedia and interactive functions of web pages. 2.H5 is often used to refer to HTML5-based mobile web pages or applications, and is suitable for various mobile devices.

HTML5: The Building Blocks of the Modern Web (H5)HTML5: The Building Blocks of the Modern Web (H5)Apr 21, 2025 am 12:05 AM

HTML5 is the latest version of the Hypertext Markup Language, standardized by W3C. HTML5 introduces new semantic tags, multimedia support and form enhancements, improving web structure, user experience and SEO effects. HTML5 introduces new semantic tags, such as, ,, etc., to make the web page structure clearer and the SEO effect better. HTML5 supports multimedia elements and no third-party plug-ins are required, improving user experience and loading speed. HTML5 enhances form functions and introduces new input types such as, etc., which improves user experience and form verification efficiency.

H5 Code: Writing Clean and Efficient HTML5H5 Code: Writing Clean and Efficient HTML5Apr 20, 2025 am 12:06 AM

How to write clean and efficient HTML5 code? The answer is to avoid common mistakes by semanticizing tags, structured code, performance optimization and avoiding common mistakes. 1. Use semantic tags such as, etc. to improve code readability and SEO effect. 2. Keep the code structured and readable, using appropriate indentation and comments. 3. Optimize performance by reducing unnecessary tags, using CDN and compressing code. 4. Avoid common mistakes, such as the tag not closed, and ensure the validity of the code.

H5: How It Enhances User Experience on the WebH5: How It Enhances User Experience on the WebApr 19, 2025 am 12:08 AM

H5 improves web user experience with multimedia support, offline storage and performance optimization. 1) Multimedia support: H5 and elements simplify development and improve user experience. 2) Offline storage: WebStorage and IndexedDB allow offline use to improve the experience. 3) Performance optimization: WebWorkers and elements optimize performance to reduce bandwidth consumption.

Deconstructing H5 Code: Tags, Elements, and AttributesDeconstructing H5 Code: Tags, Elements, and AttributesApr 18, 2025 am 12:06 AM

HTML5 code consists of tags, elements and attributes: 1. The tag defines the content type and is surrounded by angle brackets, such as. 2. Elements are composed of start tags, contents and end tags, such as contents. 3. Attributes define key-value pairs in the start tag, enhance functions, such as. These are the basic units for building web structure.

Understanding H5 Code: The Fundamentals of HTML5Understanding H5 Code: The Fundamentals of HTML5Apr 17, 2025 am 12:08 AM

HTML5 is a key technology for building modern web pages, providing many new elements and features. 1. HTML5 introduces semantic elements such as, , etc., which enhances web page structure and SEO. 2. Support multimedia elements and embed media without plug-ins. 3. Forms enhance new input types and verification properties, simplifying the verification process. 4. Offer offline and local storage functions to improve web page performance and user experience.

H5 Code: Best Practices for Web DevelopersH5 Code: Best Practices for Web DevelopersApr 16, 2025 am 12:14 AM

Best practices for H5 code include: 1. Use correct DOCTYPE declarations and character encoding; 2. Use semantic tags; 3. Reduce HTTP requests; 4. Use asynchronous loading; 5. Optimize images. These practices can improve the efficiency, maintainability and user experience of web pages.

H5: The Evolution of Web Standards and TechnologiesH5: The Evolution of Web Standards and TechnologiesApr 15, 2025 am 12:12 AM

Web standards and technologies have evolved from HTML4, CSS2 and simple JavaScript to date and have undergone significant developments. 1) HTML5 introduces APIs such as Canvas and WebStorage, which enhances the complexity and interactivity of web applications. 2) CSS3 adds animation and transition functions to make the page more effective. 3) JavaScript improves development efficiency and code readability through modern syntax of Node.js and ES6, such as arrow functions and classes. These changes have promoted the development of performance optimization and best practices of web applications.

See all articles

Hot AI Tools

Undresser.AI Undress

Undresser.AI Undress

AI-powered app for creating realistic nude photos

AI Clothes Remover

AI Clothes Remover

Online AI tool for removing clothes from photos.

Undress AI Tool

Undress AI Tool

Undress images for free

Clothoff.io

Clothoff.io

AI clothes remover

Video Face Swap

Video Face Swap

Swap faces in any video effortlessly with our completely free AI face swap tool!

Hot Tools

SecLists

SecLists

SecLists is the ultimate security tester's companion. It is a collection of various types of lists that are frequently used during security assessments, all in one place. SecLists helps make security testing more efficient and productive by conveniently providing all the lists a security tester might need. List types include usernames, passwords, URLs, fuzzing payloads, sensitive data patterns, web shells, and more. The tester can simply pull this repository onto a new test machine and he will have access to every type of list he needs.

DVWA

DVWA

Damn Vulnerable Web App (DVWA) is a PHP/MySQL web application that is very vulnerable. Its main goals are to be an aid for security professionals to test their skills and tools in a legal environment, to help web developers better understand the process of securing web applications, and to help teachers/students teach/learn in a classroom environment Web application security. The goal of DVWA is to practice some of the most common web vulnerabilities through a simple and straightforward interface, with varying degrees of difficulty. Please note that this software

SAP NetWeaver Server Adapter for Eclipse

SAP NetWeaver Server Adapter for Eclipse

Integrate Eclipse with SAP NetWeaver application server.

MinGW - Minimalist GNU for Windows

MinGW - Minimalist GNU for Windows

This project is in the process of being migrated to osdn.net/projects/mingw, you can continue to follow us there. MinGW: A native Windows port of the GNU Compiler Collection (GCC), freely distributable import libraries and header files for building native Windows applications; includes extensions to the MSVC runtime to support C99 functionality. All MinGW software can run on 64-bit Windows platforms.

Safe Exam Browser

Safe Exam Browser

Safe Exam Browser is a secure browser environment for taking online exams securely. This software turns any computer into a secure workstation. It controls access to any utility and prevents students from using unauthorized resources.