[{"data":1,"prerenderedAt":658},["ShallowReactive",2],{"blog-canvas-game-loop":3},{"id":4,"title":5,"body":6,"description":15,"extension":648,"meta":649,"navigation":145,"path":654,"seo":655,"stem":656,"__hash__":657},"blog\u002Fblog\u002Fcanvas-game-loop.md","HTML5 Canvas: The Game Loop and Animation",{"type":7,"value":8,"toc":646},"minimark",[9,642],[10,11,12,347],"i18n-text",{},[13,14,16,20,29,32,54,64,79,88,96,102,117,121,124,340],"template",{"v-slot:en":15},"",[17,18,5],"h1",{"id":19},"html5-canvas-the-game-loop-and-animation",[21,22,23,24,28],"p",{},"Drawing shapes on a canvas is just the beginning. To make a game, those shapes need to move! This is where the ",[25,26,27],"strong",{},"Game Loop"," comes in. It's the beating heart of every video game ever made.",[21,30,31],{},"A Game Loop does three things repeatedly, usually 60 times a second (60 FPS):",[33,34,35,42,48],"ol",{},[36,37,38,41],"li",{},[25,39,40],{},"Clear"," the old drawings off the canvas.",[36,43,44,47],{},[25,45,46],{},"Update"," the positions and logic of your game objects.",[36,49,50,53],{},[25,51,52],{},"Draw"," the objects in their new positions.",[55,56,58,59,63],"h2",{"id":57},"_1-why-requestanimationframe","1. Why ",[60,61,62],"code",{},"requestAnimationFrame","?",[21,65,66,67,70,71,74,75,78],{},"In the early days of the web, developers used ",[60,68,69],{},"setInterval"," or ",[60,72,73],{},"setTimeout"," for animations. Today, we use ",[60,76,77],{},"window.requestAnimationFrame",". It's significantly better because:",[80,81,82,85],"ul",{},[36,83,84],{},"It's optimized by the browser to match your screen's refresh rate (usually 60Hz or 144Hz for buttery smooth animations).",[36,86,87],{},"It pauses when the user switches to another browser tab, saving battery and CPU.",[55,89,91,92,95],{"id":90},"_2-clearing-the-frame-clearrect","2. Clearing the Frame (",[60,93,94],{},"clearRect",")",[21,97,98,99,101],{},"If you move an object without clearing the canvas first, it will leave a permanent \"trail\" behind it, like a paintbrush dragging across a page. You must erase the entire canvas at the start of every frame using ",[60,100,94],{},".",[103,104,108],"pre",{"className":105,"code":106,"language":107,"meta":15,"style":15},"language-javascript shiki shiki-themes github-light github-dark","ctx.clearRect(0, 0, canvas.width, canvas.height); \u002F\u002F Erases everything\n","javascript",[60,109,110],{"__ignoreMap":15},[111,112,115],"span",{"class":113,"line":114},"line",1,[111,116,106],{},[55,118,120],{"id":119},"_3-building-a-simple-bouncing-ball","3. Building a Simple Bouncing Ball",[21,122,123],{},"Let's put it all together into a working Game Loop. We'll make a ball that bounces off the left and right walls of the canvas.",[103,125,127],{"className":105,"code":126,"language":107,"meta":15,"style":15},"const canvas = document.getElementById('gameCanvas');\nconst ctx = canvas.getContext('2d');\n\n\u002F\u002F 1. Define our object state\nlet ball = {\n  x: 50,\n  y: 150,\n  radius: 20,\n  speedX: 5 \u002F\u002F How much X changes per frame (velocity)\n};\n\n\u002F\u002F 2. The Game Loop Function\nfunction update() {\n  \u002F\u002F Step A: Clear the Canvas\n  ctx.clearRect(0, 0, canvas.width, canvas.height);\n  \n  \u002F\u002F Step B: Update Logic (Move the ball)\n  ball.x += ball.speedX;\n  \n  \u002F\u002F Bounce logic: If ball hits right or left edge, reverse speed\n  if (ball.x + ball.radius > canvas.width || ball.x - ball.radius \u003C 0) {\n    ball.speedX = -ball.speedX; \u002F\u002F Reverse direction\n  }\n  \n  \u002F\u002F Step C: Draw the new frame\n  ctx.beginPath();\n  ctx.arc(ball.x, ball.y, ball.radius, 0, 2 * Math.PI);\n  ctx.fillStyle = 'red';\n  ctx.fill();\n  \n  \u002F\u002F Step D: Loop it! Call update again before the next screen repaint\n  requestAnimationFrame(update);\n}\n\n\u002F\u002F 3. Start the loop\nupdate();\n",[60,128,129,134,140,147,153,159,165,171,177,183,189,194,200,206,212,218,224,230,236,241,247,253,259,265,270,276,282,288,294,300,305,311,317,323,328,334],{"__ignoreMap":15},[111,130,131],{"class":113,"line":114},[111,132,133],{},"const canvas = document.getElementById('gameCanvas');\n",[111,135,137],{"class":113,"line":136},2,[111,138,139],{},"const ctx = canvas.getContext('2d');\n",[111,141,143],{"class":113,"line":142},3,[111,144,146],{"emptyLinePlaceholder":145},true,"\n",[111,148,150],{"class":113,"line":149},4,[111,151,152],{},"\u002F\u002F 1. Define our object state\n",[111,154,156],{"class":113,"line":155},5,[111,157,158],{},"let ball = {\n",[111,160,162],{"class":113,"line":161},6,[111,163,164],{},"  x: 50,\n",[111,166,168],{"class":113,"line":167},7,[111,169,170],{},"  y: 150,\n",[111,172,174],{"class":113,"line":173},8,[111,175,176],{},"  radius: 20,\n",[111,178,180],{"class":113,"line":179},9,[111,181,182],{},"  speedX: 5 \u002F\u002F How much X changes per frame (velocity)\n",[111,184,186],{"class":113,"line":185},10,[111,187,188],{},"};\n",[111,190,192],{"class":113,"line":191},11,[111,193,146],{"emptyLinePlaceholder":145},[111,195,197],{"class":113,"line":196},12,[111,198,199],{},"\u002F\u002F 2. The Game Loop Function\n",[111,201,203],{"class":113,"line":202},13,[111,204,205],{},"function update() {\n",[111,207,209],{"class":113,"line":208},14,[111,210,211],{},"  \u002F\u002F Step A: Clear the Canvas\n",[111,213,215],{"class":113,"line":214},15,[111,216,217],{},"  ctx.clearRect(0, 0, canvas.width, canvas.height);\n",[111,219,221],{"class":113,"line":220},16,[111,222,223],{},"  \n",[111,225,227],{"class":113,"line":226},17,[111,228,229],{},"  \u002F\u002F Step B: Update Logic (Move the ball)\n",[111,231,233],{"class":113,"line":232},18,[111,234,235],{},"  ball.x += ball.speedX;\n",[111,237,239],{"class":113,"line":238},19,[111,240,223],{},[111,242,244],{"class":113,"line":243},20,[111,245,246],{},"  \u002F\u002F Bounce logic: If ball hits right or left edge, reverse speed\n",[111,248,250],{"class":113,"line":249},21,[111,251,252],{},"  if (ball.x + ball.radius > canvas.width || ball.x - ball.radius \u003C 0) {\n",[111,254,256],{"class":113,"line":255},22,[111,257,258],{},"    ball.speedX = -ball.speedX; \u002F\u002F Reverse direction\n",[111,260,262],{"class":113,"line":261},23,[111,263,264],{},"  }\n",[111,266,268],{"class":113,"line":267},24,[111,269,223],{},[111,271,273],{"class":113,"line":272},25,[111,274,275],{},"  \u002F\u002F Step C: Draw the new frame\n",[111,277,279],{"class":113,"line":278},26,[111,280,281],{},"  ctx.beginPath();\n",[111,283,285],{"class":113,"line":284},27,[111,286,287],{},"  ctx.arc(ball.x, ball.y, ball.radius, 0, 2 * Math.PI);\n",[111,289,291],{"class":113,"line":290},28,[111,292,293],{},"  ctx.fillStyle = 'red';\n",[111,295,297],{"class":113,"line":296},29,[111,298,299],{},"  ctx.fill();\n",[111,301,303],{"class":113,"line":302},30,[111,304,223],{},[111,306,308],{"class":113,"line":307},31,[111,309,310],{},"  \u002F\u002F Step D: Loop it! Call update again before the next screen repaint\n",[111,312,314],{"class":113,"line":313},32,[111,315,316],{},"  requestAnimationFrame(update);\n",[111,318,320],{"class":113,"line":319},33,[111,321,322],{},"}\n",[111,324,326],{"class":113,"line":325},34,[111,327,146],{"emptyLinePlaceholder":145},[111,329,331],{"class":113,"line":330},35,[111,332,333],{},"\u002F\u002F 3. Start the loop\n",[111,335,337],{"class":113,"line":336},36,[111,338,339],{},"update();\n",[21,341,342,343,346],{},"And that’s it! The ",[60,344,345],{},"requestAnimationFrame(update)"," at the end creates an infinite loop that smoothly animates the ball back and forth across your screen. Once you understand this loop, you are officially making a game!",[13,348,349,353,360,363,383,389,401,414,420,425,440,444,447,631],{"v-slot:id":15},[17,350,352],{"id":351},"html5-canvas-game-loop-dan-animasi","HTML5 Canvas: Game Loop dan Animasi",[21,354,355,356,359],{},"Menggambar bentuk statis di dalam canvas hanyalah awal mulanya. Untuk membuat sebuah game, bentuk-bentuk itu harus dipaksa bergerak merespons interaksi! Di sinilah ",[25,357,358],{},"Game Loop (Siklus Game)"," berperan mengambil alih kemudi. Engine daur ulang inilah jantung yang berdetak di setiap game digital mana pun di jagat raya ini.",[21,361,362],{},"Sebuah Game Loop melakukan tiga fungsi ini secara berulang terus menerus secara stabil, tipikalnya dipanggil 60 kali per detiknya (60 Frames Per Second \u002F FPS):",[33,364,365,371,377],{},[36,366,367,370],{},[25,368,369],{},"Bersihkan (Clear)"," layar kanvas secara massal dari sisa coretan frame gambar di detik sebelumnya.",[36,372,373,376],{},[25,374,375],{},"Perbarui (Update)"," angka koordinat posisi variabel fisika game Anda (Contoh: Nambah nilai X geser ke kanan ujung layar).",[36,378,379,382],{},[25,380,381],{},"Cetak Ulang (Draw)"," menggambar ulang wujud objek-objek tersebut di titik mendarat kordinat barunya.",[55,384,386,387,63],{"id":385},"_1-mengapa-menggunakan-engine-requestanimationframe","1. Mengapa Menggunakan Engine ",[60,388,62],{},[21,390,391,392,394,395,397,398,400],{},"Di era lampau ketika browser web baru mengenal JS, programmer memodifikasi ",[60,393,69],{}," atau ",[60,396,73],{}," paksa untuk mengkalkulasi waktu gerak animasi. Tapi di standar modern sekarang kita mewajibkan pemakaian ",[60,399,77],{},". Kenapa ini jauh lebih dihormati?",[80,402,403,406],{},[36,404,405],{},"Fungsi ini sinkronisasinya diawasi sepenuhnya oleh otak Mesin Browser demi menyamakan timing Refresh Rate spek asli monitor perangkat layar pemakainya (Misalnya menembus 120Hz\u002F144Hz) sehingga visual pergerakan animasinya serasa mulus merayap laksana mentega.",[36,407,408,409,413],{},"Animasi engine Loop akan otomatis dibekukan \u002F di-",[410,411,412],"em",{},"pause"," sejenak ketika pemain berpindah (alt-tab) asik melakukan browsing pada laman window tab browser lain. Ini adalah trik luar biasa menghemat penarikan aliran beban Baterai laptop\u002FRAM HP, serta meringankan panas performa CPU!",[55,415,417,418,95],{"id":416},"_2-sapu-bersih-pigmen-layar-keseluruhan-clearrect","2. Sapu Bersih Pigmen Layar Keseluruhan (",[60,419,94],{},[21,421,422,423,101],{},"Canvas itu hakikat dasarnya persis bak papan lukis selembar coretan kertas putih yang dituangi cat berwarna secara permanen (Destructive Drawing).\nOleh karenanya bilamana Anda iseng menyuntik posisi koordinat angka X\u002FY agar gambarnya bergeser letak kedepan secara konstan, benda tersebut malahan pasti akan meninggalkan jejak \"ekor\" garis warna warna kotor berkepanjangan menyeret bak kuas kuas ngebut terhulus paksa mencoreng kertasnya. Karena itu hukum kanvas; \"layar lama harus dihancurkan sebelum melahirkan wujud masa depan!\" menggoreskan sintak metode ",[60,424,94],{},[103,426,428],{"className":105,"code":427,"language":107,"meta":15,"style":15},"\u002F\u002F Menghancurkan jejak keseluruhan pigmen warna layar dari kordinat titik asalnya (0,0) sebanyak luas lebar dan total tingginya \nctx.clearRect(0, 0, canvas.width, canvas.height); \n",[60,429,430,435],{"__ignoreMap":15},[111,431,432],{"class":113,"line":114},[111,433,434],{},"\u002F\u002F Menghancurkan jejak keseluruhan pigmen warna layar dari kordinat titik asalnya (0,0) sebanyak luas lebar dan total tingginya \n",[111,436,437],{"class":113,"line":136},[111,438,439],{},"ctx.clearRect(0, 0, canvas.width, canvas.height);\n",[55,441,443],{"id":442},"_3-merakit-game-animasi-pertama-bola-pemantul-tembok","3. Merakit Game Animasi Pertama: \"Bola Pemantul Tembok\"",[21,445,446],{},"Mari kita gabungkan seluruh konsep ilmu di semua part seri dasar yang lalu untuk menciptakan Animasi Loop abadi! Kali ini ditambahkan bumbu resep deteksi benturan kiri kanan pinggiran layar dari kanvasnya.",[103,448,450],{"className":105,"code":449,"language":107,"meta":15,"style":15},"const canvas = document.getElementById('myGameCanvas');\nconst ctx = canvas.getContext('2d');\n\n\u002F\u002F 1. Deklarasi Sifat\u002FKarakteristik Fisik Objek \nlet ball = {\n  x: 50,          \u002F\u002F Titik pusat koordinat X\n  y: 150,         \u002F\u002F Titik pusat koordinat Y  \n  radius: 20,     \u002F\u002F Lembaran jari-jari lingkaran (Radius Bulat)\n  speedX: 5       \u002F\u002F Daya lari pacu (Velocity): Menjumlah perpindahan pixel memanjang +5 pixel untuk tiap 1 Frame siklus update loop berjalan!\n};\n\n\u002F\u002F 2. Fungsi Engine Jantung Loop Game Utama Sang Eksekutor\nfunction gameLoop() {\n  \n  \u002F\u002F Fase A: PENGHAPUSAN MASAL - Reset Kebersihan Kanvas Papan Gambar\n  ctx.clearRect(0, 0, canvas.width, canvas.height);\n  \n  \u002F\u002F Fase B: EVALUASI LOGIC GERAK (Perbarui pergerakan)\n  ball.x += ball.speedX;  \u002F\u002F Dorong titik (x) laju bola ditambah beban akselerasi (speedX+5px) terus setiap putarannya\n  \n  \u002F\u002F Deteksi Pantulan Fisika Sederhana: \n  \u002F\u002F APABILA ujung kulit terluar kanan lingakaran (titik Pusatx + jarak radius bola) menembus lewat ukuran batas 'lebar canvas', \n  \u002F\u002F ATAU ujung terluar cangkang sisi posisi bola kiri (x - beban radius) membentur tembok sumbu mula layar pangkal nol (0).\n  if (ball.x + ball.radius > canvas.width || ball.x - ball.radius \u003C 0) {\n    ball.speedX = -ball.speedX; \u002F\u002F Arahkan nilai pantulnya jadi nilai yang berkebalikang(-) berputar hadap belakang! (Contoh awal jalan positif 5 obah mundur jadi minus -5) memantul berlawanan!.\n  }\n  \n  \u002F\u002F Fase C: MENGGAMBAR (Printing Ulang objek tersebut)\n  ctx.beginPath();\n  ctx.arc(ball.x, ball.y, ball.radius, 0, 2 * Math.PI);\n  ctx.fillStyle = 'red';\n  ctx.fill();\n  \n  \u002F\u002F Fase D: Panggil kembali perintah memaksa Engine mengukir di frame pengulangan animasi secara rekap rekrusif berikutnya (sebelum refresh cat ulang repaint selanjutnya layarnya si monitor meledak)  \n  requestAnimationFrame(gameLoop);\n}\n\n\u002F\u002F 3. Pemicu Petir Kehidupan Pertama agar Game Loop Jaga Menyala Sepanjang Masa\ngameLoop();\n",[60,451,452,457,461,465,470,474,479,484,489,494,498,502,507,512,516,521,525,529,534,539,543,548,553,558,562,567,571,575,580,584,588,592,596,600,605,610,614,619,625],{"__ignoreMap":15},[111,453,454],{"class":113,"line":114},[111,455,456],{},"const canvas = document.getElementById('myGameCanvas');\n",[111,458,459],{"class":113,"line":136},[111,460,139],{},[111,462,463],{"class":113,"line":142},[111,464,146],{"emptyLinePlaceholder":145},[111,466,467],{"class":113,"line":149},[111,468,469],{},"\u002F\u002F 1. Deklarasi Sifat\u002FKarakteristik Fisik Objek \n",[111,471,472],{"class":113,"line":155},[111,473,158],{},[111,475,476],{"class":113,"line":161},[111,477,478],{},"  x: 50,          \u002F\u002F Titik pusat koordinat X\n",[111,480,481],{"class":113,"line":167},[111,482,483],{},"  y: 150,         \u002F\u002F Titik pusat koordinat Y  \n",[111,485,486],{"class":113,"line":173},[111,487,488],{},"  radius: 20,     \u002F\u002F Lembaran jari-jari lingkaran (Radius Bulat)\n",[111,490,491],{"class":113,"line":179},[111,492,493],{},"  speedX: 5       \u002F\u002F Daya lari pacu (Velocity): Menjumlah perpindahan pixel memanjang +5 pixel untuk tiap 1 Frame siklus update loop berjalan!\n",[111,495,496],{"class":113,"line":185},[111,497,188],{},[111,499,500],{"class":113,"line":191},[111,501,146],{"emptyLinePlaceholder":145},[111,503,504],{"class":113,"line":196},[111,505,506],{},"\u002F\u002F 2. Fungsi Engine Jantung Loop Game Utama Sang Eksekutor\n",[111,508,509],{"class":113,"line":202},[111,510,511],{},"function gameLoop() {\n",[111,513,514],{"class":113,"line":208},[111,515,223],{},[111,517,518],{"class":113,"line":214},[111,519,520],{},"  \u002F\u002F Fase A: PENGHAPUSAN MASAL - Reset Kebersihan Kanvas Papan Gambar\n",[111,522,523],{"class":113,"line":220},[111,524,217],{},[111,526,527],{"class":113,"line":226},[111,528,223],{},[111,530,531],{"class":113,"line":232},[111,532,533],{},"  \u002F\u002F Fase B: EVALUASI LOGIC GERAK (Perbarui pergerakan)\n",[111,535,536],{"class":113,"line":238},[111,537,538],{},"  ball.x += ball.speedX;  \u002F\u002F Dorong titik (x) laju bola ditambah beban akselerasi (speedX+5px) terus setiap putarannya\n",[111,540,541],{"class":113,"line":243},[111,542,223],{},[111,544,545],{"class":113,"line":249},[111,546,547],{},"  \u002F\u002F Deteksi Pantulan Fisika Sederhana: \n",[111,549,550],{"class":113,"line":255},[111,551,552],{},"  \u002F\u002F APABILA ujung kulit terluar kanan lingakaran (titik Pusatx + jarak radius bola) menembus lewat ukuran batas 'lebar canvas', \n",[111,554,555],{"class":113,"line":261},[111,556,557],{},"  \u002F\u002F ATAU ujung terluar cangkang sisi posisi bola kiri (x - beban radius) membentur tembok sumbu mula layar pangkal nol (0).\n",[111,559,560],{"class":113,"line":267},[111,561,252],{},[111,563,564],{"class":113,"line":272},[111,565,566],{},"    ball.speedX = -ball.speedX; \u002F\u002F Arahkan nilai pantulnya jadi nilai yang berkebalikang(-) berputar hadap belakang! (Contoh awal jalan positif 5 obah mundur jadi minus -5) memantul berlawanan!.\n",[111,568,569],{"class":113,"line":278},[111,570,264],{},[111,572,573],{"class":113,"line":284},[111,574,223],{},[111,576,577],{"class":113,"line":290},[111,578,579],{},"  \u002F\u002F Fase C: MENGGAMBAR (Printing Ulang objek tersebut)\n",[111,581,582],{"class":113,"line":296},[111,583,281],{},[111,585,586],{"class":113,"line":302},[111,587,287],{},[111,589,590],{"class":113,"line":307},[111,591,293],{},[111,593,594],{"class":113,"line":313},[111,595,299],{},[111,597,598],{"class":113,"line":319},[111,599,223],{},[111,601,602],{"class":113,"line":325},[111,603,604],{},"  \u002F\u002F Fase D: Panggil kembali perintah memaksa Engine mengukir di frame pengulangan animasi secara rekap rekrusif berikutnya (sebelum refresh cat ulang repaint selanjutnya layarnya si monitor meledak)  \n",[111,606,607],{"class":113,"line":330},[111,608,609],{},"  requestAnimationFrame(gameLoop);\n",[111,611,612],{"class":113,"line":336},[111,613,322],{},[111,615,617],{"class":113,"line":616},37,[111,618,146],{"emptyLinePlaceholder":145},[111,620,622],{"class":113,"line":621},38,[111,623,624],{},"\u002F\u002F 3. Pemicu Petir Kehidupan Pertama agar Game Loop Jaga Menyala Sepanjang Masa\n",[111,626,628],{"class":113,"line":627},39,[111,629,630],{},"gameLoop();\n",[21,632,633,634,637,638,641],{},"Selesai sudah teorinya! Baris pemanggilan ",[60,635,636],{},"requestAnimationFrame(gameLoop)"," pada pengujung blok loop kode fungsi lah yang melahirkan daur siklus pengulangan tak berujung batas mutlak (Infinite Loop). Sekali Anda mantap mengerti perihal logikal perulangan fungsi engine Loop ini, Maka dengan ini secara ",[410,639,640],{},"sah"," selamat, Anda sudah resmi dilantik menjadi sang arsitek Game Developer sejati!",[643,644,645],"style",{},"html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"title":15,"searchDepth":136,"depth":136,"links":647},[],"md",{"title_en":5,"title_id":352,"description_en":650,"description_id":651,"date":652,"readingTime":653},"Learn the heart of game development: creating a smooth game loop using requestAnimationFrame, clearRect, and updating object positions.","Pelajari jantung dari pembuatan game: membuat game loop yang mulus menggunakan requestAnimationFrame, clearRect, dan update posisi objek.","2026-03-25","6 min read","\u002Fblog\u002Fcanvas-game-loop",{"title":5,"description":15},"blog\u002Fcanvas-game-loop","UVYvyXAIGX2HLeZrNBkxDlAmOKKAwJyCwkHSdWb-pL4",1783751390679]