小记
本次创作是基于Voxel.js框架实现,但是该框架已发布8年,后期的维护工作并不完善,官网并无文档,并且官网介绍的voxel-hello-world启动文件包已在npm库中失效。作者由于对该框架很感兴趣就制作了该文档。以各个引入文件中的readme文件为主,源代码为辅总结。如有理解不当之处,欢迎批评指教。
Voxel.js官网地址:Voxel.js
文档作者csdn:lmmmmmnb
文档作者:YiDaoDo
简单的开始
1,创建你的web项目:只需要一个js文件(以下称为index.js)与html文件(以下称为index.html)
2,在你创建好的项目中执行
npm install voxel-engine --save-dev
npm install voxel-player --save -dev
npm install voxel-highlight --save -dev
下载好基础的三个包。(当然还有很多别的功能包,后期作者会同步上)
3,
npm install browserify -g
安装browserify为的是可以利用Node.js实现JS模块化加载
4,
var createGame =require('voxel-engine');//引入包
var Highlight = require('voxel-highlight')//引入包
var game=createGame( //以该函数为基础创造世界
{
generate: function(x,y,z) { //generate里面的函数为初始的地图创建函数
if (y==0){
return x*x+z*z <=55*55? 1:0
}else if(y==8&&x==0&&z==0){
return 1
}
},
texturePath:'textures/', //引入纹理包。纹理包里面的图片都可以在voxel-engine包里面找到
materials: ["grass"] //添加初始纹理(都是纹理包里面的)
}
);
var createPlayer=require('voxel-player')(game); //引入包
game.appendTo(document.body); //获得全屏
var substack=createPlayer('skin/shama.png'); //创建你的小人
substack.possess(); //小人获得移动视角
substack.yaw.position.set(3,30,0); //小人初始位置
在index.js中加入上述代码.
5,
browserify index.js -o bundle.js
终端里执行该命令(用browserify加载你的index.js产生bundle.js)
然后在你的index.html引入bundle.js文件。运行你的html页面,这样初始世界就创建好了
以下是对于三个基础包函数解读
voxel-engine
1,generate
创建世界的三维坐标并不是z轴朝上,是y轴朝上。x轴,z轴分别是:左右,前后。
2,texturePath:'textures/'
是引用纹理
3,game.appendTo(document.body)
是获得页面
4,game.controls.target().avatar.position()
获取当前玩家位置
5,
game.setBlock(pos, 0) // off
game.setBlock(pos, 1) // on
game.setBlock(pos, 2) // on, with another material
pos是传的方块[x,y,z]的坐标,后面的数字决定该模块是否存在
6,game.voxels.voxelVector([x,y,z])
获取某个位置的体素坐标,
以下是该函数的源码
Chunker.prototype.voxelVector = function(pos) {
var cubeSize = this.cubeSize
var mask = (1 << this.chunkBits) - 1
var vx = (Math.floor(pos[0] / cubeSize)) & mask
var vy = (Math.floor(pos[1] / cubeSize)) & mask
var vz = (Math.floor(pos[2] / cubeSize)) & mask
return [vx, vy, vz]};
7,
game.voxels.chunkAtPosition([0,3,1])
根据方块的坐标来获取块
8,gameInstance.createBlock([x,y,z], val)
由于在传入的坐标处创建一个全新的块,
val可以是0-9,这些对应于您传递给游戏的材质数组。
(和setBlock差不多但是有一定的区别:这个会检查小人是否阻碍着新方块的创建,如果你不建议,完全可以用setBlock)
9,
gameInstance.getBlock([x,y,z])
用于获取某一位置方块的值
10,
game.raycastVoxels()
获取默认光影投射到的方块的信息(所谓光影就是小人身前的描点),可以在里面传入参数
gameInstance.raycastVoxels(start, position, distance)
来自定义光影投射。
11,
gameInstance.createAdjacent(raycastResults, materialIndex)
在此函数中传入光影投射结果,方块纹理参数。就可以在光影投射到的方块旁边创建新方块。
12,
game.on('tick', function(delta) {})
渲染函数,delta距离上次渲染发生的毫秒数
13,
game.on('mouseup', function(pos) {}), game.on('mousedown', function(pos) {})
鼠标点击事件函数,pos为点击方块的地址(未使用)
14,
game.on('collision', function(item) {})
回调函数,当item项目与小人操作发生碰撞,进行回调
15,
game.voxelRegion.on('change', function(pos) {})
小人发生移动时就会调用的函数
16,
game.chunkRegion.on('change', function(pos) {})
当小人在方块之间移动时会调用的函数
17,
game.on('renderChunk', function(chunk) {})
当方块被绘制时(使用showcunk方法)调用的函数。
18,
game.on('missingChunk', function(chunkPosition) {})
小人到尚未加载的区域时会调用
19,
game.on('dirtyChunkUpdate', function(chunk) {})
当方块被更改时会调用的函数。(例如setBlock)
20,
game.on('setBlock', function(pos, val, old) {})
只要game.setBlock函数被调用,该函数就会被调用。
21,
game.getCollisions(item.mesh.position, item)
返回与item的碰撞对象信息。(REANME记载,但是并未在源码中找到该函数)
22,
game.materials.load(['obsidian', 'dirt'], function(textures) { })
将纹理加入到纹理图集。前提是obsidian,dirt已经存在textures
23,
{
materials: ["#fff", "#000", "#ff0000"],
materialFlatColor: true
}
可以指定十六进制颜色作为材质,只要在创建时,传入以上参数
24,以下内容用来在世界添加自定义的是事务(村民,怪物,自定义方块)
var mesh = new game.THREE.Mesh(
new game.THREE.CubeGeometry(1, 3, 1), // 宽,高,深
game.materials.material
)
创建一个mesh,并将该世界已添加的纹理库赋予使用权。
game.materials.paint(mesh, 'obsidian')
向事物添加纹理库里的纹理。
mesh.position.set(0, 3, -5)
设定事务出现的位置
var item = game.addItem({
mesh: mesh,
size: 1,
velocity: { x: 0, y: 0, z: 0 } // initial velocity
})
将你创建的事物添加的你的世界里
game.removeItem(item)
可使用该方法删除你已添加的方法
25,
setTimeout
setInterval
这两个函数是与电脑时间保持同步,但是当你的世界掉帧或者暂停,这个函数还是会跟着电脑的时间进行发生。
例如:
setInterval(function() {
jump()
}, 2000)
上述代码是让你的小人跟着电脑时间。每两秒跳一次。
game.setInterval(fn, duration[, args])
game.setTimeout(fn, duration[, args])
这两个函数是与游戏世界里的时间保持同步,当你游戏暂停,这个函数的时间也会暂停
var clearInterval = game.setInterval(function() {
jump()
}, 2000)
上述代码是让你的小人跟着游戏时间。每两秒跳一次。
26,
关于voxel交换格式(没看懂,上源码)
{
"voxels": [packed 1D array of voxels],
"dimensions": [2, 2, 2],
"position": [10, 10, 10]
}
var length = 5, width = 5, depth = 5
var start = [10, 10, 10]
var voxels = new Int8Array(length * width * depth)
var idx = 0
for(var z = start[2]; z < depth; ++z)
for(var y = start[1]; y < height; ++y)
for(var x = start[0]; x < length; ++x, ++idx) {
voxels[idx] = getVoxelDataFor(x+start[0], y+start[1], z+start[2])
}
return {voxels: voxels, dimensions: [length, width, height], position: start}
voxel-player
1,var substack=createPlayer('maxogden.png');
给小人添加纹理
2,substack.possess();
给小人添加可移动视角
3,
substack.toggle();
切换小人第一人称和第三人称视角
4,
player.position.set(x, y, z)
给小人设置个初始位置
5,
player.subjectTo(forceVector)
使小人收到力矢量
6,
player.move(x, y, z)
或
player.move(vec)
小人刚开始降落到的位置
7,
player.moveTo(x, y, z)
或
player.move(pos)
和4差不多
8,player.pov(view)
将小人视角固定为第一人称或者第三人称
voxel-highlight
该文件主要是投影到方块时,方块的变化,以及信息获取等。
1,
var Highlight = require('voxel-highlight')
var highlighter = new Highlight(game)
通过这两行代码可以使投影投射到的方块出现高亮边框,并且可以获取到投影到的方块的信息。
也可以用以下代码代替:
var highlight = require('voxel-highlight')
var highlighter = highlight(game)
highlighter.on('highlight', function (voxelPosArray) {
//添加你需要的代码
})
2,
{
frequency: 以毫秒为单位高亮显示的频率,默认值为100
distance: 游戏中应该突出显示的距离,默认值是10
geometry: threejs用于高亮显示的几何体,默认为cubegeometry
material: 用于几何体的材质,默认为线框(wireframe)
wireframeLinewidth: 如果使用默认材质线框,则默认值为3(边框宽度)
wireframeOpacity: 如果使用默认材质线框,则默认值为0.5(边框透明度)
color: 高亮显示立方体颜色,默认值为0x000000
animate: 动画高亮长方体的移动,默认为 false
adjacentActive: 用于切换相邻突出显示的函数,默认值为 { return game.controls.state.alt }
selectActive: 用于切换相邻高亮显示的函数,默认值为 { return game.controls.state.select }
animateFunction: 用于简化位置更改的函数,详细请见该部分文档第三条
}
以上是可以在创建highlight时可以添加的选项
3,
opts.animateFunction = function (position, targetPosition, deltaTime) {
if (!position || !targetPosition || !deltaTime) return;
var rate = 10 // speed in voxels per second
if (Math.abs(targetPosition[0] - position.x) < 0.05
&& Math.abs(targetPosition[1] - position.y) < 0.05
&& Math.abs(targetPosition[2] - position.z) < 0.05) {
position.set(targetPosition[0], targetPosition[1], targetPosition[2])
return; // close enough to snap and be done
}
deltaTime = deltaTime / 1000 // usually around .016 seconds (60 FPS)
position.x += rate * deltaTime * (targetPosition[0] - position.x)
position.y += rate * deltaTime * (targetPosition[1] - position.y)
position.z += rate * deltaTime * (targetPosition[2] - position.z)
}
animateFunction的使用
4,
highlighter.on('highlight', function(voxelPosArray) {})
方块被高亮显示时调用
5,
highlighter.on('remove', function(voxelPosArray) {})
方块高亮显示被取消时调用
6,
highlighter.on('highlight-adjacent', function(voxelPosArray) {})
相邻方块被高亮显示时调用
7,
highlighter.on('remove-adjacent', function(voxelPosArray) {})
相邻方块高亮显示被取消时调用
8,
highlighter.on('highlight-select', funnction(selectionBounds) {}
多个方块被高亮显示时调用
9,
highlighter.on('highlight-deselect', funnction(selectionBounds) {}
多个方块被取消高亮时调用