Wayback Machinekoobas.hobune.stream
May JUN Jul
Previous capture 13 Next capture
2021 2022 2023
1 capture
13 Jun 22 - 13 Jun 22
sparklines
Close Help
  • Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
  • Asset Store
  • Get Unity

UNITY ACCOUNT

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account
  • Blog
  • Forums
  • Answers
  • Evangelists
  • User Groups
  • Beta Program
  • Advisory Panel

Navigation

  • Home
  • Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
    • Blog
    • Forums
    • Answers
    • Evangelists
    • User Groups
    • Beta Program
    • Advisory Panel

Unity account

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account

Language

  • Chinese
  • Spanish
  • Japanese
  • Korean
  • Portuguese
  • Ask a question
  • Spaces
    • Default
    • Help Room
    • META
    • Moderators
    • Topics
    • Questions
    • Users
    • Badges
  • Home /
avatar image
4
Question by Oskar · Sep 26, 2010 at 04:44 PM · 2dterraingridmap

What is the best way to make modular (selectable squares) terrain?

I'm looking for best way to make Dungeon Keeper style terrain (or better map, I don't want to use Unity terrain editor). For those who don't know this old great game:

  • Whole map should be made from squares - ground, earth, rock, water, lava, etc.
  • Every square should be selectable by player.
  • There should be squares which can't be changed by player - rock, water, etc.
  • Player can dig through earth (destroy it and and place ground there instead).
  • On the ground player can build something (traps, buildings, etc).

I'm looking for best way to script it and a nice way to build such maps after scripting.

Regards,
Oskar

PS I'm new to Unity. I know some programming in C/C++/Obj-C and I'm not afraid of complicated answers but please provide some links to the documentation which I should read if your answer is very complicated.

Comment
Add comment · Show 3
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image · Sep 27, 2010 at 07:06 AM 0
Share

This is a monster of a question. I'm slowly working my way through a decent answer, but it's not something where a single link will solve everything. Also, as I never played Dungeon $$anonymous$$eeper, I've spent a good deal of time watching Youtube videos to understand what you need, heh.

avatar image · Sep 27, 2010 at 08:18 AM 0
Share

A monster of an answer to go with. Now, fingers crossed that you make a return visit. ;)

avatar image downward · Sep 07, 2011 at 09:46 PM 0
Share

Anyone willing to show the project for this first part of the answer that actually generates the board. I'm having a hard time getting it to work. I'm new to Unity3d and still learning everything.

Or if not i have some specific issues im running into i can elaborate.

THAN$$anonymous$$S!

2 Replies

· Add your reply
  • Sort: 
avatar image
22
Best Answer

Answer by · Sep 27, 2010 at 08:18 AM

I recently whipped up a 2D grid game. I believe that "the best way" is fairly subjective when it comes to project design, but this approach worked well enough for me. I've assumed you know very little about Unity, but linking the manual/documentation/scripting-reference where possible, and you can hopefully fill in the gaps.

General concepts

For my game, I worked under the premise that every tile (square) is a separate GameObject.
Working backwards from that decision, every tile type (ground, earth, rock, water, lava, etc.) was its own prefab. Keeping each tile as a separate prefab allows you to quickly change types (even at runtime), and assign different properties via different components on each tile prefab. You can also add and remove components at runtime, so your buildings and traps could be components that are created/destroyed on gameobjects. I've also assumed that you'll use a top-down (rotated 90 degrees on the X axis) orthographic camera.

Specific implementation

To start, you'll need a grid to play around with. I wrote a quick script to build me a 20x20 board of tiles, but you can modify it as necessary.

using UnityEngine;
using System.Collections;

public class GenerateTiles : MonoBehaviour {

   public int board_size_x_;
   public int board_size_z_;
   public Transform tile_prefab_;

   // Use this for initialization
   void Start () {
      GameObject board = new GameObject();
      board.name = "Board";
      for ( int x = 0; x < board_size_x_; x++ ) {
         for ( int z = 0; z < board_size_z_; z++ ) {
            Transform tile = (Transform)Instantiate(tile_prefab_,new Vector3(x,0,z),Quaternion.identity);
            tile.name = "Tile" + x + z;
            tile.parent = board.transform;
         }
      }
   }
}

Add the script to an empty GameObject, hook up the appropriate base tile prefab, set the x and z dimension variables, and run the game (click Play) - your board will be created. Then, while the game is still running, create a new prefab in your Project window, and drag the 'Board' object down to it. Then, stop running the game (click Play again). Drag the prefab from your Project window back up to the Hierarchy and you have yourself a board! With this approach, any changes you make to your base prefabs will echo through to the instances in your Hierarchy.

You can read up on the documentation for Transform and Instantiate on the Scripting Reference. One other thing to note is that C# scripts must have the same name as the class contained within. i.e. the script should be named GenerateTiles.cs

