Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations Mike Lewis on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

Function not rendering in setInterval 1

Status
Not open for further replies.

ralphonzo

Programmer
Apr 9, 2003
228
GB
Can anybody see why the distcount() function doesn't render the race distance here?

Code:
var race = 2000;
var counter = setInterval(function(){distcount(race)}, 1000); //1000 will  run it every 1 second

function distcount(race)
{
  var inrace = race;
  if (inrace > 0)
  {
     clearInterval(counter);
     return;
  }

 document.getElementById("race").innerHTML = inrace + "yds"; 
}

var runners = 6;
$(function() {
	$('#clickme').click(function() {
		if(racestart == false){
			$('#book').animate({
				left: '+=50'
			}, 5000, function() {
			});
			racestart = true;
		}
	});
});

$(function() {
	$.perSecond = function() {
		if(race){
			for(looper = 0; looper < 2; looper++){
				looperplus = looper+1;
				disttravelled[looper] += racepace[looper];
				//document.write(namers[looper]+": "+disttravelled[looper]+"<br/><br/>");
				if(racepace[looper] > bestdistance) {
					bestdistance = racepace[looper];
				} 
				$('#h'+looperplus).animate({ left: '+='+racepace[looper]/10+"px" }, 1000, function() { });
			}
			race -= bestdistance;
			
		} else {
			alert("Race ended");
		}
  	};
});

function raceGo(){
	//document.write("runners: "+runners+"<br/><br/>");
	bestdistance = 0;
	var int = self.setInterval(function(){$.perSecond()},1000);
	racestart = true;
}

and in the HTML:

Code:
<span id="race"></span>
 
one second might well not be enough for the DOM to render. try putting the setInterval code in a $(document).ready() block or an onload event etc.
 
No, neither method worked. setInterval is working fine elsewhere, and also works if I use function specific code. It just falls down when I try to use code from another function.
 
Silly me.
Race is greater than 0 so the conditional is always triggered in distcount. Thus it returns before the new value is rendered in the dom. Comment out the return line and try again.
 
That's got it rendering, but it doesn't update.
 
Sure. Because you are clearing the interval too.

I guess you didn't write the initial code?
 
Trying to figure what goes where to do what. I'm getting there, but some things leave me dumbfounded! I'm a whiz with ActionScript, but this seems complex for the sake of it!
 
you're not showing us all the javascript on the page. for example, it looks like there is a jquery plugin that runs $.perSecond script, probably every second ....

if that's the case then try getting rid of the setInterval and distcount functions and adding this code after the if(race){} block (thus at the end of the function).

Code:
$('#race').html( race + " yards");

 
So simple...once it's there in black and white that is! You're right about the $.perSecond script. Are you a clairvoyant? I don't suppose you know how to make it wait until a button event triggers it do you?
 
assuming your button has the id 'clickme' the the existing function will work fine. just add the racestart variable to the global scope and edit the main function as shown

Code:
$(function() {
	$.perSecond = function(){
              [red]if(racestart){[/red]	
              if(race){
			for(looper = 0; looper < 2; looper++){
				looperplus = looper+1;
				disttravelled[looper] += racepace[looper];
				//document.write(namers[looper]+": "+disttravelled[looper]+"<br/><br/>");
				if(racepace[looper] > bestdistance) {
					bestdistance = racepace[looper];
				} 
				$('#h'+looperplus).animate({ left: '+='+racepace[looper]/10+"px" }, 1000, function() { });
			}
			race -= bestdistance;
			
		} else {
			alert("Race ended");
                        [red]racestart = false;[/red] //this might be dealt with elsewhere aswell.
		}
              [red]  $('#race').html(race + " yards");
             } [/red]
 	};
});
 
That's got it a treat now, thanks. More techniques to play with. I think I'm guilty of coding this as if it were a piece of ActionScript code, and it's suffering for it. Do you know is there a way of making the animation run smoother through the loop?
 
wouldn't it be better to calculate the pixels each thing had to travel (I guess that's 200 given that race is 2000), and then set the animation duration of each 'thing' to a relative time dependent on the racepace?

or use a progress bar script?
 
Progress will be influenced by external values, such as stamina, jockey skill, random factoring, etc, so that's not really an option. I've got the images trundling along quite nicely now, and the irregularity of movement is actually an asset I think.

This is a little hobby project of mine, which also serves to (attempt) to get me up to speed in JS and JQ. You've been a massive help. What is it that you do for a living, and where?
 
Understood that the variables are external but do they change during a race?

In any event, to make the animation more fluid using your method I would set the duration of each to fast, explicitly set queue to false and not run the perSecond script every second but instead run it on race start and then loop the animation while race start is true.

Re your last question I practice law in the UK (and Anglo-Saxon ) markets but live in the South West of France.
 
A legal AND technical genius? Nice part of the world. Someone's got life sussed :eek:)
 
i had some spare time so wrote this code as an example of how you could create a smooth animation with more information given to the viewer (without effecting the animation).

