feat: sound, generator, etc.

This commit is contained in:
Mahdi Dibaiee
2018-12-28 23:04:00 +03:30
parent e983346ffc
commit d6eaa09346
17 changed files with 233 additions and 98 deletions
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+6
View File
@@ -31,7 +31,9 @@
<script src='lib/physics-module.js'></script> <script src='lib/physics-module.js'></script>
<script src='lib/ammo.js'></script> <script src='lib/ammo.js'></script>
<script src='lib/mousetrap.js'></script> <script src='lib/mousetrap.js'></script>
<script src='lib/howler.min.js'></script>
<script src='lib/moment.min.js'></script> <script src='lib/moment.min.js'></script>
<script src='lib/color-scheme.min.js'></script>
</head> </head>
<body> <body>
<div id='gui'> <div id='gui'>
@@ -44,10 +46,14 @@
<p> <p>
Score: <span id='score'>000</span> Score: <span id='score'>000</span>
</p> </p>
<p>
Hits: <span id='hits'>00</span>
</p>
</div> </div>
<script src='src/utils.js'></script> <script src='src/utils.js'></script>
<script src='src/config.js'></script> <script src='src/config.js'></script>
<script src='src/audio.js'></script>
<script src='src/gui.js'></script> <script src='src/gui.js'></script>
<script src='src/objects.js'></script> <script src='src/objects.js'></script>
<script src='src/world.js'></script> <script src='src/world.js'></script>
+1
View File
File diff suppressed because one or more lines are too long
+4
View File
File diff suppressed because one or more lines are too long
+30
View File
@@ -0,0 +1,30 @@
const audio = {
fire: new Howl({
src: ['assets/audio/fire.wav'],
autoplay: true,
loop: true,
volume: 0.3
}),
music: new Howl({
src: ['assets/audio/music.mp3'],
autoplay: true,
loop: true,
volume: 0.1,
}),
rumble: new Howl({
src: ['assets/audio/rumble.wav'],
autoplay: false,
loop: true,
volume: 0.2,
}),
impacts: [0, 1, 2].map(i => new Howl({
src: [`assets/audio/impact-${i}.wav`],
volume: 0.5
})),
}
audio.fire.play();
audio.music.play();
+44 -57
View File
@@ -1,10 +1,5 @@
const RADIUS = 10; const RADIUS = 10;
const SEGMENTS = 40; const SEGMENTS = 40;
const material = new THREE.MeshLambertMaterial({
color: 0xFFFFFF,
emissive: 0xFF0000,
emissiveIntensity: 0.4,
});
const ballPhysics = new PHYSICS.SphereModule({ const ballPhysics = new PHYSICS.SphereModule({
mass: 2, mass: 2,
friction: 0.5, friction: 0.5,
@@ -20,7 +15,11 @@ const ball = new WHS.Sphere({
z: -30, z: -30,
y: 10 y: 10
}, },
material, material: new THREE.MeshLambertMaterial({
color: 0xFFFFFF,
emissive: 0xFF0000,
emissiveIntensity: 0.4,
}),
modules: [ modules: [
new WHS.TextureModule({ new WHS.TextureModule({
@@ -30,21 +29,16 @@ const ball = new WHS.Sphere({
], ],
}); });
const fireLight = new WHS.PointLight({
color: 0xff0000,
intensity: 5,
});
ball.physics = ballPhysics; ball.physics = ballPhysics;
ball.fireLight = fireLight;
ball.addTo(app); ball.addTo(app);
ball.add(fireLight);
camera.native.target = ball.native; camera.native.target = ball.native;
ball.checkLife = () => { ball.checkLife = () => {
if (ball.position.x > ground.geometry.parameters.width / 2 || ball.position.x < -ground.geometry.parameters.width / 2) { if (ball.position.x > ground.geometry.parameters.width / 2
|| ball.position.x < -ground.geometry.parameters.width / 2
|| ball.position.z > -ground.SIZE) {
location.reload(); location.reload();
} }
} }
@@ -79,66 +73,37 @@ ball.checkLife = () => {
color: 0xffffff, color: 0xffffff,
}); });
new THREE.Geometry();
var smokeCount = 2000,
smokes = new THREE.Geometry(),
smokeMaterial = new THREE.PointsMaterial({
size: 1.5,
transparent: true,
color: 0x666666,
opacity: 0.5,
});
const radius = ball.params.geometry.radius; const radius = ball.params.geometry.radius;
const start = ball.position; const start = ball.position;
for (var p = 0; p < particleCount; p++) { for (var p = 0; p < particleCount; p++) {
// create a particle with random
// position values, -250 -> 250
var pX = start.x + THREE.Math.randFloatSpread(radius), var pX = start.x + THREE.Math.randFloatSpread(radius),
pY = start.y + THREE.Math.randFloatSpread(radius), pY = start.y + THREE.Math.randFloatSpread(radius),
pZ = start.z + THREE.Math.randFloatSpread(radius), pZ = start.z + THREE.Math.randFloatSpread(radius),
particle = new THREE.Vector3(pX, pY, pZ) particle = new THREE.Vector3(pX, pY, pZ)
particle.lifetime = ball.params.geometry.radius + THREE.Math.randFloat(1, 1 + FIRE_HEIGHT_RANDOMNESS) * FIRE_HEIGHT; particle.lifetime = Math.random() < 0.5 ? 0 : ball.params.geometry.radius + THREE.Math.randFloat(0.5, 1 + FIRE_HEIGHT_RANDOMNESS) * FIRE_HEIGHT;
//particle.color.offsetHSL(Math.random(), 0, Math.random());
// add it to the geometry
particles.vertices.push(particle); particles.vertices.push(particle);
particles.colors.push(new THREE.Color(1, 0, 0)); particles.colors.push(new THREE.Color(1, 0, 0));
} }
particles.colorsNeedUpdate = true;
for (var i = 0; i < spriteCount; i++) { for (var i = 0; i < spriteCount; i++) {
var pX = start.x + THREE.Math.randFloatSpread(radius), var pX = start.x + THREE.Math.randFloatSpread(radius),
pY = start.y + THREE.Math.randFloatSpread(radius), pY = start.y + THREE.Math.randFloatSpread(radius),
pZ = start.z + THREE.Math.randFloatSpread(radius), pZ = start.z + THREE.Math.randFloatSpread(radius),
particle = new THREE.Vector3(pX, pY, pZ) particle = new THREE.Vector3(pX, pY, pZ)
particle.lifetime = ball.params.geometry.radius + THREE.Math.randFloat(1, 1 + FIRE_HEIGHT_RANDOMNESS) * FIRE_HEIGHT; particle.lifetime = Math.random() < 0.5 ? 0 : ball.params.geometry.radius + THREE.Math.randFloat(0.5, 1 + FIRE_HEIGHT_RANDOMNESS) * FIRE_HEIGHT;
sprites.vertices.push(particle); sprites.vertices.push(particle);
} }
for (var i = 0; i < smokeCount; i++) {
var pX = start.x + THREE.Math.randFloatSpread(radius),
pY = start.y + THREE.Math.randFloat(radius),
pZ = start.z + THREE.Math.randFloatSpread(radius),
particle = new THREE.Vector3(pX, pY, pZ);
particle.lifetime = ball.params.geometry.radius + THREE.Math.randFloat(1, 1 + FIRE_HEIGHT_RANDOMNESS) * FIRE_HEIGHT * 1.5;
smokes.vertices.push(particle);
}
// create the particle system // create the particle system
var points = WHS.MeshComponent.from(new THREE.Points(particles, pMaterial)); var points = WHS.MeshComponent.from(new THREE.Points(particles, pMaterial));
var spritesPoints = WHS.MeshComponent.from(new THREE.Points(sprites, spriteMaterial)); var spritesPoints = WHS.MeshComponent.from(new THREE.Points(sprites, spriteMaterial));
var smokePoints = WHS.MeshComponent.from(new THREE.Points(smokes, smokeMaterial));
smokePoints.isSmoke = true;
ball.fire = [points, spritesPoints, smokePoints]; ball.fire = [points, spritesPoints];
ball.fire.forEach(fire => { ball.fire.forEach(fire => {
fire.addTo(app); fire.addTo(app);
}) })
@@ -154,25 +119,32 @@ ball.checkLife = () => {
); );
fire.geometry.vertices.forEach((v, i) => { fire.geometry.vertices.forEach((v, i) => {
v.y += THREE.Math.randFloat(0, SPREAD_SPEED / 4); let x = v.x + THREE.Math.randFloatSpread(SPREAD_SPEED) + velocity.x * -0.02;
v.x += THREE.Math.randFloatSpread(SPREAD_SPEED) + velocity.x * -0.02; let y = v.y + THREE.Math.randFloat(0, SPREAD_SPEED / 4);
v.z += THREE.Math.randFloatSpread(SPREAD_SPEED) + velocity.z * -0.01; let z = v.z + THREE.Math.randFloatSpread(SPREAD_SPEED) + velocity.z * -0.01;
if (fire.material.vertexColors === THREE.VertexColors) { v.set(x, y, z);
if (!v.isSmoke && fire.material.vertexColors === THREE.VertexColors) {
fire.geometry.colors[i].offsetHSL(7e-4, 0, 0); fire.geometry.colors[i].offsetHSL(7e-4, 0, 0);
} }
if (v.y >= v.lifetime) { if (v.y >= v.lifetime) {
if (fire.isSmoke) { if (!v.isSmoke && fire.material.vertexColors === THREE.VertexColors) {
v.y = FIRE_HEIGHT/3 + THREE.Math.randFloat(0, FIRE_HEIGHT_RANDOMNESS); v.isSmoke = true;
fire.geometry.colors[i].setHex(0x444444)
v.lifetime += FIRE_HEIGHT * 0.5;
} else { } else {
v.y = Math.min(radius, radius * velocity.z / -50); y = Math.min(radius, radius * velocity.z / -50);
}
v.x = 0; x = 0;
v.z = -ball.params.geometry.radius * 3; z = -ball.params.geometry.radius * 3;
v.lifetime = ball.params.geometry.radius + THREE.Math.randFloat(1, 1 + FIRE_HEIGHT_RANDOMNESS) * FIRE_HEIGHT * (fire.isSmoke ? 1.5 : 1); v.lifetime = ball.params.geometry.radius + THREE.Math.randFloat(1, 1 + FIRE_HEIGHT_RANDOMNESS) * FIRE_HEIGHT;
v.set(x, y, z);
v.isSmoke = false;
if (fire.material.vertexColors === THREE.VertexColors) { if (fire.material.vertexColors === THREE.VertexColors) {
const r = THREE.Math.randFloat(0.8, 1); const r = THREE.Math.randFloat(0.8, 1);
@@ -181,6 +153,7 @@ ball.checkLife = () => {
fire.geometry.colors[i].setRGB(r, g, b); fire.geometry.colors[i].setRGB(r, g, b);
} }
} }
}
}); });
if (fire.material.vertexColors === THREE.VertexColors) { if (fire.material.vertexColors === THREE.VertexColors) {
@@ -189,5 +162,19 @@ ball.checkLife = () => {
fire.geometry.verticesNeedUpdate = true; fire.geometry.verticesNeedUpdate = true;
}); });
}); });
const fireLight = new WHS.PointLight({
color: 0xff0000,
intensity: 5,
});
ball.fireLight = fireLight;
ball.add(fireLight);
}()); }());
let hits = 0;
ball.on('collision', (o, v, r, cn) => {
if (o.uuid === ground.native.uuid) return;
rand(audio.impacts).play();
hits++;
GUI.setHits(hits);
});
+19 -15
View File
@@ -1,14 +1,18 @@
const DFORCE = 3e3; const DFORCE = 6e3;
const AFORCE = 500; const AFORCE = 500;
const VFORCE = 1e4; const VFORCE = 1e4;
Mousetrap.bind('left', () => { Mousetrap.bind('left', () => {
if (!ball.started) return; if (!ball.started) return;
const v = ball.physics.getLinearVelocity();
ball.physics.setLinearVelocity({ x: Math.min(0, v.x), y: v.y, z: v.z });
ball.physics.applyCentralForce({ x: -DFORCE, y: 0, z: 0 }); ball.physics.applyCentralForce({ x: -DFORCE, y: 0, z: 0 });
}); });
Mousetrap.bind('right', () => { Mousetrap.bind('right', () => {
if (!ball.started) return; if (!ball.started) return;
const v = ball.physics.getLinearVelocity();
ball.physics.setLinearVelocity({ x: Math.max(0, v.x), y: v.y, z: v.z });
ball.physics.applyCentralForce({ x: DFORCE, y: 0, z: 0 }); ball.physics.applyCentralForce({ x: DFORCE, y: 0, z: 0 });
}); });
@@ -19,20 +23,20 @@ Mousetrap.bind('up', () => {
//ball.methods.updateVelocity(); //ball.methods.updateVelocity();
}); });
Mousetrap.bind('space', () => { //Mousetrap.bind('space', () => {
if (!ball.started) return; //if (!ball.started) return;
if (ball.physics.data.touches.length) { //if (ball.physics.data.touches.length) {
ball.physics.applyCentralForce({ x: 0, y: VFORCE, z: 0 }); //ball.physics.applyCentralForce({ x: 0, y: VFORCE, z: 0 });
} //}
//ball.speed = Math.min(config.MAX_SPEED, Math.max(config.FINAL_SPEED, ball.speed + config.SPEED_INCREASE)); ////ball.speed = Math.min(config.MAX_SPEED, Math.max(config.FINAL_SPEED, ball.speed + config.SPEED_INCREASE));
//ball.methods.updateVelocity(); ////ball.methods.updateVelocity();
}); //});
Mousetrap.bind('down', () => { //Mousetrap.bind('down', () => {
if (!ball.started) return; //if (!ball.started) return;
ball.physics.applyCentralForce({ x: 0, y: 0, z: AFORCE * 3 }); //ball.physics.applyCentralForce({ x: 0, y: 0, z: AFORCE * 3 });
//ball.speed = Math.min(config.MAX_SPEED, Math.max(config.FINAL_SPEED, ball.speed - config.SPEED_INCREASE)); ////ball.speed = Math.min(config.MAX_SPEED, Math.max(config.FINAL_SPEED, ball.speed - config.SPEED_INCREASE));
//ball.methods.updateVelocity(); ////ball.methods.updateVelocity();
}); //});
+4
View File
@@ -3,6 +3,7 @@ const GUI = {
score: document.getElementById('score'), score: document.getElementById('score'),
speed: document.getElementById('speed'), speed: document.getElementById('speed'),
time: document.getElementById('time'), time: document.getElementById('time'),
hits: document.getElementById('hits'),
}, },
setScore(s) { setScore(s) {
GUI.elements.score.textContent = Math.floor(s).toString().padStart(3, '0'); GUI.elements.score.textContent = Math.floor(s).toString().padStart(3, '0');
@@ -13,6 +14,9 @@ const GUI = {
setStartingTime() { setStartingTime() {
GUI.startingTime = moment(); GUI.startingTime = moment();
}, },
setHits(s) {
GUI.elements.hits.textContent = Math.floor(s).toString().padStart(2, '0');
},
tickTime() { tickTime() {
const now = moment(); const now = moment();
const diff = moment.duration(now.diff(GUI.startingTime)); const diff = moment.duration(now.diff(GUI.startingTime));
+109 -18
View File
@@ -1,36 +1,127 @@
function level0() { function level0() {
function jumpBoard(x, z) { const step = rad(10);
const cylinder = new WHS.Cylinder({ const tan = Math.tan(step);
const BOX_SIZE = 100;
function add({ x, y, z } = {}, { width, depth, height } = {}, rotation = {}) {
y = y || (tan * z) + BOX_SIZE/2;
width = width || BOX_SIZE;
height = height || BOX_SIZE;
depth = depth || BOX_SIZE;
rotation.x = rotation.x || -step;
const box = new WHS.Box({
geometry: { geometry: {
radiusTop: 50, width,
radiusBottom: 1, depth,
radiusSegments: 3, height,
heightSegments: 1,
height: 2,
}, },
material: new THREE.MeshPhongMaterial({ material: new THREE.MeshPhongMaterial({
color: 0xffff00, color: 0xffffff,
}), }),
position: [x, 0, z], position: [x, y, z],
rotation: [Math.PI, rad(-35), 0],
rotation,
modules: [ modules: [
new PHYSICS.CylinderModule({ new PHYSICS.BoxModule({
mass: 0, mass: 0,
friction: 1,
restitution: 0,
}) })
] ]
}); });
//cylinder.addTo(app); box.addTo(app);
ground.add(cylinder); return box;
} }
//jumpBoard(5, -50); const SPACE_UNIT = 250;
//jumpBoard(5, -100);
// const patterns = [{
//ring({ x: 0, y: 10, z: -150 }); items: [3,4,5],
randoms: {
startX() {
return Math.random() > 0.5 ? 200 : -200;
},
},
x(i, props) {
return props.startX + i * 50 * (props.startX === 200 ? -1 : 1);
},
z(i) {
return i * -BOX_SIZE;
},
}, {
items: [3,4,6],
props: {
side: 150,
},
rot: {
y(i, props) {
if (i % 3 == 0) {
return THREE.Math.randFloatSpread(Math.PI);
}
return 0;
}
},
size(i, props) {
return THREE.Math.randInt(BOX_SIZE * 0.8, BOX_SIZE * 1.2);
},
x(i, props) {
if (i % 3 == 0) {
return 0;
} else {
return i % 3 == 1 ? props.side : -props.side;
}
},
z(i) {
if (i % 3 == 0) {
return i * -SPACE_UNIT;
} else {
return i % 3 == 1 ? i * -SPACE_UNIT : (i - 1) * -SPACE_UNIT;
}
}
}];
const applyPattern = (sz, { items, x, z, rot, props, randoms, space, size } = {}) => {
props = props || {};
randoms = randoms || {};
space = space || SPACE_UNIT;
rot = rot || {};
const count = rand(items);
const rs = {};
Object.entries(randoms).forEach(([key, value]) => {
rs[key] = value();
});
Object.assign(props, rs);
let zz;
for (let i = 0; i < count; i++) {
zz = sz + z(i, props);
const rotation = {};
Object.entries(rot).forEach(([key, value]) => {
rotation[key] = value(i, props);
});
let boxSize = BOX_SIZE;
if (size) {
boxSize = size(i, props);
}
add({ x: x(i, props), z: zz }, { width: boxSize, height: boxSize, depth: boxSize }, rotation);
}
return zz - space;
}
let sz = -300;
while (-sz < ground.SIZE) {
const pattern = rand(patterns);
sz = applyPattern(sz, pattern);
}
} }
level0();
+5 -1
View File
@@ -40,9 +40,13 @@ const entrance = () => {
GUI.setStartingTime(); GUI.setStartingTime();
const diff = camera.position.y - ball.position.y; const diff = camera.position.y - ball.position.y;
ball.started = true; ball.started = true;
level0();
audio.rumble.play();
app.physics.addEventListener('update', function() { app.physics.addEventListener('update', function() {
camera.position.set(camera.position.x, ball.position.y + diff, ball.position.z + 130); //camera.position.set(camera.position.x, ball.position.y + diff, ball.position.z + 130);
camera.position.set(ball.position.x, ball.position.y + diff, ball.position.z + 130);
camera.native.lookAt(ball.position); camera.native.lookAt(ball.position);
directionalLight.position.set(directionalLight.position.x, directionalLight.position.y, ball.position.z - 300); directionalLight.position.set(directionalLight.position.x, directionalLight.position.y, ball.position.z - 300);
GUI.setScore(-ball.position.z / 100); GUI.setScore(-ball.position.z / 100);
+2
View File
@@ -1,2 +1,4 @@
const rad = (deg) => deg * Math.PI / 180; const rad = (deg) => deg * Math.PI / 180;
const rand = (items) => items[Math.floor(Math.random() * items.length)];
+4 -2
View File
@@ -34,7 +34,7 @@ let ground;
(function groundinit() { (function groundinit() {
const WIDTH = 500; const WIDTH = 500;
const SIZE = 1e5; const SIZE = 1e5;
const mesh = new WHS.Plane({ ground = new WHS.Plane({
geometry: { geometry: {
width: WIDTH, width: WIDTH,
height: SIZE, height: SIZE,
@@ -51,12 +51,14 @@ let ground;
}), }),
new PHYSICS.PlaneModule({ new PHYSICS.PlaneModule({
mass: 0, mass: 0,
restitution: 0,
}), }),
], ],
material: new THREE.MeshPhongMaterial({ color: 0xffffff }) material: new THREE.MeshPhongMaterial({ color: 0xffffff })
}); });
ground = mesh; ground.SIZE = SIZE;
ground.addTo(app); ground.addTo(app);
}()); }());