<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8" />
<title>狼来了</title>
<link
rel="stylesheet"
href="https://public.codepenassets.com/css/reset-2.0.min.css"
/>
<style>
@import url("https://fonts.googleapis.com/css?family=Voltaire");
#world {
position: absolute;
width: 100%;
height: 100%;
background-color: #dbe6e6;
overflow: hidden;
}
#gameoverInstructions {
position: absolute;
font-family: "Voltaire", sans-serif;
font-weight: bold;
text-transform: uppercase;
font-size: 120px;
text-align: center;
color: #ffc5a2;
opacity: 0;
left: 50%;
top: 50%;
width: 100%;
transform: translate(-50%, -100%);
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
transition: all 500ms ease-in-out;
}
#gameoverInstructions.show {
opacity: 1;
transform: translate(-50%, -50%);
transition: all 500ms ease-in-out;
}
#dist {
position: absolute;
left: 50%;
top: 50px;
transform: translate(-50%, 0%);
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
}
.label {
position: relative;
font-family: "Voltaire", sans-serif;
text-transform: uppercase;
color: #ffa873;
font-size: 12px;
letter-spacing: 2px;
text-align: center;
margin-bottom: 5px;
}
#distValue {
position: relative;
text-transform: uppercase;
color: #dc5f45;
font-size: 40px;
font-family: "Voltaire";
text-align: center;
}
#credits {
position: absolute;
width: 100%;
margin: auto;
bottom: 0;
margin-bottom: 20px;
font-family: "Voltaire", sans-serif;
color: #544027;
font-size: 12px;
letter-spacing: 0.5px;
text-transform: uppercase;
text-align: center;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
}
#credits a {
color: #544027;
}
#credits a:hover {
color: #dc5f45;
}
#instructions {
position: absolute;
width: 100%;
bottom: 0;
margin: auto;
margin-bottom: 50px;
font-family: "Voltaire", sans-serif;
color: #dc5f45;
font-size: 16px;
letter-spacing: 1px;
text-transform: uppercase;
text-align: center;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
}
.lightInstructions {
color: #5f9042;
}
</style>
</head>
<body>
<div id="world" />
<div id="gameoverInstructions">游戏结束</div>
<div id="dist">
<div class="label">距离</div>
<div id="distValue">000</div>
</div>
<div id="instructions">
点击跳跃<span class="lightInstructions"> — 捡起胡萝卜 / 避开刺猬</span>
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r80/three.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/1.19.0/TweenMax.min.js"></script>
<script src="https://s3-us-west-2.amazonaws.com/s.cdpn.io/264161/OrbitControls.js"></script>
<script>
var scene,
camera,
fieldOfView,
aspectRatio,
nearPlane,
farPlane,
gobalLight,
shadowLight,
backLight,
renderer,
container,
controls,
clock;
var delta = 0;
var floorRadius = 200;
var speed = 6;
var distance = 0;
var level = 1;
var levelInterval;
var levelUpdateFreq = 3000;
var initSpeed = 5;
var maxSpeed = 48;
var monsterPos = 0.65;
var monsterPosTarget = 0.65;
var floorRotation = 0;
var collisionObstacle = 10;
var collisionBonus = 20;
var gameStatus = "play";
var cameraPosGame = 160;
var cameraPosGameOver = 260;
var monsterAcceleration = 0.004;
var malusClearColor = 0xb44b39;
var malusClearAlpha = 0;
var audio = new Audio(
"https://s3-us-west-2.amazonaws.com/s.cdpn.io/264161/Antonio-Vivaldi-Summer_01.mp3"
);
var fieldGameOver, fieldDistance;
var HEIGHT,
WIDTH,
windowHalfX,
windowHalfY,
mousePos = {
x: 0,
y: 0,
};
var hero;
var blackMat = new THREE.MeshPhongMaterial({
color: 0x100707,
shading: THREE.FlatShading,
});
var brownMat = new THREE.MeshPhongMaterial({
color: 0xb44b39,
shininess: 0,
shading: THREE.FlatShading,
});
var greenMat = new THREE.MeshPhongMaterial({
color: 0x7abf8e,
shininess: 0,
shading: THREE.FlatShading,
});
var pinkMat = new THREE.MeshPhongMaterial({
color: 0xdc5f45,
shininess: 0,
shading: THREE.FlatShading,
});
var lightBrownMat = new THREE.MeshPhongMaterial({
color: 0xe07a57,
shading: THREE.FlatShading,
});
var whiteMat = new THREE.MeshPhongMaterial({
color: 0xa49789,
shading: THREE.FlatShading,
});
var skinMat = new THREE.MeshPhongMaterial({
color: 0xff9ea5,
shading: THREE.FlatShading,
});
var PI = Math.PI;
function initScreenAnd3D() {
HEIGHT = window.innerHeight;
WIDTH = window.innerWidth;
windowHalfX = WIDTH / 2;
windowHalfY = HEIGHT / 2;
scene = new THREE.Scene();
scene.fog = new THREE.Fog(0xd6eae6, 160, 350);
aspectRatio = WIDTH / HEIGHT;
fieldOfView = 50;
nearPlane = 1;
farPlane = 2000;
camera = new THREE.PerspectiveCamera(
fieldOfView,
aspectRatio,
nearPlane,
farPlane
);
camera.position.x = 0;
camera.position.z = cameraPosGame;
camera.position.y = 30;
camera.lookAt(new THREE.Vector3(0, 30, 0));
renderer = new THREE.WebGLRenderer({
alpha: true,
antialias: true,
});
renderer.setPixelRatio(window.devicePixelRatio);
renderer.setClearColor(malusClearColor, malusClearAlpha);
renderer.setSize(WIDTH, HEIGHT);
renderer.shadowMap.enabled = true;
container = document.getElementById("world");
container.appendChild(renderer.domElement);
window.addEventListener("resize", handleWindowResize, false);
document.addEventListener("mousedown", handleMouseDown, false);
document.addEventListener("touchend", handleMouseDown, false);
clock = new THREE.Clock();
}
function handleWindowResize() {
HEIGHT = window.innerHeight;
WIDTH = window.innerWidth;
windowHalfX = WIDTH / 2;
windowHalfY = HEIGHT / 2;
renderer.setSize(WIDTH, HEIGHT);
camera.aspect = WIDTH / HEIGHT;
camera.updateProjectionMatrix();
}
function handleMouseDown(event) {
if (gameStatus == "play") hero.jump();
else if (gameStatus == "readyToReplay") {
replay();
}
}
function createLights() {
globalLight = new THREE.AmbientLight(0xffffff, 0.9);
shadowLight = new THREE.DirectionalLight(0xffffff, 1);
shadowLight.position.set(-30, 40, 20);
shadowLight.castShadow = true;
shadowLight.shadow.camera.left = -400;
shadowLight.shadow.camera.right = 400;
shadowLight.shadow.camera.top = 400;
shadowLight.shadow.camera.bottom = -400;
shadowLight.shadow.camera.near = 1;
shadowLight.shadow.camera.far = 2000;
shadowLight.shadow.mapSize.width =
shadowLight.shadow.mapSize.height = 2048;
scene.add(globalLight);
scene.add(shadowLight);
}
function createFloor() {
floorShadow = new THREE.Mesh(
new THREE.SphereGeometry(floorRadius, 50, 50),
new THREE.MeshPhongMaterial({
color: 0x7abf8e,
specular: 0x000000,
shininess: 1,
transparent: true,
opacity: 0.5,
})
);
floorShadow.receiveShadow = true;
floorGrass = new THREE.Mesh(
new THREE.SphereGeometry(floorRadius - 0.5, 50, 50),
new THREE.MeshBasicMaterial({
color: 0x7abf8e,
})
);
floorGrass.receiveShadow = false;
floor = new THREE.Group();
floor.position.y = -floorRadius;
floor.add(floorShadow);
floor.add(floorGrass);
scene.add(floor);
}
Hero = function () {
this.status = "running";
this.runningCycle = 0;
this.mesh = new THREE.Group();
this.body = new THREE.Group();
this.mesh.add(this.body);
var torsoGeom = new THREE.CubeGeometry(7, 7, 10, 1);
this.torso = new THREE.Mesh(torsoGeom, brownMat);
this.torso.position.z = 0;
this.torso.position.y = 7;
this.torso.castShadow = true;
this.body.add(this.torso);
var pantsGeom = new THREE.CubeGeometry(9, 9, 5, 1);
this.pants = new THREE.Mesh(pantsGeom, whiteMat);
this.pants.position.z = -3;
this.pants.position.y = 0;
this.pants.castShadow = true;
this.torso.add(this.pants);
var tailGeom = new THREE.CubeGeometry(3, 3, 3, 1);
tailGeom.applyMatrix(new THREE.Matrix4().makeTranslation(0, 0, -2));
this.tail = new THREE.Mesh(tailGeom, lightBrownMat);
this.tail.position.z = -4;
this.tail.position.y = 5;
this.tail.castShadow = true;
this.torso.add(this.tail);
this.torso.rotation.x = -Math.PI / 8;
var headGeom = new THREE.CubeGeometry(10, 10, 13, 1);
headGeom.applyMatrix(new THREE.Matrix4().makeTranslation(0, 0, 7.5));
this.head = new THREE.Mesh(headGeom, brownMat);
this.head.position.z = 2;
this.head.position.y = 11;
this.head.castShadow = true;
this.body.add(this.head);
var cheekGeom = new THREE.CubeGeometry(1, 4, 4, 1);
this.cheekR = new THREE.Mesh(cheekGeom, pinkMat);
this.cheekR.position.x = -5;
this.cheekR.position.z = 7;
this.cheekR.position.y = -2.5;
this.cheekR.castShadow = true;
this.head.add(this.cheekR);
this.cheekL = this.cheekR.clone();
this.cheekL.position.x = -this.cheekR.position.x;
this.head.add(this.cheekL);
var noseGeom = new THREE.CubeGeometry(6, 6, 3, 1);
this.nose = new THREE.Mesh(noseGeom, lightBrownMat);
this.nose.position.z = 13.5;
this.nose.position.y = 2.6;
this.nose.castShadow = true;
this.head.add(this.nose);
var mouthGeom = new THREE.CubeGeometry(4, 2, 4, 1);
mouthGeom.applyMatrix(new THREE.Matrix4().makeTranslation(0, 0, 3));
mouthGeom.applyMatrix(new THREE.Matrix4().makeRotationX(Math.PI / 12));
this.mouth = new THREE.Mesh(mouthGeom, brownMat);
this.mouth.position.z = 8;
this.mouth.position.y = -4;
this.mouth.castShadow = true;
this.head.add(this.mouth);
var pawFGeom = new THREE.CubeGeometry(3, 3, 3, 1);
this.pawFR = new THREE.Mesh(pawFGeom, lightBrownMat);
this.pawFR.position.x = -2;
this.pawFR.position.z = 6;
this.pawFR.position.y = 1.5;
this.pawFR.castShadow = true;
this.body.add(this.pawFR);
this.pawFL = this.pawFR.clone();
this.pawFL.position.x = -this.pawFR.position.x;
this.pawFL.castShadow = true;
this.body.add(this.pawFL);
var pawBGeom = new THREE.CubeGeometry(3, 3, 6, 1);
this.pawBL = new THREE.Mesh(pawBGeom, lightBrownMat);
this.pawBL.position.y = 1.5;
this.pawBL.position.z = 0;
this.pawBL.position.x = 5;
this.pawBL.castShadow = true;
this.body.add(this.pawBL);
this.pawBR = this.pawBL.clone();
this.pawBR.position.x = -this.pawBL.position.x;
this.pawBR.castShadow = true;
this.body.add(this.pawBR);
var earGeom = new THREE.CubeGeometry(7, 18, 2, 1);
earGeom.vertices[6].x += 2;
earGeom.vertices[6].z += 0.5;
earGeom.vertices[7].x += 2;
earGeom.vertices[7].z -= 0.5;
earGeom.vertices[2].x -= 2;
earGeom.vertices[2].z -= 0.5;
earGeom.vertices[3].x -= 2;
earGeom.vertices[3].z += 0.5;
earGeom.applyMatrix(new THREE.Matrix4().makeTranslation(0, 9, 0));
this.earL = new THREE.Mesh(earGeom, brownMat);
this.earL.position.x = 2;
this.earL.position.z = 2.5;
this.earL.position.y = 5;
this.earL.rotation.z = -Math.PI / 12;
this.earL.castShadow = true;
this.head.add(this.earL);
this.earR = this.earL.clone();
this.earR.position.x = -this.earL.position.x;
this.earR.rotation.z = -this.earL.rotation.z;
this.earR.castShadow = true;
this.head.add(this.earR);
var eyeGeom = new THREE.CubeGeometry(2, 4, 4);
this.eyeL = new THREE.Mesh(eyeGeom, whiteMat);
this.eyeL.position.x = 5;
this.eyeL.position.z = 5.5;
this.eyeL.position.y = 2.9;
this.eyeL.castShadow = true;
this.head.add(this.eyeL);
var irisGeom = new THREE.CubeGeometry(0.6, 2, 2);
this.iris = new THREE.Mesh(irisGeom, blackMat);
this.iris.position.x = 1.2;
this.iris.position.y = 1;
this.iris.position.z = 1;
this.eyeL.add(this.iris);
this.eyeR = this.eyeL.clone();
this.eyeR.children[0].position.x = -this.iris.position.x;
this.eyeR.position.x = -this.eyeL.position.x;
this.head.add(this.eyeR);
this.body.traverse(function (object) {
if (object instanceof THREE.Mesh) {
object.castShadow = true;
object.receiveShadow = true;
}
});
};
BonusParticles = function () {
this.mesh = new THREE.Group();
var bigParticleGeom = new THREE.CubeGeometry(10, 10, 10, 1);
var smallParticleGeom = new THREE.CubeGeometry(5, 5, 5, 1);
this.parts = [];
for (var i = 0; i < 10; i++) {
var partPink = new THREE.Mesh(bigParticleGeom, pinkMat);
var partGreen = new THREE.Mesh(smallParticleGeom, greenMat);
partGreen.scale.set(0.5, 0.5, 0.5);
this.parts.push(partPink);
this.parts.push(partGreen);
this.mesh.add(partPink);
this.mesh.add(partGreen);
}
};
BonusParticles.prototype.explose = function () {
var _this = this;
var explosionSpeed = 0.5;
for (var i = 0; i < this.parts.length; i++) {
var tx = -50 + Math.random() * 100;
var ty = -50 + Math.random() * 100;
var tz = -50 + Math.random() * 100;
var p = this.parts[i];
p.position.set(0, 0, 0);
p.scale.set(1, 1, 1);
p.visible = true;
var s = explosionSpeed + Math.random() * 0.5;
TweenMax.to(p.position, s, {
x: tx,
y: ty,
z: tz,
ease: Power4.easeOut,
});
TweenMax.to(p.scale, s, {
x: 0.01,
y: 0.01,
z: 0.01,
ease: Power4.easeOut,
onComplete: removeParticle,
onCompleteParams: [p],
});
}
};
function removeParticle(p) {
p.visible = false;
}
Hero.prototype.run = function () {
this.status = "running";
var s = Math.min(speed, maxSpeed);
this.runningCycle += delta * s * 0.7;
this.runningCycle = this.runningCycle % (Math.PI * 2);
var t = this.runningCycle;
var amp = 4;
var disp = 0.2;
this.body.position.y = 6 + Math.sin(t - Math.PI / 2) * amp;
this.body.rotation.x = 0.2 + Math.sin(t - Math.PI / 2) * amp * 0.1;
this.torso.rotation.x = Math.sin(t - Math.PI / 2) * amp * 0.1;
this.torso.position.y = 7 + Math.sin(t - Math.PI / 2) * amp * 0.5;
this.mouth.rotation.x = Math.PI / 16 + Math.cos(t) * amp * 0.05;
this.head.position.z = 2 + Math.sin(t - Math.PI / 2) * amp * 0.5;
this.head.position.y = 8 + Math.cos(t - Math.PI / 2) * amp * 0.7;
this.head.rotation.x = -0.2 + Math.sin(t + Math.PI) * amp * 0.1;
this.earL.rotation.x = Math.cos(-Math.PI / 2 + t) * (amp * 0.2);
this.earR.rotation.x = Math.cos(-Math.PI / 2 + 0.2 + t) * (amp * 0.3);
this.eyeR.scale.y = this.eyeL.scale.y =
0.7 + Math.abs(Math.cos(-Math.PI / 4 + t * 0.5)) * 0.6;
this.tail.rotation.x = Math.cos(Math.PI / 2 + t) * amp * 0.3;
this.pawFR.position.y = 1.5 + Math.sin(t) * amp;
this.pawFR.rotation.x = (Math.cos(t) * Math.PI) / 4;
this.pawFR.position.z = 6 - Math.cos(t) * amp * 2;
this.pawFL.position.y = 1.5 + Math.sin(disp + t) * amp;
this.pawFL.rotation.x = (Math.cos(t) * Math.PI) / 4;
this.pawFL.position.z = 6 - Math.cos(disp + t) * amp * 2;
this.pawBR.position.y = 1.5 + Math.sin(Math.PI + t) * amp;
this.pawBR.rotation.x = (Math.cos(t + Math.PI * 1.5) * Math.PI) / 3;
this.pawBR.position.z = -Math.cos(Math.PI + t) * amp;
this.pawBL.position.y = 1.5 + Math.sin(Math.PI + t) * amp;
this.pawBL.rotation.x = (Math.cos(t + Math.PI * 1.5) * Math.PI) / 3;
this.pawBL.position.z = -Math.cos(Math.PI + t) * amp;
};
Hero.prototype.jump = function () {
if (this.status == "jumping") return;
this.status = "jumping";
var _this = this;
var totalSpeed = 10 / speed;
var jumpHeight = 45;
TweenMax.to(this.earL.rotation, totalSpeed, {
x: "+=.3",
ease: Back.easeOut,
});
TweenMax.to(this.earR.rotation, totalSpeed, {
x: "-=.3",
ease: Back.easeOut,
});
TweenMax.to(this.pawFL.rotation, totalSpeed, {
x: "+=.7",
ease: Back.easeOut,
});
TweenMax.to(this.pawFR.rotation, totalSpeed, {
x: "-=.7",
ease: Back.easeOut,
});
TweenMax.to(this.pawBL.rotation, totalSpeed, {
x: "+=.7",
ease: Back.easeOut,
});
TweenMax.to(this.pawBR.rotation, totalSpeed, {
x: "-=.7",
ease: Back.easeOut,
});
TweenMax.to(this.tail.rotation, totalSpeed, {
x: "+=1",
ease: Back.easeOut,
});
TweenMax.to(this.mouth.rotation, totalSpeed, {
x: 0.5,
ease: Back.easeOut,
});
TweenMax.to(this.mesh.position, totalSpeed / 2, {
y: jumpHeight,
ease: Power2.easeOut,
});
TweenMax.to(this.mesh.position, totalSpeed / 2, {
y: 0,
ease: Power4.easeIn,
delay: totalSpeed / 2,
onComplete: function () {
_this.status = "running";
},
});
};
Monster = function () {
this.runningCycle = 0;
this.mesh = new THREE.Group();
this.body = new THREE.Group();
var torsoGeom = new THREE.CubeGeometry(15, 15, 20, 1);
this.torso = new THREE.Mesh(torsoGeom, blackMat);
var headGeom = new THREE.CubeGeometry(20, 20, 40, 1);
headGeom.applyMatrix(new THREE.Matrix4().makeTranslation(0, 0, 20));
this.head = new THREE.Mesh(headGeom, blackMat);
this.head.position.z = 12;
this.head.position.y = 2;
var mouthGeom = new THREE.CubeGeometry(10, 4, 20, 1);
mouthGeom.applyMatrix(new THREE.Matrix4().makeTranslation(0, -2, 10));
this.mouth = new THREE.Mesh(mouthGeom, blackMat);
this.mouth.position.y = -8;
this.mouth.rotation.x = 0.4;
this.mouth.position.z = 4;
this.heroHolder = new THREE.Group();
this.heroHolder.position.z = 20;
this.mouth.add(this.heroHolder);
var toothGeom = new THREE.CubeGeometry(2, 2, 1, 1);
toothGeom.vertices[1].x -= 1;
toothGeom.vertices[4].x += 1;
toothGeom.vertices[5].x += 1;
toothGeom.vertices[0].x -= 1;
for (var i = 0; i < 3; i++) {
var toothf = new THREE.Mesh(toothGeom, whiteMat);
toothf.position.x = -2.8 + i * 2.5;
toothf.position.y = 1;
toothf.position.z = 19;
var toothl = new THREE.Mesh(toothGeom, whiteMat);
toothl.rotation.y = Math.PI / 2;
toothl.position.z = 12 + i * 2.5;
toothl.position.y = 1;
toothl.position.x = 4;
var toothr = toothl.clone();
toothl.position.x = -4;
this.mouth.add(toothf);
this.mouth.add(toothl);
this.mouth.add(toothr);
}
var tongueGeometry = new THREE.CubeGeometry(6, 1, 14);
tongueGeometry.applyMatrix(
new THREE.Matrix4().makeTranslation(0, 0, 7)
);
this.tongue = new THREE.Mesh(tongueGeometry, pinkMat);
this.tongue.position.z = 2;
this.tongue.rotation.x = -0.2;
this.mouth.add(this.tongue);
var noseGeom = new THREE.CubeGeometry(4, 4, 4, 1);
this.nose = new THREE.Mesh(noseGeom, pinkMat);
this.nose.position.z = 39.5;
this.nose.position.y = 9;
this.head.add(this.nose);
this.head.add(this.mouth);
var eyeGeom = new THREE.CubeGeometry(2, 3, 3);
this.eyeL = new THREE.Mesh(eyeGeom, whiteMat);
this.eyeL.position.x = 10;
this.eyeL.position.z = 5;
this.eyeL.position.y = 5;
this.eyeL.castShadow = true;
this.head.add(this.eyeL);
var irisGeom = new THREE.CubeGeometry(0.6, 1, 1);
this.iris = new THREE.Mesh(irisGeom, blackMat);
this.iris.position.x = 1.2;
this.iris.position.y = -1;
this.iris.position.z = 1;
this.eyeL.add(this.iris);
this.eyeR = this.eyeL.clone();
this.eyeR.children[0].position.x = -this.iris.position.x;
this.eyeR.position.x = -this.eyeL.position.x;
this.head.add(this.eyeR);
var earGeom = new THREE.CubeGeometry(8, 6, 2, 1);
earGeom.vertices[1].x -= 4;
earGeom.vertices[4].x += 4;
earGeom.vertices[5].x += 4;
earGeom.vertices[5].z -= 2;
earGeom.vertices[0].x -= 4;
earGeom.vertices[0].z -= 2;
earGeom.applyMatrix(new THREE.Matrix4().makeTranslation(0, 3, 0));
this.earL = new THREE.Mesh(earGeom, blackMat);
this.earL.position.x = 6;
this.earL.position.z = 1;
this.earL.position.y = 10;
this.earL.castShadow = true;
this.head.add(this.earL);
this.earR = this.earL.clone();
this.earR.position.x = -this.earL.position.x;
this.earR.rotation.z = -this.earL.rotation.z;
this.head.add(this.earR);
var eyeGeom = new THREE.CubeGeometry(2, 4, 4);
var tailGeom = new THREE.CylinderGeometry(5, 2, 20, 4, 1);
tailGeom.applyMatrix(new THREE.Matrix4().makeTranslation(0, 10, 0));
tailGeom.applyMatrix(new THREE.Matrix4().makeRotationX(-Math.PI / 2));
tailGeom.applyMatrix(new THREE.Matrix4().makeRotationZ(Math.PI / 4));
this.tail = new THREE.Mesh(tailGeom, blackMat);
this.tail.position.z = -10;
this.tail.position.y = 4;
this.torso.add(this.tail);
var pawGeom = new THREE.CylinderGeometry(1.5, 0, 10);
pawGeom.applyMatrix(new THREE.Matrix4().makeTranslation(0, -5, 0));
this.pawFL = new THREE.Mesh(pawGeom, blackMat);
this.pawFL.position.y = -7.5;
this.pawFL.position.z = 8.5;
this.pawFL.position.x = 5.5;
this.torso.add(this.pawFL);
this.pawFR = this.pawFL.clone();
this.pawFR.position.x = -this.pawFL.position.x;
this.torso.add(this.pawFR);
this.pawBR = this.pawFR.clone();
this.pawBR.position.z = -this.pawFL.position.z;
this.torso.add(this.pawBR);
this.pawBL = this.pawBR.clone();
this.pawBL.position.x = this.pawFL.position.x;
this.torso.add(this.pawBL);
this.mesh.add(this.body);
this.torso.add(this.head);
this.body.add(this.torso);
this.torso.castShadow = true;
this.head.castShadow = true;
this.pawFL.castShadow = true;
this.pawFR.castShadow = true;
this.pawBL.castShadow = true;
this.pawBR.castShadow = true;
this.body.rotation.y = Math.PI / 2;
};
Monster.prototype.run = function () {
var s = Math.min(speed, maxSpeed);
this.runningCycle += delta * s * 0.7;
this.runningCycle = this.runningCycle % (Math.PI * 2);
var t = this.runningCycle;
this.pawFR.rotation.x = (Math.sin(t) * Math.PI) / 4;
this.pawFR.position.y = -5.5 - Math.sin(t);
this.pawFR.position.z = 7.5 + Math.cos(t);
this.pawFL.rotation.x = (Math.sin(t + 0.4) * Math.PI) / 4;
this.pawFL.position.y = -5.5 - Math.sin(t + 0.4);
this.pawFL.position.z = 7.5 + Math.cos(t + 0.4);
this.pawBL.rotation.x = (Math.sin(t + 2) * Math.PI) / 4;
this.pawBL.position.y = -5.5 - Math.sin(t + 3.8);
this.pawBL.position.z = -7.5 + Math.cos(t + 3.8);
this.pawBR.rotation.x = (Math.sin(t + 2.4) * Math.PI) / 4;
this.pawBR.position.y = -5.5 - Math.sin(t + 3.4);
this.pawBR.position.z = -7.5 + Math.cos(t + 3.4);
this.torso.rotation.x = (Math.sin(t) * Math.PI) / 8;
this.torso.position.y = 3 - Math.sin(t + Math.PI / 2) * 3;
this.head.rotation.x = -0.1 + Math.sin(-t - 1) * 0.4;
this.mouth.rotation.x = 0.2 + Math.sin(t + Math.PI + 0.3) * 0.4;
this.tail.rotation.x = 0.2 + Math.sin(t - Math.PI / 2);
this.eyeR.scale.y = 0.5 + Math.sin(t + Math.PI) * 0.5;
};
Hero.prototype.nod = function () {
var _this = this;
var sp = 0.5 + Math.random();
var tHeadRotY = -Math.PI / 6 + (Math.random() * Math.PI) / 3;
TweenMax.to(this.head.rotation, sp, {
y: tHeadRotY,
ease: Power4.easeInOut,
onComplete: function () {
_this.nod();
},
});
var tEarLRotX = Math.PI / 4 + (Math.random() * Math.PI) / 6;
var tEarRRotX = Math.PI / 4 + (Math.random() * Math.PI) / 6;
TweenMax.to(this.earL.rotation, sp, {
x: tEarLRotX,
ease: Power4.easeInOut,
});
TweenMax.to(this.earR.rotation, sp, {
x: tEarRRotX,
ease: Power4.easeInOut,
});
var tPawBLRot = (Math.random() * Math.PI) / 2;
var tPawBLY = -4 + Math.random() * 8;
TweenMax.to(this.pawBL.rotation, sp / 2, {
x: tPawBLRot,
ease: Power1.easeInOut,
yoyo: true,
repeat: 2,
});
TweenMax.to(this.pawBL.position, sp / 2, {
y: tPawBLY,
ease: Power1.easeInOut,
yoyo: true,
repeat: 2,
});
var tPawBRRot = (Math.random() * Math.PI) / 2;
var tPawBRY = -4 + Math.random() * 8;
TweenMax.to(this.pawBR.rotation, sp / 2, {
x: tPawBRRot,
ease: Power1.easeInOut,
yoyo: true,
repeat: 2,
});
TweenMax.to(this.pawBR.position, sp / 2, {
y: tPawBRY,
ease: Power1.easeInOut,
yoyo: true,
repeat: 2,
});
var tPawFLRot = (Math.random() * Math.PI) / 2;
var tPawFLY = -4 + Math.random() * 8;
TweenMax.to(this.pawFL.rotation, sp / 2, {
x: tPawFLRot,
ease: Power1.easeInOut,
yoyo: true,
repeat: 2,
});
TweenMax.to(this.pawFL.position, sp / 2, {
y: tPawFLY,
ease: Power1.easeInOut,
yoyo: true,
repeat: 2,
});
var tPawFRRot = (Math.random() * Math.PI) / 2;
var tPawFRY = -4 + Math.random() * 8;
TweenMax.to(this.pawFR.rotation, sp / 2, {
x: tPawFRRot,
ease: Power1.easeInOut,
yoyo: true,
repeat: 2,
});
TweenMax.to(this.pawFR.position, sp / 2, {
y: tPawFRY,
ease: Power1.easeInOut,
yoyo: true,
repeat: 2,
});
var tMouthRot = (Math.random() * Math.PI) / 8;
TweenMax.to(this.mouth.rotation, sp, {
x: tMouthRot,
ease: Power1.easeInOut,
});
var tIrisY = -1 + Math.random() * 2;
var tIrisZ = -1 + Math.random() * 2;
var iris1 = this.iris;
var iris2 = this.eyeR.children[0];
TweenMax.to([iris1.position, iris2.position], sp, {
y: tIrisY,
z: tIrisZ,
ease: Power1.easeInOut,
});
if (Math.random() > 0.2)
TweenMax.to([this.eyeR.scale, this.eyeL.scale], sp / 8, {
y: 0,
ease: Power1.easeInOut,
yoyo: true,
repeat: 1,
});
};
Hero.prototype.hang = function () {
var _this = this;
var sp = 1;
var ease = Power4.easeOut;
TweenMax.killTweensOf(this.eyeL.scale);
TweenMax.killTweensOf(this.eyeR.scale);
this.body.rotation.x = 0;
this.torso.rotation.x = 0;
this.body.position.y = 0;
this.torso.position.y = 7;
TweenMax.to(this.mesh.rotation, sp, { y: 0, ease: ease });
TweenMax.to(this.mesh.position, sp, { y: -7, z: 6, ease: ease });
TweenMax.to(this.head.rotation, sp, {
x: Math.PI / 6,
ease: ease,
onComplete: function () {
_this.nod();
},
});
TweenMax.to(this.earL.rotation, sp, { x: Math.PI / 3, ease: ease });
TweenMax.to(this.earR.rotation, sp, { x: Math.PI / 3, ease: ease });
TweenMax.to(this.pawFL.position, sp, { y: -1, z: 3, ease: ease });
TweenMax.to(this.pawFR.position, sp, { y: -1, z: 3, ease: ease });
TweenMax.to(this.pawBL.position, sp, { y: -2, z: -3, ease: ease });
TweenMax.to(this.pawBR.position, sp, { y: -2, z: -3, ease: ease });
TweenMax.to(this.eyeL.scale, sp, { y: 1, ease: ease });
TweenMax.to(this.eyeR.scale, sp, { y: 1, ease: ease });
};
Monster.prototype.nod = function () {
var _this = this;
var sp = 1 + Math.random() * 2;
var tHeadRotY = -Math.PI / 3 + Math.random() * 0.5;
var tHeadRotX = Math.PI / 3 - 0.2 + Math.random() * 0.4;
TweenMax.to(this.head.rotation, sp, {
x: tHeadRotX,
y: tHeadRotY,
ease: Power4.easeInOut,
onComplete: function () {
_this.nod();
},
});
var tTailRotY = -Math.PI / 4;
TweenMax.to(this.tail.rotation, sp / 8, {
y: tTailRotY,
ease: Power1.easeInOut,
yoyo: true,
repeat: 8,
});
TweenMax.to([this.eyeR.scale, this.eyeL.scale], sp / 20, {
y: 0,
ease: Power1.easeInOut,
yoyo: true,
repeat: 1,
});
};
Monster.prototype.sit = function () {
var sp = 1.2;
var ease = Power4.easeOut;
var _this = this;
TweenMax.to(this.torso.rotation, sp, { x: -1.3, ease: ease });
TweenMax.to(this.torso.position, sp, {
y: -5,
ease: ease,
onComplete: function () {
_this.nod();
gameStatus = "readyToReplay";
},
});
TweenMax.to(this.head.rotation, sp, {
x: Math.PI / 3,
y: -Math.PI / 3,
ease: ease,
});
TweenMax.to(this.tail.rotation, sp, {
x: 2,
y: Math.PI / 4,
ease: ease,
});
TweenMax.to(this.pawBL.rotation, sp, { x: -0.1, ease: ease });
TweenMax.to(this.pawBR.rotation, sp, { x: -0.1, ease: ease });
TweenMax.to(this.pawFL.rotation, sp, { x: 1, ease: ease });
TweenMax.to(this.pawFR.rotation, sp, { x: 1, ease: ease });
TweenMax.to(this.mouth.rotation, sp, { x: 0.3, ease: ease });
TweenMax.to(this.eyeL.scale, sp, { y: 1, ease: ease });
TweenMax.to(this.eyeR.scale, sp, { y: 1, ease: ease });
};
Carrot = function () {
this.angle = 0;
this.mesh = new THREE.Group();
var bodyGeom = new THREE.CylinderGeometry(5, 3, 10, 4, 1);
bodyGeom.vertices[8].y += 2;
bodyGeom.vertices[9].y -= 3;
this.body = new THREE.Mesh(bodyGeom, pinkMat);
var leafGeom = new THREE.CubeGeometry(5, 10, 1, 1);
leafGeom.applyMatrix(new THREE.Matrix4().makeTranslation(0, 5, 0));
leafGeom.vertices[2].x -= 1;
leafGeom.vertices[3].x -= 1;
leafGeom.vertices[6].x += 1;
leafGeom.vertices[7].x += 1;
this.leaf1 = new THREE.Mesh(leafGeom, greenMat);
this.leaf1.position.y = 7;
this.leaf1.rotation.z = 0.3;
this.leaf1.rotation.x = 0.2;
this.leaf2 = this.leaf1.clone();
this.leaf2.scale.set(1, 1.3, 1);
this.leaf2.position.y = 7;
this.leaf2.rotation.z = -0.3;
this.leaf2.rotation.x = -0.2;
this.mesh.add(this.body);
this.mesh.add(this.leaf1);
this.mesh.add(this.leaf2);
this.body.traverse(function (object) {
if (object instanceof THREE.Mesh) {
object.castShadow = true;
object.receiveShadow = true;
}
});
};
Hedgehog = function () {
this.angle = 0;
this.status = "ready";
this.mesh = new THREE.Group();
var bodyGeom = new THREE.CubeGeometry(6, 6, 6, 1);
this.body = new THREE.Mesh(bodyGeom, blackMat);
var headGeom = new THREE.CubeGeometry(5, 5, 7, 1);
this.head = new THREE.Mesh(headGeom, lightBrownMat);
this.head.position.z = 6;
this.head.position.y = -0.5;
var noseGeom = new THREE.CubeGeometry(1.5, 1.5, 1.5, 1);
this.nose = new THREE.Mesh(noseGeom, blackMat);
this.nose.position.z = 4;
this.nose.position.y = 2;
var eyeGeom = new THREE.CubeGeometry(1, 3, 3);
this.eyeL = new THREE.Mesh(eyeGeom, whiteMat);
this.eyeL.position.x = 2.2;
this.eyeL.position.z = -0.5;
this.eyeL.position.y = 0.8;
this.eyeL.castShadow = true;
this.head.add(this.eyeL);
var irisGeom = new THREE.CubeGeometry(0.5, 1, 1);
this.iris = new THREE.Mesh(irisGeom, blackMat);
this.iris.position.x = 0.5;
this.iris.position.y = 0.8;
this.iris.position.z = 0.8;
this.eyeL.add(this.iris);
this.eyeR = this.eyeL.clone();
this.eyeR.children[0].position.x = -this.iris.position.x;
this.eyeR.position.x = -this.eyeL.position.x;
var spikeGeom = new THREE.CubeGeometry(0.5, 2, 0.5, 1);
spikeGeom.applyMatrix(new THREE.Matrix4().makeTranslation(0, 1, 0));
for (var i = 0; i < 9; i++) {
var row = i % 3;
var col = Math.floor(i / 3);
var sb = new THREE.Mesh(spikeGeom, blackMat);
sb.rotation.x =
-Math.PI / 2 + (Math.PI / 12) * row - 0.5 + Math.random();
sb.position.z = -3;
sb.position.y = -2 + row * 2;
sb.position.x = -2 + col * 2;
this.body.add(sb);
var st = new THREE.Mesh(spikeGeom, blackMat);
st.position.y = 3;
st.position.x = -2 + row * 2;
st.position.z = -2 + col * 2;
st.rotation.z =
Math.PI / 6 - (Math.PI / 6) * row - 0.5 + Math.random();
this.body.add(st);
var sr = new THREE.Mesh(spikeGeom, blackMat);
sr.position.x = 3;
sr.position.y = -2 + row * 2;
sr.position.z = -2 + col * 2;
sr.rotation.z =
-Math.PI / 2 + (Math.PI / 12) * row - 0.5 + Math.random();
this.body.add(sr);
var sl = new THREE.Mesh(spikeGeom, blackMat);
sl.position.x = -3;
sl.position.y = -2 + row * 2;
sl.position.z = -2 + col * 2;
sl.rotation.z =
Math.PI / 2 - (Math.PI / 12) * row - 0.5 + Math.random();
this.body.add(sl);
}
this.head.add(this.eyeR);
var earGeom = new THREE.CubeGeometry(2, 2, 0.5, 1);
this.earL = new THREE.Mesh(earGeom, lightBrownMat);
this.earL.position.x = 2.5;
this.earL.position.z = -2.5;
this.earL.position.y = 2.5;
this.earL.rotation.z = -Math.PI / 12;
this.earL.castShadow = true;
this.head.add(this.earL);
this.earR = this.earL.clone();
this.earR.position.x = -this.earL.position.x;
this.earR.rotation.z = -this.earL.rotation.z;
this.earR.castShadow = true;
this.head.add(this.earR);
var mouthGeom = new THREE.CubeGeometry(1, 1, 0.5, 1);
this.mouth = new THREE.Mesh(mouthGeom, blackMat);
this.mouth.position.z = 3.5;
this.mouth.position.y = -1.5;
this.head.add(this.mouth);
this.mesh.add(this.body);
this.body.add(this.head);
this.head.add(this.nose);
this.mesh.traverse(function (object) {
if (object instanceof THREE.Mesh) {
object.castShadow = true;
object.receiveShadow = true;
}
});
};
Hedgehog.prototype.nod = function () {
var _this = this;
var speed = 0.1 + Math.random() * 0.5;
var angle = -Math.PI / 4 + (Math.random() * Math.PI) / 2;
TweenMax.to(this.head.rotation, speed, {
y: angle,
onComplete: function () {
_this.nod();
},
});
};
function createHero() {
hero = new Hero();
hero.mesh.rotation.y = Math.PI / 2;
scene.add(hero.mesh);
hero.nod();
}
function createMonster() {
monster = new Monster();
monster.mesh.position.z = 20;
scene.add(monster.mesh);
updateMonsterPosition();
}
function updateMonsterPosition() {
monster.run();
monsterPosTarget -= delta * monsterAcceleration;
monsterPos += (monsterPosTarget - monsterPos) * delta;
if (monsterPos < 0.56) {
gameOver();
}
var angle = Math.PI * monsterPos;
monster.mesh.position.y =
-floorRadius + Math.sin(angle) * (floorRadius + 12);
monster.mesh.position.x = Math.cos(angle) * (floorRadius + 15);
monster.mesh.rotation.z = -Math.PI / 2 + angle;
}
function gameOver() {
fieldGameOver.className = "show";
gameStatus = "gameOver";
monster.sit();
hero.hang();
monster.heroHolder.add(hero.mesh);
TweenMax.to(this, 1, { speed: 0 });
TweenMax.to(camera.position, 3, {
z: cameraPosGameOver,
y: 60,
x: -30,
});
carrot.mesh.visible = false;
obstacle.mesh.visible = false;
clearInterval(levelInterval);
}
function replay() {
gameStatus = "preparingToReplay";
fieldGameOver.className = "";
TweenMax.killTweensOf(monster.pawFL.position);
TweenMax.killTweensOf(monster.pawFR.position);
TweenMax.killTweensOf(monster.pawBL.position);
TweenMax.killTweensOf(monster.pawBR.position);
TweenMax.killTweensOf(monster.pawFL.rotation);
TweenMax.killTweensOf(monster.pawFR.rotation);
TweenMax.killTweensOf(monster.pawBL.rotation);
TweenMax.killTweensOf(monster.pawBR.rotation);
TweenMax.killTweensOf(monster.tail.rotation);
TweenMax.killTweensOf(monster.head.rotation);
TweenMax.killTweensOf(monster.eyeL.scale);
TweenMax.killTweensOf(monster.eyeR.scale);
monster.tail.rotation.y = 0;
TweenMax.to(camera.position, 3, {
z: cameraPosGame,
x: 0,
y: 30,
ease: Power4.easeInOut,
});
TweenMax.to(monster.torso.rotation, 2, {
x: 0,
ease: Power4.easeInOut,
});
TweenMax.to(monster.torso.position, 2, {
y: 0,
ease: Power4.easeInOut,
});
TweenMax.to(monster.pawFL.rotation, 2, {
x: 0,
ease: Power4.easeInOut,
});
TweenMax.to(monster.pawFR.rotation, 2, {
x: 0,
ease: Power4.easeInOut,
});
TweenMax.to(monster.mouth.rotation, 2, {
x: 0.5,
ease: Power4.easeInOut,
});
TweenMax.to(monster.head.rotation, 2, {
y: 0,
x: -0.3,
ease: Power4.easeInOut,
});
TweenMax.to(hero.mesh.position, 2, { x: 20, ease: Power4.easeInOut });
TweenMax.to(hero.head.rotation, 2, {
x: 0,
y: 0,
ease: Power4.easeInOut,
});
TweenMax.to(monster.mouth.rotation, 2, {
x: 0.2,
ease: Power4.easeInOut,
});
TweenMax.to(monster.mouth.rotation, 1, {
x: 0.4,
ease: Power4.easeIn,
delay: 1,
onComplete: function () {
resetGame();
},
});
}
Fir = function () {
var height = 200;
var truncGeom = new THREE.CylinderGeometry(2, 2, height, 6, 1);
truncGeom.applyMatrix(
new THREE.Matrix4().makeTranslation(0, height / 2, 0)
);
this.mesh = new THREE.Mesh(truncGeom, greenMat);
this.mesh.castShadow = true;
};
var firs = new THREE.Group();
function createFirs() {
var nTrees = 100;
for (var i = 0; i < nTrees; i++) {
var phi = (i * (Math.PI * 2)) / nTrees;
var theta = Math.PI / 2;
theta +=
Math.random() > 0.05
? 0.25 + Math.random() * 0.3
: -0.35 - Math.random() * 0.1;
var fir = new Tree();
fir.mesh.position.x = Math.sin(theta) * Math.cos(phi) * floorRadius;
fir.mesh.position.y =
Math.sin(theta) * Math.sin(phi) * (floorRadius - 10);
fir.mesh.position.z = Math.cos(theta) * floorRadius;
var vec = fir.mesh.position.clone();
var axis = new THREE.Vector3(0, 1, 0);
fir.mesh.quaternion.setFromUnitVectors(axis, vec.clone().normalize());
floor.add(fir.mesh);
}
}
function createCarrot() {
carrot = new Carrot();
scene.add(carrot.mesh);
}
function updateCarrotPosition() {
carrot.mesh.rotation.y += delta * 6;
carrot.mesh.rotation.z = Math.PI / 2 - (floorRotation + carrot.angle);
carrot.mesh.position.y =
-floorRadius +
Math.sin(floorRotation + carrot.angle) * (floorRadius + 50);
carrot.mesh.position.x =
Math.cos(floorRotation + carrot.angle) * (floorRadius + 50);
}
function updateObstaclePosition() {
if (obstacle.status == "flying") return;
if (floorRotation + obstacle.angle > 2.5) {
obstacle.angle = -floorRotation + Math.random() * 0.3;
obstacle.body.rotation.y = Math.random() * Math.PI * 2;
}
obstacle.mesh.rotation.z = floorRotation + obstacle.angle - Math.PI / 2;
obstacle.mesh.position.y =
-floorRadius +
Math.sin(floorRotation + obstacle.angle) * (floorRadius + 3);
obstacle.mesh.position.x =
Math.cos(floorRotation + obstacle.angle) * (floorRadius + 3);
}
function updateFloorRotation() {
floorRotation += delta * 0.03 * speed;
floorRotation = floorRotation % (Math.PI * 2);
floor.rotation.z = floorRotation;
}
function createObstacle() {
obstacle = new Hedgehog();
obstacle.body.rotation.y = -Math.PI / 2;
obstacle.mesh.scale.set(1.1, 1.1, 1.1);
obstacle.mesh.position.y = floorRadius + 4;
obstacle.nod();
scene.add(obstacle.mesh);
}
function createBonusParticles() {
bonusParticles = new BonusParticles();
bonusParticles.mesh.visible = false;
scene.add(bonusParticles.mesh);
}
function checkCollision() {
var db = hero.mesh.position.clone().sub(carrot.mesh.position.clone());
var dm = hero.mesh.position.clone().sub(obstacle.mesh.position.clone());
if (db.length() < collisionBonus) {
getBonus();
}
if (dm.length() < collisionObstacle && obstacle.status != "flying") {
getMalus();
}
}
function getBonus() {
bonusParticles.mesh.position.copy(carrot.mesh.position);
bonusParticles.mesh.visible = true;
bonusParticles.explose();
carrot.angle += Math.PI / 2;
monsterPosTarget += 0.025;
}
function getMalus() {
obstacle.status = "flying";
var tx =
Math.random() > 0.5
? -20 - Math.random() * 10
: 20 + Math.random() * 5;
TweenMax.to(obstacle.mesh.position, 4, {
x: tx,
y: Math.random() * 50,
z: 350,
ease: Power4.easeOut,
});
TweenMax.to(obstacle.mesh.rotation, 4, {
x: Math.PI * 3,
z: Math.PI * 3,
y: Math.PI * 6,
ease: Power4.easeOut,
onComplete: function () {
obstacle.status = "ready";
obstacle.body.rotation.y = Math.random() * Math.PI * 2;
obstacle.angle = -floorRotation - Math.random() * 0.4;
obstacle.angle = obstacle.angle % (Math.PI * 2);
obstacle.mesh.rotation.x = 0;
obstacle.mesh.rotation.y = 0;
obstacle.mesh.rotation.z = 0;
obstacle.mesh.position.z = 0;
},
});
monsterPosTarget -= 0.04;
TweenMax.from(this, 0.5, {
malusClearAlpha: 0.5,
onUpdate: function () {
renderer.setClearColor(malusClearColor, malusClearAlpha);
},
});
}
function updateDistance() {
distance += delta * speed;
var d = distance / 2;
fieldDistance.innerHTML = Math.floor(d);
}
function updateLevel() {
if (speed >= maxSpeed) return;
level++;
speed += 2;
}
function loop() {
delta = clock.getDelta();
updateFloorRotation();
if (gameStatus == "play") {
if (hero.status == "running") {
hero.run();
}
updateDistance();
updateMonsterPosition();
updateCarrotPosition();
updateObstaclePosition();
checkCollision();
}
render();
requestAnimationFrame(loop);
}
function render() {
renderer.render(scene, camera);
}
window.addEventListener("load", init, false);
function init(event) {
initScreenAnd3D();
createLights();
createFloor();
createHero();
createMonster();
createFirs();
createCarrot();
createBonusParticles();
createObstacle();
initUI();
resetGame();
loop();
}
function resetGame() {
scene.add(hero.mesh);
hero.mesh.rotation.y = Math.PI / 2;
hero.mesh.position.y = 0;
hero.mesh.position.z = 0;
hero.mesh.position.x = 0;
monsterPos = 0.56;
monsterPosTarget = 0.65;
speed = initSpeed;
level = 0;
distance = 0;
carrot.mesh.visible = true;
obstacle.mesh.visible = true;
gameStatus = "play";
hero.status = "running";
hero.nod();
audio.play();
updateLevel();
levelInterval = setInterval(updateLevel, levelUpdateFreq);
}
function initUI() {
fieldDistance = document.getElementById("distValue");
fieldGameOver = document.getElementById("gameoverInstructions");
}
Tree = function () {
this.mesh = new THREE.Object3D();
this.trunc = new Trunc();
this.mesh.add(this.trunc.mesh);
};
Trunc = function () {
var truncHeight = 50 + Math.random() * 150;
var topRadius = 1 + Math.random() * 5;
var bottomRadius = 5 + Math.random() * 5;
var mats = [
blackMat,
brownMat,
pinkMat,
whiteMat,
greenMat,
lightBrownMat,
pinkMat,
];
var matTrunc = blackMat;
var nhSegments = 3;
var nvSegments = 3;
var geom = new THREE.CylinderGeometry(
topRadius,
bottomRadius,
truncHeight,
nhSegments,
nvSegments
);
geom.applyMatrix(
new THREE.Matrix4().makeTranslation(0, truncHeight / 2, 0)
);
this.mesh = new THREE.Mesh(geom, matTrunc);
for (var i = 0; i < geom.vertices.length; i++) {
var noise = Math.random();
var v = geom.vertices[i];
v.x += -noise + Math.random() * noise * 2;
v.y += -noise + Math.random() * noise * 2;
v.z += -noise + Math.random() * noise * 2;
geom.computeVertexNormals();
if (Math.random() > 0.7) {
var size = Math.random() * 3;
var fruitGeometry = new THREE.CubeGeometry(size, size, size, 1);
var matFruit = mats[Math.floor(Math.random() * mats.length)];
var fruit = new THREE.Mesh(fruitGeometry, matFruit);
fruit.position.x = v.x;
fruit.position.y = v.y + 3;
fruit.position.z = v.z;
fruit.rotation.x = Math.random() * Math.PI;
fruit.rotation.y = Math.random() * Math.PI;
this.mesh.add(fruit);
}
if (Math.random() > 0.5 && v.y > 10 && v.y < truncHeight - 10) {
var h = 3 + Math.random() * 5;
var thickness = 0.2 + Math.random();
var branchGeometry = new THREE.CylinderGeometry(
thickness / 2,
thickness,
h,
3,
1
);
branchGeometry.applyMatrix(
new THREE.Matrix4().makeTranslation(0, h / 2, 0)
);
var branch = new THREE.Mesh(branchGeometry, matTrunc);
branch.position.x = v.x;
branch.position.y = v.y;
branch.position.z = v.z;
var vec = new THREE.Vector3(v.x, 2, v.z);
var axis = new THREE.Vector3(0, 1, 0);
branch.quaternion.setFromUnitVectors(axis, vec.clone().normalize());
this.mesh.add(branch);
}
}
this.mesh.castShadow = true;
};
</script>
</body>
</html>