NGMsoftware

NGMsoftware
로그인 회원가입
  • 매뉴얼
  • 학습
  • 매뉴얼

    학습


    C# C# .NET 매크로 프로그램 만들기. (다중 조건 액션 만들기)

    페이지 정보

    본문

    안녕하세요. 엔지엠소프트웨어입니다. 엔지엠 매크로에는 이미지 멀티 서치, 이미지 멀티 매치, 이미지 멀티 픽셀 서치등등... 여러개의 이미지 또는 조건을 동시에 처리할 수 있는 기능들이 존재합니다. 이번에 알아볼 내용은 다중 조건 액션인데요. 엔지엠 매크로 6 버전도 제공하는 기능입니다. 이번에 새롭게 개선된 다중 조건을 사용하면 이미지 멀티 서치, 이미지 멀티 매치, 멀티 픽셀 서치와 같은 복잡한 액션은 더이상 사용하지 않아도 됩니다.

     

    차세대 엔지엠 매크로는 이미지 멀티 조건들이 모두 삭제되었습니다. 다중 조건 액션으로 동일하게 처리할 수 있기 때문입니다. 기존에는 구조적인 문제로 각각의 액션들을 상속 받아서 처리하는게 불가능했는데요. 이번에는 새로운 방식으로 디자인했기 때문에 좀 더 유연하게 액션들을 처리할 수 있게 되었습니다. 엔지엠 3부터 6까지 동일한 디자인을 적용하다가 이번에 새로운 닷넷을 도입하면서 매크로 엔진을 상당부분 튜닝했습니다. 또한, 아키텍쳐도 변경되었습니다. 물론, 더 효율적인 방향으로요^^

     

    다중 조건 모델을 컨디션 카테고리에 추가해줍니다.

    public class MultiConditionModel : BaseModel

     

    여러개의 조건을 하위 모델로 등록하면 각각의 조건 결과를 평가하고, 어떻게 처리할지에 대한 옵션으로 최종 결과를 만듭니다.

    [LocalizedCategory("Action")]
    [LocalizedDisplayName("ConditionOption")]
    [LocalizedDescription("ConditionOption")]
    [Browsable(true)]
    [DefaultValue(typeof(Ai.Definition.ConditionOption), "Or")]
    public Ai.Definition.ConditionOption Option { get; set; } = Definition.ConditionOption.Or;

     

    옵션은 총 3가지인데요. 기존과 동일한 방식을 채택했습니다. And 조건은 다중 조건에 추가한 모든 조건이 True여야 최종 결과가 True가 됩니다. Or 조건은 하나만 True여도 최종 결과가 True가 됩니다. Custom은 추가 옵션과 같이 사용됩니다.

    public enum ConditionOption
    {
        And = 0,
        Or = 1,
        Custom = 2
    }

     

    위에서 Custom 옵션을 선택하면 아래 속성에서 몇개까지 일치해야 True로 처리할지를 입력해야 합니다. 예를 들어서 이미지 서치 3개가 있다고 상상해보세요. 여기서 2개만 일치해도 최종적으로는 True로 처리하고 싶다면 아래 값을 2로 입력해야 합니다. And와 Or 조건으로는 처리할 수 없는 것들은 Custom 옵션을 사용해야 합니다.

    [LocalizedCategory("Action")]
    [LocalizedDisplayName("CustomCount")]
    [LocalizedDescription("CustomCount")]
    [Browsable(true)]
    [DefaultValue(1)]
    public int CustomCount { get; set; } = 1;     

     

    조건 액션들은 True와 False를 처리하는 방식이 모두 동일합니다. 계속해서 미뤄두다가 다중 조건 액션을 만들면서 리펙토링도 같이 진행했습니다.

        public override string? Execute(Ai.Interface.IPlayer player)
        {
            if (Actions == null || Actions.Count == 0) return null;
    
            string? id = base.Execute(player);
            bool isBreak = false;
            int trueCount = 0;
            var actions = player.GetActionList(Actions.Cast<Interface.IModel>().ToList()).Cast<ActionModel>().ToList();
    
            foreach (var action in actions)
            {
                if (action is BaseModel)
                {
                    var act = (BaseModel)action;
                    act.Execute(player);
                    ConditionResult = act.ConditionResult;
                }
    
                switch (Option)
                {
                    case Definition.ConditionOption.Or:
                        isBreak = ConditionResult;
                        break;
                    case Definition.ConditionOption.And:
                        if (!ConditionResult)
                            isBreak = ConditionResult;
                        break;
                    case Definition.ConditionOption.Custom:
                        if (ConditionResult)
                            trueCount++;
    
                        isBreak = trueCount == CustomCount;
                        break;
                }
    
                if (isBreak) 
                    break;
            }
    
            Common.ConditionProcess(this, id);
    
            return id;
        }
    }

     

    조건을 처리하는 코드는 리팩토링을 통해서 Common.ConditionProcess 메소드가 처리합니다.

    internal static void ConditionProcess(BaseModel model, string? id)
    {
        if (model.ConditionResult)
        {
            id = model.TrueID;
    
            if (model.Actions != null)
            {
                var trueModel = model.Actions.Where(w => w is TrueModel);
                var falseModel = model.Actions.Where(w => w is FalseModel);
    
                if (trueModel.FirstOrDefault() != null)
                {
                    ((ActionModel)trueModel.First()).IsSkip = string.IsNullOrEmpty(id);
                    ((ActionModel)falseModel.First()).IsSkip = true;
                }
            }
        }
        else
        {
            id = model.FalseID;
    
            if (model.Actions != null)
            {
                var trueModel = model.Actions.Where(w => w is TrueModel);
                var falseModel = model.Actions.Where(w => w is FalseModel);
    
                if (trueModel.FirstOrDefault() != null)
                {
                    ((ActionModel)trueModel.First()).IsSkip = true;
                    ((ActionModel)falseModel.First()).IsSkip = string.IsNullOrEmpty(id);
                }
            }
        }
    }

     

    그동안 알아본 이미지 조건들보다는 코드가 간단합니다. 이미지를 처리하는 부분들은 다른 액션이 하고, 해당 액션이 처리하는 부분을 취합해서 최종 판단만 하면 되기 때문입니다. 글로는 잘 이해가 안갈수도 있는데요. 아래 테스트를 통해서 어떻게 동작하는지 알아보도록 하겠습니다.

    aMJwmcC.png

     

     

    다중 조건을 테스트하기 위해 그림판에 사각형과 오각형 도형을 하나씩 추가 했습니다.

    V0rPal3.png

     

     

    이미지 매치 2개는 각각 사각형과 오각형을 찾습니다. 현재 조건은 And이기 때문에 도형 2개가 모두 존재해야 합니다. 현재 상황은 2개 모두 존재하기 때문에 최종 결과의 참 클릭과 마지막 마우스 클릭이 동작하게 됩니다.

     

     

    매크로가 흘러간 흔적을 보면 좀 더 명확하게 동작을 분석할 수 있습니다.

    FtyiIwu.png

     

     

    아래와 같이 두번째 오각형 이미지 매치에서 참인 경우 마우스가 클릭하도록 설정 해보세요.

    TIj0aGm.png

     

     

    멀티 조건 안에 조건도 동작하는걸 확인할 수 있습니다. 하지만, 멀티 조건의 True와 False안에 있는 조건들은 동작하지 않습니다. 이들은 멀티 조건 액션이 완료된 후 결과에 따라서 실행 여부가 나중에 결정되기 때문입니다.

     

    아래 시나리오는 그림판에서 Or 조건에 따라 두번째 이미지 매치의 실행 여부를 확인하고 있습니다. 오각형이 없으면 두번째 이미지 매치는 실행되지 않고, 최종 결과의 클릭만 동작합니다. 그림판에서 오각형을 다시 추가하고 실행하면 두번째 이미지 매치가 동작하고, 참이기 때문에 그림판 중앙을 클릭합니다.

     

     

    간단하게 다중 조건 액션을 만들어 봤는데요. 1부에서는 간단하게 이 액션이 어떻게 동작하고, 다른 조건 액션들과 상호 관계를 어떻게 맺고 처리하는지를 알아봤습니다. 이번에 새롭게 개선되는 다중 조건 액션의 핵심 기능은 2부에서 알아볼 내용입니다. 여러개의 이미지중 하나라도 존재하면 True가 작동해야 하는 방식을 많이 사용하고 있습니다. And 조건보다는 Or 조건으로 뭔가 빠르게 변화하는 이미지를 캐치하기 위함이죠.

     

    다음에는 여러개의 이미지를 Or 조건으로 반복 처리할 때 가중치를 부여하고, 값을 누적해서 자주 매치되는 이미지가 먼저 확인할 수 있도록 알고리즘을 만들 예정입니다. 예를 들어서 빠르게 변화하는 이미지를 찾기 위해서 픽셀 서치를 주로 이용하는데요. 여기서, 빠르게 무지개색으로 변화한다고 생각 해보세요. 픽셀을 비교하다가 색이 바뀌면 못찾겠죠? 그래서, 몇가지 다양한 색들을 등록해두고 하나라도 일치하면 참으로 간주하는게 정확도가 좋을겁니다. 하지만, 효율적인 측면으로 볼 때 모두 비교할 필요는 없으니 자주 매칭되는 이미지에 우선 순위를 줘서 다음 실행될 때 먼저 매치를 해보는게 좋을거 같습니다.

     

    가중치를 부여하고, 계산하는데 너무 많은 시간이 소비되면 실제로 원하는 퍼포먼스보다 더 떨어질수도 있습니다. 그래서, 최대한 심플하면서도 누적량을 최소화해서 처리할 수 있도록 해야겠습니다. 이런 정보들도 내부에 가지고 있어야 하기 때문에 최적화가 중요할거 같습니다. 처음에 5개 이미지에 가중치를 부여했다가 나중에 변경되면 이상한 이미지가 가중치를 받을수도 있거든요. 이런 구조적인 변화가 있을 때는 초기화하고 다시 처음부터 프로세스를 돌리는게 좋을거 같네요.

     

    개발자에게 후원하기

    MGtdv7r.png

     

    추천, 구독, 홍보 꼭~ 부탁드립니다.

    여러분의 후원이 빠른 귀농을 가능하게 해줍니다~ 답답한 도시를 벗어나 귀농하고 싶은 개발자~

    감사합니다~

    • 네이버 공유하기
    • 페이스북 공유하기
    • 트위터 공유하기
    • 카카오스토리 공유하기
    추천0 비추천0

    댓글목록

    등록된 댓글이 없습니다.