Get Size of 3d mesh inside a Prefab in Unity? - c#

I want to create a hexagon grid. I Have a 3D model which I made in blender with some dimensions.
I have a script in Unity which is supposed to generate a hex grid with a given hexagon.
The model of the hex is placed in a Prefab. I need the size "Real size not the scale" of that prefab in order to generate the grid.
How can I get the size of the model which is in a prefab.
public class GameWorld : MonoBehaviour
{
// Fields
public GameObject HexPrefab;
// Size of the map in terms of number of the objects
// This is not representative of the actual size of the map in units
public int Width = 20;
public int Height = 20;
void Start()
{
MeshRenderer[] asd = HexPrefab.GetComponentsInChildren<MeshRenderer>();
var a = asd[0].bounds;
Debug.Log(string.Format("x: - {0:f3}", a.size.x));
Debug.Log(string.Format("y: - {0:f3}", a.size.y));
Debug.Log(string.Format("z: - {0:f3}", a.size.z));
for (int x = 0; x < Width; x++)
{
for (int y = 0; y < Height; y++)
{
Instantiate(HexPrefab, new Vector3(x, 0, y), Quaternion.identity);
}
}
}
void Update()
{
}
}
Here are the dimensions from blender.
I don't want to hard code it because I will need to use hexagons of different sizes in the future!
This code gives me a size of 0.
The prefab consists of only one model and nothing else.
Thank you in advance!

My Prefab Consists of only the model.
Here is what it looks like.
And this is the properties of the model:
Then in the code I did the following:
Mesh mesh = HexPrefab.GetComponentsInChildren<MeshFilter>()[0].sharedMesh;
And now I can get the dimensions of the mesh like this:
mesh.bounds.size
In my case the prefab has a scale of 1 so the size of the model and the size of the prefab are the same but if you want to go the extra step you can multiply the size that we got from the model by the scale of the prefab.
Hope this helps someone who is having the same question!
Have a nice day!

Related

Unity - Colliding canvas elements with viewport elements using WorldToScreenPoint per vertex

I wish to make collide a UI element with a viewport element. To achieve this I figured I take the collision data EdgeCollider2D of the viewport element and convert each of its vertices to Screen space, then assign the points to another canvas element which has an EdgeCollider2D on it.
Problem is, the generated collision is way off, and I can't figure out why is that.
Here's my short code:
[RequireComponent(typeof(EdgeCollider2D))]
public class ScreenSpaceEdgeCollisionGenerator : MonoBehaviour, IScreenSpaceCollisionGenerator {
public EdgeCollider2D target;
private void Update() {
GenerateCollision();
}
public void GenerateCollision() {
var mEdge = GetComponent<EdgeCollider2D>();
var viewportPts = target.points;
Vector2[] n_Pts = new Vector2[viewportPts.Length];
for (int i = 0; i < viewportPts.Length; i++) {
n_Pts[i] = Camera.main.WorldToScreenPoint(viewportPts[i]);
}
mEdge.points = n_Pts;
}
}
here's the result:
On this first image you see how off the collision data is.
On this second image the red rect is the viewport element, while the white square is the ui element. I use only one, the main camera, the same which is used to determine the point transformation. The viewport element's EdgeCollider2D is placed on top of the red rect, as it should be.

Unity paint circular healthbar dynamically

I got a circular healthbar. It updates, when the current or max life changes.
healthBar.fillAmount = currentHealth / maxHealth;
So this bar looks boring. There are no borders between the "pieces". When I got eight lifepoints I want to see eight parts there.
Super Mario 64 should be an excellent example
Important would be having small borders showing the lifepoints. Is this even possible?
I don't have 8 lifepoints. The lifepoints are not constant. They are set by the value X. Otherwise I could use a Texture, yes. Furthermore I want to increase the max life in the game, so everything has to work dynamically.
The simplest solution would be to create a thin line in a graphics editor, import it into Unity as a sprite, then add the sprite as an Image object in your scene.
If you have eight health pieces, you need 4 border lines spaced 45 degrees apart. The code below will clone the image as many times as you need (set via the field pieces, instead of X as you said) and rotate each clone round the z-axis.
public GameObject line; //Set your line image via the inspector here
private int pieces = 8;
public void DrawLines()
{
int linecount = pieces/2;
float angle = 360 / linecount;
for(int i = 0; i < linecount; i++)
{
GameObject clone = Instantiate(line, Vector3.zero,
Quaternion.Euler(0,0,(angle*i)));
}
}

