Skip to content

Instantly share code, notes, and snippets.

@shshaw
Last active December 14, 2016 02:53
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save shshaw/15ecb75c79b4cee0d6f74b7aadeb86a8 to your computer and use it in GitHub Desktop.
Save shshaw/15ecb75c79b4cee0d6f74b7aadeb86a8 to your computer and use it in GitHub Desktop.
Space Joyride πŸš€+⭐+πŸ•Ή (#3December - Day 13)
<div class="controls">Thrust with <key>W</key>, click or touch. Steer with <key>left</key>/<key>right</key>, <key>A</key>/<key>D</key>, mouse or touch.</div>
<script id="vertexShader" type="x-shader/x-vertex">
varying vec3 vNormal;
void main()
{
vNormal = normalize( normalMatrix * normal );
gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );
}
</script>
<script id="fragmentShader" type="x-shader/x-vertex">
varying vec3 vNormal;
void main()
{
float intensity = pow( 0.6 - dot( vNormal, vec3( 0.0, 0.0, 1.0 ) ), 4.0 );
gl_FragColor = vec4( 1.0, 1.0, 0.5, 0.9 ) * intensity;
}
</script>
console.clear();
var renderCalls = [];
function render () {
requestAnimationFrame( render );
renderCalls.forEach((callback)=>{ callback(); });
}
render();
/*////////////////////////////////////////*/
var keys = [];
document.body.addEventListener("keydown", function(e) {
keys[e.keyCode] = true;
e.preventDefault();
});
document.body.addEventListener("keyup", function(e) {
keys[e.keyCode] = false;
e.preventDefault();
});
/*////////////////////////////////////////*/
var pointer = {
down: false,
x: 0,
y: 0,
onDown: function(e){
pointer.down = true;
pointerMove(e);
},
onUp: function(e){
pointer.down = false;
pointerMove(e);
}
};
document.addEventListener('mousedown', pointer.onDown);
document.addEventListener('touchstart', pointer.onDown);
document.addEventListener('mouseup', pointer.onUp);
document.addEventListener('touchend', pointer.onUp);
document.addEventListener('mousemove', pointerMove);
document.addEventListener('touchmove', pointerMove);
function pointerMove(e){
let pos = e.touches ? e.touches[0] : e;
pointer.x = pos.clientX / window.innerWidth;
pointer.y = pos.clientY / window.innerWidth;
};
/*////////////////////////////////////////*/
var scene, renderer, orbit, light;
/*////////////////////////////////////////*/
var camera = new THREE.PerspectiveCamera( 75, window.innerWidth / window.innerHeight, 10, 3000 );
camera.position.z = 600;
/*////////////////////////////////////////*/
scene = new THREE.Scene();
//scene.fog = new THREE.FogExp2( 0x000000, 0.0005);//new THREE.Fog(0xEEEEEE, 20, 600);
renderer = new THREE.WebGLRenderer( { antialias: true } );
renderer.setPixelRatio( window.devicePixelRatio );
renderer.setSize( window.innerWidth, window.innerHeight );
renderer.setClearColor( 0x060712 );
renderer.toneMapping = THREE.LinearToneMapping;
renderer.toneMappingExposure = Math.pow( 0.91, 5.0 );
if ( window.innerWidth > 500 ) {
renderer.shadowMap.enabled = true;
renderer.shadowMap.type = THREE.PCFSoftShadowMap;
}
window.addEventListener( 'resize', function () {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize( window.innerWidth, window.innerHeight );
}, false );
document.body.appendChild( renderer.domElement);
renderCalls.push(function(){ renderer.render( scene, camera ); });
/*////////////////////////////////////////*/
var ambientLight = new THREE.AmbientLight(0x222222);
scene.add(ambientLight);
var hemiLight = new THREE.HemisphereLight( 0xEBF7FD, 0xFFF7EB, 0.3 );
//hemiLight.color.setRGB(0.75,0.8,0.95);
hemiLight.position.set( 0, 100, 0 );
scene.add( hemiLight );
/*////////////////////////////////////////*/
function makeSun(){
var geometry = new THREE.SphereGeometry( 80, 24, 8 );
var customMaterial = new THREE.ShaderMaterial({
uniforms: { },
vertexShader: document.getElementById( 'vertexShader' ).textContent,
fragmentShader: document.getElementById( 'fragmentShader' ).textContent,
side: THREE.BackSide,
blending: THREE.AdditiveBlending,
transparent: true
});
let sun = new THREE.Mesh( geometry, customMaterial );
let light = new THREE.PointLight( 0xffffaa, 1 );
light.power = 20;
//light.position.y = 400;
sun.add( light );
let light2 = new THREE.PointLight( 0xffffaa, 1 );
light2.power = 20;
sun.add( light2 );
return sun;
}
var sun = makeSun();
scene.add( sun );
/*////////////////////////////////////////*/
function makePlanet(size, distance, color, speed){
size = size || 30,
distance = distance || 300;
speed = speed || 0.001;
color = color || 0x6DECB9;
let pivot = new THREE.Group();
var geometry = new THREE.SphereGeometry( size, 16, 16 );
var material = new THREE.MeshLambertMaterial( {
color: color,
emissive: 0x11999E,
emissiveIntensity: 0.3,
//shininess: 0,
reflectivity: 3,
});
let planet = new THREE.Mesh( geometry, material );
pivot.add(planet);
planet.position.z = distance;
pivot.rotation.y = Math.PI * (Math.random() - Math.random());
renderCalls.push(function(){
pivot.rotation.y -= 0.001;
planet.rotation.y += 0.005;
//pivot.rotation.x += 0.1006;
});
return pivot;
}
var planet = makePlanet(25, 200, 0xB74242);
planet.rotation.x = Math.PI/7;
scene.add(planet);
var planet2 = makePlanet(15, 400, 0x6DECB9, 0.002);
planet2.rotation.x = Math.PI/7;
scene.add( planet2 );
var planet3 = makePlanet(40, 700, 0xE3CE8B, 0.002);
planet3.rotation.x = Math.PI/7;
scene.add( planet3 );
/*////////////////////////////////////////*/
const TWOPI = Math.PI * 2;
const rad2deg = Math.PI * 180;
function ease(current,target,ease){
return current + (target - current) * ( ease || 0.2 );
}
function getDistance(x1, y1, x2, y2){
return Math.sqrt( (x1-x2)*(x1-x2) + (y1-y2)*(y1-y2) );
}
/*////////////////////////////////////////*/
// fire = new Fire();
// fire.position.y = 10;
let colors = [ 0xdb2902, 0xfb4402 ];
function Flame(color){
THREE.Group.apply(this,arguments);
var light = new THREE.PointLight( colors[1] || 0xFFFFFF , 1, 0 );
light.castShadow = true;
light.shadow.mapSize.width = 512;
light.shadow.mapSize.height = 512;
light.shadow.camera.near = 0.1;
light.shadow.camera.far = 120;
light.shadow.bias = 0.9;
light.shadow.radius = 5;
light.power = 6;
this.light = light;
this.light.position.z -= 6;
this.light.position.y += 2;
this.add( this.light );
let geometry = new THREE.CylinderGeometry( 2.5, 4, 1, 4 ); //new THREE.BoxGeometry(10,10,10);
let material = new THREE.MeshPhongMaterial({
color: color,
//specular: 0x009900,
shininess: 50,
emissive: color,
transparent: true,
opacity: 0.6,
shading: THREE.FlatShading
});
let flame = new THREE.Mesh( geometry, material );
this.flame = flame;
this.add( flame );
}
Flame.prototype = Object.assign(THREE.Group.prototype, {
constructor: Flame,
});
function Ship(){
THREE.Object3D.call(this);
let material = new THREE.MeshPhongMaterial({
color: 0xEEEEEE,
shininess: 200,
shading: THREE.SmoothShading
});
let geometry = new THREE.CylinderGeometry(12, 8, 20, 3, 1, false, Math.PI/2, Math.PI);
let body = new THREE.Mesh( geometry, material );
body.rotation.x = Math.PI / 2;
body.receiveShadow = true;
body.castShadow = true;
this.add(body);
let domeGeometry = new THREE.SphereGeometry(3, 4, 4, 0, Math.PI);
let domeMaterial = new THREE.MeshPhongMaterial({
color: 0xAAAAFF,
emissive: 0xAAAAFF,
emissiveIntensity: 0.8,
shininess: 500,
transparent: true,
opacity: 0.8,
shading: THREE.SmoothShading
});
let dome = new THREE.Mesh(domeGeometry, domeMaterial);
dome.position.y = 8;
dome.rotation.x = Math.PI / -2;
this.add(dome);
let flame = new Flame(colors[0]);
flame.position.z = 15;
flame.position.y = 7;
flame.rotation.x = Math.PI / 2;
flame.rotation.y = Math.PI;
this.add(flame);
let count = 0;
renderCalls.push(()=>{
count +=0.01;
flame.light.power = 4 + 6 * Math.sin( Math.abs(this.speed) + (Math.random() * 0.1));
//flame.rotation.y = Math.abs(this.speed)/4 * count * Math.PI/4;
flame.scale.y = 1 + ( 0.5 * this.speed * (Math.random()+0.8) + (Math.sin(count)+1/2))
});
}
Ship.prototype = Object.assign(THREE.Object3D.prototype,{
constructor: Ship,
maxspeed: 3,
speed: 0,
angle: 0,
steering: 0,
angleV: 0,
steeringV: 0,
acceleration: 0.015,
decceleration: 0.999,
steerPower: 0.0002,
controls: true,
control: function(){
if ( !this.controls ) { return; }
// steering
if ( pointer.down ) {
this.steering += this.steerPower * (pointer.x - 0.5) * 0.25;
this.steeringV += this.steerPower * (pointer.y - 0.5);
} else if ( keys[39] || keys[68] ) {
this.steering += ( this.steering > -.01) ? this.steerPower : 0;
// left
} else if ( keys[37] || keys[65] ) {
this.steering -= ( this.steering < .01) ? this.steerPower : 0;
} else {
this.steering *= 0.98;
}
// gas
if ( keys[38] || keys[87] || pointer.down ) {
this.speed += (this.speed < this.maxspeed) ? this.acceleration : 0;
} else if ( keys[40] || keys[83] ) { // reverse
this.speed -= (this.speed > -this.maxspeed/2 )? this.acceleration : 0;
} else {
this.speed *= 0.995;
}
this.speed *= 1 - Math.abs(this.steering/2);
this.angle += this.steering * this.speed;
this.angleV += this.steeringV * this.speed;
},
keepInBounds(){
if ( this.tl ) { return; }
let near = getDistance(this.position.x, this.position.z, 0, 0) < 35;
let far = getDistance(this.position.x, this.position.z, 0, 0) > 950;
if ( near || far ) {
this.controls = false;
console.log('out of bounds!');
var tl = new TimelineLite({
onComplete: function(){ this.controls = true; this.tl = null; },
onCompleteScope: this
});
tl.to(this.position, 0.8, {
x: this.position.x * ( near ? 4 : 0.90 ),
z: this.position.z * ( near ? 4 : 0.90 ),
ease: Cubic.easeInOut
})
tl.to(this, 0.7, {
angle: this.angle + ( this.speed > 0 ? ( this.angle > Math.PI ? -Math.PI : Math.PI ) : 0 ),
speed: this.speed * 0.2,
ease: Cubic.easeInOut
},0);
this.tl = tl;
}
},
// Driving controls adapted from http://codepen.io/Beclamide/pen/bNyxVz?editors=0010
update(){
var prev = {
x: this.position.x,
y: this.position.y,
z: this.position.z,
rot: this.rotation.y
}
this.control();
var xdir = this.speed * Math.cos(this.angle);
var ydir = this.speed * Math.sin(this.angle);// * Math.cos(this.angleV);
var zdir = this.speed * Math.sin(this.angleV)+1/2;
this.position.z += -xdir;
this.position.x += ydir;
//this.position.y += zdir;
this.rotation.y = -this.angle;
//this.rotation.z = this.angleV;
this.keepInBounds();
camera.position.x = ease(camera.position.x, 50 * (this.steering * this.speed * 20),0.05); //ease(camera.position.y, 50 + ( 10 * this.speed ),0.05);
camera.position.z = ease(camera.position.z, 100 + 20 * (this.speed),0.05);
camera.position.y = ease(camera.position.y, 50 + ( 10 * this.speed ),0.05);//( this.position.y - camera.position.y + (60 - ( this.speed / 2 ) * 10 ) );
},
// update: function () {
// // Get the direction we are facing
// var radians = this.angle/(ra2deg);
// if(this.isThrusting){
// this.velX += Math.cos(radians) * this.thrust;
// this.velY += Math.sin(radians) * this.thrust;
// }
// // calc the point out in front of the ship
// this.px = this.x - this.pointLength * Math.cos(radians);
// this.py = this.y - this.pointLength * Math.sin(radians);
// // apply friction
// this.velX *= 0.985;
// this.velY *= 0.985;
// // apply velocities
// this.x -= this.velX;
// this.y -= this.velY;
// }
});
let ship = new Ship();
ship.add(camera);
ship.position.z = 350;
camera.position.y = 50;
camera.position.z = 100;
renderCalls.push(ship.update.bind(ship));
scene.add(ship);
/*////////////////////////////////////////*/
function makeSprite(spriteSize){
let canvas = document.createElement('canvas'),
ctx = canvas.getContext('2d');
spriteSize = spriteSize || 32;
canvas.width = canvas.height = spriteSize * 2;
ctx.fillStyle = '#FFF';
ctx.beginPath();
ctx.arc( spriteSize, spriteSize, spriteSize, 0, TWOPI, true );
ctx.fill();
let sprite = new THREE.Texture(canvas);
sprite.needsUpdate = true;
return sprite;
}
function makeStars() {
let starMaterial = new THREE.PointsMaterial({
size: 4,
map: makeSprite(),
blending: THREE.AdditiveBlending
});
let geometry = new THREE.SphereGeometry(1200, 100, 100);
for (let i = 0, len = geometry.vertices.length; i < len; i++){
let vertex = geometry.vertices[i];
vertex.x += Math.random() * -500;
vertex.y += Math.random() * -500;
vertex.z += Math.random() * -500;
}
geometry.verticesNeedUpdate = true;
geometry.normalsNeedUpdate = true;
geometry.computeFaceNormals();
// let starQty = 3000;
// let geometry = new THREE.Geometry();//;
// for (var i = 0; i < starQty; i++) {
// var starVertex = new THREE.Vector3();
// starVertex.x = Math.random() * 1000 - 500; //500 - 250;
// starVertex.y = Math.random() * 1000 - 500; //500 - 250;
// starVertex.z = Math.random() * 1000 - 500; //500 - 250;
// geometry.vertices.push(starVertex);
// }
return new THREE.Points(geometry, starMaterial);
}
let stars = makeStars()
scene.add(stars);
<script src="http://codepen.io/shshaw/pen/epmrgO"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r79/three.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/1.19.0/TweenMax.min.js"></script>
<script src="https://threejs.org/examples/js/controls/OrbitControls.js"></script>
canvas { display: block; }
.controls { position: absolute; bottom: 0; left: 0; right: 0; padding: 2em; z-index: 10; font-size: 10px; color: #FFF; opacity: 0.6; }
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment