0

I'm trying to port my working java Snake game to JavaScript so people can play it on my website.

DEMO TO GAME HERE... Press arrow keys and try to run over the sprites.

For this Snake, I wanted to get the hang of cameras... so I implemented a camera that follows the snake (snake is in the middle). When the camera reaches the edge of the "World", the snake is allowed to keep going until it reaches the world edge.

Normally, I would simply append the new segment to the end of the snake by getting the last element's x,yin the array, then set the new segment to that once that last segment has moved. To move all the segments as a tail, I would store the pre-moved segment x,y, then set all the segments to the one before it.

Something like:

function getPrevCoords()  {
for (i = 1; i < players.length; i++) {
    prevX[i] = players[i-1].x;
    prevY[i] = players[i-1].y;
}   
}

function moveTail() {
//just need to move head, and set rest of player containers to the last position of head..
for (j = 1; j < players.length; j++) {
    players[j].x = prevX[j];
    players[j].y = prevY[j];
}
}

My question: The camera and putting all the objects in relation to the camera coordinates versus the world coordinates is throwing me off.

To make the camera move to the edge of the world, and then the player continue moving, I use the following logic:

    if (direction == "right") {
        if (camX < (world.w - camW) && (players[0].x == camW/2)) {
            camX+=velocity;
        }
        else {
            if (players[0].x < (camW-15)) {
                players[0].x += velocity;   
                moveTail();
            }
            else {
                console.log("HIT RIGHT WALL. GAME OVER.");
                reset();
            }
        }   
    }

The problem with this is, when you add a new segment, you set its x,y to the segment before it after they've moved. As you can see above, when I move the camera, I only want the cam coordinates to move and the player's x,y to be set to camera middle. I only change the player's x,y when the camera reaches the edge of the world and the player needs to keep moving. So, you'll notice that the extra body segments only fall staggered when the player x,y is updated... when the cam is moving, the player's x,y doesn't change so all the body segments' x,y equal each other.

Any ideas on how to solve that?


UPDATED CODE:

I've updated to include centerViewTo... as you can see from the picture, it just places everything in the top left.

function createPlayers() {
    playerBMP = new createjs.Bitmap("Images/cat_sit.png");      
    playerContainer = new createjs.Container(); 

    playerContainer.addChild(playerBMP);
    centerViewTo(stage.canvas, stage, playerContainer, {x:0, y:0, width:bg.image.width, height:bg.image.height});

    stage.addChild(playerContainer);    
}

function createNPCs() {
    npcBMP = new createjs.Bitmap("Images/myBmp.png");
    npcBMP2 = new createjs.Bitmap("Images/myBmp.png");

    npcContainer = new createjs.Container();
    npcContainer2 = new createjs.Container();   

    npcContainer.addChild(npcBMP);
    npcContainer2.addChild(npcBMP2);

    centerViewTo(stage.canvas, stage, npcContainer, {x:0, y:0, width:bg.image.width, height:bg.image.height});
    centerViewTo(stage.canvas, stage, npcContainer2, {x:0, y:0, width:bg.image.width, height:bg.image.height});

    stage.addChild(npcContainer);
    stage.addChild(npcContainer2);
}

enter image description here

user3871
  • 12,432
  • 33
  • 128
  • 268

1 Answers1

1

I feel a little sorry for you, that you have invested so much effort in trying to make a "camera" (but on the positive side you sure learned a lot I guess)

So, basically: You don't need any of the cam-variables (camX, camY, ect...)

Here is a small method, that I'm allways using to center objects in the stage: (explanation how it works can be found below)

function centerViewTo(viewPort,container,object,bounds) {
    var containerPosition = object.localToLocal(0,0,container),
        pw = viewPort.width || 0,
        ph = viewPort.height || 0;

    if ( bounds ) {
        var minX = bounds.x + pw / 2,
            maxX = bounds.x + bounds.width - pw / 2,
            minY = bounds.y + ph / 2,
            maxY = bounds.y + bounds.height - ph / 2;
        containerPosition.x = Math.max(minX, Math.min(containerPosition.x, maxX));
        containerPosition.y = Math.max(minY, Math.min(containerPosition.y, maxY));
    }

    container.regX = containerPosition.x;
    container.regY = containerPosition.y;
    container.x = pw / 2;
    container.y = ph / 2;
}

What the method does, it puts the position container(which is most likely the stage) to the position of the object in relation to the view-port(which is most likely the canvas) - so the viewPort is usually the canvas and the container is usually the stage - very rarely I've had other cases.

In your case you could use it like follows: centerViewTo(stage.canvas,stage,playerBMP,{x:0,y:0,width:bg.image.width,height:bg.image.height});

But you will have to make some changes to your code: All containers and object's positions should be 0-based, so for example your bg should be at (0|0), your playerContainer should be positioned at (0|0).

Another positive aspect of this method is, that you can at any time rotate the stage, and it will automatically rotate around the current centered object, same with scaling.

I hope this does help you more than it might confuse you ;)

*Edit: I added a graphic that hopefully helps to visualize what the method does. The method does NOT alter any positions or position any objects for you, exept the position of the container (in the simplest case the stage) that holds the object.

enter image description here

olsn
  • 16,644
  • 6
  • 59
  • 65
  • @olson thanks for this. But how does this method interact with other sprites on the map that are now followed by the camera, but exist with static world coordinates? – user3871 Aug 13 '13 at 14:16
  • I'm not sure if I got your question right - you are probably talking about HUD-/Interface-buttons? If you use interface-buttons, then you simply don't use the `stage` and `container` but create another container where you place all the world's sprites (the grass, the cat ect...) – olsn Aug 13 '13 at 15:02
  • Olsn, couple more things before I accept: I've updated the code above using your method... I'm obviously not understanding/using it right. The objects are just being added to the top left of the canvas. Second, to clarify my comment above, I need the player (cat) to be centered and the camera follows it... and sprites are placed in static positions on the stage... so when I move the player/camera right, the sprites should appearing to move left (but really, they're just placed at a camera offset). Can you explain your method line by line with comments? Thanks! – user3871 Aug 13 '13 at 15:43
  • I've added an image, that hopefully helps you to better understand what the method does – olsn Aug 13 '13 at 18:55
  • Still not sure why it's better to move the stage around rather than move the cam around a fixed stage? Can you explain that? And I call `centerViewTo(stage.canvas, stage, npcContainer, {x:0, y:0, width:bg.image.width, height:bg.image.height});` before every stage update? I do this for all objects? – user3871 Aug 13 '13 at 19:03
  • No, just for the one you want to view in the center of the screen. And you don't HAVE to use the stage to move around, you can also create something like a `worldContainer` but the point is: you just move the container, by moving the container all objects inside that container will automatically move as well, that's the reason why you have Containers and children, so you don't have to move every objects single-handed or create additional helpers like a camera. – olsn Aug 13 '13 at 19:14
  • let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/35385/discussion-between-olsn-and-growler) – olsn Aug 13 '13 at 19:17