25개 이상의 토픽을 선택하실 수 없습니다. Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

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