PDA

View Full Version : Game movement problems (event.keyCode, setTimeout)



schorhr
09-19-2008, 08:08 AM
Hello,
sorry if this has been discussed before, but I browsed through the forum and did not find an answer.
I learned javascript about 8 years ago, and never really used it since then. Many things have changed, and using php and actionscript have not helped to remember much :-)

Basicly I want to create a small game engine, either a RPG or Point&Click adventure. While I did find some premade demos and projects (such as this (http://www.planet-source-code.com/vb/scripts/ShowCode.asp?txtCodeId=2152&lngWId=2)), the controls usualy have the typical key-down delay.

Basicly I started a bit simpler by modifying this:
"moving image" demo (http://www.w3schools.com/dhtml/tryit.asp?filename=trydhtml_imagemove)

I tried to avoid the key-down-delay by triggering a "loop" when the key gets pressed the first time untill it gets released again.
It works up to the point I insert if...event.keyCode. Then the key action will only be performed once.



<script type="text/javascript">
var i=1

function goPic(){

if(event.keyCode=="68")
{i++;}
else if(event.keyCode=="65")
{i--;}

document.getElementById('myimage').style.position="relative";
document.getElementById('myimage').style.left=i;
timer=setTimeout("goPic()",10);

//test
//document.getElementById('myinput').value="=?="+i+"_"+Math.random(4);
}

function stopPic()
{clearTimeout(timer);}

</script>
</head>

<body onkeydown="goPic()" onkeyup="stopPic()" onunload="stopPic()">

<input id="myinput" />w=87, a=65, s=83, d=68,
<br />

<img id="myimage" src="smiley.gif" width="32" height="32" />


If I replace

if(event.keyCode=="68")
{i++;}
else if(event.keyCode=="65")
{i--;}
with a simple

i++;
it will repeat as long as the key is pressed just fine.

Can anyone point out to me what I am doing wrong?
(Or has a link to a sample?)

Thank you very much!

rangana
09-19-2008, 08:26 AM
Hope this helps:


<script type="text/javascript">
var i=1;
function goPic(e){
keynum=(window.event)?e.keyCode:e.which;
if(keynum===68)
i++;
else if(keynum===65)
i--;
document.getElementById('myimage').style.position="relative";
document.getElementById('myimage').style.left=i+'px';
// timer=setTimeout("goPic()",10);

//test
//document.getElementById('myinput').value="=?="+i+"_"+Math.random(4);
}

function stopPic()
{clearTimeout(timer); }

</script>

rangana
09-19-2008, 08:32 AM
You might also find it useful to set a maxlength attribute:


<input id="myinput" maxlength="1" />w=87, a=65, s=83, d=68,


Hope that helps.

schorhr
09-19-2008, 09:02 AM
Hello,
thank you for the quick reply!
Unfortunaly nothing happens when I replace my script with the one you provided (using opera and safari as I am not on my own computer at the moment).

As for the input's maxlength: I only use the input field for testing so it is not a problem :-)

keynum=(window.event)?e.keyCode:e.which;
is completely new to me, so I will read up on it and hopefully find the error/what I did wrong this time :-)

rangana
09-19-2008, 09:50 AM
Please accept my apology, I miss to instruct you to add an event keyword:


<body onkeydown="goPic(event)" onkeyup="stopPic()" onunload="stopPic()">

schorhr
09-19-2008, 10:03 AM
Thanks, the initial problem remains though.
As long the key is down the picture is suppose to keep moving.
timer=setTimeout("goPic()",10);
does not work though as long the if...else statements are inside the function?

Right now the picture will move one pixel and stop.

Sorry for the confusion, I might just be missing something here.

jscheuer1
09-19-2008, 01:51 PM
All browsers I tested would repeat the motion without a timeout, except for Opera. Opera also was the only one that would not respond to the event at all if it was assigned in the body tag. This is tested and works in FF, IE, Opera, and Safari 3 Win:


<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<title></title>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">

<script type="text/javascript">
var i=0;

function goPic(e){
e = e || window.event;
var k = e.keyCode || e.which;

i = k == 68? i + 1 : k == 65? i - 1 : i;

document.getElementById('myimage').style.position = "relative";
document.getElementById('myimage').style.left = i + 'px';

if(window.opera){
goPic.spoof = {keyCode : k};
goPic.timer = setTimeout(function(){goPic(goPic.spoof);}, 20);
};

//test
//document.getElementById('myinput').value = i;
};

function stopPic(){
if(goPic.timer)
clearTimeout(goPic.timer);
};

document.onkeydown = goPic;
if(window.opera)
document.onkeyup = stopPic;
</script>
</head>

<body>

<input id="myinput">w=87, a=65, s=83, d=68,
<br>

<img id="myimage" src="smiley.gif" width="32" height="32" alt="pic">
</body>
</html>

schorhr
09-19-2008, 02:22 PM
Thanks for testing it!
Strange that it performs so much differently on Opera 9.5 (mac) and Safari 1.3.2 (mac).

Right before reading your reply I got it to work by sending the keycode when calling the function from the body tag:

onkeydown="starttimer(event.keyCode)"


<html>
<head>
<script type="text/javascript">

var i=1;

function starttimer(foo)

{
if(foo==65)
{i--;}
else if(foo==68)
{i++;}

document.getElementById('myimage').style.position="relative";
document.getElementById('myimage').style.left=+i;

////document.getElementById('bla').value="_"+foo+"_"+var1;

bar=foo; //if I try to use starttimer(foo) it will not work?

timer=setTimeout("starttimer(bar)",10);
}

function stoptimer(){clearTimeout(timer);}

</script>
</head>
<body onkeydown="starttimer(event.keyCode)" onkeyup="stoptimer()">

<img id="myimage" src="smiley.gif" width="32" height="32" />

<input id="bla"/>

</body>
</html>

This results in odd behavor when pressing another key. I suppose the function is called again then.

I still do not understand why the function will not be called again by settimeout when I use if...event.keyCode?
At least this Opera-Version is rather up to date.
Safari 1.3.2 (mac) will show the same problem when I use your script: The image will move one pixel then stop.
The script I just posted works in 1.3.2 though.

Usualy I would update the browsers, but as this is not my computer I work with what is installed.

Anyway, this is really confusing me. I was trying all evening yesturday to figure out why if...event.keyCode would result in moving the image into the correct direction but settimeout would not execute anymore. I must be missing something. From all other programming/scripting languages I know I would expect it to function as long as the syntax is correct (which seemed to be the case, as the image was moved by 1 pixel)


I will now try to implement your solutions, especially skipping the use of onkey... in the body-tag.
Thank you very much :) if you (or anyone) knows a tutorial/guide page where a sample movement script is explained step by step please let me know; Especially lines such as
i = k == 68? i + 1 : k == 65? i - 1 : i;
are still a little cryptic to me, and I want to understand what I am using ;-)

