
게임매니저에도 포톤뷰를 넣어야한다
안넣어도 photonView를 코드 내에서 쓸때 에러가 나지 않지만, 실제 실행시 에러가 난다
데이터를 관리하는거기 때문에 UDP로 하면 안되고 TCP/IP로 해야한다
void GetConnectCnt()
{
if (PhotonNetwork.IsMasterClient)
{
photonView.RPC("ApplyPlayerCountUpdate", RpcTarget.All); // 모든 클라이언트에게 플레이어 수 업데이트 요청
//photonView 컴퍼넌트를 안붙여도 코드에선 에러를 못잡지만, 실제 실행시 버그남
}
}
_____________________________________________________________
버튼 누를때 총알 발사 안되게 하기
void Update()
{
if (EventSystem.current.IsPointerOverGameObject()) return;
if (this.input.isFire)
{
if (photonView.IsMine) // 로컬이라면
{
Fire(); //그냥 내 Fire호출
photonView.RPC("Fire", RpcTarget.Others);
}
}
}
나가기 버튼 누를때 포 발사가 안되도록 이벤트 훅
______________________________________________________________
Apache(적) 소환
{
if (isGameOver) return;
int count = (int)GameObject.FindGameObjectsWithTag("Apache").Length; // 현재 생성된 탱크의 수를 확인
if(count < 10)
{
int idx = Random.Range(0, spawnList.Count); // 랜덤으로 스폰 포인트 선택
Vector3 spawnPos = spawnList[idx].position; // 선택된 스폰 포인트의 위치
PhotonNetwork.InstantiateRoomObject(
apachePrefab.name,
spawnPos,
Quaternion.identity,
0,
null); // 아파치 생성
}
}
Instantiate 와 InstantiateRoomObject
Instantiate는 소환한 쪽이 게임을 끄거나 방에서 나가면 사라진다
RoomObject는 룸에 소환되서 소환한 쪽이 게임을 끄거나 해도 사라지지 않는다
public class ApacheAI : MonoBehaviourPun
{
void Start()
{
photonView.Synchronization = ViewSynchronization.Unreliable;
//통신 유형을 UDP방식으로
//플레이어 탱크가 여러개 일 경우, 그중 가장 가까운애를 타겟으로 잡는다
//없을때가 있을수 있으니, 그때는 그냥 return 한다.
private Transform TankSearch()
{
#region 탱크가 2개 이상일때의 로직
this.targets = GameObject.FindGameObjectsWithTag(tankTag);
Transform targetTr = null;
if (targets.Length > 0)
{
float minDist = Mathf.Infinity;
foreach (GameObject target in targets)
{
float dist = Vector3.Distance(target.transform.position, myTr.position);
if (dist < minDist)
{
minDist = dist;
targetTr = target.transform;
}
}
if (minDist <= 80f)
{
isSearch = false;
//가장 가까운 탱크를 타겟으로 잡는다
Vector3 targetDist = (targetTr.position - myTr.transform.position);
myTr.rotation = Quaternion.Slerp(myTr.rotation, Quaternion.LookRotation(targetDist.normalized), Time.fixedDeltaTime * rotSpeed);
}
}
else
{
isSearch = true;
}
return targetTr;
#endregion
}
없으면 null이 리턴된다
void Attack()
{
//플레이어 탱크가 여러개 일 경우, 그중 가장 가까운애를 타겟으로 잡는다
//없을때가 있을수 있으니, 그때는 그냥 return 한다.
state = AppacheState.ATTACK;
//Vector3 targetDist = (GameObject.FindWithTag(tankTag).transform.position - myTr.transform.position);
if (TankSearch() == null)
{
isSearch = true;
return;
}
var targetDist = TankSearch().position - myTr.transform.position;
myTr.rotation = Quaternion.Slerp(myTr.rotation, Quaternion.LookRotation(targetDist.normalized), Time.fixedDeltaTime * rotSpeed);
if (Time.time - attackTime >= attackRemiming)
{
attak.Fire(attak.firePosL, attak.leaserBeamL);
attak.Fire(attak.firePosR, attak.leaserBeamR);
attackTime = Time.time;
}
if (targetDist.magnitude > 80f)
isSearch = true;
}
null이면 그대로 순찰돌도록
void FixedUpdate()
{
if (PhotonNetwork.IsMasterClient)
{
if (isSearch)
WayPatrol();
else
Attack();
}
else
{
Attack();
}
}
탱크가 죽었을때 움직이지 못하게 하기
private void ScriptsCtrl(bool onoff)
{
var script = this.GetComponentsInChildren<MonoBehaviourPun>();
foreach (var s in script)
{
s.enabled = onoff;
}
}
ScriptCtrl 생성
MonobehaviorPun을 상속중인 모든 코드를 잡고, 키거나 끈다
IEnumerator Explosion()
{
var eff = Instantiate(this.expEffect, this.transform.position, Quaternion.identity);
Destroy(eff, 2f); // 폭발 이펙트 제거
this.GetComponent<BoxCollider>().enabled = false; // 탱크의 충돌체를 비활성화
this.GetComponent<Rigidbody>().isKinematic = true; // 탱크의 물리 엔진을 비활성화
SetTankVisible(false); // 탱크 메쉬를 비활성화
this.gameObject.tag = "Untagged"; // 탱크의 태그를 언태그로 변경
ScriptsCtrl(false);
yield return ws; // 잠시 대기
SetTankVisible(true); // 탱크 메쉬를 다시 활성화
this.GetComponent<BoxCollider>().enabled = true; // 탱크의 충돌체를 다시 활성화
this.GetComponent<Rigidbody>().isKinematic = false; // 탱크의 물리 엔진을 다시 활성화
this.curHp = this.maxHp; // 부활 시 체력을 최대 체력으로 초기화
this.hpBar.fillAmount = (float)this.curHp / (float)this.maxHp; // 체력바 UI 업데이트
this.gameObject.tag = this.tankTag; // 탱크의 태그를 다시 탱크 태그로 변경
ScriptsCtrl(true); // 탱크의 MonoBehaviourPun 스크립트를 다시 활성화
}
코루틴 내에 ScriptCtrl을 넣는다
__________________________________________________________

네트워크에 연결 됐을때만 Interactable 활성화,
한번 누르면 다시 비활성화
public override void OnJoinedRoom()
{
this.connectInfoTxt.text = "룸 참가 성공";
//룸에 참가 성공시 자동 실행
// 룸에 참가한 모든 참가자가 MainScene으로 이동하게 설정
PhotonNetwork.LoadLevel("MainScene");
}
________________________________________________
탱크에서 썼던 방법
IEnumerator LoadBattleFieldScene()
{
PhotonNetwork.IsMessageQueueRunning = false; // 씬을 이동하는 동안 클라우드 서버로부터 네트워크 메시지 수신 중단
AsyncOperation ao = SceneManager.LoadSceneAsync(1); // 씬 비동기적으로 로딩
yield return ao;
}
코루틴을 이용해서 비동기적으로 씬 로딩
LoadLevel과 LoadScene의 차이점
다른사람의 컴퓨터에서도 자동으로 실행되서 방장과 같은 씬을 로드하게 된다
뒤늦게 들어가더라도 LoadLevel로 같은 씬에 도착 했을 때, 해당 씬의 모습이 다른 플레이어가 보는 씬의 모습과 동일하게 자동구성되어 굉장히 편하다
'2025유니티수업' 카테고리의 다른 글
| 코드 온오프와 상관 없이 자동 실행되는 애들 (0) | 2025.07.22 |
|---|---|
| 0714(포톤 채팅) (1) | 2025.07.14 |
| 0711 Photon(Pun, Realtime) (0) | 2025.07.11 |
| 0710 유니티(LineRenderer, 사운드매니저) , Pun2 (3) | 2025.07.10 |
| 0709 유니티(헬기, ) (0) | 2025.07.09 |