XNA/C# Edit list<> from another class

I have a project in class where I decided to make a DX Ball game in XNA, and have goten along quite well but now I'm stuck.
I have created a list of "bricks", that is rectangles, for my sprites to be positioned by and for my ball to collide with.
I have an idea to let all ball logic be in the ball class so now the fun part that I need help with. How to edit this list when the ball collides with one of the bricks. I want to delete the brick that has been hit, and I figure that will be okay since they are declared as individual bricks with individual coordinates.
I have found this question, and it answers the part of how to get things out of a list but not how to edit it.
Access List from another class
I was thinking about writing a Boolean function in the ball update field, since i don't need it to calculate every time it updates a frame. When collision is true it can cal the function that iterates through the list of bricks and delete the one the ball hit.
I'm not sure what I need to show from my ball class so there might be some if needed later on.
public struct BoundingBrick
{
public Vector2 brickPosision;
public double BrickW;
public double BrickH;
}
public BoundingBrick boundingBrick = new BoundingBrick();
boundingBrick.BrickW = 50;
boundingBrick.BrickH = 20;
boundingBrick.brickPosision.X = 50;
boundingBrick.brickPosision.Y = 50;
bricks = new List<Rectangle>();
for (var i = 0; i < 14; i++)
{
for (var j = 0; j < 12; j++)
{
bricks.Add(new Rectangle((int)boundingBrick.brickPosision.X + j * 50, (int)boundingBrick.brickPosision.Y + i * 20, (int)boundingBrick.BrickW, (int)boundingBrick.BrickH));
}
}
I've done this:
List bricks
Rectangle ball;
foreach (BoundingBrick brick in bricks.ToArray())
{
if (ball.rect.Intersects(brick.rect))
{
ball.CollideEffect();
brick.TakeDamage();
}
}
and in the TakeDamage Class from the brick:
public void TakeDamage(List<BoundingBrick> bricks)
{
lives -= 1;
if (lives <= 0)
{
bricks.remove(this)
}
}
The 'ToArray()' part will prevent it from crashing in the list.

How to draw a 2D graph on Canvas in Unity 5

I need to draw a graph for my decibel app that I am making with Unity. The solution below works but is not as exact as my employer would like. Could I make this graph look more professional and exact? Basically I want the lines to be of equal width and prevent the line from going almost invisible like in the following pic: http://puu.sh/qjSvO/a51c11cef5.png
I was thinking about making a 2D texture and using SetPixel, but I am not sure if that is the correct way.
The graph is drawn on a canvas as part of an scalable UI.
public class Graph : MonoBehaviour {
public float graphWidth;
public float graphHeight;
LineRenderer newLineRenderer;
List<int> decibels;
int vertexAmount = 50;
float xInterval;
GameObject parentCanvas;
// Use this for initialization
void Start ()
{
parentCanvas = GameObject.Find("Canvas");
graphWidth = transform.Find("Linerenderer").GetComponent<RectTransform>().rect.width;
graphHeight = transform.Find("Linerenderer").GetComponent<RectTransform>().rect.height;
newLineRenderer = GetComponentInChildren<LineRenderer>();
newLineRenderer.SetVertexCount(vertexAmount);
xInterval = graphWidth / vertexAmount;
}
//Display 1 minute of data or as much as there is.
public void Draw(List<int> decibels)
{
if (decibels.Count == 0)
return;
float x = 0;
for (int i = 0; i < vertexAmount && i < decibels.Count; i++)
{
int _index = decibels.Count - i - 1;
float y = decibels[_index] * (graphHeight/130); //(Divide grapheight with the maximum value of decibels.
x = i * xInterval;
newLineRenderer.SetPosition(i, new Vector3(x - graphWidth / 2 , y - graphHeight / 2 , 0));
}
}
}
Using the editor, you can "cut" sprites into nine pieces, so that there is a texture for each side, a texture for each corner and a texture to fill it in. I would recommend using that to make it look good if you want it so. It is some time since i used it myself, but maybe you can find information on the Unity manual.

XNA How to create randomly generated (differing) turn rates for duplicated objects?

