Stick champ oyunu
İşte şampiyonumuzun taşların üzerinden atlamak için bir sopa kullandığı küçük oyunumuzun kodu (ayrıntılı açıklama aşağıda):
| <html> |
| <body> |
| <canvas id="myCanvas" width="600" height="500" style='position:absolute; left:0;'></canvas> |
| <script> |
| let canvas = document.getElementById("myCanvas"); |
| let context = canvas.getContext("2d"); |
| context.font = 'bold 30px sans-serif'; |
| context.lineWidth = 4; |
| let image = new Image(); |
| image.src = "sprite.png"; |
| const maxStones = 6, size = 40; |
| let angle = -Math.PI / 2; |
| let x, y, frame, currentStone, mode, run, offset, stickLength, stones; |
| |
| function reset() { |
| currentStone = 0; |
| x = 100; |
| y = 360; |
| frame = 0; |
| stones = []; |
| stickLength = 0; |
| offset = 0; |
| run = 0; |
| for (let i = 0; i < maxStones; i++) { |
| stones[i] = { |
| x: i * 300 + Math.floor(Math.random() * 80), |
| width: 50 + Math.floor(Math.random() * 50) |
| }; |
| } |
| stones[0].x = 80; |
| mode = 'wait'; |
| } |
| |
| function animate() { |
| context.clearRect(0, 0, canvas.width, canvas.height); |
| context.fillText('Kalan mesafe: ' + (maxStones - currentStone - 1), 250, 100); |
| stones.forEach((stone)=>{ |
| context.fillRect(stone.x - offset, 398, stone.width, 600); |
| } |
| ); |
| |
| context.drawImage(image, Math.floor(frame) * size, 0, size, size, x + size / 2, y, size, size); |
| switch (mode) { |
| case 'pointerdown': |
| stickLength++; |
| break; |
| case 'stickFall': |
| angle = angle + Math.PI / 64; |
| if (angle >= 0) |
| mode = 'run'; |
| break; |
| case 'run': |
| offset++; |
| run++; |
| frame = frame + .5; |
| if (frame == 20) |
| frame = 0; |
| if (stickLength == run) { |
| mode = 'wait'; |
| angle = -Math.PI / 2; |
| stickLength = 0; |
| run = 0; |
| let gameOver = true; |
| stones.forEach((stone,index)=>{ |
| if (offset + x + size > stone.x && offset + x < stone.x + stone.width - size) { |
| gameOver = false; |
| currentStone = Math.max(currentStone, index); |
| if (currentStone == maxStones - 1) { |
| mode = 'gameOver'; |
| frame = 21; |
| } |
| } |
| } |
| ); |
| if (gameOver) { |
| mode = 'gameOver'; |
| frame = 20; |
| } |
| } |
| break; |
| case 'gameOver': |
| if (currentStone < maxStones - 1) { |
| y++; |
| context.fillText('Oyun bitti. Yeniden başlatmak için tıklayın', 20, 60); |
| } else |
| context.fillText('Kazandın! Yeniden başlatmak için tıklayın', 20, 60); |
| } |
| let x2 = x + (stickLength - run) * Math.cos(angle); |
| let y2 = y + (stickLength - run) * Math.sin(angle); |
| context.beginPath(); |
| context.moveTo(x + size - run, y + size); |
| context.lineTo(x2 + size, y2 + size); |
| context.stroke(); |
| window.requestAnimationFrame(animate); |
| } |
| |
| window.onpointerdown = function() { |
| switch (mode) { |
| case 'wait': |
| mode = 'pointerdown'; |
| break; |
| case 'gameOver': |
| mode = 'wait'; |
| reset(); |
| } |
| }; |
| |
| window.onpointerup = function() { |
| if (mode == 'pointerdown') |
| mode = 'stickFall'; |
| }; |
| reset(); |
| animate(); |
| </script> |
| </body> |
| </html> |
Satır [1-8] HTML5 Canvas ve 2d bağlamını ayarlar
[9-10] sprite sayfasını tutan görünmez resim (20 kare koşu sekansı, 1 düşüş, 1 kutlama):

[11-13] Oyun değişkenlerini ve sabitlerini tanımla:
[11] maksimum taş sayısı (=katedilecek mesafe), sprite boyutu (40x40 piksel)
[12] çubuğun başlangıç açısı - düz yukarı gider
[13] x - şampiyonun x koordinatı
y - çubuğun tepesinin y koordinatı
frame - mevcut animasyon karesi
currentStone - kaç taşa ulaşıldı
mode - oyun modu (bekle/tıklandı/çubukDüşüşü/oyunBitti)
run - mevcut koşunun uzunluğu
offset - ekranın yatay kaydırma ofseti
stickLength - çubuğun mevcut uzantısı
stones - taş nesneleri dizisi
[15-32] tüm değişkenleri başlangıç değerlerine sıfırla
[24-29] taş pozisyonlarını ve genişliklerini rastgele belirle
[34-96] ana oyun döngüsü:
[35] kareyi temizle
[36] kalan mesafeyi ekranda göster
[37-40] taşları çiz (ekrana sığmasalar bile - işleri basit tutmak için)
[42] sprite'ın mevcut animasyon karesini çiz
drawImage'ın nasıl çalıştığı hakkında
ayrıntılara ihtiyacınız varsa, buraya tıklayın
[44-46] işaretçiye (fare/dokunmatik) basılırsa, çubuk uzunluğunu artır
[47-51] çubuk düşüyorsa, açıyı artır.
[49-50] tamamen aşağı düştüyse, oyun modunu "run" (koş) olarak değiştir
[52-80] eğer 'run' modundaysak:
[53-54] ofseti ve koşu uzunluğunu artır
[55] sprite karesi her 2 animasyon karesinde bir değişir
[56-57] spritesheet'teki animasyon sekansının sonuna ulaşırsak, başa dön
[58-62] koşu uzunluğu çubuğun ucuna eşitse; çubuk uzunluğunu, açıyı, koşuyu sıfırla ve 'wait' (bekle) moduna geç
[63-74] taşın üzerine inip inmediğimizi kontrol et:
[63] boş bir alana indiğimizi varsay
[64-65] şampiyon koordinatlarını her taşla karşılaştır
[66] şampiyon bir taşa indiyse, [63]'teki kötümser varsayımı düzelt
[67] currentStone'u (mevcut taşı) hesapla
[68-71] son taşa ulaşıldıysa, kazandın!
[75-78] şampiyon boş bir alana indiyse, modu gameOver (oyun bitti) yap ve düşme pozunu göster
[81-87] 'gameOver' modunda:
[82-84] kaybettiysen, düşersin
[85-86] kazandıysan, kazandın.
[88-89] çubuğun ucunun koordinatlarını hesapla
[90-93] çubuğu çiz
[94] bir sonraki animasyon karesini tetikle
[97-107] ekrana tıklanırsa/dokunulursa:
[98-101] bekliyorsak, 'pointerdown' moduna geçeriz
[102-105] 'gameOver' modundaysak, oyun yeniden başlatılır
[108-111] işaretçi bırakılırsa ve 'pointerdown' modundaysak, 'stickFall' moduna geçeriz
[112] oyunu başlat
[113] animasyonu başlat
Oyunun tadını çıkarın!