组合起来
使用控制对象 Controls 监听方向键(和触摸事件)。使用游戏循环对象 GameLoop 调用 requestAnimationFrame 请求渲染帧。这里的 gameloop 只有三行
oop.start( function frame(seconds) {
map.update(seconds);
player.update(controls.states, map, seconds);
camera.render(player, map);
});
|
细节
雨滴
var rainDrops = Math.pow(Math.random(), 3) * s;
var rain = (rainDrops > 0) && this .project(0.1, angle, step.distance);
ctx.fillStyle = '#ffffff' ;
ctx.globalAlpha = 0.15;
while (--rainDrops > 0) ctx.fillRect(left, Math.random() * rain.top, 1, rain.height);
|
这里没有画出墙完全的宽度,而是画了一个像素点的宽度。
照明和闪电
照明其实就是明暗处理。所有的墙都是以完全亮度画出来,然后覆盖一个带有一定不透明度的黑色矩形。不透明度决定于距离与墙的方向(N/S/E/W)。
ctx.fillStyle = '#000000' ;
ctx.globalAlpha = Math.max((step.distance + step.shading) / this .lightRange - map.light, 0);
ctx.fillRect(left, wall.top, width, wall.height);
|
要模拟闪电,map.light 随机达到2然后再快速地淡出。
碰撞检测
要防止玩家穿墙,我们只要用他要到的位置跟地图比较。分开检查 x 和 y 玩家就可以靠着墙滑行。
Player.prototype.walk = function (distance, map) {
var dx = Math.cos( this .direction) * distance;
var dy = Math.sin( this .direction) * distance;
if (map.get( this .x + dx, this .y) <= 0) this .x += dx;
if (map.get( this .x, this .y + dy) <= 0) this .y += dy;
};
|
墙壁贴图
没有贴图(texture)的墙面看起来会比较无趣。但我们怎么把贴图的某个部分对应到特定的列上?这其实很简单:取交叉点坐标的小数部分。
step.offset = offset - Math.floor(offset);
var textureX = Math.floor(texture.width * step.offset);
|
举例来说,一面墙上的交点为(10,8.2),于是取小数部分0.2。这意味着交点离墙左边缘20%远(8),离墙右边缘80%远(9)。所以我们用 0.2 * texture.width 得出贴图的 x 坐标。
试一试
接下来做什么?
因为光线投射器是如此地快速、简单,你可以快速地实现许多想法。你可以做个地牢探索者(Dungeon
Crawler)、第一人称射手、或者侠盗飞车式沙盒。靠!常数级的时间消耗真让我想做一个老式的大型多人在线角色扮演游戏,包含大量的、程序自动生成的
世界。这里有一些带你起步的难题:
- 浸入式体验。样例在求你为它加上全屏、鼠标定位、下雨背景和闪电时同时出现雷响。
- 室内级别。用对称渐变取代天空盒。或者,你觉得自己很屌的话,尝试用瓷片渲染地板和天花板。(可以这么想:所有墙面画出来之后,画面剩下的空隙就是地板和天花板了)
- 照明对象。我们已经有了一个相当健壮的照明模型。为何不将光源放到地图上,通过它们计算墙的照明?光源占了80%大气层。
- 良好的触摸事件。我已经搞定了一些基本的触摸操作,手机和平板的小伙伴们可以尝试一样 demo。但这里还有巨大的提升空间。
- 摄像机特效。比如放大缩小、模糊、醉汉模式等等。有了光线投射器这些都显得特别简单。先从控制台中修改 camera.fov 开始。
同往常一样,如果你造了什么炫爆的东西或者有什么相关的研究要分享,发 email 给我或 tweet 我,我会分享给大家的。
讨论
本来打算写两个钟的文章结果写了三周。没有以下的帮助我不可能写完这篇文章:
原文链接: A first-person engine in 265 lines 翻译: 伯乐在线 - Jaward华仔
译文链接: http://blog.jobbole.com/70956/
|