I am trying to make an animation in which a rocket like thing will go up the screen and blast into various parts and follow its path down and fade just like actual firecracker. I have tried to make it using an update loop and a draw loop and then rendering the images on a bitmap. But there is a lot of lag there in the animation. I want to implement this thing at the end of my game and when a user taps the screen the rocket will go to that place and then explode. The code which I have tried is here...
public class Plotter : UserControl, IDisposable
{
Random _rand = new Random((int)DateTime.Now.Ticks);
WriteableBitmap _particleBmp;
EventBlob[] _data;
private int NUMPBLOBS = 25;
private const int CANWIDTH = 1366;
private const int CANHEIGHT = 768;
double _lastx, _lasty;
public Plotter()
{
}
public async Task PlotterMethod(Point current)
{
_lastx = current.X;
_lasty = current.Y;
await Setup();
}
private async Task Setup()
{
_particleBmp = await Util.LoadBitmap("tspark.png");
CompositionTarget.Rendering += CompositionTarget_Rendering;
_data = new EventBlob[NUMPBLOBS];
int ang = 0;
for (int i = 0; i < NUMPBLOBS; i++)
{
EventBlob eb = new EventBlob();
eb.img = _particleBmp;
eb.SourceRect = new Rect(0, 0, 30, 30);
eb.Position.X = _rand.Next((int)_lastx - 10, (int)_lastx + 10);
eb.Position.Y = _rand.Next((int)_lasty - 10, (int)_lasty + 10);
eb.VX = 5;
eb.VY = 5;
eb.angle = ang;
ang += 36 / 5;
eb.Opacity = 1;
eb.BlendMode = WriteableBitmapExtensions.BlendMode.Additive;
eb.FadeRate = _rand.NextDouble() * 0.005 + 0.002;
Color c = new Color();
c.A = (byte)0;
c.R = (byte)_rand.Next(0, 255);
c.G = (byte)_rand.Next(0, 255);
c.B = (byte)_rand.Next(0, 255);
eb.Color = c;
_data[i] = eb;
}
}
int counterupdate = 0;
void CompositionTarget_Rendering(object sender, object e)
{
if (counterupdate % 2 == 0)
{
Update();
DrawBitmap();
}
counterupdate++;
}
int count = 0;
bool opacitycheck = true;
private void Update()
{
bool isallclear = true;
for (int i = 0; i < _data.Length; i++)
{
var p = _data[i];
if (i < 51)
{
p.VX = 2 * Math.Cos(p.angle);
p.VY = 2 * Math.Sin(p.angle);
}
p.Position.X += p.VX;
p.Position.Y += p.VY;
if (opacitycheck)
{
if (p.Color.A + 30 < 255)
p.Color.A += 30;
else
{
opacitycheck = false;
p.Color.A = 255;
}
}
else
{
if (p.Color.A - 30 > 0)
p.Color.A -= 30;
else
{
p.Color.A = 0;
}
}
if (p.Color.A != 0)
{
isallclear = false;
}
}
count++;
if (isallclear)
{
_data = new EventBlob[0];
CompositionTarget.Rendering -= CompositionTarget_Rendering;
NUMPBLOBS = 0;
opacitycheck = true;
Completed(this, null);
}
}
private void DrawBitmap()
{
using (TargetBmp.GetBitmapContext())
{
TargetBmp.Clear();
for (int i = 0; i < _data.Length; i++)
{
var b = _data[i];
this.TargetBmp.Blit(b.Position, b.img, b.SourceRect, b.Color, b.BlendMode);
}
TargetBmp.Invalidate();
}
}
public WriteableBitmap TargetBmp { get; set; }
public Image Imagemain { get; set; }
public event EventHandler<object> Completed;
public void Dispose()
{
}
}
public class EventBlob
{
public double Opacity { get; set; }
public double FadeRate { get; set; }
public Color Color;
public Rect SourceRect { get; set; }
public WriteableBitmap img { get; set; }
public Point Position;
public double VX { get; set; }
public double VY { get; set; }
public WriteableBitmapExtensions.BlendMode BlendMode;
public double angle { get; set; }
}
and in my main page i have called it like this...
async void MainPage_PointerPressed(object sender, PointerRoutedEventArgs e)
{
if (LayoutRoot.Children.Count < 6)
{
Plotter asd = new Plotter();
await asd.PlotterMethod(e.GetCurrentPoint(LayoutRoot).Position);
WriteableBitmap _wb = new WriteableBitmap(1366, 786);
asd.TargetBmp = _wb;
Image image = new Image();
image.Height = 786;
image.Width = 1366;
image.Stretch = Stretch.Fill;
image.Source = _wb;
asd.Imagemain = image;
asd.Completed += asd_Completed;
LayoutRoot.Children.Add(image);
}
}
void asd_Completed(object sender, object e)
{
var obj = (Plotter)sender;
LayoutRoot.Children.Remove(obj.Imagemain);
obj.Dispose();
}
but there is too much of lag if I create 4 of these objects the fps goes down to 10.
Please suggest a better way or a way to optimize this code. Thanks.
Try implementing the parallel feature of C# , For Reference check
http://www.parallelcsharp.com/
I hope this will solve your Problem
Related
I'm trying to calculate the largest common surface of metal sheets in order to reduce wasting our materials.
I belive that I am succeeded but I'am not sure if this is the best way.
Is there any ready Math functions for this?
Here is my solution.
private void frmCalculate_Load(object sender, EventArgs e)
{
//Width and length values can vary, this is just one of possible dimensions.
List<Material> lstGivenMaterials = new List<Calculator.Material>();
lstGivenMaterials.Add(new Calculator.Material(10, 40));
lstGivenMaterials.Add(new Calculator.Material(60, 20));
lstGivenMaterials.Add(new Calculator.Material(5, 20));
var largestCommonSurface = CalculateCommunSurface(lstGivenMaterials);
}
A method who takes a list of Material class.
private decimal? CalculateCommunSurface(List<Material> givenMaterials)
{
decimal? retVal = 0;
var largestMat = givenMaterials.Max(ro => ro.Surface);
var smallestMat = givenMaterials.Min(ro => ro.Surface);
List<Material> possibleComplexing = new List<Material>();
foreach (var mat1 in givenMaterials)
{
foreach (var mat2 in givenMaterials)
{
possibleComplexing.Add(mat1);
possibleComplexing.Add(new Calculator.Material(mat1.Width, mat2.Width));
possibleComplexing.Add(new Calculator.Material(mat1.Width, mat2.Length));
}
}
var possibleValues = possibleComplexing.Where(ro => ro.Surface <= smallestMat).ToList().OrderByDescending(ro => ro.Surface).ToList();
bool isPossible;
foreach (var item in possibleValues)
{
isPossible = true;
foreach (var mat in givenMaterials)
{
//If not suitable for any material, not ok.
if (!mat.IsPossible(item))
{
isPossible = false;
break;
}
}
if (isPossible)
{
retVal = item.Surface;
break;
}
}
return retVal;
}
My material class.
public class Material
{
public decimal Width { get; set; }
public decimal Length { get; set; }
public decimal Surface
{
get
{
return Width * Length;
}
}
public Material(decimal width, decimal length)
{
this.Width = width;
this.Length = length;
}
internal bool IsPossible(Material refMat)
{
bool retVal = false;
if (
(refMat.Width <= this.Width && refMat.Length <= this.Length) ||
(refMat.Width<= this.Length && refMat.Length <= this.Width)
)
{
retVal = true;
}
return retVal;
}
}
I currently have a class that extends the System.Windows.Forms.Label class. I'm looking to program minesweeper for a knowledge assignment. It basically adds some functionality to the regular label and then gets instantiated in the form1.cs part.
public partial class Cell : System.Windows.Forms.Label
{
private bool hasBomb;
private bool isRevealed;
private int neighbourBombCount;
static int BombAmount;
// Properties
public bool HasBomb
{
get { return hasBomb; }
set { hasBomb = value; }
}
public bool IsRevealed
{
get { return isRevealed; }
set { isRevealed = value; }
}
public int NeighbourBombCount
{
get { return neighbourBombCount; }
set { neighbourBombCount = value; }
}
// constructors
public Cell()
{
hasBomb = false;
isRevealed = false;
neighbourBombCount = 0;
this.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
this.Size = new System.Drawing.Size(50, 50);
}
and then theres the form1.cs:
public partial class Form1 : Form
{
// Public variable declarations
int chance;
Random rand1 = new Random();
static int bombAmount;
public Form1()
{
InitializeComponent();
this.AutoSize = false;
this.Width = 420;
this.Height = 420;
createGrid();
}
public void createGrid()
{
for (int i = 0; i < 8; i++)
{
for (int j = 0; j < 8; j++)
{
grid[i][j] = new Cell();
grid[i][j].Name = "grid" + i.ToString() + j.ToString();
grid[i][j].Location = new System.Drawing.Point(i * 49, j * 49);
grid[i][j].Size = new System.Drawing.Size(50, 50);
grid[i][j].TabIndex = 0;
chance = rand1.Next(0, 6);
if (chance % 6 == 0 && bombAmount < 10)
{
grid[i][j].HasBomb = true;
bombAmount++;
}
}
}
for (int i = 0; i < 8; i++)
{
for (int j = 0; j <8; j++)
{
this.Controls.Add(grid[i][j]);
}
}
}
private Cell[][] grid = new Cell[8][];
which has some more logic beneath which is unimportant for now. The problem is that nothing is showing up, what am I missing?
You aren't initializing the second part of your jagged array.
Try adding this:
public void createGrid() {
for (int i = 0; i < 8; i++) {
grid[i] = new Cell[8];
I am creating really simple pacman game as a homework. I am working in Visual Studio, in c#. The problem is, when I click run, only the winform shows with nothing on it. Can someone tell me what have I done wrong?
namespace pacman
{
public partial class Form1 : Form
{
Timer timer;
Pacman pacman;
static readonly int TIMER_INTERVAL = 250;
static readonly int WORLD_WIDTH = 15;
static readonly int WORLD_HEIGHT = 10;
Image foodImage;
bool[][] foodWorld;
public Form1()
{
InitializeComponent();
foodImage = Properties.Resources.orange_detoure;
DoubleBuffered = true;
newGame();
}
public void newGame()
{
pacman = new Pacman();
this.Width = Pacman.radius * 2 * (WORLD_WIDTH + 1);
this.Height = Pacman.radius * 2 * (WORLD_HEIGHT + 1);
foodWorld = new bool[WORLD_WIDTH][];
timer = new Timer();
timer.Interval = TIMER_INTERVAL;
timer.Tick += new EventHandler(timer_Tick);
timer.Start();
}
void timer_Tick(object sender, EventArgs e)
{
timer.Interval = TIMER_INTERVAL - 1;
if (TIMER_INTERVAL == 0)
{
timer.Stop();
}
pacman.Move(WORLD_WIDTH, WORLD_HEIGHT);
Invalidate();
}
private void Form1_KeyUp(object sender, KeyEventArgs e)
{
if (Keys.Up != 0)
{
pacman.ChangeDirection("UP");
}
if (Keys.Down != 0)
{
pacman.ChangeDirection("DOWN");
}
if (Keys.Left != 0)
{
pacman.ChangeDirection("LEFT");
}
if (Keys.Right != 0)
{
pacman.ChangeDirection("RIGHT");
}
Invalidate();
}
private void Form1_Paint(object sender, PaintEventArgs e)
{
Graphics g = e.Graphics;
g.Clear(Color.White);
for (int i = 0; i < foodWorld.Length; i++)
{
for (int j = 0; j < foodWorld[i].Length; j++)
{
if (foodWorld[i][j])
{
g.DrawImageUnscaled(foodImage, j * Pacman.radius * 2 + (Pacman.radius * 2 - foodImage.Height) / 2, i * Pacman.radius * 2 + (Pacman.radius * 2 - foodImage.Width) / 2);
}
}
}
pacman.Draw(g);
}
}
}
And here is the class Pacman:
namespace pacman
{
public class Pacman
{
public enum dir {UP, DOWN, RIGHT, LEFT};
public float x { get; set; }
public float y { get; set; }
public string direction { get; set; }
static public int radius = 20;
public double speed { get; set; }
public bool open { get; set; }
public Brush brush = new SolidBrush(Color.Yellow);
public Pacman() {
this.x = 7;
this.y = 5;
this.speed = 20;
this.direction = Convert.ToString(dir.RIGHT);
this.open = false;
}
public void ChangeDirection(string direct)
{
// vasiot kod ovde
for (int i = 0; i < 3; i++) {
if(direct == Convert.ToString(dir.RIGHT))
{
direction = "RIGHT";
}
if (direct == Convert.ToString(dir.LEFT))
{
direction = "LEFT";
}
if (direct == Convert.ToString(dir.UP))
{
direction = "UP";
}
if (direct == Convert.ToString(dir.DOWN))
{
direction = "DOWN";
}
}
}
public void Move(float width, float height)
{
if (direction == Convert.ToString(dir.RIGHT))
{
x = x + 1;
if (x > width) {
x = 1;
}
}
else if (direction == Convert.ToString(dir.LEFT))
{
x = x - 1;
if (x < 0) {
x = 14;
}
}
else if (direction == Convert.ToString(dir.UP))
{
y = y + 1;
if (y > height) {
y = 1;
}
}
else if (direction == Convert.ToString(dir.DOWN))
{
y = y - 1;
if (y < 0) {
y = 14;
}
}
}
public void Draw(Graphics g)
{
if (!open) {
g.FillEllipse(brush, 7, 5, 15, 15);
}
}
}
}
It should look like this http://prntscr.com/70e0jt.
I will be grateful if someone can tell me what should I fix so it finally works..
Add this to your constructor:
this.Paint += Form1_Paint;
What is happening is that you made a Paint handler, but never assigned the paint event to handle it (that I can see, its possible that the event was assigned in the other partial part of the class).
The other problem is that you did not fully define the "food world" variable, you initialized the first rank, but not the second. You need to fully initialize this and set the booleans inside of it.
To start off I am new to C# and I am in need of some help. I a class that contains a list. I can set the items in the list from the application but not from the class(where it needs to be done). I am also needing to move an event to class as well. This works in the app as well. Any help with this is greatly appreciated. Below is the code from my class:
namespace CarRace
{
class Cars
{
public string Name { get; set; }
public int StartPOS { get; set; }
public int Speed { get; set; }
public int CurPOS { get; set; }
public double Location { get; set; }
public Cars(string Name, int StartPOS, int Speed, int CurPOS, long Location)
{
this.Name = Name;
this.StartPOS = StartPOS;
this.Speed = Speed;
this.CurPOS = 0;
this.Location = 0;
}
public static int CompareCurrentLocation(Cars c1, Cars c2)
{
return c2.Location.CompareTo(c1.Location);
}
}
}
I am needing to add this to the class:
if (File.Exists("NewRace.xml"))
{
XDocument doc = XDocument.Load("NewRace.xml");
var nCars = doc.Descendants("Car").Select(x => new Cars("", 0, 0, 0, 0)
{
Name = x.Attribute("Name").Value,
StartPOS = int.Parse(x.Attribute("StartPOS").Value),
Speed = int.Parse(x.Attribute("Speed").Value),
CurPOS = 0
});
}
And this:
int p = 1;
int prevPOS = 1;
DateTime? PrevTime;
double dist = 0;
double PrevLoc = 0;
if (i == 0)
{
return;
}
foreach (var car in RaceList)
{
dist = (((car.Speed * 1609.344) * 1) / 1609.344) / 3600;
car.Location = car.Location + dist;
}
Comparison<Cars> compLoc = Cars.CompareCurrentLocation;
RaceList.Sort(compLoc);
PrevTime = DateTime.Now;
foreach (var car in RaceList)
{
if (car.Location != PrevLoc)
{
car.CurPOS = p;
}
else
{
car.CurPOS = prevPOS;
}
prevPOS = car.CurPOS;
PrevLoc = car.Location;
p++;
}
Thanks
Thanks for all of your replies. I tried the car.speed/3600 but only get
back 0 for that so I did the long way. I did get everything working
the way I needed it to.
That's because you are doing an integer division (car.Speed is of type int) so the fractional part of the result is discarded. Since the car's speed is less than 3600 this would hence always result in zero. You can avoid this by casting car.Speed to a double first - this should produce the result you want:
dist = (double)car.Speed / 3600;
Thanks for all of your replies. I tried the car.speed/3600 but only get back 0 for that so I did the long way. I did get everything working the way I needed it to. I am a rookie at this and any tips are greatly appreciated. Below is the code I have updated to.
namespace CarRace
{
class Cars
{
public string Name { get; set; }
public int StartPOS { get; set; }
public int CurPOS { get; set; }
public int Speed { get; set; }
public double Location { get; set; }
public string Make { get; set; }
private static List<Cars> CarList;
private static string ProgPart;
public Cars(string Name, int StartPOS, int CurPOS, int Speed, double Location, string Make)
{
this.Name = Name;
this.StartPOS = StartPOS;
this.CurPOS = CurPOS;
this.Speed = Speed;
this.Location = Location;
this.Make = Make;
}
public static List<Cars> FillList()
{
return CarList;
}
public static void Main()
{
try
{
bool Prog = false;
//Get Part to display
while (!Prog)
{
Console.WriteLine("Select the part you would like to test.(1 or 2)");
ProgPart = Console.ReadLine();
if (ProgPart == "1" || ProgPart == "2")
{
Prog = true;
}
}
Console.WriteLine("----------------------------------------");
//Read XML File and set the CarList
if (File.Exists("NewRace.xml"))
{
XDocument doc = XDocument.Load("NewRace.xml");
var nCars = doc.Descendants("Car").Select(x => new Cars("", 0, 0, 0, 0, "")
{
Name = x.Attribute("Name").Value,
StartPOS = int.Parse(x.Element("StartPOS").Value),
CurPOS = 0,
Speed = int.Parse(x.Element("Speed").Value),
Location = double.Parse(x.Element("Location").Value),
Make = x.Attribute("Make").Value
});
CarList = new List<Cars>();
foreach (var car1 in nCars)
{
if (ProgPart == "1")
{
CarList.Add(new Cars(car1.Name, car1.StartPOS, car1.CurPOS, car1.Speed, car1.Location, car1.Make));
}
else
{
CarList.Add(new Cars(car1.Name, car1.StartPOS, car1.CurPOS, 0, car1.Location, car1.Make));
}
}
}
else
{
Console.WriteLine("File Not Found!");
Console.ReadKey();
}
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
public static int CompareCurrentLocation(Cars c1, Cars c2)
{
return c2.Location.CompareTo(c1.Location);
}
public static Boolean UpdateLeaderBoard(long i)
{
try
{
int p = 1;
int prevPOS = 1;
DateTime? PrevTime;
double dist = 0;
double prevLocation = 0;
if (i == 0)
{
return false;
}
foreach (var car in CarList)
{
if (ProgPart == "2")
{
switch (car.Make)
{
case "300ZX":
//Slow continuous gain of speed by percentage after 60 with top speed of 320.
if (i <= 15)
{
car.Speed = car.Speed + (60 / 10);
}
else if (car.Speed < 320)
{
double percent = (double)(car.Speed * .1);
if ((Convert.ToInt32(car.Speed + percent)) > 320)
{
car.Speed = 320;
}
else
{
car.Speed = Convert.ToInt32(car.Speed + (percent));
}
}
break;
case "Camero":
//0-60 4 seconds 60-220 20 seconds Top 220
if (i <= 4)
{
car.Speed = car.Speed + (60 / 4);
}
else if (i <= 20)
{
car.Speed = car.Speed + 10;
}
break;
case "Mustang":
//0-top(210) 25 seconds
if (car.Speed <= 200)
{
car.Speed = car.Speed + (200 / 20);
}
break;
case "VW Bug":
//Constant Speed
car.Speed = 165;
break;
default:
Console.WriteLine("Make not found");
break;
}
}
//Set Cars Current Location
dist = (((car.Speed * 1609.344) * 1) / 1609.344) / 3600;
car.Location = car.Location + dist;
}
//Sort list by location
Comparison<Cars> compLoc = Cars.CompareCurrentLocation;
CarList.Sort(compLoc);
PrevTime = DateTime.Now;
//Set the Current Position
foreach (var car in CarList)
{
if (car.Location != prevLocation)
{
car.CurPOS = p;
}
else
{
car.CurPOS = prevPOS;
}
prevPOS = car.CurPOS;
prevLocation = car.Location;
p++;
}
return true;
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
return false;
}
}
}
}
I've been working days on a program that draws a grid of dots, and I had to start all over again several times because of a bad approach / to complicated. I've come to a point now where I have to draw a line from a clicked dot (point) to a second clicked dot (point) on the form.
Seriously I've been spending hours even days of my time searching for the right approach.
As for now I only managed to get a line drawn from a point on the form to another point on the form on random clicks...
Could someone please help get the code done, its just frustrating me how I don't have any progress after all attempts of drawing a grid of dots..
So what I want to do is "draw a line from a clicked dot (point) to a second clicked dot (point) on the form".
See below of my code:
Form1.cs:
public partial class Form1 : Form
{
private GridDrawing drawing;
private Point point1;
private Point point2;
List<Point> p1List = new List<Point>(); //Temp
List<Point> p2List = new List<Point>(); //Temp
//True if point1 must be updated
//False if point2 must be updated
private bool firstPoint = true;
private int sizeOfDot;
private int rows;
private int columns;
public Form1()
{
InitializeComponent();
sizeOfDot = 10; //The size of the dot
rows = 6; //The amount of rows for the matrix
columns = 8; //The amount of columns for the matrix
}
private void Form_Paint(object sender, PaintEventArgs e)
{
e.Graphics.FillRectangle(Brushes.White, ClientRectangle); //Fill the form in white
drawing = new GridDrawing(this, rows, columns); //Control, Rows, Columns
foreach (var piece in drawing.Pieces) //Draws all the dots
{
e.Graphics.FillEllipse(Brushes.Black, (piece.Dot.X - sizeOfDot / 2),
(piece.Dot.Y - sizeOfDot / 2), sizeOfDot, sizeOfDot); //Draws the dot
}
using (var pen = new Pen(Color.Black, 2))
{
for (int i = 0; i < p1List.Count; i++)
{
e.Graphics.DrawLine(pen, p1List[i], p2List[i]);
}
}
}
private void startToolStripMenuItem_Click(object sender, EventArgs e)
{}
private void Form1_MouseDown(object sender, MouseEventArgs e)
{
if (firstPoint) //Update point1 or point2
{
//Point 1
point1.X = e.X;
point1.Y = e.Y;
}
else
{
//Point 2
point2.X = e.X;
point2.Y = e.Y;
p1List.Add(point1);
p2List.Add(point2);
}
firstPoint = !firstPoint; //Change the bool value
Invalidate(); //Redraw
}
private void Form1_SizeChanged(object sender, EventArgs e)
{
Invalidate();
}
}
GridDrawing.cs:
public class GridDrawing
{
private int columns;
private int rows;
private List<GridPiece> pieces;
private Point dot;
//private Point point1; //point1 to start drawing line from
//private Point point2; //point2 to end drawing line from
/// <summary>
/// Constructs a grid
/// </summary>
/// <param name="ctrl"></param>
/// <param name="rows"></param>
/// <param name="columns"></param>
/// <param name="sizeOfDot"></param>
public GridDrawing(Control ctrl, int rows, int columns)
{
this.rows = rows; // The amount of rows in the matrix.
this.columns = columns; // The amount of columns in the matrix.
this.pieces = new List<GridPiece>(); // Initializes the List GridPieces
int xOffset = (int)ctrl.ClientRectangle.Width / (columns + 1); // FP offset for X
int yOffset = (int)ctrl.ClientRectangle.Height / (rows + 1); // FP offset for Y
//Generate the dots
for (int i = 0; i < rows; i++) //Matrix with 6 rows
{
for (int j = 0; j < columns; j++) //Matrix with 8 columns
{
dot = new Point((j + 1) * xOffset, (i + 1) * yOffset); // Center of the dot
GridPiece p = new GridPiece(dot); // Creates a piece
pieces.Add(p); // Puts the piece that has to be drawn in the List<GridPiece>pieces
}
}
}
public List<GridPiece> Pieces //Property List<GridPiece>pieces
{
get { return this.pieces; }
}
public Point Dot //Property Point dot
{
get { return this.dot; }
}
}
GridPiece.cs:
public class GridPiece
{
private Point dot;
/// <summary>
/// Constructor of GriedPiece
/// </summary>
/// <param name="bmpPic"></param>
/// <param name="position"></param>
public GridPiece(Point dot)
{
this.dot = dot;
}
public Point Dot
{
get { return dot; }
}
}
Here's an example how I'm trying to make it look like
Could someone please help me?
Here is how to do this. add following code
public class Line
{
public float X1 { get; set; }
public float X2 { get; set; }
public float Y1 { get; set; }
public float Y2 { get; set; }
}
public sealed class Grid : Panel
{
readonly DotDrawing drawing = new DotDrawing();
private List<Line> Markers { get; set; }
public Grid()
{
this.DoubleBuffered = true;
Markers = new List<Line>();
}
protected override void OnPaint(PaintEventArgs e)
{
foreach (Line line in Markers)
{
using (Pen pen = new Pen(Brushes.Black))
{
pen.Width = 2;
e.Graphics.SmoothingMode = SmoothingMode.HighQuality;
e.Graphics.DrawLine(pen, line.X1, line.Y1, line.X2, line.Y2);
}
}drawing.Render(e.Graphics);
base.OnPaint(e);
}
private Dot lastDot;
protected override void OnMouseDown(MouseEventArgs e)
{
base.OnMouseDown(e);
var x = this.drawing.GetDotFromPoint(e.Location);
if (x != null)
{
lastDot = x;
}
else
{
lastDot = null;
}
}
protected override void OnMouseUp(MouseEventArgs e)
{
base.OnMouseUp(e);
var x = this.drawing.GetDotFromPoint(e.Location);
if (x != null)
{
Line line = new Line();
line.X1 = lastDot.Center.X;
line.Y1 = lastDot.Center.Y;
line.X2 = x.Center.X;
line.Y2 = x.Center.Y;
this.Markers.Add(line);
Invalidate();
}
}
}
public class Dot
{
public PointF Location { get; set; }
public int Radius { get; set; }
public PointF Center
{
get
{
return new PointF(this.Bounds.Left + (float)this.Radius,
this.Bounds.Top + (float)this.Radius);
}
}
public RectangleF Bounds
{
get
{
return new RectangleF(Location, new SizeF(2 * Radius, 2 * Radius));
}
}
public Dot()
{
Radius = 5;
}
}
public class DotDrawing
{
private List<Dot> Dots { get; set; }
public int RowCount { get; set; }
public int ColumnCount { get; set; }
public int ColumnSpacing { get; set; }
public int RowSpacing { get; set; }
public int DotRadius { get; set; }
public DotDrawing()
{
Dots = new List<Dot>();
DotRadius = 10;
ColumnCount = 15;
RowCount = 25;
this.RowSpacing = 30;
this.ColumnSpacing = 30;
}
public void Render(Graphics g)
{
this.Dots.Clear();
float x = 0;
float y = 0;
for (int i = 0; i < RowCount; i++)
{
for (int j = 0; j < ColumnCount; j++)
{
{
Dot dot = new Dot();
dot.Location = new PointF(x, y);
using (SolidBrush brush = new SolidBrush(ColorTranslator.FromHtml("#009aff")))
{
g.FillEllipse(brush, dot.Location.X, dot.Location.Y, DotRadius, DotRadius);
}
x += (DotRadius + ColumnSpacing);
Dots.Add(dot);
}
}
x = 0;
y += (DotRadius + this.RowSpacing);
}
}
public Dot GetDotFromPoint(PointF point)
{
for (int i = 0; i < this.Dots.Count; i++)
{
RectangleF rect = this.Dots[i].Bounds;
rect.Inflate(new SizeF(3, 3));
Region region = new Region(rect);
if (region.IsVisible(point))
{
return this.Dots[i];
}
}
return null;
}
}
Drag the Grid from the tool box.
Mouse Click on any of the dots without releasing it point to another grid you'll see the effect.