Cell.ts 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316
  1. import {
  2. _decorator,
  3. AssetManager,
  4. assetManager,
  5. color,
  6. Color,
  7. Component,
  8. instantiate,
  9. Label,
  10. Node,
  11. Prefab,
  12. RichText,
  13. Sprite,
  14. SpriteFrame,
  15. tween,
  16. v3,
  17. Vec2,
  18. Vec3,
  19. Widget,
  20. } from "cc";
  21. import { GameAudioMgr } from "./GameAudioMgr";
  22. import { PlayerMovement2D } from "./PlayerMovement2D";
  23. import { IGamePlayer } from "../../module_basic/shared/protocols/public/game/GameTypeDef";
  24. import { CellBullet } from "./CellBullet";
  25. import { GameMgr } from "../../module_basic/scripts/GameMgr";
  26. import { CellMgr } from "./CellMgr";
  27. import { UserMgr } from "../../module_basic/scripts/UserMgr";
  28. import { TEAM_ID_MAP } from "../../module_basic/shared/types/TeamInfo";
  29. import { ModuleDef } from "../../scripts/ModuleDef";
  30. import { RoomMgr } from "../../module_basic/scripts/RoomMgr";
  31. import { GameResMgr } from "./GameResMgr";
  32. import { GenderIcon } from "../../module_basic/scripts/GenderIcon";
  33. import { ExtraNode, NodeUtils } from "../../module_basic/scripts/NodeUtils";
  34. import { SpriteUtils } from "../../module_basic/scripts/SpriteUtils";
  35. import { utils } from "cc";
  36. const { ccclass, property } = _decorator;
  37. const tempV2 = new Vec2();
  38. const tempV3 = new Vec3();
  39. const tempColor = new Color();
  40. @ccclass("Cell")
  41. export class Cell extends Component {
  42. @property(Node) visualRoot: Node;
  43. @property(Node) body: Node;
  44. @property(Node) firePoint: Node;
  45. @property(Node) dir: Node;
  46. @property(Sprite) sprIcon: Sprite;
  47. @property(Sprite) sprEfx: Sprite;
  48. @property(Label) lblName: Label;
  49. @property(Label) lblTeam: Label;
  50. @property(Label) lblLocation: Label;
  51. @property(GenderIcon) genderIcon: GenderIcon;
  52. @property(Label) lblPos: Label;
  53. public player: IGamePlayer;
  54. public movement: PlayerMovement2D;
  55. private _transformsCache: number[][] = [];
  56. start() {
  57. this.movement = this.node.getComponent(PlayerMovement2D);
  58. CellMgr.inst.addCell(this);
  59. }
  60. setPlayer(player: IGamePlayer) {
  61. this.player = player;
  62. this.dir.active = player.uid == UserMgr.inst.uid;
  63. this.setRadius(player.radius);
  64. this.lblName.string = player.roleName;
  65. let teamName = TEAM_ID_MAP[player.teamId].name;
  66. this.lblTeam.string = `[${teamName}]`;
  67. if (GameMgr.inst.selfPlayer.teamId == player.teamId) {
  68. tempColor.fromHEX("#00EF00");
  69. this.lblTeam.color = tempColor;
  70. tempColor.fromHEX("#000000");
  71. this.lblTeam.outlineColor = tempColor;
  72. } else {
  73. tempColor.fromHEX("#FF0000");
  74. this.lblTeam.color = tempColor;
  75. tempColor.fromHEX("#FFFFFF");
  76. this.lblTeam.outlineColor = tempColor;
  77. }
  78. this.setColor(player.color);
  79. this.setState("normal");
  80. this.lblLocation.string = player.location || "保密";
  81. this.lblLocation.updateRenderData(true);
  82. this.genderIcon.setGender(RoomMgr.inst.getUser(player.uid)?.gender);
  83. this.lblLocation.node.children.forEach((v) => {
  84. v.getComponent(Widget).updateAlignment();
  85. });
  86. SpriteUtils.setTeamSkin(this.sprIcon, player.teamId);
  87. this.setColor(0xffffffff);
  88. }
  89. setState(state: "normal" | "destroyed") {
  90. if (state == "normal") {
  91. this.visualRoot.active = true;
  92. } else if (state == "destroyed") {
  93. this.visualRoot.active = false;
  94. }
  95. }
  96. displayPos() {
  97. let scale = this.body.scale.x;
  98. this.lblPos.string = `${this.node.worldPosition.x.toFixed(
  99. 0
  100. )},${this.node.worldPosition.y.toFixed(0)}\n
  101. scale:${scale.toFixed(1)}
  102. radius:${this.player.radius.toFixed(0)}
  103. `;
  104. }
  105. private _scaleAnimDoing = false;
  106. setRadius(radius: number) {
  107. if (radius > 2000) {
  108. return;
  109. }
  110. this.player.radius = radius;
  111. let self = this;
  112. if (this._scaleAnimDoing) {
  113. return;
  114. }
  115. this._scaleAnimDoing = true;
  116. let scale = (radius * 2) / 150;
  117. // this.body.setScale(scale, scale, 1.0);
  118. this.lblLocation.node.active = radius > 75;
  119. tween(this.body)
  120. // .to(0.1, { scale: new Vec3(scale * 1.05, scale * 1.05, 1.0) })
  121. .to(
  122. 0.2,
  123. { scale: new Vec3(scale, scale, 1.0) },
  124. {
  125. onComplete: () => {
  126. (self.node as ExtraNode).__radius__ = radius;
  127. self._scaleAnimDoing = false;
  128. },
  129. }
  130. )
  131. .start();
  132. }
  133. setColor(colorVal: number) {
  134. Color.fromUint32(tempColor, colorVal | 0xff000000);
  135. this.sprIcon.color = tempColor;
  136. }
  137. protected onDestroy(): void {
  138. CellMgr.inst.removeCell(this);
  139. }
  140. shootAnim(cb?: Function) {
  141. let t = GameMgr.inst.selfPlayer.transform;
  142. tempV3.set(t[0], t[1], t[2]);
  143. let volume = GameAudioMgr.getVolumeByDist(this.node.worldPosition, tempV3);
  144. GameAudioMgr.playOneShot("sounds/sfx_shoot", volume);
  145. //animation
  146. }
  147. fireBullet(
  148. pos: { x: number; y: number; z: number },
  149. rotationDegrees: number
  150. ) {
  151. let bullet = instantiate(GameResMgr.inst.bulletPrefab);
  152. this.node.parent.addChild(bullet);
  153. bullet.setWorldPosition(pos.x, pos.y, pos.z);
  154. bullet.setRotationFromEuler(0, 0, rotationDegrees);
  155. let rotationAngle = (rotationDegrees / 180) * Math.PI;
  156. let dir = tempV2.set(Math.cos(rotationAngle), Math.sin(rotationAngle));
  157. bullet.getComponent(CellBullet).moveDir = dir;
  158. return bullet;
  159. }
  160. private computeTargetDist(x1: number, y1: number, x2: number, y2: number) {
  161. let dx = x1 - x2;
  162. let dy = y1 - y2;
  163. let dist = Math.sqrt(dx * dx + dy * dy);
  164. return dist;
  165. }
  166. syncTransform(trans: number[], forceSync: boolean) {
  167. if (forceSync) {
  168. this._transformsCache = [];
  169. this.node.setWorldPosition(trans[0], trans[1], trans[2]);
  170. if (this.movement) {
  171. this.movement.onMovement(trans[3], 1.0);
  172. }
  173. } else {
  174. this._transformsCache.push(trans);
  175. let dist = 0;
  176. let pos = this.node.worldPosition;
  177. let lastX = pos.x;
  178. let lastY = pos.y;
  179. this._transformsCache.forEach((v) => {
  180. dist += this.computeTargetDist(lastX, lastY, v[0], v[1]);
  181. lastX = v[0];
  182. lastY = v[1];
  183. });
  184. //distance is too far
  185. if (dist >= this.player.speed) {
  186. this._transformsCache = [];
  187. this.node.setWorldPosition(trans[0], trans[1], trans[2]);
  188. console.log("distance is too far,force sync transform");
  189. }
  190. }
  191. }
  192. protected update(dt: number): void {
  193. if (this.player.protectedTime > 0) {
  194. this.sprEfx.node.active = true;
  195. tempColor.set(this.sprEfx.color);
  196. //clamp to 0.2 ~ 0.8
  197. tempColor.a = 255 * (Math.sin(Date.now() / 50 / Math.PI) * 0.6 + 0.2);
  198. this.sprEfx.color = tempColor;
  199. } else {
  200. this.sprEfx.node.active = false;
  201. }
  202. }
  203. private _lastRotation = NaN;
  204. private _lastSyncTime = 0;
  205. protected lateUpdate(dt: number): void {
  206. if (GameMgr.inst.gameData && GameMgr.inst.gameData.gameState != "playing") {
  207. return;
  208. }
  209. if (this.player.playerId == GameMgr.inst.selfPlayer.playerId) {
  210. this.lateUpdate_SelfPlayer(dt);
  211. } else {
  212. this.lateUpdate_OtherPlayers(dt);
  213. }
  214. this.displayPos();
  215. }
  216. lateUpdate_SelfPlayer(dt: number) {
  217. if (this.movement?.getRealSpeed() > 0) {
  218. let pos = this.node.worldPosition;
  219. this.dir.setWorldRotationFromEuler(0, 0, this.movement.realDegree);
  220. let rotation = this.movement.rotDegree;
  221. if (
  222. rotation != this._lastRotation ||
  223. Date.now() - this._lastSyncTime > 2000
  224. ) {
  225. this._lastRotation = rotation;
  226. this._lastSyncTime = Date.now();
  227. //console.log(rotation);
  228. GameMgr.inst.sendMsg_CellDataChange(pos.x, pos.y, pos.z, rotation);
  229. }
  230. }
  231. }
  232. lateUpdate_OtherPlayers(dt: number) {
  233. if (this.player.state != "moving") {
  234. return;
  235. }
  236. if (this._transformsCache.length == 0) {
  237. let rotation = (this.player.transform[3] / 180) * Math.PI;
  238. let dirX = Math.cos(rotation);
  239. let dirY = Math.sin(rotation);
  240. let len = Math.sqrt(dirX * dirX + dirY * dirY);
  241. if (len > 0) {
  242. dirX /= len;
  243. dirY /= len;
  244. }
  245. let pos = this.node.worldPosition;
  246. let targetX = pos.x + dirX * this.player.speed * dt;
  247. let targetY = pos.y + dirY * this.player.speed * dt;
  248. this.node.setWorldPosition(targetX, targetY, pos.z);
  249. } else {
  250. //加速处理
  251. let speed = this._transformsCache.length * this.player.speed;
  252. let movement = speed * dt;
  253. while (movement > 0 && this._transformsCache.length > 0) {
  254. let pos = this.node.worldPosition;
  255. let target = this._transformsCache[0];
  256. let dist = this.computeTargetDist(pos.x, pos.y, target[0], target[1]);
  257. if (dist > movement) {
  258. let factor = movement / dist;
  259. let targetX = pos.x * (1 - factor) + target[0] * factor;
  260. let targetY = pos.y * (1 - factor) + target[1] * factor;
  261. this.node.setWorldPosition(targetX, targetY, pos.z);
  262. movement = 0;
  263. } else {
  264. movement -= dist;
  265. this.node.setWorldPosition(target[0], target[1], pos.z);
  266. this._transformsCache.shift();
  267. }
  268. }
  269. }
  270. NodeUtils.clampInMapBoundary(this.node as ExtraNode);
  271. }
  272. }