开发者

Not Looping? HTML5 and JavaScript

I have no idea why this code does not loop as it should. My mind is blown and hopefully someone can give me a hand. This is my first attempt into the HTML5 and JavaScript world and my first StackOverflow post. My background is in java so that should explain the quirks in my code. By the way, if you run the code the canvas and balls will show up, just not move.

First off, here is the HTML5

    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
    <html xmlns="http://www.w3.org/1999/xhtml">
    <head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    <title>ChainReaction5</title>
    <script type=开发者_C百科"text/javascript" src="chain_reaction.js"></script>
    </head>

    <body>
    <body onLoad="init();">
    <canvas id="myCanvas" width="500" height="400">
    Your browser dosen't support the HTML5 canvas.</canvas><br />
    </body>
    </html>

Secondly here is the js

    //gobal vars
    var context;
    var box;
    var balls;

    var defaultBallX=240;
    var defaultBallY=190;
    var defaultBallRad=6;
    var defaultBallV=5;

    var defaultNumBalls=10;

    //box class
    function Box() {
        var boxx=20;
        var boxy=20;
        var boxWidth=460;
        var boxHeight=360;

        this.getX = function() {return boxx;}

        this.getY = function() {return boxy;}

        this.getWidth = function() {return boxWidth;}

        this.getHeight = function() {return boxHeight;}

        this.getBalls = function() {return ball;}

        this.paintMe = function() {
            context.fillStyle = "black";
            context.strokeRect(boxx, boxy, boxWidth, boxHeight);
        }
    }

    /*  Box Class
     *  this class is sloppy but more memory efficent
     */
    function Ball(x, y, radius, vx, vy, color) {
        this.x=x;
        this.y=y;
        this.radius=radius;
        this.vx=vx;
        this.vy=vy;
        this.color=color;   

        this.paintMe = function() {
            context.beginPath();
            context.arc(this.x, this.y, radius, 0, 2*Math.PI, true);
            context.fillStyle = this.color; 
            context.fill();
        }
    }

    Array.prototype.appendBalls = new function(array) {}
    Array.prototype.clearBalls = new function() {}

    Array.prototype.appendBalls = function(array) {
            for (var i = 0; i < array.length; i++) {
                balls.push(array[i]);
            }
        }

    Array.prototype.clearBalls = function() {
            balls = new Array();
        }

    // begin program
    function init() {
        context = document.getElementById("myCanvas").getContext("2d"); 
        box = new Box();
        balls = new Array();
        balls.appendBalls(createBalls(box, defaultNumBalls));
        setInterval(moveBall(balls, box), 100);
    }

    function createBalls(box, numBalls) {
        var locBalls = new Array(numBalls);
        for (var i = 0; i < numBalls; i++) {
            var randx = randp(50, 400)
            var randy = randp(50, 300);
            var randr = Math.random()*defaultBallRad+1;
            var randvx = randv();
            var randvy = randv();
            var randc = randColor();
            locBalls[i] = new Ball(randx, randy, randr, randvx, randvy, randc);
        }
        return locBalls;    

        function randv() {
            var neg = 1;
            if (Math.random()>.5) neg = -neg;
            return Math.random()*defaultBallV*neg;  
        }

        function randp(low, hight) {
            if (low < 0) low = 0;
            var p = -1;
            while (p > hight || p < low) {
                p = Math.random()*hight;
            }
            return p;
        }

        function randColor() {
            var letters = '0123456789ABCDEF'.split('');
            var color = '#';
            for (var i = 0; i < 6; i++ ) {
                color += letters[Math.round(Math.random() * 15)];
            }
            return color;
        }
    }
    function moveBall(balls, box) {
        clear(this.box);
        this.box.paintMe();

        for (var i = 0; i < this.balls.length; i++) {
                moveAndCheck(this.balls[i], this.box);
            }
    }

    function moveAndCheck(b, box) {

        if ((b.x+b.vx+b.radius-1)>(this.box.boxWidth+this.box.boxx) || b.x+b.vx-b.radius<this.box.boxx+1) {
            b.vx = -b.vx;
        }
        if ((b.y+b.vy+b.radius-1)>(this.box.boxHeight+this.box.boxy) || b.y+b.vy-b.radius<this.box.boxy+1) {
            b.vy = -b.vy;
        }

        b.x += b.vx;
        b.y += b.vy;

        b.paintMe();

    }

    function clear(box) {
        context.clearRect(this.box.boxx, this.box.boxy, 
        this.box.boxWidth, this.box.boxHeight);
    }


The first time I tried running it I got the following in the Firebug console:

useless setInterval call (missing quotes around argument?) [Break On This Error] setInterval(moveBall(balls, box), 100);

Putting quotes around 'moveBalls(balls, box)' animates things.

Incidentally, you can use prototype inhertiance to make your function a bit more efficient, the methods in Box are given to each instance. To have them inherit the methods, put them on the constructor's prototype:

Box.prototype = {

    getX: function() {return this.boxx;},

    getY: function() {return this.boxy;},

    getWidth: function() {return this.boxWidth;},

    getHeight: function() {return this.boxHeight;},

    getBalls: function() {return this.ball;},

    paintMe: function() {
        context.fillStyle = "black";
        context.strokeRect(this.boxx, this.boxy, this.boxWidth, this.boxHeight);
    }
};

Note that in javascript, a function's this keyword is set by the call, it is not set by how you declare the function (though you can use ES5 bind, but that is not widely supported yet).

Some other hints:

In the Box constructor you are making local variables but you really want to assign them to the new Box instance, so use this instead of var:

function Box() {
    this.boxx=20;
    this.boxy=20;
    this.boxWidth=460;
    this.boxHeight=360;
}

In the clearBox function, you are using this when it is not set in the call, so it references window. Just get rid of it, you pass box to the function so reference it directly:

function clear(box) {
    context.clearRect(box.boxx, box.boxy, 
    box.boxWidth, box.boxHeight);
}

Same applies to the moveBall and moveAndCheck functions, just get rid of this (I think you should do some research on how this is handled in javascript, there are many articles on it, it's quite different to Java). Now the balls will bounce around nicely inside the box.


I want to thank the people who contributed to my question and it has been helpful in resolving the issue and the answer I selected was current in a way, but it fixed the problem for a different reason.

Incorrect:

Putting quotes around 'moveBalls(balls, box)' animates things.

What actually fixes the problem is removing the arguments and parentheses from the call to the moveball function. I discovered this when rewriting other parts of my code as the poster suggested.

So for future notice to other people with a similar problem if you need to remove the arguments and use a wrapper function or global variables.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