A proof of concept for a space ship configurator that i'm working on. :]
A Pen by Lewi Hussey on CodePen.
A proof of concept for a space ship configurator that i'm working on. :]
A Pen by Lewi Hussey on CodePen.
| <script src="https://code.jquery.com/jquery-3.1.0.min.js"></script> | |
| <h1>spacebar for Hyperdrive!</h1> | |
| <div class="distance"> | |
| <div> | |
| <span data-distance>0</span>km from home. | |
| </div> | |
| <div> | |
| <span data-speed>0</span>km per tick. | |
| </div> | |
| </div> | |
| <canvas id="ship"></canvas> | |
| <canvas id="bg"></canvas> |
| var c = document.getElementById('bg'); | |
| var ctx = c.getContext('2d'); | |
| var s = document.getElementById('ship'); | |
| var ship = s.getContext('2d'); | |
| var stars = []; | |
| var speed = 0.1; | |
| var maxSpeed = 200; | |
| var distance = 0; | |
| c.width = window.innerWidth; | |
| c.height = window.innerHeight; | |
| s.width = window.innerWidth; | |
| s.height = window.innerHeight; | |
| var shipCenter = {x: s.width / 2, y: s.height / 2 - 100}; | |
| var decreaseInterval = null; | |
| var flameEndX = shipCenter.x; | |
| draw(); | |
| createStars(); | |
| eventListeners(); | |
| function eventListeners(){ | |
| $('body').on('keydown', function(e){ | |
| switch(e.keyCode){ | |
| case 32: | |
| $('h1').addClass('pressed'); | |
| console.log(speed); | |
| clearInterval(decreaseInterval); | |
| if(speed < maxSpeed){ | |
| speed += (speed / 10); | |
| } | |
| break; | |
| } | |
| }); | |
| $('body').on('keyup', function(){ | |
| $('h1').removeClass('pressed'); | |
| decreaseInterval = setInterval(function(){ | |
| if(speed > 0.1){ | |
| decreaseSpeed(); | |
| } else { | |
| clearInterval(decreaseInterval); | |
| speed = .1; | |
| } | |
| }, 100); | |
| }); | |
| } | |
| function decreaseSpeed(){ | |
| speed -= (speed / 10); | |
| } | |
| function draw(){ | |
| drawBg(); | |
| drawStars(); | |
| moveStars(); | |
| drawSpeed(); | |
| clearShipBg(); | |
| drawRocketship(); | |
| updateDistance(); | |
| window.requestAnimationFrame(draw); | |
| } | |
| function drawBg(){ | |
| ctx.rect(0, 0, c.width, c.height); | |
| ctx.fillStyle = 'rgb(10, 15, 30)'; | |
| ctx.fill(); | |
| } | |
| function createStars(){ | |
| for(i = 0; i < 1000; i++){ | |
| stars.push({ | |
| x: Math.random() * 3000, | |
| y: Math.random() * 3000, | |
| r: Math.random() * 2, | |
| o: Math.random(), | |
| m: Math.random() | |
| }); | |
| } | |
| } | |
| function drawStars(){ | |
| for(i = 0; i < stars.length; i++){ | |
| // Draw trail | |
| if(speed > 100){ | |
| var alpha = (speed - 100) / 100; | |
| ctx.beginPath(); | |
| ctx.rect((stars[i].x - stars[i].r), stars[i].y, (stars[i].r * 2), 150); | |
| ctx.fillStyle = 'rgba(100, 150, 200, ' + alpha + ')'; | |
| ctx.closePath(); | |
| ctx.fill(); | |
| } | |
| // Draw normal stars | |
| ctx.beginPath(); | |
| ctx.arc(stars[i].x, stars[i].y, stars[i].r, 0, Math.PI * 2); | |
| ctx.fillStyle = 'rgba(255, 255, 255, ' + stars[i].o + ')'; | |
| ctx.closePath(); | |
| ctx.fill(); | |
| } | |
| } | |
| function moveStars(){ | |
| for(i = 0; i < stars.length; i++){ | |
| if(stars[i].y + .1 > c.height){ | |
| stars[i].y = -(Math.random() * 1000); | |
| } else { | |
| stars[i].y += (speed + stars[i].m); | |
| } | |
| // if(stars[i].x + .1 > c.width){ | |
| // stars[i].x = -(Math.random() * 1000); | |
| // } else { | |
| // stars[i].x += speed + 0.15; | |
| // } | |
| } | |
| } | |
| function clearShipBg(){ | |
| ship.clearRect(0, 0, s.width, s.height); | |
| } | |
| function drawRocketship(){ | |
| drawShipLeftWing(); | |
| drawShipRightWing(); | |
| drawShipBody(); | |
| drawShipHead(); | |
| drawWindow(); | |
| drawWindowShine(); | |
| drawShine(); | |
| drawFlames(shipCenter.y + 200, 'rgba(230, 110, 0, .8)'); | |
| drawFlames(shipCenter.y + 180, 'rgba(240, 150, 0, .9)'); | |
| drawFlames(shipCenter.y + 160, 'rgba(250, 170, 0, 1)'); | |
| changeFlameEnd(); | |
| ship.translate(shipCenter.x, (shipCenter.y + 50)); | |
| //ship.rotate(Math.PI / 3000); | |
| ship.translate(-shipCenter.x, (-shipCenter.y - 50)); | |
| } | |
| function changeFlameEnd(){ | |
| flameEndX = shipCenter.x + Math.random() * 5; | |
| } | |
| function drawShipLeftWing(){ | |
| ship.beginPath(); | |
| ship.moveTo(shipCenter.x, shipCenter.y + 50); | |
| ship.quadraticCurveTo(shipCenter.x - 80, shipCenter.y + 80, shipCenter.x - 30, shipCenter.y + 150); | |
| ship.quadraticCurveTo(shipCenter.x - 40, shipCenter.y + 90, shipCenter.x, shipCenter.y + 100); | |
| ship.fillStyle = 'rgb(200, 0, 0)'; | |
| ship.closePath(); | |
| ship.fill(); | |
| } | |
| function drawShipRightWing(){ | |
| ship.beginPath(); | |
| ship.moveTo(shipCenter.x, shipCenter.y + 50); | |
| ship.quadraticCurveTo(shipCenter.x + 80, shipCenter.y + 80, shipCenter.x + 30, shipCenter.y + 150); | |
| ship.quadraticCurveTo(shipCenter.x + 40, shipCenter.y + 90, shipCenter.x, shipCenter.y + 100); | |
| ship.fillStyle = 'rgb(200, 0, 0)'; | |
| ship.closePath(); | |
| ship.fill(); | |
| } | |
| function drawShipBody(){ | |
| ship.beginPath(); | |
| ship.moveTo(shipCenter.x, shipCenter.y); | |
| ship.bezierCurveTo(shipCenter.x - 40, shipCenter.y + 50, shipCenter.x - 30, shipCenter.y + 80, shipCenter.x - 20, shipCenter.y + 100); | |
| ship.lineTo(shipCenter.x + 20, shipCenter.y + 100) | |
| ship.bezierCurveTo(shipCenter.x + 30, shipCenter.y + 80, shipCenter.x + 40, shipCenter.y + 50, shipCenter.x, shipCenter.y); | |
| ship.fillStyle = 'rgb(200, 200, 200)'; | |
| ship.closePath(); | |
| ship.fill(); | |
| } | |
| function drawShipHead(){ | |
| ship.beginPath(); | |
| ship.moveTo(shipCenter.x, shipCenter.y); | |
| ship.quadraticCurveTo(shipCenter.x - 8, shipCenter.y + 10, shipCenter.x - 14, shipCenter.y + 20); | |
| ship.lineTo(shipCenter.x + 14, shipCenter.y + 20) | |
| ship.quadraticCurveTo(shipCenter.x + 8, shipCenter.y + 10, shipCenter.x, shipCenter.y); | |
| ship.fillStyle = 'rgb(200, 0, 0)'; | |
| ship.closePath(); | |
| ship.fill(); | |
| } | |
| function drawShine(){ | |
| ship.beginPath(); | |
| ship.moveTo(shipCenter.x, shipCenter.y + 15); | |
| ship.quadraticCurveTo(shipCenter.x - 30, shipCenter.y + 65, shipCenter.x - 10, shipCenter.y + 90); | |
| ship.lineWidth = 6; | |
| ship.lineCap = 'round'; | |
| ship.strokeStyle = 'rgba(255, 255, 255, .25)' | |
| ship.stroke(); | |
| ship.closePath(); | |
| } | |
| function drawWindow(){ | |
| ship.beginPath(); | |
| ship.arc(shipCenter.x, shipCenter.y + 50, 12, 0, Math.PI * 2); | |
| ship.lineWidth = 4; | |
| ship.strokeStyle = 'rgb(120, 120, 130)'; | |
| ship.fillStyle = 'rgb(100, 150, 250)'; | |
| ship.closePath(); | |
| ship.fill(); | |
| ship.stroke(); | |
| } | |
| function drawWindowShine(){ | |
| ship.beginPath(); | |
| ship.arc(shipCenter.x, shipCenter.y + 50, 10, Math.PI * 1.65, Math.PI * .65, true); | |
| ship.fillStyle = 'rgba(255, 255, 255, .25)'; | |
| ship.closePath(); | |
| ship.fill(); | |
| } | |
| function drawSpeed(){ | |
| var speedHeight = (speed / maxSpeed) * 100; | |
| ctx.beginPath(); | |
| ctx.rect(50, 50, 10, 100); | |
| ctx.fillStyle = 'rgba(255, 255, 255, .2)' | |
| ctx.closePath(); | |
| ctx.fill(); | |
| ctx.beginPath(); | |
| ctx.rect(50, 150 - speedHeight, 10, speedHeight); | |
| ctx.fillStyle = 'rgb(100, 220, 180)'; | |
| ctx.closePath(); | |
| ctx.fill(); | |
| } | |
| function updateDistance(){ | |
| distance += speed; | |
| $('[data-distance]').text(parseInt(distance)); | |
| $('[data-speed]').text(Math.ceil(speed) + '0'); | |
| } | |
| function drawFlames(flameHeight, color){ | |
| flameHeight += (speed / 3); | |
| ship.beginPath(); | |
| ship.moveTo(shipCenter.x, shipCenter.y + 110); | |
| ship.quadraticCurveTo(shipCenter.x - 40, shipCenter.y + 110, flameEndX, flameHeight); | |
| ship.quadraticCurveTo(shipCenter.x + 40, shipCenter.y + 110, shipCenter.x, shipCenter.y + 110); | |
| ship.fillStyle = color; | |
| ship.fill(); | |
| ship.closePath(); | |
| } |
| @import 'https://fonts.googleapis.com/css?family=Bungee'; | |
| $prim: rgb(50, 150, 220); | |
| *{ | |
| box-sizing: border-box; | |
| padding: 0; | |
| margin: 0; | |
| } | |
| body{ | |
| overflow: hidden; | |
| height: 100vh; | |
| width: 100vw; | |
| font-family: 'Bungee', sans-serif; | |
| } | |
| canvas{ | |
| position: fixed; | |
| top: 0; | |
| left: 0; | |
| } | |
| #ship{ | |
| z-index: 2; | |
| } | |
| h1{ | |
| position: fixed; | |
| bottom: 40px; | |
| left: calc(50% - 200px); | |
| width: 400px; | |
| text-align: center; | |
| color: rgb(70, 75, 80); | |
| padding: 14px 0 10px 0; | |
| z-index: 7; | |
| font-weight: 300; | |
| font-size: 18px; | |
| background-color: white; | |
| text-transform: uppercase; | |
| border-radius: 6px; | |
| border-bottom: 3px solid rgb(190, 190, 190); | |
| transition-duration: .25s; | |
| &.pressed{ | |
| background-color: $prim; | |
| color: white; | |
| border-bottom: 0; | |
| margin-top: 3px; | |
| } | |
| } | |
| .distance{ | |
| position: fixed; | |
| top: 20px; | |
| right: 20px; | |
| padding: 20px; | |
| color: white; | |
| z-index: 7; | |
| } |