簡體   English   中英

Unity 中的基於網格/平鋪移動 + 碰撞?

[英]Grid-based/Tile Movement + Collisions in Unity?

在弄清楚如何進行基於網格的運動或基於圖塊的運動時遇到了一個巨大的問題。 有點類似於 Nitrome 的 Redungeon:無法真正發布圖片:所以這是一個 gif。 http://www.eneminds.com/redungeon/img/gifs/gif_1.gif

我想我應該創建一個網格系統。 我認為這很簡單,就像舊游戲(口袋妖怪等)一樣。但不知道該怎么做。 但我也希望動作快。

Unity擁有自己的tilemap實現,應該可以讓您以背景為基礎構建背景: https ://docs.unity3d.com/Manual/Tilemap.html

此外,Unity提供了更多2d內容來幫助您在此處構建內容: https : //github.com/Unity-Technologies/2d-extras

在此處找到的許多教程中概述了沖突: https : //unity3d.com/learn/tutorials/s/2d-game-creation

要制作像GIF動畫那樣的游戲並不容易 如果您是游戲開發者的新手,那么尤其是這樣,不要指望簡單的解決方案。

您可能想查看Unity資產商店,以快速獲得基於圖塊的移動的骯臟方式,但這將一如既往地附帶價格,並且無濟於事。 https://assetstore.unity.com/

關於移動速度,這始終只是游戲中的變量,可以根據自己的喜好進行調整。 在基於圖塊的游戲中,它對應於角色在視覺上從一個圖塊轉移到另一個圖塊所花費的時間。 嘗試閱讀Lerping,它是Unity引擎的一部分。 https://docs.unity3d.com/ScriptReference/Vector3.Lerp.html

我能夠完成。 我剛剛從Unity學習部分的RogueLike教程中修改了輸入內容。

所以這是負責運動的代碼

    void Move(string direction_string)
    {
        ChangeDirection(direction_string);

        Vector2 start = transform.position;
        Vector2 end = start + direction;

        boxCollider.enabled = false;
        hit = Physics2D.Linecast(start, end, blockingLayer);
        boxCollider.enabled = true;

        if (hit.transform == null) {
            StartCoroutine(Movement(end));
            animator.SetTrigger(direction_string);
            return;
        } else {
            moveSequence.RemoveAt(0);
            animator.SetTrigger(direction_string);
            return;
        }
    }

    void ChangeDirection(string direction_string)
    {
        switch (direction_string) {
            case "up":
                direction = dir_Up;
                break;
            case "down":
                direction = dir_Down;
                break;
            case "left":
                direction = dir_Left;
                break;
            case "right":
                direction = dir_Right;
                break;
        }
    }

    IEnumerator Movement(Vector3 end)
    {
        moving = true;
        float sqrRemainingDistance = (transform.position - end).sqrMagnitude;

        while (sqrRemainingDistance > float.Epsilon) {
            Vector3 newPosition = Vector3.MoveTowards(rb2D.position, end, moveSpeed * Time.deltaTime);
            rb2D.MovePosition(newPosition);
            sqrRemainingDistance = (transform.position - end).sqrMagnitude;
            yield return null;
        }

        currentPos = end;
        moveSequence.RemoveAt(0);
        moving = false;
    }
}

這是負責輸入的內容


    void FixedUpdate ()
    {
        if (moveSequence.Count > 0 && !moving) {
            Move(moveSequence[0]);
        }
    }

然后將其連接到一個Update()函數,該函數偵聽按鈕的按下並將一個列表項添加到moveSequence List中,例如

moveSequence.Add("up");

