how to implement factory design pattern in c# to draw shapes? - c#

I am trying to learn c# and in c# I am trying to implement a factory design pattern to draw basic shapes like circle, rectangle, triangle, etc. I created a IShape Interface class. And other three Circle, Rectangle, and Triangle class. I also created a ShapeFactory static method. These classes sould be called after from compiler class and draw in another window i.e Output window. Below is the code.
//IShape Class
namespace CPaint.Class
{
public interface IShape
{
void Draw();
}
}
//Cicle Class
namespace CPaint.Class
{
internal class Circle : IShape
{
//public Output outputWindow;
private float x;
private float y;
private Color color;
private float radius;
private Graphics graphics;
public Circle(Color color, float x, float y, float radius)
{
this.color = color;
this.x = x;
this.y = y;
this.radius = radius;
}
public void Draw()
{
Pen pen = new Pen(Color.Black, 4);
SolidBrush brush = new SolidBrush(color);
graphics.FillEllipse(brush, x, y, radius, radius);
graphics.DrawEllipse(pen, x, y, radius, radius);
}
}
}
//Triangle class
namespace CPaint.Class
{
internal class Triangle : IShape
{
private float x;
private float y;
private Color color;
private float side1;
private float side2;
private float side3;
public Triangle(Color color, float x, float y, float side1, float side2, float side3)
{
this.color = color;
this.x = x;
this.y = y;
this.side1 = side1;
this.side2 = side2;
this.side3 = side3;
}
public void Draw()
{
//will write drawing code here...
}
}
}
//Shape Factory Class
namespace CPaint.Class
{
public class ShapeFactory
{
public static IShape GetShape(string shapeType, Color color, float x, float y, float height, float width, float radius, float side1, float side2, float side3)
{
if (shapeType == null)
{
return null;
}
if (shapeType.Equals("circle"))
{
return new Circle(color, x, y, radius);
}
else if (shapeType.Equals("rectangle"))
{
return new Rectangle(color, x, y, height, width); ;
}
else if (shapeType.Equals("triangle"))
{
return new Triangle(color, x, y, side1, side2, side3);
}
else
{
return null;
}
}
}
}
//Compiler Class
if (code[0].Trim().ToLower().Equals("circle"))
{
try
{
int parameter1 = Int32.Parse(code[1]);
IShape shape = ShapeFactory.GetShape("circle", color, initX, initY, 0, 0, parameter1, 0, 0, 0);
outputWindow.Show();
//outputWindow.outputArea.Image=new ShapeFactory.GetShape("circle", color, initX, initY, 0, 0, parameter1, 0, 0, 0);
//outputWindow.outputArea.Image = shape;
output = "command executed successfully: parameter is" + parameter1;
//output = "is numeric ";
}
catch (Exception ex)
{
Console.WriteLine("Exception Message: " + ex.Message);
output = "\n Parameter Error : Invalid/Insufficient Parameter. \n";
}
}
Here in Compiler class, I want to open output window by outputWindow.show(); and then draw the shape in window by outputWindow.OutputArea.Image=...
I got stuck. Please help.

This post explains differences between
Factory,
Factory Method, and
Abstract Factory
design patterns.
Since you want to be able to create a whole family of objects that need to be of "the same kind", this can be done with Abstract Factory pattern.
The factory can have multiple creator methods. You can add parameters to the creator method(s) of the factory.
IShapesFactory.cs is the interface of the Abstract Factory:
public interface IShapesFactory
{
Circle MakeCircle(Color color, float x, float y, float radius);
Triangle MakeTriangle(Color color, float x, float y, float side1, float side2, float side3);
}
The implementation of the factory would handle passing the Graphics object to the shapes it creates.
ShapeFactory.cs
public class ShapeFactory: IShapeFactory
{
private Graphics _graphics;
public ShapeFactory(Graphics graphics)
{
_graphics = graphics;
}
public Circle MakeCircle(Color color, float x, float y, float radius)
{
// pass the Graphics object in the constructor of Circle
return new Circle(_graphics, color, x, y, radius);
}
[..other methods of the factory interface]
}
The factory in use:
IShapeFactory factory = new ShapeFactory(graphics);
var circle = factory.MakeCircle(Color.Blue, 10, 10, 20);
circle.Draw();

Related

In Unity can I make the instantiate function accept custom coordinates instead of Vector3 or Transform?

