ippa / jaws

Jaws - HTML5 canvas javascript 2D Game Framework
https://jawsjs.ippa.se
GNU Lesser General Public License v3.0
363 stars 75 forks source link

sprite.rect() X and Y NaN #47

Closed levincem closed 11 years ago

levincem commented 12 years ago

Hi,

I'm trying to make a game using jawsJs, which is really helpful. I found a weird comportement, trying to detect collision between a sprite and a tile block. when i use a statement as :

if(tile_map.atRect(sprite.rect()).length > 0) { 
...;
}

the test was always false. I made a console.log(sprite.rect()); and sees that X and Y properties of the rect were "NaN". then a console.log(sprite); shows that the "offset"properties are false either (NaN also)

When i initialise my sprite, i declare the offsets

            var sprite = new jaws.Sprite({anchor: "center center", x: x, y: y});
                        (......other sprite properties...)
            sprite.setImage( sprite.anim_default.next() );
            sprite.left_offset = 0;
            sprite.right_offset = 0;
            sprite.top_offset = 0;
            sprite.bottom_offset = 0;

It seems sprite.move() change the offsets to NaN

i have to re-declare the 4 offsets as shown before, to have the collision detected correctly.

Anyway, i first started a Html5 game from scratch.. it's much easier with JawsJs.. thanks && keep up !

ippa commented 12 years ago

can you put the full problem-code online? that would make it easy for me to take a look and debug with chrome.

levincem commented 12 years ago

ok, but it's just an experiment.. code is not very clean !

i create 50 sprites (same anim) and they must find their way through a simple path if you comment lines 137-140, the sprites go through, they never meet an obstacle, the test just after, "tile_map.atRect(sprite.rect()).length > 0" is not correct.

you''ll need 2 assets, including your demo sprite, droid_11_15 and a "grass.png" which is just a 32_32 texture image.

thanks.

<!doctype html>
<html lang="fr">
<head>
    <meta charset="utf-8" />
    <title>Html5 Experience !</title>

<script language="javascript" type="application/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js"></script>
<script language="javascript" type="application/javascript" src="http://ajax.googleapis.com/ajax/libs/jqueryui/1.8.6/jquery-ui.min.js"></script>
<script src="jaws.js"></script>
</head>
<body>
<div style="width:790px;margin:auto;">
  <canvas id="gameCanvas" width="790" height="640">
    Votre navigateur n'est pas compatible !
  </canvas>

  <div id="live_info"></div>
</div>
<script type="text/javascript">
var map = [];
var mapData = [];
map.push(".......D............");
map.push(".......#............");
map.push(".......######.......");
map.push("............#.......");
map.push("..###########.......");
map.push("..#.................");
map.push("..#.................");
map.push("..######..#######...");
map.push(".......#..#.....#...");
map.push(".......#..#.....#...");
map.push(".......####.....##..");
map.push(".................#..");
map.push(".................#..");
map.push(".......###########..");
map.push(".......#............");
map.push(".......#............");
map.push(".......#............");
map.push(".......#............");
map.push(".......#............");
map.push(".......A............");
mapData['test'] = map.join("\n");

var mapSize = 20; // nb de cases largeur et hauteur
var posInitiale = [];
var posFinale = [];
var compteur = 0;
var live_info = document.getElementById("live_info");
var anim;
var tile_map;

