스타봇

스타크래프트 봇 동아리, 내전용 봇 개발 (#10)

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

사용하기 매우 까다롭지만 사용만 잘하면 이득을 최대한 취할 수 있는 유닛 ''

퀸에게 4가지의 특별한 능력인

'패러사이트', '브루들링 스폰', '인스네어', '인페스트 커맨드 센터'가 있다.

패러사이트는 적군에게 기생충을 심어 해당 적군의 시야를 엿 볼 수 있다.

패러사이트를 제거하는 방법은 해당 적군이 죽거나 메딕의 리스토레이션으로만 제거가 가능하다.

브루들링은 모든 적군을 즉사를 시킬 수 있는 강력한 능력이다.

적군 1기를 죽여 공생충(브루들링)을 2기 생성한다.

인스네어는 적군의 발을 묶는 데에 매우 효과적이다.

광역으로 적군의 이동속도를 50%만큼 감소시킨다.

인페스트 커맨드 센터는 파손되가는 커맨드 센터에 퀸이 들어가 커맨드 센터를 저그로 감염시킬 수 있는 능력이다.

 

위 4가지 능력들 중 저자는 2가지의 능력만 구현을 하려고 한다.

(인페스트 커맨드 센터는 자동 시전이 존재하기에 제외시켰다)

'패러사이트'와 '인스네어'를 개발하고자한다.

일단 퀸이 죽어가는 지에 대해 확인을 한다.

퀸이 죽더라도 패러사이트를 성공했다면 퀸의 죽음은 아깝지않다.

private boolean queenAboutToDie(Unit queen) {
	return queen.getHitPoints() < 30 ||
		queen.isIrradiated() ||
		queen.isPlagued();
}

그런다음 바로 패러사이트를 구현하도록하자.

private void queenControl(Unit unit) {
		
	if (MyBotModule.Broodwar.getFrameCount() % 24 != 0)
		return;

	boolean dying = queenAboutToDie(unit);
    
	if (dying && unit.getEnergy() >= 75) {
		// 죽기 전에는 가장 가까운 녀석에게 패러사이트
		Unit closestEnemy = getNearestEnemy(unit, 12*32);
		if (closestEnemy != null) {
			if (closestEnemy.getDistance(unit) < 1200 && unit.canUseTech(TechType.Parasite, closestEnemy)) {
				commandUtil.useTech(unit, TechType.Parasite, closestEnemy);
				setSpecialAction(unit, 0);
			}
		}
	}
	if (unit.getEnergy() >= 200) {
		// 원래는 우선순위를 정하려다가 걍 가장 가까운 녀석에게 패러사이트 (운 좋으면 캐리어나 배슬에 붙이겠지)
		Unit closestEnemy = getNearestEnemy(unit, 12*32);
		if (closestEnemy != null) {
			if (unit.canUseTech(TechType.Parasite, closestEnemy)) {
				commandUtil.useTech(unit, TechType.Parasite, closestEnemy);
				setSpecialAction(unit, 100);
				System.out.println("패러사이트 심은 대상 : " + closestEnemy.getType());
			}
		}
	}
...

위 코드와 같이 개발을 하였는 데, 추후 코드는 수정될 수 있다.

 

commandUtil.useTech() 메소드는 오버로딩을 하여 총 3가지이다.

public void useTech(Unit unit, TechType techType) {
	if (commandHash.contains(unit))
		return;
	else
		commandHash.add(unit);
	if (unit.canUseTech(techType))
		unit.useTech(techType);
}

public void useTech(Unit unit, TechType techType, Unit enemy) {
	if (commandHash.contains(unit))
		return;
	else
		commandHash.add(unit);
	if (unit.canUseTech(techType, enemy))
		unit.useTech(techType, enemy);
}

public void useTech(Unit unit, TechType techType, Position position) {
	if (commandHash.contains(unit))
		return;
	else
		commandHash.add(unit);
	if (unit.canUseTech(techType, position))
		unit.useTech(techType, position);
}

이제 인스네어를 구현해보자

일단 인스네어를 개발하였는 지부터 확인하자

if (MyBotModule.Broodwar.self().hasResearched(TechType.Ensnare))

그런 다음 유닛이 정상상태 (여러가지 이유로 비정상 상태이나 사용이 되는 경우가 있기때문)

를 확인한다.

if (unit.exists())

그런 다음 인스네어는 아군 적군 할 거 없이 다 피해를 보기때문에

꽤 단순하게 코드를 작성하였다.

적군의 상태 및 유닛 종류를 확인 후, 작동

그리고 해당 적군 근처에 아군과 적군을 세어 인스네어를 뿌리도록한다.

...
    if (MyBotModule.Broodwar.self().hasResearched(TechType.Ensnare)) {
		if (unit.exists()) {
			int maxEnemyCount = 0;
			Unit targetEnemy = null;
			for (Unit enemy : unit.getUnitsInRadius(WeaponType.Ensnare.maxRange())) {
				if (!enemy.getType().isWorker() || (enemy.getType().canAttack() && enemy.getType() != UnitType.Zerg_Zergling
					&& enemy.getType() != UnitType.Zerg_Scourge && !enemy.getType().isBuilding() && !enemy.getType().isNeutral()
					&& !enemy.isInvincible() && enemy.getHitPoints() > 0)) {
					int enemyCount = 0;
					int selfCount = 0;
					for (Unit u : enemy.getUnitsInRadius(128)) {
						if (u.getPlayer() == MyBotModule.Broodwar.enemy())
							enemyCount++;
						else if (u.getPlayer() == MyBotModule.Broodwar.self())
							selfCount++;
					}
					int gapCount = enemyCount - selfCount;
					if (gapCount > 0 && maxEnemyCount <= gapCount) {
						maxEnemyCount = gapCount;
						targetEnemy = enemy;
					}
				}
			}
			if (maxEnemyCount == 0) {
				Chokepoint moveTo = InformationManager.Instance().getFirstChokePoint(MyBotModule.Broodwar.self());
				commandUtil.move(unit, moveTo.getPoint());
			}
			else {
				if (unit.getEnergy() < 75)
					commandUtil.move(unit, InformationManager.Instance().getMainBaseLocation(MyBotModule.Broodwar.self()).getRegion().getCenter().getPoint());
				else if (targetEnemy != null && unit.getEnergy() > 75) {
					System.out.println("인스네어 맞은 적군 카운트 :" + maxEnemyCount);
					commandUtil.useTech(unit, TechType.Ensnare, targetEnemy.getPosition());
					setSpecialAction(unit, 50);
				}
			}
		}
	}
}

영상을 끝으로 글을 마무리하겠다.

 

영상 2개를 이어붙였다.

순서대로 패러사이트를 먼저 하고 그후 인스네어 영상이다.