// 테스트용 변수들. // bool is_test_mode = false; // byte test_auto_slot_index; void Awake() { // if (this.is_test_mode) // { // Time.timeScale = 100.0f; // } CEffectManager.Instance.load_effects(); this.waiting_packets = new Queue <CPacket>(); this.card_collision_manager = GameObject.Find("GameManager").GetComponent <CCardCollision>(); this.card_collision_manager.callback_on_touch = this.on_card_touch; this.player_me_index = 0; this.deck_cards = new Stack <CCardPicture>(); this.card_manager = new CCardManager(); this.card_manager.make_all_cards(); this.floor_ui_slots = new List <CVisualFloorSlot>(); for (byte i = 0; i < 12; ++i) { this.floor_ui_slots.Add(new CVisualFloorSlot(i, byte.MaxValue)); } this.player_hand_card_manager = new List <CPlayerHandCardManager>(); this.player_hand_card_manager.Add(new CPlayerHandCardManager()); this.player_hand_card_manager.Add(new CPlayerHandCardManager()); this.player_card_manager = new List <CPlayerCardManager>(); this.player_card_manager.Add(new CPlayerCardManager()); this.player_card_manager.Add(new CPlayerCardManager()); this.player_info_slots = new List <CPlayerInfoSlot>(); this.player_info_slots.Add(transform.FindChild("player_info_01").GetComponent <CPlayerInfoSlot>()); this.player_info_slots.Add(transform.FindChild("player_info_02").GetComponent <CPlayerInfoSlot>()); CPacketBufferManager.initialize(1); this.hwatoo_sprites = Resources.LoadAll <Sprite>("images/allcard"); this.back_image = Resources.Load <Sprite>("images/back"); this.floor_slot_position = new List <Vector3>(); make_slot_positions(this.floor_slot_root, this.floor_slot_position); // 카드 만들어 놓기. this.total_card_pictures = new List <CCardPicture>(); GameObject original = Resources.Load("hwatoo") as GameObject; Vector3 pos = this.deck_slot.position; for (int i = 0; i < this.card_manager.cards.Count; ++i) { GameObject obj = GameObject.Instantiate(original); obj.transform.parent = transform; obj.AddComponent <CMovingObject>(); CCardPicture card_pic = obj.AddComponent <CCardPicture>(); this.total_card_pictures.Add(card_pic); //obj.GetComponent<Image>().color = back_red; } }
List <CCardPicture> parse_cards_to_take_from_others(byte player_index, CPacket msg) { // 뺏어올 카드. List <CCardPicture> take_cards_from_others = new List <CCardPicture>(); byte victim_count = msg.pop_byte(); for (byte victim = 0; victim < victim_count; ++victim) { byte victim_index = msg.pop_byte(); byte count_to_take = msg.pop_byte(); for (byte i = 0; i < count_to_take; ++i) { byte card_number = msg.pop_byte(); PAE_TYPE pae_type = (PAE_TYPE)msg.pop_byte(); byte position = (byte)msg.pop_byte(); CCardPicture card_pic = this.player_card_manager[victim_index].get_card( card_number, pae_type, position); take_cards_from_others.Add(card_pic); this.player_card_manager[victim_index].remove(card_pic); } } short score = msg.pop_int16(); byte remain_bomb_card_count = msg.pop_byte(); // UI적용. this.player_info_slots[player_index].update_score(score); return(take_cards_from_others); }
void Update() { if (Input.GetMouseButtonDown(0)) { RaycastHit hit; Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition); if (Physics.Raycast(ray, out hit)) { GameObject obj = hit.transform.gameObject; if (!obj.CompareTag("card")) { return; } CCardPicture card_picture = obj.GetComponent <CCardPicture>(); if (card_picture == null) { return; } if (this.callback_on_touch != null) { this.callback_on_touch(card_picture); } card_picture.on_touch(); //Debug.Log(string.Format("number {0}, pae {1}, position {2}", // card_picture.card.number, // card_picture.card.pae_type, // card_picture.card.position)); } } }
public CCardPicture get_card(byte number, PAE_TYPE pae_type, byte position) { CCardPicture card_pic = this.floor_slots[pae_type].Find(obj => obj.is_same(number, pae_type, position)); return(card_pic); }
void Update() { if (Input.GetMouseButtonDown(0)) { RaycastHit hit; Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition); if (Physics.Raycast(ray, out hit)) { GameObject obj = hit.transform.gameObject; if (!obj.CompareTag("card")) { return; } CCardPicture card_picture = obj.GetComponent <CCardPicture>(); if (card_picture == null) { return; } if (this.callback_on_touch != null) { this.callback_on_touch(card_picture); } } } }
public void remove_card(CCardPicture card_pic) { this.card_pictures.Remove(card_pic); if (this.card_pictures.Count <= 0) { this.card_number = byte.MaxValue; } }
public void remove(CCardPicture card_picture) { bool result = this.cards.Remove(card_picture); if (!result) { UnityEngine.Debug.LogError("Cannot remove the card!"); } }
IEnumerator show_choice_card_popup(CCardPicture deck_card_picture) { if (deck_card_picture != null) { yield return(StartCoroutine(flip_deck_card(deck_card_picture))); } // 카드 선택 팝업 출력. CUIManager.Instance.show(UI_PAGE.POPUP_CHOICE_CARD); }
/// <summary> /// 플레이어의 바닥 카드 위치를 갱신한다. /// 피를 뺏기거나 옮기거나 했을 때 생기는 빈자리를 채워준다. /// </summary> /// <param name="player_index"></param> void refresh_player_floor_slots(PAE_TYPE pae_type, byte player_index) { int count = this.player_card_manager[player_index].get_card_count(pae_type); for (int i = 0; i < count; ++i) { Vector3 pos = this.player_card_positions[player_index].get_floor_position(i, pae_type); CCardPicture card_pic = this.player_card_manager[player_index].get_card_at(pae_type, i); // pos.z = card_pic.transform.position.z; card_pic.transform.position = pos; } }
IEnumerator flip_deck_card(CCardPicture deck_card_picture) { Animator ani = deck_card_picture.GetComponentInChildren <Animator>(); ani.enabled = true; ani.Play("rotation"); // 덱에서 pop할때 회전 yield return(StartCoroutine(scale_to( deck_card_picture, 3.0f, 0.1f))); }
/// <summary> /// 플레이어의 패의 위치를 갱신한다. /// 패를 내면 중간중간 빠진 자리가 생기는데 그 자리를 처음부터 다시 채워준다. /// </summary> /// <param name="player_index"></param> void refresh_player_hand_slots(byte player_index) { CPlayerHandCardManager hand_card_manager = this.player_hand_card_manager[player_index]; byte count = (byte)hand_card_manager.get_card_count(); for (byte card_index = 0; card_index < count; ++card_index) { CCardPicture card = hand_card_manager.get_card(card_index); // 슬롯 인덱스를 재설정 한다. card.set_slot_index(card_index); // 화면 위치를 재설정 한다. card.transform.position = this.player_card_positions[player_index].get_hand_position(card_index); } }
void sort_floor_cards_when_finished_turn() { for (int i = 0; i < this.floor_ui_slots.Count; ++i) { CVisualFloorSlot slot = this.floor_ui_slots[i]; if (slot.get_card_count() == 0) { continue; } CCardPicture card_pic = slot.get_first_card(); move_card(card_pic, card_pic.transform.position, this.floor_slot_position[slot.ui_slot_position]); } }
IEnumerator move_flip_card(byte number, PAE_TYPE pae_type, byte position) { // 뒤집은 카드 움직이기. CCardPicture deck_card_picture = this.deck_cards.Pop(); CCard flipped_card = this.card_manager.find_card(number, pae_type, position); deck_card_picture.update_card(flipped_card, get_hwatoo_sprite(flipped_card)); yield return(StartCoroutine(flip_deck_card(deck_card_picture))); yield return(new WaitForSeconds(0.3f)); deck_card_picture.transform.localScale = SCALE_TO_FLOOR; move_card_to_floor(deck_card_picture, CARD_EVENT_TYPE.NONE); yield return(new WaitForSeconds(0.5f)); }
public void refresh_hint_mark() { hide_hint_mark(); for (int i = 0; i < this.player_hand_card_manager[this.player_me_index].get_card_count(); ++i) { CCardPicture card_picture = this.player_hand_card_manager[this.player_me_index].get_card(i); CVisualFloorSlot slot = this.floor_ui_slots.Find(obj => obj.is_same_card(card_picture.card.number)); if (slot == null) { continue; } show_hint_mark(card_picture.transform.position); } }
void move_card(CCardPicture card_picture, Vector3 begin, Vector3 to, float duration = 0.1f) { if (card_picture.card != null) { card_picture.update_image(get_hwatoo_sprite(card_picture.card)); } else { card_picture.update_image(this.back_image); } CMovingObject mover = card_picture.GetComponent <CMovingObject>(); mover.begin = begin; mover.to = to; mover.duration = duration; mover.run(); }
void move_card_to_floor(CCardPicture card_picture, CARD_EVENT_TYPE event_type) { byte slot_index = 0; Vector3 begin = card_picture.transform.position; Vector3 to = Vector3.zero; CVisualFloorSlot slot = this.floor_ui_slots.Find(obj => obj.is_same_card(card_picture.card.number)); if (slot == null) { byte empty_slot = find_empty_floorslot(); //Debug.Log(string.Format("empty slot pos " + empty_slot)); to = this.floor_slot_position[empty_slot]; slot_index = empty_slot; } else { to = get_ui_slot_position(slot); List <CCardPicture> floor_card_pictures = slot.get_cards(); for (int i = 0; i < floor_card_pictures.Count; ++i) { Animator ani = floor_card_pictures[i].GetComponentInChildren <Animator>(); ani.enabled = true; ani.Play("card_hit_under"); } slot_index = slot.ui_slot_position; if (event_type != CARD_EVENT_TYPE.BOMB) { CEffectManager.Instance.play_dust(to, 0.1f, false); } Animator card_ani = card_picture.GetComponentInChildren <Animator>(); card_ani.enabled = true; card_ani.Play("card_hit"); } // 바닥 카드로 등록. this.floor_ui_slots[slot_index].add_card(card_picture); move_card(card_picture, begin, to, 0.01f); }
void move_card(CCardPicture card_picture, Vector3 begin, Vector3 to, float duration = 0.1f) { if (card_picture.card != null) { int sprite_index = card_picture.card.number * 4 + card_picture.card.position; card_picture.update_image(this.hwatoo_sprites[sprite_index]); //Debug.Log(sprite_index + ", " + this.hwatoo_sprites[sprite_index].name); } else { card_picture.update_image(this.back_image); } CMovingObject mover = card_picture.GetComponent <CMovingObject>(); mover.begin = begin; mover.to = to; mover.duration = duration; mover.run(); }
void on_card_touch(CCardPicture card_picture) { // 카드 연속 터치등을 막기 위한 처리. this.card_collision_manager.enabled = false; this.ef_focus.SetActive(false); int count = this.player_hand_card_manager.Count; for (int i = 0; i < count; ++i) { this.player_hand_card_manager[i].enable_all_colliders(false); } // 일반 카드, 폭탄 카드에 따라 다르게 처리한다. if (card_picture.is_back_card()) { CPacket msg = CPacket.create((short)PROTOCOL.FLIP_BOMB_CARD_REQ); CNetworkManager.Instance.send(msg); } else { // 손에 같은 카드 3장이 있고 바닥에 같은카드가 없을 때 흔들기 팝업을 출력한다. int same_on_hand = this.player_hand_card_manager[this.player_me_index].get_same_number_count(card_picture.card.number); int same_on_floor = get_same_number_count_on_floor(card_picture.card.number); if (same_on_hand == 3 && same_on_floor == 0) { CUIManager.Instance.show(UI_PAGE.POPUP_ASK_SHAKING); CPopupShaking popup = CUIManager.Instance.get_uipage(UI_PAGE.POPUP_ASK_SHAKING).GetComponent <CPopupShaking>(); popup.refresh(card_picture.card, card_picture.slot); } else { CPlayRoomUI.send_select_card(card_picture.card, card_picture.slot, 0); } } }
IEnumerator scale_to(CCardPicture card_picture, float ratio, float duration) { card_picture.sprite_renderer.sortingOrder = CSpriteLayerOrderManager.Instance.Order; Vector3 from = card_picture.transform.localScale; float begin = Time.time; Vector3 to = from * ratio; while (Time.time - begin <= duration) { float t = (Time.time - begin) / duration; Vector3 scale = from; scale.x = Mathf.Lerp(from.x, to.x, t); //덱에서 패를 뒤집을때 부드럽게 움직이도록 구현 scale.y = Mathf.Lerp(from.y, to.y, t); card_picture.transform.localScale = scale; yield return(0); } card_picture.transform.localScale = to; }
IEnumerator move_kookjin_to_pee(byte player_index) { CCardPicture card_picture = this.player_card_manager[player_index].get_card(8, PAE_TYPE.YEOL, 0); // 카드 자리 움직이기. move_card(card_picture, card_picture.transform.position, get_player_card_position(player_index, PAE_TYPE.PEE)); // 열끗에서 지우고 피로 넣는다. this.player_card_manager[player_index].remove(card_picture); card_picture.card.change_pae_type(PAE_TYPE.PEE); card_picture.card.set_card_status(CARD_STATUS.TWO_PEE); this.player_card_manager[player_index].add(card_picture); yield return(new WaitForSeconds(1.0f)); // 바닥 패 정렬. refresh_player_floor_slots(PAE_TYPE.YEOL, player_index); refresh_player_floor_slots(PAE_TYPE.PEE, player_index); }
public void add(CCardPicture card_picture) { this.cards.Add(card_picture); }
public void add(CCardPicture card_pic) { PAE_TYPE pae_type = card_pic.card.pae_type; this.floor_slots[pae_type].Add(card_pic); }
public void remove(CCardPicture card_pic) { PAE_TYPE pae_type = card_pic.card.pae_type; this.floor_slots[pae_type].Remove(card_pic); }
IEnumerator distribute_cards(Queue <CCard> floor_cards, Dictionary <byte, Queue <CCard> > player_cards) { yield return(new WaitForSeconds(1.0f)); List <CCardPicture> begin_cards_picture = new List <CCardPicture>(); // [바닥 -> 1P -> 2P 나눠주기] 를 두번 반복한다. for (int looping = 0; looping < 2; ++looping) { // 바닥에는 4장씩 분배한다. for (int i = 0; i < 4; ++i) { CCard card = floor_cards.Dequeue(); CCardPicture card_picture = this.deck_cards.Pop(); card_picture.update_card(card, get_hwatoo_sprite(card)); begin_cards_picture.Add(card_picture); card_picture.transform.localScale = SCALE_TO_FLOOR; move_card(card_picture, card_picture.transform.position, this.floor_slot_position[i + looping * 4]); yield return(new WaitForSeconds(0.02f)); } yield return(new WaitForSeconds(0.1f)); // 플레어이의 카드를 분배한다. foreach (KeyValuePair <byte, Queue <CCard> > kvp in player_cards) { byte player_index = kvp.Key; Queue <CCard> cards = kvp.Value; byte ui_slot_index = (byte)(looping * 5); // 플레이어에게는 한번에 5장씩 분배한다. for (int card_index = 0; card_index < 5; ++card_index) { CCardPicture card_picture = this.deck_cards.Pop(); card_picture.set_slot_index(ui_slot_index); this.player_hand_card_manager[player_index].add(card_picture); // 본인 카드는 해당 이미지를 보여주고, // 상대방 카드(is_nullcard)는 back_image로 처리한다. if (player_index == this.player_me_index) { CCard card = cards.Dequeue(); card_picture.update_card(card, get_hwatoo_sprite(card)); card_picture.transform.localScale = SCALE_TO_MY_HAND; move_card(card_picture, card_picture.transform.position, this.player_card_positions[player_index].get_hand_position(ui_slot_index)); } else { card_picture.update_backcard(this.back_image); card_picture.transform.localScale = SCALE_TO_OTHER_HAND; move_card(card_picture, card_picture.transform.position, this.player_card_positions[player_index].get_hand_position(ui_slot_index)); } ++ui_slot_index; yield return(new WaitForSeconds(0.02f)); } } } sort_floor_cards_after_distributed(begin_cards_picture); sort_player_hand_slots(this.player_me_index); CPacket msg = CPacket.create((short)PROTOCOL.DISTRIBUTED_ALL_CARDS); CNetworkManager.Instance.send(msg); }
/// <summary> /// 플레이어가 선택한 카드를 바닥에 내는 장면 구현. /// 폭탄 이벤트가 존재할 경우 같은 번호의 카드 세장을 한꺼번에 내도록 구현한다. /// </summary> /// <param name="player_index"></param> /// <param name="event_type"></param> /// <param name="slot_index"></param> /// <param name="player_card_number"></param> /// <param name="player_card_pae_type"></param> /// <param name="player_card_position"></param> /// <returns></returns> IEnumerator move_player_cards_to_floor( byte player_index, CARD_EVENT_TYPE event_type, List <CCard> bomb_cards_info, byte slot_index, byte player_card_number, PAE_TYPE player_card_pae_type, byte player_card_position) { float card_moving_delay = 0.2f; List <CCardPicture> targets = new List <CCardPicture>(); if (event_type == CARD_EVENT_TYPE.BOMB) { card_moving_delay = 0.1f; // 폭탄인 경우에는 폭탄 카드 수 만큼 낸다. if (this.player_me_index == player_index) { for (int i = 0; i < bomb_cards_info.Count; ++i) { CCardPicture card_picture = this.player_hand_card_manager[player_index].find_card( bomb_cards_info[i].number, bomb_cards_info[i].pae_type, bomb_cards_info[i].position); targets.Add(card_picture); } } else { for (int i = 0; i < bomb_cards_info.Count; ++i) { CCardPicture card_picture = this.player_hand_card_manager[player_index].get_card(i); CCard card = this.card_manager.find_card(bomb_cards_info[i].number, bomb_cards_info[i].pae_type, bomb_cards_info[i].position); card_picture.update_card(card, get_hwatoo_sprite(card)); targets.Add(card_picture); } } } else { // 폭탄이 아닌 경우에는 한장의 카드만 낸다. CCardPicture card_picture = this.player_hand_card_manager[player_index].get_card(slot_index); targets.Add(card_picture); if (this.player_me_index != player_index) { CCard card = this.card_manager.find_card(player_card_number, player_card_pae_type, player_card_position); card_picture.update_card(card, get_hwatoo_sprite(card)); } } if (event_type == CARD_EVENT_TYPE.BOMB) { CVisualFloorSlot slot = this.floor_ui_slots.Find(obj => obj.is_same_card(player_card_number)); Vector3 to = get_ui_slot_position(slot); CEffectManager.Instance.play_dust(to, 0.3f, true); } // 카드 움직이기. for (int i = 0; i < targets.Count; ++i) { // 손에 들고 있는 패에서 제거한다. CCardPicture player_card = targets[i]; this.player_hand_card_manager[player_index].remove(player_card); // 스케일 장면. yield return(StartCoroutine(scale_to( player_card, 3.5f, 0.05f))); yield return(new WaitForSeconds(card_moving_delay)); // 이동 장면. player_card.transform.localScale = SCALE_TO_FLOOR; move_card_to_floor(player_card, event_type); } }
public void add_card(CCardPicture card_pic) { this.card_number = card_pic.card.number; this.card_pictures.Add(card_pic); }
/// <summary> /// 패킷을 순차적으로 처리하기 위한 루프. /// 카드 움직이는 연출 장면을 순서대로 처리하기 위해 구현한 매소드 이다. /// 코루틴에 의한 카드 이동 연출이 진행중일때도 서버로부터의 패킷은 수신될 수 있으므로 /// 연출 도중에 다른 연출이 수행되는 경우가 생겨 버린다. /// 이런 경우를 방지하려면 두가지 방법이 있다. /// 첫번째. 각 연출 단계마다 다른 클라이언트들과 동기화를 수행한다. /// 두번째. 들어오는 패킷을 큐잉처리 하여 하나의 연출 장면이 끝난 뒤에 다음 패킷을 꺼내어 처리한다. /// 여기서는 두번째 방법으로 구현하였다. /// 첫번째 방법의 경우 동기화 패킷을 수시로 교환해야 하기 때문에 구현하기가 번거롭고 /// 상대방의 네트워크 상태가 좋지 않을 경우 게임 진행이 매끄럽지 못하게 된다. /// </summary> /// <returns></returns> IEnumerator sequential_packet_handler() { while (true) { if (this.waiting_packets.Count <= 0) { yield return(0); continue; } CPacket msg = this.waiting_packets.Dequeue(); PROTOCOL protocol = (PROTOCOL)msg.pop_protocol_id(); switch (protocol) { case PROTOCOL.LOCAL_SERVER_STARTED: { CPacket send = CPacket.create((short)PROTOCOL.READY_TO_START); CNetworkManager.Instance.send(send); } break; case PROTOCOL.PLAYER_ORDER_RESULT: { reset(); CUIManager.Instance.show(UI_PAGE.POPUP_PLAYER_ORDER); CPopupPlayerOrder popup = CUIManager.Instance.get_uipage(UI_PAGE.POPUP_PLAYER_ORDER).GetComponent <CPopupPlayerOrder>(); popup.reset(this.back_image); popup.play(); yield return(new WaitForSeconds(2.6f)); byte slot_count = msg.pop_byte(); byte best_number = 0; byte head = 0; for (byte i = 0; i < slot_count; ++i) { byte slot_index = msg.pop_byte(); byte number = msg.pop_byte(); PAE_TYPE pae_type = (PAE_TYPE)msg.pop_byte(); byte position = msg.pop_byte(); CCard card = this.card_manager.find_card(number, pae_type, position); Debug.Log(string.Format("{0}, {1}, {2}", number, pae_type, position)); popup.update_slot_info(slot_index, get_hwatoo_sprite(card)); if (best_number < number) { head = slot_index; best_number = number; } yield return(new WaitForSeconds(0.7f)); } yield return(new WaitForSeconds(0.5f)); GameObject ef = CUIManager.Instance.get_uipage(UI_PAGE.POPUP_FIRST_PLAYER); if (head == 0) { ef.transform.localPosition = new Vector3(100, 100, 0); } else { ef.transform.localPosition = new Vector3(100, -100, 0); } CUIManager.Instance.show(UI_PAGE.POPUP_FIRST_PLAYER); yield return(new WaitForSeconds(1.5f)); CUIManager.Instance.hide(UI_PAGE.POPUP_PLAYER_ORDER); CUIManager.Instance.hide(UI_PAGE.POPUP_FIRST_PLAYER); } break; case PROTOCOL.BEGIN_CARD_INFO: { if (is_test_mode) { this.test_auto_slot_index = 0; } Queue <CCard> floor_cards = new Queue <CCard>(); // floor cards. this.player_me_index = msg.pop_byte(); byte floor_count = msg.pop_byte(); for (byte i = 0; i < floor_count; ++i) { byte number = msg.pop_byte(); PAE_TYPE pae_type = (PAE_TYPE)msg.pop_byte(); byte position = msg.pop_byte(); CCard card = this.card_manager.find_card(number, pae_type, position); if (card == null) { Debug.LogError(string.Format("Cannot find the card. {0}, {1}, {2}", number, pae_type, position)); } floor_cards.Enqueue(card); } Dictionary <byte, Queue <CCard> > player_cards = new Dictionary <byte, Queue <CCard> >(); byte player_count = msg.pop_byte(); for (byte player = 0; player < player_count; ++player) { Queue <CCard> cards = new Queue <CCard>(); byte player_index = msg.pop_byte(); byte card_count = msg.pop_byte(); for (byte i = 0; i < card_count; ++i) { byte number = msg.pop_byte(); if (number != byte.MaxValue) { PAE_TYPE pae_type = (PAE_TYPE)msg.pop_byte(); byte position = msg.pop_byte(); CCard card = this.card_manager.find_card(number, pae_type, position); cards.Enqueue(card); } } player_cards.Add(player_index, cards); } yield return(StartCoroutine(distribute_cards(floor_cards, player_cards))); } break; case PROTOCOL.START_TURN: { byte remain_bomb_card_count = msg.pop_byte(); refresh_hint_mark(); if (this.is_test_mode) { if (this.player_hand_card_manager[0].get_card_count() <= 0) { break; } CPacket card_msg = CPacket.create((short)PROTOCOL.SELECT_CARD_REQ); CCardPicture card_pic = this.player_hand_card_manager[0].get_card(0); card_msg.push(card_pic.card.number); card_msg.push((byte)card_pic.card.pae_type); card_msg.push(card_pic.card.position); card_msg.push(this.test_auto_slot_index); ++this.test_auto_slot_index; CNetworkManager.Instance.send(card_msg); } else { // 내 차례가 되었을 때 카드 선택 기능을 활성화 시켜준다. this.ef_focus.SetActive(true); this.card_collision_manager.enabled = true; this.player_hand_card_manager[0].enable_all_colliders(true); // 이전에 폭탄낸게 남아있다면 가운데 카드를 뒤집을 수 있도록 충돌박스를 켜준다. if (remain_bomb_card_count > 0) { CCardPicture top_card = deck_cards.Peek(); top_card.enable_collider(true); show_hint_mark(top_card.transform.position); } } } break; case PROTOCOL.SELECT_CARD_ACK: yield return(StartCoroutine(on_select_card_ack(msg))); break; case PROTOCOL.FLIP_DECK_CARD_ACK: yield return(StartCoroutine(on_flip_deck_card_ack(msg))); break; case PROTOCOL.TURN_RESULT: { // 데이터 파싱 시작 ---------------------------------------- byte player_index = msg.pop_byte(); yield return(StartCoroutine(on_turn_result(player_index, msg))); } break; case PROTOCOL.ASK_GO_OR_STOP: CUIManager.Instance.show(UI_PAGE.POPUP_GO_STOP); break; case PROTOCOL.UPDATE_PLAYER_STATISTICS: update_player_statistics(msg); break; case PROTOCOL.ASK_KOOKJIN_TO_PEE: CUIManager.Instance.show(UI_PAGE.POPUP_ASK_KOOKJIN); break; case PROTOCOL.MOVE_KOOKJIN_TO_PEE: { byte player_index = msg.pop_byte(); yield return(StartCoroutine(move_kookjin_to_pee(player_index))); } break; case PROTOCOL.NOTIFY_GO_COUNT: { byte delay = msg.pop_byte(); byte go_count = msg.pop_byte(); yield return(StartCoroutine(delay_if_exist(delay))); yield return(StartCoroutine(show_go_count(go_count))); } break; case PROTOCOL.GAME_RESULT: yield return(StartCoroutine(on_game_result(msg))); break; } yield return(0); } }
IEnumerator move_after_flip_card(byte player_index, List <CCardPicture> take_cards_from_others, List <CCard> cards_to_give) { // 상대방에게 뺏어올 카드 움직이기. for (int i = 0; i < take_cards_from_others.Count; ++i) { Vector3 pos = get_player_card_position(player_index, PAE_TYPE.PEE); move_card(take_cards_from_others[i], take_cards_from_others[i].transform.position, pos); this.player_card_manager[player_index].add(take_cards_from_others[i]); yield return(new WaitForSeconds(0.5f)); } // 카드 가져오기. for (int i = 0; i < cards_to_give.Count; ++i) { CVisualFloorSlot slot = this.floor_ui_slots.Find(obj => obj.is_same_card(cards_to_give[i].number)); if (slot == null) { UnityEngine.Debug.LogError(string.Format("Cannot find floor slot. {0}, {1}, {2}", cards_to_give[i].number, cards_to_give[i].pae_type, cards_to_give[i].position)); } CCardPicture card_pic = slot.find_card(cards_to_give[i]); if (card_pic == null) { UnityEngine.Debug.LogError(string.Format("Cannot find the card. {0}, {1}, {2}", cards_to_give[i].number, cards_to_give[i].pae_type, cards_to_give[i].position)); } slot.remove_card(card_pic); Vector3 begin = card_pic.transform.position; Vector3 to = get_player_card_position(player_index, card_pic.card.pae_type); if (this.player_me_index == player_index) { card_pic.transform.localScale = SCALE_TO_MY_FLOOR; } else { card_pic.transform.localScale = SCALE_TO_OTHER_FLOOR; } move_card(card_pic, begin, to); this.player_card_manager[player_index].add(card_pic); yield return(new WaitForSeconds(0.1f)); } //yield return new WaitForSeconds(0.5f); sort_floor_cards_when_finished_turn(); refresh_player_hand_slots(player_index); yield return(new WaitForSeconds(0.2f)); CPacket finish = CPacket.create((short)PROTOCOL.TURN_END); CNetworkManager.Instance.send(finish); }
/// <summary> /// 패킷을 순차적으로 처리하기 위한 루프. /// 카드 움직이는 연출 장면을 순서대로 처리하기 위해 구현한 매소드 이다. /// 코루틴에 의한 카드 이동 연출이 진행중일때도 서버로부터의 패킷은 수신될 수 있으므로 /// 연출 도중에 다른 연출이 수행되는 경우가 생겨 버린다. /// 이런 경우를 방지하려면 두가지 방법이 있다. /// 첫번째. 각 연출 단계마다 다른 클라이언트들과 동기화를 수행한다. /// 두번째. 들어오는 패킷을 큐잉처리 하여 하나의 연출 장면이 끝난 뒤에 다음 패킷을 꺼내어 처리한다. /// 여기서는 두번째 방법으로 구현하였다. /// 첫번째 방법의 경우 동기화 패킷을 수시로 교환해야 하기 때문에 구현하기가 번거롭고 /// 상대방의 네트워크 상태가 좋지 않을 경우 게임 진행이 매끄럽지 못하게 된다. /// </summary> /// <returns></returns> IEnumerator sequential_packet_handler() { while (true) { if (this.waiting_packets.Count <= 0) { yield return(0); continue; } CPacket msg = this.waiting_packets.Dequeue(); PROTOCOL protocol = (PROTOCOL)msg.pop_protocol_id(); switch (protocol) { case PROTOCOL.LOCAL_SERVER_STARTED: { CPacket send = CPacket.create((short)PROTOCOL.READY_TO_START); CNetworkManager.Instance.send(send); } break; case PROTOCOL.BEGIN_CARD_INFO: { reset(); // if (is_test_mode) // { // this.test_auto_slot_index = 0; // } Queue <CCard> floor_cards = new Queue <CCard>(); // floor cards. this.player_me_index = msg.pop_byte(); byte floor_count = msg.pop_byte(); for (byte i = 0; i < floor_count; ++i) { byte number = msg.pop_byte(); PAE_TYPE pae_type = (PAE_TYPE)msg.pop_byte(); byte position = msg.pop_byte(); CCard card = this.card_manager.find_card(number, pae_type, position); if (card == null) { Debug.LogError(string.Format("Cannot find the card. {0}, {1}, {2}", number, pae_type, position)); } floor_cards.Enqueue(card); } Dictionary <byte, Queue <CCard> > player_cards = new Dictionary <byte, Queue <CCard> >(); byte player_count = msg.pop_byte(); for (byte player = 0; player < player_count; ++player) { Queue <CCard> cards = new Queue <CCard>(); byte player_index = msg.pop_byte(); byte card_count = msg.pop_byte(); for (byte i = 0; i < card_count; ++i) { byte number = msg.pop_byte(); if (number != byte.MaxValue) { PAE_TYPE pae_type = (PAE_TYPE)msg.pop_byte(); byte position = msg.pop_byte(); CCard card = this.card_manager.find_card(number, pae_type, position); cards.Enqueue(card); } } player_cards.Add(player_index, cards); } yield return(StartCoroutine(distribute_cards(floor_cards, player_cards))); } break; case PROTOCOL.START_TURN: { byte remain_bomb_card_count = msg.pop_byte(); // if (this.is_test_mode) // { // if (this.player_hand_card_manager[0].get_card_count() <= 0) // { // break; // } // // CPacket card_msg = CPacket.create((short)PROTOCOL.SELECT_CARD_REQ); // CCardPicture card_pic = this.player_hand_card_manager[0].get_card(0); // // card_msg.push(card_pic.card.number); // card_msg.push((byte)card_pic.card.pae_type); // card_msg.push(card_pic.card.position); // // card_msg.push(this.test_auto_slot_index); // // ++this.test_auto_slot_index; // // CNetworkManager.Instance.send(card_msg); // } // 내 차례가 되었을 때 카드 선택 기능을 활성화 시켜준다. this.card_collision_manager.enabled = true; this.player_hand_card_manager[0].enable_all_colliders(true); // 이전에 폭탄낸게 남아있다면 가운데 카드를 뒤집을 수 있도록 충돌박스를 켜준다. if (remain_bomb_card_count > 0) { CCardPicture top_card = deck_cards.Peek(); top_card.enable_collider(true); } } break; case PROTOCOL.SELECT_CARD_ACK: yield return(StartCoroutine(on_select_card_ack(msg))); break; case PROTOCOL.FLIP_DECK_CARD_ACK: yield return(StartCoroutine(on_flip_deck_card_ack(msg))); break; case PROTOCOL.CHOICE_ONE_CARD: { List <Sprite> target_cards = new List <Sprite>(); PLAYER_SELECT_CARD_RESULT result = (PLAYER_SELECT_CARD_RESULT)msg.pop_byte(); CCardPicture deck_card = null; if (result == PLAYER_SELECT_CARD_RESULT.CHOICE_ONE_CARD_FROM_DECK) { deck_card = this.deck_cards.Pop(); byte number = msg.pop_byte(); PAE_TYPE pae_type = (PAE_TYPE)msg.pop_byte(); byte position = msg.pop_byte(); CCard card = this.card_manager.find_card(number, pae_type, position); deck_card.update_card(card, get_hwatoo_sprite(card)); } byte count = msg.pop_byte(); for (byte i = 0; i < count; ++i) { byte number = msg.pop_byte(); PAE_TYPE pae_type = (PAE_TYPE)msg.pop_byte(); byte position = msg.pop_byte(); CCard card = this.card_manager.find_card(number, pae_type, position); target_cards.Add(get_hwatoo_sprite(card)); //Debug.Log(string.Format("choice one card. {0}, {1}, {2}", number, pae_type, position)); } CUIManager.Instance.show(UI_PAGE.POPUP_CHOICE_CARD); CPopupChoiceCard popup = CUIManager.Instance.get_uipage(UI_PAGE.POPUP_CHOICE_CARD).GetComponent <CPopupChoiceCard>(); popup.refresh(result, target_cards[0], target_cards[1]); yield return(StartCoroutine(show_choice_card_popup(deck_card))); } break; case PROTOCOL.TURN_RESULT: { // 데이터 파싱 시작 ---------------------------------------- byte player_index = msg.pop_byte(); yield return(StartCoroutine(on_turn_result(player_index, msg))); } break; case PROTOCOL.ASK_GO_OR_STOP: CUIManager.Instance.show(UI_PAGE.POPUP_GO_STOP); break; case PROTOCOL.UPDATE_PLAYER_STATISTICS: update_player_statistics(msg); break; case PROTOCOL.ASK_KOOKJIN_TO_PEE: CUIManager.Instance.show(UI_PAGE.POPUP_ASK_KOOKJIN); break; case PROTOCOL.MOVE_KOOKJIN_TO_PEE: { byte player_index = msg.pop_byte(); yield return(StartCoroutine(move_kookjin_to_pee(player_index))); } break; case PROTOCOL.GAME_RESULT: on_game_result(msg); break; } yield return(0); } }