jscheuer1
09-19-2008, 02:37 PM
Well, older Safari must not apply typematic repeat to the event. That's the issue with Opera. So, it could be determined at what version of Safari it started applying typematic repeat to the onkeydown event, and testing for that, lump it in with Opera for code branching in my approach.

Better still would be to find a way of detecting whether or not any given browser supports typematic repeat on its onkeydown event. However, I am not aware of any way to reliably determine that, but I will look around a bit (there may actually be a property for that, or a way of figuring it out with the code).

jscheuer1
09-19-2008, 03:23 PM
This seems to do the trick. I decided to just not use typematic repeat for any browser, that way they all can follow the path I originally set out for Opera. However, with them all following that path, things got both a little simpler, and a little more complex:


<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<title></title>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">

<script type="text/javascript">

function goPic(e){

if(goPic.running) return;
goPic.running = true;

e = e || window.event;

var goPic2 = function(){
goPic.i = k == 68? goPic.i + 1 : k == 65? goPic.i - 1 : goPic.i;
document.getElementById('myimage').style.left = goPic.i + 'px';
goPic.timer = setTimeout(goPic2, 20);
}, k = e.keyCode || e.which;

document.getElementById('myimage').style.position = "relative";
goPic2();

//test
//document.getElementById('myinput').value = goPic.i;
};

goPic.i = 0;

goPic.stopPic = function(){
goPic.running = false;
clearTimeout(goPic.timer);
};

document.onkeydown = goPic;
document.onkeyup = goPic.stopPic;

</script>
</head>

<body>

<input id="myinput">w=87, a=65, s=83, d=68,
<br>

<img id="myimage" src="smiley.gif" width="32" height="32" alt="pic">
</body>
</html>

Notes: I also changed the code to expose only one global variable (goPic). This could also probably be done without exposing any globals, but that would make it a bit more complicated to integrate it into certain other types of code.

Added Later:


i = k == 68? i + 1 : k == 65? i - 1 : i;

is just shorthand for:


if(k == 68)
i = i + 1;
else if (k == 65)
i = i - 1;
else
i = i;

schorhr
09-19-2008, 06:27 PM
Thank you very much for taking the time to write the script and the explanation!

Together with this and http://jsfromhell.com/math/is-point-in-poly I now have the basics to complete my non-tile based game -
and learn some more javascript along the way... ;-)

Strange that all other tutorials/demos I found so far never adress the issue at all.