import { _decorator, Component, Node } from "cc"; import { GameCamera } from "./GameCamera"; import { Material } from "cc"; import { GameEvent, GameMgr } from "../../module_basic/scripts/GameMgr"; import { UITransform } from "cc"; import { size } from "cc"; import { Sprite } from "cc"; import { Vec2 } from "cc"; import { renderer } from "cc"; import { IFood, IGameData, IGamePlayer, } from "../../module_basic/shared/protocols/public/game/GameTypeDef"; import { instantiate } from "cc"; import { GameResMgr } from "./GameResMgr"; import { Cell } from "./Cell"; import { UserMgr } from "../../module_basic/scripts/UserMgr"; import { PlayerMovement2D } from "./PlayerMovement2D"; import { PlayerController } from "./PlayerController"; import { UIGameJoystick } from "../ui_game_joystick/UIGameJoystick"; import { UIGameHUD } from "../ui_game_hud/UIGameHUD"; import { UIGameRank } from "../ui_game_rank/UIGameRank"; import { RoomMgr } from "../../module_basic/scripts/RoomMgr"; import { IRoomData, IUserData } from "../../module_basic/shared/types/RoomData"; import { UserInfo } from "../../module_basic/shared/types/UserInfo"; import { color } from "cc"; import { GameLocalData } from "./GameLocalData"; import { director } from "cc"; import { SceneUtil } from "../../core_tgx/base/SceneUtils"; import { ModuleDef } from "../../scripts/ModuleDef"; import { SceneDef } from "../../scripts/SceneDef"; import { GameSceneUtil } from "../../module_basic/scripts/GameSceneUtil"; import { UIGameResult } from "../../module_ball/ui_game/UIGameResult"; const { ccclass, property } = _decorator; @ccclass("GameLocalScene") export class GameLocalScene extends Component { @property(Node) mapRoot: Node; @property(Node) background: Node; @property(Node) objectsRoot: Node; @property(GameCamera) gameCamera: GameCamera; @property(Material) mapMaterial: Material; public static MAP_WIDTH = 10000; public static MAP_HEIGHT = 10000; // private _cellMap: { [key: number]: Cell } = {}; private _foodMap: { [key: number]: Node } = {}; private _foodInfoMap: { [key: number]: IFood } = {}; private _foodPool: Node[] = []; private _backgroundPass: renderer.Pass; private _handleEdgeFactor: number; private _selfPlayers: Cell[] = []; start() { let localUser: UserInfo = { uid: "local-me-uid-xxx-001", }; UserMgr.inst.setUserInfo(localUser); let roomData: IRoomData = GameLocalData.ins.createLocalRoomData( localUser.uid ); RoomMgr.inst.onNet_RoomDataSyncPush({ data: roomData, }); tgx.UIMgr.inst.showUI(UIGameJoystick); tgx.UIMgr.inst.showUI(UIGameHUD); // tgx.UIMgr.inst.showUI(UIGameRank); let selfPlayerInfo = GameLocalData.ins.mockIGamePlayer(); let gameData = GameLocalData.ins.createLocalGameData(selfPlayerInfo); GameMgr.inst.localMode(gameData); GameMgr.inst.onNet_PlayerComesPush({ player: selfPlayerInfo, }); this.initBackground(); this.createCell(selfPlayerInfo); let self = this; let intIn = setInterval(() => { if ( !GameMgr.inst.gameData || GameMgr.inst.gameData.gameState == "gameover" ) { clearInterval(intIn); return; } self.createFoods(); }, 1000); director.on(GameEvent.GAME_EXIT, this.onGameExit, this); director.on(GameEvent.LOCAL_PLAYER_SPAWN, this.onLocalPlayerSpawn, this); } private _lastSpawnTime = 0; private onLocalPlayerSpawn() { if (Date.now() - this._lastSpawnTime < 500) { return; } this._lastSpawnTime = Date.now(); let waitCreateData = []; for (let i = 0; i < this._selfPlayers.length; i++) { console.log(">>>> i", i, this._selfPlayers.length); let oneSelfCell = this._selfPlayers[i]; if (oneSelfCell.player.radius > 50) { oneSelfCell.player.radius = Math.floor(oneSelfCell.player.radius / 2); oneSelfCell.setRadius(oneSelfCell.player.radius); let newInfo = JSON.parse(JSON.stringify(oneSelfCell.player)); newInfo.state = "moving"; let moveDistance = oneSelfCell.player.radius * 3; let move2D = oneSelfCell.getComponent(PlayerMovement2D); let moveDir = move2D.moveDir; let newPos = new Vec2( oneSelfCell.node.getWorldPosition().x + moveDistance * moveDir.x, oneSelfCell.node.getWorldPosition().y + moveDistance * moveDir.y ); newInfo.transform[0] = newPos.x; newInfo.transform[1] = newPos.y; newInfo.transform[3] = move2D.rotDegree; waitCreateData.push(newInfo); } } for (let i = 0; i < waitCreateData.length; i++) { this.createCell(waitCreateData[i]); } } onGameExit() { tgx.UIMgr.inst.closeAll(); GameMgr.inst.localGameOver(); UIGameResult.show(); } protected onDestroy(): void { director.off(GameEvent.GAME_EXIT, this.onGameExit, this); } initBackground() { const extBorder = 4000; let gameData = GameMgr.inst.gameData; const realWidth = gameData.mapWidth + extBorder; const realHeight = gameData.mapHeight + extBorder; this.background.getComponent(UITransform).contentSize = size( realWidth, realHeight ); //@en initialize the material parameters of the background. //@zh 初始化地图背景材质 const halfWidth = gameData.mapWidth / 2; const halfHeight = gameData.mapHeight / 2; let spriteFrame = this.background.getComponent(Sprite).spriteFrame; let uvScale = new Vec2(); let scaler = 0.6; //@en use uv scale to adapt the map size //@zh 使用uv缩放来适配地图大小 uvScale.x = (realWidth / spriteFrame.width) * scaler; uvScale.y = (realHeight / spriteFrame.height) * scaler; this.mapMaterial.setProperty("uvScale", uvScale); this.mapMaterial.setProperty( "halfMapSize", new Vec2(halfWidth, halfHeight) ); //this.mapMaterial.setProperty('edgeColor', new Vec4(1.0,0.0,0.0,1.0)); //this.mapMaterial.setProperty('fadeOutRange', 1000.0); //@en save the material parameter handle for efficient setting of material parameters in update //@zh 保存材质参数相关句柄,方便在update中高效率地设置材质参数 this._backgroundPass = this.mapMaterial.passes[0]; this._handleEdgeFactor = this._backgroundPass.getHandle("edgeFactor"); } tmpColor = color(); createFoods() { let createCount = 1000 - Object.keys(this._foodMap).length; if (createCount <= 0) { return; } if (createCount > 100) { createCount = 100; } for (let i = 0; i < createCount; i++) { this.createFood(GameLocalData.ins.newFoodData()); } } protected update(dt: number): void { let value = Math.sin(Date.now() / 50 / Math.PI); value = value * 0.5 + 0.5; this._backgroundPass.setUniform(this._handleEdgeFactor, value); this.checkFoodAndEat(); this.mergeLogic(); } mergeLogic() { let mergeInfo = this.checkCanMerge(); if (mergeInfo) { let left = mergeInfo.left; let right = mergeInfo.right; left.setRadius(left.player.radius + right.player.radius); let index = this._selfPlayers.indexOf(right); if (this.gameCamera.target === right) { this.gameCamera.target = left; } right.node.destroy(); this._selfPlayers.splice(index, 1); } } checkCanMerge(): { left: Cell; right: Cell; } { let m1 = null; let m2 = null; for (let i = 0; i < this._selfPlayers.length; i++) { let left = this._selfPlayers[i]; for (let j = i + 1; j < this._selfPlayers.length; j++) { let right = this._selfPlayers[j]; if (left === right) { continue; } let distance = Vec2.distance( left.node.getWorldPosition(), right.node.getWorldPosition() ); let ddd = left.player.radius + right.player.radius; if (distance < ddd) { m1 = left; m2 = right; if (m1.player.radius > m2.player.radius) { m1 = right; m2 = left; } return { left: m1, right: m2, }; } } } } async createCell(player: IGamePlayer) { let newCell = instantiate(GameResMgr.inst.cellPrefab); this.objectsRoot.addChild(newCell); newCell.setWorldPosition( player.transform[0], player.transform[1], player.transform[2] ); let cellComp = newCell.getComponent(Cell); cellComp.setPlayer(player); // this._cellMap[player.playerId] = cellComp; if (player.uid == UserMgr.inst.uid) { this._selfPlayers.push(cellComp); let mv2d = newCell.addComponent(PlayerMovement2D); mv2d.needRotation = false; mv2d.moveSpeed = player.speed; mv2d.setPrecision(10); if (this._selfPlayers.length == 1) { this.gameCamera.target = cellComp; } newCell.addComponent(PlayerController); if (player.state == "moving") { mv2d.onMovement(player.transform[3], 1.0); } } } async createFood(fd: IFood) { // console.log("createFood", fd); let newFood = this._foodPool.pop(); if (!newFood) { newFood = new Node(); newFood.addComponent(Sprite); } this._foodInfoMap[fd.id] = fd; this.mapRoot.addChild(newFood); newFood.name = "food_" + fd.id; this._foodMap[fd.id] = newFood; let foodSprites = GameResMgr.inst.foodSprites; let sprf = foodSprites[fd.type % foodSprites.length]; let spr = newFood.getComponent(Sprite); spr.spriteFrame = sprf; this.tmpColor.fromHEX(fd.color.toString(16)); spr.color = this.tmpColor; let scale = (fd.radius * 2) / sprf.rect.width; newFood.setScale(scale, scale, 1.0); newFood.setRotationFromEuler(0, 0, Math.random() * 360); newFood.setWorldPosition(fd.x, fd.y, 0); } checkFoodAndEat() { if (this._selfPlayers.length == 0) { return; } for (let foodId in this._foodMap) { let foodNode = this._foodMap[foodId]; let foodPos = foodNode.getWorldPosition(); for (let i = 0; i < this._selfPlayers.length; i++) { let oneSelfCell = this._selfPlayers[i]; let playerPos = oneSelfCell.node.getWorldPosition(); let distance = Vec2.distance(foodPos, playerPos); let ddd = oneSelfCell.player.radius / 1.5; let foodInfo = this._foodInfoMap[foodId]; if (foodInfo && distance < ddd) { delete this._foodMap[foodId]; delete this._foodInfoMap[foodId]; foodNode.removeFromParent(); this._foodPool.push(foodNode); let oneAdd = foodInfo.radius / 10; oneSelfCell.setRadius(oneSelfCell.player.radius + oneAdd); } } } } }