스타봇

스타크래프트 봇 동아리, 내전용 봇 개발 (#11) | 디파일러 파트 (1)

오잎 클로버 2021. 7. 22. 12:00
728x90

다음으로 컨트롤이 어려운 유닛이자, 저그의 심장이라고도 불리우는 유닛, '디파일러'.

디파일러는 테란전에서 빠질 수 없는 유닛입니다.

과 마찬가지로 공격은 따로 없으나, 3가지의 특수한 능력이 있습니다.

'다크스웜', '플레이그', '컨슘'으로 

순서대로 '다크스웜'은 저그의 연막탄이라고 할 수 있다.

생성된 구름안에 있는 유닛들은 원거리 공격의 타점을 빗나가게 한다.

즉, 타점을 빗나가게 하는 무시하는 것은 아니다.

타점은 본 유닛의 앞쪽으로 타점이 변경되기에 뒤쪽에 있는 유닛을 겨냥하면 타점 변경으로 앞쪽에 있는 유닛이 맞게된다. 시즈탱크의 공격을 무력화시키는 데 있어 좋다.

'플레이그'는 지속형 피해를 주는 능력 중 하나이나, 스타크래프트 내에서 가장 강력한 능력 중 하나이다.

브루들링은 150에너지를 소모하여 단 하나의 단일 객체만 즉사 시키는 데에 반해

플레이그는 약 0.333..초마다 약 3.9453125가량의 피해를 약 25초동안 계속 하여 입히는 능력이다.

플레이그의 이펙트는 인스네어의 붉은 버전이라고 생각하면 편하지만 꾸준히 체력이 1이될 때까지 입히며, 범위 능력이다.

둘 다 막대한 에너지를 소모하기에 이를 꾸준히 충전시킬 능력인 '컨슘'이 있다.

컨슘은 아군을 소모하여 에너지를 50회복한다.

아군의 종류는 무관하게 무조건 50만 회복한다.

 

위 능력들을 전부 구현해보고자하나, 

로직이 까다롭고, 여러 문제가 있으므로

해당 코드가 잘 작동하지않을 수 있기에

파트를 2가지로 나누겠다.

파트1은 코드와 시연영상, 그리고 저자의 문제점

파트2는 개선된 코드와 시연영상, 그리고 문제점 해결

일단은 시연 영상을 시작으로 저자의 실수와 함께 여러 가능성에 대해 적는 것으로 마무리를 하겠다.

 

 

더보기

디파일러는 하이브 단계에서 사용가능한 유닛이므로 어쩔 수 없이 치트를 사용하였다.

 

먼저 확인해볼 코드는 '다크스웜'의 코드이다.

...	
	Unit target = getNearestEnemy(unit, WeaponType.Dark_Swarm.maxRange());

	if (target == null || !target.exists()) {
		Unit nearestUnit = getNearestUnit(unit);
		if (nearestUnit != null) {
			if (unit.canFollow(nearestUnit) && !unit.isFollowing() && nearestUnit.canAttack() && 
					!nearestUnit.getType().isWorker() && !nearestUnit.getType().isBuilding() && !nearestUnit.getType().isDetector())
				unit.follow(nearestUnit);
		}
	}
	else {
		if (unit.getEnergy() > 100) {
			System.out.println("적 감지");
			defaultDarkSwarm(unit, target);
		}
		else {
			Chokepoint moveTo = InformationManager.Instance().getFirstChokePoint(MyBotModule.Broodwar.self());
			commandUtil.move(unit, moveTo.getPoint());
		}
	}
...

여러 시행착오를 껶어가며 적용한 코드지만 여전히 문제가 존재한다.

private void defaultDarkSwarm(Unit defiler, Unit target) {
		
	if (target.getPlayer() == MyBotModule.Broodwar.enemy()) {
			
		Unit nearestUnitFromEnemy = getNearestUnit(target);
		if (nearestUnitFromEnemy != null) {
			// 이 둘의 위치 가운데 접점에 다크스웜을 뿌림
			Position willDarkSwarm = new Position(
					(target.getPoint().getX() + nearestUnitFromEnemy.getPoint().getX()) / 2,
					(target.getPoint().getY() + nearestUnitFromEnemy.getPoint().getY()) / 2
			);
			// 이방법 안 먹히면 또다른 방법 알아내야함
			if (willDarkSwarm.isValid()) {
				commandUtil.useTech(defiler, TechType.Dark_Swarm, willDarkSwarm);
				setSpecialAction(defiler, 50);
			}
		}
	}
}

다크스웜 로직을 어떻게 작성해야할지가 제일 막막하여

제일 가까운 적군과 그 적군에게서 제일 가까운 아군위치의 가운데 접점에 다크스웜을 뿌리도록하였다.

 

일단 위부터 천천히 코드 해석을 하자면

 

디파일러다크스웜 최대사거리인 9이내에 가장 가까운 적을 가져온 후,

해당 적을 target으로 지정한다.

targetnull이라면 디파일러는 가장 가까운 아군 중 일꾼, 건물이 아닌 공격 가능 유닛을 따라다니도록했다.

그렇지않다면 에너지가 100이상인지 체크를 하고

100초과라면 다크스웜을 사용하도록했다.

그렇지않다면 본진 길목으로 이동을 하도록했다.

 

defaultDarkSwarm메소드는 위 로직을 수행하는 메소드로서

주석에도 나와있듯이 이 둘의  위치 가운데 접접에 다크스웜을 뿌림을 구현하였다.

Position을 인스턴스하여 새로운 위치를 만들고 해당 위치가 유효한지 검사 후, 다크스웜을 뿌리도록하였다.

로직만을 본다면 아무런 문제가 없어보이나

이부분에서 상당한 문제가 발생하였다.

시연영상만 10개를 찍을 정도로 수정에 수정을 거듭하여 그나마 나아진 것이 이것이다.

 

문제점

1) 100초과가 되지않으면 본진 길목으로 이동해야하나, 이동하지않는다.

