> 웹 프론트엔드 > H5 튜토리얼 > HTML5 Canvas를 사용하여 자위 게임 구현

HTML5 Canvas를 사용하여 자위 게임 구현

不言
풀어 주다: 2018-06-22 15:33:37
원래의
3679명이 탐색했습니다.

이 글에서는 주로 HTML5 Canvas를 사용하여 간단한 자위 게임을 만드는 방법을 소개합니다. 저자는 관련 Javascript 코드도 제공합니다. 필요한 친구는 이를 참고할 수 있습니다.

전에 Dang Knight의 DEMO에서 자위 게임을 본 적이 있습니다. , 그리고 그의 사진과 오디오를 아래로 내렸습니다. . . . 그냥 재미로 다시 썼습니다. 단지 오락을 위해서입니다. . . . . . 저는 프레임워크를 사용하지 않고 모든 js를 직접 작성합니다. . . . . . 그래서 이것은 캔버스를 처음 접하는 사람들에게 도움이 될 수 있습니다. 작가는 오랫동안 캔버스를 연주하지 않았으며 실력이 좋지 않습니다.

더 이상 고민하지 말고 먼저 DEMO: 비행기 게임부터 시작하겠습니다. 원래 포스터는 이 내용을 순전히 오락용으로 썼으며 진지한 게임에 쓸 의도는 없었습니다.

주제를 살펴보겠습니다. 자위 게임 파일에는 index.html 항목 파일, allSprite.js 스프라이트 로직 처리 파일, loading.js 로딩 처리 파일 및 data.js(일부 초기화된 데이터)가 포함되어 있습니다.

우선 일반 게임은 기본적으로 로딩이 필요합니다. 로딩 페이지는 스프라이트 시트 이미지, 오디오 등의 데이터를 미리 로드하는 데 사용됩니다. 이 게임은 작은 게임이기 때문에 일부 오디오와 이미지만 로드하면 됩니다. 내부의 로딩 코드는 주로 다음과 같습니다. 다른 것들은 로딩 애니메이션을 만들기 위한 것이므로 관심이 있으시면 게시하지 않겠습니다.

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);   
        }   
    }   
}
로그인 후 복사
.

먼저 data.js에 넣었습니다. 배열은 파일에 대한 링크를 저장하는 데 사용되며, 그런 다음 해당 링크가 사진인지 오디오인지 확인합니다. 사진인 경우 preLoadImg를 사용하여 사진을 미리 로드하는 코드가 매우 복잡합니다. 간단합니다. 새 그림 개체를 만든 다음 로드한 후 다시 호출하면 됩니다. 오디오는 HTML5 오디오 DOM 개체를 생성하고 이에 대한 링크를 할당하여 로드됩니다. 오디오에는 "canplaythrough" 이벤트가 있습니다. 브라우저가 버퍼링을 위해 중지하지 않고 지정된 오디오/비디오를 계속 재생할 수 있을 것으로 예상하면 canplaythrough 이벤트가 발생합니다. 이는 canplaythrough가 호출되면 오디오가 거의 로드되었으며 다음 오디오를 로드할 수 있음을 의미합니다. 이와 같이 모든 것이 로드된 후 콜백이 이루어지고 게임이 시작됩니다.

게임을 시작하려면 많은 개체가 필요하므로 이를 하나의 스프라이트 개체로 통합했습니다. 서로 다른 개체 사이의 각 프레임의 움직임은 동작을 사용하여 별도로 작성할 수 있습니다.

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);   
            }   
        }   
    }   
}
로그인 후 복사

elf 클래스를 작성한 후 각 페인터와 동작을 작성하여 다양한 객체를 생성할 수 있습니다. 다음 단계는 페인터 작성입니다. 페인터는 일반 페인터와 스프라이트 시트 페인터 두 가지로 나누어집니다. 폭발 애니메이션과 비행기 사격 애니메이션은 그림 하나로는 할 수 없기 때문에 사용해야 할 때입니다. 스프라이트 시트의 경우:
2015511181456172.png (168×24)

2015511181533636.png (896×64)

이를 그리려면 스프라이트 시트 서랍을 사용자 정의해야 합니다. 다음은 게임의 복잡성에 따라 가장 간단한 스프라이트 시트 작성 방법입니다. , 적절할 때까지 수정할 수 있지만 원리는 비슷하며 약간만 수정하면 됩니다.

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);   
            }   
        }
로그인 후 복사

일반 화가는 훨씬 더 간단합니다. 화가를 쓰고 그리고 싶은 모든 것을 작성하면 됩니다.

스프라이트 클래스와 스프라이트 시트 페인터를 사용하면 별, 비행기, 총알 및 폭발 객체를 작성할 수 있습니다. 다음은 전체 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);
로그인 후 복사

이 그리기 방법 등은 모두 비교적 간단합니다.

주로 항공기의 움직임과 물체의 개수 조절에 대해 이야기합니다. 항공기는 어떻게 움직이는 걸까요? 키보드를 통해 움직임을 제어함으로써 많은 사람들이 keydown 메소드를 누를 때 keyCode를 판단하여 항공기가 계속 움직이도록 생각할 수 있다는 것은 의심의 여지가 없습니다. 그러나 문제가 있습니다. keydown 이벤트는 여러 키 누름을 지원하지 않습니다. 즉, X 키를 누르면 keyCode가 88입니다. 동시에 방향 키를 누르면 keyCode가 즉시 됩니다. 37, 즉, 단순히 키를 누른 상태로 항공기의 움직임을 제어하려는 경우 항공기는 특정 방향으로만 이동하거나 사격만 할 수 있는 한 가지 작업만 수행할 수 있습니다.

따라서 keydown과 keyup을 통해 항공기의 움직임을 구현해야 합니다. 원리는 이해하기 쉽습니다. 왼쪽 방향 키를 누르면 항공기에 왼쪽 상태를 부여합니다. Aircraft가 true이면 애니메이션 루프에서 항공기의 상태를 확인합니다. toLeft가 true이면 항공기의 x 값이 계속 감소하고 손가락을 떼면 항공기가 계속 왼쪽으로 이동합니다. , keyup 이벤트가 트리거되고 우리는 keyup 이벤트에서 항공기가 왼쪽 상태에서 해제됩니다. 비행기가 왼쪽으로 움직이지 않았습니다. 다른 상태에도 동일한 원칙이 적용됩니다. 이렇게 작성하면 항공기가 수명 동안 여러 상태를 갖도록 만들 수 있습니다. 촬영과 달리기를 동시에 할 수 있습니다.

구현된 코드는 다음과 같습니다.

//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);   
            }
로그인 후 복사

그렇게 간단합니다.

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

  我的做法就是,在游戏初始化的时候,直接生成一定数量的对象,存放在数组里面。当我们需要一个对象的时候,就从里面取,当用完后,再放回数组里面。数组里的所有对象都有一个属性,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实现手机摇一摇的换衣特效

위 내용은 HTML5 Canvas를 사용하여 자위 게임 구현의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

관련 라벨:
원천:php.cn
본 웹사이트의 성명
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.
인기 튜토리얼
더>
최신 다운로드
더>
웹 효과
웹사이트 소스 코드
웹사이트 자료
프론트엔드 템플릿