How to make GUI Rect child of an object? - c#

I have this problem, that I draw a new Rect with a GUI: it only draws now on screen. What I want to do is to make this drawing a child of an object, so I can hide this with SetActive(false). This will be only available when players will pause and open Inventory. The game is 2D for Android.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Inventory : MonoBehaviour
{
public int SlotsX, SlotsY;
public GUISkin Skin;
public List<Item> inventory = new List<Item>();
public List<Item> slots = new List<Item>();
private ItemDatabase database;
void Start()
{
for (int i = 0; i < (SlotsX * SlotsY); i++)
{
slots.Add(new Item());
}
database = GameObject.FindGameObjectWithTag("Item Database").GetComponent<ItemDatabase>();
inventory.Add(database.Items[0]);
inventory.Add(database.Items[1]);
inventory.Add(database.Items[3]);
inventory.Add(database.Items[4]);
inventory.Add(database.Items[5]);
inventory.Add(database.Items[6]);
}
void OnGUI()
{
GUI.skin = Skin;
DrawInventory();
for (int i = 0; i < inventory.Count; i++)
{
GUI.Label(new Rect(10, i * 40, 200, 50), inventory[i].itemName);
}
}
void DrawInventory()
{
for (int x = 0; x < SlotsX; x++)
{
for (int y = 0; y < SlotsY; y++)
{
GUI.Box(new Rect(x * 180, y * 180, 160, 160), "", Skin.GetStyle("Slot"));
}
}
}
}

To set the parent of a GameObject in Unity programmatically, simply use this:
childGameObject.transform.SetParent(parentGameObject);
EDIT:
Turns out it isn't this simple with OnGUI. Follow Draco18s's advice and use the new GUI system.

Related

Why does my generated mesh have some distortion?