I am making asteroids, and I need them to rotate at different rates and directions to give the effect I want. Instead of creating 10+ different things for each one, I tried to do the
for (int i = 0; i < 25; i++)
{
AsteroidPositions[i] = new Vector2(1 * random.Next(800), 1 * random.Next(600));
}
and that seems to work out nicely for randomly generated positions. I can have 25 randomly generated asteroids on screen in different places at once. What it doesn't work for is the rotation, because it is a float and not a Vector2. I have tried to do something like this:
AsteroidRotation = MathHelper.Lerp(-0.5f, +0.5f, (float)random.NextDouble());
but that gives me the error of all of the on screen rocks randomly facing a single direction. and the same one as well. I can not add [i] to it because it says that it can not convert float to float[]. I also have this for the spriteBatch:
for (int i = 0; i < 25; i++)
{
spriteBatch.Draw(AsteroidTexture,
AsteroidPositions[i],
AsteroidSourceLocation,
Color.White,
AsteroidRotation,
AsteroidSourceOrigin,
1.0f,
SpriteEffects.None,
AsteroidLocation.Y / 720.0f);
}
so is there any way of me doing this? should I not be using the [i] method and use an array? if so, how?
Straight off the bat I would say using variables instead of a class to represent your asteroid is probably not a good idea. You mention in your title that what you have here is a duplicated object - this isn't even the case as you are not using any objects! Since, in your mind, you are visualising this asteroid as an object, you should be using a Class to contain it.
The reason why all of your asteroids face the same direction is because AsteroidRotation = MathHelper.Lerp(-0.5f, +0.5f, (float)random.NextDouble()); is a single value, the same value you use for every asteroid's rotation.
Equally, you can not simply use AsteroidRotation[i] as this would mean that AsteroidRotation is a collection of rotations where you can to access the i th value in your collection by using [i]. It is not a collection, it's a single float value.
Two ways of solving this:
1) Quick and easy. Not recommended. Not future proof. Will lead to bad habits.
Make your rotation values an array.
float[] asteroidRotation = new float[25];
for (int i = 0; i < 25; i++)
{
asteroidRotation[i] = MathHelper.ToRadians(random.Next(360));
// ToRadians() important, XNA does not work in degrees.
}
And then in your drawing code you need to use:
spriteBatch.Draw(AsteroidTexture,
AsteroidPositions[i],
AsteroidSourceLocation,
Color.White,
AsteroidRotation[i],
AsteroidSourceOrigin,
1.0f,
SpriteEffects.None,
AsteroidLocation.Y / 720.0f);
2) Create an Asteroid class. Good practice. Uses object-oreintated nature of C# / .Net.
Create an asteroid class which contains all the data and relevant methods for each. This combats your "instead of creating 10+ different things for each one".
A very quick class setup but it will get the job done:
public class Asteroid
{
public Texture2D Texture { get; set; }
public Vector2 Position { get; set; }
public Color Color { get; set; }
public float Rotation { get; set; }
public Rectangle SourceLocation { get; set; }
public Vector2 SourceOrigin { get; set; }
public Asteroid()
{
}
public void Draw(SpriteBatch sb)
{
sb.Draw(
Texture,
Position,
SourceLocation,
Color,
Rotation,
SourceOrigin,
1.0f,
SpriteEffects.None,
0f);
}
}
Create a list of asteroids and fill the list:
List<Asteroid> asteroids = new List<Asteroid>();
int numAsteroids = 25;
for (int i = 0; i < numAsteroids; i++)
{
Asteroid asteroid = new Asteroid();
asteroid.Texture = asteroidTexture;
asteroid.Position = new Vector2(1 * random.Next(800), 1 * random.Next(600));
asteroid.Color = Color.White;
asteroid.Rotation = MathHelper.ToRadians(random.Next(360));
asteroid.SourceLocation = new Rectangle(0, 0, 0, 0); // Fill me in
asteroid.SourceOrigin = new Vector2(0, 0); // Fill me in
asteroids.Add(asteroid);
}
Make sure you do this only once, ideally in other your game's LoadContent() or Initialize() method!
Then to draw:
foreach (Asteroid asteroid in asteroids)
{
asteroid.Draw(spriteBatch);
}
And that should be it. I don't think I've missed anything!
In the future this allows you to expand upon what asteroids can do extremely easily. You could create an Update() method that controls rotational speeds; have the asteroid move by giving them their own velocity.

Categories