JS寫小游戲(一):游戲框架


前言

  前一陣發現一個不錯的網站,都是一些用html5+css+js寫的小游戲,於是打算學習一番,寫下這個系列博客主要是為了加深理解,當然也有一些個人感悟,如果英文好可以直接Click Here.

概述

  一般,小游戲都要關注兩個問題:刷新和交互。因為游戲一般是動態的,所以需要不斷刷新。JavaScript是單線程,如果用C語言寫過貪吃蛇之類的小游戲,應該知道,單線程一般是掛起一個時間來達到動態效果。比如C語言的Sleep(),JS的setInterval()等。但是js還有一種更高性能的方法requestAnimationFrame。可以在網上找些資料進行學習,在此不做贅述。另一個就是交互,即用戶需要通過鼠標、鍵盤控制游戲,從編程角度來書就是要添加對應事件的監聽器。

  以下,正式開始。

HTML5

  先創建一個canvas畫布:

 1 <!DOCTYPE html>
 2 <html>
 3 <head>
 4 <meta charset="UTF-8">
 5 <title>Rembound.com Example</title>
 6 <script type="text/javascript" src="script.js"></script>
 7 </head>
 8 <body>
 9 <canvas id="viewport" width="640" height="480"></canvas>
10 </body>
11 </html> 

JS

  添加以下基本代碼,代碼詳情可以看注釋,最好單步調試加深理解:

//窗口加載完成后調用
window.onload = function() {
    // 獲取畫布及context(上下文)
    var canvas = document.getElementById("viewport"); 
    var context = canvas.getContext("2d");
 
    // 記錄時間幀,這個最好通過單步調試來理解
    var lastframe = 0;
    var fpstime = 0;
    var framecount = 0;
    var fps = 0;
 
    // 初始化游戲,添加鼠標的監聽事件
    function init() {
        canvas.addEventListener("mousemove", onMouseMove);
        canvas.addEventListener("mousedown", onMouseDown);
        canvas.addEventListener("mouseup", onMouseUp);
        canvas.addEventListener("mouseout", onMouseOut);
 
        // 進入游戲主循環
        main(0);
    }
 
    // 主循環
    function main(tframe) {
        // 結束時繼續調用main函數
        window.requestAnimationFrame(main);
 
        // 更新游戲
        update(tframe);
        render();
    }
 
    // 更新游戲狀態,計算已經過去了的時間
    function update(tframe) {
        var dt = (tframe - lastframe) / 1000;
        lastframe = tframe;
 
        //更新幀數計數器
        updateFps(dt);
    }
 
    function updateFps(dt) {
        if (fpstime > 0.25) {
            //計算幀數
            fps = Math.round(framecount / fpstime);
 
            //重置時間
            fpstime = 0;
            framecount = 0;
        }
 
        //增加幀時間、幀數
        fpstime += dt;
        framecount++;
    }
 
    // 渲染(更新畫布)
    function render() {
        drawFrame();
    }
 
    // 
    function drawFrame() {
        // 背景、邊界
        context.fillStyle = "#d0d0d0";
        context.fillRect(0, 0, canvas.width, canvas.height);
        context.fillStyle = "#e8eaec";
        context.fillRect(1, 1, canvas.width-2, canvas.height-2);
 
        // 標題頭
        context.fillStyle = "#303030";
        context.fillRect(0, 0, canvas.width, 65);
 
        // 標題
        context.fillStyle = "#ffffff";
        context.font = "24px Verdana";
        context.fillText("HTML5 Canvas Basic Framework - Rembound.com", 10, 30);
 
        // 顯示幀數
        context.fillStyle = "#ffffff";
        context.font = "12px Verdana";
        context.fillText("Fps: " + fps, 13, 50);
    }
 
    //鼠標監聽
    function onMouseMove(e) {}
    function onMouseDown(e) {}
    function onMouseUp(e) {}
    function onMouseOut(e) {}
 
    // 獲取鼠標位置
    function getMousePos(canvas, e) {
        var rect = canvas.getBoundingClientRect();
        return {
            x: Math.round((e.clientX - rect.left)/(rect.right - rect.left)*canvas.width),
            y: Math.round((e.clientY - rect.top)/(rect.bottom - rect.top)*canvas.height)
        };
    }
 
    // 游戲入口
    init();
};

  效果:

  

添加游戲元素

  以上就是一個通用的游戲框架了,雖然它在不斷刷新,但是沒什么直觀感受,以下建立一個簡單游戲來感受一下:

 ......  
    var framecount = 0;
    var fps = 0;
 
    // 游戲平面
    var level = {
        x: 1,
        y: 65,
        width: canvas.width - 2,
        height: canvas.height - 66
    };
    
    // 小方塊
    var square = {
        x: 0,
        y: 0,
        width: 0,
        height: 0,
        xdir: 0,
        ydir: 0,
        speed: 0
    }
    
    // 分數
    var score = 0;

    // 初始化游戲,添加鼠標的監聽事件
    function init() {
....

  在init()函數中添加:

....
        canvas.addEventListener("mouseout", onMouseOut);
         // 初始化方塊
        square.width = 100;
        square.height = 100;
        square.x = level.x + (level.width - square.width) / 2;
        square.y = level.y + (level.height - square.height) / 2;
        square.xdir = 1;
        square.ydir = 1;
        square.speed = 200;
        
        // 初始化分數
        score = 0;
    
        // 進入游戲主循環
        main(0);
....

  在update()函數中更新方塊

.... 
       //更新幀數計數器
        updateFps(dt);

       // 基於時間移動方塊
        square.x += dt * square.speed * square.xdir;
        square.y += dt * square.speed * square.ydir;
        
        // 處理碰撞
        if (square.x <= level.x) {
            // Left edge
            square.xdir = 1;
            square.x = level.x;
        } else if (square.x + square.width >= level.x + level.width) {
            // Right edge
            square.xdir = -1;
            square.x = level.x + level.width - square.width;
        }

        if (square.y <= level.y) {
            // Top edge
            square.ydir = 1;
            square.y = level.y;
        } else if (square.y + square.height >= level.y + level.height) {
            // Bottom edge
            square.ydir = -1;
            square.y = level.y + level.height - square.height;
        }    
...

  render()函數中還要渲染方塊

....
        // 繪制方塊
        context.fillStyle = "#ff8080";
        context.fillRect(square.x, square.y, square.width, square.height);
        
        // 繪制內部
        context.fillStyle = "#ffffff";
        context.font = "38px Verdana";
        var textdim = context.measureText(score);
        context.fillText(score, square.x+(square.width-textdim.width)/2, square.y+65);
...

  添加鼠標事件

    function onMouseDown(e) {
        // 獲取鼠標位置
        var pos = getMousePos(canvas, e);
        
        // 檢查是否碰到了方塊
        if (pos.x >= square.x && pos.x < square.x + square.width &&
            pos.y >= square.y && pos.y < square.y + square.height) {
            
            // 增加分數
            score += 1;
            
            // 增加速度
            square.speed *= 1.1;
            
            // 隨機給一個新的位置
            square.x = Math.floor(Math.random()*(level.x+level.width-square.width));
            square.y = Math.floor(Math.random()*(level.y+level.height-square.height));
            
            // 隨機方向
            square.xdir = Math.floor(Math.random() * 2) * 2 - 1;
            square.ydir = Math.floor(Math.random() * 2) * 2 - 1;
        }
    }

效果

  

 

  完整源代碼:Click Here

  注:這只是眾多小游戲合集中的一個,今后會繼續添加。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM