일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | ||||
4 | 5 | 6 | 7 | 8 | 9 | 10 |
11 | 12 | 13 | 14 | 15 | 16 | 17 |
18 | 19 | 20 | 21 | 22 | 23 | 24 |
25 | 26 | 27 | 28 | 29 | 30 | 31 |
- unity 설치
- 오픽 im1 5일
- unity 공부
- 게임 개발
- 크래프톤 정글랩
- 유니티 퀘스트
- unity
- unity 게임 개발
- 유니티 독학
- unity 게임
- protobuf란
- 유니티
- 유니티 스토리
- unity 강의
- 크래프톤
- unity 개발
- 유니티 체스
- 크래프톤 게임 정글 랩
- 유니티 대화
- node.js
- protobuf 란?
- 오픽 im1
- 게임 독학
- 게임 개발 독학
- Unity Chess
- 유니티 미연시
- 크래프톤 정글 게임랩
- ETRI 연구연수
- 크래프톤 정글 게임 랩
- Unity 독학
- Today
- Total
하참이의 아이디어노트
유니티로 2D 체스 만들기 (5) 본문
public void PawnMovePlate(int x, int y)
{
Game sc = controller.GetComponent<Game>();
if(sc.PositionOnBoard(x, y))
{
if(sc.GetPosition(x, y) == null)
{
MovePlateSpawn(x, y);
}
if(sc.PositionOnBoard(x + 1, y) && sc.GetPosition(x+1, y) != null && sc.GetPosition(x + 1, y).GetComponent<Chessman>().player != player)
{
MovePlateAttackSpawn(x + 1, y);
}
if (sc.PositionOnBoard(x - 1, y) && sc.GetPosition(x + 1, y) != null && sc.GetPosition(x - 1, y).GetComponent<Chessman>().player != player)
{
MovePlateAttackSpawn(x + 1, y);
}
}
}
https://www.youtube.com/watch?v=CkCQWGfQY2U&list=PLXV-vjyZiT4b7WGjgiqMy422AVyMaigl1&index=6
글 작성에 앞서 이 주제로 작성하는 모든 글의 내용은 위 영상을 참고해서 제작하여 만든 것들임을 미리 밝힙니다.
안녕하십니까! 지난 글에서는 moveplate 프리팹을 제작하여보았는데요, 아직 moveplate에는 제작할 요소가 많습니다. 다른 말을 클릭하면 원래 클릭했던 체스말의 이동경로를 제거하기도 해야하고, 각각 다른 체스말들은 클릭하면 각각 다른 이동경로를 보여주어야 합니다. 오늘은 이러한 moveplate의 기능들을 좀 더 다듬어봅시다.
주의! 이번 글에는 어느정도의 프로그래밍 이해도가 필요합니다! 초보자분들께서는 처음 보는 메소드에도 당황하지 않고 이름과 설명을 읽고 이러이러 하게 구현되겠구나를 생각하며 천천히 여러번 읽으시는 것을 권장드립니다.
저희가 이번시간에 구현할 기능들은 다음과 같습니다.
1. 체스말을 클릭하면 해당 체스말의 가능한 이동경로를 보여주는 InitiateMovePlates() 메소드
2. 또한 체스말을 클릭하거나 이동에 성공하면 이동경로를 지우기 위한 DestroyMovePlates() 메소드
위 기능들을 위하여 Chessman.cs의 코드에 다음 메소드들을 추가합니다.
private void OnMouseUp()
{
DestroyMovePlates();
InitiateMovePlates();
}
public void DestroyMovePlates()
{
GameObject[] movePlates = GameObject.FindGameObjectsWithTag("MovePlate");
for(int i = 0; i < movePlates.Length; i++)
{
Destroy(movePlates[i]);
}
}
public void InitiateMovePlates()
{
switch(this.name)
{
case "black_queen":
case "white_queen":
LineMovePlate(1, 0);
LineMovePlate(0, 1);
LineMovePlate(1, 1);
LineMovePlate(-1, 0);
LineMovePlate(0, -1);
LineMovePlate(-1, -1);
LineMovePlate(1, -1);
LineMovePlate(1, -1);
break;
case "black_knight":
case "white_knight":
LMovePlate();
break;
case "black_bishop":
case "white_bishop":
LineMovePlate(1, 1);
LineMovePlate(1, -1);
LineMovePlate(-1, 1);
LineMovePlate(-1, -1);
break;
case "black_king":
case "white_king":
SurroundMovePlate();
break;
case "black_rook":
case "white_rook":
LineMovePlate(1, 0);
LineMovePlate(0, 1);
LineMovePlate(-1, 0);
LineMovePlate(0, -1);
break;
case "black_pawn":
PawnMovePlate(xBoard, yBoard - 1);
break;
case "white_pawn":
PawnMovePlate(xBoard, yBoard + 1);
break;
}
}
메소드들에 대한 설명은 다음과 같습니다.
OnMouseUp은 해당 오브젝트가 클릭되면 호출되는 메소드입니다. 체스말이 클릭되면 다른 말의 이동경로를 표현하던 moveplate를 전부 제거하고 해당 말의 이동경로를 보여줍니다.
DestroyMovePlates()는 모든 MovePlate라는 태그를 가진 (이후에 moveplate 프리팹에 MovePlate 태그를 추가 할 것입니다.) 게임 오브젝트를 찾은 뒤, for문으로 전부 제거합니다.
InitiateMovePlates()는 해당 체스말의 이름에 따라 이동경로를 보이는 메소드입니다. 이후에 구현할 것이지만 각 경로를 보여주는 메소드들에 대한 설명을 간단히 하겠습니다.
LineMovePlate는 상하좌우와 각 사이값, 즉 8방의 방향을 x, y 값으로 입력하면 방향을 향해 직선으로 MovePlate를 생성합니다.
LMovePlate는 Knight(나이트) 체스말 전용으로 L 자모양의 경로에 MovePlate를 생성합니다.
SurroundMovePlate는 8방의 방향 1칸으로 MovePlate를 생성합니다.
PawnMovePlate는 Pawn(폰) 체스말 전용으로 1칸 앞(또는 뒤)방향으로 MovePlate 를 생성합니다. 단, 앞에 말이 있을경우 움직이지 못하고 대각선 직진방향에 상대 말이 있을 경우 공격으로 이동 할 수 있습니다.
이제 각각의 MovePlate를 생성하는 메소드들을 구현해보도록 하겠습니다. 하나의 메소드를 이해하면 다른 메소드들도 이해하기 편할 것 입니다.
처음은 LineMovePlate(int xIncrement, int yIncrement)입니다. 다음 메서드를 Chessman.cs 코드에 추가합니다.
public void LineMovePlate(int xIncrement, int yIncrement)
{
Game sc = controller.GetComponent<Game>();
int x = xBoard + xIncrement;
int y = yBoard + yIncrement;
while (sc.PositionOnBoard(x, y) && sc.GetPosition(x, y) == null)
{
MovePlateSpawn(x, y);
x += xIncrement;
y += yIncrement;
}
if (sc.PositionOnBoard(x, y) && sc.GetPosition(x, y).GetComponent<Chessman>().player != player)
{
MovePlateAttackSpawn(x, y);
}
}
하나하나 분석해보겠습니다.
sc는 게임 컨트롤러 객체를 가쳐오기 위한 변수입니다. 보통의 게임 컨트롤러는 싱글턴 패턴으로 작성하지만 이번 프로젝트는 간단한 게임을 구현하기 위함으로 위 코드와 같이 객체를 가져옵니다.
매개변수로 가져온 xIncrement(X축 진행 방향)과 yIncrement(Y축 진행 방향)을 본인 말의 위치에 더하여 변수 x, y에 저장합니다.
그렇게 위치가 체스보드 위에 있고 해당 위치에 체스말이 없다면 MovePlate를 생성합니다. MovePlateSpawn은 아직 구현되지 않은 메소드입니다.
만약 해당 위치에 적의 말이 있다면 AttackMovePlate를 생성합니다. (지난 글에 붉은색으로 만들었던)
다음은 LMovePlate() 메소드입니다.
public void LMovePlate()
{
PointMovePlate(xBoard + 1, yBoard + 2);
PointMovePlate(xBoard - 1, yBoard + 2);
PointMovePlate(xBoard + 2, yBoard + 1);
PointMovePlate(xBoard - 2, yBoard + 1);
PointMovePlate(xBoard + 1, yBoard - 2);
PointMovePlate(xBoard - 1, yBoard - 2);
PointMovePlate(xBoard + 2, yBoard - 1);
PointMovePlate(xBoard - 2, yBoard - 1);
}
PointMovePlate는 해당 좌표에 MovePlate를 생성하는 메소드로 아직 구현되지 않았습니다. PointMovePlate메소드를 이용하여 자신의 L 위치 (Knight 체스말의 이동경로)에 MovePlate를 생성합니다.
다음은 SurroundMovePlate() 메소드입니다.
public void SurroundMovePlate()
{
PointMovePlate(xBoard, yBoard + 1);
PointMovePlate(xBoard, yBoard - 1);
PointMovePlate(xBoard - 1, yBoard);
PointMovePlate(xBoard + 1, yBoard);
PointMovePlate(xBoard + 1, yBoard + 1);
PointMovePlate(xBoard + 1, yBoard - 1);
PointMovePlate(xBoard - 1, yBoard + 1);
PointMovePlate(xBoard - 1, yBoard - 1);
}
PointMovePlate메소드를 이용하여 자신주변 (King 체스말의 이동경로)에 MovePlate를 생성합니다.
다음은 PointMovePlate() 메소드입니다.
public void PointMovePlate(int x, int y)
{
Game sc = controller.GetComponent<Game>();
if (sc.PositionOnBoard(x, y))
{
GameObject cp = sc.GetPosition(x, y);
if (cp == null)
{
MovePlateSpawn(x, y);
}
else if (cp.GetComponent<Chessman>().player != player)
{
MovePlateAttackSpawn(x, y);
}
}
}
MovePlate를 생성할 위치좌표 x 와 y를 매개변수로 받습니다.
sc에 게임 컨트롤러 컴포넌트 객체를 참조합니다.
만약 x와 y가 체스보드 위에 있을 경우
해당 위치가 비어있다면 MovePlate를 해당 위치에 생성합니다.
해당 위치에 상대의 체스말이 있다면 AttackMovePlate를 생성합니다.
다음은 PawnMovePlate(int x, int y) 메소드입니다.
public void PawnMovePlate(int x, int y)
{
Game sc = controller.GetComponent<Game>();
if(sc.PositionOnBoard(x, y))
{
if(sc.GetPosition(x, y) == null)
{
MovePlateSpawn(x, y);
}
if(sc.PositionOnBoard(x + 1, y) && sc.GetPosition(x + 1, y) != null && sc.GetPosition(x + 1, y).GetComponent<Chessman>().player != player)
{
MovePlateAttackSpawn(x + 1, y);
}
if (sc.PositionOnBoard(x - 1, y) && sc.GetPosition(x - 1, y) != null && sc.GetPosition(x - 1, y).GetComponent<Chessman>().player != player)
{
MovePlateAttackSpawn(x + 1, y);
}
}
}
MovePlate를 생성할 위치좌표 x 와 y를 매개변수로 받습니다.
sc에 게임 컨트롤러 컴포넌트 객체를 참조합니다.
만약 x와 y가 체스보드 위에 있 을 경우
해당위치가 비어있다면 MovePlate를 해당 위치게 생성합니다.
대각선경로가 비어있고 해당위치에 적의 말이 있다면 AttackMovePlate를 생성합니다.
다음은 MovePlateSpawn, MovePlateAttackSpawn 메소드 입니다.
public void MovePlateSpawn(int matrixX, int matrixY)
{
float x = matrixX;
float y = matrixY;
x *= 0.66f;
y *= 0.66f;
x += -2.3f;
y += -2.3f;
GameObject mp = Instantiate(movePlate, new Vector3(x, y, -3.0f), Quaternion.identity);
MovePlate mpScript = mp.GetComponent<MovePlate>();
mpScript.SetReference(gameObject);
mpScript.SetCoords(matrixX, matrixY);
}
public void MovePlateAttackSpawn(int matrixX, int matrixY)
{
float x = matrixX;
float y = matrixY;
x *= 0.66f;
y *= 0.66f;
x += -2.3f;
y += -2.3f;
GameObject mp = Instantiate(movePlate, new Vector3(x, y, -3.0f), Quaternion.identity);
MovePlate mpScript = mp.GetComponent<MovePlate>();
mpScript.attack = true;
mpScript.SetReference(gameObject);
mpScript.SetCoords(matrixX, matrixY);
}
체스보드상의 좌표를 받으면 유니티 에디터 게임 화면 상의 좌표를 계산하여 movePlate객체를 생성합니다.
다음 생성된 객체의 MovePlate 컴포넌트 속성에 해당 체스말의 참조 변수와 좌표를 전달합니다.
AttackMovePlate를 생성하는 MovePlateAttackSpawn의 경우 attack만 true로 바꾸어 생성합니다.
전부 입력한 ChessMan의 코드는 다음과 같습니다.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Chessman : MonoBehaviour
{
// References
public GameObject controller;
public GameObject movePlate;
// Positions
private int xBoard = -1;
private int yBoard = -1;
// Variable to keep track of "black" player of "white" player
private string player;
// References for all the sptrites that the chesspiece can be
public Sprite black_queen, black_knight, black_bishop, black_king, black_rook, black_pawn;
public Sprite white_queen, white_knight, white_bishop, white_king, white_rook, white_pawn;
public void Activate()
{
controller = GameObject.FindGameObjectWithTag("GameController");
// take the instantiated location and adjust the transform
SetCoords();
switch(this.name)
{
case "black_queen": this.GetComponent<SpriteRenderer>().sprite = black_queen; player = "black"; break;
case "black_knight": this.GetComponent<SpriteRenderer>().sprite = black_knight; player = "black"; break;
case "black_bishop": this.GetComponent<SpriteRenderer>().sprite = black_bishop; player = "black"; break;
case "black_king": this.GetComponent<SpriteRenderer>().sprite = black_king; player = "black"; break;
case "black_rook": this.GetComponent<SpriteRenderer>().sprite = black_rook; player = "black"; break;
case "black_pawn": this.GetComponent<SpriteRenderer>().sprite = black_pawn; player = "black"; break;
case "white_queen": this.GetComponent<SpriteRenderer>().sprite = white_queen; player = "white"; break;
case "white_knight": this.GetComponent<SpriteRenderer>().sprite = white_knight; player = "white"; break;
case "white_bishop": this.GetComponent<SpriteRenderer>().sprite = white_bishop; player = "white"; break;
case "white_king": this.GetComponent<SpriteRenderer>().sprite = white_king; player = "white"; break;
case "white_rook": this.GetComponent<SpriteRenderer>().sprite = white_rook; player = "white"; break;
case "white_pawn": this.GetComponent<SpriteRenderer>().sprite = white_pawn; player = "white"; break;
}
}
public void SetCoords()
{
float x = xBoard;
float y = yBoard;
x *= 0.66f;
y *= 0.66f;
x += -2.3f;
y += -2.3f;
this.transform.position = new Vector3(x, y, -1.0f);
}
public int GetXBoard()
{
return xBoard;
}
public int GetYBoard()
{
return yBoard;
}
public void SetXBoard(int x)
{
this.xBoard = x;
}
public void SetYBoard(int y)
{
this.yBoard = y;
}
private void OnMouseUp()
{
DestroyMovePlates();
InitiateMovePlates();
}
public void DestroyMovePlates()
{
GameObject[] movePlates = GameObject.FindGameObjectsWithTag("MovePlate");
for(int i = 0; i < movePlates.Length; i++)
{
Destroy(movePlates[i]);
}
}
public void InitiateMovePlates()
{
switch(this.name)
{
case "black_queen":
case "white_queen":
LineMovePlate(1, 0);
LineMovePlate(0, 1);
LineMovePlate(1, 1);
LineMovePlate(-1, 0);
LineMovePlate(0, -1);
LineMovePlate(-1, -1);
LineMovePlate(1, -1);
LineMovePlate(1, -1);
break;
case "black_knight":
case "white_knight":
LMovePlate();
break;
case "black_bishop":
case "white_bishop":
LineMovePlate(1, 1);
LineMovePlate(1, -1);
LineMovePlate(-1, 1);
LineMovePlate(-1, -1);
break;
case "black_king":
case "white_king":
SurroundMovePlate();
break;
case "black_rook":
case "white_rook":
LineMovePlate(1, 0);
LineMovePlate(0, 1);
LineMovePlate(-1, 0);
LineMovePlate(0, -1);
break;
case "black_pawn":
PawnMovePlate(xBoard, yBoard - 1);
break;
case "white_pawn":
PawnMovePlate(xBoard, yBoard + 1);
break;
}
}
public void LineMovePlate(int xIncrement, int yIncrement)
{
Game sc = controller.GetComponent<Game>();
int x = xBoard + xIncrement;
int y = yBoard + yIncrement;
while (sc.PositionOnBoard(x, y) && sc.GetPosition(x, y) == null)
{
MovePlateSpawn(x, y);
x += xIncrement;
y += yIncrement;
}
if (sc.PositionOnBoard(x, y) && sc.GetPosition(x, y).GetComponent<Chessman>().player != player)
{
MovePlateAttackSpawn(x, y);
}
}
public void LMovePlate()
{
PointMovePlate(xBoard + 1, yBoard + 2);
PointMovePlate(xBoard - 1, yBoard + 2);
PointMovePlate(xBoard + 2, yBoard + 1);
PointMovePlate(xBoard - 2, yBoard + 1);
PointMovePlate(xBoard + 1, yBoard - 2);
PointMovePlate(xBoard - 1, yBoard - 2);
PointMovePlate(xBoard + 2, yBoard - 1);
PointMovePlate(xBoard - 2, yBoard - 1);
}
public void SurroundMovePlate()
{
PointMovePlate(xBoard, yBoard + 1);
PointMovePlate(xBoard, yBoard - 1);
PointMovePlate(xBoard - 1, yBoard);
PointMovePlate(xBoard + 1, yBoard);
PointMovePlate(xBoard + 1, yBoard + 1);
PointMovePlate(xBoard + 1, yBoard - 1);
PointMovePlate(xBoard - 1, yBoard + 1);
PointMovePlate(xBoard - 1, yBoard - 1);
}
public void PointMovePlate(int x, int y)
{
Game sc = controller.GetComponent<Game>();
if (sc.PositionOnBoard(x, y))
{
GameObject cp = sc.GetPosition(x, y);
if (cp == null)
{
MovePlateSpawn(x, y);
}
else if (cp.GetComponent<Chessman>().player != player)
{
MovePlateAttackSpawn(x, y);
}
}
}
public void PawnMovePlate(int x, int y)
{
Game sc = controller.GetComponent<Game>();
if(sc.PositionOnBoard(x, y))
{
if(sc.GetPosition(x, y) == null)
{
MovePlateSpawn(x, y);
}
if(sc.PositionOnBoard(x + 1, y) && sc.GetPosition(x + 1, y) != null && sc.GetPosition(x + 1, y).GetComponent<Chessman>().player != player)
{
MovePlateAttackSpawn(x + 1, y);
}
if (sc.PositionOnBoard(x - 1, y) && sc.GetPosition(x - 1, y) != null && sc.GetPosition(x - 1, y).GetComponent<Chessman>().player != player)
{
MovePlateAttackSpawn(x + 1, y);
}
}
}
public void MovePlateSpawn(int matrixX, int matrixY)
{
float x = matrixX;
float y = matrixY;
x *= 0.66f;
y *= 0.66f;
x += -2.3f;
y += -2.3f;
GameObject mp = Instantiate(movePlate, new Vector3(x, y, -3.0f), Quaternion.identity);
MovePlate mpScript = mp.GetComponent<MovePlate>();
mpScript.SetReference(gameObject);
mpScript.SetCoords(matrixX, matrixY);
}
public void MovePlateAttackSpawn(int matrixX, int matrixY)
{
float x = matrixX;
float y = matrixY;
x *= 0.66f;
y *= 0.66f;
x += -2.3f;
y += -2.3f;
GameObject mp = Instantiate(movePlate, new Vector3(x, y, -3.0f), Quaternion.identity);
MovePlate mpScript = mp.GetComponent<MovePlate>();
mpScript.attack = true;
mpScript.SetReference(gameObject);
mpScript.SetCoords(matrixX, matrixY);
}
}
이제 MovePlate 프리팹의 태그를 추가해야합니다. MovePlate 프리팹의 Tag에서 Add Tag... 를 클릭합니다. Tags의 우측 하단 + 버튼을 누른 뒤 MovePlate로 이름을 입력, 태그가 생성되면 MovePlate로 태그를 설정합니다.
다음으로 ChessMan과 MovePlate는 클릭을 하면 호출되는 OnMouseUp 메소드를 사용하기 때문에 Collider 속성이 필요합니다. MovePlate 프리팹에 Add Component를 클릭, Box Collider2D를 추가합니다.
또한 Chesspiece 프리팹의 Chessman 스크립트에는 MovePlate를 비워뒀었습니다. MovePlate 프리팹을 드래그 하여 추가해줍니다.
게임을 실행해 잘 작동되는지 확인해봅니다.
네! 이제 거의 다 왔습니다. 아직 턴플레이나 폰의 2칸 전진, 게임오버(체크메이트)등 구현할 것들이 남았지만 대략적으로 체스라는 느낌이 확 와닿게 되었지요. 다들 따라와주셔서 고생 많으셨고 긴 글 읽어주셔서 감사합니다!!
'Unity > Unity Chess' 카테고리의 다른 글
유니티로 2D 체스 만들기 (6) (0) | 2024.03.25 |
---|---|
유니티로 2D 체스 만들기 (4) (0) | 2024.03.18 |
유니티로 2D 체스 만들기 (3) (0) | 2024.03.16 |
유니티로 2D 체스 만들기 (2) (0) | 2024.03.16 |
유니티로 2D 체스 만들기 (1) (0) | 2024.03.16 |