25'ten fazla konu seçemezsiniz Konular bir harf veya rakamla başlamalı, kısa çizgiler ('-') içerebilir ve en fazla 35 karakter uzunluğunda olabilir.
 
 
 

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