Skip to content

Tutorial_Step2_JAVA

juns2lee edited this page Nov 12, 2018 · 1 revision

(초급 단계) 적군 정보 업데이트하기

TutorialLevel2Bot 프로젝트를 통해, 적군 정보 업데이트를 해보겠습니다.

개발 범위 정의

  1. 적군 종족 정보 업데이트

앞에서 개발한 TutorialLevel1Bot 을 실행시키고, 적군 종족을 Random 으로 설정한 상태에서 대결을 시작시켜보면, 적군 종족이 Unknown 이라고 표시됩니다. 게임 시작 시에는 알 수 없는 것이니 맞는 값인거죠.

이제 아군 일꾼 유닛을 적군 유닛이 있는 곳으로 찾아 이동시켜봅시다. 적군 유닛을 발견하면 사람은 '아 적군 종족이 무엇이구나' 알아치릴 수 있는데, 적군 종족이 Unknown 은 그대로일 것입니다. Protoss / Zerg / Terran 중 하나로 바뀌어야 할텐데, BWAPI 가 그런 기능은 제공하지 않는군요.

스타크래프트 게임의 특성상 적군 플레이어의 종족이 무엇이냐에 따라 전략과 전술이 크게 달라지는데, 종족 정보가 계속 바뀌지 않고 Unknown 으로 남아있으면 않되겠죠? 적군 플레이어의 종족 정보를 별도 멤버변수로 저장하여 관리하고, 적군 유닛 발견시 업데이트하도록 개발해보겠습니다.

  1. 적군 Base Location 정보 업데이트

스타크래프트는 기본적으로 적군 건물들을 모두 파괴(Eliminate)하는 것이 목표인 게임입니다. 적군 건물들을 공격하려면 먼저 적군 건물들의 위치를 파악해서 메모리에 저장(기억)해두었다가, 공격이 가능한 상황이 되면 공격을 가야겠죠.

게임 시작 시 아군 및 적군은 각각 랜덤하게 선정된 Start Location 에 건물 1개를 갖고 시작하며, 대부분의 건물을 Start Location 과 그 주위의 Base Location 에 짓기 마련입니다. 따라서 상대편의 Start Location 위치를 저장(기억)해두는 것은 필수적입니다.

아군 및 적군의 Start Location 을 별도 멤버변수로 저장하여 관리하고, 적군 건물 발견시 업데이트하도록 개발해보겠습니다.

개발 환경 설정

  1. Eclipse 를 실행시킵니다

  2. Package Explorer 에서 TutorialLevel2Bot 프로젝트를 선택합니다

  3. 메뉴 -> Run -> Run Configurations... -> 왼쪽 트리에서 Java Application 밑에 TutorialLevel2Bot 을 선택합니다

  4. 오른쪽 Arguments 탭 -> Working Directory : Others 에 C:\StarCraft 를 입력합니다

파일 목록

그전까지는 봇 프로그램의 모든 코드를 MyBotModule.cpp 하나 안에 넣어서 작성하였습니다. 하지만, 봇 프로그램이 일반적으로 2000줄 ~ 10000줄 정도 되기 때문에 어느정도 나눠서 작성을 하는 것이 코드 관리 효율성, 코드 가독성, 팀 협업 효율성 면에서 좋을 것입니다.

TutorialLevel2Bot 에서는 다음과 같이 GameCommander 와 InformationManager 클래스를 추가하였습니다.

MyBotModule 이 하던 일을 여러 클래스로 나누었고, 각 클래스는 Singleton Pattern 으로 작성하여 Static 인스턴스를 통해 이벤트를 처리하도록 하였습니다.

파일명 설명
Main.java 봇 프로그램의 시작 지점입니다. MyBotModule을 실행시킵니다
MyBotModule.java 스타크래프트 게임과 Connection 을 맺고, 스타크래프트 게임에서 발생하는 각 이벤트를 GameCommander 가 처리하도록 전달합니다. 스타크래프트 게임이 종료되면 봇 프로그램을 종료시킵니다
GameCommander.java 각각의 게임 이벤트가 적절하게 처리되도록 해당 객체에게 이벤트를 전달하는 관리자 역할을 합니다
InformationManager.java 게임 상황정보 중 일부를 자체 자료구조 및 변수들에 저장하고 업데이트합니다

1. 적군 종족 정보 업데이트

적군 플레이어의 종족 정보를 저장하는 변수를 InformationManager 클래스의 멤버변수로 선언해보겠습니다.

(InformationManager.java)

class InformationManager 
{
	...
	public Race enemyRace;
	...

}

적군 플레이어의 종족 정보를 초기화하는 코드는 InformationManager 클래스의 생성자 함수에 작성하면 될 것입니다.

(InformationManager.cpp)

InformationManager::InformationManager()
{
	...
	_enemyRace = _enemy->getRace();
}

적군 플레이어의 종족 정보는 언제 어떻게 업데이트 될 수 있을까요? 적군 유닛이 발견되었을 때, 적군 유닛의 UnitType 을 보고, 그 UnitType 은 어느 종족의 것인지 판단하면 될 것입니다.

onUnitShow 나 onUnitDiscover 이벤트에 대해 처리하면 되지만, onFrame 이벤트에서 처리해도 되므로, 일단은 onFrame 이벤트에서 처리하겠습니다.

