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.
 
 
 

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