Manually changing over prefabs in your map will be exhausting, so you'll want a way to change which tiles are in your map; i.e. a level editor of some sort. Create some other tile prefabs. For now, you might like to set their colour so you can easily differentiate between them. The quick way to do this is create a new material. On this, you can manually specify the Main Color with the color picker tool in the Inspector properties for the material. Personally, I group similar assets in folders, so the following script assumes that your tile prefabs are in Assets/Prefabs/Tiles/. It's also in javascript, and not the cleanest of code - I just wanted a quick-and-dirty level editor tool. Please also note that I am by no means an expert Unity user - I pieced this together by reading the 'Extending the Editor' page in the manual.

enum TileType { Blank, Ground, Earth, Rock, Water, Lava }

class TileEditor extends EditorWindow
{
   var selectedType : TileType = TileType.Blank;
   var selectedTile : GameObject;
   var passiveSelect : boolean = true;
   var tilePrefab : Object;

   @MenuItem ("Window/TileEditor")
   static function Init ()
   {
      var window : TileEditor = EditorWindow.GetWindow (TileEditor);
      window.Show();
   }

   function OnSelectionChange ()
   {
      Repaint();

      if ( passiveSelect == false )
         ChangeTile();
   }

   function OnGUI ()
   {      
      GUILayout.Label ("Selected tile: " + (Selection.activeGameObject != null ? Selection.activeGameObject.name : "None"), EditorStyles.boldLabel);
      GUILayout.Label ("Type to apply:", EditorStyles.boldLabel);
      selectedType = EditorGUILayout.EnumPopup(selectedType);

      passiveSelect = EditorGUILayout.BeginToggleGroup ("Manually Apply", passiveSelect);
         if (GUI.Button (Rect(10,85,60,20), "Apply"))
            ChangeTile();
      EditorGUILayout.EndToggleGroup ();           
   }

   function ChangeTile ()
   {
      selectedTile = Selection.activeGameObject;

      if ( selectedTile == null )
         return;

      if ( selectedTile.layer != LayerMask.NameToLayer("Tile") )
         return;

      switch ( selectedType )
      {
         case selectedType.Blank:
            tilePrefab = Resources.LoadAssetAtPath("Assets/Prefabs/Tiles/Blank.prefab", Object);
            break;
         case selectedType.Ground:
            tilePrefab = Resources.LoadAssetAtPath("Assets/Prefabs/Tiles/Ground.prefab", Object);
            break;
         case selectedType.Earth:
            tilePrefab = Resources.LoadAssetAtPath ("Assets/Prefabs/Tiles/Earth.prefab", Object);
            break;
         case selectedType.Rock:
            tilePrefab = Resources.LoadAssetAtPath ("Assets/Prefabs/Tiles/Rock.prefab", Object);
            break;
         case selectedType.Water:
            tilePrefab = Resources.LoadAssetAtPath ("Assets/Prefabs/Tiles/Water.prefab", Object);
            break;
         case selectedType.Lava:
            tilePrefab = Resources.LoadAssetAtPath ("Assets/Prefabs/Tiles/Lava.prefab", Object);
            break;
      }

      if ( !tilePrefab )
         return;

      var newTile : GameObject = EditorUtility.InstantiatePrefab(tilePrefab) as GameObject;
      newTile.transform.position = selectedTile.transform.position;
      newTile.transform.parent = selectedTile.transform.parent;
      Selection.activeGameObject = newTile;
      DestroyImmediate(selectedTile);
      tilePrefab = null;
   }
}

The editor script assumes you have tile prefabs named the following: Blank, Ground, Earth, Rock, Water, Lava. It will probably throw you an error if you use it without having those tiles, but you can edit as necessary. You'll need to create a new Javascript object in your Project view, inside a folder named "Editor" (or it won't work). Then, in your Window menu (at the top), you should have a new entry: TileEditor. Clicking that will bring up your new tile editor. In the Scene view, you should now be able to select a tile, and apply a new type to it (from the dropdown menu in the Tile Editor tool). You will also need to create a user layer called "Tile", and specify the tiles as belonging to this layer (I used User Layer 8). As I said, this was rushed together as something of a prototype, so I'm sure the code could be neater/nicer, but it works. For any of the functions you're unfamiliar with, I'd suggest searching for them on the script reference.

Now you have a board, and a means to edit it, you can move onto the player perspective. You could use the built-in OnMouseEnter and OnMouseExit MonoBehaviours, which are called every frame while the mouse is over the Collider (on each tile / unit). You could enable and disable a gameObject or GUI element over the tile from these events.

