2D XNA - Draw a Circle - c#

Yo, Hi everybody
Is there any Way to draw a circle? I don't want to use a Texture/sprite to draw a circle Because the Player is the Circle so the Circle Should move ... and also I'm Trying to make it so the Player/Circle's Size gets bigger and bigger When he eats some food blablabla...
anyways, if anybody knows how to do it please Tell me.
OTHERWISE : IS THERE A WAY TO CHANGE A TEXTURE HEIGHT / WIDTH , THEN I WILL MAKE A SIMPLE CIRCLE TEXTURE AND CHANGE HEIGHT / WIDTH OF IT.
Thanks.

You can use 3D primitives like 'Someone' :> already posted or use the C3.XNA.Primitives2D libary where you can use a extension for SpriteBatch to draw a circle
public static void DrawCircle(this SpriteBatch spriteBatch, Vector2 center, float radius, int sides, Color color, float thickness);
If you use the same value for radius and thickness the circle appears filled.
I didn't find the offizial download link, but there are also uploads at sourceforge.
Also you can generate a circle dynamically via code like:
public static Texture2D GenerateCircleTexture(GraphicsDevice graphicsDevice, int radius, Color color, float sharpness)
{
int diameter = radius * 2;
Texture2D circleTexture = new Texture2D(graphicsDevice, diameter, diameter, false, SurfaceFormat.Color);
Color[] colorData = new Color[circleTexture.Width * circleTexture.Height];
Vector2 center = new Vector2(radius);
for (int colIndex = 0; colIndex < circleTexture.Width; colIndex++)
{
for (int rowIndex = 0; rowIndex < circleTexture.Height; rowIndex++)
{
Vector2 position = new Vector2(colIndex, rowIndex);
float distance = Vector2.Distance(center, position);
// hermite iterpolation
float x = distance / diameter;
float edge0 = (radius * sharpness) / (float)diameter;
float edge1 = radius / (float)diameter;
float temp = MathHelper.Clamp((x - edge0) / (edge1 - edge0), 0.0f, 1.0f);
float result = temp * temp * (3.0f - 2.0f * temp);
colorData[rowIndex * circleTexture.Width + colIndex] = color * (1f - result);
}
}
circleTexture.SetData<Color>(colorData);
return circleTexture;
}
Sharpness below 1f blurs the circle.

The only way to draw primitives (e.g. circles) is in 3D:
https://msdn.microsoft.com/en-us/library/bb196414.aspx
Or you can load a texture that is 1*1, stretch it into a line and then use a bunch of those lines to make a circle.
Use:
public void Draw (
Texture2D texture,
Vector2 position,
Nullable<Rectangle> sourceRectangle,
Color color,
float rotation,
Vector2 origin,
Vector2 scale,
SpriteEffects effects,
float layerDepth
)
to stretch the texture.
Or you can just use a circle texture and stretch it.
If you are making something like agar.io then you might want to use a texture combined with the circle primitive so you can make the circle 'wobbly'.

Related

Color Picker In Unity