I want to instantiate GameObjects(specifically hexagonal tiles) at the hexagonalCoodinates(hexcoordinates).
For this I wrote a custom coordinate system.
But I found out that unity doesn't accept anything other than Vector3 or transform.
How do I make it do that?
Or is there a easier way to do this?
This is the method to generate the gameObjects
private void TouchCell(Vector3 point)//This method instantiates cubes
{
point = transform.InverseTransformPoint(point);
HexCoordinates coordinates = HexCoordinates.FromPosition(point);
Instantiate(cubes, coordinates, Quaternion.identity);//<-The coordinate variable here is a hex coordinate.
Debug.Log("Touched at:" + coordinates);
}
And This is the Hex coordinate generator:
public struct HexCoordinates
{
public int X { get; private set; }
public int Z { get; private set; }
public int Y { get
{
return -X - Z;
} }
public HexCoordinates(int x,int z)
{
X = x;
Z = z;
}
public static HexCoordinates FromOffsetCoordinates(int x,int z)
{
return new HexCoordinates(x-z/2, z);
}
public override string ToString()
{
return "("+X.ToString()+","+Y.ToString()+","+Z.ToString()+")";
}
public string ToStringOnSeperateLines()
{
return X.ToString() + "\n" +Y.ToString()+ "\n" + Z.ToString();
}
public static HexCoordinates FromPosition(Vector3 point)//This converts the Vector3 to Hex coords
{
float x = point.x / (HexMetrics.InnerRadius * 2f);
float y = -x;
float offset = point.z / (HexMetrics.OuterRadius * 3f);
x -= offset;
y -= offset;
int iX = Mathf.RoundToInt(x);
int iY = Mathf.RoundToInt(y);
int iZ = Mathf.RoundToInt(-x - y);
if (iX + iY + iZ != 0)
{
float dX = Mathf.Abs(x-iX);
float dY = Mathf.Abs(y - iY);
float dZ = Mathf.Abs(-x-y-iZ);
if(dX>dY&&dX>dZ)
{
iX = -iY - iZ;
}
else if(dZ>dY)
{
iZ = -iX - iY;
}
}
return new HexCoordinates(iX,iZ);
}
}
Just convert from your HexCoordinates to Vector3 using any way:
create method for HexCoordinates, something like public Vector3 ToVector3() {...}
create implicit operator for implicit cast to Vector3
public struct HexCoordinates
{
public int X { get; private set; }
public int Z { get; private set; }
public int Y => -X - Z;
public HexCoordinates(int x,int z)
{
X = x;
Z = z;
}
...
public static implicit operator Vector3(HexCoordinates coords)
{
Vector3 result = // convert to Vector3
// Vector3 result = ToVector3() -- or like this for code reuse
return result;
}
public Vector3 ToVector3()
{
Vector3 result = //convert to Vector3
return result;
}
}
And then you can extend Unity's Object class and add overloading for Instantiate() method that will accept HexCoordinates, convert to Vector3 and call Instantiate()
public static class ObjectExtension
{
public static void Instantiate(this Object obj, Object origin, HexCoordinates coords, Quaternion q)
{
Vector3 position = coords.ToVector3();
obj.Instantiate(origin, position, q);
}
}
Also if you create implicit cast for your HexCoordinates to Vector3 you don't need to create overloading for Instantiate() method because converting will be implicitly
You are using using catlike coding's code. (This would have been helpful to mention in the question ;) ). In part 3 of the tutorial featuring this hex coordinate system, you can see how they would do something like below, accessing a hex inside of an array by calculating an index:
public HexCell GetCell (Vector3 position) {
position = transform.InverseTransformPoint(position);
HexCoordinates coordinates = HexCoordinates.FromPosition(position);
int index = coordinates.X + coordinates.Z * width + coordinates.Z / 2;
return cells[index];
}
So, since a HexCell has a transform.position, you can use that to get its center (making sure you don't access out of bounds):
private void TouchCell(Vector3 point)
{
point = transform.InverseTransformPoint(point);
HexCoordinates coordinates = HexCoordinates.FromPosition(point);
int index = coordinates.X + coordinates.Z * width + coordinates.Z / 2;
if (index >=0 && index < cells.Length)
{
Vector3 worldPos = cells[index].transform.position;
Instantiate(cubes, worldPos, Quaternion.identity);
Debug.Log("Touched at:" + coordinates);
}
}
Better yet, it may be worthwhile to make a method to retrieve this index, for the sake of code reuse:
private bool IsValidCellIndex(Vector3 point, out int index)
{
point = transform.InverseTransformPoint(point);
HexCoordinates coordinates = HexCoordinates.FromPosition(point);
index = coordinates.X + coordinates.Z * width + coordinates.Z / 2;
return index >=0 && index < cells.Length;
}
private void TouchCell(Vector3 point)
{
if (IsValidCellIndex(point, out int index))
{
Vector3 worldPos = cells[index].transform.position;
Instantiate(cubes, worldPos, Quaternion.identity);
Debug.Log("Touched at:" + worldPos);
}
}
Or, just use GetCell as the tutorial does :)

