1

I am new to javascript and to programming in general so don't assume I know a lot.

I am creating a simple html5 javascript game where vehicles on a highway are coming down towards you (represented by canvas rectangles). I am creating the vehicle spawning and movement at the moment. My goal is to have the vehicles spawn and come down with a constant space in between them regardless of what speed they are going.

What I have works except when any lag occurs and when the speed variable gets set to around the numbers four and under. I did some research and I believe this is because setTimeout doesn't take lag into account. Since I am new I don't know many of the functions, I have no clue on how to fix this and I can't find a solution online.

You can see a working demo of my code here - mess with opening tabs and other lag causing processes and you can try setting the speed variable to a number below 5 and you'll see where i'm coming from. Any help is appreciated.

<!DOCTYPE html>
<html>
<body>
<canvas id="ctx" width="480" height="320" style="border:1px solid #000000;"></canvas>
<script>
        var ctx = document.getElementById("ctx").getContext("2d");

            function setIntervalX(callback, delay, repetitions) {
                var x = 0;
                var intervalID = window.setInterval(function () {
                    callback();
                    if (++x === repetitions) {
                       window.clearInterval(intervalID);
                   }
                }, delay);
            }

            var speed = 50


            function game() {
                var yAxis
                var selectType = Math.floor((Math.random()*6)+1)
                switch (selectType){
                    case 1: //semi
                    case 2:
                        yAxis = -80
                        var lane = Math.floor((Math.random()*3)+1)
                            switch (lane)
                                {
                                    case 1: //left lane
                                        setIntervalX(function () {
                                        ctx.fillStyle = "white";
                                        ctx.fillRect(200,yAxis,15,80);
                                        yAxis = yAxis + 2
                                        ctx.fillStyle = "black";
                                        ctx.fillRect(200,yAxis,15,80);
                                        }, speed, 400);
                                    break;
                                    case 2: //middle lane
                                        setIntervalX(function () {
                                        ctx.fillStyle = "white";
                                        ctx.fillRect(230,yAxis,15,80);
                                        yAxis = yAxis + 2
                                        ctx.fillStyle = "black";
                                        ctx.fillRect(230,yAxis,15,80);
                                        }, speed, 400);
                                    break;
                                    case 3: //right lane
                                        setIntervalX(function () {
                                        ctx.fillStyle = "white";
                                        ctx.fillRect(260,yAxis,15,80);
                                        yAxis = yAxis + 2
                                        ctx.fillStyle = "black";
                                        ctx.fillRect(260,yAxis,15,80);
                                        }, speed, 400);
                                    break;
                                }
                        setTimeout(function() {game()}, speed * 80) 
                    break;      
                    case 3: //bike
                        yAxis = -10
                        var lane = Math.floor((Math.random()*3)+1)
                            switch (lane)
                                {
                                    case 1: //left lane
                                        setIntervalX(function () {
                                        ctx.fillStyle = "white";
                                        ctx.fillRect(200,yAxis,10,10);
                                        yAxis = yAxis + 2
                                        ctx.fillStyle = "black";
                                        ctx.fillRect(200,yAxis,10,10);
                                        }, speed, 400);
                                    break;
                                    case 2: //middle lane
                                        setIntervalX(function () {
                                        ctx.fillStyle = "white";
                                        ctx.fillRect(230,yAxis,10,10);
                                        yAxis = yAxis + 2
                                        ctx.fillStyle = "black";
                                        ctx.fillRect(230,yAxis,10,10);
                                        }, speed, 400);
                                    break;
                                    case 3: //right lane
                                        setIntervalX(function () {
                                        ctx.fillStyle = "white";
                                        ctx.fillRect(260,yAxis,10,10);
                                        yAxis = yAxis + 2
                                        ctx.fillStyle = "black";
                                        ctx.fillRect(260,yAxis,10,10);
                                        }, speed, 400);
                                    break;
                                }
                        setTimeout(function() {game()}, speed * 45)     
                    break;  
                    case 4: //car
                    case 5:
                    case 6:
                        yAxis = -20
                        var lane = Math.floor((Math.random()*3)+1)
                        switch (lane)
                                {
                                    case 1: //left lane
                                        setIntervalX(function () {
                                        ctx.fillStyle = "white";
                                        ctx.fillRect(200,yAxis,10,20);
                                        yAxis = yAxis + 2
                                        ctx.fillStyle = "black";
                                        ctx.fillRect(200,yAxis,10,20);
                                        }, speed, 400);
                                    break;
                                    case 2: //middle lane
                                        setIntervalX(function () {
                                        ctx.fillStyle = "white";
                                        ctx.fillRect(230,yAxis,10,20);
                                        yAxis = yAxis + 2
                                        ctx.fillStyle = "black";
                                        ctx.fillRect(230,yAxis,10,20);
                                        }, speed, 400);
                                    break;
                                    case 3: //right lane
                                        setIntervalX(function () {
                                        ctx.fillStyle = "white";
                                        ctx.fillRect(260,yAxis,10,20);
                                        yAxis = yAxis + 2
                                        ctx.fillStyle = "black";
                                        ctx.fillRect(260,yAxis,10,20);
                                        }, speed, 400);
                                    break;
                                }
                        setTimeout(function() {game()}, speed * 50)         
                    break;}
                }           
            game()

    </script>

    </body>
    </html>
tysonsmiths
  • 485
  • 1
  • 8
  • 19
  • setInterval guarantees only a **minimum** time between executions. If other code is blocking your intervals could be longer. Instead, whenever an interval is fired, check the time and work out what needs to be done based on how much time since the last iteration. –  Jan 06 '14 at 06:47
  • _"setting the speed variable to a number below 5"_ - For game animation you shouldn't need to use a timeout/interval anywhere near that small. I mean, a 5ms delay is equivalent to 200 frames/second, but a 20ms interval (50 frames/second) should be fast enough. Regardless of perceived framerate, if you try with too small an interval your code will be causing its own lag because it won't be able to do all the required processing in between each interval. – nnnnnn Jan 06 '14 at 06:53
  • So should I have the vehicles move more than two pixels down each time so that I can get the required speed? – tysonsmiths Jan 06 '14 at 07:03

1 Answers1

1

You should only have 1 main setInterval that updates everything.
Lag shouldn't be an issue, especially with a project of this size.

RainingChain
  • 7,397
  • 10
  • 36
  • 68
  • If your meaning to use a setInterval for the whole function that wont work to my understanding. Each vehicle is a different length so they need their own timer so the same amount of space is between each vehicle. Im not sure if its the lag is causing the problems but when the speed gets down to those lower numbers the game doesn't do what its supposed to and I cant can't seem to fix it. (the reason i thought it was lag is because every time you open a tab and go back to it its all messed up) – tysonsmiths Jan 06 '14 at 07:01
  • Your vehicule should be an object that has different properties such as their length/space/image etc... All the vehicules should be in an array. Normally, a game runs between 30-60 fps. Objects in a game are all updated at the same interval. The difference is how many pixel they move per frame. (Ex: 0.1 pixel) – RainingChain Jan 06 '14 at 08:00