質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

88.93%

Unity:戦略シミュレーションゲームで、攻撃範囲にいる敵を検索→攻撃対象選択→攻撃を実行したい

解決済

回答 1

投稿

  • 評価
  • クリップ 0
  • VIEW 1,581

zenobread

score 38

やりたいこと

戦略シミュレーションゲームでよくある
「敵対象の近くまで移動→攻撃範囲内にいる敵を検索→その中から攻撃対象を選択→攻撃実行」
以上を実装したいと考えています。
現在、移動と検索までは実装することが出来ました。
問題は「攻撃範囲にいる敵を選択しその敵に対し攻撃行動を実行」の部分が全く分かりません。

特に、全てマスのクリックで完結させたいと考えているので、「配列内の攻撃対象をボタンで選択」ではないやり方を模索しております。

以下は該当スクリプトです。

using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Tilemaps;

public class Test_player_tile : MonoBehaviour
{
    [SerializeField] private Tilemap atk_area_color;//移動と攻撃タイルを設置するマップ
    [SerializeField] private Tilemap map;//キャラクターが移動するマップ
    [SerializeField] private Game_Manager manager;
    [SerializeField] private Test_tilemap tile;
    [SerializeField] private Log_Manager logsc;
    [SerializeField] private Tile atk_tile;//移動範囲タイル
    [SerializeField] private Tile gren_tile;//攻撃範囲タイル

    public bool mouse_onoff;
    public int atk = 50;
    public int hp = 100;
    public Vector3Int position;

    private bool atk_bool=true;
    private bool behave_bool = true;
    private bool ui_bool = false;
    private bool calic_sign;
    private int atk_area_int = 2;//移動範囲
    private int behave_int = 1;//攻撃範囲
    private int a_i, b_i, c, d, area_length, gth;
    private GameObject[] enemys;
    private Vector3Int atk_area;
    public Status Ch_Status;
    Gridman[] grids;

    public enum Status//オブジェクトの状態
    {
        Waiting,
        Move,
        Wait_for_Behave,
        Behaving,
        False,
    }
    // Start is called before the first frame update

    public struct Gridman
    {
        public int x, y;
    }
    public struct Enemy
    {
        public Vector3 pos;
        public GameObject name;
    }

    void Start()
    {
        enemys = GameObject.FindGameObjectsWithTag("Unit");
    }

    public void Caliculator(int ans,int x,int y)
    {
        //移動と攻撃範囲を計算
        ans *= ans;
        var cal = (x - position.x) * (x - position.x) + (y - position.y) * (y - position.y);
        if (ans >= cal)
        {
            ++gth;
            Array.Resize(ref grids, gth);
            grids[gth-1] = new Gridman() { x = x, y = y };
            //Debug.Log("ans:"+ans+"\tcal:"+cal+"\tgrids_number:"+gth+"\tgrids_x:"+grids[gth-1].x+"\tgrids_y:"+grids[gth-1].y);
        }
        else
        {
           //Debug.Log("error\t" + "ans:" + ans + "\tcal:" + cal + "\tx:" + x + "\ty:" + y);
        }
    }

    // Update is called once per frame
    void Update()
    {
        //移動タイルを設置した後「Move」状態となり、マウス座標と一致した移動となる
        if (mouse_onoff == false) this.transform.position = new Vector3(map.WorldToCell(this.transform.position).x + 0.5f, map.WorldToCell(this.transform.position).y + 0.5f, -1f);
        if (this.Ch_Status==Status.Move) this.transform.position = new Vector3(manager.mouse_position.x + 0.5f, manager.mouse_position.y + 0.5f, -1f);
    }

