You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

735 regels
16 KiB

  1. define([
  2. 'js/resources',
  3. 'js/system/events',
  4. 'js/misc/physics',
  5. 'js/rendering/effects',
  6. 'js/rendering/tileOpacity',
  7. 'js/rendering/particles',
  8. 'js/rendering/shaders/outline',
  9. 'js/rendering/spritePool'
  10. ], function(
  11. resources,
  12. events,
  13. physics,
  14. effects,
  15. tileOpacity,
  16. particles,
  17. shaderOutline,
  18. spritePool
  19. ) {
  20. var scale = 40;
  21. var scaleMult = 5;
  22. var pixi = PIXI;
  23. return {
  24. stage: null,
  25. layers: {
  26. objects: null,
  27. mobs: null,
  28. characters: null,
  29. attacks: null,
  30. effects: null,
  31. particles: null,
  32. tileSprites: null,
  33. hiders: null
  34. },
  35. titleScreen: false,
  36. width: 0,
  37. height: 0,
  38. showTilesW: 0,
  39. showTilesH: 0,
  40. pos: {
  41. x: 0,
  42. y: 0
  43. },
  44. moveTo: null,
  45. moveSpeed: 0,
  46. moveSpeedMax: 1.50,
  47. moveSpeedInc: 0.5,
  48. zoneId: null,
  49. textures: {},
  50. textureCache: {},
  51. sprites: [],
  52. lastTick: null,
  53. hiddenRooms: null,
  54. init: function() {
  55. PIXI.GC_MODES.DEFAULT = PIXI.GC_MODES.AUTO;
  56. PIXI.SCALE_MODES.DEFAULT = PIXI.SCALE_MODES.NEAREST;
  57. events.on('onGetMap', this.onGetMap.bind(this));
  58. events.on('onDeath', this.onDeath.bind(this));
  59. events.on('onToggleFullscreen', this.toggleScreen.bind(this));
  60. this.width = $('body').width();
  61. this.height = $('body').height();
  62. this.showTilesW = Math.ceil((this.width / scale) / 2) + 3;
  63. this.showTilesH = Math.ceil((this.height / scale) / 2) + 3;
  64. this.renderer = pixi.autoDetectRenderer(this.width, this.height, {
  65. backgroundColor: 0x2d2136
  66. });
  67. window.onresize = this.onResize.bind(this);
  68. $(this.renderer.view)
  69. .appendTo('.canvasContainer');
  70. this.stage = new pixi.Container();
  71. var layers = this.layers;
  72. Object.keys(layers).forEach(function(l) {
  73. if (l == 'tileSprites') {
  74. layers[l] = new pixi.Container();
  75. layers[l].layer = 'tiles';
  76. } else
  77. layers[l] = new pixi.Container();
  78. this.stage.addChild(layers[l])
  79. }, this);
  80. var spriteNames = ['sprites', 'tiles', 'mobs', 'bosses', 'bigObjects', 'objects', 'characters', 'attacks', 'auras', 'walls', 'ui', 'animChar', 'animMob', 'animBoss'];
  81. resources.spriteNames.forEach(function(s) {
  82. if (s.indexOf('.png') > -1)
  83. spriteNames.push(s);
  84. });
  85. spriteNames.forEach(function(t) {
  86. this.textures[t] = new pixi.BaseTexture(resources.sprites[t].image);
  87. this.textures[t].scaleMode = pixi.SCALE_MODES.NEAREST;
  88. }, this);
  89. particles.init({
  90. renderer: this.renderer,
  91. stage: this.layers.particles
  92. });
  93. },
  94. toggleScreen: function() {
  95. var screenMode = 0;
  96. var isFullscreen = (window.innerHeight == screen.height);
  97. if (isFullscreen)
  98. screenMode = 0;
  99. else
  100. screenMode = 1;
  101. if (screenMode == 0) {
  102. (document.cancelFullscreen || document.msCancelFullscreen || document.mozCancelFullscreen || document.webkitCancelFullScreen).call(document);
  103. return 'Windowed';
  104. } else if (screenMode == 1) {
  105. var el = $('body')[0];
  106. (el.requestFullscreen || el.msRequestFullscreen || el.mozRequestFullscreen || el.webkitRequestFullscreen).call(el);
  107. return 'Fullscreen';
  108. }
  109. },
  110. buildTitleScreen: function() {
  111. this.titleScreen = true;
  112. this.setPosition({
  113. x: 0,
  114. y: 0
  115. }, true);
  116. var w = Math.ceil(this.width / scale) + 1;
  117. var h = Math.ceil(this.height / scale) + 1;
  118. var container = this.layers.tileSprites;
  119. for (var i = 0; i < w; i++) {
  120. for (var j = 0; j < h; j++) {
  121. var tile = 5;
  122. if (Math.random() < 0.4)
  123. tile = 6;
  124. var tile = new pixi.Sprite(this.getTexture('sprites', tile));
  125. var alpha = Math.sin((i % 4) + Math.cos(j % 8));
  126. if (tile == 5)
  127. alpha /= 2;
  128. tile.alpha = alpha;
  129. tile.position.x = i * scale;
  130. tile.position.y = j * scale;
  131. tile.width = scale;
  132. tile.height = scale;
  133. if (Math.random() < 0.5) {
  134. tile.position.x += scale;
  135. tile.scale.x = -scaleMult;
  136. }
  137. container.addChild(tile);
  138. }
  139. }
  140. },
  141. onDeath: function(pos) {
  142. this.setPosition({
  143. x: (pos.x - (this.width / (scale * 2))) * scale,
  144. y: (pos.y - (this.height / (scale * 2))) * scale
  145. }, true);
  146. },
  147. onResize: function() {
  148. var zoom = window.devicePixelRatio;
  149. this.width = $('body').width() * zoom;
  150. this.height = $('body').height() * zoom;
  151. this.showTilesW = Math.ceil((this.width / scale) / 2) + 3;
  152. this.showTilesH = Math.ceil((this.height / scale) / 2) + 3;
  153. this.renderer.resize(this.width, this.height);
  154. if (window.player) {
  155. this.setPosition({
  156. x: (window.player.x - (this.width / (scale * 2))) * scale,
  157. y: (window.player.y - (this.height / (scale * 2))) * scale
  158. }, true);
  159. }
  160. if (this.titleScreen) {
  161. this.clean();
  162. this.buildTitleScreen();
  163. }
  164. events.emit('onResize');
  165. },
  166. getTexture: function(baseTex, cell, size) {
  167. size = size || 8;
  168. var name = baseTex + '_' + cell;
  169. var textureCache = this.textureCache;
  170. var cached = textureCache[name];
  171. if (!cached) {
  172. var y = ~~(cell / 8);
  173. var x = cell - (y * 8);
  174. cached = new pixi.Texture(this.textures[baseTex], new pixi.Rectangle(x * size, y * size, size, size));
  175. textureCache[name] = cached;
  176. }
  177. return cached;
  178. },
  179. clean: function() {
  180. var container = this.layers.tileSprites;
  181. this.stage.removeChild(container);
  182. this.layers.tileSprites = container = new pixi.Container();
  183. container.layer = 'tiles';
  184. this.stage.addChild(container);
  185. this.stage.children.sort(function(a, b) {
  186. if (a.layer == 'tiles')
  187. return -1;
  188. else if (b.layer == 'tiles')
  189. return 1;
  190. else
  191. return 0;
  192. }, this);
  193. },
  194. onGetMapCustomization: function(msg) {
  195. if (!msg.collide) {
  196. var children = this.layers.tiles.children;
  197. var cLen = children.length;
  198. var x = msg.x * scale;
  199. var y = msg.y * scale;
  200. for (var i = cLen - 1; i >= 0; i--) {
  201. var c = children[i];
  202. var cx = c.x;
  203. if (c.scale.x < 0)
  204. cx -= scale;
  205. if ((cx == x) && (c.y == y)) {
  206. c.parent.removeChild(c);
  207. break;
  208. }
  209. }
  210. }
  211. var tile = new pixi.Sprite(this.getTexture('sprites', msg.tile))
  212. tile.alpha = tileOpacity.map(msg.tile);
  213. tile.position.x = msg.x * scale;
  214. tile.position.y = msg.y * scale;
  215. tile.width = scale;
  216. tile.height = scale;
  217. if (Math.random() < 0.5) {
  218. tile.position.x += scale;
  219. tile.scale.x = -scaleMult;
  220. }
  221. this.layers.tiles.addChild(tile);
  222. physics.collisionMap[msg.x][msg.y] = msg.collide;
  223. physics.graph.grid[msg.x][msg.y] = !msg.collide;
  224. },
  225. buildTile: function(c, i, j) {
  226. var alpha = tileOpacity.map(c);
  227. var canFlip = tileOpacity.canFlip(c);
  228. var tile = new pixi.Sprite(this.getTexture('sprites', c));
  229. tile.alpha = alpha;
  230. tile.position.x = i * scale;
  231. tile.position.y = j * scale;
  232. tile.width = scale;
  233. tile.height = scale;
  234. if (canFlip) {
  235. if (Math.random() < 0.5) {
  236. tile.position.x += scale;
  237. tile.scale.x = -scaleMult;
  238. }
  239. }
  240. return tile;
  241. },
  242. onGetMap: function(msg) {
  243. this.titleScreen = false;
  244. physics.init(msg.collisionMap);
  245. var map = this.map = msg.map;
  246. var w = this.w = map.length;
  247. var h = this.h = map[0].length;
  248. this.clean();
  249. spritePool.clean();
  250. this.buildHiddenRooms(msg);
  251. this.sprites = _.get2dArray(w, h, 'array');
  252. this.stage.children.sort(function(a, b) {
  253. if (a.layer == 'tiles')
  254. return -1;
  255. else if (b.layer == 'tiles')
  256. return 1;
  257. else
  258. return 0;
  259. }, this);
  260. if (this.zoneId != null)
  261. events.emit('onRezone', this.zoneId);
  262. this.zoneId = msg.zoneId;
  263. msg.clientObjects.forEach(function(c) {
  264. c.zoneId = this.zoneId;
  265. events.emit('onGetObject', c);
  266. }, this);
  267. },
  268. buildHiddenRooms: function(msg) {
  269. var hiddenWalls = msg.hiddenWalls;
  270. var hiddenTiles = msg.hiddenTiles;
  271. this.hiddenRooms = msg.hiddenRooms;
  272. this.hiddenRooms.forEach(function(h) {
  273. h.container = new pixi.Container();
  274. this.layers.hiders.addChild(h.container);
  275. this.buildRectangle({
  276. x: h.x * scale,
  277. y: h.y * scale,
  278. w: h.width * scale,
  279. h: h.height * scale,
  280. color: 0x2d2136,
  281. parent: h.container
  282. });
  283. for (var i = h.x; i < h.x + h.width; i++) {
  284. for (var j = h.y; j < h.y + h.height; j++) {
  285. [hiddenTiles, hiddenWalls].forEach(function(k) {
  286. var cell = k[i][j];
  287. if (cell == 0)
  288. return;
  289. var tile = this.buildTile(cell - 1, i, j);
  290. tile.width = scale;
  291. tile.height = scale;
  292. h.container.addChild(tile);
  293. }, this);
  294. }
  295. }
  296. }, this);
  297. },
  298. hideHiders: function() {
  299. var player = window.player;
  300. if (!player)
  301. return;
  302. var x = player.x;
  303. var y = player.y;
  304. var hiddenRooms = this.hiddenRooms;
  305. var hLen = hiddenRooms.length;
  306. for (var i = 0; i < hLen; i++) {
  307. var h = hiddenRooms[i];
  308. h.container.visible = (
  309. (x < h.x) ||
  310. (x >= h.x + h.width) ||
  311. (y < h.y) ||
  312. (y >= h.y + h.height)
  313. );
  314. }
  315. },
  316. setPosition: function(pos, instant) {
  317. pos.x += 16;
  318. pos.y += 16;
  319. this.hideHiders();
  320. if (instant) {
  321. this.moveTo = null;
  322. this.pos = pos;
  323. this.stage.x = -~~this.pos.x;
  324. this.stage.y = -~~this.pos.y;
  325. } else
  326. this.moveTo = pos;
  327. this.updateSprites();
  328. },
  329. updateSprites: function() {
  330. var player = window.player;
  331. if (!player)
  332. return;
  333. var w = this.w;
  334. var h = this.h;
  335. var x = player.x;
  336. var y = player.y;
  337. var sprites = this.sprites;
  338. var map = this.map;
  339. var container = this.layers.tileSprites;
  340. var sw = this.showTilesW;
  341. var sh = this.showTilesH;
  342. var lowX = Math.max(0, x - sw);
  343. var lowY = Math.max(0, y - sh);
  344. var highX = Math.min(w - 1, x + sw);
  345. var highY = Math.min(h - 1, y + sh);
  346. var addedSprite = false;
  347. for (var i = lowX; i < highX; i++) {
  348. for (var j = lowY; j < highY; j++) {
  349. cell = map[i][j];
  350. if (!cell)
  351. continue;
  352. var rendered = sprites[i][j];
  353. if (rendered.length > 0)
  354. continue;
  355. else if (!cell.split)
  356. cell += '';
  357. cell = cell.split(',');
  358. for (var k = 0; k < cell.length; k++) {
  359. var c = cell[k];
  360. if (c == 0)
  361. continue;
  362. c--;
  363. var flipped = '';
  364. if (tileOpacity.canFlip(c)) {
  365. if (Math.random() < 0.5)
  366. flipped = 'flip';
  367. }
  368. var tile = spritePool.getSprite(flipped + c);
  369. if (!tile) {
  370. tile = this.buildTile(c, i, j);
  371. container.addChild(tile);
  372. tile.type = c;
  373. tile.sheetNum = tileOpacity.getSheetNum(c);
  374. addedSprite = true;
  375. } else {
  376. tile.position.x = i * scale;
  377. tile.position.y = j * scale;
  378. if (flipped != '')
  379. tile.position.x += scale;
  380. tile.visible = true;
  381. }
  382. rendered.push(tile);
  383. }
  384. }
  385. }
  386. lowX = Math.max(0, lowX - 10);
  387. lowY = Math.max(0, lowY - 10);
  388. highX = Math.min(w - 1, highX + 10);
  389. highY = Math.min(h - 1, highY + 10);
  390. for (var i = lowX; i < highX; i++) {
  391. var outside = ((i >= x - sw) && (i < x + sw));
  392. for (var j = lowY; j < highY; j++) {
  393. if ((outside) && (j >= y - sh) && (j < y + sh))
  394. continue;
  395. var list = sprites[i][j];
  396. var lLen = list.length;
  397. for (var k = 0; k < lLen; k++) {
  398. var sprite = list[k];
  399. sprite.visible = false;
  400. spritePool.store(sprite);
  401. }
  402. sprites[i][j] = [];
  403. }
  404. }
  405. //Reorder
  406. if (addedSprite) {
  407. container.children.sort(function(a, b) {
  408. return (a.sheetNum - b.sheetNum);
  409. });
  410. }
  411. },
  412. update: function() {
  413. var time = +new Date;
  414. if (this.moveTo) {
  415. var deltaX = this.moveTo.x - this.pos.x;
  416. var deltaY = this.moveTo.y - this.pos.y;
  417. if ((deltaX != 0) || (deltaY != 0)) {
  418. var moveSpeed = this.moveSpeed;
  419. var distance = Math.max(Math.abs(deltaX), Math.abs(deltaY));
  420. var moveSpeedMax = this.moveSpeedMax;
  421. if (distance > 100)
  422. moveSpeedMax *= 1.75;
  423. if (this.moveSpeed < moveSpeedMax)
  424. this.moveSpeed += this.moveSpeedInc;
  425. var elapsed = time - this.lastTick;
  426. moveSpeed *= (elapsed / 16.67);
  427. if (moveSpeed > distance)
  428. moveSpeed = distance;
  429. deltaX = (deltaX / distance) * moveSpeed;
  430. deltaY = (deltaY / distance) * moveSpeed;
  431. this.pos.x = this.pos.x + (deltaX);
  432. this.pos.y = this.pos.y + (deltaY);
  433. } else {
  434. this.moveSpeed = 0;
  435. this.moveTo = null;
  436. }
  437. this.stage.x = -~~this.pos.x;
  438. this.stage.y = -~~this.pos.y;
  439. events.emit('onSceneMove');
  440. }
  441. this.lastTick = time;
  442. },
  443. buildContainer: function(obj) {
  444. var container = new pixi.Container;
  445. this.layers[obj.layerName || obj.sheetName].addChild(container);
  446. return container;
  447. },
  448. buildRectangle: function(obj) {
  449. var graphics = new pixi.Graphics;
  450. var alpha = obj.alpha;
  451. if (alpha != null)
  452. graphics.alpha = alpha;
  453. var fillAlpha = obj.fillAlpha;
  454. if (fillAlpha == null)
  455. fillAlpha = 1;
  456. graphics.beginFill(obj.color || '0x48edff', fillAlpha);
  457. if (obj.strokeColor)
  458. graphics.lineStyle(scaleMult, obj.strokeColor);
  459. graphics.moveTo(obj.x, obj.y);
  460. graphics.lineTo(obj.x + obj.w, obj.y);
  461. graphics.lineTo(obj.x + obj.w, obj.y + obj.h);
  462. graphics.lineTo(obj.x, obj.y + obj.h);
  463. graphics.lineTo(obj.x, obj.y);
  464. graphics.endFill();
  465. (obj.parent || this.layers[obj.layerName || obj.sheetName]).addChild(graphics);
  466. return graphics;
  467. },
  468. moveRectangle(obj) {
  469. var points = obj.sprite.graphicsData[0].shape.points;
  470. if (!points)
  471. return;
  472. obj.sprite.dirty = true;
  473. obj.sprite.clearDirty = true;
  474. points[0] = obj.x;
  475. points[1] = obj.y;
  476. points[2] = obj.x + obj.w;
  477. points[3] = obj.y;
  478. points[4] = obj.x + obj.w;
  479. points[5] = obj.y + obj.h;
  480. points[6] = obj.x;
  481. points[7] = obj.y + obj.h;
  482. points[8] = obj.x;
  483. points[9] = obj.y;
  484. },
  485. buildObject: function(obj) {
  486. var w = 8;
  487. var h = 8;
  488. if (obj.w) {
  489. w = obj.w / scaleMult;
  490. h = obj.h / scaleMult;
  491. }
  492. if (obj.sheetName == 'bosses') {
  493. obj.layerName = 'mobs';
  494. w = 24;
  495. h = 24;
  496. obj.w = w * scaleMult;
  497. obj.h = h * scaleMult;
  498. } else if (obj.sheetName == 'bigObjects') {
  499. obj.layerName = 'mobs';
  500. w = 24;
  501. h = 24;
  502. obj.w = w * scaleMult;
  503. obj.h = h * scaleMult;
  504. }
  505. var sprite = new pixi.Sprite(this.getTexture(obj.sheetName, obj.cell, w))
  506. sprite.x = obj.x * scale;
  507. sprite.y = obj.y * scale;
  508. sprite.width = obj.w || scale;
  509. sprite.height = obj.h || scale;
  510. if (obj.sheetName == 'bosses') {
  511. sprite.x -= scale;
  512. sprite.y -= (scale * 2);
  513. } else if (obj.sheetName == 'bigObjects') {
  514. sprite.x -= scale;
  515. sprite.y -= (scale * 2);
  516. sprite.alpha = 0.80;
  517. }
  518. if (obj.flipX) {
  519. sprite.scale.x *= -1;
  520. if ((obj.sheetName == 'bosses') || (obj.sheetName == 'bigObjects'))
  521. sprite.x += (scale * 2);
  522. else
  523. sprite.x += scale;
  524. }
  525. (this.layers[obj.layerName || obj.sheetName] || this.layers.objects).addChild(sprite);
  526. return sprite;
  527. },
  528. addFilter: function(sprite) {
  529. var thickness = 16;
  530. if (sprite.width > scale)
  531. thickness = 8;
  532. var filter = new shaderOutline(this.renderer.width, this.renderer.height, thickness, '0xffffff');
  533. if (!sprite.filters)
  534. sprite.filters = [filter];
  535. else
  536. sprite.filters.push();
  537. return filter;
  538. },
  539. removeFilter: function(sprite, filter) {
  540. if (!sprite.filters)
  541. return;
  542. sprite.filters = null;
  543. },
  544. buildText: function(obj) {
  545. var textSprite = new pixi.Text(obj.text, {
  546. fontFamily: 'bitty',
  547. fontSize: (obj.fontSize || 14),
  548. fill: obj.color || 0xF2F5F5,
  549. stroke: 0x2d2136,
  550. strokeThickness: 4,
  551. align: 'center'
  552. });
  553. textSprite.x = obj.x - (textSprite.width / 2);
  554. textSprite.y = obj.y;
  555. var parent = obj.parent || this.layers[obj.layerName]
  556. parent.addChild(textSprite);
  557. return textSprite;
  558. },
  559. buildEmitter: function(config) {
  560. return particles.buildEmitter(config);
  561. },
  562. destroyEmitter: function(emitter) {
  563. particles.destroyEmitter(emitter);
  564. },
  565. setSprite: function(obj) {
  566. var cell = obj.cell;
  567. var y = ~~(cell / 8);
  568. var x = cell - (y * 8);
  569. var baseTex = this.textures[obj.sheetName];
  570. obj.sprite.texture = this.getTexture(obj.sheetName, obj.cell, obj.sprite.width / scaleMult);
  571. },
  572. reorder: function(sprite) {
  573. var mobLayer = this.layers.mobs;
  574. var mobs = mobLayer.children;
  575. mobs.sort(function(a, b) {
  576. return (b.y - a.y);
  577. });
  578. },
  579. destroyObject: function(obj) {
  580. if (!obj.sprite.parent)
  581. return;
  582. obj.sprite.parent.removeChild(obj.sprite);
  583. },
  584. render: function() {
  585. if (!this.stage)
  586. return;
  587. effects.render();
  588. particles.update();
  589. this.renderer.render(this.stage);
  590. }
  591. };
  592. });