前言

  前一阵发现一个不错的网站,都是一些用html5+css+js写的小游戏,于是打算学习一番,写下这个系列博客主要是为了加深理解,当然也有一些个人感悟,如果英文好可以直接Click Here.

概述

  一般,小游戏都要关注两个问题:刷新和交互。因为游戏一般是动态的,所以需要不断刷新。JavaScript是单线程,如果用C语言写过贪吃蛇之类的小游戏,应该知道,单线程一般是挂起一个时间来达到动态效果。比如C语言的Sleep(),JS的setInterval()等。但是js还有一种更高性能的方法requestAnimationFrame。可以在网上找些资料进行学习,在此不做赘述。另一个就是交互,即用户需要通过鼠标、键盘控制游戏,从编程角度来书就是要添加对应事件的监听器。

  以下,正式开始。

HTML5

  先创建一个canvas画布:

 <!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Rembound.com Example</title>
<script type="text/javascript" src="script.js"></script>
</head>
<body>
<canvas id="viewport" width="640" height="480"></canvas>
</body>
</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

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

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

  1. 用JS写了一个打字游戏,反正我是通不了关

    今天想写个简单的游戏, 打字游戏好像都没写过, 那么就写打字游戏吧, gamePad包含了关卡的信息, 可以用来调整给个关卡字符下落的速度: getRandom函数会返回一个字符对象, 这个对象包含了 ...

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

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  3. 这个程序员有点牛,现场直接用JS写了个飞机游戏,半小时吸粉三千

    程序员昨晚在b站直播的时用JavaScript代码写了一个飞机大战游戏,半小时不到粉丝关注就上千了. 今日就拿出来跟大家分享一下,对许多大佬来说做这个特效也不是很难,但是对于刚开始学习前端这方面还是有 ...

  4. 快速上手小程序的mpvue框架

    一.什么是mpvue框架? mpvue 是一个使用 Vue.js 开发小程序的前端框架.框架基于 Vue.js 核心(所以建议熟练掌握vue再使用mpvue框架,否则还是建议去使用原生框架去写小程序) ...

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

    这几天一直在忙着期末考试,所以一直没有更新我的博客,今天刚把我的期末作业完成了,心情澎湃,所以晚上不管怎么样,我也要写一篇博客纪念一下我上课都没有听,还是通过强大的度娘完成了我的作业的经历.(当然作业 ...

  6. pixi.js 微信小游戏 入手

    pixi是什么?一款h5游戏引擎 优点:简单简洁性能第一 缺点:大多数用的国产三大引擎,pixi资料少,工具少, 为什么学,装逼 用pixi开发小游戏行吗? 行.但要简单处理下 下载官网上的 weap ...

  7. 原生JS实战:写了个斗牛游戏,分享给大家一起玩!

    本文是苏福的原创文章,转载请注明出处:苏福CNblog:http://www.cnblogs.com/susufufu/p/5869953.html 该程序是本人的个人作品,写的不好,未经本人允许,请 ...

  8. 排名前10的H5、Js 3D游戏引擎和框架

    由于很多人都在用JavaScript.HTML5和WebGL技术创建基于浏览器的3D游戏,所有JavaScript 3D游戏引擎是一个人们主题.基于浏览器的游戏最棒的地方是平台独立,它们能在iOS.A ...

  9. 原生js写的贪吃蛇网页版游戏特效

    <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> <bo ...

随机推荐

  1. php面向对象编程 设计模式

    面向对象编程的基本原则: 单一职责:一个类,只需要做好一件事 开放封闭:一个类,应该是可扩展的,而不是可修改的 依赖倒置:一个类,不应该强依赖另一个类.每个类对应另外一个类都是可替换的 配置化:尽可能 ...

  2. 125个工具与技术(PMBOK2008)

    名称 定义 适用场景 适用过程 专家判断 对某方面擅长的人就是专家,找专家协助就是专家判断,专家可能是顾问.干系人.PMO.团队成员 制定项目章程.制定项目管理计划.指导与管理项目执行.监控项目工作. ...

  3. String.Empty、null、“” 区别

    概念准备: 1.引用类型是将对象是实际数据保存在堆中, 将对象在堆中的地址保存在栈中. 2.值类型直接将实际数据存放在堆中,不会将对象在堆中的地址保存在栈中. 一.String.Empty和" ...

  4. Write on ……… failed: 112(failed to retrieve text for this error. Reason: 15105)

    早上检查数据库的备份邮件时,发现一台Microsoft SQL Server 2008 R2 (SP2)数据库的Maintenance Report有错误 在SSMS里面执行Exec YourSQLD ...

  5. SQL SERVER中的OLEDB等待事件

    OLEDB等待事件介绍 OLEDB等待类型是SQL SERVER 数据库中最常见的几种等待类型之一.它意味着某个会话(SPID)通过SQL Server Native Client OLEDB Pro ...

  6. 【hive】——Hive sql语法详解

    Hive 是基于Hadoop 构建的一套数据仓库分析系统,它提供了丰富的SQL查询方式来分析存储在Hadoop 分布式文件系统中的数据,可以将结构 化的数据文件映射为一张数据库表,并提供完整的SQL查 ...

  7. mapreduce导出MSSQL的数据到HDFS

    今天想通过一些数据,来测试一下我的<基于信息熵的无字典分词算法>这篇文章的正确性.就写了一下MapReduce程序从MSSQL SERVER2008数据库里取数据分析.程序发布到hadoo ...

  8. Spark调度管理(读书笔记)

    Spark调度管理(读书笔记) 转载请注明出处:http://www.cnblogs.com/BYRans/ Spark调度管理 本文主要介绍在单个任务内Spark的调度管理,Spark调度相关概念如 ...

  9. [Java入门笔记] Java语言基础(二):常量、变量与数据类型

    常量与变量 什么是常量和变量 常量与变量都是程序在运行时用来存储数据一块内存空间 常量: 常量的值在程序运行时不能被改变,Java中声明常量必须使用final关键字.常量还可以分为两种意思: 第1种意 ...

  10. shell统计指定范围内的所有质数以及它们的和

    #!bin/bash a= $) ;do n= $x);do ];then n=$[$n+] fi done ];then { echo -n -e "$x\t" sum=$[$s ...