In my implementation (C#), I used a Raycast for tile selection. I also specified a LayerMask so the Raycast only hit tiles.

   GameObject SelectTile ()
   {
      RaycastHit hit = new RaycastHit();
      Ray ray = Camera.main.ScreenPointToRay (Input.mousePosition);
      LayerMask layerMask = 1 << 8;
      if (Physics.Raycast (ray, out hit, 100.0f, layerMask))
      {
      // print(hit.collider.gameObject.name);
         return(hit.collider.gameObject);
      }
      return null;
   }

However, you could also use a combination of OnMouseOver and GetMouseButtonDown.

Further reading

While working on this prototype, I asked a question on 'finding adjacent tiles in a grid', which I imagine will come in handy when you get to creating some sort of pathfinding logic (as you'll need to know which tiles are adjacent).

You'll also find plenty of other answers about adding components, which you can use to create traps and buildings on a specific tile.

Summary

This is mostly a broad overview, giving specific details where possible. Hopefully it'll give you a good start on your project. In future, I'd encourage you to ask smaller, more specific questions, as the answers will generally be a lot easier to digest. Welcome to UnityAnswers!

P.S. Please forgive any typos - I have the flu and a splitting headache to go with!

Comment
Add comment · Show 14 · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image Oskar · Sep 27, 2010 at 12:54 PM 0
Share

I've made a return visit and this is a great answer! Before reading your post $$anonymous$$arowi I didn't even know where to start reading documentation (first page? :P) and what questions to ask. This is definitively very good knowledge base to start and tomorrow at free time I will.

Thanks again, Oskar

avatar image · Sep 27, 2010 at 01:25 PM 0
Share

No troubles. I'll check back here, so be sure to comment if you have any specific questions about things I've mentioned. Also (if you haven't already done so), remember to vote up answers that help you, and (once you know that it has), mark questions as 'correct' if they solve your problem. Cheers :)

avatar image sebastian · Oct 05, 2010 at 09:46 PM 0
Share

Wow this is indeed a very detailed and useful answer. Thank you.

avatar image e-bonneville · Oct 06, 2010 at 06:18 PM 0
Share

Very nice! I can't wait to implement it.

avatar image e-bonneville · Oct 06, 2010 at 08:38 PM 0
Share

Okay, so I gave your editor code a shot. Unfortunately, it didn't work. I put the tiles in the right folder, but nothing happened when I hit "Apply." Can you think of any reasons? Thanks - Elliot

Show more comments
avatar image
0

Answer by downward · Sep 07, 2011 at 09:57 PM

Will someone be willing to show me a screenshot of their project layout and script variable assignments who were able to get this to work?

When i create a prefab tile object from a generic cube should i name the object i drop into the prefab container the same as the prefab container name?

 using UnityEngine;
 using System.Collections;
 
 public class GenerateTiles : MonoBehaviour {
 
    public int board_size_x_;  //For a 10 by 10 grid should i add "= 10" ?
 
    public int board_size_z_;  //should i add  "= somenumber" here?
 
    public Transform tile_prefab_; // <-- do i need to assign this?
 
    Use this for initialization
    void Start () {
 
       GameObject board = new GameObject();
       board.name = "Board";
     
       for ( int x = 0; x < board_size_x_; x++ ) {
          for ( int z = 0; z < board_size_z_; z++ ) {
     
             Transform tile = (Transform)Instantiate(tile_prefab_,new Vector3(x,0,z),Quaternion.identity);
             tile.name = "Tile" + x + z;
             tile.parent = board.transform;
          }
       }
    }
 }
Comment
Add comment · Show 1 · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image Outlaw Lemur · Sep 01, 2012 at 03:41 PM 0
Share

Ask a new question ins$$anonymous$$d of using this as an answer

Your answer

Hint: You can notify a user about this post by typing @username

Up to 2 attachments (including images) can be used with a maximum of 524.3 kB each and 1.0 MB total.

Follow this Question

Answers Answers and Comments

3 People are following this question.

avatar image avatar image avatar image

Related Questions

The name 'Joystick' does not denote a valid type ('not found') 2 Answers

Modifying Terrain Splat Texture at Runtime 2 Answers

Infinite 2D placement grid 1 Answer

Adding map through script 0 Answers

2D Game Visual Grid to Place Objects 2 Answers


Enterprise
Social Q&A

Social
Subscribe on YouTube social-youtube Follow on LinkedIn social-linkedin Follow on Twitter social-twitter Follow on Facebook social-facebook Follow on Instagram social-instagram

Footer

  • Purchase
    • Products
    • Subscription
    • Asset Store
    • Unity Gear
    • Resellers
  • Education
    • Students
    • Educators
    • Certification
    • Learn
    • Center of Excellence
  • Download
    • Unity
    • Beta Program
  • Unity Labs
    • Labs
    • Publications
  • Resources
    • Learn platform
    • Community
    • Documentation
    • Unity QA
    • FAQ
    • Services Status
    • Connect
  • About Unity
    • About Us
    • Blog
    • Events
    • Careers
    • Contact
    • Press
    • Partners
    • Affiliates
    • Security
Copyright © 2020 Unity Technologies
  • Legal
  • Privacy Policy
  • Cookies
  • Do Not Sell My Personal Information
  • Cookies Settings
"Unity", Unity logos, and other Unity trademarks are trademarks or registered trademarks of Unity Technologies or its affiliates in the U.S. and elsewhere (more info here). Other names or brands are trademarks of their respective owners.
  • Anonymous
  • Sign in
  • Create
  • Ask a question
  • Spaces
  • Default
  • Help Room
  • META
  • Moderators
  • Explore
  • Topics
  • Questions
  • Users
  • Badges