javascript - How should I use requestAnimationFrame and setTimeout in parallel to make a better game loop? -
my goal create efficient game loop uses requestanimationframe updating display canvas , settimeout updating game logic. question should put drawing operations inside requestanimationframe loop or main drawing operation updates html canvas?
what mean "all drawing operations" of buffering. instance, i'd draw sprites buffer , draw buffer main canvas. on 1 hand, if put buffering requestanimationframe won't wasting cpu drawing on each logic update, on other hand, drawing cpu heavy , cause requestaniomationframe wait until operations finished... point of separating logic updates drawing requestanimationframe doesn't bogged down non-drawing processing.
does have experience approach creating game loop? , don't "just put in requestanimationframe," because slow down rendering. i'm convinced separating logic drawing way go. here's example of i'm talking about:
/* drawing loop. */ function render(time_stamp_){//first parameter of raf callback timestamp. window.requestanimationframe(render); /* draw sprites in render function? */ /* or should move logic loop? */ (var i=sprites.length-1;i>-1;i--){ sprites[i].drawto(buffer); } /* update on screen canvas. */ display.drawimage(buffer.canvas,0,0,100,100,0,0,100,100); } /* logic loop. */ function update(){ window.settimeout(update,20); /* update sprites. */ (var i=sprites.length-1;i>-1;i--){ sprites[i].update(); } } thanks!
edit:
i've decided go web workers separate game logic drawing, understand, must take place in main script loaded dom.
so, never found great way separate logic , drawing because javascript uses single thread. no matter execution of draw function may in way of logic or vis versa. did find way execute them in timely manner possible while ensuring constant time updates logic , optimized drawing using requestanimation frame. system set interpolate animations make skipped frames should device slow draw @ desired frame rate. anyway, here's code.
var engine = { /* functions. */ /* starts engine. */ /* interval_ number of milliseconds wait between updating logic. */ start : function(interval_) { /* accumulated_time how time has passed between last logic update , recent call render. */ var accumulated_time = interval_; /* current time current time of recent call render. */ var current_time = undefined; /* amount of time between second recent call render , recent call render. */ var elapsed_time = undefined; /* need reference in order keep track of timeout , requestanimationframe ids inside loop. */ var handle = this; /* last time render called, in time second recent call render made. */ var last_time = date.now(); /* here functions looped. */ /* loop setting callbacks inside own execution, creating string of endless callbacks unless intentionally stopped. */ /* each function defined , called using fancy parenthesis. keeps functions totally private. scope above them won't know exist! */ /* want call logic function first drawing function have work with. */ (function logic() { /* set next callback logic perpetuate loop! */ handle.timeout = window.settimeout(logic, interval_); /* pretty used add onto accumulated time since last update. */ current_time = date.now(); /* really, don't need elapsed time variable. add computation right onto accumulated time , save allocation. */ elapsed_time = current_time - last_time; last_time = current_time; accumulated_time += elapsed_time; /* want update once every time interval_ can fit accumulated_time. */ while (accumulated_time >= interval_) { /* update logic!!!!!!!!!!!!!!!! */ red_square.update(); accumulated_time -= interval_; } })(); /* reason keeping logic , drawing loops separate though they're executing in same thread asynchronously because of nature of timer based updates in asynchronously updating environment. */ /* don't want waste time when comes updating; "naps" taken processor should @ end of cycle after has been processed. */ /* so, logic wrapped in raf loop: it's going run whenever raf says it's ready draw. */ /* if want logic run consistently possible on set interval, it's best keep separate, because if has wait raf or input events processed, still might naturally happen before or after events, , don't want force occur @ earlier or later time if don't have to. */ /* ultimately, keeping these separate allow them execute in more efficient manner rather waiting when don't have to. */ /* , since logic way faster update drawing, drawing won't have wait long updates finish, should happen before raf. */ /* time_stamp_ argument accepted callback function of raf. records high resolution time stamp of when function first executed. */ (function render(time_stamp_) { /* set next callback raf perpetuate loop! */ handle.animation_frame = window.requestanimationframe(render); /* don't want render if accumulated time greater interval_. */ /* dropping frame when refresh rate faster logic can update. */ /* it's dropped reason. if interval > accumulated_time, no new updates have occurred recently, you'd redrawing same old scene, anyway. */ if (accumulated_time < interval_) { buffer.clearrect(0, 0, buffer.canvas.width, buffer.canvas.height); /* accumulated_time/interval_ time step. */ /* should less 1. */ red_square.draw(accumulated_time / interval_); html.output.innerhtml = "number of warps: " + red_square.number_of_warps; /* last. */ /* updates actual display canvas. */ display.clearrect(0, 0, display.canvas.width, display.canvas.height); display.drawimage(buffer.canvas, 0, 0, buffer.canvas.width, buffer.canvas.height, 0, 0, display.canvas.width, display.canvas.height); } })(); }, /* stops engine killing timeout , raf. */ stop : function() { window.cancelanimationframe(this.animation_frame); window.cleartimeout(this.timeout); this.animation_frame = this.timeout = undefined; }, /* variables. */ animation_frame : undefined, timeout : undefined }; this ripped straight out of 1 of projects there few variables in there defined elsewhere in code. red_square 1 of variables. if want check out full example, take @ github page! userpoth.github.io also, side note, tried using web workers separate out logic , miserable failure. web workers great when have lot of math , few objects pass between threads, can't drawing , slow big data transfers, @ least in context of game logic.
Comments
Post a Comment