List requires a type argument

There are three errors while compiling the code.
1.Using the generic type List requires 1 argument.
2.Using the generic type List requires 1 argument.
3. foreach statement cannot operate on variables of type because List does not contain a public definition for 'GetEnumerator'
The program of Polymorphism example is below.
namespace PolymorExample
{
abstract class Shape
{
public abstract void area();
}
class Rectangle : Shape
{
private double length;
private double width;
public Rectangle(double length, double width)
{
this.length = length;
this.width = width;
}
public override void area()
{
Console.WriteLine("Rectangel Area: {0}", length * width);
}
}
class Triangle : Shape
{
private double baseline;
private double height;
public Triangle(double baseline, double height)
{
this.baseline = baseline;
this.height = height;
}
public override void area()
{
Console.WriteLine("Triangel Area: {0}", baseline * height / 2.0);
}
}
class Circle : Shape
{
const double PI = 3.14;
private double radius;
public Circle(double radius)
{
this.radius = radius;
}
public override void area()
{
Console.WriteLine("Circle Area: {0}", radius * radius * PI);
}
}
public class TestShape
{
static void Main()
{
List shapes = new List();
Shape shape1 = new Rectangle(10, 10);
shapes.Add(shape1);
shapes.Add(new Circle(10));
shapes.Add(new Triangle(10, 10));
shapes.Add(new Circle(20));
foreach (Shape s in shapes)
{
s.area();
}
Console.Read();
}
}
}
If you take a look at the documentation for the List<T> class, you'll notice that List is a generic type (hence the <T>), and generic types require a parameter (or more) that specifies the type(s) of object it will use/contain. You must specify some type, even if it's just object.
In your case, you have a list of Shape objects, so your initialization code can be modified (and simplified by using collection initializer syntax) to specify that type:
var shapes = new List<Shape>
{
new Rectangle(10, 10),
new Circle(10),
new Triangle(10, 10),
new Circle(20)
};
List<Shape> shapes = new List<Shape>();
you need the shape type in your list declaration so it knows what its a list of

C# coding problems with Wiimote

Currently working on creating a VR head tracking using Wii remotes have faced a error.
The class *** can be designed, but is not the first class in the file.Visual Studio requires that designers use the first class in the file. Move the class code so that it is the first class in the file and try loading the designer again.
I have split the code in different pages however I receive the same error. This is the code I'm working on:
namespace WiiDesktopVR
{
class Point2D
{
public float x = 0.0f;
public float y = 0.0f;
public void set(float x, float y)
{
this.x = x;
this.y = y;
}
}
public class WiiDesktopVR : Form
{
struct Vertex
{
float x, y, z;
float tu, tv;
public Vertex(float _x, float _y, float _z, float _tu, float _tv)
{
x = _x; y = _y; z = _z;
tu = _tu; tv = _tv;
}
public static readonly VertexFormats FVF_Flags = VertexFormats.Position | VertexFormats.Texture1;
};
Vertex[] targetVertices =
{
new Vertex(-1.0f, 1.0f,.0f, 0.0f,0.0f ),
new Vertex( 1.0f, 1.0f,.0f, 1.0f,0.0f ),
new Vertex(-1.0f,-1.0f,.0f, 0.0f,1.0f ),
new Vertex( 1.0f,-1.0f,.0f, 1.0f,1.0f ),
};
}
}
Thanks
Move Point2D to the bottom of the file. Best practices state you should have only one class per file, so taking Stuart's advice and moving it to another file would be best.
namespace WiiDesktopVR
{
public class WiiDesktopVR : Form
{
struct Vertex
{
float x, y, z;
float tu, tv;
public Vertex(float _x, float _y, float _z, float _tu, float _tv)
{
x = _x; y = _y; z = _z;
tu = _tu; tv = _tv;
}
public static readonly VertexFormats FVF_Flags = VertexFormats.Position | VertexFormats.Texture1;
};
Vertex[] targetVertices =
{
new Vertex(-1.0f, 1.0f,.0f, 0.0f,0.0f ),
new Vertex( 1.0f, 1.0f,.0f, 1.0f,0.0f ),
new Vertex(-1.0f,-1.0f,.0f, 0.0f,1.0f ),
new Vertex( 1.0f,-1.0f,.0f, 1.0f,1.0f ),
};
}
class Point2D
{
public float x = 0.0f;
public float y = 0.0f;
public void set(float x, float y)
{
this.x = x;
this.y = y;
}
}
}

