# Java游戏引擎竟然可以如此简单

### 玩家

JavaScript

function Player(x, y, direction) {
this.x = x;
this.y = y;
this.direction = direction;
}

function Player(x, y, direction) {
this.x = x;
this.y = y;
this.direction = direction;
}

### 地图

JavaScript

function Map(size) {
this.size = size;
this.wallGrid = new Uint8Array(size * size);
}

function Map(size) {
this.size = size;
this.wallGrid = new Uint8Array(size * size);
}

### 投射一束光线

#### 1. 找到每条光线的角度

JavaScript

var angle = this.fov * (column / this.resolution - 0.5);
var ray = map.cast(player, player.direction + angle, this.range);

var angle = this.fov * (column / this.resolution - 0.5);
var ray = map.cast(player, player.direction + angle, this.range);

#### 2. 通过网格跟踪每条光线

JavaScript

function ray(origin) {
var stepX = step(sin, cos, origin.x, origin.y);
var stepY = step(cos, sin, origin.y, origin.x, true);
var nextStep = stepX.length2 < stepY.length2
? inspect(stepX, 1, 0, origin.distance, stepX.y)
: inspect(stepY, 0, 1, origin.distance, stepY.x);

if (nextStep.distance > range) return [origin];
return [origin].concat(ray(nextStep));
}

function ray(origin) {
var stepX = step(sin, cos, origin.x, origin.y);
var stepY = step(cos, sin, origin.y, origin.x, true);
var nextStep = stepX.length2 < stepY.length2
? inspect(stepX, 1, 0, origin.distance, stepX.y)
: inspect(stepY, 0, 1, origin.distance, stepY.x);

if (nextStep.distance > range) return [origin];
return [origin].concat(ray(nextStep));
}

JavaScript

var dx = run > 0 ? Math.floor(x + 1) - x : Math.ceil(x - 1) - x;
var dy = dx * (rise / run);

var dx = run > 0 ? Math.floor(x + 1) - x : Math.ceil(x - 1) - x;
var dy = dx * (rise / run);

#### 3. 绘制一列

JavaScript

var z = distance * Math.cos(angle);
var wallHeight = this.height * height / z;

var z = distance * Math.cos(angle);
var wallHeight = this.height * height / z;

### 渲染出来

JavaScript

Camera.prototype.render = function(player, map) {
this.drawSky(player.direction, map.skybox, map.light);
this.drawColumns(player, map);
this.drawWeapon(player.weapon, player.paces);
};

Camera.prototype.render = function(player, map) {
this.drawSky(player.direction, map.skybox, map.light);
this.drawColumns(player, map);
this.drawWeapon(player.weapon, player.paces);
};

• 分辨率决定了每帧要画多少列，即要投射多少条光线。
• 视野决定了我们能看的宽度，即光线的角度。
• 射程决定了我们能看多远，即光线长度的最大值

### 组合起来

JavaScript

oop.start(function frame(seconds) {
map.update(seconds);
player.update(controls.states, map, seconds);
camera.render(player, map);
});

oop.start(function frame(seconds) {
map.update(seconds);
player.update(controls.states, map, seconds);
camera.render(player, map);
});

### 细节

#### 雨滴

JavaScript

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);

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);

#### 照明和闪电

JavaScript

ctx.fillStyle = '#000000';
ctx.globalAlpha = Math.max((step.distance + step.shading) / this.lightRange - map.light, 0);
ctx.fillRect(left, wall.top, width, wall.height);

ctx.fillStyle = '#000000';
ctx.globalAlpha = Math.max((step.distance + step.shading) / this.lightRange - map.light, 0);
ctx.fillRect(left, wall.top, width, wall.height);

#### 碰撞检测

JavaScript

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;
};

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;
};

#### 墙壁贴图

JavaScript

step.offset = offset - Math.floor(offset);
var textureX = Math.floor(texture.width * step.offset);

step.offset = offset - Math.floor(offset);
var textureX = Math.floor(texture.width * step.offset);

• 在恐怖废墟中逛一逛。
• 还有人扩展了社区版。
• ctolsen添加了 WASD 方向键。
• Fredrik Wallgren 实现了 Java 移植。

### 接下来做什么？

• 浸入式体验。样例在求你为它加上全屏、鼠标定位、下雨背景和闪电时同时出现雷响。
• 室内级别。用对称渐变取代天空盒。或者，你觉得自己很屌的话，尝试用瓷片渲染地板和天花板。（可以这么想：所有墙面画出来之后，画面剩下的空隙就是地板和天花板了）
• 照明对象。我们已经有了一个相当健壮的照明模型。为何不将光源放到地图上，通过它们计算墙的照明？光源占了80%大气层。
• 良好的触摸事件。我已经搞定了一些基本的触摸操作，手机和平板的小伙伴们可以尝试一样 demo。但这里还有巨大的提升空间。
• 摄像机特效。比如放大缩小、模糊、醉汉模式等等。有了光线投射器这些都显得特别简单。先从控制台中修改 camera.fov 开始。

06-16 963

09-11 1万+

11-11 7095

04-16 412

01-08 49万+

02-19 35万+

06-22 4万+

05-05 2437

#### C++游戏引擎开发

©️2020 CSDN 皮肤主题: 大白 设计师: CSDN官方博客

1.余额是钱包充值的虚拟货币，按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载，可以购买VIP、C币套餐、付费专栏及课程。