How to create 2D map in unity using single image? - c#

I have to create 2D map in unity using single image. So, i have one .png file with 5 different pieces out of which I have to create a map & i am not allowed to crop the image. So, how do create this map using only one image.
I am bit new to unity, i tried searching but didn't find exactly what i am looking for. Also tried, tilemap using Pallet but couldn't figure out how to extract only one portion of the image.

You can create various Sprites from the given texture on the fly in code.
You can define which part of a given Texture2D shall be used for the Sprite using Sprite.Create providing the rect in pixel coordinates of the given image. Remember however that in unity texture coordinates start bottom left.
Example use the given pixel coordinate snippet of a texture for the attached UI.Image component:
[RequireComponent(typeof(Image))]
public class Example : MonoBehaviour
{
// your texture e.g. from a public field via the inspector
public Texture2D texture;
// define which pixel coordinates to use for this sprite also via the inspector
public Rect pixelCoordinates;
private void Start()
{
var newSprite = Sprite.Create(texture, pixelCoordinates, Vector2.one / 2f);
GetComponent<Image>().sprite = newSprite;
}
// called everytime something is changed in the Inspector
private void OnValidate()
{
if (!texture)
{
pixelCoordinates = new Rect();
return;
}
// reset to valid rect values
pixelCoordinates.x = Mathf.Clamp(pixelCoordinates.x, 0, texture.width);
pixelCoordinates.y = Mathf.Clamp(pixelCoordinates.y, 0, texture.height);
pixelCoordinates.width = Mathf.Clamp(pixelCoordinates.width, 0, pixelCoordinates.x + texture.width);
pixelCoordinates.height = Mathf.Clamp(pixelCoordinates.height, 0, pixelCoordinates.y + texture.height);
}
}
Or you get make a kind of manager class for generating all needed sprites once e.g. in a list like
public class Example : MonoBehaviour
{
// your texture e.g. from a public field via the inspector
public Texture2D texture;
// define which pixel coordinates to use for this sprite also via the inspector
public List<Rect> pixelCoordinates = new List<Rect>();
// OUTPUT
public List<Sprite> resultSprites = new List<Sprite>();
private void Start()
{
foreach(var coordinates in pixelCoordinates)
{
var newSprite = Sprite.Create(texture, coordinates, Vector2.one / 2f);
resultSprites.Add(newSprite);
}
}
// called everytime something is changed in the Inspector
private void OnValidate()
{
if (!texture)
{
for(var i = 0; i < pixelCoordinates.Count; i++)
{
pixelCoordinates[i] = new Rect();
}
return;
}
for (var i = 0; i < pixelCoordinates.Count; i++)
{
// reset to valid rect values
var rect = pixelCoordinates[i];
rect.x = Mathf.Clamp(pixelCoordinates[i].x, 0, texture.width);
rect.y = Mathf.Clamp(pixelCoordinates[i].y, 0, texture.height);
rect.width = Mathf.Clamp(pixelCoordinates[i].width, 0, pixelCoordinates[i].x + texture.width);
rect.height = Mathf.Clamp(pixelCoordinates[i].height, 0, pixelCoordinates[i].y + texture.height);
pixelCoordinates[i] = rect;
}
}
}
Example:
I have 4 Image instances and configured them so the pixelCoordinates are:
imageBottomLeft: X=0, Y=0, W=100, H=100
imageTopLeft: X=0, Y=100, W=100, H=100
imageBottomRight: X=100, Y=0, W=100, H=100
imageTopRight: X=100, Y=100, W=100, H=100
The texture I used is 386 x 395 so I'm not using all of it here (just added the frames the Sprites are going to use)
so when hitting Play the following sprites are created:

Related

Texture2D to get Rect Transform properties of the Image

