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.
 
 
 

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