Implement a Resize/Move/Save Visitor Pattern

I am making a paint program where i can make Rectangle/Ellipse. In that program i can move/resize them but also save them.
My problem is now that i need to make a visitor pattern(Resize/Move and save) But I don't know where i should start.
These are the method i use at the moment:
public abstract void ResizeShape(PosSizableRect posSizableRect, float lastX, float lastY, float newX, float newY);
public abstract void MoveShape(int x, int y);
private void Write(List<Shape> shapes, StreamWriter streamWriter, string tabs = "")
sorry can't give you pictures because of my reputation...
public interface IShape
{
void Resize(PosSizableRect posSizableRect, float lastX, float lastY, float newX, float newY);
void Move(int dx, int dy);
void Write (StreamWriter writer, string tabs ="");
void AcceptVisitor(IVisitor visitor);
}
public interface IVisitor
{
void Visit(IShape shape);
}
Thats the interfaces, now the implementation (one example)
public class MoveVisitor : IVisitor
{
private int dx;
private int dy;
public MoveVisitor(int dx, int dy)
{
this.dx = dx;
this.dy = dy;
}
public void Visit(IShape shape)
{
shape.Move(dx,dy);
}
}

Collision between circle and a radius

I need to implement collision detection here. The objects i have here are a ball/circle and a rectangle. The balls are moving vertically, while the rectangle is moving horizontally. The condition is that if the ball and rectangle touch each other then an event should be raised. I have been trying to do that for a while with my colleague but without success. This is my first program in C# so please bear with me.
here is my code:
public partial class Form1 : Form
{
bool collided = false;
Player player;
List<Ball> balls;
const int fps = 60;
public Form1()
{
InitializeComponent();
balls = new List<Ball>();
Random r = new Random();
for(int i =0; i<1;i ++)
{
balls.Add(new Ball(Width, Height,r));
}
var task = new Task(Run);
task.Start();
player = new Player()
{
x = this.Width/2,
y = (Height*9/10),
xvel = 10,
brush = Brushes.Black,
};
}
protected void Run()
{
while (true)
{
for(int i = 0; i < balls.Count; i++)
{
balls[i].Move(this.Width);
}
this.Invalidate();
Thread.Sleep(1000 / fps);
}
}
private void Form1_Paint(object sender, PaintEventArgs e)
{
Graphics g = e.Graphics;
g.Clear(Color.White);
for(int i = 0; i < balls.Count; i++)
{
balls[i].Draw(g);
}
player.DrawPlayer(g);
}
//This is the part where i was trying to check collision between the circle and a ball
private void CheckCollision(PaintEventArgs e)
{
if (player.IntersectsWith(balls))
{
player.Intersect(balls);
if (!player.IsEmpty)
{
collided = true;
MessageBox.Show("collision detected");
}
}
}
}
public class Player
{
public float x, y, xvel;
public Brush brush;
public Player()
{
}
public void DrawPlayer(Graphics g)
{
g.FillRectangle(brush, new RectangleF(x, y, 30,30));
}
public void MovePlayerLeft(int gameWidth)
{
if (x > 0)
{
x -= xvel;
}
}
public void MovePlayerRight(int gameWidth)
{
if (x < gameWidth-47)
{
x += xvel;
}
}
}
public class Ball
{
public float x, y, yvel, radius;
public Brush brush;
public Ball(int gamewidth,int gameHeight,Random r)
{
x = r.Next(gamewidth);
y = r.Next(gameHeight);
yvel = r.Next(2) + 5;
radius = r.Next(10) + 5;
brush = new SolidBrush(Color.Blue);
}
public void Move(int gameHeight)
{
if (y + radius >= gameHeight)
{
y = 0;
}
y += yvel;
}
public void Draw(Graphics g)
{
g.FillEllipse(brush, new RectangleF(x-radius,y - radius, radius * 2, radius * 2));
}
}
If you're trying to figure out if a rectangle and a circle is intersecting, try this algorithm for each of the four sides:
Circle line-segment collision detection algorithm?
You can probably speed this up by checking if corners are inside the circle.
Also, remember that a circle completely inside a rectangle and vice versa should probably count as a collision.

Categories

Resources