(function() {

  function GameState ()
  {
    var sprites = [];
    this.setup = function()
    {
        anim = new jaws.Animation({sprite_sheet: "assets/droid_11x15.png", frame_size: [11,15], frame_duration: 100});
        gameMap = new Array(mapSize);
        for (var i = 0; i < mapSize; i++) {
            gameMap[i] = new Array(mapSize);
        }
        parseMap(mapData['test']);
        jaws.context.mozImageSmoothingEnabled = false;

        blocks = new jaws.SpriteList();
        for (var x = 0; x < mapSize; x++) {
            for (var y = 0; y < mapSize; y++) {
                p = [x, y];
                if (gameMap[x][y] === undefined) {
                    blocks.push( new jaws.Sprite({image: "assets/grass.png", x: (p[0]) * 32, y: (p[1]) * 32}) );
                }
            }
        }
        tile_map = new jaws.TileMap({size: [20, 20], cell_size: [32,32]});
        tile_map.push(blocks);
    }

    this.update = function()
    {
        compteur++;

        if(compteur % 12 == 0 && sprites.length < 50)
        {
            var x = parseInt(posInitiale[0]);
            var y = parseInt(posInitiale[1]);
            var sprite = new jaws.Sprite({anchor: "center center", x: x, y: y});
            sprite.anim_default = anim.slice(0,5);
            sprite.anim_up = anim.slice(6,8);
            sprite.anim_down = anim.slice(8,10);
            sprite.anim_left = anim.slice(10,12);
            sprite.anim_right = anim.slice(12,14);
            sprite.setImage( sprite.anim_default.next() );
            sprite.scale = 1.7;
            sprite.resizeTo(25,25);
            sprite.speed = 1.5*(Math.random()+0.5);
            sprite.left_offset = 0;
            sprite.right_offset = 0;
            sprite.top_offset = 0;
            sprite.bottom_offset = 0;
            sprite.direction = 1;
            sprites.push(sprite);
        }

        //console.log(sprites);
        sprites.forEach(function(sprite, index) {
            //console.log(sprite);
            sprite.collision = false;
            sprite.setImage( anim.next() );

            var xord = [Math.floor((sprite.x) / 32), Math.floor((sprite.y) / 32)];
            //console.log(xord);

            if (sprite.direction === 0) {
                sprite.setImage( sprite.anim_right.next() );
                sprite.vx = sprite.speed;
                sprite.vy = 0;
            }
            if (sprite.direction === 1) {
                sprite.setImage( sprite.anim_down.next() );
                sprite.vx = 0;
                sprite.vy = sprite.speed;
            }
            if (sprite.direction === 2) {
                sprite.setImage( sprite.anim_left.next() );
                sprite.vx = -sprite.speed;
                sprite.vy = 0;
            }   
            if (sprite.direction === 3) {
                sprite.setImage( sprite.anim_up.next() );
                sprite.vx = 0;
                sprite.vy = -sprite.speed;
            }
            //console.log(sprite.rect());
            sprite.move(sprite.vx, sprite.vy);
            sprite.left_offset = 0;
            sprite.right_offset = 0;
            sprite.top_offset = 0;
            sprite.bottom_offset = 0;

            if(tile_map.atRect(sprite.rect()).length > 0) { 

                //console.log(sprite);
                //console.log(sprite.rect());
                if (sprite.direction === 0) {
                    sprite.vx = -sprite.speed;
                    sprite.vy = 0;
                }
                else if (sprite.direction === 1) {
                    sprite.vx = 0;
                    sprite.vy = -sprite.speed;
                }
                else if (sprite.direction === 2) {
                    sprite.vx = sprite.speed;
                    sprite.vy = 0;
                }
                else if (sprite.direction === 3) {
                    sprite.vx = 0;
                    sprite.vy = sprite.speed;
                }
                sprite.move(sprite.vx, sprite.vy);

                var possibleDirections = [];
                if (tile_map.cell([xord[0] + 1],[xord[1]]).length == 0) {
                    possibleDirections.push(0);
                }
                if (tile_map.cell([xord[0]],[xord[1] + 1]).length == 0) {
                    possibleDirections.push(1);
                }
                if (tile_map.cell([xord[0] - 1],[xord[1]]).length == 0) {
                    possibleDirections.push(2);
                }
                if (tile_map.cell([xord[0]],[xord[1] - 1]).length == 0) {
                    possibleDirections.push(3);
                }
                newPossibleDirections = arrayWithout(possibleDirections, ((sprite.direction + 2) % 4));
                sprite.direction = randomChoice(newPossibleDirections);
            }
        });
        live_info.innerHTML = jaws.game_loop.fps + " fps.";
    }

    this.draw = function()
    {
        jaws.context.clearRect(0, 0, jaws.width, jaws.height);
        blocks.draw();
        sprites.forEach(function(sprite, index) {
            sprite.draw();
        });
        var context = document.getElementById("gameCanvas").getContext("2d");
        context.fillStyle = "rgb(24,24,24)";
        context.fillRect(posInitiale[0], posInitiale[1], 32, 32);
        context.fillStyle = "rgb(190, 250 ,150)";
        context.fillRect(posFinale[0], posFinale[1], 32, 32);
    }
  }

  window.onload = function()
  {
    jaws.assets.add("assets/droid_11x15.png")
    jaws.assets.add("assets/grass.png")
    jaws.start(GameState);
  }
})();