    public void Cursol_1(ref bool mouse)
    {
        if (this.Ch_Status == Status.Waiting)
        {
            //移動計算。このオブジェクトから見て周囲2マス程度を移動範囲とする
            this.Ch_Status = Status.Move;
            Debug.Log(this.Ch_Status);
            gth = 0;
            area_length = (2 * atk_area_int + 1) * (2 * atk_area_int + 1);//9(n=1),25(n=2),49(n=3),81(n=4)  (int+(int+1))*(int+(int+1)) (2x+1)^2
            grids = null;
            grids = new Gridman[0];
            position = map.WorldToCell(this.transform.position);
            for (var i = position.x - atk_area_int; i <= position.x + atk_area_int; i++)
            {
                for (var z = position.y - atk_area_int; z <= position.y + atk_area_int; z++)
                {
                    Caliculator(atk_area_int, i, z);
                }
            }
            //移動範囲にタイル設置
            foreach (Gridman grideach in grids)
            {
                var tile_position = new Vector3Int(grideach.x, grideach.y, (int)atk_area_color.transform.position.z);
                atk_area_color.SetTile(tile_position, atk_tile);
            }
        }
        else if (this.Ch_Status == Status.Move)
        {
            //移動終了行動、マウスとともに移動し、マウスの座標に先ほど設置したタイルがなければ移動できない
            Vector3Int mon = new Vector3Int(manager.mouse_position.x, manager.mouse_position.y, (int)atk_area_color.transform.position.z);
            Debug.Log(mon);
            if (atk_area_color.HasTile(atk_area_color.WorldToCell(mon)) == false)
            {
                this.mouse_onoff = true;
                Debug.Log("ここにはおけません");
            }
            else if (atk_area_color.HasTile(atk_area_color.WorldToCell(mon)) == true)
            {
                atk_area_color.ClearAllTiles();
                this.Ch_Status = Status.Wait_for_Behave;
                mouse_onoff = false;
            }
        }
        else if (this.Ch_Status == Status.Wait_for_Behave)
        {
            //攻撃範囲計算、このオブジェクトに対して上下左右1マスを範囲として設定。
            gth = 0;
            var x = behave_int;
            area_length = (2 * behave_int + 1) * (2 * behave_int + 1);//9(n=1),25(n=2),49(n=3),81(n=4)  (int+(int+1))*(int+(int+1)) (2x+1)^2
            grids = null;
            grids = new Gridman[area_length];
            position = map.WorldToCell(this.transform.position);
            for (var i = position.x - behave_int; i <= position.x + behave_int; i++)
            {
                for (var z = position.y - behave_int; z <= position.y + behave_int; z++)
                {
                    Caliculator(x, i, z);
                }
            }
            //攻撃範囲にいる敵オブジェクト座標にタイル設置。
            foreach (Gridman grid in grids)
            {
                var tile_position = new Vector3Int(grid.x, grid.y, (int)atk_area_color.transform.position.z);
                foreach (GameObject enemy in enemys)
                {
                    if (tile_position == map.WorldToCell(enemy.transform.position) && this.gameObject.name != enemy.name)
                    {
                        atk_area_color.SetTile(tile_position, gren_tile);
                    }
                }
            }
        }//攻撃範囲に設置したタイルを削除し、もう一度タイルを設置
        else if (this.Ch_Status == Status.Wait_for_Behave)
        {
            atk_area_color.ClearAllTiles();
            Debug.Log(this.Ch_Status);
        }
    }
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Tilemaps;

public class Game_Manager : MonoBehaviour
{

    [SerializeField] private Test_tilemap testmap;
    [SerializeField] private GameObject player;
    [SerializeField] private Test_player_tile player_script;
    [SerializeField] private Tilemap map;
    [SerializeField] private Tilemap atk_color_map;

    public Vector3Int mouse_position;

    private Test_player_tile test; 
    private Vector3 position;
    private Vector3 screenToWorldPointPosition;

    bool mouse_having;
    GameObject clickobject;
    Test_player_tile a;
    // Start is called before the first frame update
    void Start()
    {
        mouse_having = false;
        test = null;
    }

    // Update is called once per frame
    void Update()
    {
        position = Input.mousePosition;
        position.z = 10f;
        screenToWorldPointPosition = Camera.main.ScreenToWorldPoint(position);
        mouse_position = testmap.ClickedAction(screenToWorldPointPosition);
        Ray ray = Camera.main.ScreenPointToRay(position);
        RaycastHit2D hit2d = Physics2D.Raycast((Vector2)ray.origin, (Vector2)ray.direction, 10f);

        if (Input.GetMouseButtonDown(0)&&mouse_having==false)
        {
            Debug.Log(mouse_position);
            clickobject = null;
            if (hit2d)
            {
                clickobject = hit2d.transform.gameObject;
                //上記
                a = clickobject.GetComponent<Test_player_tile>();
                if (clickobject.transform.tag=="Unit"&&mouse_having==false)
                {
                    Debug.Log(a.Ch_Status);
                    a.Cursol_1(ref mouse_having);
                }else
                {
                    Debug.Log("エラー");
                }
            }
        }
    }
}
  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

質問への追記・修正、ベストアンサー選択の依頼