Code:
<!DOCTYPE HTML>
<html>
	<head>
		<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
		<title>Race Test</title>
		<!--<script type="text/javascript" src="jquery.min.js"></script>-->
		<script src="[URL unfurl="true"]http://code.jquery.com/jquery-latest.js"></script>[/URL]
		<style type="text/css">
			html, body, div {padding:0; margin:0;}
			#course {width: 500px;}
			.racer	{width: 20px; height: 20px; min-width: 20px; min-height:20px; border:thin black solid; margin-top: 10px; text-align:center;}
			#race{ margin-top: 50px; min-height:100px; border: thin red solid;}
			#buttons{ margin-top: 30px;}
		</style>
		<script type="text/javascript">
			$(document).ready(function(){
	
	var race = 2000; //race length in yards
	
	/* set race pace */
	/* this is an array of objects with the div id and speed as the prop and value */
	/* if this needs more granularity then make this a function that gathers and calculates the right numbers and puts it in an object */
	var racepace2 = { 
						h1: 10, 
						h2: 8, 
						h3: 15 
					};
	
	/* get and store opening positions */
	var openingPositions = new Array();
	for(var i=1; i<=3; i++) openingPositions[i] = $('#h' + i).offset();
	
	/* method to bring the racers back to the origin */
	var returnToStart = function(){
		for(var i=1; i<=3; i++) $('#h'+i).offset({top: openingPositions[i].top, left: openingPositions[i].left});
		$('#race').html('Results<br/>');
	};
	
	/* helper method to sort the racepace object */
	function sortObject(obj){
    	var arr = [];
    	for (var prop in obj) {
        	if (obj.hasOwnProperty(prop)) {
            	arr.push({
                	'key': prop,
                	'value': obj[prop]
            	});
        	}
    	}
    	arr.sort(function(a, b) { return a.value - b.value; });
    	return arr; // returns array
	}
	
	$('#clickme').on('click', function(e){
		e.preventDefault();
		var duration = new Array();
		var i;
		switch($(this).text()){
			case 'Stop':
				for(var j=1;j<=3;j++) $('#h' + j).stop( true ); //stop animations
				$(this).text('Start');
				break;
				
			case 'Start':
				returnToStart();
				racestart = true;
				$(this).text('Stop');
				//pick a random race length between 10 and 20 seconds
				var racelength = Math.floor((Math.random()*10)+10);
				
				//sort the racepace2 object  
				var rp = sortObject(racepace2);
				
				//get the total of the racepaces
				var t = 0;
				for (var prop in racepace2) {
					t += racepace2[prop];
            	}
        	
				
				for(i = rp.length - 1; i >= 0; i--){
					duration[i] = (rp[i].value / rp[0].value) * racelength * 1000;
					if (i == rp.length - 1) {
						$('#' + rp[i].key).animate(
							{'margin-left': '+=' + ($('#course').width() - $('#' + rp[i].key).width()) + "px"}, 
							{
								duration: duration[i],
								queue: false,
								complete: (function(j){
									return function(){
										$('#race').html($('#race').html() + 'Racer ' + rp[j].key.charAt(rp[j].key.length - 1) + ' finished in ' + duration[j] / 1000 + " seconds<br/>");
									};
								}(i))
							}
						);
					} else if (i == 0){
						$('#' + rp[i].key).animate(
							{'margin-left': '+=' + ($('#course').width() - $('#' + rp[i].key).width()) + "px"}, 
							{
								duration: duration[i],
								queue: false,
								step: (function(j){
									return function(){
										var o = $('#' + rp[j].key).offset();
										var distance = $('#course').width() - (o.left - openingPositions[rp[j].key.charAt(rp[j].key.length - 1)].left);
										$('#race').html(  Math.round(  (race/$('#course').width()) * distance ) + " yards to go");
									};
								}(i)),
								complete: (function(j){
									return function(){
										$('#race').html('Race Finished.<br/>Racer ' + rp[j].key.charAt(rp[j].key.length - 1) + ' wins in ' + duration[j] / 1000 + " seconds<br/>");
										$('#clickme').text('Start');
									};
								}(i))
							}
						);	
	
					} else {
						$('#' + rp[i].key).animate(
							{'margin-left': '+=' + ($('#course').width() - $('#' + rp[i].key).width()) + "px"},
							{
								duration: duration[i],
								queue: false,
								complete: (function(j){
									return function(){
										$('#race').html($('#race').html() + 'Racer ' + rp[j].key.charAt(rp[j].key.length - 1) + ' finished in ' + duration[j] / 1000 + " seconds<br/>");
									};
								}(i))
							}
						);	
					}
				}
				break;
			
		}
	});
});
		</script>
	</head>
	<body>
		
		<div id="course">
			<div style="overflow-y:hidden;"><div style="float:left; color:green;">|| <- Start</div><div style="float:right;color:red; text-align:right">Finish -> ||</div></div>
			<div id="h1" class="racer">1</div>
			<div id="h2" class="racer">2</div>
			<div id="h3" class="racer">3</div>
		</div>
		
		
		<div id="race">Results</div>
		
		<div id="buttons">
			<button id="clickme">Start</button>
		</div>
	</body>
</html>
 
Crikey! Did you enjoy that? I'll have a play with that tomorrow when I get the chance. Busy looking for some part-time work to prop up the exchequer while my business gains traction. Not as much fun as playing with coding racing games!! Or finding a legal precedent I'll warrant!!!
 
Im not a JavaScript guru at all but I have used the jquery abstraction framework for a few years. So I'm not holding this out as good coding or the right way to do something. And I only spent fifteen minutes or so on it.

The interesting challenge for me was how to pass a parameter to a callback function without jquery executing the callback before it should. Turns out you have to use not one but two nested anonymous functions to achieve this. I assume because with a parameter jquery assumes that it must execute the code at instantiation time and that the function (not the result) is returned and will be used for the callback. Makes sense, particularly in a loop, as otherwise the value of the parameter will/may have changed between instantiation and execution of the callback.
 
Sorry for the delay. A big project's come into the studio, so all hobby pieces on hold. It works nicely, and I'll be using it as the new framework if you don't mind ... mine's in the bin!! I'll keep you updated on the project if you wish?
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top