de-vraag
  • Pertanyaan
  • Tag
  • Pengguna
Notifikasi
Imbalan
Registrasi
Setelah Anda mendaftar, Anda akan diberitahu tentang balasan dan komentar untuk pertanyaan Anda.
Gabung
Jika Anda sudah memiliki akun, masuk untuk memeriksa pemberitahuan baru.
Akan ada hadiah untuk pertanyaan, jawaban, dan komentar tambahan.
Lebih
Sumber
Sunting
 robert.vinluan
robert.vinluan
Question

Mengendalikan fps dengan requestAnimationFrame?

Sepertinya requestAnimationFrame adalah de facto cara untuk menghidupkan hal-hal yang sekarang. Ini bekerja cukup baik bagi saya untuk sebagian besar, tapi sekarang saya'm mencoba untuk melakukan beberapa kanvas animasi dan aku bertanya-tanya: Apakah ada cara untuk memastikan itu berjalan di suatu fps? Saya mengerti bahwa tujuan dari rAF adalah untuk secara konsisten animasi yang halus, dan saya bisa menjalankan risiko membuat animasi berombak, tapi sekarang tampaknya untuk menjalankan secara drastis kecepatan yang berbeda cukup sewenang-wenang, dan I'm bertanya-tanya jika ada's cara untuk memerangi yang entah bagaimana.

I'd gunakan setInterval tapi aku ingin optimasi bahwa rAF ini (terutama secara otomatis berhenti ketika tab di fokus).

Dalam kasus seseorang ingin melihat kode saya, it's cukup banyak:

animateFlash: function() {
    ctx_fg.clearRect(0,0,canvasWidth,canvasHeight);
    ctx_fg.fillStyle = 'rgba(177,39,116,1)';
    ctx_fg.strokeStyle = 'none';
    ctx_fg.beginPath();
    for(var i in nodes) {
        nodes[i].drawFlash();
    }
    ctx_fg.fill();
    ctx_fg.closePath();
    var instance = this;
    var rafID = requestAnimationFrame(function(){
        instance.animateFlash();
    })

    var unfinishedNodes = nodes.filter(function(elem){
        return elem.timer < timerMax;
    });

    if(unfinishedNodes.length === 0) {
        console.log("done");
        cancelAnimationFrame(rafID);
        instance.animate();
    }
}

Di Mana Node.drawFlash() adalah hanya beberapa kode yang menentukan radius didasarkan dari variabel counter dan kemudian menarik sebuah lingkaran.

111 2013-11-04T08:31:58+00:00 8
Lee Taylor
Lee Taylor
Pertanyaan edit 26 Februari 2018 в 3:07
Pemrograman
animation
javascript
performance
canvas
requestanimationframe
Solution / Answer
 markE
markE
4 November 2013 в 4:25
2013-11-04T16:25:50+00:00
Lebih
Sumber
Sunting
#22705860

Cara throttle requestAnimationFrame tertentu frame rate

Demo throttling pada 5 FPS:

Metode ini bekerja dengan pengujian waktu yang telah berlalu sejak mengeksekusi frame terakhir loop.

Gambar kode mengeksekusi hanya bila anda ditentukan FPS interval yang telah berlalu.

Bagian pertama dari kode menetapkan beberapa variabel yang digunakan untuk menghitung waktu yang telah berlalu.

var stop = false;
var frameCount = 0;
var $results = $("#results");
var fps, fpsInterval, startTime, now, then, elapsed;

// initialize the timer variables and start the animation

function startAnimating(fps) {
    fpsInterval = 1000 / fps;
    then = Date.now();
    startTime = then;
    animate();
}

Dan ini kode aktual requestAnimationFrame loop yang menarik pada anda ditentukan FPS.

// the animation loop calculates time elapsed since the last loop
// and only draws if your specified fps interval is achieved

function animate() {

    // request another frame

    requestAnimationFrame(animate);

    // calc elapsed time since last loop

    now = Date.now();
    elapsed = now - then;

    // if enough time has elapsed, draw the next frame

    if (elapsed > fpsInterval) {

        // Get ready for next frame by setting then=now, but also adjust for your
        // specified fpsInterval not being a multiple of RAF's interval (16.7ms)
        then = now - (elapsed % fpsInterval);

        // Put your drawing code here

    }
}
 Hydroper