I am making a game where there is a color picker to change the color of an GameObject where clicking on a color in the button should take back the color it points though inside the buttons and pass it to the material of the game object. It mostly works fine but there is some issue with the cursor position which brings in a different color, but not the color to which it is pointed. Requesting help.
public RectTransform Rect;
public Text TestText;
public Texture2D ColorTexture;
public GameObject Plane;
public void PickColor()
{
Vector3 imagePos = Rect.position;
float globalPosX = Input.mousePosition.x - imagePos.x;
float globalPosY = Input.mousePosition.y - imagePos.y;
int localPosX = (int)(globalPosX * (ColorTexture.width / Rect.rect.width));
int localPosY = (int)(globalPosY * (ColorTexture.height / Rect.rect.height));
float x = Input.mousePosition.x * (ColorTexture.width / Rect.rect.width);
float y = Input.mousePosition.y * (ColorTexture.width / Rect.rect.width);
Color Col = ColorTexture.GetPixel(localPosX, localPosY);
TestText.color = Col;
SetActualColor(Col);
}
void SetActualColor(Color Col)
{
TestText.color = Col;
Plane.GetComponent<MeshRenderer>().sharedMaterial.color = Col;
}
RectTransform.rect.width and RectTransform.rect.height aren't actually in screen size pixels as opposed to Input.mousePosition.`They are scaled with the canvace/screen, so that you always get a significant error with your correct formula.
You need to determine the global position of the corners and calculate the dimensions from that. Luckily there is a build in function for that.
Vector3[] corners = new Vector3[4];
Rect.GetWorldCorners(corners);
Vector2 dimensions = corners[2] - corners[0];
int localPosX = (int)(globalPosX * (ColorTexture.width / dimensions.x));
int localPosY = (int)(globalPosY * (ColorTexture.height / dimensions.y));
You also need to make sure that the pivot of the rect is set to (0,0) since the texture coordinates start from the bottom left.

Unity - Can't center mini-map viewport rect inside center of the image

How do I convert image position to camera viewport view?
I have a radar and I use a camera to show that viewport on the screen but it only works on a set rect which works fine for only 1 type of screen, the one that i set.
How can I match this rect to a image transform position. so if the screen changes and as it moves, the ui around it will move the camera view with it too.
This is for the screen of an iPhone XS Max (2688x1242)
I would want something like overlayCamera.rect = transform.position
Here is the code that I use to show the camera rect.
private void UpdateCameraViewportRect()
{
float aspectRatio = (float)Screen.width / Screen.height;
float desiredScreenWidth = 0.271f;
float viewHeight = 0.831f;
float viewWidth = 0.78f;
float width = desiredScreenWidth;
float height = width * aspectRatio;
if (height > 1.0f)
{
height = 1.0f;
width = height / aspectRatio;
}
// Controls the position of the view
overlayCamera.rect = new Rect(
viewHeight - width, viewWidth - height,
width, height
);
/*
// Method 1 -> Does not work
Vector3 p = overlayCamera.ViewportToWorldPoint(new Vector3(1, 1, overlayCamera.nearClipPlane));
Debug.Log(p);
// Method 2 -> Does not work
Vector3 screenPos = overlayCamera.WorldToScreenPoint(overlayCamera.transform.position);
float posx = screenPos.x - (width * 0.5f);
float posy = screenPos.y - (height * 0.5f);
Debug.Log(posx + " & " + posy);
// Method 3 -> Does not work
overlayCamera.rect = radarBorder.rectTransform.rect;
*/
}
How can I center the viewport rect in the center of the gold border image?
Solution: Create a RenderTexture instead and show it in a RawImage to move around the UI.
Ok I may have misunderstood but it looks like the approach is to adjust the UI dynamically based on the aspect ratio of the screen.
It may be best to lay out the UI normally in the editor and force the aspect ratio of the overlayCamera to be 1:1 using Camera.aspect:
void Start(){
var cam = GetComponent<Camera>();
cam.aspect = 1;
cam.ResetAspect();
}
EDIT:
While it is possible to adjust where on the screen a camera renders, as you can see its a little messy. Common practice is to render to a RenderTexture and place that on a material inside the UI.

Trying to map a sphere with Perlin Noise