剛剛為 reddit 上的某個人做了一個這樣的代碼,來這里看看之前是否有人問過它。 我知道我遲到了 2 年,但如果有人需要它,它就在這里。

    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
     
    public class GameController : MonoBehaviour
    {
     
        // a script created so that a player always moves one direction at a time on a grid.
        // It uses a plane with even width and height to make a grid
        //     - if needed, turn off the mesh renderer so that you dont see the tiled grid.
     
     
     
     
        // the game object we use to create a grid. Should be a plane with an even width and height.
        public  GameObject tile_object;
     
        // grid x and y sizes, set them to odd numbers
        public float x_grid_size, y_grid_size;
     
        // List of all our floor tiles
        Dictionary<(float x, float y), GameObject> floor_list = new Dictionary<(float x, float y), GameObject>();
     
        // Reference to the player prefab
        public GameObject player;
     
        // reference to player character
        private GameObject player_character;
     
        // a tool used for debugging
        bool debugging = true;
     
        //check if player is moving
        bool player_is_moving = false;
     
        (float x, float y) players_current_tile;
     
        // players speed
        public float player_speed = 35f;
     
        // used in calculating movements
        (float x, float y) to_tile;
     
        //used to calculate movement
        Vector3 to_pos;
     
     
        // Start is called before the first frame update
        void Start()
        {
            // put the player into the scene
           player_character = Instantiate(player, Vector3.zero, player.transform.rotation);
     
            // Sets the Middle Tile and checks grid is odd
            SetMiddleTile();
     
            // create a floor grid to help us visualize our play field.
            CreateGrid();
     
        }
     
        // Update is called once per frame
        void Update()
        {
            PlayerMovement();
            MovePlayer();
        }
     
        // gets inputs on A S W D keys for movement
        void PlayerMovement() {
            if (Input.GetKeyDown(KeyCode.W)){
                PlayerInput((0, 1));
            }
            if (Input.GetKeyDown(KeyCode.A))
            {
                PlayerInput((-1, 0));
            }
            if (Input.GetKeyDown(KeyCode.S))
            {
                PlayerInput((0, -1));
            }
            if (Input.GetKeyDown(KeyCode.D))
            {
                PlayerInput((1, 0));
            }
        }
     
     
        // simplifies player entries, and gets input directional data
        void PlayerInput((float x, float y) input)
        {
            if (!player_is_moving)
            {
                (float x, float y) to_tile_check = (players_current_tile.x + input.x, players_current_tile.y + input.y);
                if (floor_list[to_tile_check] != null)
                {
                    player_is_moving = true;
     
                    to_tile = (players_current_tile.x + input.x, players_current_tile.y + input.y);
                    to_pos = floor_list[to_tile].transform.position;
                }
            }
     
        }
     
       // used to move the player
        void MovePlayer()
        {
     
            if (player_is_moving)
            {
                player_character.transform.position = Vector3.MoveTowards(player_character.transform.position, to_pos, Time.deltaTime * player_speed);
     
                if (player_character.transform.position == to_pos)
                {
                    players_current_tile = to_tile;
                    player_is_moving = false;
                }
            }
        }
     
        // used to create the floor grid
        void CreateGrid()
        {
            // Create an empty to hold our floor grid
            GameObject grid_empty = new GameObject();
            grid_empty.name = "grid_floor";
     
            // get the size of our floor tile so we know how far to space them.
            float tile_size = tile_object.GetComponent<MeshRenderer>().bounds.size.x;
     
            // create an offset so the grid is always centered in game view
            Vector3 offSet = new Vector3((x_grid_size * tile_size) / 2 - (tile_size / 2), 0, (y_grid_size * tile_size)/2 - (tile_size / 2));
     
            // iterate to create tiles on x axis
            for (int x = 0; x < x_grid_size; x++)
            {
                // iterate to create tiles on y axis
                for (int y = 0; y < y_grid_size; y++)
                {
                    // instantiate new tile
                    GameObject floor_tile = Instantiate(tile_object, (new Vector3(x * tile_size, 0, y * tile_size) - offSet), tile_object.transform.rotation);
                    floor_tile.name = "flr_x: " + (x  + 1) + " y:" + (y + 1);
     
                    // set the parent to grid empty so the scene isnt filled with objects and all floor tiles are neatly centerd
                    floor_tile.transform.parent = grid_empty.transform;
     
                    // add the tile to our dictionary.
                    floor_list.Add(((x + 1),(y + 1)), floor_tile);
                }
            }
            if (debugging) { print("Created Floors: " + (x_grid_size * y_grid_size) + " Floor List Size: " + floor_list.Count);}
        }
     
        // sets the middle tile the player is spawned on, also checks to make sure grid size is set correctly
       void SetMiddleTile()
        {
            // these check to make sure grid size isnt 0 and are odd
            if (x_grid_size == 0 && y_grid_size == 0) { print("Forgot to set grid size! setting default to 7x and 7y"); x_grid_size = 7; y_grid_size = 7; }
            if (x_grid_size % 2 == 0) { print("x_grid_size is set to an even number(" + x_grid_size + "), changing it to odd(" + (x_grid_size + 1) + ")"); x_grid_size += 1; }
            if (y_grid_size % 2 == 0) { print("y_grid_size is set to an even number(" + y_grid_size + "), changing it to odd(" + (y_grid_size + 1) + ")"); y_grid_size += 1; }
     
            // splits the grid and half
            float x = x_grid_size / 2 + 0.5f;
            float y = y_grid_size / 2 + 0.5f;
     
            // set the players current tile to middle tile
            players_current_tile = (x, y);
     
            // set the to tile to current tile to avoid null instances when first checking our dictionary
            to_tile = players_current_tile;
     
            // used for debugging
            if (debugging) { print("the middle tile is: x(" + x + ")" + " y(" + y + ")"); }
        }
    }
         

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM