so I am having troubles with automatic movement
The code I am using is
if (myGameArea.key && myGameArea.key == 40) {
snake.y ++;
}
which is moving but only when the key is hold, is there a way to let the object move in one direction automatically after just pressing the button. Sorry, if that's a stupid question, I really am not an experienced coder.
You should consider giving the snake object another attribute: velocity! Since you are dealing with two dimensions you can define vx and vy as the two components of the velocity, and when a key is pressed you can change the velocity to the appropriate value, for example:
if (myGameArea.key && myGameArea.key==40) {
snake.vx = 0;
snake.vy = 1;
}
As well as this, inside the snake object you should define the position by updating the current position. For this you just add the current velocity.
Hopefully this gets you on the path to a working snake game! If not, let me know and I can try to help out more.
I would use flags, and when you press a key set the flag to true for a while loop. When you press a key, go to a move function and have it move the direction of the flag until another key is pressed or you hit a wall.
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'm looking for a simple line of code or an API, if it is as simple as that.
I am using BabylonJS to make an online game, and I have run into a problem. I can't find anything on the documentation to support my problem. I am using
canvas.requestPointerLock = canvas.requestPointerLock || canvas.mozRequestPointerLock;
canvas.requestPointerLock();
To lock the mouse, when normally you have to click and drag. I am also using this movement script for basic movement:
function KEY_DOWN(event)
{
if (event.keyCode == 87)
{
player.position.z -= 0.5;
}
else if (event.keyCode == 65)
{
player.position.x += 0.5;
}
else if (event.keyCode == 83)
{
player.position.z += 0.5;
}
else if (event.keyCode == 68)
{
player.position.x -= 0.5;
}
}
This only transforms on an axis unfortunately. Is there any way to determine where my mouse is looking and move towards that point, and not just move on a fixed axis? I can't seem to find anything that has the exact methods I need. Thanks!
I don't know of any API, but it shouldn't be so bad, if I understand your problem correctly. You'll need to hook into the mousemove event after the point has been locked, and instead of the simple handling like shown here: http://www.html5rocks.com/en/tutorials/pointerlock/intro/ you would need to do your vector calculations against each vector of movement possible with the keys in that handler. Effectively, you would compute the x, y, z deltas that each key press corresponds to within your pointerlockchange handler based on the mouse deltas. Probably not as bad as it sounds, since your mouse deltas are only going to affect up to 2 axes at a time.
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 little HTML/JavaScript/CSS3 project for fun. I'm basically trying to make a wheel that rolls around in the browser window. To control the wheel I'm using keyup and keydown events for the cursor keys (left and right turn the wheel and up and down roll it forward or backward).
I've got it working pretty well so far, but there are two major glitches. Say I want to roll the wheel forward and without stopping I want to turn it a little to the right, then I would keep the up key pressed and press the right cursor key. When I do this there's a pause in the movement before it registers both events and keeps rolling.
That's one of the problems, the main problem is that, once I've performed the previous action and then wheel is at a desirable angle, if I let go of the right cursor key the browser registers both keys as released and the wheel comes to a stand still. Here is a jsFiddle of what it looks like: http://jsfiddle.net/UKqwu/1/. I know the code is a mess but it's a work in progress/learning experience and I've only been programming for a month or so.
Anyways thanks for any help. It only works in Chrome at the moment as far is I know. Haven't really been bothered fixing compatibility issues at this stage.
So, what is happening is essentially a limitation built in by your operating system, but there is a simple work-around. First I'll explain the limitation, and then the work-around.
If you were to (in a text box) hold down the "j" button, first one "j" would appear, and then after a short delay many "j"s would appear "jjjjjjjjjjjjjjjjjjjj"
This is the same problem your experiencing. The event fires once, waits for a moment, and then fires many more times.
The solution, however is simple. Instead of having your wheel move when the events are fired... have it update constantly, and separately keep track of what keys are up or down.
The Key Handler would look something like this...
function KeyHandler() {
this.left = false;
this.right= false;
...
function onKeyDown(e) {
if (e.keyCode == 37) {
this.left = true;
}
...
}
function onKeyUp(e) {
if (e.keyCode == 37) {
this.left = false;
}
...
}
}
(you'd attach the key handler to the body or whatever element you wish)
Your wheel would have an update function that looked like...
wheel.update = function() {
// the wheel is turning left
if (wheel.keyhandler.left) {
// make the appropriate adjustments
}
}
and then the game would have something like this...
wheel = new Wheel;
setInterval(function() {
wheel.update();
},100);
That way your wheel will always be updating based on the current state of the keys, and you wont have to rely on the limitations of events that are firing. :)
Here's a snippet of a simple game I once wrote
//key codes
var KEY_LEFT = 37;
var KEY_RIGHT = 39;
var KEY_A = 65;
var KEY_D = 68;
var KEY_SPACE = 32;
var keys = {};
function onKeyDown(e)
{
e = e || window.event;
var key = window.event.keyCode || e.which; // ie
keys[key] = true;
}
function onKeyUp(e)
{
var key = window.event.keyCode || e.which; // ie
delete keys[key];
}
This keeps track of all current key states. Then your game "tick" is on a setTimeout() rather than moving on key events and checks for appropriate keys.
function gameTick()
{
// update paddle angles
if (keys[KEY_LEFT])
{
// move left
}
if (keys[KEY_RIGHT])
{
// move right
}
}
Here's the game;
the problem you are facing is because your code is meant to detect single key press while your game needs 2 key press detection.
put this line in loop over size of e. that will set all pressed keys as 1. currently its detecting only one key press and processing for one at a time.
keys[e.keyCode] = 1;
check out this thread and u might get what you need. though its jquery, it might help conceptually. m also working on this with js... if anything new comes up will share...
Detect multiple keys on single keypress event in jQuery
your code and concept is cool if you are really one month old in programming.
Since my other bug got solved, I'm posting a new question for this bug.
I made a Snake canvas game, but my snake tends to eat itself when you press two buttons at the same time.. I'm not sure how to explain it properly, but this is what happens:
Say my snake is moving towards the left, and I press down + right, it'll eat itself and trigger a game over. Same when it goes to the right: down + left and bam, dead. I can't seem to reproduce the bug when the snake goes up and down though..
This is the code involved with changing directions:
bindEvents = ->
keysToDirections =
37 : LEFT
38 : UP
39 : RIGHT
40 : DOWN
$(document).keydown (e) ->
key = e.which
newDirection = keysToDirections[key]
if newDirection
setDirection newDirection
e.preventDefault()
setDirection = (newDirection) ->
# TODO: there's some bug here; try pressing two buttons at the same time..
switch Snake.direction
when UP, DOWN
allowedDirections = [LEFT, RIGHT]
when LEFT, RIGHT
allowedDirections = [UP, DOWN]
if allowedDirections.indexOf(newDirection) > -1
Snake.direction = newDirection
I thought there was something wrong with the compiled JS because my switch statement doesn't have a break on the last case; however, I tried adding else return to the coffee script file and this didn't change anything. I'm completely lost here so I hope someone will be able to spot where I'm going wrong.
It seems as if it takes the keydown events right, but they get overridden when you press too fast. If that makes sense? Like.. You'd press up when the snake is going right, but then you press left before it actually had a chance to go up and then it just goes left. Chaotic sentence right there, I suggest you play for a while and try to reproduce this if you're as intrigued as I am :(
I have no clue how to debug this properly.. The game loop tends to spam me with messages when I do console.log.
A live demo and link to my github repo can be found here
Thanks in advance.
The problem is that if you push the keys quickly enough, its possible to trigger the event callback multiple times during one frame. Thus, if the snake is going down, it can turn right and then up in the same frame, thus reversing direction and eating itself. I'll suggest two ways to solve this problem:
The first is to set a flag when the direction is changed, i.e.:
if allowedDirections.indexOf(newDirection) > -1 and !turnedThisFrame
Snake.direction = newDirection
turnedThisFrame = true
and then, in your code that runs every frame, set turnedThisFrame to false.
The second is to rework how you deal with keypresses. This is often the approach that I take. Keep a map of which keys are pressed (say, keysDown), and bind a function that sets keysDown[e.which] = true to keydown and another function which sets keysDown[e.which] = false to keyup. Then, you can check which keys are pressed in the code that runs each frame, and act accordingly.
Here's some details on how I implemented the second solution in a current project. The following code appears in my onload handler:
do ->
keysDown = []
$(document).keydown (e) ->
keysDown.push e.which
$(document).keyup (e) ->
keysDown = _.without keysDown, e.which
window.isPressed = (keyCode) -> keyCode in keysDown
The do -> construct is used to create a function and immediately calling it, which has the beneficial effect of keeping keysDown in closure for the handlers and isPressed, while avoiding polluting the main scope of the onload callback.
Then, at the beginning of my tick function (which runs once per frame and handles game logic, drawing the screen, etc.) I would have something like this:
switch Snake.direction
when UP, DOWN
allowedDirections = [LEFT, RIGHT]
when LEFT, RIGHT
allowedDirections = [UP, DOWN]
for direction in allowedDirections
if isPressed(directionToKey[direction])
Snake.direction = newDirection
break
The map directionToKey would just be the opposite of your keysToDirections.
Note that this means that keys listed first in allowedDirections will have priority, i.e. if you are going right and press both up and down in the same frame, up will occur regardless of which was pressed first.
Added advantage to this second method: you don't have to change the key handler callbacks when switching between, say, a menu screen and the game. You just have a different tick function checking for what is pressed.
You must retain the last direction is which the snake actually moved and determine allowedDirection based on that. Pressing a key only represents the intent to move in that direction, but it does not actually move when the key is pressed, but based on the speed of the game, i guess.
Your snake eating itself shows a problem with your hit detection (and hit detection handling) code. If you're hitting the snake, the game should end. A snake is not an apple! Nevermind, apparently I missed the part where the game is ending for you.
If you choose to allow pixel-granularity (I can't see your demo, my work's network is half-down..), you can't really make U turns "safe", like you could with a hex-granularity approach. Not saying your choice is bad, just telling you to pick your battles, some you just can't win.
I had the same problem, but I solved it by implementing a queue; each keypress sets the direction of the snake and that (new) direction is pushed to an array. Then, before I actually move the snake in the game loop, I check if there are any elements in my direction queue. If so, I shift it once via Array.shift. The return value is the first element of the queue and the new direction for my snake. Array.shift also removes that element from the queue, which is exactly what we want. If two keys are pressed almost simultaneously, the first and the second direction change is stored in our queue, and our aforementioned routine takes care of the rest, by first applying the first direction change in the next available tick and then applying the second direction change in the next tick thereafter.
Hope that makes sense? :-)