I am making a simple process which will create a colour changing spiral so I can test a range of variables and learn some C#. However, though I can not find a problem in the code, when I debug it, I am returned with a blank blue screen. Can any one find the problem. Here is all the code containing the variables needed for the ball point:
Vector2 Tripos;
List<Color> Tricol;
List<Vector2> datatripos;
List<int> count;
Color currentcol;
float Tri_angle;
float Triscale;
int Tri_speed;
int screenwidth;
int screenheight;
int addtocount;
Texture2D Ball;
int colourchangespeed;
protected override void LoadContent()
{
// Create a new SpriteBatch, which can be used to draw textures.
Tripos = new Vector2(screenwidth / 2, screenheight / 2);
Triscale = 1;
Tri_angle = 1;
Tri_speed = 1;
colourchangespeed = 1;
Ball = Content.Load<Texture2D>("ball");
currentcol = new Color(0, 0, 0);
addtocount = 0;
datatripos = new List<Vector2>();
Tricol = new List<Color>();
}
This is called by the update method:
private void Posgen()
{
Tripos.X += (float)Math.Sin(MathHelper.ToRadians(Tri_angle))*Tri_speed;
Tripos.Y += (float)Math.Cos(MathHelper.ToRadians(Tri_angle))*Tri_speed;
Tri_angle++;
}
private void colchanger()
{
currentcol.R += (byte)colourchangespeed;
if (currentcol.R == 255)
{
currentcol.R = 0;
currentcol.G += (byte)colourchangespeed;
}
if (currentcol.G == 255)
{
currentcol.G = 0;
currentcol.B += (byte)colourchangespeed;
}
if (currentcol.B == 255)
{
currentcol.B = 0;
}
}
private void dataadd()
{
addtocount++;
Tricol.Add(currentcol);
datatripos.Add(Tripos);
count.Add(addtocount);
}
Called by the draw method:
private void drawtri()
{
foreach (Vector2 data in datatripos)
{
spriteBatch.Draw(Ball, data, null, currentcol, 0, new Vector2(5, 5), Triscale, SpriteEffects.None, 0);
}
}
If you want the full code ask in advance. There are some variables I don't use but I intend to use for later so ignore these.
Thanks in advance.
Yours Mona.
Check that you are calling dataadd().
As a precaution, colourchangespeed should be declared as a byte rather than as an int because you're only casting to a byte anyway. When checking you colour values, the current value should be compared as >= 255 in the case that colourchangespeed is not 1.
A tip to writing good questions: Remove everything that's unrelated. Everything.
Related
I've created a procedural mesh script while watching one of Freya Holmér's improvised live course vods, and re purposed the code to create a procedural tube mesh with subdivision and plenty of other niche features.
But, after looking over the code and the lesson, I still cannot for the life of me figure out why sometimes I will get an:
argument out of range exception
...and sometimes I won't depending on the level of subdivision; also, entire faces wont be generated by the script.
TL;DR Problems list:
Argument out of range exception (Depending on level of subdivision).
Entire sides/faces of the tube mesh will not be generated, even when no errors are provided.
These problems are stemming from line 154 in the UpdateTris() method.
Code
using System.Collections.Generic;
using UnityEngine;
#if UNITY_EDITOR
using UnityEditor;
using OpenNexus.ExtraGizmos;
#endif
using OpenNexus.BaseMath;
using OpenNexus.MeshFormat;
namespace OpenNexus.Procedurals
{
[RequireComponent(typeof(MeshFilter))]
public class TubeMesh : MonoBehaviour
{
private MeshFilter filter;
private Mesh mesh;
public List<Vector3> Points = new List<Vector3>()
{
new Vector3(0, 0, 0),
new Vector3(0, 1, 1),
new Vector3(0, 0, 2)
};
[Header("Bezier Data")]
public Precision BezierPrecision = Precision.Fast;
[Header("Tube Data")]
[Range(0.01f, 1f)]public float Radius = 0.01f;
[Range(3, 32)] public int Segments = 8;
[Range(3, 6)] public int Subdivisions = 3;
[Header("Mesh Data")]
public ProceduralMesh2D BaseProceduralMesh = new ProceduralMesh2D();
public List<Vector3> Vertices;
public List<int> Tris;
private void OnEnable()
{
if (!GetComponent<MeshRenderer>()) // Check for and add missing mesh renderer.
gameObject.AddComponent<MeshRenderer>();
if (filter == null) // Check for and assign mesh filter variable.
filter = GetComponent<MeshFilter>();
if (mesh == null) // Check for and instantiate a new mesh object.
mesh = new Mesh();
mesh.name = "TubeMesh"; // Set name to mesh object.
filter.sharedMesh = mesh; // Set MeshFilter's shared mesh variable to new mesh object.
}
private void Update()
{
/*
Data reset
------------------------------
*/
// Reset base mesh data.
BaseProceduralMesh.Vertices = new List<Vertex>();
BaseProceduralMesh.LineIndex = new List<int>();
// Reset mesh data.
Vertices = new List<Vector3>();
Tris = new List<int>();
/*
Data update
------------------------------
*/
// Update base mesh.
UpdateBaseMesh();
// Update mesh data.
UpdateVertices();
UpdateTris();
}
private void LateUpdate() => UpdateMesh();
private BezierPoint GetBezierPoint(int index)
{
float _t = index / (Segments - 1f);
BezierPoint _bp = BezierMath.QuadraticBezier(Points, BezierPrecision, _t);
return _bp;
}
private void UpdateBaseMesh()
{
// Generate base vertices.
for (int i = 0; i < Subdivisions; i++)
{
float _point = i / (float)Subdivisions;
float _radius = _point * Floats.TAU;
Vertex _vertex = new Vertex(VectorThrees.UnitVectorByAngle(_radius) * Radius);
BaseProceduralMesh.Vertices.Add(_vertex);
}
// Generate base LineIndexes.
for (int i = 0; i < BaseProceduralMesh.VertexCount; i++)
{
BaseProceduralMesh.LineIndex.Add(i);
}
BaseProceduralMesh.LineIndex.Add(0);
}
private void UpdateVertices()
{
for (int i = 0; i < Segments; i++)
{
BezierPoint _point = GetBezierPoint(i);
for (int j = 0; j < BaseProceduralMesh.VertexCount; j++)
{
Vertices.Add(_point.LocalToWorldPosition(BaseProceduralMesh.Vertices[j].Point));
}
}
}
private void UpdateTris()
{
for (int s = 0; s < Segments - 1; s++)
{
int _root = s * BaseProceduralMesh.VertexCount;
int _rootNext = (s + 1) * BaseProceduralMesh.VertexCount;
for (int i = 0; i < BaseProceduralMesh.EdgeCount; i+=2)
{
int _lineA = BaseProceduralMesh.LineIndex[i];
int _lineB = BaseProceduralMesh.LineIndex[i + 1];
int _currentA = _root + _lineA;
int _currentB = _root + _lineB;
int _nextA = _rootNext + _lineA;
int _nextB = _rootNext + _lineB;
Tris.Add(_currentA);
Tris.Add(_nextA);
Tris.Add(_nextB);
Tris.Add(_currentA);
Tris.Add(_nextB);
Tris.Add(_currentB);
}
}
}
private void UpdateMesh()
{
mesh.Clear();
mesh.SetVertices(Vertices);
mesh.SetTriangles(Tris, 0);
mesh.RecalculateNormals();
}
#if UNITY_EDITOR
private void OnDrawGizmos()
{
// Draw psudo mesh with gizmos.
/*
Draw segment/edge loops
-------------------------------------
*/
for (int i = 0; i < Segments; i++) // Debug each segment, and what their 2D mesh segment should look like.
{
BezierPoint _point = GetBezierPoint(i);
WireGizmos.DrawWireCircle(_point.Position, _point.Rotation, Radius, Subdivisions);
}
Gizmos.color = Color.red;
for (int i = 0; i < Vertices.Count; i++) // Debug each vertex.
{
Gizmos.DrawSphere(Vertices[i], 0.01f);
Handles.Label(Vertices[i], "\n\nVertex: " + i + "\n\nVertex position:\n" + Vertices[i].ToString());
}
for (int i = 0; i < Tris.Count; i++)
{
Gizmos.DrawLine(Vertices[Tris[i]], Vertices[Tris[(i + 1) % Tris.Count]]);
}
}
#endif
}
}
I've already looked over my code compared to the code in the video, it's fundamentally the same, with the main differences being, how I'm creating the 2D mesh format for the script to work with, and the structure of the code.
After looking back at what they had done compared to mine, I just don't see how I'm running into this issue.
Things I've tried
Change the loop iteration i+=2 -to- i++ (This spits out the exception, but generates the first section of the tube before getting stuck between the second vertex in the next segment, and vert 0).
Every suggestion I try from this question, I will update the "Things I've tried..." list.
Please let me know if I need to clarify anything in this post, and if you wish to see the other classes/structs referenced in this script.
After a day of resting, and the a couple of hours of testing different values and questioning the code. I've found the problem.
The real issue
The nested for loop in the UpdateTris() method was going up by twos assuming I was making a hard edge mesh with pared vertices. This caused the loop to skip over an entire face of the mesh, and causing the
ArgumentOutOfRangeException
...when the Subdivision value was an even number.
My solution
I had to bring it back to the default single iteration (since I was trying to make a smooth lighting mesh), the second issue with the for loop was the iteration limit BaseProceduralMesh.LineCount needing to be subtracted by one since that was causing another
ArgumentOutOfRangeException
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;
}
}
I just started to learn XNA/MonoGame and I encountered a weird exception.
The error says: The method or operation is not implemented.
And what's even more weird that a very similar code, almost the same, works. The only difference is that the other code is run on XNA and on another computer, and my code runs on MonoGame.
The code is supposed to make an animation from a sprite sheet.
Inside of my class, Animate:
public void set_state(string name, string state)
{
this.name = name;
this.state = state;
}
public void animate(int frameIndex)
{
this.frameIndex = frameIndex;
this.animatedTexture = Game1.contentManager.Load<Texture2D>(name + '/' + state);
prepare_frames();
while (this.frameIndex > rectangles.Count )
{
frameIndex = frameIndex - rectangles.Count;
}
base.draw(animatedTexture, rectangles[frameIndex], origins[frameIndex]);
}
public void prepare_frames()
{
find_dots();
find_rectangles();
find_origins();
}
public void find_dots()
{
cols = new Color[animatedTexture.Width];
lowestRectangle = new Rectangle(0, animatedTexture.Height - 1, animatedTexture.Width, 1);
animatedTexture.GetData<Color>(0, lowestRectangle, cols, 0, animatedTexture.Width);
for (int i = 0; i < cols.Length; i++)
{
if (cols[i] == Color.Black)
{
dots.Add(new Vector2(i, animatedTexture.Height));
}
}
}
public void find_rectangles()
{
for (int i = 0; i < dots.Count-2; i+=2)
{
rectangles.Add(new Rectangle((int)dots[i].X, 0, (int)dots[i+2].X - (int)dots[i].X, animatedTexture.Height-1));
}
}
public void find_origins()
{
for (int i = 1; i < dots.Count; i++)
{
if (i%2 != 0)
{
origins.Add(dots[i]);
}
}
}
the idea behind is that there is a line of dots below the sprite sheet, with those dots i can make frames from the sprite sheet.
Here is the data of the class Animated:
#region data
Texture2D animatedTexture;
string name, state; // to determine the animated state.
Rectangle lowestRectangle; // is the rectangle of the dot's.
Color[] cols; // this array is for the colors on the dot's rectungle.
List<Vector2> dots = new List<Vector2>(); // this list is for the dot's coordinates on the dot's rectungle.
List<Rectangle> rectangles = new List<Rectangle>(); // this list is for the new rectungles, each rectungle is a diffirent frame from the sprite sheet.
List<Vector2> origins = new List<Vector2>(); // this list is for each origin point of the new retungles.
int frameIndex;
#endregion
Here is the part that summons the methods above, in the main class of the MonoGame, Game1:
protected override void Draw(GameTime gameTime)
{
GraphicsDevice.Clear(Color.CornflowerBlue);
spriteBatch.Begin();
if (Keyboard.GetState().IsKeyDown(Keys.Right))
{
player.set_state("moshe", "run");
player.animate(frameIndex);
frameIndex++;
}
else
player.draw();
spriteBatch.End();
base.Draw(gameTime);
}
So the error occurs in this line:
animatedTexture.GetData<Color>(0, lowestRectangle, cols, 0, animatedTexture.Width);
in the method animate in the class Animate. ( The method or operation is not implemented.) When I press the right key. Why does that happens?
Quite honestly that is a big difference, between XNA and a port of it.
A NotImplementedException does exactly what it suggest, it is thrown when a method or operation has not been implemented.
Nothing appears to be documented much about this, but it has been reported to the MonoGame bug tracker and is assigned to a developer for the 3.x release.
Using the SharpDX version however, this error does not exist.
I would like to say sorry in advance for the amount of code I will post, but I can't seem to get my collision detection to work, the player and the objects pass through each other with no effect when I play test.
I receive 0 warnings or errors, but the Player playerBot object does not seem to interact with any of the level items I have imported from GLEED2D.
One thing I did was to store the values of my item's rectangles and color arrays in lists so they could be all easily iterated through, maybe this is the source of the problem.
If you can spot why my code is not working I will be hugely grateful. I have removed any code that is definitely not relevant, and I am running VS 2010 with GLEED2D 1.3 if that helps.
Thanks again.
// Item Class ImageItem Downcast
public class ImageItem : Item
{
public Texture2D Texture;
}
// Level
Level level;
// Ints
int iNumOfItems = 0;
int iTextureDataListNum = 0;
int iRectangleListNum = 0;
// Lists
List<Color []> itemTextureDataList = new List<Color[]>();
List<Rectangle> itemRectangleList = new List<Rectangle>();
protected override void Initialize()
{
if (filename.Length > 0) level = Level.FromFile(filename, Content);
else level = Level.FromFile("level1.xml", Content);
foreach (Layer layer in level.Layers)
{
foreach (Item item in layer.Items)
{
iNumOfItems =+ 1;
}
}
// Creates Player Ship
playerBot = new Player(new Vector2(400f, 240f), new Vector2(0f, 0f));
base.Initialize();
}
protected override void LoadContent()
{
Texture2D pixel = new Texture2D(GraphicsDevice, 1, 1, false, SurfaceFormat.Color);
pixel.SetData(new[] { Color.White });
spriteBatch = new SpriteBatch(GraphicsDevice);
// Player Bot
playerBot.LoadContent(Content, "Images/Player Bot Sprite Sheet", 40, 40, 4);
// Assigns level textures color data to array
foreach (Layer layer in level.Layers)
{
foreach (Item item in layer.Items)
{
ImageItem imageItem = item as ImageItem;
if (imageItem != null)
{
Texture2D texture = imageItem.Texture;
itemTextureDataList[iTextureDataListNum] = new Color[imageItem.Texture.Width * imageItem.Texture.Height];
imageItem.Texture.GetData(itemTextureDataList[iTextureDataListNum]);
iTextureDataListNum++;
}
}
}
// Creates a rectangle for every level texture
foreach (Layer layer in level.Layers)
{
foreach (Item item in layer.Items)
{
ImageItem imageItem = item as ImageItem;
if (imageItem != null)
{
itemRectangleList[iRectangleListNum] = new Rectangle((int)imageItem.Position.X, (int)imageItem.Position.Y, imageItem.Texture.Width, imageItem.Texture.Height);
iRectangleListNum++;
}
}
}
spriteBatch = new SpriteBatch(GraphicsDevice);
}
protected override void Update(GameTime gameTime)
{
// Player Update
playerBot.Update(gameTime);
((Sprite)playerBot).Update(gameTime);
// Check for player collisons with level
for (int i = 0; i < iNumOfItems - 1; i++)
{
if (IntersectPixels(playerBot.colRectangle, playerBot.textureDataArray, itemRectangleList[i], itemTextureDataList[i]) == true)
{
playerBot.StopMovement();
}
}
base.Update(gameTime);
}
// Level Collision Detection Method
static bool IntersectPixels(Rectangle rectangleA, Color[] dataA, Rectangle rectangleB, Color[] dataB)
{
// Find the bounds of the rectangle intersection
int top = Math.Max(rectangleA.Top, rectangleB.Top);
int bottom = Math.Min(rectangleA.Bottom, rectangleB.Bottom);
int left = Math.Max(rectangleA.Left, rectangleB.Left);
int right = Math.Min(rectangleA.Right, rectangleB.Right);
// Check every point within the intersection bounds
for (int y = top; y < bottom; y++)
{
for (int x = left; x < right; x++)
{
// Get the color of both pixels at this point
Color colorA = dataA[(x - rectangleA.Left) + (y - rectangleA.Top) * rectangleA.Width];
Color colorB = dataB[(x - rectangleB.Left) + (y - rectangleB.Top) * rectangleB.Width];
// If both pixels are not completely transparent
if (colorA.A != 0 && colorB.A != 0)
{
// Then an intersection has been found
return true;
}
}
}
// No intersection fond
return false;
}
// Sprite Class
public void Update(GameTime gameTime)
{
textureDataArray = new Color[texture.Width * texture.Height];
texture.GetData(textureDataArray);
// Player Class
public void StopMovement()
{
velocity.X *= -1;
velocity.Y *= -1;
}
The first thing I'll say here is, you should aim to be more Object Oriented in your approach. Storing a list of textures and a list of rectangles alongside your list of Items is "bad" technique and going to eventually cause you some massive headaches when it comes to debugging.
So first of all, instead of having a list of Color[] and a list of Rectangle, add one Color[] and one Rectangle to your ImageItem class and work with those instead, or at least create a little class called "CollisionData" that has a Rectangle and a Color[] and store those in a single list.
Secondly, note that there is a Rectangle.Intersect(Rectangle A, Rectangle B) that gets your the rectangle of intersection. So you can tidy up your code a bit by using that.
Your color checking can be simplified to (ColorA.A * ColorB.A != 0) as either being zero will
cause the result to be zero.
Regarding not getting any errors, put a breakpoint at the start of the collision checking loop. Does the application break? If yes, what is the value of iNumItems? (you can hover over it to see the current value at point of breaking). If no, then that section of code isn't being reached. Put another breakpoint a bit further back and a bit further back until it gets hit, then figure out why the code isn't executing.
I am working on a space shooter game using XNA and have followed multiple tutorials to create a parallax background. So far I can get it to go along one axis, either X or Y, but not both at the same time. I have a camera class that follows the player, which the player moves (instead of the 'world'), since I figured it would be easier to just move the player versus moving everything else around the player.
So far, the background doesn't keep up with the player, and it also can't comprehend both axis at the same time. I thought about a tile engine, but that wouldn't let me parallax different layers would it?
Could anyone help me understand what I need to do, or recommend a tutorial that can do both axis at the same time? I can't seem to find the answer on my own this time.
Here is the code for my background class:
class Background
{
// Textures to hold the two background images
Texture2D spaceBackground, starsParallax;
int backgroundWidth = 2048;
int backgroundHeight = 2048;
int parallaxWidth = 2048;
int parallaxHeight = 2048;
int backgroundWidthOffset;
int backgroundHeightOffset;
int parallaxWidthOffset;
int parallaxHeightOffset;
public int BackgroundWidthOffset
{
get { return backgroundWidthOffset; }
set
{
backgroundWidthOffset = value;
if (backgroundWidthOffset < 0)
{
backgroundWidthOffset += backgroundWidth;
}
if (backgroundWidthOffset > backgroundWidth)
{
backgroundWidthOffset -= backgroundWidth;
}
}
}
public int BackgroundHeightOffset
{
get { return backgroundHeightOffset; }
set
{
backgroundHeightOffset = value;
if (backgroundHeightOffset < 0)
{
backgroundHeightOffset += backgroundHeight;
}
if (backgroundHeightOffset > backgroundHeight)
{
backgroundHeightOffset -= backgroundHeight;
}
}
}
public int ParallaxWidthOffset
{
get { return parallaxWidthOffset; }
set
{
parallaxWidthOffset = value;
if (parallaxWidthOffset < 0)
{
parallaxWidthOffset += parallaxWidth;
}
if (parallaxWidthOffset > parallaxWidth)
{
parallaxWidthOffset -= parallaxWidth;
}
}
}
public int ParallaxHeightOffset
{
get { return parallaxHeightOffset; }
set
{
parallaxHeightOffset = value;
if (parallaxHeightOffset < 0)
{
parallaxHeightOffset += parallaxHeight;
}
if (parallaxHeightOffset > parallaxHeight)
{
parallaxHeightOffset -= parallaxHeight;
}
}
}
// Constructor when passed a Content Manager and two strings
public Background(ContentManager content,
string sBackground, string sParallax)
{
spaceBackground = content.Load<Texture2D>(sBackground);
backgroundWidth = spaceBackground.Width;
backgroundHeight = spaceBackground.Height;
starsParallax = content.Load<Texture2D>(sParallax);
parallaxWidth = starsParallax.Width;
parallaxHeight = starsParallax.Height;
}
public void Draw(SpriteBatch spriteBatch)
{
// Draw the background panel, offset by the player's location
spriteBatch.Draw(
spaceBackground,
new Rectangle(-1 * backgroundWidthOffset,
-1 * backgroundHeightOffset,
backgroundWidth,
backgroundHeight),
Color.White);
// If the right edge of the background panel will end
// within the bounds of the display, draw a second copy
// of the background at that location.
if (backgroundWidthOffset > backgroundWidth)
{
spriteBatch.Draw(
spaceBackground,
new Rectangle(
(-1 * backgroundWidthOffset) + backgroundWidth, 0,
backgroundWidth, backgroundHeight),
Color.White);
}
else //(backgroundHeightOffset > backgroundHeight - viewportHeight)
{
spriteBatch.Draw(
spaceBackground,
new Rectangle(
0, (-1 * backgroundHeightOffset) + backgroundHeight,
backgroundHeight, backgroundHeight),
Color.White);
}
// Draw the parallax star field
spriteBatch.Draw(
starsParallax,
new Rectangle(-1 * parallaxWidthOffset,
0, parallaxWidth,
parallaxHeight),
Color.SlateGray);
// if the player is past the point where the star
// field will end on the active screen we need
// to draw a second copy of it to cover the
// remaining screen area.
if (parallaxWidthOffset > parallaxWidth)
{
spriteBatch.Draw(
starsParallax,
new Rectangle(
(-1 * parallaxWidthOffset) + parallaxWidth,
0,
parallaxWidth,
parallaxHeight),
Color.White);
}
}
}
The main game then has ties to move the backgrounds, along with the player.
background.BackgroundWidthOffset -= 2;
background.ParallaxWidthOffset -= 1;
Visually, the background is sort of jumpy, and seems to randomly skip or overlap background tiles.
I've used this method in the past with great results:
http://www.david-gouveia.com/scrolling-textures-with-zoom-and-rotation/
It uses a shader to accomplish the effect, resulting in a fast implementation.
There is a complete example here.