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

  注:这只是众多小游戏合集中的一个,今后会继续添加。

时间: 2024-10-25 08:52:53

JS写小游戏(一):游戏框架的相关文章

第一次写小小小小小游戏, 扫雷

想写扫雷的起因: 前两天上机课做完作业同学没事干, 跟我说:学校的电脑怎么连扫雷都没有啊? 当时我就跟她说 等我写一个给你玩! 然后, 就给自己挖下了这个坑. 现在正好快要期末考了, 这几天在努力复习高数, 好害怕挂啊, 所以扫雷这个坑就一点点填,八成是要等考完试之后再填完. 写这个扫雷跟竞赛完全没有关系, 就当是提高自己代码能力吧, 学习算法之余也搞点好玩的. 本人也不是经常玩扫雷, 不知道自己写的机制和真正的扫雷机制一不一样, 还顺便去百度了一下, 感觉差不多. 游戏呢就是一个简单的控制台,

用原生js写小游戏--Flappy Bird

<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title></title> <style type="text/css"> body { margin: 0; padding: 0; } #game { width: 800px; height: 600px; border: 1px

JS写的一个猜拳游戏

const readline = require("readline-sync"); console.log("欢迎来到猜拳游戏:"); console.log("输入 1 为 剪刀\n输入 2 为石头\n输入 3 为布\n"); //电脑随机 function computer() { let computer = parseInt(Math.random() * 3 + 1); switch (computer) { case 1: cons

用Js写的贪吃蛇游戏

<!doctype html> <html> <head><title>snake</title> <script> function Snake(canvas){ this.canvas = canvas; this.length = 0; this.direction = 'down'; this.body = [], this.head = function(){ return this.length == 0 ? null :

利用node.js写一个后台服务器---express框架的搭建及使用

一.node.js+express框架的服务项目搭建 step1:创建一个项目目录:myApp step2:命令行进入该目录,执行: npm init 在命令执行过程中,会让你设置一个项目的入口文件(entry point),可以随意设置例如:index.js. 执行完毕后,会在项目中创建一个package.json的文件,这个文件就是用来管理项目中今后需要安装的一些模块或依赖. step3:安装express插件: npm install express --save step4:expres

分享:计算机图形学期末作业!!利用WebGL的第三方库three.js写一个简单的网页版“我的世界小游戏”

这几天一直在忙着期末考试,所以一直没有更新我的博客,今天刚把我的期末作业完成了,心情澎湃,所以晚上不管怎么样,我也要写一篇博客纪念一下我上课都没有听,还是通过强大的度娘完成了我的作业的经历.(当然作业不是百度来的,我只是百度了一些示例代码的意思,怎么用!算了,越解释万一越黑呢!哈哈O(∩_∩)O哈哈~) ----------------------------------------------------------------分界线------------------------------

用Netty和Raphael来写塔防online游戏(二) - JS中使用protobuf协议

一. 简单介绍一下protobuf: Protocol Buffers are a language-neutral, platform-neutral, extensible way of serializing structured data for use in communications protocols, data storage, and more, originally designed at Google . 如今,已经有人用JS实现了protobuf协议,就是ProtoBu

使用cocos2d-x v3.1开发小游戏(基本框架)

小游戏的组成 欢迎界面 在游戏资源未全部加载完之前就需要载入,避免进入游戏会有一段黑屏时间. 可以用来展示游戏名称或者开发者logo. 开始菜单界面 一般用于显示游戏名称和关卡选择(或者称游戏难度选择). 可以外加一些设置性功能,如声音开关,帮助入口等等. 如果游戏设置内容较多可以把设置作为一个单独界面,在开始菜单上提供入口即可. 有的小游戏是以弹窗方式的菜单 主游戏界面 游戏的中心部分,比如2048游戏的格子滑动界面,扫雷游戏的扫雷界面,贪吃蛇游戏的蛇移动的界面,等等. 小游戏拥有这一个界面也

原生js写的贪吃蛇网页版游戏

<html> <head> <meta http-equiv="Content-Type" content="text/html; charset=gb2312" /> <title>原生js写的贪吃蛇网页版游戏</title> </head> <body><div><A href="http://www.999jiujiu.com/">h