0
\$\begingroup\$

Say I have an image of PNG or a bitmap with a line zigzagging through it. I have done quite a bit of research in the answer still eludes me to how to use an image in unity and have it generate Primitives IE cubes along a black line in the bitmap. If anyone could just point me in the right direction as far as the tutorial or information that will get me started that will be great.

Ok so take the image below. What I am attempting to do is where the black line is instantiate a cube. I pretty much have the code written but the 4 issues I am having is 1. Identifying if black is found in my Color[] variable 2. Getting the blocks to render on the black lines without overlapping 3. Not freeze when generating the blocks.

using System.Collections;
using System.Collections.Generic;

using UnityEngine;


public class MazeGeneratorV1 : MonoBehaviour {
public Texture2D img;
public GameObject wall;
public int unitWidth = 10;
public int unitHeight = 10;

// Use this for initialization
void Start () {
    Pixelreader();
}


private void Pixelreader()
{
    //img = (Texture2D)Resources.Load("test2.png");
    for(int w=0; w < img.width; w++)
    {
        for(int h=0; h < img.height; h++)
        {
            Color[] colors = img.GetPixels(w, h, 10, 10);
            print(colors);
            if (colors == Color.black)
            {
                print("wall");
                Instantiate(wall, new Vector3(w,0,h), Quaternion.Euler(0, 0, 0));

            }
        }
    }
  }
}

enter image description here

\$\endgroup\$
1
\$\begingroup\$

You are honestly almost there I gather from the source code you have in your question. What it appears to me that may account for things not showing up right is you are not including the size of the wall (prefab? Sorry I am not well versed in Unity). So when you set the position you will want it to be the h and w times the size of the prefab, otherwise you are just offsetting their position by the value of 1 for every given row/column.

For example, if you have 11 blocks in a row starting at 0,0 your second block is going to be at 1,0, then 2,0 and so on.. if your blocks are 10 units wide then it will not be until the 11th block that it would actually be outside of the first block placed down in the line and you actually want them to be placed down at 0,0 then 10,0 and 20,0 and so on so the blocks do not overlap.

You will also want to read this one pixel at a time I believe, right now the code looks like you are reading a 10x10 block instead of one at a time (assuming your image is 1x1 instead of 10x10 for the size of a block).

The code changes would be

Color[] colors = img.GetPixels(w, h, 1, 1);
if (colors[0] == Color.black)
{
    Instantiate(wall, new Vector3(w * wall.width, 0 ,h * wall.height), Quaternion.Euler(0, 0, 0));
}

This offsets the positions by the coordinates of the pixels in the image multiplied by the width and height of the wall object.

This should handle issues 1 and 2... 3 is going to be a bit harder because you are doing rather slow processing and creating -alot- of objects in this manner. For example if its a 128x128 image then you are doing a color check of 16384 pixels and generating possibly that many wall objects as a worst case scenario.

There are a few things you could try but Ill not be able to write the code for them or run them to see if they improve the situation. I will however explain how they can help.

1) Expand the size of the wall when you instantiate it to the size of all of the black pixels you read consecutively or until you reach the end of the row. You can calculate the size you would need by the default wall size and the number of pixels you read so you create one object that would take you from the top left corner to the opening near the middle and then the other side of the opening all the way to the top right corner. This could potentially reduce the number of wall objects you have to Instantiate(). You could also make this logic a bit more complicated and try to handle vertical lines as well.

2) Your maze seems to have a set size between two walls. You could read only the first pixel and see if its black then assume the next X amount must also be solid because it should either be a passable edge or a solid wall. This would then let you lower the amount of times you have to check the image and just increment your h and w by the amount of pixels that have to be set in order to give you a wall for that section or an opening. Of note, this optimization could also be done with suggestion 1.

3) You could break apart the creation of the blocks so you only do a certain number of them at a time. I believe a coroutine would be of use here as you can yield after reading a certain number of pixels or more likely after creating a certain number of wall objects. This will let other systems run for a frame or so and then return to generate more objects for you.

4) You could find a better format than using the image for laying out your maze. Right now the image is -mostly- empty space which means you are going to spend a lot of the time processing it to do nothing. You could do some pre-processing to take an image and just generate the coordinates that contain a block in them so you are only processing the black lines and use that data to Intantiate() the wall instances.

5) You can actually do all of the above suggestions at the same time. They are of all different levels of difficulty depending on your development situation and your time requirements but you could get a better data format to only contain the objects you need to create (update the new format to be the coordinates AND the height and width of the wall to create). You could scan from a solid point Horizontal OR Vertically until you reach the end of a row or column respectively to reduce the number of blocks you have to create.. And you can also do this in a coroutine to 'time slice' the processing across multiple update loops so as to not freeze your application, for too long in any case.

EDIT: 6) You could make specific prefabs for each 'section' of the maze. Each section has a combination of four walls, you could use that to your advantage and create your prefabs to have just the four corners but no blocking walls (a four way intersection), another one with a wall across the top and bottom (a horizontal hallway), another one with a wall on the left and right (a vertical hallway) and then ones for a left turn or a right turn (wall across the top and to the right but the bottom and left side open for example) and finally a set of dead ends coming in from one side (opening on the top but a wall on the left, right and bottom sides). The hard part here is identifying which of the prefab shapes you would need from the image. This is not overly difficult but does require checking I think at a minimum of four values per 'grid' such as (1,0) to see if the top wall is there (assuming each prefab will always have a column in each corner at the least). (0,1) would then get you the left wall. (GridSize, 1) would get you the left wall and (1,GridSize) would get you the bottom wall. As 5 states, this could also be incorporated with the other 4 options as needed to further optimize.

I hope this helps, you seem to be on the right track for the first two issues. I hope the 6 examples of how to speed it up/not lock up the application give some assistance in that area as well. I will admit it is a bit harder with out knowing more details, those are just general things you can try of increasing difficulty (in my opinion).

Note: I do not see a fourth issue actually listed in the question as of the writing of this answer.

\$\endgroup\$
  • \$\begingroup\$ That solved it! Thank you for the detailed response and guidance. It was a great help. As to problem 3 with Unity generation of items in the editor is going to slow it down when there are thousands of elements generated so that is just going to be what it is in development. Running the game its fine with over 90FPS so I will live with the editor issue. Thanks again you were and EPIC help. \$\endgroup\$ – The Gugaru Apr 6 '18 at 23:34

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.