not really known
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.

918 lines
31 KiB

  1. define(["sugar-web/activity/activity","tween","rAF","activity/directions","sugar-web/graphics/presencepalette", "sugar-web/env", "sugar-web/graphics/icon", "webL10n", "sugar-web/graphics/palette", "rot", "humane"], function (activity, TWEEN, rAF, directions, presencepalette, env, icon, webL10n, palette, ROT, humane) {
  2. requirejs(['domReady!'], function (doc) {
  3. activity.setup();
  4. var maze = {};
  5. var ended=false;
  6. var oponentEnded = 0;
  7. var oponentCount = 0;
  8. maze.width = undefined;
  9. maze.height = undefined;
  10. maze.startPoint = {};
  11. maze.goalPoint = {};
  12. maze.walls = [];
  13. maze.visited = [];
  14. maze.directions = [];
  15. maze.forks = [];
  16. var firstentry=true;
  17. var xoLogo = '<?xml version="1.0" ?><!DOCTYPE svg PUBLIC \'-//W3C//DTD SVG 1.1//EN\' \'http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd\' [<!ENTITY stroke_color "#010101"><!ENTITY fill_color "#FFFFFF">]><svg enable-background="new 0 0 55 55" height="55px" version="1.1" viewBox="0 0 55 55" width="55px" x="0px" xml:space="preserve" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" y="0px"><g display="block" id="stock-xo_1_"><path d="M33.233,35.1l10.102,10.1c0.752,0.75,1.217,1.783,1.217,2.932 c0,2.287-1.855,4.143-4.146,4.143c-1.145,0-2.178-0.463-2.932-1.211L27.372,40.961l-10.1,10.1c-0.75,0.75-1.787,1.211-2.934,1.211 c-2.284,0-4.143-1.854-4.143-4.141c0-1.146,0.465-2.184,1.212-2.934l10.104-10.102L11.409,24.995 c-0.747-0.748-1.212-1.785-1.212-2.93c0-2.289,1.854-4.146,4.146-4.146c1.143,0,2.18,0.465,2.93,1.214l10.099,10.102l10.102-10.103 c0.754-0.749,1.787-1.214,2.934-1.214c2.289,0,4.146,1.856,4.146,4.145c0,1.146-0.467,2.18-1.217,2.932L33.233,35.1z" fill="&fill_color;" stroke="&stroke_color;" stroke-width="3.5"/><circle cx="27.371" cy="10.849" fill="&fill_color;" r="8.122" stroke="&stroke_color;" stroke-width="3.5"/></g></svg>';
  18. env.getEnvironment(function(err, environment) {
  19. // Set current language to Sugarizer
  20. var defaultLanguage = (typeof chrome != 'undefined' && chrome.app && chrome.app.runtime) ? chrome.i18n.getUILanguage() : navigator.language;
  21. var language = environment.user ? environment.user.language : defaultLanguage;
  22. webL10n.language.code = language;
  23. // Shared instances
  24. if (environment.sharedId) {
  25. console.log("Shared instance");
  26. presence = activity.getPresenceObject(function(error, network) {
  27. network.onDataReceived(onNetworkDataReceived);
  28. network.onSharedActivityUserChanged(onNetworkUserChanged);
  29. });
  30. }
  31. // Load from datastore
  32. if (!environment.objectId) {
  33. runLevel();
  34. } else {
  35. activity.getDatastoreObject().loadAsText(function(error, metadata, data) {
  36. if (error==null && data!=null) {
  37. data = JSON.parse(data);
  38. maze = data.maze;
  39. gameSize = data.gameSize;
  40. updateMazeSize();
  41. updateSprites();
  42. onLevelStart();
  43. }
  44. });
  45. }
  46. });
  47. var generateXOLogoWithColor = function(color) {
  48. var coloredLogo = xoLogo;
  49. coloredLogo = coloredLogo.replace("#010101", color.stroke)
  50. coloredLogo = coloredLogo.replace("#FFFFFF", color.fill)
  51. return "data:image/svg+xml;base64," + btoa(coloredLogo);
  52. }
  53. var onNetworkDataReceived = function(msg) {
  54. if (presence.getUserInfo().networkId === msg.user.networkId) {
  55. return;
  56. }
  57. switch (msg.action){
  58. case 'start':
  59. ended=false;
  60. oponentEnded=0;
  61. maze=msg.content;
  62. gameSize=msg.SizeOfGame;
  63. oponentCount=msg.oponentCount;
  64. updateMazeSize();
  65. updateSprites();
  66. onLevelStart();
  67. break;
  68. case 'ended':
  69. oponentEnded++;
  70. var userName = msg.user.name.replace('<', '&lt;').replace('>', '&gt;');
  71. var html = "<img style='height:30px;' src='" + generateXOLogoWithColor(msg.user.colorvalue) + "'>";
  72. humane.log(html + webL10n.get("PlayerEndLevel",{user: userName}));
  73. break;
  74. }
  75. };
  76. var onNetworkUserChanged = function(msg) {
  77. var userName = msg.user.name.replace('<', '&lt;').replace('>', '&gt;');
  78. var html = "<img style='height:30px;' src='" + generateXOLogoWithColor(msg.user.colorvalue) + "'>";
  79. if (msg.move === 1) {
  80. oponentCount++;
  81. humane.log(html + webL10n.get("PlayerJoin",{user: userName}));
  82. } else if (msg.move === -1) {
  83. oponentCount--;
  84. humane.log(html + webL10n.get("PlayerLeave",{user: userName}));
  85. }
  86. if (isHost) {
  87. presence.sendMessage(presence.getSharedInfo().id, {
  88. user: presence.getUserInfo(),
  89. action: 'start',
  90. SizeOfGame: gameSize,
  91. oponentCount: oponentCount,
  92. content: maze
  93. });
  94. }
  95. console.log("User "+msg.user.name+" "+(msg.move == 1 ? "join": "leave"));
  96. };
  97. var soundType = /(iPad|iPhone|iPod)/g.test(navigator.userAgent) ? '.mp3' : '.ogg';
  98. var canvasWidth;
  99. var canvasHeight;
  100. var wallColor = "#101010";
  101. var corridorColor = "#ffffff";
  102. var startColor = "hsl(0, 0%, 80%)";
  103. var startPlayerColor = "hsl(0, 90%, 50%)";
  104. var goalColor;
  105. var cellWidth;
  106. var cellHeight;
  107. var dirtyCells = [];
  108. var controls = {
  109. 'arrows': [38, 39, 40, 37],
  110. 'wasd': [87, 68, 83, 65],
  111. 'ijkl': [73, 76, 75, 74],
  112. 'mouse': [-1, -1, -1, -1]
  113. };
  114. var controlNames = ['arrows', 'wasd', 'ijkl', 'mouse'];
  115. var controlColors = {};
  116. var controlSprites = {};
  117. var players = {};
  118. var winner;
  119. var gameSize = 60;
  120. var levelStatus;
  121. var levelTransitionRadius;
  122. var levelStartingValue;
  123. var debug = false; //true;
  124. var mazeCanvas = document.getElementById("maze");
  125. var spriteCanvas = document.createElement("canvas");
  126. var updateMazeSize = function () {
  127. var toolbarElem = document.getElementById("main-toolbar");
  128. canvasWidth = window.innerWidth;
  129. canvasHeight = window.innerHeight - toolbarElem.offsetHeight - 3;
  130. cellWidth = Math.floor(canvasWidth / maze.width);
  131. cellHeight = Math.floor(canvasHeight / maze.height);
  132. mazeCanvas.width = canvasWidth;
  133. mazeCanvas.height = canvasHeight;
  134. spriteCanvas.width = cellWidth * 2; // number of states
  135. spriteCanvas.height = cellHeight * controlNames.length;
  136. };
  137. var onWindowResize = function () {
  138. updateMazeSize();
  139. updateSprites();
  140. drawMaze();
  141. };
  142. window.addEventListener('resize', onWindowResize);
  143. var updateSprites = function () {
  144. for (control in controls) {
  145. if (control in controlColors) {
  146. createPlayerSprite(control);
  147. }
  148. }
  149. }
  150. var createPlayerSprite = function (control) {
  151. var i = controlNames.indexOf(control);
  152. ctx = spriteCanvas.getContext("2d");
  153. drawPlayerFace(ctx, 0, i, controlColors[control].normal);
  154. drawPlayerFace(ctx, 1, i, controlColors[control].blocked);
  155. return {
  156. 'normal': {'image': spriteCanvas, 'x': 0, 'y': i},
  157. 'blocked': {'image': spriteCanvas, 'x': 1, 'y': i}
  158. };
  159. }
  160. var drawCell = function (ctx, x, y, color) {
  161. ctx.fillStyle = color;
  162. ctx.fillRect(cellWidth * x, cellHeight * y, cellWidth, cellHeight);
  163. }
  164. var drawGround = function (ctx, x, y, value) {
  165. var color;
  166. if (value == 1) {
  167. color = wallColor;
  168. } else {
  169. color = corridorColor;
  170. }
  171. drawCell(ctx, x, y, color);
  172. };
  173. var drawPoint = function (ctx, x, y, color, size) {
  174. var centerX = cellWidth * (x + 0.5);
  175. var centerY = cellHeight * (y + 0.5);
  176. var radius = size * Math.min(cellWidth, cellHeight) / 2;
  177. ctx.beginPath();
  178. ctx.arc(centerX, centerY, radius, 0, 2 * Math.PI, false);
  179. ctx.fillStyle = color;
  180. ctx.fill();
  181. };
  182. var drawPlayerFace = function (ctx, x, y, color) {
  183. drawPoint(ctx, x, y, color, 0.9);
  184. var eye1X = cellWidth * (x + 0.3);
  185. var eye1Y = cellHeight * (y + 0.45);
  186. var eyeRadius = 0.28 * Math.min(cellWidth, cellHeight) / 2;
  187. ctx.beginPath();
  188. ctx.arc(eye1X, eye1Y, eyeRadius, 0, 2 * Math.PI, false);
  189. var eye2X = cellWidth * (x + 0.7);
  190. var eye2Y = cellHeight * (y + 0.45);
  191. ctx.arc(eye2X, eye2Y, eyeRadius, 0, 2 * Math.PI, false);
  192. ctx.fillStyle = "#ffffff";
  193. ctx.fill();
  194. ctx.beginPath();
  195. ctx.arc(eye1X, eye1Y, eyeRadius / 2, 0, 2 * Math.PI, false);
  196. ctx.arc(eye2X, eye2Y, eyeRadius / 2, 0, 2 * Math.PI, false);
  197. ctx.fillStyle = "#000000";
  198. ctx.fill();
  199. ctx.beginPath();
  200. ctx.moveTo(cellWidth * (x + 0.25), cellHeight * (y + 0.65));
  201. ctx.quadraticCurveTo(cellWidth * (x + 0.5), cellHeight * (y + 0.75),
  202. cellWidth * (x + 0.75), cellHeight * (y + 0.65));
  203. ctx.quadraticCurveTo(cellWidth * (x + 0.5), cellHeight * (y + 0.75),
  204. cellWidth * (x + 0.75), cellHeight * (y + 0.65));
  205. ctx.quadraticCurveTo(cellWidth * (x + 0.5), cellHeight * (y + 1),
  206. cellWidth * (x + 0.25), cellHeight * (y + 0.65));
  207. ctx.quadraticCurveTo(cellWidth * (x + 0.5), cellHeight * (y + 1),
  208. cellWidth * (x + 0.25), cellHeight * (y + 0.65));
  209. ctx.fillStyle = "#ffffff";
  210. ctx.fill();
  211. }
  212. var drawSprite = function (ctx, x, y, spriteData) {
  213. ctx.drawImage(spriteData.image,
  214. cellWidth * spriteData.x, cellHeight * spriteData.y,
  215. cellWidth, cellHeight,
  216. cellWidth * x, cellHeight * y,
  217. cellWidth, cellHeight)
  218. }
  219. var drawMazeCell = function (x, y, ctx) {
  220. if (ctx === undefined) {
  221. ctx = mazeCanvas.getContext("2d");
  222. }
  223. drawGround(ctx, x, y, maze.walls[x][y]);
  224. if (maze.visited[x][y] !== undefined) {
  225. drawPoint(ctx, x, y, maze.visited[x][y], 0.5);
  226. }
  227. if (debug) {
  228. if (maze.forks[x][y] == 1) {
  229. drawPoint(ctx, x, y, '#faa', 0.5);
  230. }
  231. }
  232. if (x == maze.startPoint.x && y == maze.startPoint.y) {
  233. drawPoint(ctx, maze.startPoint.x, maze.startPoint.y, startColor, 0.9);
  234. }
  235. if (x == maze.goalPoint.x && y == maze.goalPoint.y) {
  236. drawCell(ctx, maze.goalPoint.x, maze.goalPoint.y, goalColor);
  237. }
  238. for (control in players) {
  239. var player = players[control];
  240. if (x == player.x && y == player.y) {
  241. drawSprite(ctx, x, y, player.sprite);
  242. }
  243. };
  244. }
  245. var drawMaze = function (ctx) {
  246. if (ctx === undefined) {
  247. ctx = mazeCanvas.getContext("2d");
  248. }
  249. for (var x=0; x<maze.width; x++) {
  250. for (var y=0; y<maze.height; y++) {
  251. drawGround(ctx, x, y, maze.walls[x][y]);
  252. if (maze.visited[x][y] !== undefined) {
  253. drawPoint(ctx, x, y, maze.visited[x][y], 0.5);
  254. }
  255. if (debug) {
  256. if (maze.forks[x][y] == 1) {
  257. drawPoint(ctx, x, y, '#faa', 0.5);
  258. }
  259. }
  260. }
  261. }
  262. drawPoint(ctx, maze.startPoint.x, maze.startPoint.y, startColor, 0.9);
  263. drawPlayerFace(ctx, maze.startPoint.x, maze.startPoint.y, startPlayerColor);
  264. drawCell(ctx, maze.goalPoint.x, maze.goalPoint.y, goalColor);
  265. for (control in players) {
  266. var player = players[control];
  267. drawSprite(ctx, x, y, player.sprite);
  268. };
  269. };
  270. var drawLevelComplete = function (ctx) {
  271. if (ctx === undefined) {
  272. ctx = mazeCanvas.getContext("2d");
  273. }
  274. var centerX = cellWidth * (winner.x + 0.5);
  275. var centerY = cellHeight * (winner.y + 0.5);
  276. var radius = levelTransitionRadius;
  277. ctx.beginPath();
  278. ctx.arc(centerX, centerY, radius, 0, 2 * Math.PI, false);
  279. ctx.fillStyle = winner.color;
  280. ctx.fill();
  281. }
  282. var drawLevelStarting = function (ctx) {
  283. if (ctx === undefined) {
  284. ctx = mazeCanvas.getContext("2d");
  285. }
  286. ctx.fillStyle = goalColor;
  287. var width = cellWidth * levelStartingValue;
  288. var height = cellHeight * levelStartingValue;
  289. var x;
  290. var y;
  291. if (maze.goalPoint.x == 1) {
  292. x = cellWidth;
  293. }
  294. else {
  295. x = ((maze.goalPoint.x + 1) * cellWidth) - width;
  296. }
  297. if (maze.goalPoint.y == 1) {
  298. y = cellHeight;
  299. }
  300. else {
  301. y = ((maze.goalPoint.y + 1) * cellHeight) - height;
  302. }
  303. ctx.fillRect(x, y, width, height);
  304. drawPoint(ctx, maze.startPoint.x, maze.startPoint.y, startColor,
  305. 0.9 * levelStartingValue);
  306. }
  307. var onLevelStart = function () {
  308. levelStatus = 'starting';
  309. tween = new TWEEN.Tween({t: 0});
  310. tween.to({t: 1}, 900);
  311. tween.easing(TWEEN.Easing.Quadratic.InOut);
  312. tween.onUpdate(function () {
  313. levelStartingValue = this.t;
  314. });
  315. tween.onComplete(function () {
  316. levelStartingValue = undefined;
  317. levelStatus = 'playing';
  318. drawMaze();
  319. });
  320. tween.start();
  321. }
  322. var generate = function (aspectRatio, size) {
  323. initialize(aspectRatio, size);
  324. maze.walls = createMatrix(maze.width, maze.height);
  325. maze.visited = createMatrix(maze.width, maze.height);
  326. maze.directions = createMatrix(maze.width, maze.height);
  327. maze.forks = createMatrix(maze.width, maze.height);
  328. var rotmaze = new ROT.Map.IceyMaze(maze.width, maze.height, 1);
  329. //var rotmaze = new ROT.Map.EllerMaze(maze.width, maze.height, 1);
  330. rotmaze.create(onCellGenerated);
  331. findDirections();
  332. findForks();
  333. };
  334. var onLevelComplete = function (player) {
  335. winner = player;
  336. levelStatus = 'transition';
  337. ended=true;
  338. if(presence){
  339. presence.sendMessage(presence.getSharedInfo().id, {
  340. user: presence.getUserInfo(),
  341. action: 'ended'
  342. });
  343. }
  344. var audio = new Audio('sounds/win'+soundType);
  345. audio.play();
  346. for (control in players) {
  347. players[control].stop();
  348. }
  349. var hypot = Math.sqrt(Math.pow(window.innerWidth, 2) +
  350. Math.pow(window.innerHeight, 2));
  351. tween = new TWEEN.Tween({radius: 0});
  352. tween.to({radius: hypot}, 1200);
  353. tween.easing(TWEEN.Easing.Circular.Out);
  354. tween.onUpdate(function () {
  355. levelTransitionRadius = this.radius;
  356. });
  357. maze.startPoint={};
  358. players={};
  359. if(!presence){
  360. tween.onComplete(function () {
  361. nextLevel();
  362. });
  363. } else {
  364. if(oponentEnded+1==oponentCount){
  365. tween.onComplete(function () {
  366. nextLevel();
  367. });
  368. } else {
  369. var waitCount = (oponentCount-oponentEnded-1);
  370. humane.log(webL10n.get((waitCount > 1 ?"PlayersWaitMany":"PlayersWaitOne"), {count: waitCount}));
  371. }
  372. }
  373. tween.start();
  374. }
  375. var nextLevel = function () {
  376. gameSize *= 1.2;
  377. runLevel();
  378. }
  379. var Player = function (control) {
  380. this.control = control;
  381. this.x = maze.startPoint.x;
  382. this.y = maze.startPoint.y;
  383. if (!(control in controlColors)) {
  384. var hue = Math.floor(Math.random()*360);
  385. controlColors[control] = {
  386. 'normal': 'hsl(' + hue + ', 90%, 50%)',
  387. 'blocked': 'hsl(' + hue + ', 90%, 80%)',
  388. 'visited': 'hsl(' + hue + ', 30%, 80%)'
  389. };
  390. controlSprites[control] = createPlayerSprite(control);
  391. }
  392. this.color = controlColors[control].normal;
  393. this.sprite = controlSprites[control].normal;
  394. this.visitedColor = controlColors[control].visited;
  395. this.path = undefined;
  396. this.animation = undefined;
  397. this.blockTween = undefined;
  398. dirtyCells.push({'x': this.x, 'y': this.y});
  399. };
  400. var countOptions = function (x, y) {
  401. var dirs = maze.directions[x][y];
  402. return dirs.reduce(function (previousValue, currentValue) {
  403. return previousValue + currentValue;
  404. });
  405. };
  406. var isDeadEnd = function (x, y) {
  407. return countOptions(x, y) == 1;
  408. };
  409. var isFork = function (x, y) {
  410. return countOptions(x, y) > 2;
  411. };
  412. var initialize = function (aspectRatio, size) {
  413. maze.height = Math.sqrt(size / aspectRatio);
  414. maze.width = maze.height * aspectRatio;
  415. maze.height = Math.floor(maze.height);
  416. maze.width = Math.floor(maze.width);
  417. var maxCellX;
  418. var maxCellY;
  419. if (maze.width % 2) {
  420. maxCellX = maze.width-2;
  421. } else {
  422. maxCellX = maze.width-3;
  423. }
  424. if (maze.height % 2) {
  425. maxCellY = maze.height-2;
  426. } else {
  427. maxCellY = maze.height-3;
  428. }
  429. var startX;
  430. var goalY;
  431. if (Math.random() < 0.5) {
  432. startX = 1;
  433. goalX = maxCellX;
  434. } else {
  435. startX = maxCellX;
  436. goalX = 1;
  437. }
  438. var startY;
  439. var goalX;
  440. if (Math.random() < 0.5) {
  441. startY = 1;
  442. goalY = maxCellY;
  443. } else {
  444. startY = maxCellY;
  445. goalY = 1;
  446. }
  447. maze.startPoint = {'x': startX, 'y': startY};
  448. maze.goalPoint = {'x': goalX, 'y': goalY};
  449. };
  450. var createMatrix = function (width, height) {
  451. var matrix = [];
  452. for (var x=0; x<width; x++) {
  453. matrix[x] = new Array(height);
  454. }
  455. return matrix;
  456. };
  457. var onCellGenerated = function (x, y, value) {
  458. maze.walls[x][y] = value;
  459. };
  460. var findDirections = function () {
  461. for (var x=0; x<maze.width; x++) {
  462. for (var y=0; y<maze.height; y++) {
  463. maze.directions[x][y] = getDirections(x, y);
  464. }
  465. }
  466. };
  467. var getDirections = function (x, y) {
  468. var dirs = [0, 0, 0, 0];
  469. if (maze.walls[x][y] == 1) {
  470. return dirs;
  471. }
  472. if (maze.walls[x-1][y] == 0) {
  473. dirs[directions.west] = 1;
  474. }
  475. if (maze.walls[x+1][y] == 0) {
  476. dirs[directions.east] = 1;
  477. }
  478. if (maze.walls[x][y-1] == 0) {
  479. dirs[directions.north] = 1;
  480. }
  481. if (maze.walls[x][y+1] == 0) {
  482. dirs[directions.south] = 1;
  483. }
  484. return dirs;
  485. };
  486. var findForks = function () {
  487. for (var x=0; x<maze.width; x++) {
  488. for (var y=0; y<maze.height; y++) {
  489. if (isDeadEnd(x, y) || isFork(x, y)) {
  490. maze.forks[x][y] = 1;
  491. }
  492. }
  493. }
  494. };
  495. var runLevel = function () {
  496. generate(window.innerWidth / window.innerHeight, gameSize);
  497. updateMazeSize();
  498. updateSprites();
  499. if (presence) {
  500. presence.sendMessage(presence.getSharedInfo().id, {
  501. user: presence.getUserInfo(),
  502. action: 'start',
  503. SizeOfGame: gameSize,
  504. content: maze,
  505. oponentCount: oponentCount
  506. });
  507. }
  508. ended=false;
  509. oponentEnded=0;
  510. players = {};
  511. winner = undefined;
  512. onLevelStart();
  513. }
  514. runLevel();
  515. var restartButton = document.getElementById('restart-button');
  516. restartButton.addEventListener('click', function(e) {
  517. gameSize = 60;
  518. runLevel();
  519. });
  520. Player.prototype.isMoving = function () {
  521. return (this.animation !== undefined);
  522. };
  523. Player.prototype.canGo = function (direction) {
  524. var dirs = maze.directions[this.x][this.y];
  525. var i = directions[direction];
  526. return dirs[i] == 1;
  527. };
  528. Player.prototype.findPath = function (direction) {
  529. var find = function (x, y, direction, first) {
  530. if (!(first) && (isDeadEnd(x,y) || isFork(x,y))) {
  531. return [];
  532. }
  533. var nextCell = function (x, y, direction) {
  534. var newX = x;
  535. var newY = y;
  536. var newDir;
  537. if (direction == 'north') {
  538. newY -= 1;
  539. }
  540. if (direction == 'east') {
  541. newX += 1;
  542. }
  543. if (direction == 'south') {
  544. newY += 1;
  545. }
  546. if (direction == 'west') {
  547. newX -= 1;
  548. }
  549. var dirs = maze.directions[newX][newY];
  550. var tempDirs = dirs.slice(0);
  551. tempDirs[directions[directions.getOpposite(direction)]] = 0;
  552. newDir = directions.orders[tempDirs.indexOf(1)];
  553. return {'x': newX, 'y': newY, 'direction': newDir};
  554. };
  555. var next = nextCell(x, y, direction);
  556. var result = find(next.x, next.y, next.direction, false);
  557. result.unshift(direction);
  558. return result;
  559. };
  560. return find(this.x, this.y, direction, true);
  561. }
  562. Player.prototype.stop = function () {
  563. clearInterval(this.animation);
  564. this.animation = undefined;
  565. }
  566. Player.prototype.showBlocked = function () {
  567. var that = this;
  568. function restoreColor() {
  569. that.color = controlColors[that.control].normal;
  570. that.sprite = controlSprites[that.control].normal;
  571. dirtyCells.push({'x': that.x, 'y': that.y});
  572. }
  573. if (this.blockTween !== undefined) {
  574. this.blockTween.stop();
  575. restoreColor();
  576. }
  577. this.blockTween = new TWEEN.Tween({}).to({}, 300);
  578. this.color = controlColors[this.control].blocked;
  579. this.sprite = controlSprites[this.control].blocked;
  580. dirtyCells.push({'x': this.x, 'y': this.y});
  581. this.blockTween.onComplete(function () {
  582. restoreColor();
  583. });
  584. this.blockTween.start();
  585. var audio = new Audio('sounds/tick'+soundType);
  586. audio.play();
  587. }
  588. Player.prototype.move = function (direction) {
  589. if (this.isMoving()) {
  590. return
  591. }
  592. if (!(this.canGo(direction))) {
  593. this.showBlocked();
  594. return;
  595. }
  596. var that = this;
  597. var next = function () {
  598. var direction = that.path.shift();
  599. if (direction == undefined) {
  600. that.stop();
  601. };
  602. maze.visited[that.x][that.y] = that.visitedColor;
  603. dirtyCells.push({'x': that.x, 'y': that.y});
  604. if (direction == 'north') {
  605. that.y -= 1;
  606. }
  607. if (direction == 'east') {
  608. that.x += 1;
  609. }
  610. if (direction == 'south') {
  611. that.y += 1;
  612. }
  613. if (direction == 'west') {
  614. that.x -= 1;
  615. }
  616. dirtyCells.push({'x': that.x, 'y': that.y});
  617. if (that.x == maze.goalPoint.x && that.y == maze.goalPoint.y) {
  618. onLevelComplete(that);
  619. }
  620. }
  621. this.path = this.findPath(direction);
  622. this.animation = setInterval(next, 40);
  623. };
  624. var mazeClick = function (event) {
  625. if (levelStatus == 'transition') {
  626. return;
  627. }
  628. var currentControl = 'mouse'
  629. if (!(currentControl in players)) {
  630. players[currentControl] = new Player(currentControl);
  631. }
  632. var player = players[currentControl];
  633. var px = cellWidth * (player.x + 0.5);
  634. var py = cellHeight * (player.y + 0.5);
  635. var x = event.clientX;
  636. var y = event.clientY;
  637. var canvas = document.getElementById("maze");
  638. x -= canvas.offsetLeft;
  639. y -= canvas.offsetTop;
  640. var angle = Math.atan2(y - py, x - px) * 180 / Math.PI;
  641. if (45 < angle && angle < 135) {
  642. player.move('south');
  643. } else if (-45 > angle && angle > -135) {
  644. player.move('north');
  645. } else if (-45 < angle && angle < 45) {
  646. player.move('east');
  647. } else {
  648. player.move('west');
  649. }
  650. };
  651. if (mazeCanvas.addEventListener) {
  652. mazeCanvas.addEventListener("mousedown", mazeClick);
  653. } else {
  654. mazeCanvas.attachEvent('onclick', mazeClick);
  655. }
  656. var onKeyDown = function (event) {
  657. if (levelStatus == 'transition') {
  658. return;
  659. }
  660. var currentControl;
  661. var currentDirection;
  662. for (control in controls) {
  663. if (controls[control].indexOf(event.keyCode) != -1) {
  664. currentControl = control;
  665. currentDirection = directions.orders[controls[control].
  666. indexOf(event.keyCode)];
  667. }
  668. }
  669. if (currentControl === undefined) {
  670. return;
  671. }
  672. if (!(currentControl in players)) {
  673. players[currentControl] = new Player(currentControl);
  674. }
  675. var player = players[currentControl];
  676. player.move(currentDirection);
  677. };
  678. document.addEventListener("keydown", onKeyDown);
  679. var animateGoal = function (timestamp) {
  680. var hue = Math.floor(120 * (1 + Math.cos(timestamp / 3000)));
  681. var light = Math.floor(50 + (10 * (1 + Math.cos(timestamp / 300))));
  682. goalColor = 'hsl(' + hue + ', 90%, ' + light + '%)';
  683. dirtyCells.push({'x': maze.goalPoint.x, 'y': maze.goalPoint.y});
  684. }
  685. var animate = function (timestamp) {
  686. TWEEN.update(timestamp);
  687. switch(levelStatus) {
  688. case 'transition':
  689. drawLevelComplete();
  690. break;
  691. case 'starting':
  692. animateGoal(timestamp);
  693. drawLevelStarting();
  694. break;
  695. case 'playing':
  696. animateGoal(timestamp);
  697. dirtyCells.forEach(function (cell) {
  698. drawMazeCell(cell.x, cell.y);
  699. });
  700. dirtyCells = [];
  701. break;
  702. }
  703. requestAnimationFrame(animate);
  704. // HACK: Force redraw on Android
  705. if (/Android/i.test(navigator.userAgent) && document.location.protocol.substr(0,4) != "http") {
  706. mazeCanvas.style.display='none';
  707. mazeCanvas.offsetHeight;
  708. mazeCanvas.style.display='block';
  709. }
  710. };
  711. animate();
  712. // Link presence palette
  713. var presence = null;
  714. var isHost = false;
  715. var palette = new presencepalette.PresencePalette(document.getElementById("network-button"), undefined);
  716. palette.addEventListener('shared', function() {
  717. palette.popDown();
  718. console.log("Want to share");
  719. presence = activity.getPresenceObject(function(error, network) {
  720. if (error) {
  721. console.log("Sharing error");
  722. return;
  723. }
  724. network.createSharedActivity('org.sugarlabs.MazeWebActivity', function(groupId) {
  725. console.log("Activity shared");
  726. isHost = true;
  727. presence.sendMessage(presence.getSharedInfo().id, {
  728. user: presence.getUserInfo(),
  729. action: 'connect'
  730. });
  731. });
  732. network.onDataReceived(onNetworkDataReceived);
  733. network.onSharedActivityUserChanged(onNetworkUserChanged);
  734. });
  735. });
  736. document.getElementById("stop-button").addEventListener('click', function (event) {
  737. maze.visited = createMatrix(maze.width, maze.height);
  738. var data = {
  739. maze: maze,
  740. gameSize: gameSize,
  741. }
  742. var jsonData = JSON.stringify(data);
  743. activity.getDatastoreObject().setDataAsText(jsonData);
  744. activity.getDatastoreObject().save();
  745. });
  746. });
  747. });