Hydroper
Jawaban edit 19 Juni 2016 в 12:52
153
0
Pengguna anonim
4 November 2013 в 5:31
2013-11-04T17:31:07+00:00
Lebih
Sumber
Sunting
#22705861

Update 2016/6

Masalah throttling frame rate adalah bahwa layar telah konstan tingkat update, biasanya 60 FPS.

Jika kita ingin 24 FPS kita tidak akan pernah mendapatkan yang benar 24 fps pada layar, kita dapat waktu seperti itu tapi tidak menunjukkan sebagai monitor hanya dapat menampilkan disinkronkan frame pada 15 fps, 30 fps atau 60 fps (beberapa monitor juga 120 fps).

Namun, untuk waktu tujuan kita dapat menghitung dan memperbarui bila mungkin.

Anda dapat membangun semua logika untuk mengendalikan frame-rate oleh encapsulating perhitungan dan callback ke suatu objek:

function FpsCtrl(fps, callback) {

    var delay = 1000 / fps,                               // calc. time per frame
        time = null,                                      // start time
        frame = -1,                                       // frame count
        tref;                                             // rAF time reference

    function loop(timestamp) {
        if (time === null) time = timestamp;              // init start time
        var seg = Math.floor((timestamp - time) / delay); // calc frame no.
        if (seg > frame) {                                // moved to next frame?
            frame = seg;                                  // update
            callback({                                    // callback function
                time: timestamp,
                frame: frame
            })
        }
        tref = requestAnimationFrame(loop)
    }
}

Kemudian tambahkan beberapa controller dan konfigurasi kode:

// play status
this.isPlaying = false;

// set frame-rate
this.frameRate = function(newfps) {
    if (!arguments.length) return fps;
    fps = newfps;
    delay = 1000 / fps;
    frame = -1;
    time = null;
};

// enable starting/pausing of the object
this.start = function() {
    if (!this.isPlaying) {
        this.isPlaying = true;
        tref = requestAnimationFrame(loop);
    }
};

this.pause = function() {
    if (this.isPlaying) {
        cancelAnimationFrame(tref);
        this.isPlaying = false;
        time = null;
        frame = -1;
    }
};

Penggunaan

Hal ini menjadi sangat sederhana - sekarang, semua yang kita harus lakukan adalah untuk membuat sebuah instance dengan menetapkan fungsi callback dan frame rate yang diinginkan seperti ini:

var fc = new FpsCtrl(24, function(e) {
     // render each frame here
  });

Kemudian mulai (yang bisa menjadi perilaku default jika diinginkan):

fc.start();

Yang's ini, semua logika ditangani secara internal.

Demo

var ctx = c.getContext("2d"), pTime = 0, mTime = 0, x = 0;
ctx.font = "20px sans-serif";

// update canvas with some information and animation
var fps = new FpsCtrl(12, function(e) {
    ctx.clearRect(0, 0, c.width, c.height);
    ctx.fillText("FPS: " + fps.frameRate() + 
                 " Frame: " + e.frame + 
                 " Time: " + (e.time - pTime).toFixed(1), 4, 30);
    pTime = e.time;
    var x = (pTime - mTime) * 0.1;
    if (x > c.width) mTime = pTime;
    ctx.fillRect(x, 50, 10, 10)
})

// start the loop
fps.start();

// UI
bState.onclick = function() {
    fps.isPlaying ? fps.pause() : fps.start();
};

sFPS.onchange = function() {
    fps.frameRate(+this.value)
};

function FpsCtrl(fps, callback) {

    var delay = 1000 / fps,
        time = null,
        frame = -1,
        tref;

    function loop(timestamp) {
        if (time === null) time = timestamp;
        var seg = Math.floor((timestamp - time) / delay);
        if (seg > frame) {
            frame = seg;
            callback({
                time: timestamp,
                frame: frame
            })
        }
        tref = requestAnimationFrame(loop)
    }

    this.isPlaying = false;

    this.frameRate = function(newfps) {
        if (!arguments.length) return fps;
        fps = newfps;
        delay = 1000 / fps;
        frame = -1;
        time = null;
    };

    this.start = function() {
        if (!this.isPlaying) {
            this.isPlaying = true;
            tref = requestAnimationFrame(loop);
        }
    };

    this.pause = function() {
        if (this.isPlaying) {
            cancelAnimationFrame(tref);
            this.isPlaying = false;
            time = null;
            frame = -1;
        }
    };
}
body {font:16px sans-serif}
<label>Framerate: <select id=sFPS>
    <option>12</option>
    <option>15</option>
    <option>24</option>
    <option>25</option>
    <option>29.97</option>
    <option>30</option>
    <option>60</option>
