In a game demo I am putting up for school I need to move my character using the W-A-S-D keys and also the arrow keys. I put up a function and set up a switch case to listen for any of the key presses. Here is my code snippet:
//Handles the player's movement
var PlayerMovement = (function () {
//Constructor
function PlayerMovement() {
this.gameObject = null;
this.movementSpeed = 0;
this.rotationSpeed = 0;
}
PlayerMovement.prototype.awake = function () {
console.log("Awake");
};
PlayerMovement.prototype.update = function () {
//console.log(Tools.getFps());
}
PlayerMovement.prototype.onKeyPressed = function (key) {
switch(key)
{
case KeyType.W:
case KeyType.UpArrow:
console.log("Moving up");
this.gameObject.meshObject.position.z += (BABYLON.Vector3.Up() * this.movementSpeed * Tools.getDeltaTime());
break;
case KeyType.A:
case KeyType.LeftArrow:
//TODO: Do stuff
break;
case KeyType.S:
case KeyType.DownArrow:
//TODO: Do stuff
break;
case KeyType.D:
case KeyType.RightArrow:
//TODO: Do stuff
break;
}
}
return PlayerMovement;
})();
My issue is that my character jumps so far ahead that he vanishes from the screen. Can anyone help me figure out what is wrong with my calculation?
A few things -
BABYLON.Vector3.Up() is (0,1,0) . Multiplying this object with any number will return NaN. I guess the object doesn't jump away from the screen, it simply disappears.
Z is not up :-) position.y should be changed if you wish to jump up.
If you want to translate using vectors (using the BABYLON.Vector3.Up() Vector) use the mesh.translate(vector, distance) function. In your case (assuming this is the right value you want to set):
this.gameObject.meshObject.translate(BABYLON.Vector3.Up(), this.movementSpeed * Tools.getDeltaTime());
I assume you did that already, but if not - turn the physics engine on and set gravity for your scene. You can learn about it in the BJS Docs : http://doc.babylonjs.com/page.php?p=22091
A better way to implement a jump would be to apply acceleration in the right direction (up) and letting the physics engine do its magic. Check out "Applying impulse" here - http://blogs.msdn.com/b/eternalcoding/archive/2013/12/19/create-wonderful-interactive-games-for-the-web-using-webgl-and-a-physics-engine-babylon-js-amp-cannon-js.aspx
It's nearly impossible for us to help you without the rest of the code. Could you provide the entirety of your custom JS file? I'm thinking this is likely an issue with your camera angle, not so much the character movement. Also, is this a first person game or third person game?
Sorry, would have left this "answer" as a comment but I don't have 50 reputation points to do so. Trying to solicit more information to provide an actual answer.
Related
I have a snake game that's "finished" except for one pretty serious annoyance.
Previously, I had the following problem.
Say the snake is going right. If the player changed directions multiple times in quick succession, e.g., by pressing down then left, then the snake would go back into itself and reverse direction. Once I added collision detection code, this would cause the game to end and the player to lose because the snake collided with itself by going inward into itself. This problem was made possible because direction could be changed multiple times in one interval, e.g., from right to down then from down to left.
This problem was fixed by adding a bool that would store whether or not direction was allowed to change this interval. If the direction had not been changed yet this interval, then direction was allowed to change. If it had already been changed this interval, then it would have to wait until next interval to change again. This prevented the snake from ever going inward into itself because it guaranteed that the snake's direction could only change once per interval. But this created another problem in that in each interval, every key press after the first would not register.
Now, the problem is that the game no longer feels responsive. If the snake is going to the right, there is no reason that spamming down right in quick succession shouldn't do what the player expects. As it stands, the second right sometimes doesn't register because it was pressed too quickly (on the same interval as down was pressed). So by fixing one big issue in this way, I created another annoyance. How do I get the best of both worlds. How do I stay rid of the possibility to go inward into myself while restoring responsiveness?
I can provide code if necessary, but I thought that the question was pretty clear even in abstraction.
It sounds like the game either acts on the new direction in the next interval or the direction is lost until the user presses again.
Have you tried queuing the next direction? for instance, at every interval, you can check the queue to see if there is a new direction. If there is, change direction. If not, continue in the current direction.
This will probably accomplish the responsiveness you want while still being accurate to the user’s input.
Good luck
I had the exact same problem! Very annoying! I ended up implementing a queue, where recent keypresses are stored in a queue, and for each 'tick' I check if any elements in queue, and if so, shift it once (with Array.shift, which returns the shifted value) and then set the snakes's direction to the direction from the queue, like this:
if (dir_queue.length) {
let d = dir_queue.shift();
dx = d.dx;
dy = d.dy;
}
// move snake
x += dx;
y += dy;
Directions are pushed to the dir. queue in the keydown event handler, like this:
var key = evt.keyCode;
if (key === KEY.UP || key === KEY.DOWN || key === KEY.LEFT || key === KEY.RIGHT) {
switch (key) {
case 37:
dx = dx || -1; dy = 0;
break;
case 38:
dx = 0; dy = dy || -1;
break;
case 39:
dx = dx || 1; dy = 0;
break;
case 40:
dx = 0; dy = dy || 1;
}
// push to dir. queue
dir_queue.push({ dx: dx, dy: dy });
}
I am building an small CAD app that allows the user to select items and then press LEFT/RIGHT arrow keys to move them.
The problem
The problem is that the function that moves the elements takes too long to process if my canvas has many elements drawn on it.
The worst is that if the user presses and holds the arrow keys, the function needs to get fired so many times that I get the dreaded Unresponsive Script alert from my browser.
Even if the user burst-fires a keypress instead of holding it, I still have a problem.
So I figured that the way to go, is:
Collect keypresses and after e.g 2000ms to fire up the function with
the appropriate keypressCounter - the number of keypresses collected
before keyUp
The problem with the method above:
The user will have to wait for the timeout even if just one keypress was made - which does not have a huge overhead - therefore the ''crude'' method described above is less than ideal. It will make the nudge functionality feel cludgy where it could be fast.
What would be the most correct way to go around this? Any suggestions are welcome since the solution I suggest above seems rather crude
Notes:
I would appreciate code snippets, even rudimentary ones. I'm still in
my early coding stages. Or at least a comprehensive explanation to
any proposed solutions.
I am using Paper.js as the canvas library to draw the items, but that
shouldn't be a factor in any solution
The code this far:
//Keybinding ''right'' arrow key - Fires up the function to nudge left.
$(document).keydown(function (e) {
if (e.which === 39) {
nudgeSelection("right");
}
});
//Function that moves the selected element(s). Accepts direction as parameter.
function nudgeSelection(direction) {
var selected = paper.project.selectedItems;
for (var i = 0; i < selected.length; i++) {
switch (direction) {
case "up":
selected[i].position.y = selected[i].position.y - 1;
break;
case "down":
selected[i].position.y = selected[i].position.y + 1;
break;
case "left":
selected[i].position.x = selected[i].position.x - 1;
break;
case "right":
selected[i].position.x = selected[i].position.x + 1;
break;
}
}
}
I am making a game for my computing class where a player moves round a grid and depending on their settings and the terrain they move on their playerPower should decrease differently.
When the player moves I need to check what colour the box they land on is in order to determine the amount of power to deduct. I can't seem to fathom out how to do it.
Here is the JSFiddle: http://jsfiddle.net/nZ8vA/
The comments: //HERE IS WHERE I NEED TO CHECK THE COLOUR is where I need to check the boxes colour when the player moves onto it.
I would strongly suggest keeping track of the player's position with a separate variable, since it's much easier/quicker to access a JavaScript variable than trying to derive it from CSS positioning, and figuring out background colours from the DOM itself. Anyways, here's a quick solution I threw together, which I think gives you what you want:
I added this variable to track player position:
// x, y coordinates of player
var playerPos = [0, 0];
Then, to check colours, I took advantage of your previously defined map array, which gives the colours of each map cell. I wrote a little function that takes two coordinates, and feeds them into the map array to get back the colour. Using a switch/case after that allows you to respond to each colour accordingly:
// Checks colour against predefined map
function checkCol(cell, row){
var color = map[row][cell];
switch (color){
// Brown
case "b":
break;
// Green
case "g":
break;
// White
case "w":
break;
default:
break;
}
}
Lastly, with each key press, the coordinates of the player position are updated. One way to do it (while keeping within bounds of the map) is like so (note that each of these must be placed separately in your code, under the corresponding case during a key press):
// Left
playerPos[0] = Math.max(0, playerPos[0] - 1);
// Up
playerPos[1] = Math.max(0, playerPos[1] - 1);
// Right (you didn't specify you wanted this in your code with a comment, so just omit it if you don't want it)
playerPos[0] = Math.min(map[0].length - 1, playerPos[0] + 1);
// Down
playerPos[1] = Math.min(map.length - 1, playerPos[1] + 1);
// After each case, just call this to check the colour at the given position:
checkCol(playerPos[0], playerPos[1]);
This solution keeps all the logic within the JavaScript, and doesn't need to check the CSS of any elements.
Here's an updated JSFiddle to show you the code implemented. Check the console using web developer tools, in case you want to verify it is returning the correct colours.
Hope this helps! Let me know if you have any questions.
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
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.