  • izmktr

    2019/09/18 18:01

    具体的に何がわからないのでしょうか
    普通、この手のゲームは自ユニット選択→敵ユニット選択で、勝手に敵のそばに移動し攻撃すると思います
    移動可能マスと攻撃可能マスの洗い出しが済んでいれば、敵ユニットを選択した時点で攻撃可能かはわかりますし、
    敵のマスから攻撃射程の範囲で移動可能なマスが移動するべきマスになります

    キャンセル

  • zenobread

    2019/09/18 19:07

    分かりにくい書き方で申し訳ありません。
    私が開発しているスクリプトでは
    「自ユニット選択」→「敵ユニット選択」→「移動」→「攻撃」
    ではなく
    「自ユニット選択」→「移動」→「敵ユニット選択」→「攻撃」
    となっております。
    例えば移動した先で、周囲の敵情報を検索したのち、仮に
    「敵ユニット1」「敵ユニット2」「敵ユニット3」
    が攻撃可能範囲にいるとします。
    そのなかで1か2か3か選んで攻撃するとした場合、どうやってプレイヤーに攻撃対象を選択させることが出来るか、といったところです。

    例えば現在マウスで自ユニットをクリックすることで
    移動範囲・攻撃範囲を表示させているのですが、
    攻撃範囲を表示させている状態で、敵ユニットをクリックし攻撃対象とする
    ということについてどうすれば実装できるか分からない状態です。

    キャンセル

  • izmktr

    2019/09/19 03:57

    自ユニットや移動地点のクリックが出来るのに、敵ユニットのクリックが出来ない、というのがいまいちよくわかりません
    クリックした位置からどのユニットやマス目になるのかの変換ができていれば、敵ユニットに応用するのはさほど困難ではないはずです
    その部分は他の誰かが制作していて、自分ではその辺の仕組みを理解していない、というケースなのでしょうか?

    キャンセル

  • zenobread

    2019/09/19 08:52

    大変失礼しました。自己解決することが出来ました。
    このファイルは
    「GameManagerが自ユニットをクリックすることで、GameManagerのclickobjectに自ユニットが選択され、そのユニットのCursol_1関数を呼び出し、自ユニットのenum StatusがWaitingからMoveとなり自ユニットはマウスの動きに追従する。
    その状態だとマウスカーソルの座標と自ユニットの座標が共通するので、もう一度クリックすると自動的に自ユニットをクリックすることとなり、自ユニットのCursol_1関数を呼び出し移動完了となる。」
    という動きを取っています。
    ですので敵ユニットをクリックすると、自ユニットの関数を呼び出すことが出来ないのでダメージ計算をどうすればよいか分かりませんでした。

    そのため正確には
    「敵ユニットをクリックしたとき、自ユニットの関数を呼び出すにはどうすればよいか」
    でした。

    自己解決として、攻撃範囲にいる敵ユニットを配列に入れ、「GameMnagerのclickobjectに配列に入っている敵ユニットが代入された場合Debug.Logで確認する」ということをUpdate関数で行いました。

    ご返事していただきありがとうございます。

    キャンセル

回答 1

checkベストアンサー

0

「質問への追記・修正の依頼」の内容を踏まえての回答です。

「自ユニットのCursol_1関数を呼び出し移動完了」のタイミングでGame_Managerに既に用意してある変数のprivate Test_player_tile test;へその選択していた自キャラのクラスを渡して敵キャラ選択後はそれを参照すれば良いかと思います。

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2019/09/22 17:00

    ありがとうございます!

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 88.93%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る

  • トップ
  • C#に関する質問
  • Unity:戦略シミュレーションゲームで、攻撃範囲にいる敵を検索→攻撃対象選択→攻撃を実行したい