</select></label><br>
<canvas id=c height=60></canvas><br>
<button id=bState>Start/Stop</button>

Lama menjawab

Tujuan utama dari requestAnimationFrame adalah untuk melakukan sinkronisasi update ke monitor's refresh rate. Ini akan memerlukan anda untuk menghidupkan di FPS monitor atau faktor itu (ie. 60, 30, 15 FPS untuk khas refresh rate @ 60 Hz).

Jika anda ingin lebih sewenang-wenang FPS maka tidak ada gunanya menggunakan rAF sebagai frame rate tidak akan pernah cocok dengan monitor's frekuensi update lagian (hanya frame di sana-sini) yang hanya tidak dapat memberikan animasi yang halus (seperti dengan semua frame re-timing) dan anda dapat mungkin juga menggunakan setTimeout atau setInterval sebagai gantinya.

Ini juga masalah yang diketahui dalam video profesional industri ketika anda ingin pemutaran video pada berbagai FPS maka perangkat akan menunjukkan itu di refresh. Banyak teknik telah digunakan seperti frame blending dan kompleks re-timing re-building frame menengah didasarkan pada gerakan vektor, tetapi dengan kanvas teknik ini tidak tersedia dan hasilnya akan selalu menjadi dendeng video.

var FPS = 24;  /// "silver screen"
var isPlaying = true;

function loop() {
    if (isPlaying) setTimeout(loop, 1000 / FPS);

    ... code for frame here
}