So as the title says I'm trying to map properly a octahedron sphere using a 3D Perlin Noise as a procedural texture.
I suppose it has something to do about the UVs or about the edges vertices of the texture (left, right, probably even top and down). It's a texture with size 512*512, but it can be 1024*1024.
I've been documentating, trying other techniques, using normal maps, tangets, etc but i still can't figure out how to solve that seam (keep in mind it should be procedurally generated) to generate a surface around the sphere to update it during runtime (in that way I can change the noise (shape of the terrain) as well as the colours).
By the way, when I do the same with a prepared texture (1024*512) with the edges properly corrected the seam disappear, but what I want is the ability to change it in run time (can survive without it but would be nice to have it)
private void OnEnable()
{
if(autoUpdateTexture)
{
if (texture == null)
{
texture = new Texture2D(resolution, resolution, TextureFormat.RGB24, true);
texture.name = "Procedural Texture";
texture.wrapMode = TextureWrapMode.Repeat;
texture.filterMode = FilterMode.Trilinear;
texture.anisoLevel = 9;
GetComponent<MeshRenderer>().sharedMaterial.mainTexture = texture;
}
FillTexture();
}
}
public void FillTexture()
{
if (texture.width != resolution)
{
texture.Resize(resolution, resolution);
}
Vector3 point00 = transform.TransformPoint(new Vector3(-0.5f, -0.5f));
Vector3 point10 = transform.TransformPoint(new Vector3(0.5f, -0.5f));
Vector3 point01 = transform.TransformPoint(new Vector3(-0.5f, 0.5f));
Vector3 point11 = transform.TransformPoint(new Vector3(0.5f, 0.5f));
NoiseMethod method = Noise.noiseMethods[(int)type][dimensions - 1];
float stepSize = 1f / resolution;
for (int y = 0; y < resolution; y++)
{
Vector3 point0 = Vector3.Lerp(point00, point01, (y + 0.5f) * stepSize);
Vector3 point1 = Vector3.Lerp(point10, point11, (y + 0.5f) * stepSize);
for (int x = 0; x < resolution; x++)
{
Vector3 point = Vector3.Lerp(point0, point1, (x + 0.5f) * stepSize);
float sample = Noise.Sum(method, point, frequency, octaves, lacunarity, persistence);
if (type != NoiseMethodType.Value)
{
sample = sample * 0.5f + 0.5f;
}
texture.SetPixel(x, y, coloring.Evaluate(sample));
}
}
texture.Apply();
}
So, I have 2 images, one showing the 3D generated noise in the sphere (when I save the textue to png it just goes to 2D, something obvious)
And the other one, showing that 3D noise IN the sphere with a seam at the edges, so the thing is get that 3D noise in the sphere without the seam.
If you need any more related info, please let me know, as this is giving me a nice headache.
procedural texture in 2D
3D noise on sphere

Get world position of a pixel from texture2d/sprite