error detail
this mesh is generated by my script.I want to generate a voronoi diagram and split a plane to three zones.And I drag a material to one of the zones to test the generated result.
using SharpVoronoiLib;
using System.Collections;
using System.Collections.Generic;
using System.Windows.Forms.VisualStyles;
using UnityEngine;
public class Fortune : MonoBehaviour
{
List<VoronoiEdge> edges;
private void Awake()
{
List<VoronoiSite> sites = new List<VoronoiSite>
{
new VoronoiSite(22, 26),
new VoronoiSite(10, 40),
new VoronoiSite(38, 5)
};
edges = VoronoiPlane.TessellateOnce(
sites,
0, 0,
50, 50
);
//site represent a zone. ClockwisePoints represent some points,which makes up the zone.
for (int i = 0; i < sites.Count; i++)
{
var ver = new List<Vector3>();
var uv= new List<Vector2>();
foreach (var item in sites[i].ClockwisePoints)
{
float x = (float)item.X;
float y = (float)item.Y;
ver.Add(new Vector3(x, 0, y));
uv.Add(new Vector2(x/50, y/50));
}
ver.Reverse();
uv.Reverse();
List<int> tri = new List<int>();
for (int j = 1; j < ver.Count - 1; j++)
{
tri.Add(0);
tri.Add(j);
tri.Add(j + 1);
}
Mesh mesh = new Mesh();
mesh.vertices = ver.ToArray();
mesh.triangles = tri.ToArray();
mesh.uv=uv.ToArray();
var gameObject = Resources.Load<GameObject>("test");
MeshFilter meshfilter = gameObject.GetComponent<MeshFilter>();
meshfilter.mesh = mesh;
Instantiate(gameObject,Vector3.zero,Quaternion.identity);
}
}
Maybe the uv setting has error.But I don't know the reason.Thank for your reply.
After some try,I find if I delete height map in shader.The error has disappeared.I don't know reason.
shader windows

Unity Editor crashes on running these scripts

So, my editor keeps on crashing on running these scripts.
Specifications of my pc(if needed): Intel i5,8GB ram,Windows 10
I am trying to make a Minecraft game and my editor crashes:
VoxelData.cs:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public static class VoxelData
{
public static readonly int ChunkWidth = 2;
public static readonly int ChunkHeight = 2;
public static readonly Vector3[] voxelVerts = new Vector3[8] {
new Vector3(0.0f,0.0f,0.0f),
new Vector3(1.0f,0.0f,0.0f),
new Vector3(1.0f,1.0f,0.0f),
new Vector3(0.0f,1.0f,0.0f),
new Vector3(0.0f,0.0f,1.0f),
new Vector3(1.0f,0.0f,1.0f),
new Vector3(1.0f,1.0f,1.0f),
new Vector3(0.0f,1.0f,1.0f),
};
public static readonly int[,] voxelTris = new int[6, 6]{
{0,3,1,1,3,2},
{5,6,4,4,6,7},
{3,7,2,2,7,6}, // top face
{1,5,0,0,5,4},
{4,7,0,0,7,3},
{1,2,5,5,2,6}
};
}
and the Chunk.cs script:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Chunk : MonoBehaviour
{
public MeshRenderer meshRenderer;
public MeshFilter meshFilter;
// Start is called before the first frame update
int vertexIndex = 0;
List<Vector3> vertices = new List<Vector3>();
List<int> triangles = new List<int>();
List<Vector2> uvs = new List<Vector2>();
void Start()
{
for(int y = 0; y < VoxelData.ChunkHeight; y++)
{
for (int x = 0; x < VoxelData.ChunkWidth; x++)
{
for (int z = 0; x < VoxelData.ChunkWidth; z++)
{
AddVoxelDataToChunk(new Vector3(x, y, z));
}
}
}
CreateMesh();
}
void AddVoxelDataToChunk(Vector3 pos)
{
for (int p = 0; p < 6; p++)
{
for (int i = 0; i < 6; i++)
{
int triangleIndex = VoxelData.voxelTris[p, i];
vertices.Add(VoxelData.voxelVerts[triangleIndex] + pos);
triangles.Add(vertexIndex);
uvs.Add(Vector2.zero);
vertexIndex++;
}
}
}
void CreateMesh()
{
Mesh mesh = new Mesh();
mesh.vertices = vertices.ToArray();
mesh.triangles = triangles.ToArray();
mesh.uv = uvs.ToArray();
mesh.RecalculateNormals();
meshFilter.mesh = mesh;
}
// Update is called once per frame
}
why does it keep crashing, it is quite annoying and not letting me continue on this project.
Please help and advise what to do
The most inner
// | here !
// v
for (int z = 0; x < VoxelData.ChunkWidth; z++)
{
AddVoxelDataToChunk(new Vector3(x, y, z));
}
will cause an infinite loop since x is nowhere changed inside it.
It should most probably be z
// | here !
// v
for (int z = 0; z < VoxelData.ChunkWidth; z++)
{
AddVoxelDataToChunk(new Vector3(x, y, z));
}

Method is not working inside onGUI() method

The thing that I want to do is writing a method which can call in onGUI() method.
I wrote this method. However when I run the program , method did not show the effect.
private void ShowSubPartsOnClick(float x, float y, float widthLABEL, float heigth, HumanBodyPart bodyPart)
{
x = x + 14;
for(int i = 0; i < bodyPart.SubParts.Count; i++)
{
y = y + 14;
GUI.Label(new Rect(x+14,y,widthLABEL,heigth), bodyPart.SubParts[i].EnglishTitle);
if(GUI.Button(new Rect(x, y, 14, heigth),"+"))
{
ShowSubPartsOnClick(x, y, widthLABEL, heigth, bodyPart.SubParts[i]);
}
}
}
}
private void OnGUI()
{
GUI.Label(new Rect(text.transform.position.x+14, text.transform.position.y, text.rectTransform.sizeDelta.x, 14),bodyVisualizer.BodyData.Body.SubParts[0].EnglishTitle);
if(GUI.Button(new Rect(text.transform.position.x, text.transform.position.y, 14, 14), "+"))
{
ShowSubPartsOnClick(text.transform.position.x, text.transform.position.y, text.rectTransform.sizeDelta.x, 14, bodyVisualizer.BodyData.Body.SubParts[0]);
}
}
How can I fix this or what is the problem?
The challenge here is functions like GUI.Label and GUI.Button must be invoked directly from OnGUI to work:
From Unity Forums: "The only place you can draw/create GUI elements is by triggering them from inside an OnGUI function."
Given the recommendation there, one solution is to run an iterative depth first search via a while loop. See attached example.
That being said, I'd highly recommend using Unity Canvas instead of OnGUI. It's much more powerful and its programmatic logic is not constrained to a single function.
OnGUI Snippet:
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class HumanBodyPart
{
public string EnglishTitle;
public List<HumanBodyPart> SubParts;
public bool IsExpanded;
public int DrawDepth;
public HumanBodyPart(string title, HumanBodyPart[] subParts)
{
this.EnglishTitle = title;
this.SubParts = new List<HumanBodyPart>();
this.SubParts.AddRange(subParts);
this.IsExpanded = false;
this.DrawDepth = 0;
}
}
public class Script : MonoBehaviour
{
[SerializeField]
Text text;
HumanBodyPart mainBodyPart;
private void Start()
{
HumanBodyPart subSubSubBodyPart = new HumanBodyPart("SubSubSubBodyPart", new HumanBodyPart[] { });
HumanBodyPart subSubBodyPart1 = new HumanBodyPart("SubSubBodyPart1", new HumanBodyPart[] { subSubSubBodyPart });
HumanBodyPart subSubBodyPart2 = new HumanBodyPart("SubSubBodyPart2", new HumanBodyPart[] { });
HumanBodyPart subBodyPart = new HumanBodyPart("SubBodyPart", new HumanBodyPart[] { subSubBodyPart1, subSubBodyPart2});
mainBodyPart = new HumanBodyPart("BodyPart", new HumanBodyPart[] { subBodyPart });
UpdateDrawDepths(mainBodyPart);
}
private void UpdateDrawDepths(HumanBodyPart currentBodyPart, int currentDrawDepth=0)
{
currentBodyPart.DrawDepth = currentDrawDepth;
foreach (HumanBodyPart bodyPart in currentBodyPart.SubParts)
{
UpdateDrawDepths(bodyPart, currentDrawDepth + 1);
}
}
private void OnGUI()
{
float spacing = 30;
float x = text.transform.position.x + spacing;
float y = text.transform.position.y;
int drawDepth = 0;
List<HumanBodyPart> nextPartsToRender = new List<HumanBodyPart>(new HumanBodyPart[] { mainBodyPart });
while (nextPartsToRender.Count > 0)
{
HumanBodyPart currentPart = nextPartsToRender[0];
GUI.Label(new Rect(currentPart.DrawDepth * spacing + x, y, 200, 20), currentPart.EnglishTitle);
nextPartsToRender.RemoveAt(0);
if (GUI.Button(new Rect(x - spacing + currentPart.DrawDepth * spacing, y, 20, 20), "+"))
{
currentPart.IsExpanded = true;
}
if (currentPart.IsExpanded)
{
nextPartsToRender.InsertRange(0, currentPart.SubParts);
}
y += spacing;
}
}
}

