如何加速我的Javascript游戏引擎

时间:2012-01-08 20:54:09

标签: javascript html5 html

所以,最近,我一直在研究JS / HTML5游戏引擎。现在我称之为DimSumJs,因为像DimSum不是一顿饭,我的框架仍然运行得太慢而无法制作完整的游戏(它只能运行大约250个“对象”,尽管在减速之前,它在300个“物体”周围变得非常明显。它在iframe中使用div。

http://pandamochi.x10.bz

提供了一个示例游戏

只需使用Google Chrome查看资源,您就可以找到dimsum.js文件

//DimSumJS - Open Source Game Engine
//DimSumJS (C) Ruochen Tang
//Can be used commerically, but please give credit
//Constants
var RIGHTKEY = 37;
var UPKEY = 38;
var LEFTKEY = 39;
var DOWNKEY = 40;
var SPACEKEY = 32;
var MASTER_WIDTH = 480;
var MASTER_HEIGHT = 600;

var Game = window.frames[0].document.body;
Game.setAttribute("width",MASTER_WIDTH + "px");
Game.setAttribute("height",MASTER_HEIGHT + "px");
var gl = setInterval("gameLoop();",15);

//Global Vars
var keyDown = new Array();
for (var i = 0; i < 256; i++){
    keyDown[i] = false;
}
var gameState = 1;

//Settings
Game.style.backgroundColor = "#000";

//Key
processKeyEvent = function(event){
        // MSIE hack
        if (window.event)
        {
            event = window.event;
        }

        keyDown[event.keyCode] = true;      
};

releaseKey = function(event){
    // MSIE hack
        if (window.event)
        {
            event = window.event;
        }

    keyDown[event.keyCode] = false;
}
Game.onkeydown = processKeyEvent;
Game.onkeyup = releaseKey;


var GameObjects = new Array();

function GameObject(xx, yy, w, h, i, inc, gs, name, img){

    GameObjects.push(this);

    this.width = w;
    this.height = h;
    this.index = i;
    this.currIndex = 0;
    this.increment = inc;
    this.currInc = 0;
    this.x = xx;
    this.y = yy;
    this.depth = 0;
    this.objType = name;
    this.image = img;
    this.xScale = 1;
    this.yScale = 1;
    this.scaleString = "scale(" + this.xScale + "," + this.yScale + ")";
    this.speed = 0;
    this.direction = 0;
    this.gravity = 0;
    this.gravityDirection = 0;
    this.active = true;
    this.visible = true;
    this.bindToRoom = false;
    this.text = "";
    this.color = "#FFF";
    this.gameState = gs;

    this.div = document.createElement("div");
    this.div.className=this.objType;
    this.div.style.position="absolute";
    this.div.style.left= this.x + "px";
    this.div.style.top= this.y + "px";
    this.div.style.width= this.width + "px";    
    this.div.style.height= this.height + "px";  
    this.div.style.backgroundImage = "url(images/" + this.image + ")";

    this.div.style[getTransformProperty(this.div)] = this.scaleString;

    Game.appendChild(this.div);
    this.isDiv = true;
    this.classChanged = false;

    this.move = move;
    this.anim = anim;
    this.setScale = setScale;
    this.checkCollisionAt = checkCollisionAt;
    this.objectAt = objectAt;
    this.objectTypeAt = objectTypeAt;
    this.toggleActive = toggleActive;
    this.extend = extend;
    this.unextend = unextend;
    this.isType = isType;
    this.update = update;


    function move(xx,yy){
        this.x += xx;
        this.y += yy;
    }

    function anim(){
        this.currInc += 1;
        if (this.currInc >= this.increment){
            this.currInc -= this.increment;
            this.currIndex += 1;
            if (this.currIndex >= this.index){
                this.currIndex -= this.index;
            }

        }

    }
    function extend(type) {
        this.objType += " " + type;
        this.classChanged = true;
    }

    function unextend(type) {
        this.objType = this.objType.replace( /(?:^|\s)type(?!\S)/ , '' );
        this.classChanged = true;
    }

    function isType(type) {
            return ((' ' + this.objType + ' ').indexOf(' ' + type + ' ') > -1);
    }

    function setScale(xx,yy){
        this.xScale = xx;
        this.yScale = yy;
        this.scaleString = "scale(" + this.xScale + "," + this.yScale + ")";    
    }


    function checkCollisionAt(xx,yy,other){
        //Check For Collision
        xx += this.x;
        yy += this.y;

        if ((xx + this.width > other.x) && (xx < other.x + other.width) && (yy + this.height > other.y) && (yy < other.y + other.height)){
            return true;
        }
        else{
            return false;
        }
    }

    function objectAt(xx,yy,solid){
        //Loop All Objects
        for (var i = 0; i < GameObjects.length; i++){
            if (GameObjects[i] != this && this.isDiv){
                if (this.checkCollisionAt(xx,yy,GameObjects[i])){
                    console.log(i);
                    return true;
                }
            }           
        }
        return false;
    }

    function objectTypeAt(xx,yy,type){
        //Loop All Objects
        for (var i = 0; i < GameObjects.length; i++){
            if (GameObjects[i] != this && GameObjects[i].isType(type) && this.isDiv){
                if (this.checkCollisionAt(xx,yy,GameObjects[i])){
                    return true;
                }
            }
        }
        return false;
    }

    function toggleActive(a){
        this.visible = a;
        this.update();
        this.active = a;
    }

    function update(){      
        if ((this.active == false || this.gameState != gameState) && this.isDiv){
            this.isDiv = false;
            Game.removeChild(this.div);
            return;
        }
        else if(!this.isDiv){
            this.isDiv = true;
            Game.appendChild(this.div);
        }

        this.div.style.display = "inline";

        if (this.speed != 0){
            this.x += this.speed*Math.cos(this.direction*Math.PI/180);
            this.y += this.speed*Math.sin(this.direction*Math.PI/180);
        }

        if (this.bindToRoom == true){
            if (this.x < 0){
                this.x = 0;
            }

            if (this.y < 0){
                this.y = 0;
            }

            if (this.x > MASTER_WIDTH-this.width){
                this.x = MASTER_WIDTH-this.width;
            }

            if (this.y > MASTER_HEIGHT-this.height){
                this.y = MASTER_HEIGHT-this.height;
            }
        }

        if (!this.visible && this.isDiv){
            this.isDiv = false;
            Game.removeChild(this.div);
            return;
        }
        if (this.classChanged){
            this.div.className = this.objType;
        }

        this.div.style.zIndex = this.depth;

        this.div.style.color = this.color;
        this.div.innerHTML = this.text;

        this.div.style.left= this.x + "px";
        this.div.style.top= this.y + "px";

        this.div.style[getTransformProperty(this.div)] = this.scaleString;
        this.div.style.backgroundPosition = this.currIndex * this.width +"px 0";


    }
}
function getTransformProperty(element) {

    // Note that in some versions of IE9 it is critical that
    // msTransform appear in this list before MozTransform
    // By ZachAstronaut

    var properties = [
        'transform',
        'WebkitTransform',
        'msTransform',
        'MozTransform',
        'OTransform'
    ];
    var p;
    while (p = properties.shift()) {
        if (typeof element.style[p] != 'undefined') {
            return p;
        }
    }
    return false;
}

现在,只要对象不在当前gameState中,变为不活动状态或不可见,我将从游戏的iframe中删除div。我有检查以确保不在update()函数中运行任何不必要的脚本。无论如何我能提高速度吗?

1 个答案:

答案 0 :(得分:4)

您熟悉分析器吗? Google Chrome包括一个相当不错的人。当我运行您的程序并开始对其进行分析时,Chrome会报告您对isType的定义很昂贵。

function isType(type) {
    return this.objType && new RegExp("(^|\\s)" + type + "(\\s|$)").test(this.objType);
} 

果然,这很贵。动态构建RegExps可能代价高昂。

为了避免这种成本,如果可以,请从isType中取出正则表达式的定义。假设这组类型是固定的,您可以预先计算顶层所有类型的正则表达式,将它们存储在一个对象中,然后进行简单的查找以获得预先计算的正则表达式。如果你事先并不知道它们,你仍然可以将之前调用的regexp缓存到isType。

var priorTypeRegexps = {};
function isType(type) {
    var aRegexp;
    if (! priorTypeRegexps[type]) {
        priorTypeRegexps[type] = new RegExp("(^|\\s)" + type + "(\\s|$)");
    }
    aRegexp = priorTypeRegexps[type];        
    return this.objType && aRegexp.test(this.objType);
}