Keydown producing unexpected result. HTML5 Game - javascript

So I am at the very beginning stages of creating my first platform style game in html5.So far I have only implemented left and right movement and no 'gravity' or collision detection is at play.
However, I've already hit an issue.
If you go left or right for a short period of time the 'character' acts as intended (I use character loosely as it's the map that is actually moving). If, however, you hold the key down the map moves too fast.
I figure the issue is that the keydown event listener is listening all of the time, there for moving the map is moving before each tick or frame of the game.
So my question is how can I make the keydown increase the map offset only on every tick of the game (20 milliseconds).
Here is my JSFiddle: CLICK HERE
document.addEventListener('keydown',function(event){
var dir = event.which;
if(dir == directions.LEFT){
mapOffsetX += mapOffsetDistanceX;
event.preventDefault();
};
if(dir == directions.RIGHT){
mapOffsetX -= mapOffsetDistanceX;
event.preventDefault();
};
});
document.addEventListener('keyup',function(event){
var dir = event.which;
if(dir == directions.LEFT){
mapOffsetX -= mapOffsetDistanceX;
};
if(dir == directions.RIGHT){
mapOffsetX += mapOffsetDistanceX;
};
});
initFloorObject(100,c.height/2,300,20,0,0,0,1);
var myInt = setInterval(function(){
clearScreen();
for(var i=0;i<floorObject.length;i++){
floorObject[i][0] = parseInt(floorObject[i][0])+mapOffsetX;
};
drawChar();
drawFloorObjects();
},20);

Set variable to false every time you keydown and set it back to true every 20 milliseconds.
var isKeydownAvailable = true;
document.addEventListener('keydown', function (event) {
var dir = event.which;
if(isKeydownAvailable){
if (dir == directions.LEFT) {
mapOffsetX += mapOffsetDistanceX;
event.preventDefault();
};
if (dir == directions.RIGHT) {
mapOffsetX -= mapOffsetDistanceX;
event.preventDefault();
};
isKeydownAvailable = false;
};
});
In the interval, reset the isKeydownAvailable to true.
var myInt = setInterval(function () {
clearScreen();
for (var i = 0; i < floorObject.length; i++) {
floorObject[i][0] = parseInt(floorObject[i][0]) + mapOffsetX;
};
drawChar();
drawFloorObjects();
isKeydownAvailable = true;
}, 20);

Use booleans for actions and check for them inside your interval.
On keydown you set the boolean isMovingLeft to true, then you add the offset in your interval function only if(isMovingLeft).
Do that for the other actions and you are good to go.

Related

Three.js Set relative position to another Object

Recently, I've been working on a video game with Three.js and I want the up arrow key to go forward relative to the camera.
Here is my code for the arrow key.
var x = 0;
var rotx = 0;
setInterval(function() {
if (x == 1){
camera.position.z += 0.05
}
}
document.addEventListener("keydown", function(event){
if (event.key == "ArrowUp"){
x = 1
}
});
document.addEventListener("keyup", function(event){
if (event.key == "ArrowUp"){
x = 0
}
});
Many times I've been searching for the answer. Usually coming across both
object.localToWorld();
object.worldToLocal();
but I can't seem to understand how to use this method.

object adds velocity instead of maintaining in opposite direct

I have a group of objects i want to rotate , there is a button which should onclick change from left to right and a stop button which should stop the current group position at its current location , however every time i click rotate , it changes direction but increases in speed even though it is bound to a slider, ive tried calling the animation frame last and cancelling it on each call but nothing works
var speedslider = document.getElementById("speedinput");
var direction = true;
var stopped = true;
speedslider.addEventListener("change",DirectionBTN.onclick);
zoomOutButton.addEventListener("change", zoomOutFunction);
speedslider.addEventListener("change",StopStartBTN.onclick);
//rotation of group
const rotateGroup = function()
{
if(stopped == true){
group.rotation.y =!group.rotation.y
}
if(direction == true){
group.rotation.y += speedslider.value/1000;
requestAnimationFrame(rotateGroup)
}
if(direction == false){
group.rotation.y -= speedslider.value/1000;
requestAnimationFrame(rotateGroup)
}
};
//start rotation left
StopStartBTN.onclick = function() {
stopped = !stopped
rotateGroup()
};
DirectionBTN.onclick = function() {
direction = !direction;
rotateGroup();
};

How do I fix these touch events? Events respond if there are 2 fingers but not 1

I am making a simple game of mine mobile-friendly.
The goal is to:
Make character walk if a touchstart event is sensed on right half of screen.
Stop character if a touchend event is sensed on the right half.
Jump the character if a touchend event happens on the left half of the screen.
I have the logic working perfectly for mouse up and down events so I'm pretty sure it's something to do inside the touchstart and end functions.
If two fingers are used as one press it seems to work fine.
If only one finger is used it doesn't work properly: touching anywhere starts the movement but nothing will stop it.
Here is the code for the touch inputs and associated function:
CheckWhichScreenHalf = function(e) {
loc = WindowToCanvas(e.pageX, e.pageY);
onScreenY = loc.y >= 0 && loc.y <= gameCanvas.height;
leftSideX = loc.x >= 0 && loc.x < gameCanvas.width/2;
rightSideX = loc.x > gameCanvas.width/2 && loc.x <= gameCanvas.width;
if (onScreenY && leftSideX){
return 'left';
}
else if (onScreenY && rightSideX){
return 'right';
}
else return 'neither';
};
TouchMove = false;
TouchJump = false;
gameCanvas.ontouchstart = function(e){
if (imagesHaveBeenLoaded) {
e.preventDefault();
for (var i = 0; i < e.touches.length; i++){
var side = CheckWhichScreenHalf(e.touches.item(i));
if (side === 'right'){
TouchMove = true;
}
}
}
}
gameCanvas.ontouchend = function(e){
if (imagesHaveBeenLoaded) {
e.preventDefault();
for (var i = 0; i < e.touches.length; i++){
var side = CheckWhichScreenHalf(e.touches.item(i));
if (side === 'right'){
TouchMove = false;
}
else if (side === 'left'){
playerJumping = true;
}
}
}
}
The game can be played here: http://webstudentwork.com/jgossling/MMWD/mp2/mp2.html

Make element behave a certain way until event (Making a pacman game)

I'm making a pacman game in Javascript as an exercise. What would be a good way to make the character go one direction indefinitely until another key is pressed?
function Player(){
this.left = $('#pacMan').css('left');
this.leftMove = function(){
this.left = parseInt(this.left) - 20;
$('#pacMan').animate({'left': this.left}, 100);
};
//Pressing directional keys calls appropriate methods.
$('body').keydown(function(){
if (event.which === 39){
for (i=0; i<13; i++){
pacMan.rightMove();
}
}
if (event.which === 37){
pacMan.leftMove();
}
if (event.which === 38){
pacMan.topMove();
}
if (event.which === 40){
pacMan.bottomMove();
}
});*/
How do I make it so the element keeps moving a direction until a new key is pressed, where it would go in that direction?
A general approach I tend to use for this type of problem is have your object have a changeX (vx) and a changeY (vy) variable. Then in your main game loop change the position of the object by those to variables:
this.left = parseInt(this.left) - this.vx;
this.top = parseInt(this.top) - this.vy;
In your event handler you would set the vales of vx and vy depending on where you want to move. For example setting vx = 10 and vy = 0 would make it move left by 10 units each loop.
if (event.which === 39) {
//pacMan.leftMove();
pacMan.vx = 10; pacMan.vy = 0;
}
The player would simply have a move() function that would move based on those values in the main loop:
var timer = setInterval(function () {
pacMan.move();
}, 50);
Where move() is:
this.move = function(){
this.left = parseInt(this.left) - this.vx;
$('#pacMan').css({'left': this.left})
this.top = parseInt(this.top) - this.vy;
$('#pacMan').css({'top': this.top});
}
Working Example
I recommend setTimeout function for that
setTimeout( function() {
// leftMove, topMove, bottomMove, rightMove
// if you press new key, you have to change direction
} , 1000 );
// 1000 moving delay
You could do it using window.setInterval, something like this should work
var timer;
$('body').keydown(function () {
var key = event.which;
window.clearInterval(timer);
timer = window.setInterval(function () {
switch (key) {
case 37:
pacMan.leftMove();
break;
case 38:
pacMan.topMove();
break;
case 39:
pacMan.rightMove();
break;
case 40:
pacMan.bottomMove();
break;
}
}, 100);
});

Stop awaiting input after fixed time

I'm new to web programming and I stumbled upon a problem that I couldn't solve and I'm not sure it can be solved. I'm creating a very simple "game" using jquery, and I want to make the thread to stop waiting for the (keydown) input and just carry on with the code, so I can perform either a simple upwards "jump", or a " left jump"/"right jump". Can it be done?
Here follows the codebit from what I've been doing so far:
http://www.codecademy.com/pt/pySlayer10761/codebits/OYQ11a/edit
You need a game loop thats running independantly from your keydown-handler. Elsewise any animation you might hack into the keydown handler might stop the moment no inputs are made anymore.
By looking at your code, I can see you tried to do it by creating a new setTimeout() on those keydowns. You are creating this for every keydown event fired. This is very likely to crash/freeze your browser at some point if the engine does not realize you are creation the same timeout over and over again.
Do it like this: in the onkeydown handler you only set a variable keydowncode to the keycode value. Then you create a new game loop like this
<script>
var keydownCode = 0;
var isInAnimation = false;
var animatedKeydownCode = 0;
var animationStartTime = 0;
var animationStartValue = 0;
// Lightweight keydown handler:
$(document).keydown(function(key) {
keydownCode = parseInt(key.which,10);
}
$(document).keyup(function(key) {
keydownCode = 0;
}
function animation() {
// here comes your animation logic..
// e.g. keep moving for 100 to 200 milliseconds after keypress
// Milli secs difference from
var nowTime = Date.now();
// Animations get prioritized: Only one animation at the same time!
if(isInAnimation) {
switch(animatedKeydownCode) {
case 37:
var delta = (nowTime-animationStartTime)/100*10;
if(delta > 10) { delta = 10; isInAnimation = false; }; // Animation over!
$('img').left(animationStartValue-delta);
case 37:
var delta = (nowTime-animationStartTime)/200*10;
if(delta > 10) { delta = 10; isInAnimation = false; }; // Animation over!
$('img').top(animationStartValue-delta);
case 39:
var delta = (nowTime-animationStartTime)/100*10;
if(delta > 10) { delta = 10; isInAnimation = false; }; // Animation over!
$('img').left(animationStartValue+delta);
}
// Ready to take new input, if its not outdated
} else {
// If some key is down and no animations active
if(keydownCode > 0) {
switch(keydownCode) {
case 37:
animationStartTime = nowTime;
animatedKeydownCode = keydownCode;
animationStartValue = $('img').left();
isInAnimation = true;
case 38:
// Only start a jump if on bottom
if($('img').css("top") == '390px') {
animationStartTime = nowTime;
animatedKeydownCode = keydownCode;
animationStartValue = $('img').top();
isInAnimation = true;
}
case 39:
animationStartTime = nowTime;
animatedKeydownCode = keydownCode;
animationStartValue = $('img').left();
isInAnimation = true;
}
}
}
window.requestAnimationFrame(animation);
}
window.requestAnimationFrame(animation);
</script>
This is no full game, you need to adjust it by yourself to get a working game. E.g. you might want to add some gravity to get mario down again when there is no input..
I think you are looking for setTimeout().
Like this:
setTimeout(function(){
// do something here which will be executed after 5 seconds.
},5000);
You can't stop a thread in javascript as it is single threaded.

Categories

Resources