[C#과 유니티로 만드는 MMORPG 게임 개발 시리즈] Part7: MMO 컨텐츠 구현 (Unity + C# 서버 연동 기초)
모든 계산은 서버에서 하고 실제로 클라이언트는 보여주는 역할만 한다고 배웠습니다. 여기서 궁금한점이 있는데 유니티는 collider를 만들어서 충돌처리를 하는데 서버는 따로 유니티를 통해 키는것이 아니라서 collider게산이 쉽지 않을 것 같다는 생각이 들었습니다. 총의 충돌판정을 검사할 때 총알의 현재위치와 총알의 이전위치를 이용해서 선을 만든 후 충돌처리를 하려고 하는데 여기서 플레이어의 머리 몸통 다리 팔을 각각 collider로 나누고싶다면 직접 서버에서 머리 몸통 팔 다리 위치와 collider를 구상하고 collider를 직접 구현하고.. Raycast를 직접 구현해서 사용한다 충돌 계산 및 유니티 기능 이용을 목적으로 하는 클라이언트를 따로 제작한 후 각 위치에 collider를 직접 생산하고 유니티에 있는 기능을 이용한다. 플레이어의 모든 위치는 동기화 되어있을테니 총알을 쏜 당사자의 컴퓨터에서 충돌판단을 한 후 서버로 충돌여부를 전달한다 보통 어떤 방식이 맞는건가요? 흔히 실무자들이 말하는 모든 계산을 서버에서 한다는 말이 당장 개개인의 클라이언트에선 collider조차 만들지 않는다는 느낌인건가요? 그리고 만약 점프를 한다면 점프에서 계산마다 올라가고 내려가는걸 서버에서 직접 계산한 후 (9.8중력, 이동속도 등..) 각 플레이어에 동기화시켜주는게 맞는걸까요? 아니면 각 클라이언트의 Rigidbody를 이용해서 계산된 높이값을 서버로 전달하는게 맞는걸까요? 로컬상 이동 - 서버로 전달 - 동기화 로컬상 이동명령 - 서버에서 이동계산 - 동기화 및 블랜딩 이 강의에선 2번케이스 같은데 3d게임은 1번이 더 나은 것 같기도 하고 해서 질문드립니다.
질문 시에는 위 내용은 삭제하고 다음 내용을 남겨주세요. ========================================= [질문 템플릿] 1. 강의 내용과 관련된 질문인가요? (예/아니오) 2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예/아니오) 3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예/아니오) [질문 내용] 강의에서는 21버전 Oracle OpenJDK를 사용하라고 하셨는데 제 화면에는 (21버전) OracleGraalVM 만 뜨는데 이걸로 사용해도 무방한가요? 상관없어보이지만 혹시나 해서 궁금한 마음에 여쭤봅니다!
학습하는 분들께 도움이 되고, 더 좋은 답변을 드릴 수 있도록 질문전에 다음을 꼭 확인해주세요. 1. 강의 내용과 관련된 질문을 남겨주세요. 2. 인프런의 질문 게시판과 자주 하는 질문(링크)을 먼저 확인해주세요. (자주 하는 질문 링크: https://bit.ly/3fX6ygx) 3. 질문 잘하기 메뉴얼(링크)을 먼저 읽어주세요. (질문 잘하기 메뉴얼 링크: https://bit.ly/2UfeqCG) 질문 시에는 위 내용은 삭제하고 다음 내용을 남겨주세요. ========================================= [질문 템플릿] 1. 강의 내용과 관련된 질문인가요? (예) 2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예) 3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예) [질문 내용] 안녕하세요. 강의 잘 듣고 있습니다. 해당 강의에서 부모 클래스인 Item의 생성자 및 print(), getPrice()메서드에 대한 접근제어자를 public으로 설정하셨습니다. 제 생각에는 ShopMain 클래스에서 부모 클래스에 접근할 때에는 모두 Item의 자식(book, album, movie)을 통해서만 접근하는 상황이고 이러한 접근 방식이 옳다고 판단되어서 부모 클래스의 생성자 및 메서드의 접근 제어자를 protected로 설정하였습니다(당연하게도 해당 예제에서 실행 결과는 public으로 했을 때와 동일합니다). 이 경우에 언젠가는 자식 클래스를 통해 접근하지 않을 경우가 발생할 수 있기 때문에 public으로 설정을 하신 걸까요? 아니면 protected로 설정하는 것이 조금 더 논리에 맞는 걸까요? package extends1.ex; public class Item { private String name; private int price; protected Item(String name, int price) { this.name = name; this.price = price; } protected void print() { //이름과 가격은 모든 자식에서 동일하게 수행하는 기능이므로 부모에 구현 System.out.println("이름:" + name + ", 가격:" + price); } protected int getPrice() { return price; } }
실습도중 Script 클릭시 해당 오류가 납니다. 컴퓨터 스펙은 m1 입니다.. 2024-03-25 14:53:51,833 ERROR FileEntryRepository.java:192 : Error while fetching files from SVN for admin 다른 버전으로 설치해도 동일한 이슈가 나서 혹시 해결하셨던 내용이 있을지 문의드립니다.
[질문 템플릿] 1. 강의 내용과 관련된 질문인가요? (예) 2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예) 3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예) [질문 내용] Java HotSpot(TM) 64-Bit Server VM warning: Sharing is only supported for boot loader classes because bootstrap classpath has been appended 이 오류는 무엇인가요?
안녕하세요 이부분에서 event.removeEnrollment(enrollment); 이 메서드를 타고 들어가면 이 메서드가 실행되는데 이때 106라인 ->enrollment.setEvent(null); 이 코드는 꼭 필요 한건가요 ?? 첫번째 사진 보시면 어차피 enrollmentRepository.delete(enrollment); 이걸 실행 하는데 왜 있는건지 이해가 잘 안갑니다 ! =================두번째 질문=========== 이 부분에서 취소를 하면 대기하던사람이 자동 확정 하는 로직인데 대기 하던 사람들 중 제일 먼저 신청을 해놓은 사람들을 정렬해서 true 처리 해야하는데 이건 안되있는거 아닌가요 !!?
제 문제 해결 접근이 맞는것인지 질문드립니다! 테스트할 때마다 회원, 상품을 새로 등록해야하는 것이 번거로워서, 기본편에서 배운 초기화 콜백을 이용해 우선 Item을 초기화해보려고 했습니다. // ItemService.java @PostConstruct @Transactional public void initData() { Book book1 = new Book(); book1.setName("book1"); book1.setPrice(1000); book1.setStockQuantity(10); book1.setAuthor("Steven"); book1.setIsbn("10000"); itemRepository.save(book1); } 위와 같이 ItemService에 초기화 메서드를 추가했는데 계속 해서 에러가 났습니다. 검색해보니 아무래도 초기화 콜백과 트랜젝션 처리를 initData()하나로 동시에 처리하려다보니 발생한 문제 같았습니다. 초기화 콜백을 확실히 완료하고나서 트랜젝션 처리를 해야 트랜젝션이 정상적으로 작동하는 것 아닌가 싶습니다. 단순히 코드상으로 이를 보장할 방법이 떠오르지 않았습니다. 이 때 떠오른게 DB2편의 @EventListener(ApplicationReadyEvent.class)인데, ApplicationReadyEvent가 스프링 컨테이너 초기화를 완전히 마치고 발생하는 이벤트라고 알고 있습니다. 이렇게 하니 초기화가 잘 됐습니다. 이처럼 선언적 트랜젝션을 적용하는 상황에서 초기화를 하기 위해서는 @EventListener(ApplicationReadyEvent.class)를 적용하는 것이 맞는 접근법일까요? @EventListener(ApplicationReadyEvent.class) @Transactional public void initData() { Book book1 = new Book(); book1.setName("book1"); book1.setPrice(1000); book1.setStockQuantity(10); book1.setAuthor("Steven"); book1.setIsbn("10000"); itemRepository.save(book1); } 정상 작동한 최종 코드입니다.
학습하는 분들께 도움이 되고, 더 좋은 답변을 드릴 수 있도록 질문전에 다음을 꼭 확인해주세요. 1. 강의 내용과 관련된 질문을 남겨주세요. 2. 인프런의 질문 게시판과 자주 하는 질문(링크)을 먼저 확인해주세요. (자주 하는 질문 링크: https://bit.ly/3fX6ygx) 3. 질문 잘하기 메뉴얼(링크)을 먼저 읽어주세요. (질문 잘하기 메뉴얼 링크: https://bit.ly/2UfeqCG) 질문 시에는 위 내용은 삭제하고 다음 내용을 남겨주세요. ========================================= [질문 템플릿] 1. 강의 내용과 관련된 질문인가요? (예) 2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예) 3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예) [질문 내용] 동적쿼리 - builder 사용편 강의를 들으며 return query .select(new QMemberTeamDto( member.id.as("memberId"), member.username, member.age, member.team.id.as("teamId"), team.name.as("teamName"))) .from(member) .leftJoin(member.team, team) .where(builder) .fetch(); 이 쿼리를 따라 치고 생각해보았습니다. 원래 jpa라면 member객체를 조회해와서 member.getTeam()이나 팀 객체에 액세스 할때 지연로딩이 일어난다고 학습하였습니다. 위 쿼리에서 fetch 조인을 사용하지 않았는데 어떻게 쿼리가 한방에 조회가 됐나 갑자기 의문이 들었습니다. 제가 도출해낸 결과는 반환값이 dto이고 team 객체와 join해서 필요한 값만(team 포함) select 하기때문에 teamId, teamName까지 한방쿼리로 조회가 되는건가요?
MVC2편에서 배웠던 것 같지만 헷갈리는 부분이 있어 질문드립니다. // ItemController /** * 상품 수정 */ @PostMapping("/items/{itemId}/edit") public String updateItem(@ModelAttribute("form") BookForm form) { // updateItemForm.html <form th:object="${form}" method="post"> th:object="${form}" 에서 괄호 안에 form을 참조하여 컨트롤러의 @ModelAttritube("form")을 했을 때 요청 파라미터를 바인딩해서 BookForm 객체에 넘겨준다고 이해했는데, @ModelAttritube("form1") 이런식으로 바꿔도 정상적으로 작동했습니다. 혹시 제가 놓친 부분이 있을까요?
public static void main(String[] args) { EntityManagerFactory emf = Persistence.createEntityManagerFactory("hello"); EntityManager em = emf.createEntityManager(); EntityTransaction tx = em.getTransaction(); tx.begin(); System.out.println("zzzzzzzzzzzzzzzzzzzzzzzzzzzz"); //비영속 try{ Team teamA = new Team(); teamA.setName("teamA"); em.persist(teamA); Team teamB = new Team(); teamB.setName("teamB"); em.persist(teamB); Member member1 = new Member(); member1.setUsername("member1"); member1.setTeam(teamA); em.persist(member1); Member member2 = new Member(); member2.setUsername("member2"); member2.setTeam(teamA); em.persist(member2); Member member3 = new Member(); member3.setUsername("member3"); member3.setTeam(teamB); em.persist(member3); Member member4 = new Member(); member4.setUsername("member4"); member4.setTeam(null); em.persist(member4); em.flush(); em.clear(); String query ="select t From Team t join fetch t.members"; List<Team> result = em.createQuery(query, Team.class).getResultList(); for (Team team : result) { System.out.println("team= " + team.getName() + "|members=" + team.getMembers().size()); } tx.commit(); } catch (Exception e){ tx.rollback(); e.printStackTrace(); }finally { em.close(); } emf.close(); } 이 코드를 실행시켰더니 14분 50초에 나오는 3줄이 나오는 것이 아닌 team= teamA|members=2 team= teamB|members=1 이렇게 나오는데 혹시 어떤 이유에서 그런것인지 궁금합니다.
모달창이 안떠서 settimeout으로 처리 하니 Modal에 result 값이 true로 적용됩니다 코드는 깃으로 올리겠습니다 선생님 강의에 올라와있는 ch06 파일 코드 넣어서 해봐도 모달창이 안뜨네요 ㅜㅜ https://github.com/hyeonbin03/webstromhub
우선 강의중에 보여주셨던 HTML코드들에 대해서 행방을 알수가 없고 키를 강의마다 알려주신다는데 언제 알려주시는지 모르겠습니다. 그래서 완성되어있던 파일에 있는 HTML파일들을 끌어다가 다시 완성시켰는데 코드자체에 CSS,Js가 적용되지 않고 에러가 뜨기도 합니다. Caused by: org.attoparser.ParseException: Exception evaluating SpringEL expression: "!hasNotification" (template: "fragments.html" - line 129, col 24) 혹시 최신화된 코드나 강의 진행도에 따른 코드 접근 방법이 있을까요...? 물론 제가 옛날 강의를 듣는것이다 보니 감수해야 하는 부분이겠지만 하나하나 알아가다보니 강의를 듣는 시간도 늘어지고 지치기 시작하는거 같습니다 시간이 지나면서 바뀌는 부분에 대해서 조금이라도 안내를 해주시거나, 주의할 부분이라던가 아니면 참고할만한 내용들을 추가해주시면 감사하겠습니다.
public delegate void ValueChangedHandler(Stat stat, float currentValue, float prevValue); public event ValueChangedHandler onValueChanged; public event Action<Stat, float, float> onValueChanged; 위와 같이 delegate를 사용하셨는데, 아래 action 대신 사용하면 어떤 차이가 있는지, 또는 특별한 이유가 있는지 궁금합니다.