Drawing multiple sprites with a for loop xna 4.0

I am currently working on a platforming game and I am trying to draw 40 items in one screenstate, but I don't want to hard code them all. Here's what I've tried so far:
Sprite class:
class Sprite
{
//texture, position and color
public Texture2D texture;
public Vector2 position;
public Color color;
}
Definiton:
Sprite levelboxbg;
int LevelBoxX = 20;
Loading:
levelboxbg = new Sprite();
levelboxbg.texture = Content.Load<Texture2D>("LevelBoxBeta");
levelboxbg.position = new Vector2(0, 0);
levelboxbg.color = Color.White;
Execution:
public void DrawLevelBoxes(SpriteBatch spriteBatch)
{
for (int i = 0; i < 10; i++)
{
spriteBatch.Draw(levelboxbg.texture, new Vector2(LevelBoxX + 20 ,0), levelboxbg.color);
LevelBoxX += 20;
}
}
I then call the method in my draw function.
Visual studio has given me 0 errors for this and it will run; however, when I get to the screen where it's supposed to draw the boxes, it draws them all but only for a fraction of a second, then they dissipate.
Any help is greatly appreciated, thank you for taking the time to read this.
Your LevelBoxX goes to infinity, so the boxes are running out of the screen pretty fast. You can reset LevelBoxX just before the for-loop like so:
public void DrawLevelBoxes(SpriteBatch spriteBatch)
{
LevelBoxX = 20;
for (int i = 0; i < 10; i++)
{
spriteBatch.Draw(levelboxbg.texture, new Vector2(LevelBoxX + 20 ,0), levelboxbg.color);
LevelBoxX += 20;
}
}
Or just declare a local variable:
public void DrawLevelBoxes(SpriteBatch spriteBatch)
{
int counter = 20;
for (int i = 0; i < 10; i++)
{
spriteBatch.Draw(levelboxbg.texture, new Vector2(counter + 20 ,0), levelboxbg.color);
counter += 20;
}
}

Why does my automatic RPG inventory grid not work?

