I have two classes, Main and Grid. Grid simply makes a grid of square pixels. In my Main class, I want to get the list that was create in the Grid class. I managed to figure it out, but I'm wondering if there's a way to optimize the code.
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using System;
using System.Diagnostics;
using System.Collections.Generic;
namespace teeeest
{
public class Grid
{
Texture2D image;
Color color;
int rows;
int columns;
float outerThickness;
float innerThickness;
Vector2 size;
Vector2 origin;
Vector2 dotSize;
List<Pixel> pixels = new List<Pixel>(0);
public Grid(Texture2D image, int rows, int columns, float outerThickness, float innerThickness, Vector2 size, Vector2 origin, Vector2 dotSize, Color color)
{
this.dotSize = dotSize;
this.origin = origin;
this.color = color;
this.image = image;
this.rows = rows;
this.columns = columns;
this.outerThickness = outerThickness;
this.innerThickness = innerThickness;
this.size = size;
}
public void Update()
{
float sizeX = size.X / (columns - 1);
float sizeY = size.Y / (rows - 1);
for (int i = 0; i < rows; i++)
{
for (int g = 0; g < columns; g++)
{
Pixel p = new Pixel(image, 3, new Vector2((g * sizeX) + origin.X, sizeY * i + origin.Y), new Vector2(image.Width / 2, image.Height / 2), color);
pixels.Add(p);
}
}
}
public virtual void Draw(SpriteBatch hspritebatch, List<Grid> grids)
{
foreach (Pixel p in pixels)
{
hspritebatch.Draw(
texture: p.getImage(),
position: p.getPosition(),
sourceRectangle: null,
p.getColor(),
rotation: 0,
origin: new Vector2(image.Width / 2, image.Height),
scale: new Vector2(dotSize.X * .02f, dotSize.Y * .02f),
SpriteEffects.None,
0);
}
}
public Texture2D getImage()
{
return image;
}
public Vector2 getPosition()
{
return origin;
}
public Vector2 getOrigin()
{
return new Vector2(image.Width / 2, image.Height);
}
public Color getColor()
{
return color;
}
public List<Pixel> getList()
{
Update(); # This seems unnecessary. Is it?
return pixels;
}
}
}
The problem lies in the getList() function. In order to return the correct pixel list that was edited in the Update function, my solution there is to call that function right before returning the list. However, this seems costly for no reason. Is there a way around this without calling the Update function, or is this the only way?
I realize there's been posts similar to this, but I just don't understand them. I'm very much a beginner at coding. Here is my Main class.
using System;
using System.Diagnostics;
using System.Collections.Generic;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Graphics;
namespace teeeest
{
public class Game1 : Game
{
private GraphicsDeviceManager _graphics;
private SpriteBatch _spriteBatch;
private SpriteFont font;
private Texture2D ball;
private Texture2D square;
private Color color = Color.White * .1f;
private Vector2 MouseCoords;
private Vector2 winMiddle;
private Vector2 ballOrigin;
private bool leftDown;
private bool eDown;
private int winWidth;
private int winHeight;
List<Line> lines = new List<Line>(0);
List<Grid> grids = new List<Grid>(0);
List<Pixel> pixels = new List<Pixel>(0);
List<Pixel> test = new List<Pixel>(0);
public Game1()
{
_graphics = new GraphicsDeviceManager(this);
Content.RootDirectory = "Content";
IsMouseVisible = true;
_graphics.PreferredBackBufferWidth = 800;
_graphics.PreferredBackBufferHeight = 600;
}
protected override void Initialize()
{
base.Initialize();
}
protected override void LoadContent()
{
_spriteBatch = new SpriteBatch(GraphicsDevice);
ball = Content.Load<Texture2D>("ball");
square = Content.Load<Texture2D>("square");
font = Content.Load<SpriteFont>("File");
ballOrigin = new Vector2(ball.Width / 2, ball.Height / 2);
winWidth = _graphics.PreferredBackBufferWidth;
winHeight = _graphics.PreferredBackBufferHeight;
winMiddle = new Vector2(winWidth / 2, winHeight / 2);
}
protected override void Update(GameTime gameTime)
{
lines.Clear();
grids.Clear();
pixels.Clear();
if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed || Keyboard.GetState().IsKeyDown(Keys.Escape))
Exit();
if (Mouse.GetState().LeftButton == ButtonState.Released)
{
leftDown = false;
}
if (Mouse.GetState().LeftButton == ButtonState.Pressed && !leftDown)
{
Pixel g = new Pixel(ball, 5, MouseCoords, new Vector2(ball.Width / 2, ball.Height / 2), Color.Blue);
pixels.Add(g);
}
if (Keyboard.GetState().IsKeyUp(Keys.E))
{
eDown = false;
}
if (Keyboard.GetState().IsKeyDown(Keys.E) && !eDown)
{
color *= 1.1f;
eDown = true;
}
MouseCoords = new Vector2(Mouse.GetState().X, Mouse.GetState().Y);
Grid q = new Grid(ball, 10, 10, 7, 3, new Vector2(500, 500), new Vector2(30, 30), new Vector2(.2f, .2f), Color.White);
grids.Add(q);
# Here is where I'm calling the getList() function.
System.Console.WriteLine(q.getList()[7].getPosition());
# Here is where I'm calling the getList() function.
foreach (Line s in lines)
{
s.Update();
}
foreach (Grid gh in grids)
{
gh.Update();
}
base.Update(gameTime);
}
protected override void Draw(GameTime gameTime)
{
GraphicsDevice.Clear(Color.Black);
_spriteBatch.Begin(SpriteSortMode.Immediate, BlendState.AlphaBlend);
foreach (Line l in lines)
{
l.Draw(_spriteBatch, lines);
}
foreach (Grid g in grids)
{
g.Draw(_spriteBatch, grids);
}
foreach (Pixel p in pixels)
{
_spriteBatch.Draw(
texture: p.getImage(),
position: p.getPosition(),
sourceRectangle: null,
p.getColor(),
rotation: 0,
origin: p.getOrigin(),
scale: new Vector2(.02f, .02f),
SpriteEffects.None,
0);
}
_spriteBatch.DrawString(font,
MouseCoords.ToString(),
new Vector2 (winWidth - 100, 10),
Color.White,
rotation: 0,
origin: new Vector2(0, 0),
scale: new Vector2(1, 1),
SpriteEffects.None,
0);
_spriteBatch.End();
base.Draw(gameTime);
}
}
}
You could only call Update() when the List is EMPTY?
public List<Pixel> getList()
{
if (pixels.Count == 0)
{
Update(); // now it only gets called when pixels is EMPTY
}
return pixels;
}
This type of check may need to be done in Update() as well if it can be called directly from other places so you don't end up with more Pixel instances in it than you were expecting.
I write the program in the console, at startup, first play the music, and then the animation. Help make animation and music at the same time. Rummaged through the Internet and found nothing
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Drawing;
using System.Drawing.Imaging;
using System.Media;
using System.Threading;
namespace Animation_and_music
{
class animation
{
public void music()
{
SoundPlayer player = new SoundPlayer("C:\\audio.wav");
player.PlaySync();
}
public void gif()
{
Console.SetWindowSize(102, 49);
Image image = Image.FromFile(#"1.gif");
FrameDimension dimension = new FrameDimension(image.FrameDimensionsList[0]);
int frameCount = image.GetFrameCount(dimension);
StringBuilder sb;
int left = Console.WindowLeft, top = Console.WindowTop;
char[] chars = { '#', '#', '#', '%', '=', '+', '*', ':', '-', '.', ' ' };
for (int i = 0; ; i = (i + 1) % frameCount)
{
sb = new StringBuilder();
image.SelectActiveFrame(dimension, i);
for (int h = 0; h < image.Height; h++)
{
for (int w = 0; w < image.Width; w++)
{
Color cl = ((Bitmap)image).GetPixel(w, h);
int gray = (cl.R + cl.R + cl.B) / 3;
int index = (gray * (chars.Length - 1)) / 255;
sb.Append(chars[index]);
}
sb.Append('\n');
}
Console.SetCursorPosition(left, top);
Console.Write(sb.ToString());
System.Threading.Thread.Sleep(50);
}
}
static Image ScaleImage(Image source, int width, int height)
{
Image dest = new Bitmap(width, height);
using (Graphics gr = Graphics.FromImage(dest))
{
gr.FillRectangle(Brushes.White, 0, 0, width, height);
gr.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic;
float srcwidth = source.Width;
float srcheight = source.Height;
float dstwidth = width;
float dstheight = height;
if (srcwidth <= dstwidth && srcheight <= dstheight)
{
int left = (width - source.Width) / 2;
int top = (height - source.Height) / 2;
gr.DrawImage(source, left, top, source.Width, source.Height);
}
else if (srcwidth / srcheight > dstwidth * dstheight)
{
float cy = srcheight / srcwidth * dstwidth;
float top = ((float)dstheight - cy) / 2.0f;
if (top < 1.0f) top = 0;
gr.DrawImage(source, 0, top, dstwidth, cy);
}
else
{
float cx = srcwidth / srcheight * dstheight;
float left = ((float)dstwidth - cx) / 2.0f;
if (left < 1.0f) left = 0;
gr.DrawImage(source, 0, left, cx, dstheight);
}
return dest;
}
}
}
}
"static void Main(string[] args)" is in another code
Thanks in advance for your help
(Sorry for my english, I use a translator)
Your problem is that your trying to do two things at the same time in only one thread, which is impossible, one thread can only do one thing at a time. You need to use multiple threads to achieve your goal, which in this case is simple enough just use player.Play(); instead of player.PlaySync();.
player.Play(); automatically starts a new thread and runs the task there.
Here is a good tutorial/ introduction to threads in C#
As #MindSwipe said you need to use more threads.
Example:
class Animation
{
public Animation
{
Thread mythread = new Thread(DoSomething);
Thread mythread2 = new Thread(DoSomething2);
mythread.Start();
mythread2.Start();
}
public void DoSomething()
{
Do_gif_animation();
}
public void DoSomething2()
{
Do_music();
}
}
I've been trying to implement a function that lets me draw the tiles inside a tiled file (.tmx). I've looked around and found a kind of working piece of code but it stretches out the tiles.
This is the code I found and edited a bit:
private void DrawLayer(int index, SpriteBatch batch) {
for (var i = 0; i < Map.Layers[index].Tiles.Count; i++) {
//Get the identification of the tile
int gid = Map.Layers[index].Tiles[i].Gid;
// Empty tile, do nothing
if (gid == 0) { }
else {
int tileFrame = gid - 1 ;
int column = tileFrame % (tileset.Width / tileWidth);
int row = tileFrame / (tileset.Height / tileHeight);
float x = (i % Map.Width) * Map.TileWidth;
float y = (float)Math.Floor(i / (double)Map.Width) * Map.TileHeight;
//Put all the data together in a new rectangle
Rectangle tilesetRec = new Rectangle(tileWidth * column, tileHeight * row, tileWidth, tileHeight);
//Draw the tile that is within the tilesetRec
batch.Draw(tileset, new Rectangle((int)x, (int)y, tileWidth, tileHeight), tilesetRec, Color.White);
}
}
}
The MonoGame.Extended library has support for loading and rendering Tiled (.tmx) maps. It's open source so you can check out how it works if you want.
The layer rendering code supports different map types (orthogonal, isometric), different rendering order (right down, right up, left down, left up) and multiple tilesets so it's not boiled down into a single method like yours.
If you where to extract the relevant bits of code you might end up with something like this:
for (var y = 0; y < layerHeight; y++)
{
for (var x = 0; x < layerWidth; x++)
{
var region = tile.Id == 0 ? null : _regions[tile.Id];
if (region != null)
{
var tx = tile.X * _map.TileWidth;
var ty = tile.Y * _map.TileHeight;
var sourceRectangle = region.Bounds;
var destinationRectangle = new Rectangle(tx, ty, region.Width, region.Height);
_spriteBatch.Draw(region.Texture, destinationRectangle, sourceRectangle, Color.White);
}
}
}
Of course, there's still a few missing bits, like the dictionary of texture regions created when loading the tileset.
_regions = new Dictionary<int, TextureRegion2D>();
for (var y = Margin; y < texture.Height - Margin; y += TileHeight + Spacing)
{
for (var x = Margin; x < texture.Width - Margin; x += TileWidth + Spacing)
{
_regions.Add(id, new TextureRegion2D(Texture, x, y, TileWidth, TileHeight));
id++;
}
}
And the definition of what a texture region actually is.
public class TextureRegion2D
{
public Texture2D Texture { get; protected set; }
public int X { get; private set; }
public int Y { get; private set; }
public int Width { get; private set; }
public int Height { get; private set; }
public Rectangle Bounds { get { return new Rectangle(X, Y, Width, Height); } }
}
Keep in mind that I've mostly copy and pasted code out of MonoGame.Extended. It won't work exactly as it's written here but I think I've provided enough detail to figure out what all the other variables do if you want to write your own Tiled rendering code.
How detect collision with sprite animation?
SpriteManager.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework;
using System.IO;
namespace Mini
{
public class SpriteManager
{
protected Texture2D Texture;
public Vector2 Position = Vector2.Zero;
protected Dictionary<string, AnimationClass> Animations =
new Dictionary<string, AnimationClass>();
protected int FrameIndex = 0;
protected Vector2 Origin;
private int height;
private int width;
private string animation;
public string Animation
{
get { return animation; }
set
{
animation = value;
FrameIndex = 0;
}
}
public int Height
{
get { return height; }
}
public int Width
{
get { return width; }
}
public Rectangle Rectangle
{
get { return Animations[Animation].Rectangles[FrameIndex]; }
}
public Texture2D Texture2D
{
get { return Texture; }
}
public SpriteManager(Texture2D Texture, int Frames, int animations)
{
this.Texture = Texture;
width = Texture.Width / Frames;
height = Texture.Height / animations;
Origin = new Vector2(width / 2, height / 2);
}
public void AddAnimation(string name, int row,
int frames, AnimationClass animation)
{
Rectangle[] recs = new Rectangle[frames];
Color[][] frameImageData = new Color[frames][];
Texture2D[][] frameImage = new Texture2D[frames][];
for (int i = 0; i < frames; i++)
{
recs[i] = new Rectangle(i * width,
(row - 1) * height, width, height);
frameImageData[i] = new Color[width * height];
}
animation.Frames = frames;
animation.Rectangles = recs;
Animations.Add(name, animation);
}
public void Draw(SpriteBatch spriteBatch)
{
spriteBatch.Draw(Texture, Position,
Animations[Animation].Rectangles[FrameIndex],
Animations[Animation].Color,
Animations[Animation].Rotation, Origin,
Animations[Animation].Scale,
Animations[Animation].SpriteEffect, 0f);
}
public bool IntersectPixels(SpriteManager b)
{
Rectangle rectangleA = this.Rectangle;
Rectangle rectangleB = b.Rectangle;
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);
Color[] dataA = new Color[rectangleA.Width * rectangleA.Height];
this.Texture.GetData(0, rectangleA, dataA, 0, rectangleA.Width * rectangleA.Height);
Color[] dataB = new Color[rectangleB.Width * rectangleB.Height];
b.Texture.GetData(0, rectangleB, dataB, 0, b.Width * b.Height);
Stream s = File.Create("t.png");
b.Texture2D.SaveAsPng(s, rectangleB.Width, rectangleB.Height);
for (int y = top; y < bottom; y++)
{
for (int x = left; x < right; x++)
{
Color colorA = dataA[(x - rectangleA.Left) + (y - rectangleA.Top) * rectangleA.Width];
Color colorB = dataB[(x - rectangleB.Left) + (y - rectangleB.Top) * rectangleB.Width];
if (colorA.A != 0 && colorB.A != 0)
{
return true;
}
}
}
return false;
}
}
}
With this code, the collision is detected every few frames of animation anywhere
IntersectPixels is to detect collisions.
This is the class i created MapsLevels:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
namespace TowerDefense
{
public class Level
{
private List<Texture2D> tileTextures = new List<Texture2D>();
private List<int[,]> MapsArrays = new List<int[,]>();
private Queue<Vector2> waypoints = new Queue<Vector2>();
int[,] map = new int[,]
{
{1,1,1,0,0,0,0,0,},
{0,0,1,0,0,0,0,0,},
{0,0,1,1,0,0,1,1,},
{0,0,0,1,0,0,1,0,},
{0,0,1,1,0,0,1,0,},
{0,0,1,0,0,0,1,0,},
{0,0,1,1,1,0,1,0,},
{0,0,0,0,1,1,1,0,},
};
int[,] map1 = new int[,]
{
{0,0,0,1,1,1,1,0,},
{0,0,0,1,0,0,1,0,},
{0,0,0,1,1,0,1,0,},
{1,1,0,0,1,0,1,0,},
{0,1,0,0,1,0,1,0,},
{0,1,1,1,1,0,1,0,},
{0,0,0,1,1,0,1,1,},
{0,0,0,0,0,0,0,0,},
};
int[,] map2 = new int[,]
{
{1,1,0,0,1,0,0,0,},
{0,1,0,0,1,0,1,1,},
{0,1,0,0,1,0,1,0,},
{0,1,1,1,1,1,1,0,},
{0,0,0,0,0,1,0,0,},
{0,1,1,1,1,1,1,1,},
{0,1,0,1,0,0,0,0,},
{0,1,0,1,0,0,0,0,},
};
public Level()
{
waypoints.Enqueue(new Vector2(0, 0) * 64);
waypoints.Enqueue(new Vector2(2, 0) * 64);
waypoints.Enqueue(new Vector2(2, 3) * 64);
waypoints.Enqueue(new Vector2(3, 2) * 64);
waypoints.Enqueue(new Vector2(4, 2) * 64);
waypoints.Enqueue(new Vector2(4, 4) * 64);
waypoints.Enqueue(new Vector2(3, 4) * 64);
waypoints.Enqueue(new Vector2(3, 5) * 64);
waypoints.Enqueue(new Vector2(2, 5) * 64);
waypoints.Enqueue(new Vector2(2, 7) * 64);
waypoints.Enqueue(new Vector2(7, 7) * 64);
MapsArrays.Add(map);
MapsArrays.Add(map1);
MapsArrays.Add(map2);
}
public Queue<Vector2> Waypoints
{
get { return waypoints; }
}
public void AddTexture(Texture2D texture)
{
tileTextures.Add(texture);
}
public int Width
{
get { return map1.GetLength(1); }
}
public int Height
{
get { return map1.GetLength(0); }
}
public void Draw(SpriteBatch batch)
{
for (int x = 0; x < Width; x++)
{
for (int y = 0; y < Height; y++)
{
int textureIndex = MapsArrays[0][y, x];
if (textureIndex == -1)
continue;
Texture2D texture = tileTextures[textureIndex];
batch.Draw(texture, new Rectangle(
x * 64, y * 64, 64, 64), Color.White);
}
}
}
public int GetIndex(int cellX, int cellY)
{
if (cellX < 0 || cellX > Width - 1 || cellY < 0 || cellY > Height - 1)
return 0;
return map[cellY, cellX];
}
}
}
I have 3 maps but now im using only the first one variable map.
And i have waypoints but they are not fitting to the map so the enemy walk not on the path i created.
The path in my map is marked with numbers 1 and all the rest is 0.
This is the Pathfinder class i added it to this site:
Pathfinder class
This is my complete project maybe it will be more easy to see it in the whole project:
This is the rar file of my project called TowerDefense:
TowerDefense
The problem is with the Pathfinder class on the line number 274:
SearchNode endNode = searchNodes[endPoint.X, endPoint.Y];
I'm getting exception Index was outside the bounds of the array.
What i want to do in the end is to use the Pathfinder class in the right way and also make that the enemy will move over my path the waypoints should be automatic set to the path in my map.
And hard coded like it is now.
EDIT:
I solved the first exception in Game1.cs i changed the line:
List<Vector2> path = pathfinder.FindPath(new Point(0, 0), new Point(9, 9));
To:
List<Vector2> path = pathfinder.FindPath(new Point(0, 0), new Point(7, 7));
I still have two problems now in Pathfinder class in line number 282:
startNode.InOpenList = true;
It throw exception null since startNode is null.
In many items in the List searchNodes also in class Pathfinder some items are null.
The second problem is yet in the MapsLevel.cs class how ot make the waypoint to be automatic fit to the map ( variable map design ) so the enemy iwll move on the path in my map ?