선생님, 강의 열심히 보고 있는데 제가 5월 중순부터 시작하면서 조금 일찍 시작했는데도 불구하고 암기 할 게 너~~~~~~무 많아서 큰일입니다 ㅠㅠ 단권화 시키려고 실기용 교재를 샀는데 정말 정말 이것만큼은 꼭! 외우고 가야하는 코드나 문법같은거를 정리해주실 수 있나요? (강의나...파일로) 사실 고득점 합격은 바라지도 않고 60점 턱걸이로라도 너무 붙고싶습니다!
안녕하세요. 국비교육으로 유니티를 학습한 후 스타트업에서 중견회사(게임분야) 이상으로 이직(신입)을 준비하고 있는 중생입니다.. 지금은 전공자들에 비해 부족한 CS지식과 C++, 자료구조, 알고리즘 공부에 주력하고 있습니다. 고민이 되는 부분은 중견회사 이상(컴투스, 데브캣, 넷마블, 넥슨, 펄어비스, 스마일게이트 등등)에 어필하기 위해 뭐가 필요할까 라는 부분입니다. 일단 제가 생각하는 부분으로는 학습한 내용을 블로그에 정리 학습한 내용을 응용한 미니프로젝트 포트폴리오 1개(아직 방향성 못 잡음..) 입니다. 고민사항은 이렇습니다. 위에 1번, 2번 같은 부분은 제가 공부한 내용들을 토대로 고민한 흔적들을 기록할 예정인데 이 부분이 어필이 될까요? (참고할 만한 블로그를 개인적으로 즐찾해놓긴 했는데 추가로 추천해주면 감사하겠습니다..) 포트폴리오는 MMORPG나 FPS게임 같이 시중 게임을 모작해봐야 어중간할 것 같은데 어떤 방향성을 잡고 가야할 지 감이 오지 않습니다. 게임을 즐겨하지는 않지만 게임의 요소들을 엔진으로 구현해 보는 걸 좋아하는데요. 굳이 전체 게임을 구현하지 않더라도 제가 관심있는 부분(예를 들어 이펙트, 쉐이더)에 집중해서 만들어도 어필이 될까요..? 추가로 제가 놓치고 있는 중요한 부분을 말씀해 주시면 경청하겠습니다. 주변에 게임업계 종사자가 없어서 질문드립니다. 감사합니다.
안녕하세요 교수님. 강의 정말 잘 듣고있습니다. 현재 파머완 강의 8장 중간까지 들은 학생입니다. 저는 원래 교수님의 컴퓨터비전 로드맵을 따라갈 생각이었으나, 아직 머신러닝에 대한 기초가 부족하다고 느껴서(어느정도는 알았지만 개념적으로 부족했습니다) 이 강의와 책을 본 후 로드맵을 본격적으로 따라가려고 했습니다. 처음 강의인 CNN 강의에서 선수지식이 '기본적인 머신러닝에 대한 개념 이해' 정도로 작성되어있는데 꼭 나머지 8,9장까지 마무리하고 넘어가야할까요? 아 그리고 로드맵 강의를 수강하면서 앱(?)같은 것도 만들어볼 기회가 있을까요? 감사합니다!
안녕하세요! 강의 열심히 듣고있는 클라이언트 개발자를 꿈꾸는 한 수강생입니다. 수강전 문의에 글을 남겼었는데 답장이 오지 않아 이렇게 글 남깁니다. 저번 루키스님께서 포폴을 제작할 때 조그만한 서버라도 포함해 온라인으로 제작하라고 조언을 해주셔서 이 시리즈를 듣고 있습니다. 1. 포폴을 제작하는데 (강의를 듣는데) 있어서 4강 이후 5,6강이 필수적인가요?? 바로 7강으로 넘어가도 문제 없을지가 궁금합니다!(만약 클라이언트 개발자여도 알아둬야 하는 지식이라면 듣겠습니다!) 2. 이 시리즈는 2D로 제작 한 것으로 알고 있습니다. 만약 3D로 제작할 경우 코드나 스킬등이 많이 바뀌는지 궁금합니다!(강의 따라서 한번 만들어보고 3D rpg로 적용해 포폴을 제작 하려고 합니다.) 항상 감사드립니다!! 언리얼도 빨리 나왔으면 좋겠네요!!
저는 rider 를 통해 강의를 수강 중입니다. NetCore.Web/Program.cs 파일에 직접 추가하시면 됩니다. using NetCore.Services.Interfaces; using NetCore.Services.Svcs; var builder = WebApplication.CreateBuilder(args); // Add services to the container. builder.Services.AddControllersWithViews(); builder.Services.AddMvc(); // add dependencies with constructor builder.Services.AddScoped<IUser, UserService>(); var app = builder.Build(); // ...
안녕하세요! 교수님 강의를 듣고 있는 수강생입니다 ! 강의를 복습할 때 개인 블로그에 수업 내용을 정리하면서 게시를 하고 싶은데요 ! 강의 내용에 포함되어있는 이미지를 사용해서 간단하게 요약해서 게시를 하고 싶은데 저작권법에 걸리는 지 여쭤보고 싶어서 글을 작성합니다 ! 개인 블로그에 강의 자료(이미지 등)을 사용해서 복습 용도로 게시를 해도 될까요 ??
[C#과 유니티로 만드는 MMORPG 게임 개발 시리즈] Part1: C# 기초 프로그래밍 입문
수학과에 강화학습을 공부하고 있는 학생입니다. 그래서 유니티를 통해 강화학습을 배우면서 동시에 게임개발관련 지식겸 이 강의를 구매하여 듣고있습니다. 제 목표는 강화학습을 이용해서 적 몬스터를 ai로 학습시켜서 알고리즘을 짜고싶은 그런 계획인데 컴공지식이 전무한 저로써는 모르는 궁금점이 몇가지가 있습니다. 1. 일반적으로 게임에서 적 몬스터가 플레이어를 발견하면 공격, 플레이어가 xx행동을 하면 공격 중지 이런 식으로 전통적인 알고리즘을 사용할 때 와 제가 위에서 말한 ai모델을 사용할 때와 성능 차이가 크게 날까요? (성능은 몬스터가 잘움직이냐가 아니라 게임에서의 렉이나 그런거를 말하는겁니다.) 2. 아직 몬스터의 행동 알고리즘을 안배워서 몰라서 그런데, 만약 몬스터의 알고리즘을 직접짜기 vs 모델을 학습해서 그 모델을 적용시키기중 후자가 더 편하다면 강화학습으로 코딩하는 것이 더 좋겠죠? 3. 혹시 알고계신다면 현재 강화학습은 게임직군에서의 어느정도의 위상을 가지고있나요? 게임+강화학습을 하시는 분들을 찾기가어려워 이렇게 질문을 하게됩니다..!
분류(Classification) 성능 평가지표 개요와 정확도(Accuracy) 소개 에서 MNIST를 모두 0으로 예측하는 코드에서 fakepred와 y_test를 비교하는데요 이때 type은 같은데 하나는 1차원 배열이고 또 다른 하나는 column을 1로 가진 2차원 배열인데 이렇게 shape이 달라도 accuracy_score를 통해 비교할 수 있나요?
안녕하세요, Unity UI Button onClick 이벤트 설정 위치에 대한 고민이 있어서 질문 글을 남깁니다. Button의 onClick 이벤트에 호출할 함수를 등록하는 방법에는 아래와 같이 두 가지 방법이 있다고 알고 있습니다. 1. 인스펙터 창에서 Button 게임오브젝트의 onClick 이벤트에 호출할 함수를 등록 코드 상에서 등록 Button sampleBtn; void Start() { sampleBtn.onClick.AddListener( () => { Debug.Log("Hello World"); }); } 첫 번째 방법으로 구현을 하면 프로젝트를 처음 열어본 사람의 입장에서 보았을 때 특정 버튼을 누른 경우 어떤 동작이 이어질지 전체적인 흐름을 파악하기 쉽다는 장점이 있습니다. 그리고 연결된 함수를 타고 가서 관련 스크립트를 열어볼 수도 있고요. 하지만 매번 인스펙터 창에서 하나씩 넣어주어야 해서 귀찮(?)을 수 있다는 단점이 있습니다. 두 번째 방법으로 구현을 하면 게임오브젝트를 하나 하나 눌러가면서 인스펙터 창에서 onClick 이벤트에 등록된 함수를 확인할 필요 없이, 코드만 보면 되기 때문에 편할 수도 있다는 장점이 있습니다. 하지만 처음 프로젝트를 열어본 사람은 어디에 뭐가 있는지 어떻게 연결되어있는지 초반에 조금 헤멜 수 있다는 단점이 있습니다. (뭔가 컨벤션이 정해져 있지 않고 아무런 정보 없이 프로젝트를 처음 열어본 사람) 둘 중 어느 방법을 추천하시는지 궁금해서 질문 남깁니다!!!
안녕하세요. x:Name 을 통해 코드 상에서 콘트롤(이 맞나요?)에 접근하는 원리에 대해서는 이해했습니다. 프로퍼티를 하나씩 살펴보는 중인데, x:Uid 의 쓰임에 대해 궁금합니다. 프로퍼티의 이름만 봤을 땐 고유 식별자로서 역할을 할 것 같은데요... 혹시 코드 상에서도 Uid 를 통해 콘트롤에 접근할 수 있을까요? '지역화'에 사용한다는 설명은 확인했는데, 지역화가 무엇인지, 실제로 어떻게 사용하는지에 대한 예제를 알고 싶습니다. WPF 관련 한국어 강의가 부족했는데, 강의를 만들어주셔서 감사합니다. :)
[C#과 유니티로 만드는 MMORPG 게임 개발 시리즈] Part7: MMO 컨텐츠 구현 (Unity + C# 서버 연동 기초)
수업시간에 구글 프로토콜 버퍼를 이용하여 프로토콜 패킷을 생성하는데, 클라이언트와 서버단에서 PacketHandler에는 함수를 직접 정의해서 생성해야합니다. 이 과정이 꽤 번거롭고 이름도 정확하게 맞춰야합니다. 그래서 자동 툴을 이용하여 작성해야 할 코드를 자동으로 정확하게 생성해주는 툴을 제작하여 배포합니다. 이 기능의 배포는 여기에서만 합니다. 이 기능은 UnityEditor Tools를 구현하여 이용하는 방식입니다. [여기를 클릭하여 다운로드] 스크립트를 다운로드합니다. (또는 아래 스크립트를 복사하여 작성) 유니티 에디터 Assets 폴더 안에 넣습니다. 위치는 상관 없습니다. 유니티 에디터 상단 바에서 Tools/Bonnate/Socket/Generate Protocol Code From Enum을 선택합니다. 프로토콜 버퍼 에디터에서 MsgId에 프로토콜 이름을 복사합니다. 주석을 지원합니다. /* 주석은 구분 없이 모든곳에 동일하게 생성됩니다. // 주석은 프로토콜의 주석으로 생성됩니다. 본 글에서는 아래 이미지와 같이 복사하였습니다. 복사한 값 Enum 스니펫을 Tools 윈도우 창에 붙여넣기합니다. 우측의 변환 버튼을 클릭합니다. 생성된 값을 각 스크립트에 붙여넣기합니다. 변환된 프로토콜 코드는 프로토콜버퍼 에디터 구현부에 붙여넣으세요. 서버가 보내는 프로토콜은 클라이언트단(유니티)에서 사용합니다. 클라이언트에서 보내는 프로토콜은 서버단에서 사용합니다. 전체 코드입니다. 위에서 다운로드 받은 파일과 동일합니다. /* * GenerateProtocolCodeFromEnum - Enum을 이용한 프로토콜 코드 생성을 위한 유니티 에디터 창 * 작성자: [Bonnate] https://bonnate.tistory.com/ * 라이선스: 없음 (명시적인 라이선스 없이 제공됨) * * 설명: * 이 스크립트는 Enum 스니펫에서 프로토콜 코드, 클라이언트 핸들러 코드, 서버 핸들러 코드를 생성하기 위한 유니티 에디터 창을 정의합니다. * 입력한 Enum 스니펫을 자동으로 프로토콜 코드로 변환하고, 해당하는 클라이언트와 서버 핸들러 함수를 생성합니다. * 생성된 코드는 클립보드에 복사하여 추가적인 사용이 가능합니다. * * 주의 사항: * 이 스크립트는 [C#과 유니티로 만드는 MMORPG 게임 개발 시리즈] https://www.inflearn.com/roadmaps/355 * 의 기능을 이용하기 위해 작성된 스크립트입니다. * * 사용 방법: * 1. 이 스크립트를 유니티 프로젝트의 Editor 폴더에 첨부합니다. * 2. GenerateProtocolCodeFromEnum 창을 열기 위해 Tools -> Bonnate -> Socket -> Generate Protocol Code From Enum을 선택합니다. * 3. 입력 텍스트 영역에 Enum 코드 스니펫을 입력합니다. * 4. "변환" 버튼을 클릭하여 프로토콜 코드, 클라이언트 핸들러 코드, 서버 핸들러 코드를 생성합니다. * 5. 생성된 코드는 각각의 텍스트 영역에 표시됩니다. * 6. 해당 영역의 텍스트를 클립보드에 복사하려면 옆에 있는 버튼을 클릭합니다. * 7. 생성된 코드를 복사하여 각 코드에 붙여넣기하여 편리하게 프로토콜을 디자인합니다. * * 참고: 이 스크립트는 현재 상태로 제공되며 일부 제한 사항과 문제가 있을 수 있습니다. * 개인적으로 업데이트 되나, 온라인(깃허브 리포지트리 등)에 배포하지는 않을 예정입니다. */ #if UNITY_EDITOR using UnityEngine; using UnityEditor; using System.Text; using System.Text.RegularExpressions; public class GenerateProtocolCodeFromEnum : EditorWindow { private string mInputText = ""; private string mProtocolText = ""; private string mClientHandlerText = ""; private string mServerHandlerText = ""; private Vector2 mScrollPosition; [MenuItem("Tools/Bonnate/Socket/Generate Protocol Code From Enum")] public static void ShowWindow() { GetWindow<GenerateProtocolCodeFromEnum>("Generate Protocol Code From Enum"); } private void OnGUI() { mScrollPosition = EditorGUILayout.BeginScrollView(mScrollPosition, GUILayout.ExpandHeight(true)); // 입력 텍스트 영역 EditorGUILayout.BeginHorizontal(); GUILayout.Label("Enum 코드 스니펫 입력"); // 변환 버튼 if (GUILayout.Button("변환", GUILayout.Width(80))) { mInputText = RemoveCommonIndentation(mInputText); GenerateProtocol(); EditorGUIUtility.systemCopyBuffer = mProtocolText; // 변환된 텍스트를 클립보드에 복사 } EditorGUILayout.EndHorizontal(); mInputText = EditorGUILayout.TextArea(mInputText, GUILayout.ExpandHeight(true)); GUILayout.Space(30); // 프로토콜 코드 영역 EditorGUILayout.BeginHorizontal(); GUILayout.Label("변환된 프로토콜 코드"); // 복사 버튼 if (GUILayout.Button("복사", GUILayout.Width(80))) { EditorGUIUtility.systemCopyBuffer = mProtocolText; // 프로토콜 코드를 클립보드에 복사 } EditorGUILayout.EndHorizontal(); mProtocolText = EditorGUILayout.TextArea(mProtocolText, GUILayout.ExpandHeight(true)); GUILayout.Space(10); // 서버 핸들러 영역 EditorGUILayout.BeginHorizontal(); GUILayout.Label("서버가 보내는 프로토콜 (클라이언트단에서 구현)"); // 버튼 if (GUILayout.Button("복사", GUILayout.Width(80))) { EditorGUIUtility.systemCopyBuffer = mServerHandlerText; // 서버 핸들러 코드를 클립보드에 복사 } EditorGUILayout.EndHorizontal(); mServerHandlerText = EditorGUILayout.TextArea(mServerHandlerText, GUILayout.ExpandHeight(true)); GUILayout.Space(10); // 클라이언트 핸들러 영역 EditorGUILayout.BeginHorizontal(); GUILayout.Label("클라이언트가 보내는 프로토콜 (서버단에서 구현)"); // 버튼 if (GUILayout.Button("복사", GUILayout.Width(80))) { EditorGUIUtility.systemCopyBuffer = mClientHandlerText; // 클라이언트 핸들러 코드를 클립보드에 복사 } EditorGUILayout.EndHorizontal(); mClientHandlerText = EditorGUILayout.TextArea(mClientHandlerText, GUILayout.ExpandHeight(true)); EditorGUILayout.EndScrollView(); GUILayout.Space(20); GUILayout.BeginHorizontal(); EditorGUILayout.LabelField("Powered by: Bonnate"); if (GUILayout.Button("Github", GetHyperlinkLabelStyle())) { OpenURL("https://github.com/bonnate"); } if (GUILayout.Button("Blog", GetHyperlinkLabelStyle())) { OpenURL("https://bonnate.tistory.com/"); } GUILayout.EndHorizontal(); GUILayout.BeginHorizontal(); EditorGUILayout.LabelField("이 기능은 인프런 강의의 기능을 편리하게 사용하기 위해 구현되었습니다."); if (GUILayout.Button("[C#과 유니티로 만드는 MMORPG 게임 개발 시리즈]", GetHyperlinkLabelStyle())) { OpenURL("https://www.inflearn.com/roadmaps/355"); } GUILayout.EndHorizontal(); } private GUIStyle GetHyperlinkLabelStyle() { GUIStyle style = new GUIStyle(GUI.skin.label); style.normal.textColor = new Color(0f, 0.5f, 1f); style.stretchWidth = false; style.wordWrap = false; return style; } private void OpenURL(string url) { EditorUtility.OpenWithDefaultApp(url); } private string RemoveCommonIndentation(string input) { string[] lines = input.Split('\n'); // 찾아낼 공백 패턴 Regex indentRegex = new Regex(@"^\s+"); // 최소 공통 공백 찾기 int maxIndentLength = 0; foreach (string line in lines) { if (!string.IsNullOrWhiteSpace(line)) { Match match = indentRegex.Match(line); if (match.Success) { int indentLength = match.Length; if (indentLength > maxIndentLength) maxIndentLength = indentLength; } } } // 최소 공통 공백 제거 string output = ""; foreach (string line in lines) { if (line.Trim() == "") continue; if (!string.IsNullOrWhiteSpace(line)) { string trimmedLine = line.Substring(maxIndentLength); output += trimmedLine + "\n"; } } return output; } private void GenerateProtocol() { // 입력 텍스트를 줄 단위로 분할 string[] lines = mInputText.Split('\n'); // 생성된 코드 문자열 초기화 string generatedProtocolCode = ""; string generatedClientHandlerCode = ""; string generatedServerHandlerCode = ""; bool isMultiLineComment = false; bool isClientHandlerComment = false; bool isServerHandlerComment = false; for (int i = 0; i < lines.Length; ++i) { string line = lines[i]; // 다중 줄 주석 처리 if (line.Trim().StartsWith("/*")) { isMultiLineComment = true; } if (isMultiLineComment) { generatedProtocolCode += line + "\n"; generatedClientHandlerCode += line + "\n"; generatedServerHandlerCode += line + "\n"; // 다중 줄 주석 종료 if (line.Trim().EndsWith("*/")) { isMultiLineComment = false; } continue; } if (line == "\n") { generatedProtocolCode += "\n"; generatedClientHandlerCode += "\n"; generatedServerHandlerCode += "\n"; continue; } // 주석인 경우 처리하여 유지 if (line.Trim().StartsWith("//")) { StringBuilder funcComment = new StringBuilder(); for (; i < lines.Length; ++i) { line = lines[i]; if (!line.Trim().StartsWith("//")) { funcComment.Remove(funcComment.Length - 2, 2); --i; break; } funcComment.Append($"{line}\n"); } // 클라이언트 핸들러 주석 확인 if (i + 1 < lines.Length && lines[i + 1].Trim().StartsWith("C_")) { isClientHandlerComment = true; isServerHandlerComment = false; } // 서버 핸들러 주석 확인 else if (i + 1 < lines.Length && lines[i + 1].Trim().StartsWith("S_")) { isClientHandlerComment = false; isServerHandlerComment = true; } if (isClientHandlerComment) { generatedClientHandlerCode += funcComment + "\n"; } if (isServerHandlerComment) { generatedServerHandlerCode += funcComment + "\n"; } generatedProtocolCode += funcComment + "\n"; continue; } // 빈 줄이거나 등호 (=)가 없는 줄은 건너뜀 if (string.IsNullOrEmpty(line) || !line.Contains("=")) continue; // 줄에서 변수 이름과 값 추출 string[] parts = line.Split('='); string variableName = parts[0].Trim(); string variableValue = parts[1].Trim(); // 접두사 추출 및 나머지 이름을 카멜 표기법으로 변환 string[] nameParts = variableName.Split('_'); string prefix = nameParts[0]; string camelCaseName = ""; for (int j = 1; j < nameParts.Length; ++j) { camelCaseName += char.ToUpper(nameParts[j][0]) + nameParts[j].Substring(1).ToLower(); } // 새 프로토콜 메시지 생성 string protocolMessage = $"message {prefix}_{camelCaseName} {{\n}}"; // 생성된 프로토콜 메시지를 코드에 추가 generatedProtocolCode += protocolMessage + "\n"; // 클라이언트 핸들러 코드 생성 if (prefix.StartsWith('C')) { string clientHandlerCode = $"public static void {prefix}_{camelCaseName}Handler(PacketSession session, IMessage packet)\n{{\n {prefix}_{camelCaseName} {prefix.ToLower()}_{camelCaseName.ToLower()} = packet as {prefix}_{camelCaseName};\n // TODO\n}}\n"; generatedClientHandlerCode += clientHandlerCode + "\n"; } // 서버 핸들러 코드 생성 if (prefix.StartsWith('S')) { string serverHandlerCode = $"public static void {prefix}_{camelCaseName}Handler(PacketSession session, IMessage packet)\n{{\n {prefix}_{camelCaseName} {prefix.ToLower()}_{camelCaseName.ToLower()} = packet as {prefix}_{camelCaseName};\n // TODO\n}}\n"; generatedServerHandlerCode += serverHandlerCode + "\n"; } } // 생성된 코드를 입력 필드에 할당 mProtocolText = generatedProtocolCode; mClientHandlerText = generatedClientHandlerCode; mServerHandlerText = generatedServerHandlerCode; } } #endif