Here is my situation. I have four classes: Inventory.cs, InventoryTab.cs, ItemDatabase.cs, BaseItem.cs (and a few items that derive from BaseItem such as Weapon, Consumable, etc)
Inventory creates new InventoryTabs (Consumable, Weapon, Armor), and in each InventoryTab there is a list of BaseItems.
Inventory.AddItemByID(int ID, int Amount) is then called, which checks the IDs of ItemDatabase.cs, and has items pre-loaded into a list when the game is started.
Ok, now that you have basic info on how my inventory runs, here my problem:
In the InventoryTab:
int Column, Row; //Declared at the top of the class
for (int i = 0; i < ItemList.Count; i++)
{
Column++;
if (Column > gridSize.X)
{
Column = 0; Row++; //Row is not limited because my inventory will be unlimited in height
}
ItemList[i].gridLocation = new Point(column, row);
}
While I thought this would work, instead it creates one item at the top, and rapidly skips to the right, and then skips down one row, and repeats. If I add more items via a KeyboardState, it flashes a huge list of items, then disappears.
I'm certain it's because it is assigning the value of gridLocation in a loop, but then again I have no idea how I would go about it any other way.
What I need it to do is assign the gridLocation per BaseItem in ItemList only once.
EDIT:
InventoryTab.cs:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
namespace InventoryEngine
{
public class InventoryTab
{
public List<BaseItem> ItemList = new List<BaseItem>();
int itemSize; //In Pixels
Point gridSize = new Point(5, 4);
int LocY, Column, Row;
public float Scale;
//Region Clipping
Rectangle scissorRect;
RasterizerState rState = new RasterizerState()
{
ScissorTestEnable = true
};
Vector2 gridOffset;
Texture2D slot;
SpriteFont sf;
MouseState ms;
public void LoadContent(ContentManager c, GraphicsDevice g)
{
ItemDatabase.LoadItemData(c);
slot = c.Load<Texture2D>("inventory_slot");
sf = c.Load<SpriteFont>("SpriteFont1");
Scale = 4.0f;
itemSize = 32 * (int)Scale;
gridOffset = new Vector2(g.Viewport.Width / 2 - (itemSize * gridSize.X / 2), g.Viewport.Height / 2 - (itemSize * gridSize.Y / 2));
LocY = g.Viewport.Height / 2;
}
public void Update(GameTime gt, GraphicsDevice g)
{
ms = Mouse.GetState();
LocY += ms.ScrollWheelValue / 10;
if (LocY >= g.Viewport.Height / 2 - 252)
LocY = g.Viewport.Height / 2 - 252;
for (int i = 0; i < ItemList.Count / 1; i++)
{
Column++;
if (Column > gridSize.X)
{
Column = 0; Row++;
}
ItemList[i].gridLocation = new Point(Column, Row);
}
foreach (BaseItem item in ItemList)
{
item.UpdateValues(gridSize, itemSize, gridOffset, LocY);
}
}
public void DrawTab(SpriteBatch sb, GraphicsDevice g)
{
scissorRect = new Rectangle((int)gridOffset.X, g.Viewport.Height / 2 - 256, gridSize.X * itemSize, gridSize.Y * itemSize);
sb.Begin(SpriteSortMode.Deferred, BlendState.AlphaBlend, SamplerState.PointClamp, DepthStencilState.Default, rState);
//g.ScissorRectangle = scissorRect;
foreach (BaseItem i in ItemList)
{
sb.Draw(slot, new Vector2(i.itemRect.X, i.itemRect.Y), new Rectangle(0, 0, 32, 32), Color.White, 0, Vector2.Zero, Scale, SpriteEffects.None, .95f);
sb.Draw(i.Icon, new Vector2(i.itemRect.X, i.itemRect.Y), new Rectangle(0, 0, i.Icon.Width, i.Icon.Height), Color.White, 0, Vector2.Zero, Scale, SpriteEffects.None, .95f);
//if (i.currentAmount > 1)
sb.DrawString(sf, "" + i.currentAmount, new Vector2(i.itemRect.X, i.itemRect.Y), Color.White, 0f, Vector2.Zero, Scale, SpriteEffects.None, .95f);
}
sb.End();
}
}
}
BaseItem.cs:
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Content;
namespace InventoryEngine
{
public class BaseItem
{
public Texture2D Icon;
public string name;
string description;
public int id, currentAmount, maxAmount;
public enum TabType { Consumable, Weapon, Armor, Ammo, Jewellery, Resources, Misc }
public TabType tabType;
public bool isSelected, isUsable;
public Vector2 positionOffset;
public Point gridLocation;
public Rectangle itemRect;
public BaseItem(Texture2D IconName, int ID, string Name, string Description, int MaxAmount, TabType TabType)
{
Icon = IconName;
id = ID;
name = Name;
description = Description;
maxAmount = MaxAmount;
tabType = TabType;
}
public void UpdateValues(Point GridSize, int itemSize, Vector2 GridOffset, int OffsetY)
{
currentAmount = (int)MathHelper.Clamp(currentAmount, 0, maxAmount);
itemRect = new Rectangle(gridLocation.X * itemSize + (int)GridOffset.X, gridLocation.Y * itemSize + OffsetY, itemSize, itemSize);
}
}
}
Going with #deathismyfriend you could run a nested for loop going through each position:
int pos; //Declared at the top of the class
pos = 0;
for (int x = 0; x < gridsize.X; x++) // x represents column
{
for (int y = 0; y < ItemList.Count / gridsize.X; y++) // y represents row
{
// In the above (ItemList.count / gridsize.X) = number of rows needed
ItemList[pos].gridLocation = new Point(x, y);
pos++;
}
}
And that SHOULD do what you want it to.
Mona

Categories