I need to draw a terrain and have a camera with surfacefollow in XNA, but in some places it doesnt draw what is suposed to draw and draws the terrain behind it. Any suggestions of what it may be?
public void Draw()
{
camera.Effect.TextureEnabled = true;
camera.Effect.VertexColorEnabled = false;
camera.Effect.World = worldMatrix;
camera.Effect.Texture = texture;
camera.Effect.CurrentTechnique.Passes[0].Apply();
device.SetVertexBuffer(vertexBuffer);
device.Indices = indexBuffer;
for (int i = 1; i < (alturas.Height - 1); i++)
{
device.DrawIndexedPrimitives(PrimitiveType.TriangleStrip, 0, 0, heights.Width * 2, (heights.Width * 2) * i, (heights.Width * 2) - 2);
}
}
heights is the texture of the height map. The construction of the vertices is working fine.
Related
I have created a mesh in run-time with a special shared. The shared has the following property:
1. When it is colored for the first time the color is blue
2. When it is colored for the second time the color is yellow
3. When it is colored for the third time the color is red
4. When it is colored for the fourth or more the color becomes green
Here's an example of the colored region:
In the above image the green region has many layer of mashes. I cannot calculate the area by summing up the triangles in mesh because there are many overlaps.
EDIT! I am updating question with more information
The mesh is generated using the following code (it's not the whole code by it is enough to give a general idea of how the mesh is generated)
for (int i = start; i<colorUntil; i++)
{
parent.position = currentPosition;
Vector3 relativePos = points[i + 1] - points[i];
if (relativePos.magnitude > 0.5)
{
parent.rotation = Quaternion.LookRotation(relativePos);
}
currentPosition = points[i];
Vector3 offset = parent.right * width / 2f;
vertices.Add(currentPosition - offset);
vertices.Add(currentPosition + offset);
uvs.Add(new Vector2(0, 1));
uvs.Add(new Vector2(1, 1));
if (vertices.Count< 4)
{
return;
}
int c = vertices.Count;
triangles.Add(c - 1);
triangles.Add(c - 2);
triangles.Add(c - 3);
triangles.Add(c - 3);
triangles.Add(c - 2);
triangles.Add(c - 4);
Vector3[] v = new Vector3[c];
Vector2[] uv = new Vector2[c];
int[] t = new int[triangles.Count];
vertices.CopyTo(v, 0);
uvs.CopyTo(uv, 0);
triangles.CopyTo(t, 0);
mesh.vertices = v;
mesh.triangles = t;
mesh.uv = uv;
}
Now I have to calculate the area of each color. Given the mesh above is it possible to calculate area of each color? Any suggestion would be welcome.
EDIT 2!
Apparently, there's no way to calculate the colored area using mash information (at least according to my research). How I am looking for a creative way to achieve what I want. I would welcome and appreciate any suggestions.
A simple script to take screenshot then count the green pixels.
Put the script on the render camera, set m_TakeScreenshot to true, it'll work in the current frame.
public class ScreenshotCamera : MonoBehaviour
{
public bool m_TakeScreenshot;
public Texture2D m_OutputTexture;
void OnPostRender()
{
if (m_TakeScreenshot)
{
m_TakeScreenshot = false;
//Take screenshot
if (m_OutputTexture == null)
m_OutputTexture = new Texture2D(Screen.width, Screen.height);
m_OutputTexture.ReadPixels(new Rect(0, 0, Screen.width, Screen.height), 0, 0);
m_OutputTexture.Apply();
//Get all pixels, count green pixels
var pixels = m_OutputTexture.GetPixels(0, 0, m_OutputTexture.width, m_OutputTexture.height);
int greenPixels = 0, otherPixels = 0;
foreach (var color in pixels)
{
//green
if (color.g > 0.8f && color.r < 0.1f && color.b < 0.1f)
greenPixels++;
//not black
else if (color.r > 0.1f || color.g > 0.1f || color.b > 0.1f)
otherPixels++;
}
}
}
}
I would take only set of green vertices, compute its Delaunay triangulation and then find its area. Or, to get more precise result - compute outline of concave hull instead of Delaunay, and then use this pretty formula for area of arbitrary polygon.
I trying to slice Sprite(type casted to Texture2D) by script,
when project is running on Android or IOS Platform
is it possible by script??
I trying to use UnityEditor Class and it is work on Computer
but When I trying to Build Android or IOS It is failed.
void OnPreprocessTexture()
{
TextureImporter textureImporter = (TextureImporter)assetImporter;
textureImporter.textureType = TextureImporterType.Sprite;
textureImporter.spriteImportMode = SpriteImportMode.Multiple;
textureImporter.mipmapEnabled = false;
textureImporter.filterMode = FilterMode.Point;
}
public void OnPostprocessTexture(Texture2D texture)
{
Debug.Log("Texture2D: (" + texture.width + "x" + texture.height + ")");
int spriteSize = 350;
int colCount = texture.width / spriteSize;
int rowCount = texture.height / spriteSize;
List<SpriteMetaData> metas = new List<SpriteMetaData>();
for (int r = 0; r < rowCount; ++r)
{
for (int c = 0; c < colCount; ++c)
{
SpriteMetaData meta = new SpriteMetaData();
meta.rect = new Rect(c * spriteSize, r * spriteSize, spriteSize, spriteSize);
meta.name = c + "-" + r;
metas.Add(meta);
}
}
TextureImporter textureImporter = (TextureImporter)assetImporter;
textureImporter.spritesheet = metas.ToArray();
}
public void OnPostprocessSprites(Texture2D texture, Sprite[] sprites)
{
Debug.Log("Sprites: " + sprites.Length);
}
It is not working When running project on Android or IOS
[What I want]
Procedure
During running on Android or IOS Platform
1) Receive some Images from server (Url or file)
2) Load Image on C# script
3) Change type Images to Texture or Sprite ect...
4) Slice Images(Don't use Editor)
5) Save Pieces of Image
6) Use piece of Image
What I want is all procedure worked by Script
TextureImporter belongs to the UnityEditor namespace which doesn't exist in a built app but only within the Unity Editor itself. → You can not use this!
What you can do is using Sprite.Create to generate a sprite from a given Texture2D.
Cropping
If it is actually only about cutting out a certain part of the texture to use it as sprite than you only need to define in the rect parameter the part of the texture you want to use from that image.
// Wherever you get the texture from
Texture texture = ...;
// E.g. for using the center of the image
// but half of the size
var rect = new Rect(texture.width / 4, texture.height / 4, texture.width / 2, texture.height / 2);
// Create the sprite
var sprite = Sprite.Create(texture, rect, Vector2.one * 0.5f);
where rect is the
Location of the Sprite on the original Texture, specified in pixels.
Slicing
If you additionally want a slicing border (which you usually define in the Sprite Editor within Unity) there is an overload of Sprite.Create that additionally takes a border parameter e.g.
var borders = new Vector4(2, 2, 2, 2);
var sprite = Sprite.Create(texture, rect, Vector2.one * 0.5f, 100, SpriteMeshType.FullRect, borders);
where border
Returns the border sizes of the sprite.
X=left, Y=bottom, Z=right, W=top.
API doesn't say it but I guess like the rect values those values are also in pixels.
I solved using rect and Sprite Rnederer
here is my code
void Start()
{
rect = new Rect(0f, 0f, 255, 255);
this.GetComponent<SpriteRenderer>().sprite = Sprite.Create(img, rect, new Vector2(0.5f, 0.5f));
this.GetComponent<RectTransform>().localScale = new Vector3(100, 100, 0);
StartCoroutine(Update());
}
/*
* rect = new Rect(i, 0, 255, 255);
this.GetComponent<SpriteRenderer>().sprite = Sprite.Create(img, rect, new Vector2(0.5f, 0.5f));*/
IEnumerator Update()
{
while (true)
{
if (i < 1000)
{
i += 255;
if (i > 770)
{
i = 0;
}
}
yield return new WaitForSeconds(0.25f);
rect = new Rect(i, 0f, 255, 255);
this.GetComponent<SpriteRenderer>().sprite = Sprite.Create(img, rect, new Vector2(0.5f, 0.5f));
}
}
i am trying to crop a texture2d in xna. i have found the following code which will crop the image on the top and right sides, i have played around with the code and cannot figure a way to crop all sides at a specific interval. below is the code i have been trying to modify:
any help or ideas would be much appreciated.
Rectangle area = new Rectangle(0, 0, 580, 480);
Texture2D cropped = new Texture2D(heightMap1.GraphicsDevice, area.Width, area.Height);
Color[] data = new Color[heightMap1.Width * heightMap1.Height];
Color[] cropData = new Color[cropped.Width * cropped.Height];
heightMap1.GetData(data);
int index = 0;
for (int y = 0; y < area.Y + area.Height; y++) // for each row
{
for (int x = 0; x < area.X + area.Width; x++) // for each column
{
cropData[index] = data[x + (y * heightMap1.Width)];
index++;
}
}
cropped.SetData(cropData);
Here is the code to crop a texture. Note that the GetData method can already select rectangular subsection of the image - there is no need to manually crop.
// Get your texture
Texture2D texture = Content.Load<Texture2D>("myTexture");
// Calculate the cropped boundary
Rectangle newBounds = texture.Bounds;
const int resizeBy = 20;
newBounds.X += resizeBy;
newBounds.Y += resizeBy;
newBounds.Width -= resizeBy * 2;
newBounds.Height -= resizeBy * 2;
// Create a new texture of the desired size
Texture2D croppedTexture = new Texture2D(GraphicsDevice, newBounds.Width, newBounds.Height);
// Copy the data from the cropped region into a buffer, then into the new texture
Color[] data = new Color[newBounds.Width * newBounds.Height];
texture.GetData(0, newBounds, data, 0, newBounds.Width * newBounds.Height);
croppedTexture.SetData(data);
Of course, keep in mind that SpriteBatch.Draw can take a sourceRectangle parameter, so you may not even need to copy the texture data around at all! Just use a subsection of the original texture. For example:
spriteBatch.Draw(texture, Vector2.Zero, newBounds, Color.White);
(Where newBounds is calculated in the same way as in the first code listing.)
I'm currently working on a Windows Phone game similar to Tiny Wings and I've been having trouble with collision detection between the player's character and the hills. I've been looking into a few different ways to do this including the Farseer Physics engine and a Silverlight tutorial
Player's character initialization
lander = new Lander(new Vector2(graphics.PreferredBackBufferWidth / 4, 100));
LoadContent
protected override void LoadContent()
{
// Create a new SpriteBatch, which can be used to draw textures.
spriteBatch = new SpriteBatch(GraphicsDevice);
primitiveBatch = new PrimitiveBatch(GraphicsDevice);
// Load textures
landerTexture = this.Content.Load<Texture2D>(".\\Sprites\\boysmall");
// Initialize lander based on texture
lander.Width = landerTexture.Width;
lander.Height = landerTexture.Height;
// Load the parallaxing background
bgLayer1.Initialize(Content, "hillsbackground", GraphicsDevice.Viewport.Width, -2, 150);
bgLayer2.Initialize(Content, "hillsbackground2", GraphicsDevice.Viewport.Width, -3, 220);
// Load hills
string[] hillsArray = new string[2]{"textured","hillsmooth"};
mainHill.Initialize(Content, hillsArray, GraphicsDevice.Viewport.Width, -4);
// Load Sky
mainBackground.Initialize(Content, "mainbackground", GraphicsDevice.Viewport.Width, -1, 0);
}
I understand that fundamentally, collision detection looks for intersection points between two rectangles, and have done that for the "lander", but don't know how I can do it for the hills and how to make it slide down smoothly? let me know if you need any additional code, thanks for your help!
Rectangle attempt for Lander
public Rectangle GetScreenRectangle()
{
// calculate the rectangle from the current location
// and the current source rectangle
var rectangle = new Rectangle(
(int)graphics.PreferredBackBufferWidth / 4,
(int)100,
lander.Width,
lander.Height);
return rectangle;
}
Hills Code
class MainHill
{
// The image representing the parallaxing background
Texture2D texture;
// An array of positions of the parallaxing background
//Vector2[] positions;
// The speed which the background is moving
int speed;
// Object array holding position and texture of each live texture
object[,] positionsArray = new object[2, 2];
public void Initialize(ContentManager content, Array hillsArray, int screenWidth, int speed)
{
// Load the background texture we will be using
//texture = content.Load<Texture2D>("textured");
// Set the speed of the background
this.speed = speed;
// If we divide the screen with the texture width then we can determine the number of tiles need.
// We add 1 to it so that we won't have a gap in the tiling
//positions = new Vector2[screenWidth / texture.Width + 2];
texture = content.Load<Texture2D>("textured");
// Set the initial positions of the parallaxing background
for (int i = 0; i < screenWidth / texture.Width + 2; i++)
{
//Pull out random texture
Random random = new Random();
string[] randomHill = new string[2];
randomHill[0] = "textured";
randomHill[1] = "hillsmooth";
string currentString = randomHill[(int)(random.Next(0, 2))];
texture = content.Load<Texture2D>(currentString);
// We need the tiles to be side by side to create a tiling effect
positionsArray[i,0] = new Vector2(i * texture.Width, 290);
positionsArray[i, 1] = texture;
}
}
public void Update(ContentManager content)
{
Debug.WriteLine("=========================");
// Update the positions of the background
for (int i = 0; i < positionsArray.GetLength(0); i++)
{
Vector2 current_position = (Vector2)positionsArray[i, 0];
// Update the position of the screen by adding the speed
current_position.X += speed;
// Check the texture is out of view then put that texture at the end of the screen
if (current_position.X <= -texture.Width)
{
// Figure out a possibly new texture if it's out of view
Random random = new Random();
string[] newHill = new string[2];
newHill[0] = "textured";
newHill[1] = "hillsmooth";
string currentString = newHill[(int)(random.Next(0, 2))];
texture = content.Load<Texture2D>(currentString);
Color[] textureData = new Color[texture.Width * texture.Height];
texture.GetData(textureData);
current_position.X = texture.Width * (positionsArray.GetLength(0) - 1);
positionsArray[i, 1] = texture;
}
positionsArray[i, 0] = current_position;
}
}
public void Draw(SpriteBatch spriteBatch, ContentManager content)
{
for (int i = 0; i < positionsArray.GetLength(0); i++)
{
Vector2 current_position = (Vector2)positionsArray[i, 0];
//Random random = new Random();
//string[] hillsArray = new string[2];
//hillsArray[0] = "textured";
//hillsArray[1] = "hillsmooth";
//string currentString = hillsArray[(int)(random.Next(0,2))];
//texture = content.Load<Texture2D>(currentString);
texture = (Texture2D)positionsArray[i, 1];
spriteBatch.Draw(texture, current_position, Color.White);
}
}
}
Okay, I have a 2d Tile Map editor I'm working on in xna c#.
In the Draw method I loop through (with a 'for' loop) my 2 dimensional array of tiles so that
my map updates and draws all the tiles every frame.
My question is, how do you draw only the tiles that are seen on screen.
Also is there a better way to draw the tile map (Rather than updating every frame).
In the platformer demo I played around with the visible tiles were calculated and then only those tiles were drawn. I believe you will have to include them in the draw method to be drawn in each time.
Here is a snippet (this only had left to right scrolling so no vertical range was calculated). This kept track of the camera position to calculate it.
Edit:: Added the second method shows how it updated camera position based on the player position stored in a player object.
private void DrawTiles(SpriteBatch spriteBatch)
{
// Calculate the visible range of tiles.
int left = (int)Math.Floor(cameraPosition / Tile.Width);
int right = left + spriteBatch.GraphicsDevice.Viewport.Width / Tile.Width;
right = Math.Min(right, Width - 1);
// For each tile position
for (int y = 0; y < Height; ++y)
{
for (int x = left; x <= right; ++x)
{
// If there is a visible tile in that position
Texture2D texture = tiles[x, y].Texture;
if (texture != null)
{
// Draw it in screen space.
Vector2 position = new Vector2(x, y) * Tile.Size;
spriteBatch.Draw(texture, position, Color.White);
}
}
}
}`
private void ScrollCamera(Viewport viewport)
{
const float ViewMargin = 0.35f;
// Calculate the edges of the screen.
float marginWidth = viewport.Width * ViewMargin;
float marginLeft = cameraPosition + marginWidth;
float marginRight = cameraPosition + viewport.Width - marginWidth;
// Calculate how far to scroll when the player is near the edges of the screen.
float cameraMovement = 0.0f;
if (Player.Position.X < marginLeft)
cameraMovement = Player.Position.X - marginLeft;
else if (Player.Position.X > marginRight)
cameraMovement = Player.Position.X - marginRight;
// Update the camera position, but prevent scrolling off the ends of the level.
float maxCameraPosition = Tile.Width * Width - viewport.Width;
cameraPosition = MathHelper.Clamp(cameraPosition + cameraMovement, 0.0f, maxCameraPosition);
}
int MapSizeX = 20;
int MapSizeY = 20;
int LeftCornerX = 0; //the position of the Tile in the 2Darray that is going
int LeftCornerY = 0; //to be drawn in the left corner of the screen.
int ScreenSizeX = 10;
int ScreenSizeY = 10;
public Tiles[,] tiles = new Tile[MapSizeX, MapSizeY]; //list of all Tiles
//then you can draw it like this....
int counterX = 0; //represents the position on screen
int counterY = 0;
// y and x inside the for loops represents the position in tiles
for(int y = LeftCornerY; y < MapSizeY < y++)
{
for(int x = LeftCornerX; y < MapSizeX < x++)
{
if(counterX < ScreenSizeX && counterY < ScreenSizeY)
{
tiles[x, y].draw(tiles[counterX , counterY]);
}
counterX ++;
//when you do like this you draw the tiles you want
//at the position you want. In the draw method you just
// drawn the tile you want at the position of the tile you
// send as in parameter to the draw method.
}
counterY++;
counterX = 0;
}
then you just have to increase the LeftCorner variables to draw another part of the map