Room에 Enter와 Leave 를 통해 채팅에 참여하고 나갈 수 있습니다. 그리고 해당 session들을 순회하면서 모든 세션에 메시지를 보내야 합니다. 여기서 의문 사항은 참여하는 것에는 List(ArrayList) 는 O(1)인데, 나가는 작업 이 발생하면 자칫 O(n) 이 발생할 수도 있다고 생각했습니다. 이유는 해당 session을 찾는데 linear하게 순회 해서 찾아내야 하고, 해당 session을 제거하고나서 빈 공간 을 앞으로 당겨줘야 하기 때문입니다. 이 때문에 제 생각엔 HashSet 을 사용하는 것이 좋을 것이라 생각했습니다. 혹시 List를 사용한 이유 가 Enter Leave 연산보다 Broadcast가 훨씬 많이 이용되고 있기 때문 에 순회가 HashSet보다 List가 훨씬 빠르기 때문인가요? 언제나 양질의 강의에 감사드립니다.
[C#과 유니티로 만드는 MMORPG 게임 개발 시리즈] Part7: MMO 컨텐츠 구현 (Unity + C# 서버 연동 기초)
public Player FindPlayer()는 리턴값 Player가 당장 필요해서 호출하는 함수니까 Push()를 안 하는 건 이해했습니다. 근데 public void Broadcast()도 FindPlayer()와 같은 케이스라고 하셨습니다. 이게 무슨 뜻인지 이해가 안 갑니다. 리턴값이 있는 것도 아니고 그냥 room.Push(room.Broadcast, packet) 처럼 Push로 고쳐도 상관없을 것 같은데 아닌가요? 혹시 Broadcast()는 엄청 많이 호출되는 특수한 함수니까 성능상 이유 때문에 Push()를 생략하고 호출한다거나 그런 건가요? 왜 FindPlayer()와 Broadcast()가 같은 케이스인지 궁금합니다.
안녕하세요, BaseController의 Init() 함수 관련 질문드립니다. 예전 강의에 대한 질문이라 기억하실지 모르겠네요ㅠ BaseController - CreatureController - MonsterController 상속관계가 있는 상황에서, BaseController 내 virtual Init() 가상함수를 만들고 Awake() 내부에 Init()을 호출하도록 코드를 작성하셨습니다. 이때 CreatureController와 MonsterController 모두 Init()함수를 오버라이드한 상태입니다. 이때 가상함수의 함수호출순서가 궁금해서 디버깅해봤는데, MonsterController 생성시 BaseController의 Awake()에 가장 먼저 진입하고, Init() 함수를 호출하는데, 이때 프로그램 다음 실행흐름이 BaseController내부에 virtual로 작성한 Init()함수가 아니라 MonsterController에 override한 Init()함수를 실행하는것이 이해가 안됩니다. BaseController내부 awake()에서 Init()을 호출하면 당연히 같은 클래스인 BaseController의 Init()을 호출하고 끝내야 할것으로 예상했는데, MonsterController의 Init()을 호출한다 게 잘 납득이 안됩니다. 추가설명을 조금 해주실 수 있으실까요?
예전에는 잘 되던 Unity에 연결이 실패합니다. VS 버전 : VS Studio 2022 유니티 버전 : 2021.3.5f1 오류코드 : 대상 컴퓨터에서 연결을 거부했으므로 연결하지 못했습니다 + ip주소 제가 구글링 이후 시도한 방법으로는 Edit > Preferences > External Tools > External Script Editor에서 VS Studio 2022가 맞는지 확인 Regenerate project files로 .csproj 재생성 방화벽이 허용하는 앱에서 VS 2022 허용 체크하기 방화벽 끄고 연결시도하기 유니티와 VS를 껐다 다시 켜기 이렇게 시도해 보았지만 모두 효과가 없었습니다ㅠㅠ
[C#과 유니티로 만드는 MMORPG 게임 개발 시리즈] Part7: MMO 컨텐츠 구현 (Unity + C# 서버 연동 기초)
선생님께서 작성하신 GameObject.cs 코드에 이런 부분이 있었습니다. public ObjectInfo Info { get; set; } = new ObjectInfo(); public PositionInfo PosInfo { get; private set; } = new PositionInfo(); public StatInfo Stat { get; private set; } = new StatInfo(); public GameObject() { // 링크를 이어준다 Info.PosInfo = PosInfo; Info.StatInfo = Stat; } 근데 위 생성자에서 저 '링크'를 이어줬는데 그 후로 Info.PosInfo = new PositionInfo(); 라는 코드를 부주의로 실행시킨다면 링크가 깨지지 않나요? 그 후로는 PosInfo.PosX = 0; 같은 걸 실행해도 PosInfo와 Info.PoInfo는 별개이니 게임오브젝트에 적용이 안 될 것 같은데 이렇게 이해하고 있는데 이게 맞는지 궁금합니다. 그리고 아래처럼 고친다면 이 링크 깨짐 문제가 해결되는지 궁금합니다. public ObjectInfo Info { get; set; } = new ObjectInfo() { // 이걸 안 하고 쓰면 크래시가 난다 PosInfo = new PositionInfo(), StatInfo = new StatInfo() }; public PositionInfo PosInfo { get { return Info.PosInfo; } set { Info.PosInfo = value; } } public StatInfo Stat { get { return Info.StatInfo; } set { Info.StatInfo = value; } }
2시간동안 이리저리 따라해서 계속 널포인트가 뜹니다. PlayerController클레스의 여기에서 널포인트가 뜹니다. Managers.Input.KeyAction += OnKeyboard; 에러내용은 아래이고 NullReferenceException: Object reference not set to an instance of an object Managers.get_Input () (at Assets/Script/Managers/Managers.cs:11) PlayerController.Start () (at Assets/Script/PlayerController.cs:1 2)
개발중 궁금한 것이 하나 생겼습니다. 주위에 있는 특정 오브젝트 (ex 적)들을 찾을 때는 어떤식으로 개발하는게 좋을까요 ? OverlapSpher를 활용하는 방법 Vector3.Distance 또는 magnitude를 활용하는 방법 그리고 이 둘 중 나중에 서버를 추가한다고 할 때 어느 방법이 더 유용한가요 ?
JSON 에서 데이터를 불러오고 장비 아이콘을 클릭 하였을때 장비의 아이콘과 옵션의 수치가 표시되는 부분이 궁금하여 뜯어보다가 질문이 생겼습니다. 무기의 경우에는 HP보너스 스탯이 존재하지 않아도 JSON에서 0을 부여하고 추후에 UI_EquipmentinfoPopup에서 HP 스탯이 0인지 아닌지를 판별하여 장비의 아이콘과 옵션 수치를 표시하고 있는것을 확인 했어요. 그런데 장비의 옵션 수치가 2개를 넘어서 더 여러가지가 되었을 경우에도 이런 방식으로 처리하는것이 효율적일까요? 아래 코드를 스위치문으로 변경하여 스탯에 맞는 아이콘과 옵션을 찾던가 JSON 구조 자체를 변경해야될것 같은데 어떤 방향으로 해야할지 잘 모르겠어서 선생님의 조언을 구합니다.
안녕하세요, 학습순서에 대해서 질문드리려고 합니다. 파트 3을 완강했고, 게임서버4, 디비5, 웹서버6까지 강의를 구매해놓았습니다. 저는 컴퓨터공학을 전공했지만 파트4의 내용들이 꽤 어려운 것 같아서, 파트4->파트6순으로 듣는게 맞는것인지 아니면 6->4 순으로 듣는것이 좀더 좋은지, 혹은 아예 독립적인 내용인지 여쭤보려 글 남깁니다. 전부 다 수강한다는 전제하에 파트 별 학습순서를 추천해주실 수 있을까요:? 감사합니다!
using System; using System.Collections; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace Exam11_1 { class Exam11_1 { public void Run() { int[] intArray = new int[] { 1, 2, 3, 4, 5, 6, 7, 8, 9 }; IEnumerator enumerator = intArray.GetEnumerator(); for (int i = 0; i < intArray.Length; i++) Console.WriteLine(intArray[i]); } } } 도저히 아무리 봐도 저는 왜 아무것도 안 나오는지 모르겠습니다.ㅠㅠ
Square 오브젝트에 ColCheck1함수(print 충돌/접촉/분리)와 ColCheck2 함수(상대방 오브젝트를 사라지게함)를 Inspector창에 같이 넣었을 때, ColCheck1함수를 체크 해제 한다고 해도 ColCheck2 함수가 실행되지 않는 이유를 알 수 있을까요? 꼭, ColCheck1함수를 Inspector창에서 remove 해야만 ColCheck2 함수가 실행되더라고요! 혹시 이것도 충돌 스크립트의 비활성화 문제와 같이 RigidBody 때문인걸까요?
다음 코드에서 IEnumerator Shoot(float delta){ while(true){ GameObject bul = Instantiate(prefab,transform.position,transform.rotation); Destroy(bul,3); float delay = Random.Range(1f,delta); yield return new WaitForSeconds(delay); } } Instantiate(prefab,transform.position,transform.rotation); 이 부분의 현재 위치와 현재 방향은 프리팹의 현재 위치인가요 아니면 이 스크립트를 적용한 오브젝트의 현재 위치인가요? 저는 오브젝트(에너미)에서 프리팹(총알)이 발사되어야하기 때문에 후자로 생각했습니다.
랜덤하게 에너미이동을 진행할 때, speed를 높이면 씬뷰에서 카메라 범위를 벗어나게 되어서 기존 코드에 다음 코드를 추가하였습니다. 그런데도 씬뷰를 벗어나게 되더라고요. 업데이트 부분에서 현재 위치의 x,y가 주어진 범위를 벗어나면 코루트를 시작하는 함수를 호출하여 다시 목표 방향을 설정한건데 왜 벗어나는 걸까요? if(transform.position.x < (-hs.x)){ StartCoroutine(ChangeDir(3f)); } if(transform.position.x > (hs.x)){ StartCoroutine(ChangeDir(3f)); } if(transform.position.y < (-hs.y)){ StartCoroutine(ChangeDir(3f)); } if(transform.position.y > (hs.y)){ StartCoroutine(ChangeDir(3f)); } using System.Collections; using System.Collections.Generic; using UnityEngine; public class EnemyMove1 : MonoBehaviour { public float speed = 3; Vector2 hs; //half screen: 원점 초기화 Vector2 dir; //direction: 원점 초기화 // Start is called before the first frame update void Start() { hs.x = Camera.main.orthographicSize; //카메라 위쪽에서 아래쪽 바라보는 가로의 길이 hs.y = Camera.main.aspect * hs.x; //가로세로 비율 * 가로 길이 = 세로 길이 StartCoroutine(ChangeDir(3f)); } // Update is called once per frame void Update() { Vector2 delta = dir * speed * Time.deltaTime; transform.Translate(delta); //자동으로 z가 0으로 됨. if(transform.position.x < (-hs.x)){ StartCoroutine(ChangeDir(3f)); } if(transform.position.x > (hs.x)){ StartCoroutine(ChangeDir(3f)); } if(transform.position.y < (-hs.y)){ StartCoroutine(ChangeDir(3f)); } if(transform.position.y > (hs.x)){ StartCoroutine(ChangeDir(3f)); } } IEnumerator ChangeDir(float delta){ Vector2 goal; while(true){ goal.x = Random.Range(-hs.x,hs.x); //전체 가로 길이 goal.y = Random.Range(-hs.y,hs.y); //전체 세로 길이 dir = goal - (Vector2) transform.position; //이동방향 = 목표지점 - 현재위치(Vector3) dir.Normalize(); float delay = Random.Range(1f,delta); yield return new WaitForSeconds(delta); } } }