HTML5 Canvas: Moving/panning world with arrow keys in EaselJS - javascript

After a year of studying and experimenting through trial-and-error, I feel that I am starting to understand JavaScript a bit more. So, now, I wanna try my hand at writing a simple 2D platform game (think Super Mario World or Sonic the Hedgehog). For this, I'll be employing the EaselJS library.
I am trying to figure out how I can move/pan the 'world' within a canvas by use of the left and right arrow keys. I know how I can run a function upon a keydown of the arrow key, but I'm not too sure how I should approach the moving/panning.
Should I adjust the position/coordinates of every single thing within the canvas when a key is pressed?
Or should I perhaps put everything in a container and move the position/coordinates of the container?
I'll appreciate anything that nudges me into the right direction. Tyvm :)
Updated with answer
The chosen answer below confirmed that I indeed had to put everything in a container so that I can set the position of that container. This is the code I drafted, and it works.
// Canvas
var stage = new createjs.Stage('game');
createjs.Ticker.addEventListener('tick', tick);
function tick(event) {
stage.update();
}
// Cave
var cave = new createjs.Bitmap('img/cave.png');
cave.x = cave.y = 0;
// World
// Pans World if the left or right arrow keys are pressed
var world = new createjs.Container();
world.x = 0;
world.y = 0;
world.addChild(cave);
stage.addChild(world);
$(window).keydown(function(e){
switch (e.which || e.keyCode){
case 39: // right arrow key
world.regX += 10;
break;
case 37: // left arrow key
world.regX -= 10;
break;
}
});
I tried updating world.x as well as world.regX. Somehow, world.regX seems to go smoother.

I think the best way is to put all display objects which will be scrolled into a scrollableObjectContainer (perhaps you have static elements like lifebar).
So when you move, just update scrollableObjectContainer.regX.
You can use tweenJS for a smoother scroll.

Just an idea... but take a look at the canvas translate function and use it at the beginning of each redraw to set the context from which to draw everything else.
http://www.html5canvastutorials.com/advanced/html5-canvas-transform-translate-tutorial/

Usually I would agree with EaselJS for most canvas related projects, however the type of game you want to build would be better suited for melonJS.
Check it out http://melonjs.org

Here is a sample of 2d top down scroll and rotation following a player.
https://jsfiddle.net/StaticDelvar/bt9ntuL5/
But it boils down to:
world.regX = player.x;
world.regY = player.y;
world.rotation = -player.rotation;
Then everything including the player goes into the World container and will be rotated as the player moves. GUI must be after world so it draws on top of it.
Stage
World
Objects
Player
Gui

Related

Javascript sprites moving between two points

