Path: blob/main/public/games/files/garbage-collector/js/game.js
1036 views
/*jshint bitwise: false, camelcase: false*/1/*globals define*/2define(function( require ) {3'use strict';45var Box2D = require( 'box2d' );6var Input = require( 'input' );7var Intersection = require( 'geometry/intersection' );8var Camera = require( 'entities/camera' );9var Player = require( 'entities/player' );10var Explosion = require( 'entities/explosion' );11var Trigger = require( 'entities/trigger' );12var Door = require( 'entities/door' );13var Background = require( 'effects/background' );14var Shake = require( 'effects/shake' );15var Colors = require( 'config/colors' );16var Material = require( 'config/material' );17var Settings = require( 'config/settings' );18var world = require( 'world' );1920var DebugDraw = Box2D.Dynamics.b2DebugDraw;21var ContactListener = Box2D.Dynamics.b2ContactListener;2223function Game() {24this.prevTime = Date.now();25this.currTime = this.prevTime;2627this.running = true;2829this.element = document.createElement( 'div' );30this.canvas = document.createElement( 'canvas' );31this.ctx = this.canvas.getContext( '2d' );3233this.element.appendChild( this.canvas );3435var width = 640,36height = 480;3738this.canvas.width = width;39this.canvas.height = height;4041this.removed = [];4243this.entities = [];44this.player = null;4546this.camera = new Camera();47this.camera.margin = 10;48this.camera.world = this;4950this.shake = new Shake();5152this.level = null;5354this.input = new Input();55this.input.game = this;5657// dt should never exceed this (milliseconds).58this.MAX_FRAME_TIME = 1000 / 30;59this.MIN_FRAME_TIME = 1000 / 120;60// Frame time (seconds).61this.FRAME_TIME = 1 / 60;6263this.debug = false;64this.debugAABB = false;6566this.text = '';6768this.background = new Background( width, height );69this.background.camera = this.camera;70this.background.game = this;71this.background.prerender();7273this.world = world;74world.GetGravity().SetZero();7576// Debug view variables.77this.box2dDebug = false;78this.debugCanvas = null;79this.debugCtx = null;8081var contactListener = new ContactListener();8283function userData( fixture ) {84return fixture.GetBody().GetUserData();85}8687contactListener.BeginContact = function( contact ) {88var fixtureA = contact.GetFixtureA(),89fixtureB = contact.GetFixtureB();9091var a = userData( fixtureA ),92b = userData( fixtureB );9394// Handle player explosions.95var player, other;96if ( a instanceof Player && !fixtureB.IsSensor() ) {97player = a;98other = b;99} else if ( b instanceof Player && !fixtureA.IsSensor() ) {100player = b;101other = a;102}103104var explosion, fill;105if ( player && !( player.material & other.material ) &&106player.game && other.game ) {107player.emotion = Player.Emotion.HIT;108if ( player.emotionTimeout ) {109clearTimeout( player.emotionTimeout );110}111112player.emotionTimeout = setTimeout(function() {113player.emotion = Player.Emotion.NORMAL;114clearTimeout( player.emotionTimeout );115player.emotionTimeout = null;116}, 700 );117118if ( Settings.explosions ) {119fill = Colors.Explosion[ Material.type( other.material )];120121if ( fill ) {122explosion = new Explosion( other.x, other.y );123explosion.fill.set( fill );124this.add( explosion );125}126}127128this.shake.shake( 1, 0.4 );129this.removed.push( other );130return;131}132133// Handle explosions.134if ( !player &&135!fixtureA.IsSensor() &&136!fixtureB.IsSensor() &&137!( a.material & b.material ) &&138a.game &&139b.game ) {140var explosionA,141explosionB;142143var fillA,144fillB;145146if ( Settings.explosions ) {147fillA = Colors.Explosion[ Material.type( a.material )];148fillB = Colors.Explosion[ Material.type( b.material )];149150if ( fillA ) {151explosionA = new Explosion( a.x, a.y );152explosionA.fill.set( fillA );153this.add( explosionA );154}155156if ( fillB ) {157explosionB = new Explosion( b.x, b.y );158explosionB.fill.set( fillB );159this.add( explosionB );160}161}162163this.removed.push( a );164this.removed.push( b );165}166167// Handles trigger.168var trigger;169if ( a instanceof Trigger &&170!fixtureB.IsSensor() &&171!( b instanceof Player ) ) {172trigger = a;173other = b;174} else if ( b instanceof Trigger &&175!fixtureA.IsSensor() &&176!( a instanceof Player ) ) {177trigger = b;178other = a;179}180181if ( trigger &&182!trigger.active &&183( trigger.material & other.material ) ) {184trigger.object = other;185}186187// Handle door.188var door;189if ( a instanceof Door && b instanceof Player ) {190door = a;191player = b;192} else if ( b instanceof Door && a instanceof Player ) {193door = b;194player = a;195}196197if ( door && door.open ) {198door.player = player;199}200}.bind( this );201202world.SetContactListener( contactListener );203}204205Game.instance = null;206207Game.prototype.initializeDebugView = function() {208this.debugCanvas = document.createElement( 'canvas' );209this.debugCtx = this.debugCanvas.getContext( '2d' );210211document.body.appendChild( this.debugCanvas );212213this.debugCanvas.id = 'box2d-debug-canvas';214this.debugCanvas.width = this.canvas.width;215this.debugCanvas.height = this.canvas.height;216217var debugDraw = new DebugDraw();218debugDraw.SetSprite( this.debugCtx );219debugDraw.SetDrawScale( 1 );220debugDraw.SetFillAlpha( 0.3 );221debugDraw.SetLineThickness( 1 );222debugDraw.SetFlags( DebugDraw.e_shapeBit );223world.SetDebugDraw( debugDraw );224};225226Game.prototype.update = function() {227this.currTime = Date.now();228var dt = this.currTime - this.prevTime;229if ( dt < this.MIN_FRAME_TIME ) {230return;231}232233this.prevTime = this.currTime;234235if ( dt > this.MAX_FRAME_TIME ) {236dt = this.MAX_FRAME_TIME;237}238239dt *= 1e-3;240241this.input.update( dt );242// Camera controls.243if ( this.debug ) {244this.updateDebug( dt );245}246247this.entities.forEach(function( entity ) {248entity.update( dt );249});250251this.player.update( dt );252this.camera.update( dt );253this.shake.update( dt );254255this.world.Step( this.FRAME_TIME, 8, 3 );256257this.world.ClearForces();258259this.removed.forEach(function( removed ) {260this.remove( removed );261262if ( removed.body ) {263this.world.DestroyBody( removed.body );264}265}.bind( this ));266267this.removed = [];268};269270Game.prototype.draw = function() {271if ( this.box2dDebug ) {272this.drawDebug();273}274275var ctx = this.ctx;276277var level = this.level;278if ( level && level.fill.alpha ) {279ctx.fillStyle = level.fill.rgba();280ctx.fillRect( 0, 0, ctx.canvas.width, ctx.canvas.height );281} else {282ctx.clearRect( 0, 0, ctx.canvas.width, ctx.canvas.height );283}284285ctx.save();286this.camera.applyTransform( ctx );287this.shake.applyTransform( ctx );288289if ( Settings.background ) {290this.background.draw( ctx );291}292293this.entities.forEach(function( entity ) {294entity.draw( ctx );295});296297this.player.draw( ctx );298this.camera.draw( ctx );299300if ( this.debugAABB ) {301this.drawAABBs( ctx );302}303304ctx.restore();305306this.input.draw( ctx );307308if ( this.text ) {309ctx.font = this.font;310ctx.fillStyle = 'white';311ctx.textAlign = 'center';312ctx.textBaseline = 'middle';313314ctx.shadowBlur = 10;315ctx.shadowColor = 'black';316ctx.fillText( this.text, 0.5 * ctx.canvas.width, 0.25 * ctx.canvas.height );317ctx.shadowBlur = 0;318319ctx.textAlign = 'start';320ctx.textBaseline = 'alphabetic';321}322};323324Game.prototype.updateDebug = function( dt ) {325var aspectRatio = this.camera.width / this.camera.height;326// Basic camera controls.327// I. Zoom in.328if ( this.input.keys[ 73 ] ) {329this.camera.width = Math.max( this.camera.width - 1.5 * aspectRatio, 32 );330this.camera.height = Math.max( this.camera.height - 1.5, 24 );331}332// J. Zoom out.333if ( this.input.keys[ 74 ] ) {334this.camera.width += 1.5 * aspectRatio;335this.camera.height += 1.5;336}337// K. Rotate left.338if ( this.input.keys[ 75 ] ) {339this.camera.angle += dt;340}341// L. Rotate right.342if ( this.input.keys[ 76 ] ) {343this.camera.angle -= dt;344}345// O. Reset camera.346if ( this.input.keys[ 79 ] ) {347this.camera.width = 64;348this.camera.height = 48;349this.camera.angle = 0;350}351};352353Game.prototype.drawAABBs = function( ctx ) {354ctx.beginPath();355356var aabb;357this.entities.forEach(function( entity ) {358aabb = entity.aabb();359if ( aabb ) {360ctx.rect( aabb.xmin, aabb.ymin, aabb.xmax - aabb.xmin, aabb.ymax - aabb.ymin );361}362});363364aabb = this.player.aabb();365if ( aabb ) {366ctx.rect( aabb.xmin, aabb.ymin, aabb.xmax - aabb.xmin, aabb.ymax - aabb.ymin );367}368369aabb = this.camera.aabb();370if ( aabb ) {371ctx.rect( aabb.xmin, aabb.ymin, aabb.xmax - aabb.xmin, aabb.ymax - aabb.ymin );372}373374ctx.strokeStyle = '#f00';375ctx.lineWidth = 0.2;376ctx.stroke();377};378379Game.prototype.drawDebug = function() {380var debugCtx = this.debugCtx;381382var width = debugCtx.canvas.width,383height = debugCtx.canvas.height;384385debugCtx.clearRect( 0, 0, width, height );386debugCtx.save();387388debugCtx.translate( 0.5 * width, 0.5 * height );389this.world.DrawDebugData();390391debugCtx.restore();392};393394Game.prototype.tick = function() {395if ( !this.running ) {396return;397}398399this.update();400this.draw();401402window.requestAnimationFrame( this.tick.bind( this ) );403};404405Game.prototype.add = function( entity ) {406this.entities.push( entity );407entity.game = this;408};409410Game.prototype.remove = function( entity ) {411var index = this.entities.indexOf( entity );412if ( index !== -1 ) {413this.entities.splice( index, 1 );414entity.game = null;415}416};417418Game.prototype.setPlayer = function( player ) {419player.game = this;420this.player = player;421};422423/**424* Clear the world before loading the level.425*/426Game.prototype.clear = function() {427this.entities = [];428429var world = this.world;430world.ClearForces();431432var body = world.GetBodyList();433while ( body ) {434if ( !( body.GetUserData() instanceof Player ) ) {435world.DestroyBody( body );436}437438body = body.GetNext();439}440};441442Game.prototype.load = function( level ) {443level.entities.forEach(function( entity ) {444this.add( entity );445}.bind( this ));446};447448return Game;449});450451452