I'm setting up an automatic system to be able to attach a sprite and it will gather all its colours and the world position of each sprite. A list/class of all the colours used has been set up but how would get the position of all these sprites?
I have already tried doing this mathematically like getting the complete size of the sprite and then working out the size of each pixel and then working out the position from that. But this seems flawed due to the position of the sprite possibly changing.
Sprite ColouredSpriteTexture = ColoredSprite.GetComponent<SpriteRenderer>().sprite;
Texture2D ColouredTexture = ColouredSpriteTexture.texture;
float XsizeF = ColoredSprite.transform.localScale.x;
int Xsize = (int)XsizeF;
float YsizeF = ColoredSprite.transform.localScale.y;
int Ysize = (int)YsizeF;
List<Color> TempList = new List<Color>();
//Could spawn pixels by getting x and y size and dividing them by 100 50/100 = 0.50f
//if the tile has a color then spawn pixel if not 0.50 += 0.50
//TODO test if this logic will work
float PixelSize = XsizeF / 100;
float currentPos = PixelSize;
for (int x = 0; x < Xsize; x++)
{
for (int y = 0; y < Ysize; y++)
{
int listAmount = TempList.Count;
Color ColoredTex = ColouredTexture.GetPixel(x, y);
float TextureAlpha = ColoredTex.a;
if (!TempList.Contains(ColoredTex) && TextureAlpha != 0)
{
TempList.Add(ColoredTex);
ColorByNumber tempColor = new ColorByNumber();
tempColor.Color = ColoredTex;
tempColor.ColorNumber = listAmount;
ColorOptions.Add(tempColor);
}
if(TextureAlpha == 1)
{
GameObject ColorPixel = Instantiate(PixelPrefab);
ColorPixel.transform.localScale = new Vector3(XsizeF, YsizeF, 0);
ColorPixel.transform.SetParent(this.transform);
ColorPixel.name = "Pixel (" + x.ToString() + "," + y.ToString() + ")";
}
}
}
All I would need is somehow each pixel returning its position so I can store this data and be able to spawn anything on top of this pixel.
I haven't had a chance to test this math yet so there may be some mistakes in it:
Every graphical image in Unity has a PPU, this and the object scale are going to be a huge factor. For argument sake I am going to clearly define these for 1 object.
Image dimensions : 128x128
PPU: 64
Scale: 1,1,1
Object Bounds: would
come from the renderer, which I am unsure if that bounds already
takes in account the scale(Most likely) however in the case you
cannot use that you can calculate the ObjectBoundsWidth or height
just by dividing the width or height of the texture by the PPU.
This should give you bounds of the texture in world space.
We are also going to make an assumption that we are only working on the X and Y axis and ignore the Z axis, if you want to use Z instead of Y then just make the necessary changes to be Z Scale and Z position and Z Bounds.
World position of a pixel located at 2,10. Per the documentation the pixel coordinates start at the lower left this means 0,0 is the bottom left corner, and 2,10 is 2 pixels left and 10 pixels up.
EDIT:
So I plugged all of this into a google sheet and determined the previous algorithm I provided was wrong here is the correct one in a pseudo code format
// This function takes in either the x or y, and the width or height of
// the bounds, then the x or y position of the object attached to.
// It also assumes the pivot is the center of the sprite.
float CalculateWorldPosOfPixelCoordinate(int coord, float boundsSize, float position, float scale)
{
float PixelInWorldSpace = 1.0f / PPU;
float startPos= position - (boundsSize* 0.5f * scale);
return startPos + (PixelInWorldSpace * coord) * scale;
}
This is using objectBounds we determined ourselves that is why we are multiply by scale.
this would give use a world position of: -0.97, -0.84
The algorithm i believe is the same for Y, just replace the coord with the Y position, and the bounds with the height instead of the width.
Like I said this could be wrong as I havent had a chance to test it, this also does not account for rotation either.

Microsoft Xna Texture2D and rotation

I have a set of images in which each image needs to be able to rotate to 90 degrees, 180 degrees, and 270 degrees. All of these images are of type Texture2D. Are there built in functions to accomplish this for me? Or should I load additional rotated images of each image? Or is there a better way of completing this task?
You can rotate (and scale) your Textures as you draw them to the buffer using SpriteBatch.Draw, although you will need to specify most (or all) of the arguments. Angles are given in radians.
SpriteBatch.Begin();
angle = (float)Math.PI / 2.0f; // 90 degrees
scale = 1.0f;
SpriteBatch.Draw(myTexture, sourceRect, destRect, Color.White, angle,
position, scale, SpriteEffects.None, 0.0f);
SpriteBatch.End();
http://msdn.microsoft.com/en-us/library/microsoft.xna.framework.graphics.spritebatch.draw.aspx
You could also load pre-rotated copies of the images, but you'll probably get the usual Premature Optimization lecture.
If you want to rotate only Texture2D field without changing anything in the Draw method, You can use this (it rotates input 90 degrees clockwise):
public static Texture2D RotateTexture90Deegrees(Texture2D input)
{
Texture2D rotated = null;
if (input != null)
{
rotated = new Texture2D(input.GraphicsDevice, input.Width, input.Height);
Color[] data = new Color[input.Width * input.Height];
Color[] rotated_data = new Color[data.Length];
input.GetData<Color>(data);
var Xcounter = 1;
var Ycounter = 0;
for (int i = 0; i < data.Length; i++)
{
rotated_data[i] = data[((input.Width * Xcounter)-1) - Ycounter];
Xcounter += 1;
if (Xcounter > input.Width)
{
Xcounter = 1;
Ycounter += 1;
}
}
rotated.SetData<Color>(rotated_data);
}
return rotated;
}

Categories

Resources