123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466 |
- /*
- game coordinate system:
- +y
- |
- -x --+-- +x
- |
- -y
- */
- var Game = function(options) {
-
- var defaults = {
- maxEntities: 4*1024,
- curEntities: 0,
- nextIndex: 0,
-
- mapCenter: pt(128,128),
-
- runGame: true,
- gameState: 'loading',
-
- maxStep: .01,
- secondAcc: 0,
- gameTime: 0,
-
- input: {},
- inputCache: {
- pressed: {},
- down: {},
- clicked: null,
- },
-
- hudData: {
- cash: {
- pos: pt(35, 30),
- font: '24px Sans Serif',
- color: 'yellow',
- }
- },
-
- map: null,
- coll: null,
- entities: [],
-
- components: {
-
- },
-
- // quick lookup of entities of certain types
- classes: {
- players: [],
- npcs: [],
- activeRender: [],
- mapRender: [],
- stands: [],
- },
-
- systems: {
-
- },
-
- disabledSystems: {
-
- },
-
- aiPaths: new PathSet(),
-
- mapcounter: 0,
-
- player: null, // points to an entity
- };
-
- var e = $.extend({}, defaults, options);
- for(x in e) this[x] = e[x];
-
- // shorthand
- this.c = this.components;
-
-
- this.init();
- }
- Game.prototype.init = function() {
-
- // a little splint here. there's probably a fancier js way to do this. meh.
- var that = this;
- this.animFrame = function() {
- that.loop();
- };
-
-
- var d = new Date();
- this.lastframe = d.getTime();
-
- // input handlers
- $(document).keydown(function(e) {
- if(!that.runGame) return;
- that.inputCache.down[e.which] = 1;
- that.inputCache.down[e.which] |= 0;
- e.preventDefault();
- });
- $(document).keyup(function(e) {
- if(!that.runGame) return;
- that.inputCache.down[e.which] = 0;
- that.inputCache.pressed[e.which] = (that.inputCache.pressed[e.which]>>>0) + 1;
- e.preventDefault();
- });
-
- // need to fix this
- $(document).mousedown(function(e) {
- if(!that.runGame) return;
- /* that.inputCache.down[e.which] = 1;
- that.inputCache.down[e.which] |= 0;
- */ e.preventDefault();
- });
- $(document).mouseup(function(e) {
- if(!that.runGame) return;
- that.inputCache.clicked = that.map.documentToMap(e.pageX, e.pageY);
- e.preventDefault();
- });
-
- // need double clicks
- // need dragging
- // need hover
-
-
- // canvas for actors
- this.actorCanvas = $('#entity-canvas')[0];
- this.actorCtx = this.actorCanvas.getContext("2d");
- this.actorCtx.setTransform(1, 0, 0, 1, 0, 0);
-
-
- // canvas for HUD
- this.hudCanvas = $('#hud-canvas')[0];
- this.hudCtx = this.hudCanvas.getContext("2d");
- this.hudCtx.setTransform(1, 0, 0, 1, 0, 0);
-
- // set up the map
- this.map = new Map({
- canvasSelector: '#tex-canvas',
- showDebugLabels: true,
- });
-
-
- this.grid = new GridSP();
-
- this.systems = Systems;
-
- // add some content...
-
- /*
- var b = this.aibtree = new BehaviorTree();
-
- b.addRoot({type: 'priority');
-
-
-
- */
-
- console.log('game init completed');
- // eh...
- //this.loop();
- };
- Game.prototype.loop = function() {
-
- //console.log('looping');
- this.updateInput();
-
- // inludes timers
- this.updateGame();
-
-
- this.render();
-
-
- if(this.runGame) window.requestAnimFrame(this.animFrame);
- };
- Game.prototype.loadLevel = function() {
-
- // generate the map
- MapGen_1(this.map, this);
-
-
-
- this.spawn(Entities.susie);
- var stand = this.spawn(Entities.stand);
- this.grid.addObj(stand);
-
-
- this.spawnCustomer(pt(129,126));
- this.spawnCustomer(pt(119,126));
-
-
- this.spawn(Entities.baron);
-
-
- };
- Game.prototype.render = function() {
-
- // texture canvas
- this.map.render(this.mapCenter);
-
-
- // entity canvas
- this.actorCtx.clearRect(0, 0, this.actorCanvas.width, this.actorCanvas.height);
-
- this.systems.drawActors(
- this.actorCtx,
- { width: this.actorCanvas.width, height: this.actorCanvas.height },
- this.mapCenter
- );
-
-
- this.systems.hud.money();
-
- };
- Game.prototype.updateInput = function() {
-
- var curinput = {
- down: this.inputCache.down,
- pressed: this.inputCache.pressed,
- clicked: this.inputCache.clicked,
- };
-
- this.inputCache.pressed = {};
- this.inputCache.clicked = null;
-
- this.input = curinput;
- };
- // broken....
- Game.prototype.updateGame = function(te) {
-
- // timeless stuff
-
- this.systems.userControl();
-
-
-
- // update the time
- var d = new Date();
- var now = d.getTime();
-
- // time elapsed since last frame, in seconds
- var te = (now - this.lastframe) / 1000.0;
- this.lastframe = now; // put this at the end
- this.secondAcc += te;
-
-
-
- var steps = Math.floor(te / this.maxStep);
- var leftover = te - (steps * this.maxStep);
-
- // nice little physics steps
- for(var i = 0; i < steps; i++) {
- this.gameTime += this.maxStep;
- this.step(this.maxStep);
- }
- this.gameTime += leftover;
- this.step(leftover);
-
- // once per frame
- this.frameStep(te);
-
- // ~once per second
- if(this.secondAcc > 1) {
- this.secondStep(this.secondAcc);
- this.secondAcc = 0;
- };
-
-
-
- return te;
- }
- // this is for things that need reasonable integration like physics
- Game.prototype.step = function(te) {
-
- //this.systems.move(te);
-
- this.systems.goTo();
-
-
- this.systems.acceleration(te);
- this.systems.velocity(te);
-
- this.systems.urge(te);
-
-
-
- this.systems.checkCollisions();
-
- // the odometer must be called immediately before movement finalization
- this.systems.odometer();
- this.systems.finalizeMove();
-
-
- };
- // this is for things that need per-frame updates, but can handle large steps like HUD
- Game.prototype.frameStep = function(te) {
-
- this.systems.mapFollows();
- this.systems.lookAt();
-
- };
- // called ~ once every second. useful for game logic, etc
- Game.prototype.secondStep = function(te) {
-
- this.systems.ai.thirst();
- this.systems.ai.thirsty_LocateStand();
- this.systems.ai.buyDrink();
- this.systems.ai.followPaths();
- };
- Game.prototype.addEntity = function() {
-
- var i = this.nextIndex++;
-
- return i;
- };
- Game.prototype.firstEntityWith = function(comp) {
- var c = this.components[comp];
- if(!c) return null;
-
- for(var eid in c) return eid;
- };
- Game.prototype.getAllComponents = function(eid) {
-
- var l = [];
-
- for(var cn in this.components) { if(this.components.hasOwnProperty(cn)) {
-
- var cmp = this.components[cn][eid]
-
- if(cmp) {
- l.push({type: cn, data: cmp});
- }
- }}
-
- return l;
- };
- // checks existence first
- Game.prototype.addComponent = function(eid, name, data) {
-
- if(!this.components[name])
- this.components[name] = {};
-
- this.components[name][eid] = data;
- };
- // doesn't check existence
- Game.prototype.setComp = function(eid, name, data) {
- this.components[name][eid] = data;
- };
- Game.prototype.getComp = function(eid, name) {
- return this.components[name] ? this.components[name][eid] : null;
- };
- Game.prototype.removeComp = function(eid, name) {
- delete this.components[name][eid];
- };
- Game.prototype.spawn = function(entity) {
- var eid = this.addEntity();
-
- for(var prop in entity) { if(entity.hasOwnProperty(prop)) {
- var data = entity[prop];
- // fuck references. real languages use pointers.
- if(typeof data == 'object')
- data = $.extend({}, data);
-
- this.addComponent(eid, prop, data);
- }}
-
- return eid;
- }
- // first arg is system name. rest of args are passed through
- Game.prototype.trySystem = function() {
- var name = arguments.unshift();
-
- if(this.disabledSystems) return null;
-
- return this.systems[name].apply(this, arguments);
- };
- function runSystem(allComps, reqComps, cb){
- var len = reqComps.length;
-
-
- for(var eid in allComps[reqComps[0]]) {
- var go = true;
- var e = {};
- for(var i = 0; i < len; i++) {
- var cn = reqComps[i];
- if(!allComps[cn] || !allComps[cn].hasOwnProperty(eid)) {
- go = false;
- break;
- }
-
- e[cn] = allComps[cn][eid]
- }
-
- if(go) cb(e, eid);
- }
- }
- Game.prototype.spawnCustomer = function(pos) {
-
- var eid = this.spawn(Entities.customer1);
- this.setComp(eid, 'position', ptc(pos));
- this.addComponent(eid, 'followPaths', 1);
-
- return eid;
- }
|