Upgrade to Pro — share decks privately, control downloads, hide ads and more …

How We Built It: Pixels At Dawn

How We Built It: Pixels At Dawn

A look at Team +rehabstudio's entry to the 7 Day FPS (7DFPS) 2013 game jam: Pixels At Dawn.

Neil McCallion

August 30, 2013
Tweet

More Decks by Neil McCallion

Other Decks in Programming

Transcript

  1. Wolfenstein 3D, Doom, Duke Nukem 3D, Quake, System Shock, Half-Life,

    Bioshock, Medal Of Honor, Call Of Duty, etc etc.... #7DFPS FPS - First-Person Shooter Design and build an innovative FPS in 7 days, because Call Of Duty sucks ass.
  2. - Inverted/subverted FPS tropes - Easy-to-grasp gameplay - Simple aesthetics

    - Fun factor & replayability - Complex mechanics & systems - Story and narrative - High-grade visuals & e ects - Advanced logic 7 Days* - Time Is The Enemy * actually 7 lunchtimes + evenings Good Bad
  3. 1990s-style 2-player means: - No level design - No enemy

    AI - No 3D models - No physics - No dynamic lighting - No scripted events or narrative - Minimal controls - It’s “supposed” to look like shit and also means we “innovate”: Them: - America Fuck Yeah - Ammo spewing - Massive body count - Regenerating health - Superhuman aim - Photorealism Us: - Blackadder II - Every shot counts - Kill that one guy - Paper cut of death - Got the shakes - LOL pixels
  4. Tech Why build in-browser? - Javascript - WebGL - Node

    - Websockets - HTML5 APIs - Audio - Local Storage - Pointer Lock - CSS3 - Can use existing tools and work ow - Small ramp-up time - Easy to publish and share - No plugins or downloads required - Transferrable skills Libraries - jQuery - THREE.js
  5. WebGL OpenGL + Javascript API = hardware 3D in the

    browser THREE.js Most popular framework for creating WebGL apps Games, interactive 360 video, product showcases, infographics, VR walkthroughs, showcases, tech demos, and more
  6. Geometry Material Mesh + = CircleGeometry ConvexGeometry CubeGeometry CylinderGeometry ExtrudeGeometry

    IcosahedronGeometry LatheGeometry OctahedronGeometry ParametricGeometry PlaneGeometry PolyhedronGeometry ShapeGeometry SphereGeometry TetrahedronGeometry TextGeometry TorusGeometry TorusKnotGeometry TubeGeometry LineBasicMaterial LineDashedMaterial MeshBasicMaterial MeshDepthMaterial MeshFaceMaterial MeshLambertMaterial MeshNormalMaterial MeshPhongMaterial ParticleBasicMaterial ParticleCanvasMaterial ParticleDOMMaterial ShaderMaterial SpriteMaterial position x, y, z rotation x, y, z opacity transform color etc. jpg, png, canvas, video, etc... Y - up/down X - left/right Z - in/out
  7. Scene Light Camera The render loop Get keyboard & mouse

    control input Update camera and objects (position, rotation, etc) Render the camera’s current view of the scene Draw the view to the canvas requestAnimationFrame
  8. Art Direction - ‘90s baroque’ - Pixels everywhere - Sprites,

    not models - Decorations always face the camera - Pallette swapping - Enemies have 8 rotations - ‘Heads-up’ title screen - Casual violence and gore - Poor draw distance - Arcade-style prompts (e.g RELOAD, FIGHT, etc) - Tasteless humour
  9. Asset work ow 3D model created and posed in Blender

    Individual animation frames exported as PNG // originalImage = preloaded exported img from Blender var context = canvas.getContext(’2d’); context.scale(-1, 1); // flips canvas horizontally context.drawImage(originalImage, 0, 0); var flippedTexture = new THREE.Texture(canvas); Mirror frames generated via Canvas on app init
  10. Inheritance THREE.Mesh { position rotation geometry material opacity transform update()

    { // get ready to render } } Billboard { position rotation geometry material opacity transform update() { // face the camera // THREE.Mesh.update() } } Gib { position rotation geometry material opacity transform velocity direction update() { // Billboard.update() // move and rotate me } } Extending THREE.js objects extend extend Billboard = function(geometry, material) { THREE.Mesh.call( this, geometry, material ); }; Billboard.prototype = Object.create( THREE.Mesh.prototype );
  11. More 1990s WebGL fakery Poor draw distance -> WebGl fog

    scene.fog = new THREE.Fog(0x666666, 250, 2500); Pixels galore -> nearest- neighbour ltering texture.minFilter = texture.magFilter = THREE.NearestFilter;
  12. Shoot Him Sir! - Raycasting Camera + Raycaster Ray Intersection

    point XYZ - Cast a ray from the camera position - Randomly o set ray XY based on aiming radius - If rst intersection is not the enemy, automatic miss - Map the intersection point XY to the current enemy animation texture - If texture pixel at this co-ordinate has alpha=0, miss - Otherwise, hit - Kill enemy and/or go to reload state as needed getImageData().data: 0: r, 1: g, 2: b, 3: alpha context.drawImage(enemy.material.map.image, 0, 0); var alpha = context.getImageData(shotX, shotY, 1, 1).data[3]; var isHit = (alpha > 0);
  13. Other Cool Shit CSS3 Keyframe Animations CSS3 Transitions @-webkit-keyframes fog

    { 0% { opacity: 0.6; background-position: 0 0; } 50% { opacity: 0.2; } 100% { opacity: 0.6; background-position: 512px 512px; } } #gun { bottom: -10%; left: 70%; transition: all 0.1s; } #gun.aim { bottom: 0; left: 50%; } #gun.reload { bottom: -20%; left: 40%; } HTML5 LocalStorage $(’#volume’).on(’change’, function() { window.localStorage[’volume’] = this.val(); }); var currentVolume = window.localStorage[’volume’];
  14. Backend - Node.js Setup Server con g Javascript architecture -

    Standard Node.js (0.10+) install - package.json included in repo for dependency auto-install - nginx (1.4+) reverse proxy - port 8081 to 80 - also forwards Web proxy requests - SocketIO used for low-latency messaging between clients Master’ singleton to track both players’ Duel objects - Tracks and sets the local game phase (Ready, Walk, Turn & Fire, etc) for a player - Manages countdown timers, scores, etc. - Syncs updates to/from opponent via SharedState - Only one Duel instance will be ‘in control’ at a time Listens for changes and emits them to all other SharedState instances Registry Duel SharedState package.json: "express": "3.x", "mongodb": "~1.3.18", "socket.io": "~0.9.16", "mongoose": "~3.6.16", "ejs": "~0.8.4", "node-uuid": "~1.4.0" Registry Duel 2 Duel 1 SharedState SharedState