function parseMap(lvlstring) {
    lines = lvlstring.split("\n");
    $.each(lines, function (y, line) {
        for (var x = 0; x < line.length; x++) {
            chr = line[x];
            if (chr == '#') {
                gameMap[x][y] = 'r';
            } else if (chr == 'D') {
                gameMap[x][y] = 'D';
                posInitiale = [];
                posInitiale.push(x * 32);
                posInitiale.push(y * 32);
            } else if (chr == 'A') {
                gameMap[x][y] = 'A';
                posFinale = [];
                posFinale.push(x * 32);
                posFinale.push(y * 32);
            } else if (chr == '.') {
                gameMap[x][y] = undefined;
            } else {
                console.log('Invalid chr ' + chr + ' at ' + x + 'x' + y + ' in line: ' + line);
            }
        }
    });
}
function getTime() {
    return (new Date()).getTime();
}
function randomChoice(arr) {
    return arr[Math.floor(Math.random() * arr.length)];
}
function arrayWithout(arr, value) {
    u = [];
    $.each(arr, function (i, o) {
        if (o != value) {
            u.push(o);
        }
    });
    return u;
}
</script>
</body>
</html>
nickcoad commented 11 years ago

I'm having this same problem - I use this code:

sprite = new jaws.Sprite({image: "assets/img/tile_wall.png", x: 0, y: 0})
console.log(sprite.rect());

And the console outputs the following:

Rect {
    bottom: NaN
    height: 32
    right: NaN
    width: 32
    x: NaN
    y: NaN
}

Edit: got this sussed - it occurs when you fail to add assets using jaws.assets.add() before trying to create sprites with them. I added the following and it works fine now:

jaws.assets.add(["assets/img/tile_wall.png"]);
McFunkypants commented 11 years ago

For anyone else having the problem, the problem may be with "THIS" and object self references.

Meaning, if you are storing a function pointer:

var aabb = player.rect;

and then call

console.log(aabb());

you will get a Rect{} with tons of NaNs.

But if you call

console.log(player.rect());

you will get what you expect. So don't prematurely optimize and think you can collapse the object dot syntax.

Whew - took my many hours of debugging to figure this out - what a noob mistake on my part.

ippa commented 11 years ago

I know this is an very old issue but here goes. Gnack probably hit the spike on the head, if you create new Sprite()'s without preloading the images.. Sprite() will try to load it runtime. That means rect() isn't inimitably available.. but rather when the image finally is loaded.

Therefore I've added a warning when using images that's not pre-loaded: https://github.com/ippa/jaws/commit/3fb6d248e1d33b3af823b48171fb8a9189d55dfe

I've also added test to spec to behavior of rect() when the image isn't loaded yet: https://github.com/ippa/jaws/commit/3eee0e846f117ea1df207103cd0886ee2b7b96f9

I was thinking of just throwing an exception and always require pre-loading of assets.. but this will be the first step.