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

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.

Related

Get the center point between many GameObjects in Unity

I have created a game in which you can control X characters at the same time in the same form and they can die at any time. My problem is when I want the game camera to include all these gameobjects.
I thought that a good option is to calculate the central point between the gameobjects in the scene and make the camera follow that point at a certain distance.
I already have the camera code, but I still need to know how to get that central point or another way of doing it. In addition, the camera does not follow any of the axes (X, Y, Z) linearly, since it is placed in such a way that is the view is isometric (the game is in 3D).
As a last important fact, it is that all gameobjects that are running in the game (that are alive), are stored in a public static List <GameObject> to be able to access the components of these gameobjects at any time. Also, if a character (gameobject) dies or is born, the list is updated without problems.
I leave you a graphic example with three different cases, being the black points, the characters that are in the scene (gameobjects) and the red points, the central point (vector) that I would like to find.
Also, I leave the camera code so you can test if you have any solution:
public class Camera_Movement : MonoBehaviour {
Vector3 newPos;
public static List<GameObject> playersInGame = new List<GameObject>();
void Update() {
// Get Central Vector
// Replace playersInGame[0].transform.position with central vector
//newPos = Vector3.Lerp(gameObject.transform.position, "central vector", Time.deltaTime);
newPos = Vector3.Lerp(gameObject.transform.position, playersInGame[0].transform.position, Time.deltaTime);
gameObject.transform.position = new Vector3(newPos.x, newPos.y, newPos.z);
}
}
Thank you very much in advance!
You need to take the average x and and average y.
That would look like the following:
var totalX = 0f;
var totalY = 0f;
foreach(var player in playersInGame)
{
totalX += player.transform.position.x;
totalY += player.transform.position.y;
}
var centerX = totalX / playersInGame.Count;
var centerY = totalY / playersInGame.Count;
Let me know if this works for you (don't have access to Unity at the moment), but I put together an example here: https://dotnetfiddle.net/jGd99I
To have a solution that your camera can be best positioned to see all of your objects, then try this:
public Vector3 FindCenterOfTransforms(List<Transform> transforms)
{
var bound = new Bounds(transforms[0].position, Vector3.zero);
for(int i = 1; i < transforms.Count; i++)
{
bound.Encapsulate(transforms[i].position);
}
return bound.center;
}

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

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!

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.

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