MyBotModule 의 onFrame() 가 GameCommander 의 onFrame() 으로 이벤트를 전달하고, GameCommander 가 InformationManager 의 update() 를 호출하여 적군 플레이어의 종족 정보를 업데이트 하도록 한 코드는 다음과 같습니다.

(MyBotModule.java)

public void onFrame(){
    ...
	_gameCommander.onFrame();
	...
}
(GameCommander.java)

public void onFrame(){
	// 아군 베이스 위치. 적군 베이스 위치 정보를 저장/업데이트한다
	InformationManager.Instance().update();
	...
}
(InformationManager.java)

public void update() {
	// enemy 의 종족을 아직 모르는 경우
	if (enemyRace == Race.Unknown) {
		for (Unit unit : MyBotModule.Broodwar.enemy().getUnits())
		{
			enemyRace = unit.getType().getRace();
			break;
		}
	}
	...
}

플레이어 정보를 게임 화면에 표시하는 코드는 다음과 같습니다.

(GameCommander.java)

public void onFrame(){
	// 플레이어 정보 표시 - InformationManager 의 멤버변수 사용
	MyBotModule.Broodwar.drawTextScreen(5, 5, "My Player: "
		+MyBotModule.Broodwar.self().getTextColor()+MyBotModule.Broodwar.self().getName()
		+" ("+InformationManager.Instance().selfRace+")");
	MyBotModule.Broodwar.drawTextScreen(5, 15, "Enemy Player: "
		+MyBotModule.Broodwar.enemy().getTextColor()
		+MyBotModule.Broodwar.enemy().getName()+" ("+InformationManager.Instance().enemyRace+")");
	
	...
}

이제 TutorialLevel2Bot 을 실행시키고, 적군 종족을 Random 으로 설정한 상태에서 대결을 시작시킨 후 일꾼 유닛으로 정찰을 시켜보세요. 적군 종족이 Unknown 에서 바뀌는 것을 볼 수 있을 것입니다.

2. 적군 Start Location 정보 업데이트

이번에는 아군 및 적군 플레이어의 Start Location 정보를 Set 자료구조를 저장하고 사용해보도록 하겠습니다. InformationManager 클래스의 멤버변수로 선언하겠습니다.

(InformationManager.java)

class InformationManager {
	...
	public Map<Player, BaseLocation> mainBaseLocations;
	...

}

아군 및 적군 플레이어의 Start Location 정보를 초기화하는 코드는 InformationManager 클래스의 생성자 함수에 작성하면 될 것입니다. BWTA 라이브러리의 getStartLocation 함수를 사용하였습니다.

(InformationManager.java)

public InformationManager() {
	...
	mainBaseLocations = new HashMap<Player, BaseLocation>();
	mainBaseLocations.put(selfPlayer, BWTA.getStartLocation(MyBotModule.Broodwar.self()));
	mainBaseLocations.put(enemyPlayer, null);
}

적군 플레이어의 Start Location 정보는 언제 어떻게 업데이트 될 수 있을까요? 어떤 Start Location 에 적군 건물이 있는 것이 발견되면, 거기가 적군의 Start Location 이라고 판단하면 될 것입니다.

InformationManager 의 update() 에서 적군 플레이어의 Start Location 정보를 업데이트 하도록 한 코드는 다음과 같습니다.

(InformationManager.java)

public void update() {
	...
	// enemy 의 startLocation을 아직 모르는 경우
	if (mainBaseLocations.get(enemyPlayer) == null) {

		for (BaseLocation startLocation : BWTA.getStartLocations()) {
			
			for (Unit unit : MyBotModule.Broodwar.enemy().getUnits())
			{
				if (unit.getType().isBuilding()) {
					if (BWTA.getRegion(unit.getTilePosition()) == BWTA.getRegion(startLocation.getTilePosition())) {
						mainBaseLocations.put(enemyPlayer, startLocation);
						break;
					}
				}
			}
		}
	}
}

플레이어의 Start Location 정보를 게임 화면에 표시하는 코드는 다음과 같습니다.

(GameCommander.java)

void GameCommander::onFrame(){
	...
	// 플레이어 Start Location 표시 - InformationManager 의 멤버변수 사용
	if (InformationManager.Instance().mainBaseLocations.get(MyBotModule.Broodwar.self()) != null) {
		MyBotModule.Broodwar.drawTextScreen(200, 5, "Start Location: "
			+InformationManager.Instance().mainBaseLocations.get(MyBotModule.Broodwar.self()).getTilePosition().getX()+","
			+InformationManager.Instance().mainBaseLocations.get(MyBotModule.Broodwar.self()).getTilePosition().getY());
	}
	if (InformationManager.Instance().mainBaseLocations.get(MyBotModule.Broodwar.enemy()) != null) {
		MyBotModule.Broodwar.drawTextScreen(200, 15, "Start Location: "
			+InformationManager.Instance().mainBaseLocations.get(MyBotModule.Broodwar.enemy()).getTilePosition().getX()+","
			+InformationManager.Instance().mainBaseLocations.get(MyBotModule.Broodwar.enemy()).getTilePosition().getY());
	}
	...
}

이제 TutorialLevel2Bot 을 실행시키고, 대결을 시작시킨 후 일꾼 유닛으로 정찰을 시켜보세요. 적군의 Start Location 위치가 표시되는 것을 볼 수 있을 것입니다.

Home

Clone this wiki locally