今天郭先生发现大家更喜欢看我发的three.js小作品,今天我就发一个3d版本推箱子的游戏,其实webGL有很多框架,three.js并不合适做游戏引擎,但是可以尝试一些小游戏。在线案例请点击点击要制作一个推箱子游戏,正常要有以下4个步骤

定义一些数组,要有开始箱子数组、结束箱子数组、地面数组还有墙面数组,有这四个数组就可以组成一个关卡。

根据数组初始化地面墙面箱子和目标地点标志物。

使用FirstPersonControls控制器,控制相机移动,根据地面箱子和墙面算出可移动区域。

根据相机正对箱子时,用鼠标点击箱子,控制箱子移动,并做成功性校验。


定义一些数组,要有开始箱子数组、结束箱子数组、地面数组还有墙面数组,有这四个数组就可以组成一个关卡。根据数组初始化地面墙面箱子和目标地点标志物。使用FirstPersonControls控制器,控制相机移动,根据地面箱子和墙面算出可移动区域。根据相机正对箱子时,用鼠标点击箱子,控制箱子移动,并做成功性校验。

下面我们上代码分析代码1. 定义数组1. 定义数组这四个数组分别是墙的数组、地面的数组、箱子初始位置数组和目标数组。
wallArr = [[0, 0], [1, 0], [2, 0], [3, 0], [3, 1], [4, 1], [4, 2], [4, 3], [5, 3], [5, 4], [5, 5], [5, 6], [4, 6], [3, 6], [2, 6], [1, 6], [0, 6], [0, 5], [0, 4], [0, 3], [0, 2], [0, 1]]
scopeArr = [[1, 1], [2, 1], [1, 2], [2, 2], [3, 2], [1, 3], [2, 3], [1, 4], [4, 4], [1, 5], [2, 5], [3, 5], [4, 5]];
boxArr = [[3, 3], [2, 4], [3, 4]];
targetArr = [[2, 2], [1, 3], [2, 3]];
wallArr = [[0, 0], [1, 0], [2, 0], [3, 0], [3, 1], [4, 1], [4, 2], [4, 3], [5, 3], [5, 4], [5, 5], [5, 6], [4, 6], [3, 6], [2, 6], [1, 6], [0, 6], [0, 5], [0, 4], [0, 3], [0, 2], [0, 1]]
scopeArr = [[1, 1], [2, 1], [1, 2], [2, 2], [3, 2], [1, 3], [2, 3], [1, 4], [4, 4], [1, 5], [2, 5], [3, 5], [4, 5]];
boxArr = [[3, 3], [2, 4], [3, 4]];
targetArr = [[2, 2], [1, 3], [2, 3]]; 2. 根据箱子初始位置数组初始化箱子2. 根据箱子初始位置数组初始化箱子
initBox() {

var textureBox = new THREE.TextureLoader().load("/static/images/base/crate.png");

if (boxGroup) {

scene.remove(boxGroup)

}

boxGroup = new THREE.Group();

boxGroup.name = 'box_group'

boxArr.forEach(d => {

var boxGeom = new THREE.BoxGeometry(40, 40, 40);

var boxMate = [];

boxGeom.faces.forEach(d => boxMate.push(new THREE.MeshBasicMaterial({ map: textureBox })))

var boxMesh = new THREE.Mesh(boxGeom, boxMate);

boxMesh.position.set(d[0] * 40 - 20, 20, d[1] * 40 - 20);

boxMesh.name = 'box';

boxGroup.add(boxMesh);

})

scene.add(boxGroup);

//判断是否赢得比赛

this.isWinner(boxArr, targetArr)
}
initBox() {

var textureBox = new THREE.TextureLoader().load("/static/images/base/crate.png");

if (boxGroup) {

scene.remove(boxGroup)

}

boxGroup = new THREE.Group();

boxGroup.name = 'box_group'

boxArr.forEach(d => {

var boxGeom = new THREE.BoxGeometry(40, 40, 40);

var boxMate = [];

boxGeom.faces.forEach(d => boxMate.push(new THREE.MeshBasicMaterial({ map: textureBox })))

var boxMesh = new THREE.Mesh(boxGeom, boxMate);

boxMesh.position.set(d[0] * 40 - 20, 20, d[1] * 40 - 20);

boxMesh.name = 'box';

boxGroup.add(boxMesh);

})

scene.add(boxGroup);

//判断是否赢得比赛

this.isWinner(boxArr, targetArr)
}3. 根据地面数组初始化地面3. 根据地面数组初始化地面
initGround() {

var textureGround = new THREE.TextureLoader().load("/static/images/wall/plaster.jpg", () => {this.loaded_num --});

var textureGroundNormal = new THREE.TextureLoader().load("/static/images/wall/plaster-normal.jpg", () => {this.loaded_num --});

var textureGroundSpecular = new THREE.TextureLoader().load("/static/images/wall/plaster-diffuse.jpg", () => {this.loaded_num --});

textureGround.wrapS = textureGround.wrapT = THREE.RepeatWrapping;

textureGround.repeat.set(50, 50);

textureGroundNormal.wrapS = textureGroundNormal.wrapT = THREE.RepeatWrapping;

textureGroundNormal.repeat.set(50, 50);

var materialGround = new THREE.MeshPhongMaterial({

map: textureGround

})

materialGround.normalMap = textureGroundNormal;

materialGround.specularMap = textureGroundSpecular;

var ground = new THREE.Mesh(new THREE.PlaneGeometry(1000, 1000, 1, 1), materialGround);

ground.rotation.x = - Math.PI / 2;

scene.add(ground);
}
initGround() {

var textureGround = new THREE.TextureLoader().load("/static/images/wall/plaster.jpg", () => {this.loaded_num --});

var textureGroundNormal = new THREE.TextureLoader().load("/static/images/wall/plaster-normal.jpg", () => {this.loaded_num --});

var textureGroundSpecular = new THREE.TextureLoader().load("/static/images/wall/plaster-diffuse.jpg", () => {this.loaded_num --});

textureGround.wrapS = textureGround.wrapT = THREE.RepeatWrapping;

textureGround.repeat.set(50, 50);

textureGroundNormal.wrapS = textureGroundNormal.wrapT = THREE.RepeatWrapping;

textureGroundNormal.repeat.set(50, 50);

var materialGround = new THREE.MeshPhongMaterial({

map: textureGround

})

materialGround.normalMap = textureGroundNormal;

materialGround.specularMap = textureGroundSpecular;

var ground = new THREE.Mesh(new THREE.PlaneGeometry(1000, 1000, 1, 1), materialGround);

ground.rotation.x = - Math.PI / 2;

scene.add(ground);
}4. 根据墙数组初始化地面4. 根据墙数组初始化地面
initWall() {

var normal = new THREE.TextureLoader().load("/static/images/wall/stone.jpg", () => {this.loaded_num --});

var bump = new THREE.TextureLoader().load("/static/images/wall/stone-bump.jpg", () => {this.loaded_num --});

wallArr.forEach(d => {

var wallBox = new THREE.BoxGeometry(40, 40, 40);

var material = new THREE.MeshPhongMaterial({

map: normal,

bumpMap: bump,

bumpScale: 1

})

var wall = new THREE.Mesh(wallBox, material);

wall.position.x = d[0] * 40 - 20;

wall.position.y = 20;

wall.position.z = d[1] * 40 - 20;

scene.add(wall);

})
}
initWall() {

var normal = new THREE.TextureLoader().load("/static/images/wall/stone.jpg", () => {this.loaded_num --});

var bump = new THREE.TextureLoader().load("/static/images/wall/stone-bump.jpg", () => {this.loaded_num --});

wallArr.forEach(d => {

var wallBox = new THREE.BoxGeometry(40, 40, 40);

var material = new THREE.MeshPhongMaterial({

map: normal,

bumpMap: bump,

bumpScale: 1

})

var wall = new THREE.Mesh(wallBox, material);

wall.position.x = d[0] * 40 - 20;

wall.position.y = 20;

wall.position.z = d[1] * 40 - 20;

scene.add(wall);

})
}5. 根据目标数组初始化目标物5. 根据目标数组初始化目标物
initTarget() {

let objLoader = new OBJLoader();

objLoader.setPath("/static/images/texture/hongqi/");

objLoader.load('hongqi.obj', (object) => {

this.loaded_num --;

let hongqi = object.children[0];

targetArr.forEach(d => {

hongqi.position.set(d[0] * 40 - 20, -50, d[1] * 40 - 20)

hongqi.scale.set(0.12, 0.12, 0.12)

hongqi.material = new THREE.MeshNormalMaterial({ side: THREE.DoubleSide });

scene.add(hongqi.clone())

})

})
}
initTarget() {

let objLoader = new OBJLoader();

objLoader.setPath("/static/images/texture/hongqi/");

objLoader.load('hongqi.obj', (object) => {

this.loaded_num --;

let hongqi = object.children[0];

targetArr.forEach(d => {

hongqi.position.set(d[0] * 40 - 20, -50, d[1] * 40 - 20)

hongqi.scale.set(0.12, 0.12, 0.12)

hongqi.material = new THREE.MeshNormalMaterial({ side: THREE.DoubleSide });

scene.add(hongqi.clone())

})

})
}6. 监听箱子的点击事件6. 监听箱子的点击事件每次点击的时候执行computeMove方法,判断如果是否可移动。
initEventListener() {

raycaster = new THREE.Raycaster();

document.addEventListener('mousemove', function (event) {

event.preventDefault();

mouse.x = (event.clientX / window.innerWidth) * 2 - 1;

mouse.y = - (event.clientY / window.innerHeight) * 2 + 1;

}, false)

document.addEventListener('click', () => {

if (scene.children && scene.getObjectByName('box')) {

raycaster.setFromCamera(mouse, camera);

let intersects = raycaster.intersectObjects(scene.getObjectByName('box_group').children);

if (intersects[0] && intersects[0].object.name == 'box') {

this.computeMove(intersects[0].object, camera.position);

}

}

})
}
initEventListener() {

raycaster = new THREE.Raycaster();

document.addEventListener('mousemove', function (event) {

event.preventDefault();

mouse.x = (event.clientX / window.innerWidth) * 2 - 1;

mouse.y = - (event.clientY / window.innerHeight) * 2 + 1;

}, false)

document.addEventListener('click', () => {

if (scene.children && scene.getObjectByName('box')) {

raycaster.setFromCamera(mouse, camera);

let intersects = raycaster.intersectObjects(scene.getObjectByName('box_group').children);

if (intersects[0] && intersects[0].object.name == 'box') {

this.computeMove(intersects[0].object, camera.position);

}

}

})
}7. 监听游戏成功7. 监听游戏成功如果成功了,那么简单的弹出提示。
isWinner(arr1, arr2) {

let boo = true; //true为赢

arr1.forEach(d => {

let res = arr2.some(dd => {

return d[0] == dd[0] && d[1] == dd[1]

})

if(!res) {

boo = false;

}

})

if(boo) {

setTimeout(() => {

alert('恭喜你赢了!')

},100)

}
}
isWinner(arr1, arr2) {

let boo = true; //true为赢

arr1.forEach(d => {

let res = arr2.some(dd => {

return d[0] == dd[0] && d[1] == dd[1]

})

if(!res) {

boo = false;

}

})

if(boo) {

setTimeout(() => {

alert('恭喜你赢了!')

},100)

}
}由于当时做这个小案例时还是菜鸟,所以很少用一些three.js的辅助方法,见笑了。以上就是如何使用three.js 制作一个三维的推箱子游戏的详细内容,关于three.js 制作推箱子游戏的资料请关注其它相关文章!