2) 적군이 주변에 없다면 가장 가까운 아군을 따라다녀야 하나 따라다니지않는다.

3) 컨슘을 한 이후, 다크스웜을 사용했다고 Console에 출력되었지만 아무리 속도를 빨리 올렸다 한들

다크스웜은 시간이 매우 길기에 확인이 가능했어야한다.

 

더보기

(플레이그 시연영상도, 코드도 없는 이유는 코드는 인스네어와 동일하기에 따로 작성하지않았다.)

 

그다음은 컨슘이다.

...
// 컨슘) 에너지를 빠르게 회복하기위해서 사용한다.
// 자신에게 제일 가까운 저글링을 상대로 컨슘을 한다.
if (MyBotModule.Broodwar.self().hasResearched(TechType.Consume)) {
			
	if (unit.getEnergy() < 175) {
	
		double minDist = Double.MAX_VALUE;
		Unit nearestZergling = null;
		for (Unit zergling : getSelfUnit(UnitType.Zerg_Zergling)) {
			if (InformationManager.distancePosition(zergling.getPosition(), unit.getPosition()) < minDist) {
				minDist = InformationManager.distancePosition(zergling.getPosition(), unit.getPosition());
				nearestZergling = zergling;
				}
			}
			if (nearestZergling != null && nearestZergling.exists()) {
				commandUtil.useTech(unit, TechType.Consume, nearestZergling);
			}
		}
	}
...

주석에도 나와있듯이 가장 가까운 저글링에게 컨슘을 사용하도록했다.

 

여기서도 문제점이 있다.

문제점

1) 컨슘을 사용하면 해당 유닛에게로 이동한다. 하지만 시연영상에도 그랬듯이 다크스웜을 사용했을 당시 이동을 하지않았다.

2) 에너지가 175미만이면 계속 컨슘을 하도록했으나, 시연 영상에도 그랬듯이 에너지가 121인데도 더이상 컨슘을 사용하지않았다. (중간에 끊어서 안보이는 것이 아닌 더이상 컨슘을 하지않아서 끊은 것이다)

 

다행히도 플레이그는 정상으로 보인다.

 

아마 스타봇 블로그를 운영하면서 제일 까다로운 유닛이 아닐까하는 생각이 든다.

스타크래프트 인공지능들 중 다크스웜컨슘을 사용하는 리플레이를 보면

다크스웜을 적들이 가장 많이 모여있는 중앙에 사용하였다.

 

이로써 글을 마치겠다.

내일은 버그를 더 고치도록하며 이만 물러나겠다.