JS写小游戏(一):游戏框架
前言
前一阵发现一个不错的网站,都是一些用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写小游戏(一):游戏框架的更多相关文章
- 用JS写了一个打字游戏,反正我是通不了关
今天想写个简单的游戏, 打字游戏好像都没写过, 那么就写打字游戏吧, gamePad包含了关卡的信息, 可以用来调整给个关卡字符下落的速度: getRandom函数会返回一个字符对象, 这个对象包含了 ...
- 用原生js写小游戏--Flappy Bird
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...
- 这个程序员有点牛,现场直接用JS写了个飞机游戏,半小时吸粉三千
程序员昨晚在b站直播的时用JavaScript代码写了一个飞机大战游戏,半小时不到粉丝关注就上千了. 今日就拿出来跟大家分享一下,对许多大佬来说做这个特效也不是很难,但是对于刚开始学习前端这方面还是有 ...
- 快速上手小程序的mpvue框架
一.什么是mpvue框架? mpvue 是一个使用 Vue.js 开发小程序的前端框架.框架基于 Vue.js 核心(所以建议熟练掌握vue再使用mpvue框架,否则还是建议去使用原生框架去写小程序) ...
- 分享:计算机图形学期末作业!!利用WebGL的第三方库three.js写一个简单的网页版“我的世界小游戏”
这几天一直在忙着期末考试,所以一直没有更新我的博客,今天刚把我的期末作业完成了,心情澎湃,所以晚上不管怎么样,我也要写一篇博客纪念一下我上课都没有听,还是通过强大的度娘完成了我的作业的经历.(当然作业 ...
- pixi.js 微信小游戏 入手
pixi是什么?一款h5游戏引擎 优点:简单简洁性能第一 缺点:大多数用的国产三大引擎,pixi资料少,工具少, 为什么学,装逼 用pixi开发小游戏行吗? 行.但要简单处理下 下载官网上的 weap ...
- 原生JS实战:写了个斗牛游戏,分享给大家一起玩!
本文是苏福的原创文章,转载请注明出处:苏福CNblog:http://www.cnblogs.com/susufufu/p/5869953.html 该程序是本人的个人作品,写的不好,未经本人允许,请 ...
- 排名前10的H5、Js 3D游戏引擎和框架
由于很多人都在用JavaScript.HTML5和WebGL技术创建基于浏览器的3D游戏,所有JavaScript 3D游戏引擎是一个人们主题.基于浏览器的游戏最棒的地方是平台独立,它们能在iOS.A ...
- 原生js写的贪吃蛇网页版游戏特效
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"> <bo ...
随机推荐
- CouchDB简介
类型:开源数据库,Apache项目 存储格式:JSON 查询语言:JavaScript API :MapReduce.HTTP 特点 MVCC(Multiversion concurrency con ...
- MySQL学习笔记之视图
视图是对磁盘上保存的表数据的抽象,即抽取一个表或多个表的部分行或列的数据,展示给使用者. 首先列举下MySQL中最简单的对视图操作的语法: 1.创建视图: create view 视图名 as sel ...
- centos7搭建自己的yum源
http://www.wenbin.cf/post/37/ 1. 安装nginx,createrepo yum install nginx -y yum install createrepo -y ...
- RMAN-03002, RMAN-06059, ORA-19625 and ORA-27037 When Running RMAN Backup of Archivelogs
RMAN备份数据库时,出现下面错误错误信息: Starting backup at 25-MAY-15 current log archived allocated channel: ORA_DISK ...
- Linux iptables配置错误导致ORA-12535 & ORA-12170
实验环境: 操作系统 : Red Hat Enterprise Linux Server release 5.7 (Tikanga) 数据库版本: Oracle Databa ...
- hive 内部表和外部表的区别和理解
1. 内部表 create table test (name string , age string) location '/input/table_data'; 注:hive默认创建的是内部表 此时 ...
- mysql的DATE_FORMAT用法
DATE_FORMAT(date,format) date 参数是合法的日期.format 规定日期/时间的输出格式. mysql的DATE_FORMAT用法 %a 缩写星期名 %b 缩写月名 %c ...
- 对 Visual Studio 中的Resharper禁用对某种文件的检测
原因:在Visual Studio中安装Reshaper后,就会对各种文件进行代码检测,但是因为Reshaper更新的速度不是很及时,所以有时会对Visual Studio中某些新功能误断,导致Cod ...
- 利用epoll写一个"迷你"的网络事件库
epoll是linux下高性能的IO复用技术,是Linux下多路复用IO接口select/poll的增强版本,它能显著提高程序在大量并发连接中只有少量活跃的情况下的系统CPU利用率.另一点原因就是获取 ...
- strus2验证框架
为什么要用验证框架? 当验证规划比较复杂时,Action类的代码江边的非常繁琐,假如我们要对电话号码进行验证,是非常麻烦的. 验证框架的优点 Struts2中内置了一个验证框架,将常用的验证规则进行了 ...