If any of you had dealt with the same problem could you please tell me the solution.
User can upload his own image from phone gallery to the UI Image, then he can move it, scale it, rotate it, mirror it. After such manipulations he can save the Texture2D of this Image to the persistentDataPath with the following code. But the problem is that no matter which rotation, position or scale properties the UI Image has, Texture2D will still remain default which is 0pos, 0rotation and scale 1 (which actually has logic cause the texture is the same as I only changed the rect transform of the image.
public void SaveClick()
{
CropSprite();
SaveSprite();
}
private Texture2D output;
public void CropSprite()
{
Texture2D MaskTexture = MaskImage.sprite.texture;
//for this part MaskImage is the parent of the Image which is used to actually mask Image with which user is manipulating edits
//attached the image for better understanding what is mask and what is editable area
Texture2D originalTextureTexture = TextureMarble.sprite.texture;
Texture2D TextureTexture = Resize(originalTextureTexture,250,250);
//I rescale editable texture to the size of the mask one, otherwise big size images will be saved incorrectly
output = new Texture2D(TextureTexture.width,TextureTexture.height);
for (int i = 0; i < TextureTexture.width; i++)
{
for (int j = 0; j < TextureTexture.height; j++)
{
if (MaskTexture.GetPixel(i, j).a != 0)
output.SetPixel(i, j, TextureTexture.GetPixel(i, j));
else
output.SetPixel(i, j, new Color(1f, 1f, 1f, 0f));
}
}
//save only the part of editable texture which is overlapping mask image
output.Apply();
}
Texture2D Resize(Texture2D texture2D,int targetX,int targetY)
{
RenderTexture rt=new RenderTexture(targetX, targetY,24);
RenderTexture.active = rt;
Graphics.Blit(texture2D,rt);
Texture2D result=new Texture2D(targetX,targetY);
result.ReadPixels(new Rect(0,0,targetX,targetY),0,0);
result.Apply();
return result;
}
public void SaveSprite()
{
byte[] bytesToSave = output.EncodeToPNG();
File.WriteAllBytes(Application.persistentDataPath + "/yourTexture1.png",bytesToSave);
}
not necessary but for those of you who didn't understand what is mask in my case
So how to save Texture2D with the rect transform properties of the Image?

LoadRawTextureData() not enough data provided error in Unity

I am working on a project using ARcore.
I need a real world screen that is visible on the ARcore camera, formerly using the method of erasing UI and capturing.
But it was so slow that I found Frame.CameraImage.Texture in Arcore API
It worked normally in a Unity Editor environment.
But if you build it on your phone and check it out, Texture is null.
Texture2D snap = (Texture2D)Frame.CameraImage.Texture;
What is the reason? maybe CPU problem?
and I tried to do a different function.
public class TestFrameCamera : MonoBehaviour
{
private Texture2D _texture;
private TextureFormat _format = TextureFormat.RGBA32;
// Use this for initialization
void Start()
{
_texture = new Texture2D(Screen.width, Screen.height, _format, false, false);
}
// Update is called once per frame
void Update()
{
using (var image = Frame.CameraImage.AcquireCameraImageBytes())
{
if (!image.IsAvailable) return;
int size = image.Width * image.Height;
byte[] yBuff = new byte[size];
System.Runtime.InteropServices.Marshal.Copy(image.Y, yBuff, 0, size);
_texture.LoadRawTextureData(yBuff);
_texture.Apply();
this.GetComponent<RawImage>().texture = _texture;
}
}
}
But if I change the texture format, it will come out.
private TextureFormat _format = TextureFormat.R8;
it is work, but i don't want to red color image, i want to rgb color
what i should do?
R8 Just red data.
You can use TextureFormat.RGBA32, and set buffer like this:
IntPtr _buff = Marshal.AllocHGlobal(width * height*4);

2D avatar portrait images based on 3D model in unity

Is it possible to generate 2D avatar portrait pictures(.png) of 3D characters/objects in unity, and would it be advisable.
During my game, I want to dynamically generate and show a list of characters/objects in a scrollbar UI component, and i'm too lazy to actually go make these 2D images manually.
I want to know if it is possible to generate a list of character/object portraits from a set of 3D prefabs in to display, or if it would be more advisable to rather manually generate pictures and add the pictures to the as assets.
Apart from being lazy, this will then also be a lot easier to add characters/objects to my project and to maintain them if they are changed.
You can use a script like this to take a pic of the scene. So you could instantiate somewhere the gameobject, with a specific orientation, background, illumination, distance to the camera... Then you take the screenshot and store it somewhere with your other assets.
using UnityEngine;
using System.Collections;
public class HiResScreenShots : MonoBehaviour {
public int resWidth = 2550;
public int resHeight = 3300;
private bool takeHiResShot = false;
public static string ScreenShotName(int width, int height) {
return string.Format("{0}/screenshots/screen_{1}x{2}_{3}.png",
Application.dataPath,
width, height,
System.DateTime.Now.ToString("yyyy-MM-dd_HH-mm-ss"));
}
public void TakeHiResShot() {
takeHiResShot = true;
}
void LateUpdate() {
takeHiResShot |= Input.GetKeyDown("k");
if (takeHiResShot) {
RenderTexture rt = new RenderTexture(resWidth, resHeight, 24);
camera.targetTexture = rt;
Texture2D screenShot = new Texture2D(resWidth, resHeight, TextureFormat.RGB24, false);
camera.Render();
RenderTexture.active = rt;
screenShot.ReadPixels(new Rect(0, 0, resWidth, resHeight), 0, 0);
camera.targetTexture = null;
RenderTexture.active = null; // JC: added to avoid errors
Destroy(rt);
byte[] bytes = screenShot.EncodeToPNG();
string filename = ScreenShotName(resWidth, resHeight);
System.IO.File.WriteAllBytes(filename, bytes);
Debug.Log(string.Format("Took screenshot to: {0}", filename));
takeHiResShot = false;
}
}
}

How to change pixels per unit for sprite after importing with WWW in unity?

I am currently making a level editor where the user imports tiles from a file, and it currently works, except for the fact that I want the pixels per unit for each imported sprite to change to 32
Here is my code:
//Get tiles from file
StreamReader reader = new StreamReader(Application.dataPath + "/../Maps/" + mapName + "/Tiles/tiles.txt");
string line = reader.ReadLine ();
while (!string.IsNullOrEmpty (line)) {
string[] param = line.Split (',');
foreach (TileTexture t in tileTextures) {
if (t.name == param [0]) {
Sprite sprite = Sprite.Create (t.texture, new Rect (0, 0, t.texture.width, t.texture.height), new Vector2 (0, 0));
sprite.pixelsPerUnit = 32;//THIS LINE DOESNT WORK, GIVES READONLY ERROR
Tile tile = new Tile (param[0], sprite, new Vector2(float.Parse(param[1]), float.Parse(param[2])));
tile.sprite.texture.filterMode = FilterMode.Point;
tiles.Add (tile);
}
}
line = reader.ReadLine ();
}
Looking at the function Sprite.Create() we see that the function signature is
public static Sprite Create(Texture2D texture,
Rect rect,
Vector2 pivot,
float pixelsPerUnit = 100.0f,
uint extrude = 0,
SpriteMeshType meshType = SpriteMeshType.Tight,
Vector4 border = Vector4.zero);
We see that we can pass the pixelsPerUnit as an optional parameter into the function. You can only do this here, and you cannot change it later, because, as you have found out, the field pixelsPerUnit is readonly field (meaning it cannot be changed). So, you just need to pass in your 32f here. Correct code would be
if (t.name == param [0]) {
Sprite sprite = Sprite.Create (t.texture, new Rect (0, 0, t.texture.width, t.texture.height), new Vector2 (0, 0), 32f);
Tile tile = new Tile (param[0], sprite, new Vector2(float.Parse(param[1]), float.Parse(param[2])));
tile.sprite.texture.filterMode = FilterMode.Point;
tiles.Add (tile);
}

XNA C# Destructible Terrain

I am currently working on a game in which players can destruct the terrain. Unfortunately, I am getting this exception after using the SetData method on my terrain texture:
You may not call SetData on a resource while it is actively set on the
GraphicsDevice. Unset it from the device before calling SetData.
Now, before anyone says that there are other topics on this problem, I have looked at all of those. They all say to make sure not to call the method within Draw(), but I only use it in Update() anyways. Here is the code I am currently using to destruct the terrain:
public class Terrain
{
private Texture2D Image;
public Rectangle Bounds { get; protected set; }
public Terrain(ContentManager Content)
{
Image = Content.Load<Texture2D>("Terrain");
Bounds = new Rectangle(0, 400, Image.Width, Image.Height);
}
public void Draw(SpriteBatch spriteBatch)
{
spriteBatch.Draw(Image, Bounds, Color.White);
}
public void Update()
{
if (Globals.newState.LeftButton == ButtonState.Pressed)
{
Point mousePosition = new Point(Globals.newState.X, Globals.newState.Y);
if(Bounds.Contains(mousePosition))
{
Color[] imageData = new Color[Image.Width * Image.Height];
Image.GetData(imageData);
for (int i = 0; i < imageData.Length; i++)
{
if (Vector2.Distance(new Vector2(mousePosition.X, mousePosition.Y), GetPositionOfTextureData(i, imageData)) < 20)
{
imageData[i] = Color.Transparent;
}
}
Image.SetData(imageData);
}
}
}
private Vector2 GetPositionOfTextureData(int index, Color[] colorData)
{
float x = 0;
float y = 0;
x = index % 800;
y = (index - x) / 800;
return new Vector2(x + Bounds.X, y + Bounds.Y);
}
}
}
Whenever the mouse clicks on the terrain, I want to change all pixels in the image within a 20 pixel radius to become transparent. All GetPositionOfTextureData() does is return a Vector2 containing the position of a pixel within the texture data.
All help would be greatly appreciated.
You must unbind your texture from the GraphicsDevice by calling:
graphicsDevice.Textures[0] = null;
before trying to write to it by SetData.

Categories

Resources