threejs实现一个三维户外山上滑雪运动游戏代码
代码语言:html
所属分类:游戏
代码描述:threejs实现一个三维户外山上滑雪运动游戏代码,键盘左右键操作方向避开石头和树木。
下面为部分代码预览,完整代码请点击下载或在bfwstudio webide中打开
<!DOCTYPE html>
<html lang="en" >
<head>
<meta charset="UTF-8">
<style>
@import url('https://fonts.googleapis.com/css?family=Ranchers');
html, body {
height: 100%;
width: 100%;
padding: 0;
margin: 0;
overflow: hidden;
font-family: 'Ranchers', sans-serif;
}
body {
background-image: url('//repo.bfw.wiki/bfwrepo/images/ski/snowmountain.jpg');
background-size: cover;
background-position: center;
}
canvas {
width: 100%;
height: 100%;
margin: 0;
padding: 0;
}
div {
user-select: none;
}
.label-death {
display: none;
z-index: 10;
position: absolute;
top: 25%;
left: 50%;
transform: translate(-50%, -50%);
font-size: 10rem;
color: white;
&.active {
display: block;
}
}
.label-death-bg {
content: " ";
z-index: 9;
position: absolute;
top: 50%;
left: 50%;
width: 0;
height: 20rem;
transform: translate(-50%, -50%);
transition: all 2s ease;
background-color: black;
opacity: 0.7;
&.active {
top: 50%;
width: 100%;
height: 100%;
}
}
.label-score {
z-index: 10;
position: absolute;
left: 5vw;
bottom: 5vh;
font-size: 10rem;
transition: all 500ms ease;
color: black;
&.stopped {
top: 50%;
left: 50%;
bottom: auto;
font-size: 15rem;
transform: translate(-50%, -50%);
color: white;
}
}
.label-restart {
display: none;
z-index: 100;
position: absolute;
padding: 1rem 2rem;
top: 75%;
left: 50%;
width: 100%;
text-align: center;
font-size: 5rem;
color: white;
transform: translate(-50%, -50%);
&.active {
display: block;
}
}
</style>
</head>
<body >
<div class="label-death">REKT</div>
<div class="label-death-bg"></div>
<div class="label-score"></div>
<div class="label-restart">PRESS ENTER TO PLAY AGAIN</div>
<script type="text/javascript" src="//repo.bfw.wiki/bfwrepo/js/three.92.js"></script>
<script type="text/javascript" src="//repo.bfw.wiki/bfwrepo/js/mountain.plugins.js"></script>
<script >
class World {
constructor(wnd) {
this.window = wnd;
this.clock = new THREE.Clock();
this.isLoading = true;
this.loader = THREE.DefaultLoadingManager;
this.onLoadedCallbacks = [];
this.loader.onLoad = () => {
this.isLoading = false;
this.onLoadedCallbacks.forEach(cb => cb());
};
this.loader.onError = url => console.error(`There was an error loading ${url}`);
this.setupRenderer();
this.setupScene();
this.setupLighting();
// Auto resize engine
wnd.addEventListener('resize', () => {
this.renderer.setSize(wnd.innerWidth, wnd.innerHeight);
});
this.onRenderCallbacks = [];
this.animationMixers = [];
this.loadedFbx = {};
}
drawGridQuadrant(signX, signZ) {
const GRID_SIZE = 10;
const GRID_N = 20;
const sX = signX > 0 ? 1 : -1;
const sZ = signZ > 0 ? 1 : -1;
for (let i = 0; i < GRID_N; i++) {
for (let j = 0; j < GRID_N; j++) {
const offX = i * GRID_SIZE * sX;
const offZ = j * GRID_SIZE * sZ;
const geo = new THREE.BufferGeometry();
const verts = new Float32Array([
offX, 0, offZ,
offX, 0, offZ + GRID_SIZE,
offX + GRID_SIZE, 0, offZ + GRID_SIZE,
offX + GRID_SIZE, 0, offZ,
offX, 0, offZ]);
geo.addAttribute('position', new THREE.BufferAttribute(verts, 3));
const mat = new THREE.LineBasicMaterial({ color: 0 });
const line = new THREE.Line(geo, mat);
this.scene.add(line);
}
}
}
setupRenderer() {
const renderer = new THREE.WebGLRenderer({ alpha: true });
renderer.setSize(this.window.innerWidth, this.window.innerHeight);
this.renderer = renderer;
this.window.document.body.appendChild(renderer.domElement);
}
setupScene() {
const scene = new THREE.Scene();
scene.background = new THREE.Color(0xeeeeee);
this.scene = scene;
}
setupLighting() {
const ambientLight = new THREE.AmbientLight(0xffffff, 0.5);
this.scene.add(ambientLight);
this.ambientLight = ambientLight;
const hemisphericLight = new THREE.HemisphereLight(0xffffff, 0xffffff, 0.5);
hemisphericLight.position.y += 1500;
this.scene.add(hemisphericLight);
}
addAnimationMixer(mixer) {
this.animationMixers.push(mixer);
}
loadFbx(name, filename, addToScene = false, cb = () => {}) {
const fbxLoader = new THREE.FBXLoader(this.loader);
fbxLoader.load(filename, object => {
object.name = name;
if (this.loadedFbx[name]) {
console.log(`Warning: overwriting existing FBX '${name}'!`);
}
this.loadedFbx[name] = object;
if (addToScene) this.scene.add(object);
cb(null, object);
}, xhr => {
// console.log(xhr.loaded/xhr.total*100 + '% loaded')
}, xhr => {
const errMsg = `Error loading FBX '${name}': ${JSON.stringify(xhr)}!`;
console.error(errMsg);
cb(new Error(errMsg), null);
});
}
onLoaded(cb) {
if (typeof cb !== 'function') {
throw new Error(`${cb} must be a function!`);
}
if (this.isLoading) {
this.onLoadedCallbacks.push(cb);
} else {
// Already loaded, invoke callback immediately
cb();
}
}
onRender(cb) {
if (typeof cb !== 'function') {
throw new Error(`${cb} must be a function!`);
} else {
this.onRenderCallbacks.push(cb);
}
}
setCamera(camera) {
this.camera = camera;
}
teardown() {
cancelAnimationFrame(this.animationFrameId);
while (this.scene.children.length) {
const child = this.scene.children[0];
child.traverse(c => {
if (typeof c.dispose === 'function') {
c.dispose();
}
});
if (typeof child.dispose === 'function') {
child.dispose();
}
this.scene.remove(child);
}
this.scene = null;
this.camera = null;
this.clock = null;
this.loader = null;
this.onLoadedCallbacks = null;
this.onRenderCallbacks = null;
this.animationMixers = null;
Object.keys(this.loadedFbx).forEach(key => {
this.loadedFbx[key].traverse(child => {
if (typeof child.dispose === 'function') {
child.dispose();
}
});
this.loadedFbx[key] = null;
delete this.loadedFbx[key];
});
this.renderer.domElement.remove();
this.renderer = null;
}
render() {
// Store the delta so it can be passed around (for consistency)
const clockDelta = this.clock.getDelta();
// Run animations
this.animationMixers.forEach(mixer => mixer.update(clockDelta));
// Run onRender subscriptions
this.onRenderCallbacks.forEach(cb => cb(clockDelta));
// Render current frame only if camera available
if (this.camera) {
this.renderer.render(this.scene, this.camera);
} else {
// console.error('No camera has been setup yet!')
}
// Next frame
this.animationFrameId = requestAnimationFrame(() => this.render());
}}
class Player {
constructor(world) {
this.world = world;
this.speed = 100.; // scalar, pos units per tick
this.bearing = 0;
this.moveForward = true;
this.moveBackward = false;
this.moveLeft = false;
this.moveRight = false;
this.ROTATION_OFFSET_Y = 0;
this.dead = false;
this.attachControl();
this.setupModel();
}
get position() {
const model = this.model;
return model ? model.position : new THREE.Vector3(0, 0, 0);
}
setupModel() {
const world = this.world;
world.loadFbx('player', '//repo.bfw.wiki/bfwrepo/threemodel/player@skateboarding.fbx', true);
world.loadFbx('playerDying', '//repo.bfw.wiki/bfwrepo/threemodel/player@dying.fbx', false);
world.loadFbx('snowboard', '//repo.bfw.wiki/bfwrepo/threemodel/snowboard.fbx', true);
world.onLoaded(() => {
const player =.........完整代码请登录后点击上方下载按钮下载查看
网友评论0