I'm wanting to get some sprites moving between two points in my (very basic) javascript game. Each sprite is randomly placed in the level, so I want them to move back and forth between their base position. I have the code below
function Taniwha(pos) {
this.basePos = this.pos;
this.size = new Vector(0.6, 1);
this.move = basePos + moveDist(5,0));
}
Taniwha.prototype.type = "taniwha"
var moveSpeed = 4;
Taniwha.prototype.act = function(step) {
this.move = ???
and this is where I get stuck. I'm not sure how to tell it to go left, back to base pos, right then back to base pos again (I plan to loop this). Does anyone have any advice? (also using Eloquen Javascript's example game as an outline/guide for this, if how I'm doing things seems odd!)
For horizontal movement, change x coordinate of the position.
var pos = { x: 1, y: 2 };
pos.x++ ; // This will move right
pos.x-- ; // This will move left
Likewise for vertical movement. You also need to update the coordinates after change for the object which you are drawing.
In truth ,there are lots of library to develop a game.
Use those, control a sprite is very easy.
Like:
Pixijs
CreateJS
Both of them are opensource project, you can watch and learn the source.
And have lots of examples and document.

Cheat for hidden game "Atari Breakout" in Google Image Search

How would a cheat/auto moving paddle in this hidden html game look like?
There is a
<div id="breakout-ball"><span>●</span></div>
and a
<div id="breakout-paddle"></div>
when moving the mouse the paddle is moved horizontally. How can I connect the movement of the ball with the paddle?
This question will become "community wiki" as soon as possible.
function cheat() {
var ball = document.getElementById('breakout-ball');
var paddle = document.getElementById('breakout-paddle');
paddle.style.left = ball.style.left;
setTimeout(cheat, 20);
}
cheat();
// Add this via the FireBug console.
I modified your solution slightly to account for the scenario of the ball going off screen and breaking the hack and also the ball getting jammed into the corner.
function cheat() {
var ball = document.getElementById('breakout-ball');
var paddle = document.getElementById('breakout-paddle');
var buffer = Math.floor((Math.random()*100)+1);
var leftVal = parseInt(ball.style.left, 10);
if (ball.style.left) {
paddle.style.left = (leftVal - buffer) + 'px';
}
setTimeout(cheat, 100);
}
cheat();
To be honest though, if you are going down that road why not do this?
function cheat() {
var paddle = document.getElementById('breakout-paddle');
paddle.style.width = '100%';
}
cheat();
Anyway I'm going to continue to dig into the code and do some deeper manipulation
in chrome, search the game, ctrl+J, paste the following in, and press enter.
This is a simple goal:
//get the ball's X position from its CSS
function ballx(){
return parseFloat(document.querySelector("#breakout-ball").style.left.split("px")[0]);
}
function update(e){
//throws an exception when the game isn't up. Can be really annoying.
try{document.querySelector("#breakout-paddle").style.left = (ballx() - 75)+"px";}
catch(ex){}
}
var intervalTimer = setInterval(update, 125);//let it have a single weakness in case someone else tries it while I am around.
The lower the interval rate, the faster the paddle will move relative to the ball, but the slower the game goes. The maximum rate can be given with a simple requestAnimationFrame cycle, but that slows the browser down a lot(at least on my laptop).
I tried changing the paddle's size. It doesn't really work.
I'm sure it would be simpler with jQuery, but why make cheating easy when doing it hard core is already so easy?
I have come up with a new way to solve this problem. Whenever the screen size or window size changes, the paddle changes size based on the screen size. To combat this, I simply just added another section that splits the size of the paddle in half then uses that value to find the centre of the paddle. Very simple and very effective.
function autoMove() {
var ball = document.getElementById('breakout-ball')
var paddle = document.getElementById('breakout-paddle')
var leftVal = parseInt(ball.style.left, 10)
var paddleWidth = parseFloat(paddle.style.width, 10) / 2
paddle.style.left = (leftVal - paddleWidth) + 'px'
setTimeout(autoMove, 20)
}
autoMove();
Also, didn't like the function name. It looks way too suspicious so changed it. Hope this helps.

Unfreeze bodies in Box2Djs or prevent from exiting world

I am working on a server side physics experiment where the user controls an object through a socket. The problem I am running into results when the user moves the object outside the boundaries of the world.
I am using Box2Djs as installed through npm.
I create world 500x500 and then attach the following listener to it:
var boundaryListener = new b2d.b2BoundaryListener();
boundaryListener.Violation = function (body) {
//we will move this body to the opposite side
var position = body.GetWorldCenter();
//snap to opposite side
if (position.x < 0) {
position.x = worldAABB.upperBound.x + position.x;
}
if (position.y < 0) {
position.y = worldAABB.upperBound.y + position.y;
}
if (position.x > worldAABB.upperBound.x) {
position.x -= worldAABB.upperBound.x;
}
if (position.y > worldAABB.upperBound.y) {
position.y -= worldAABB.upperBound.y;
}
body.m_flags = body.m_flags & (~b2d.b2Body.e_frozenFlag); //does nothing :(
}
this.world.SetBoundaryListener(boundaryListener);
worldAABB is the b2AABB that the world uses as a boundary.
The problem is that I have noticed that when the boundary listener is fired, the flags are set to 22 which is allowSleep, frozen, and island flags. It would seem that when a b2Body passes outside the world boundary, it is frozen. That last line is an attempt to unfreeze the body by messing with the internal flags, but I have a distinct feeling that's the wrong way to do it.
How can I unfreeze the body? There are no functions that clear the frozen flags that I can see (the javascript is over 10,000 lines long so I honestly haven't read the whole thing) and placing some bodies as walls seems to have no effect (the user's object passes right through them).
My walls are created like so:
//create walls
var wallShape = new b2d.b2PolygonDef();
wallShape.SetAsBox(500, 10);
wallShape.density = 0.0;
wallShape.friction = 0.3;
var bodyDef = new b2d.b2BodyDef();
bodyDef.position.Set(250, 20);
var north = this.world.CreateBody(bodyDef);
north.CreateShape(wallShape);
bodyDef = new b2d.b2BodyDef();
bodyDef.position.Set(250, 499);
var south = this.world.CreateBody(bodyDef);
south.CreateShape(wallShape);
bodyDef = new b2d.b2BodyDef();
bodyDef.position.Set(499,250);
bodyDef.angle = Math.PI / 2;
var east = this.world.CreateBody(bodyDef);
east.CreateShape(wallShape);
bodyDef = new b2d.b2BodyDef();
bodyDef.position.Set(1, 250);
bodyDef.angle = Math.PI / 2;
var west = this.world.CreateBody(bodyDef);
west.CreateShape(wallShape);
Does anyone have any insights on how to fix this? There is very very little documentation I can find on using Box2D in javascript aside from the flash documentation that the website points to (which doesn't match half the time) and the C++ documentation which doesn't even talk about freezing.
It would probably be helpful to mention that the world has no gravity and all the objects have some linear and angular damping (its supposed to be a psuedo-in-space feel).
I had investigated Box2Djs source, and found next thing. Every time step Box2Djs checks if the body is inside the world boundaries. If body is out of range, then it "frozing", i.e. its excluding from collision detection. There this code (Body.js line 414):
Freeze: function(){
this.m_flags |= b2Body.e_frozenFlag;
this.m_linearVelocity.SetZero();
this.m_angularVelocity = 0.0;
for (var s = this.m_shapeList; s != null; s = s.m_next)
{
s.DestroyProxy();
}
}
Pay attention, this check performs every time step (b2Island.js 244). So, if you set e_frozenFlag at boundary listener, it will do nothing: flag will be set up at next time step. Thats more, after body had frozen, it losses its veolcity and its shapes looses theirs proxies in broad phase (as you can see from code above). Looks like proxies are not restroing automaticly, so, reseting flag is not enough.
I also not found somewhere in Box2Djs interface or logic for unfreezing bodies. Doing this manually is some kind of dirty trick, because you should acces BroadPhase, which is Box2Djs internal. Thats more, it dont help you, because on freezing body losses its velociy. But, as I see, you need continue body moving.
Solution is next. You should prevent body frozing at all in order to keep body in simulation after it moved out of world boundaries. It may be done by next trick. First, set world boundary with some large value. Then, set contact listener, and when body touches the walls, perform your boundary violation logic.
How to set contact listener in C++ you can see there: https://www.iforce2d.net/b2dtut/collision-callbacks Sory, I dont know java script and can't say, how to do this in Box2Djs.

First person simulation with three.js using keyboard arrows

For my source, visit http://jsfiddle.net/fYtwf/
Background
I have a simple 3d simulation using three.js where the camera is surrounded in 3 dimensions by cubes. These cubes are to help visualise where the camera is looking until the view controls are coded and tested. I want to create a simple 3D application, where the camera is controlled via up, down, left and right keys. Just like moving your head
Issues
In my current application, when facing forward, and starting to look up, we are successful. However when we turn left 90 degrees, and we press the up arrow... The wrong thing happens. the camera increments the x axis, but because we're facing another direction, modifying the x axis ALONE is WRONG...
Now I'm assuming this is because some trigonometry is required to calculate the correct values for the z axis. However, my trig isn't brilliant.
Current
To get a better understanding of what i mean, please visit my jsfiddle : http://jsfiddle.net/fYtwf/
UP key ONLY increments X
DOWN key ONLY decrements X
LEFT key ONLY increments Y
RIGHT key ONLY decrements Y
Q key ONLY increments Z
W key ONLY decrements Z
( Q and W were only coded to try and help me understand. )
From my current understanding, when I press the UP key, X must increment and the Z axis must be modified based on what the current Y axis is. However I don't know the algorithm :(
So X and Z must be modified in the KEYUP code ( I think, please correct me if I am wrong )
// setRotateX, getRotateX, setRotateY and getRotateY are extended
// camera functions I wrote so I could work with degrees. Solution
// IS NOT required to use them, they just helped me
switch( key )
{
case KEYUP:
if ( camera.getRotateX() < 90 ){ // restrict so they cannot look overhead
camera.setRotateX( camera.getRotateX() + VIEW_INCREMENT );
}
break;
case KEYDOWN:
if ( camera.getRotateX() > -90 ){ // restrict so they cannot look under feet
camera.setRotateX( camera.getRotateX() - VIEW_INCREMENT );
}
break;
case KEYLEFT:
camera.setRotateY( camera.getRotateY() + VIEW_INCREMENT );
break;
case KEYRIGHT:
camera.setRotateY( camera.getRotateY() - VIEW_INCREMENT );
break;
}
There are a number of solutions to this problem, but since you only want the camera to rotate up, down, left, and right, the answer in this case is easy.
You just need to set the camera Euler order to "YXZ" like so:
camera.rotation.order = "YXZ"; // three.js r.65
If you do that, everything becomes very intuitive.
Here is an updated fiddle: http://jsfiddle.net/fYtwf/3/ (this demo is using r.54, however)
Once you change camera.rotation.z from it's default value of zero, things will become very confusing. So don't do that. :-)
three.js r.65
While this does not directly fix your code, I thought I'd mention that Three.js provides two ready-made controllers to navigate in FPS mode. They both use mouse for looking and can move, but should be rather simple to adapt to keyboard look and remove movement if needed. They are:
FirstPersonControls
PointerLockControls
I'd recommend the latter as a starting point because it's rather simple and the former confusingly has the looking code twice, probably as an artifact from old features.

Question about the javascript-canvas object (save, transform, restore)

I've been playing around with canvas a lot lately. Now I am trying to build a little UI-library, here is a demo to a simple list (Note: Use your arrow keys, Chrome/Firefox only)
As you can tell, the performance is kinda bad - this is because I delete and redraw every item on every frame:
this.drawItems = function(){
this.clear();
if(this.current_scroll_pos != this.scroll_pos){
setTimeout(function(me) { me.anim(); }, 20, this);
}
for (var i in this.list_items){
var pos = this.current_scroll_pos + i*35;
if(pos > -35 && pos < this.height){
if(i == this.selected){
this.ctx.fillStyle = '#000';
this.ctx.fillText (this.list_items[i].title, 5, pos);
this.ctx.fillStyle = '#999';
} else {
this.ctx.fillText (this.list_items[i].title, 5, pos);
}
}
}
}
I know there must be better ways to do this, like via save() and transform() but I can't wrap my head around the whole idea - I can only save the whole canvas, transform it a bit and restore the whole canvas. The information and real-life examples on this specific topic are also pretty rare, maybe someone here can push me in the right direction.
One thing you could try to speed up drawing is:
Create another canvas element (c2)
Render your text to c2
Draw c2 in the initial canvas with the transform you want, simply using drawImage
drawImage takes a canvas as well as image elements.
Ok, I think I got it. HTML5 canvas uses a technique called "immediate mode" for drawing, this means that the screen is meant to be constantly redrawn. What sounds odd (and slow) first is actually a big advantage for stuff like GPU-acceleration, also it is a pretty common technique found in opengl or sdl. A bit more information here:
http://www.8bitrocket.com/2010/5/15/HTML-5-Canvas-Creating-Gaudy-Text-Animations-Just-Like-Flash-sort-of/
So the redrawing of every label in every frame is totally OK, I guess.

Categories