Alasan mengapa kita setTimeout pertama (dan mengapa beberapa tempat rAF pertama ketika poli-isi digunakan) adalah bahwa ini akan menjadi lebih akurat sebagai setTimeout akan antrian acara segera ketika loop dimulai sehingga tidak peduli berapa banyak waktu yang tersisa kode yang akan digunakan (disediakan itu doesn't melebihi batas waktu interval) panggilan berikutnya akan berada pada interval yang diwakilinya (murni rAF ini tidak penting sebagai rAF akan mencoba untuk melompat ke frame berikutnya dalam hal apapun).

Juga layak untuk dicatat bahwa menempatkan hal pertama juga akan risiko panggilan susun sebagai dengan setInterval. setInterval mungkin sedikit lebih akurat untuk penggunaan ini.

Dan anda dapat menggunakan setInterval bukan luar loop untuk melakukan hal yang sama.

var FPS = 29.97;   /// NTSC
var rememberMe = setInterval(loop, 1000 / FPS);

function loop() {

    ... code for frame here
}

Dan untuk menghentikan loop:

clearInterval(rememberMe);

Dalam rangka untuk mengurangi frame rate ketika tab menjadi kabur anda dapat menambahkan faktor seperti ini:

var isFocus = 1;
var FPS = 25;

function loop() {
    setTimeout(loop, 1000 / (isFocus * FPS)); /// note the change here

    ... code for frame here
}

window.onblur = function() {
    isFocus = 0.5; /// reduce FPS to half   
}

window.onfocus = function() {
    isFocus = 1; /// full FPS
}

Dengan cara ini anda dapat mengurangi FPS untuk 1/4 dll.

38
0
Luke Taylor
Luke Taylor
25 Agustus 2016 в 2:09
2016-08-25T02:09:38+00:00
Lebih
Sumber
Sunting
#22705864

Saya sarankan pembungkus panggilan anda untuk requestAnimationFrame dalam setTimeout. Jika anda menelepon setTimeout dari dalam fungsi dari mana anda diminta animasi frame, anda're mengalahkan tujuan requestAnimationFrame. Tetapi jika anda menelepon requestAnimationFrame dari dalam setTimeout bekerja dengan lancar:

var fps = 25
function animate() {
  setTimeout(function() {
    requestAnimationFrame(animate);
  }, 1000 / fps);
}
31
0
 jdmayfield
jdmayfield
23 Januari 2018 в 11:44
2018-01-23T23:44:55+00:00
Lebih
Sumber
Sunting
#22705866

Ini semua adalah ide-ide bagus dalam teori, sampai anda pergi jauh. Masalahnya adalah anda dapat't throttle RAF tanpa de-sinkronisasi itu, mengalahkan itu's tujuan yang ada. Jadi anda membiarkan hal itu berjalan pada kecepatan penuh, dan memperbarui data dalam sebuah loop terpisah, , atau bahkan sebuah thread terpisah!

Ya, saya mengatakan itu. Anda can melakukan multi-threaded JavaScript di browser!

Ada dua metode yang saya tahu pekerjaan yang sangat baik tanpa jank, menggunakan jauh lebih sedikit jus dan menciptakan panas yang lebih sedikit. Manusia akurat skala waktu dan efisiensi mesin adalah hasil bersih.

Maaf jika ini adalah sedikit bertele-tele, tapi here goes...


Cara 1: Update data melalui setInterval, dan grafis melalui RAF.

Terpisah setInterval untuk memperbarui terjemahan dan rotasi nilai-nilai, fisika, tabrakan, dll. Menjaga nilai-nilai tersebut dalam suatu objek untuk setiap elemen animasi. Menetapkan mengubah string ke suatu variabel di masing-masing objek setInterval 'frame'. Jauhkan benda-benda dalam sebuah array. Mengatur interval yang anda inginkan fps di ms: ms=(1000/fps). Hal ini membuat mantap jam yang memungkinkan sama fps pada perangkat apapun, terlepas dari RAF kecepatan. jangan menetapkan untuk mengubah unsur-unsur berikut!

Dalam requestAnimationFrame loop, iterate melalui array dengan tua-sekolah untuk loop-- tidak menggunakan bentuk-bentuk baru di sini, mereka lambat!

for(var i=0; i<sprite.length-1; i++){  rafUpdate(sprite[i]);  }

Di rafUpdate fungsi, bisa mengubah string dari js objek di dalam array, dan unsur-unsurnya id. Anda harus sudah memiliki 'sprite' unsur-unsur yang melekat pada sebuah variabel atau dapat diakses dengan mudah melalui cara-cara lain sehingga anda don't kehilangan waktu 'mendapatkan'-ing mereka di RAF. Menjaga mereka dalam sebuah benda bernama setelah mereka id html's bekerja dengan cukup baik. Set bagian atas bahkan sebelum masuk ke SI atau RAF.

Gunakan RAF untuk memperbarui anda mengubah only, hanya menggunakan transformasi 3D (bahkan untuk 2d), dan mengatur css "akan-berubah: mengubah;" pada unsur-unsur yang akan berubah. Hal ini membuat anda mengubah disinkronisasikan ke native refresh rate sebanyak mungkin, tendangan GPU, dan memberitahu browser mana untuk berkonsentrasi paling.

Jadi, anda harus memiliki sesuatu seperti ini pseudocode...

// refs to elements to be transformed, kept in an array
var element = [
   mario: document.getElementById('mario'),
   luigi: document.getElementById('luigi')
   //...etc.
]

var sprite = [  // read/write this with SI.  read-only from RAF
   mario: { id: mario  ....physics data, id, and updated transform string (from SI) here  },
   luigi: {  id: luigi  .....same  }
   //...and so forth
] // also kept in an array (for efficient iteration)

//update one sprite js object
//data manipulation, CPU tasks for each sprite object
//(physics, collisions, and transform-string updates here.)
//pass the object (by reference).
var SIupdate = function(object){
  // get pos/rot and update with movement
  object.pos.x += object.mov.pos.x;  // example, motion along x axis
  // and so on for y and z movement
  // and xyz rotational motion, scripted scaling etc

  // build transform string ie
  object.transform =
   'translate3d('+
     object.pos.x+','+
     object.pos.y+','+
     object.pos.z+
   ') '+

   // assign rotations, order depends on purpose and set-up. 
   'rotationZ('+object.rot.z+') '+
   'rotationY('+object.rot.y+') '+
   'rotationX('+object.rot.x+') '+

   'scale3d('.... if desired
  ;  //...etc.  include 
}

var fps = 30; //desired controlled frame-rate

// CPU TASKS - SI psuedo-frame data manipulation
setInterval(function(){
  // update each objects data
  for(var i=0; i<sprite.length-1; i++){  SIupdate(sprite[i]);  }
},1000/fps); //  note ms = 1000/fps

// GPU TASKS - RAF callback, real frame graphics updates only
var rAf = function(){
  // update each objects graphics
  for(var i=0; i<sprite.length-1; i++){  rAF.update(sprite[i])  }
  window.requestAnimationFrame(rAF); // loop
}

// assign new transform to sprite's element, only if it's transform has changed.
rAF.update = function(object){     
  if(object.old_transform !== object.transform){
    element[object.id].style.transform = transform;
    object.old_transform = object.transform;
  }
} 

window.requestAnimationFrame(rAF); // begin RAF

Hal ini membuat anda update ke data objek dan mengubah string disinkronkan dengan yang diinginkan 'frame' tingkat di SI, dan sebenarnya mengubah tugas-tugas di RAF disinkronkan dengan GPU refresh rate. Jadi sebenarnya grafis update hanya di RAF, tapi perubahan data, dan membangun mengubah string yang di SI, dengan demikian tidak ada jankies tapi 'waktu' arus yang diinginkan frame-rate.


Aliran:

[setup js sprite objects and html element object references]

[setup RAF and SI single-object update functions]

[start SI at percieved/ideal frame-rate]
  [iterate through js objects, update data transform string for each]
  [loop back to SI]

[start RAF loop]
  [iterate through js objects, read object's transform string and assign it to it's html element]
  [loop back to RAF]

Metode 2. Menempatkan SI di web-pekerja. Yang satu ini adalah FAAAST dan halus!

Sama seperti cara 1, tapi menempatkan SI di web-pekerja. It'll berjalan pada yang benar-benar terpisah benang kemudian, meninggalkan halaman untuk hanya berurusan dengan RAF dan UI. Lulus sprite array bolak-balik sebagai 'dipindahtangankan objek'. Ini adalah buko cepat. Tidak mengambil waktu untuk mengkloning atau cerita bersambung, tapi itu's tidak seperti lewat referensi dalam referensi dari sisi lain hancur, sehingga anda akan perlu untuk memiliki kedua sisi melewati ke sisi lain, dan hanya memperbarui mereka ketika hadir, seperti melewati catatan bolak-balik dengan teman pacar di sma.

Hanya satu orang yang bisa membaca dan menulis pada satu waktu. Ini baik-baik saja selama mereka memeriksa apakah itu's tidak terdefinisi untuk menghindari kesalahan. RAF lebih CEPAT dan akan menendang kembali dengan segera, kemudian pergi melalui banyak GPU frame hanya memeriksa jika itu's sudah dikirim belum kembali. SI di web-pekerja akan memiliki sprite array sebagian besar waktu, dan akan memperbarui posisi, gerakan dan fisika data, serta menciptakan baru mengubah string, kemudian menyebarkannya kembali ke RAF di halaman.

Ini adalah cara tercepat yang saya tahu untuk menghidupkan unsur-unsur melalui script. Dua fungsi ini akan berjalan sebagai dua program terpisah, di dua thread terpisah, mengambil keuntungan dari multi-core CPU's cara yang satu js script tidak. Multi-threaded animasi javascript.

Dan ia akan melakukannya dengan lancar tanpa jank, tapi sebenarnya ditentukan frame-rate, dengan sedikit perbedaan.


Hasilnya:

Salah satu dari dua metode ini akan memastikan anda skrip akan berjalan pada kecepatan yang sama pada setiap PC, ponsel, tablet, dll (hanya kemampuan perangkat dan browser, tentu saja).

Lee Taylor
Lee Taylor
Jawaban edit 26 Februari 2018 в 3:08
10
0
Rustem Kakimov
Rustem Kakimov
6 Januari 2018 в 6:51
2018-01-06T06:51:02+00:00
Lebih
Sumber
Sunting
#22705865

Cara mudah throttle tertentu FPS:

// timestamps are ms passed since document creation.
// lastTimestamp can be initialized to 0, if main loop is executed immediately
var lastTimestamp = 0,
    maxFPS = 30,
    timestep = 1000 / maxFPS; // ms for each frame

function main(timestamp) {
    window.requestAnimationFrame(main);

    // skip if timestep ms hasn't passed since last frame
    if (timestamp - lastTimestamp < timestep) return;

    lastTimestamp = timestamp;

    // draw frame here
}

window.requestAnimationFrame(main);

Sumber: Penjelasan Rinci dari Permainan JavaScript Loop dan Waktu oleh Isaac Sukin

3
0
 befzz
befzz
16 Mei 2016 в 10:05
2016-05-16T10:05:22+00:00
Lebih
Sumber
Sunting
#22705863

Skipping requestAnimationFrame penyebab tidak halus(yang diinginkan) animasi pada custom fps.

// Input/output DOM elements
var $results = $("#results");
var $fps = $("#fps");
var $period = $("#period");

// Array of FPS samples for graphing

// Animation state/parameters
var fpsInterval, lastDrawTime, frameCount_timed, frameCount, lastSampleTime, 
        currentFps=0, currentFps_timed=0;
var intervalID, requestID;

// Setup canvas being animated
var canvas = document.getElementById("c");
var canvas_timed = document.getElementById("c2");
canvas_timed.width = canvas.width = 300;
canvas_timed.height = canvas.height = 300;
var ctx = canvas.getContext("2d");
var ctx2 = canvas_timed.getContext("2d");

// Setup input event handlers

$fps.on('click change keyup', function() {
    if (this.value > 0) {
        fpsInterval = 1000 / +this.value;
    }
});

$period.on('click change keyup', function() {
    if (this.value > 0) {
        if (intervalID) {
            clearInterval(intervalID);
        }
        intervalID = setInterval(sampleFps, +this.value);
    }
});

function startAnimating(fps, sampleFreq) {

    ctx.fillStyle = ctx2.fillStyle = "#000";
    ctx.fillRect(0, 0, canvas.width, canvas.height);
    ctx2.fillRect(0, 0, canvas.width, canvas.height);
    ctx2.font = ctx.font = "32px sans";

    fpsInterval = 1000 / fps;
    lastDrawTime = performance.now();
    lastSampleTime = lastDrawTime;
    frameCount = 0;
    frameCount_timed = 0;
    animate();

    intervalID = setInterval(sampleFps, sampleFreq);
        animate_timed()
}

function sampleFps() {
    // sample FPS
    var now = performance.now();
    if (frameCount > 0) {
        currentFps =
            (frameCount / (now - lastSampleTime) * 1000).toFixed(2);
        currentFps_timed =
            (frameCount_timed / (now - lastSampleTime) * 1000).toFixed(2);
        $results.text(currentFps + " | " + currentFps_timed);

        frameCount = 0;
        frameCount_timed = 0;
    }
    lastSampleTime = now;
}

function drawNextFrame(now, canvas, ctx, fpsCount) {
    // Just draw an oscillating seconds-hand

    var length = Math.min(canvas.width, canvas.height) / 2.1;
    var step = 15000;
    var theta = (now % step) / step * 2 * Math.PI;

    var xCenter = canvas.width / 2;
    var yCenter = canvas.height / 2;

    var x = xCenter + length * Math.cos(theta);
    var y = yCenter + length * Math.sin(theta);

    ctx.beginPath();
    ctx.moveTo(xCenter, yCenter);
    ctx.lineTo(x, y);
    ctx.fillStyle = ctx.strokeStyle = 'white';
    ctx.stroke();

    var theta2 = theta + 3.14/6;

    ctx.beginPath();
    ctx.moveTo(xCenter, yCenter);
    ctx.lineTo(x, y);
    ctx.arc(xCenter, yCenter, length*2, theta, theta2);

    ctx.fillStyle = "rgba(0,0,0,.1)"
    ctx.fill();

    ctx.fillStyle = "#000";
    ctx.fillRect(0,0,100,30);

    ctx.fillStyle = "#080";
    ctx.fillText(fpsCount,10,30);
}

// redraw second canvas each fpsInterval (1000/fps)
function animate_timed() {
    frameCount_timed++;
    drawNextFrame( performance.now(), canvas_timed, ctx2, currentFps_timed);

    setTimeout(animate_timed, fpsInterval);
}

function animate(now) {
    // request another frame
    requestAnimationFrame(animate);

    // calc elapsed time since last loop
    var elapsed = now - lastDrawTime;

    // if enough time has elapsed, draw the next frame
    if (elapsed > fpsInterval) {
        // Get ready for next frame by setting lastDrawTime=now, but...
        // Also, adjust for fpsInterval not being multiple of 16.67
        lastDrawTime = now - (elapsed % fpsInterval);

        frameCount++;
            drawNextFrame(now, canvas, ctx, currentFps);
    }
}
startAnimating(+$fps.val(), +$period.val());
input{
  width:100px;
}
#tvs{
  color:red;
  padding:0px 25px;
}
H3{
  font-weight:400;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<h3>requestAnimationFrame skipping <span id="tvs">vs.</span> setTimeout() redraw</h3>
<div>
    <input id="fps" type="number" value="33"/> FPS:
    <span id="results"></span>
</div>
<div>
    <input id="period" type="number" value="1000"/> Sample period (fps, ms)
</div>
<canvas id="c"></canvas><canvas id="c2"></canvas>

Kode asli by @tavnab.

2
0
Samer Alkhabbaz
Samer Alkhabbaz
26 Agustus 2018 в 6:13
2018-08-26T06:13:43+00:00
Lebih
Sumber
Sunting
#22705867

Saya selalu melakukan hal ini dengan cara yang sangat sederhana tanpa bermain-main dengan cap waktu:

var fps, eachNthFrame, frameCount;

fps = 30;

//This variable specifies how many frames should be skipped.
//If it is 1 then no frames are skipped. If it is 2, one frame 
//is skipped so "eachSecondFrame" is renderd.
eachNthFrame = Math.round((1000 / fps) / 16.66);

//This variable is the number of the current frame. It is set to eachNthFrame so that the 
//first frame will be renderd.
frameCount = eachNthFrame;

requestAnimationFrame(frame);

//I think the rest is self-explanatory
fucntion frame() {
  if (frameCount == eachNthFrame) {
    frameCount = 0;
    animate();
  }
  frameCount++;
  requestAnimationFrame(frame);
}
Samer Alkhabbaz
Samer Alkhabbaz
Jawaban edit 28 September 2018 в 4:40
1
0
Jim Witte
Jim Witte
2 April 2015 в 11:24
2015-04-02T23:24:53+00:00
Lebih
Sumber
Sunting
#22705862

Berikut ini's baik-baik penjelasan saya temukan: CreativeJS.com, untuk membungkus setTimeou) call di dalam fungsi diteruskan ke requestAnimationFrame. Keprihatinan saya dengan "biasa" requestionAnimationFrame akan sama, "bagaimana jika saya hanya ingin untuk menghidupkan tiga kali yang kedua?" Bahkan dengan requestAnimationFrame (sebagai lawan untuk setTimeout) adalah bahwa hal itu masih limbah (beberapa) jumlah "energi" (arti bahwa Browser kode untuk melakukan sesuatu, dan mungkin memperlambat sistem anda turun) 60 atau 120 atau namun berkali-kali kedua, sebagai lawan hanya dua atau tiga kali per detik (seperti yang mungkin anda inginkan).

Sebagian besar waktu saya menjalankan browser dengan JavaScript intentially off hanya untuk alasan ini. Tapi, aku'm menggunakan Yosemite 10.10.3, dan saya pikir ada's beberapa jenis timer masalah dengan itu - setidaknya pada sistem lama (relatif tua - arti 2011).

0
0
Related communities 1
JavaScript Indonesia
JavaScript Indonesia
14 549 pengguna
Grup JavaScript yang membahas JavaScript, framework JS, dan Node JS secara universal. Cek Pinned Message untuk keterangan lebih lanjut. Komunitas ReactJS: https://t.me/react_idn
Buka telegram
Tambahkan pertanyaan
Kategori
Semua
Teknologi
Budaya / Rekreasi
Kehidupan / Seni
Ilmu Pengetahuan
Profesional
Bisnis
Pengguna
Semua
Baru
Populer
1
UbiBot UK
Terdaftar 14 jam yang lalu
2
Галина Утяшова
Terdaftar 1 hari yang lalu
3
Asilbek Qadamboyev
Terdaftar 4 hari yang lalu
4
Akshit Mehta
Terdaftar 1 minggu yang lalu
5
me you
Terdaftar 1 minggu yang lalu
ID
JA
KO
RU
© de-vraag 2022
Sumber
stackoverflow.com
di bawah lisensi cc by-sa 3.0 dengan atribusi