티스토리 뷰

자바로 스타크래프트 봇(이하 스타봇)을 개발하고자 하는 분, 그리고 스타봇이 어떤 매커니즘으로 개발되는지 궁금한 분들을 위해 글을 작성합니다.

🎥 ... 지난번


지난번에는 미네랄 채취하는 방법에 대해 설명하였습니다. 이번에는 단순 유닛 생산에 대해 설명하고자 합니다.

지난 번까지는 일꾼(SCV)로 미네랄을 채취하였으니, SCV를 커맨드 센터에서 생산하여 더 많은 자원을 채취하고자하는 것이 주된 목표입니다.

 

🎯 코드와 설명


public final class BotUtil {

    // 생략

    public static void parseTextCommand(String command) {
        if ("c_scv".equals(command)) {
            TrainManager.train(UnitType.Terran_SCV);
        }
    }

    public static Game getGame() {
        return MineralGatherBot.getGame();
    }

    public static Player getSelf() {
        return getGame().self();
    }

    public static Player getEnemy() {
        return getGame().enemy();
    }

    public static int getSelfLeftSupply() {
        return getSelf().supplyTotal() - getSelf().supplyUsed();
    }
}

우선 BotUtil 의 get 메소드들을 추가하고, 명령어를 파싱하여 처리하기 위해 parseTextCommand 라는 메소드를 생성하였습니다. 

import bwapi.Unit;
import bwapi.UnitType;
import com.tistory.iqpizza6349.scb.util.BotUtil;

import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

public class TrainManager {
    private static final Map<UnitType, Set<Unit>> BUILDER = new HashMap<>();

    private TrainManager() {}

    public static void addTrainer(Unit unit) {
        getBuilders(unit).add(unit);
    }

    private static Set<Unit> getBuilders(Unit unit) {
        return getBuilders(unit.getType());
    }

    private static Set<Unit> getBuilders(UnitType unitType) {
        BUILDER.computeIfAbsent(unitType, k -> new HashSet<>());
        return BUILDER.get(unitType);
    }

    public static void train(UnitType target) {
        train(getBuilders(target.whatBuilds().getFirst()), target);
    }

    private static void train(Set<Unit> units, UnitType target) {
        for (Unit unit : units) {
            if (BotUtil.getSelfLeftSupply() < target.supplyRequired()) {
                continue;
            }

            if (target.mineralPrice() > BotUtil.getSelf().minerals()
                    || target.gasPrice() > BotUtil.getSelf().gas()) {
                continue;
            }

            if ((unit == null || unit.isBeingConstructed())
                    || (unit.isTraining() || !unit.canTrain(target))) {
                continue;
            }

            unit.train(target);
        }
    }
}

기존 WorkerManager와 같이 TrainManager 라는 또다른 매니저 클래스를 생성하여 건물에서 유닛을 생산할 수 있도록 도와주도록 개발하였습니다.

@Override
public void onUnitComplete(Unit unit) {
    UnitType unitType = unit.getType();

    if (unitType.isWorker()) {
        Worker worker = new Worker(unit);
        WorkerManager.addMinerals(worker);
        System.out.println(worker);
    }
    if (unitType.canProduce()) {
        TrainManager.addTrainer(unit);
    }
}

그리고 마지막으로 Bot 의 onUnitComplete 메소드에 위와 같이 addTrainer 메소드를 사용하여 유닛을 생산할 수 있는 유닛들을 저장하도록 하였습니다.

 

이제 채팅에 c_scv 라고 적는다면 커맨드 센터에서 SCV 1기를 생산할 것입니다.

📷 시연 사진 및 영상


c_scv 를 채팅으로 입력할 경우
커맨드 센터에서 SCV 1기를 생산한다.
만일 이미 생산되고 있는 데, 또 생산 명령을 내린다면 이를 무시한다. (정확히는 SCV를 생산할 수 있는 건물이 하나 뿐이기에 무시되는 것처럼 보일 뿐이다.)

 

📋 다음엔...


다음에는 마법 유닛 생산하는 방식에 대해 다루고 하였으나, 해당 방식은 특수 능력으로 생산되는 유닛이기에 나중에 다루도록 하고, 다음에는 특정 유닛이 특정 유닛을 생산하는 방식인 특수 유닛 생산을 다루고자 합니다.

(여기서 말하는 특정 유닛에서는 건물 유닛이 제외됩니다.)

그리고 개발 순서는 다음과 같이 진행할 것 같습니다.

  1. 특수 유닛 생산
  2. 건물 건설 1부 (단순 건물 건설)
  3. 건물 건설 2부 (건물 제외 장소)
  4. 건물 건설 3부 (건물 강제 장소)
  5. 마법 유닛 생산
  6. 정찰
  7. 그 다음...

 

댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2025/01   »
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
글 보관함