GameScene.ts 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315
  1. import { _decorator, color, Component, director, instantiate, Label, Node, Prefab, size, screen, Sprite, SpriteFrame, UITransform, Material, renderer, Vec2, Vec4 } from 'cc';
  2. import { GameEvent, GameMgr } from '../../module_basic/scripts/GameMgr';
  3. import { UserMgr } from '../../module_basic/scripts/UserMgr';
  4. import { GameCamera } from './GameCamera';
  5. import { PlayerController } from './PlayerController';
  6. import { UIGameHUD } from '../ui_game_hud/UIGameHUD';
  7. import { UIGameRevive } from '../ui_game_revive/UIGameRevive';
  8. import { PlayerMovement2D } from './PlayerMovement2D';
  9. import { Cell } from './Cell';
  10. import { UIGameMask } from '../ui_game_mask/UIGameMask';
  11. import { UIGameJoystick } from '../ui_game_joystick/UIGameJoystick';
  12. import { UIGameRank } from '../ui_game_rank/UIGameRank';
  13. import { MsgFoodAddedPush } from '../../module_basic/shared/protocols/public/game/MsgFoodAddedPush';
  14. import { IFood, IGamePlayer } from '../../module_basic/shared/protocols/public/game/GameTypeDef';
  15. import { MsgCellDataChange } from '../../module_basic/shared/protocols/public/game/MsgCellDataChange';
  16. import { MsgFoodEatenPush } from '../../module_basic/shared/protocols/public/game/MsgFoodEatenPush';
  17. import { MsgPlayerDataChangedPush } from '../../module_basic/shared/protocols/public/game/MsgPlayerDataChangedPush';
  18. import { RoomMgr } from '../../module_basic/scripts/RoomMgr';
  19. import { UIGameTimeCounter } from '../ui_game_time_counter/UIGameTimeCounter';
  20. import { MsgGameDataChangedPush } from '../../module_basic/shared/protocols/public/game/MsgGameDataChangedPush';
  21. import { MsgGameOverPush } from '../../module_basic/shared/protocols/public/game/MsgGameOverPush';
  22. import { UIGameMatching } from '../../module_basic/ui_game_matching/UIGameMatching';
  23. import { UIGameWinner } from '../../module_basic/ui_game_winner/UIGameWinner';
  24. import { GameResMgr } from './GameResMgr';
  25. import { ExtraNode } from '../../module_basic/scripts/NodeUtils';
  26. const { ccclass, property } = _decorator;
  27. const tmpColor = color();
  28. @ccclass('GameScene')
  29. export class GameScene extends Component {
  30. @property(Node) mapRoot: Node;
  31. @property(Node) background:Node;
  32. @property(Node) objectsRoot: Node;
  33. @property(GameCamera) gameCamera: GameCamera;
  34. @property(Material) mapMaterial:Material;
  35. private _cellMap: { [key: number]: Cell } = {};
  36. private _foodMap: { [key: number]: Node } = {};
  37. private _foodPool: Node[] = [];
  38. private _backgroundPass:renderer.Pass;
  39. private _handleEdgeFactor:number;
  40. async start() {
  41. this.initBackground();
  42. if(RoomMgr.inst.selfUser && !RoomMgr.inst.selfUser.ready){
  43. RoomMgr.inst.rpc_Ready();
  44. }
  45. tgx.UIMgr.inst.closeAll();
  46. if (!RoomMgr.inst.isPlaying && !UIGameMatching.isShowing) {
  47. tgx.UIMgr.inst.showUI(UIGameMatching);
  48. }
  49. else if (GameMgr.inst.gameData.gameState == 'counting' && GameMgr.inst.gameData.gameStateRemainingTime > 0) {
  50. tgx.UIMgr.inst.showUI(UIGameTimeCounter, null, null, { endTime: GameMgr.inst.gameStateEndTime });
  51. }
  52. //tgx.UIMgr.inst.showUI(UIGameMask);
  53. tgx.UIMgr.inst.showUI(UIGameJoystick);
  54. tgx.UIMgr.inst.showUI(UIGameHUD);
  55. tgx.UIMgr.inst.showUI(UIGameRank);
  56. director.on(GameEvent.PLAYER_COMES, this.onPlayerComes, this);
  57. director.on(GameEvent.PLAYER_LEAVES, this.onPlayerLeaves, this);
  58. director.on(GameEvent.PLAYER_DATA_CHANGED, this.onPlayerDataChanged, this);
  59. director.on(GameEvent.CELL_DATA_CHANGED, this.onCellDataChanged, this);
  60. director.on(GameEvent.FOOD_EATEN, this.onFoodEaten, this);
  61. director.on(GameEvent.FOOD_ADDED, this.onFoodAdded, this);
  62. director.on(GameEvent.PLAYER_REVIVE, this.onPlayerRevive, this);
  63. director.on(GameEvent.PLAYER_DIE, this.onPlayerDie, this);
  64. director.on(GameEvent.GAME_DATA_CHANGED, this.onGameDataChanged, this);
  65. director.on(GameEvent.GAME_OVER, this.onGameOver, this);
  66. GameMgr.inst.gameData.players.forEach(player => {
  67. this.createCell(player);
  68. });
  69. let keys = Object.keys(GameMgr.inst.gameData.foodList);
  70. keys.forEach(foodId => {
  71. this.createFood(GameMgr.inst.gameData.foodList[foodId]);
  72. });
  73. }
  74. protected onDestroy(): void {
  75. director.off(GameEvent.PLAYER_COMES, this.onPlayerComes, this);
  76. director.off(GameEvent.PLAYER_LEAVES, this.onPlayerLeaves, this);
  77. director.off(GameEvent.PLAYER_DATA_CHANGED, this.onPlayerDataChanged, this);
  78. director.off(GameEvent.CELL_DATA_CHANGED, this.onCellDataChanged, this);
  79. director.off(GameEvent.FOOD_EATEN, this.onFoodEaten, this);
  80. director.off(GameEvent.FOOD_ADDED, this.onFoodAdded, this);
  81. director.off(GameEvent.PLAYER_REVIVE, this.onPlayerRevive, this);
  82. director.off(GameEvent.PLAYER_DIE, this.onPlayerDie, this);
  83. director.off(GameEvent.GAME_DATA_CHANGED, this.onGameDataChanged, this);
  84. director.off(GameEvent.GAME_OVER, this.onGameOver, this);
  85. }
  86. initBackground(){
  87. const extBorder = 4000;
  88. const realWidth = GameMgr.inst.gameData.mapWidth+extBorder;
  89. const realHeight = GameMgr.inst.gameData.mapHeight+extBorder;
  90. this.background.getComponent(UITransform).contentSize = size(realWidth,realHeight);
  91. //@en initialize the material parameters of the background.
  92. //@zh 初始化地图背景材质
  93. const halfWidth = GameMgr.inst.gameData.mapWidth/2;
  94. const halfHeight = GameMgr.inst.gameData.mapHeight/2;
  95. let spriteFrame = this.background.getComponent(Sprite).spriteFrame;
  96. let uvScale = new Vec2();
  97. let scaler = 0.6;
  98. //@en use uv scale to adapt the map size
  99. //@zh 使用uv缩放来适配地图大小
  100. uvScale.x = realWidth/spriteFrame.width * scaler;
  101. uvScale.y = realHeight/spriteFrame.height * scaler;
  102. this.mapMaterial.setProperty('uvScale', uvScale);
  103. this.mapMaterial.setProperty('halfMapSize', new Vec2(halfWidth,halfHeight));
  104. //this.mapMaterial.setProperty('edgeColor', new Vec4(1.0,0.0,0.0,1.0));
  105. //this.mapMaterial.setProperty('fadeOutRange', 1000.0);
  106. //@en save the material parameter handle for efficient setting of material parameters in update
  107. //@zh 保存材质参数相关句柄,方便在update中高效率地设置材质参数
  108. this._backgroundPass = this.mapMaterial.passes[0];
  109. this._handleEdgeFactor = this._backgroundPass.getHandle('edgeFactor');
  110. }
  111. onPlayerComes(player: IGamePlayer) {
  112. this.createCell(player);
  113. }
  114. onPlayerLeaves(player: IGamePlayer) {
  115. let cell = this._cellMap[player.playerId];
  116. if (!cell) {
  117. return;
  118. }
  119. cell.node.removeFromParent();
  120. cell.node.destroy();
  121. delete this._cellMap[player.playerId];
  122. }
  123. onPlayerDataChanged(msg: MsgPlayerDataChangedPush) {
  124. }
  125. onCellDataChanged(msg: MsgCellDataChange) {
  126. let cell = this._cellMap[msg.playerId];
  127. if (!cell) {
  128. return
  129. }
  130. if (msg.transform != undefined) {
  131. if (msg.playerId != GameMgr.inst.selfPlayer.playerId || msg.forceSync) {
  132. cell.syncTransform(msg.transform, msg.forceSync);
  133. }
  134. }
  135. if (msg.radius != undefined) {
  136. cell.setRadius(msg.radius);
  137. }
  138. if (cell.movement && msg.speed != undefined) {
  139. cell.movement.moveSpeed = msg.speed;
  140. }
  141. }
  142. onFoodEaten(msg: MsgFoodEatenPush) {
  143. for (let i = 0; i < msg.eatenFoods.length; i++) {
  144. let foodId = msg.eatenFoods[i];
  145. let foodNode = this._foodMap[foodId];
  146. delete this._foodMap[foodId];
  147. foodNode.removeFromParent();
  148. this._foodPool.push(foodNode);
  149. }
  150. }
  151. onFoodAdded(msg: MsgFoodAddedPush) {
  152. msg.foods.forEach(food => {
  153. this.createFood(food);
  154. });
  155. }
  156. onPlayerRevive(player: IGamePlayer) {
  157. let cell = this._cellMap[player.playerId];
  158. if (!cell) {
  159. return;
  160. }
  161. cell.setState('normal');
  162. cell.movement?.tempSpeedUp(1, 1);
  163. }
  164. onPlayerDie(player: IGamePlayer) {
  165. let cell = this._cellMap[player.playerId];
  166. if (!cell) {
  167. return;
  168. }
  169. cell.setState('destroyed');
  170. cell.movement?.tempSpeedUp(0, Number.MAX_VALUE);
  171. if (player.playerId == GameMgr.inst.selfPlayer.playerId) {
  172. tgx.UIMgr.inst.showUI(UIGameRevive);
  173. }
  174. }
  175. onGameDataChanged(msg: MsgGameDataChangedPush) {
  176. if (msg.gameState == 'counting' && msg.gameStateRemainingTime > 0) {
  177. tgx.UIMgr.inst.showUI(UIGameTimeCounter, null, null, { endTime: GameMgr.inst.gameStateEndTime });
  178. }
  179. }
  180. onGameOver(msg: MsgGameOverPush) {
  181. tgx.UIMgr.inst.showUI(UIGameWinner,null,null,{
  182. gameOver:msg,
  183. gameData:GameMgr.inst.gameData,
  184. roomData:RoomMgr.inst.data,
  185. });
  186. }
  187. async createCell(player: IGamePlayer) {
  188. let newCell = instantiate(GameResMgr.inst.cellPrefab);
  189. this.objectsRoot.addChild(newCell);
  190. newCell.setWorldPosition(player.transform[0], player.transform[1], player.transform[2]);
  191. let cellComp = newCell.getComponent(Cell);
  192. cellComp.setPlayer(player);
  193. this._cellMap[player.playerId] = cellComp;
  194. if (player.uid == UserMgr.inst.uid) {
  195. let mv2d = newCell.addComponent(PlayerMovement2D);
  196. mv2d.needRotation = false;
  197. mv2d.moveSpeed = player.speed;
  198. mv2d.setPrecision(10);
  199. this.gameCamera.target = cellComp;
  200. newCell.addComponent(PlayerController);
  201. if(player.state == 'moving'){
  202. mv2d.onMovement(player.transform[3],1.0);
  203. }
  204. }
  205. }
  206. async createFood(fd: IFood) {
  207. let newFood = this._foodPool.pop();
  208. if (!newFood) {
  209. newFood = new Node();
  210. newFood.addComponent(Sprite);
  211. }
  212. this.mapRoot.addChild(newFood);
  213. newFood.name = 'food_' + fd.id;
  214. this._foodMap[fd.id] = newFood;
  215. let foodSprites = GameResMgr.inst.foodSprites;
  216. let sprf = foodSprites[fd.type % foodSprites.length];
  217. let spr = newFood.getComponent(Sprite);
  218. spr.spriteFrame = sprf;
  219. tmpColor.fromHEX(fd.color.toString(16));
  220. spr.color = tmpColor;
  221. let scale = fd.radius * 2 / sprf.rect.width;
  222. newFood.setScale(scale, scale, 1.0);
  223. newFood.setRotationFromEuler(0, 0, Math.random() * 360);
  224. newFood.setWorldPosition(fd.x, fd.y, 0);
  225. }
  226. private _hasShown = false;
  227. private _lastSortTime = 0;
  228. update(deltaTime: number) {
  229. let value = Math.sin(Date.now()/50/Math.PI);
  230. value = value * 0.5 + 0.5;
  231. this._backgroundPass.setUniform(this._handleEdgeFactor,value);
  232. if (!this._hasShown && GameMgr.inst.gameData && GameMgr.inst.gameData.gameState == 'playing') {
  233. if (GameMgr.inst.gameStateEndTime - Date.now() < 5000) {
  234. this._hasShown = true;
  235. tgx.UIMgr.inst.showUI(UIGameTimeCounter, null, null, { tips: '游戏即将结束', endTime: GameMgr.inst.gameStateEndTime });
  236. }
  237. }
  238. /*
  239. let winSize = screen.windowSize;
  240. let cameraPos = this.gameCamera.node.worldPosition;
  241. this.objectsRoot.children.forEach(v=>{
  242. const wpos = v.worldPosition;
  243. const radius = v['__radius__'];
  244. const leftSize = -winSize.width /2 - radius + cameraPos.x;
  245. const rightSide = winSize.width / 2 + radius + cameraPos.x;
  246. const topSide = winSize.height /2 + radius + cameraPos.y;
  247. const bottomSide = -winSize.height /2 - radius + cameraPos.y;
  248. v.children[0].children[0].active = wpos.x >= leftSize && wpos.x <= rightSide && wpos.y >= bottomSide && wpos.y <= topSide;
  249. });
  250. */
  251. //
  252. if(Date.now() - this._lastSortTime > 333){
  253. //let t = Date.now();
  254. this.objectsRoot.children.sort((a:ExtraNode,b:ExtraNode)=>{
  255. return a.__radius__ - b.__radius__;
  256. });
  257. this._lastSortTime = Date.now();
  258. //console.log(Date.now() - t,this.objectsRoot.children.length);
  259. }
  260. }
  261. }