Delta Engine Blog

AI, Robotics, multiplatform game development and Strict programming language

How to compose entities - Build a smiley out of Ellipse2D components

This is a small tutorial article from our wiki on how to create entities via our new system, more to come soon:

This article walks you through the steps of creating a custom entity with child entities using the Ellipse2D class. Everything you see here can also be done with the Editor by just dragging components and entity templates into your entity. The Smiley entity can be reused and be combined with any other component as well (rotate, scale, outline, physics, etc.)

The Ellipse2D class combines the following components (the same will be added if you drag in an Ellipse in the Editor):

  • Ellipse2DComponent for the ellipse x and y radius
  • Polygon2DComponent for the polygon points
  • As well as Vector2D for the position, Size (automatically calculated from the points) and Color
  • Many other components can be attached via the properties available in the Entity2D base class (Rotation, Scale, Outline, Pivot, etc.) or just by attaching more components like Image, GradientColor, Rotate, Velocity, Gravity, etc.

Let's build a new entity based on just that entity. Let's start with a unit test like in the other Tutorials:

1:
2:
3:
4:
5:
6:
[Test]
public void BuildSmileyEntity()
{
       
var smileyYellow = new Color(1.0f, 0.9f, 0.2f);
       
var smiley = new Ellipse2D(Vector2D.Zero, 0.25f, smileyYellow);
}

which produces just a yellow circle:

Next we should add 2 ellipses for the eyes and connect them to the parent circle:

1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
[Test]
public void BuildSmileyEntity()
{
       
var smileyYellow = new Color(1.0f, 0.9f, 0.2f);
       
var smiley = new Ellipse2D(Vector2D.Zero, 0.25f, smileyYellow);
       
var leftEye = new Ellipse2D(new Vector2D(-0.05f, 0.1f), 0.02f, 0.04f, Color.Black);
       
var rightEye = new Ellipse2D(new Vector2D(0.05f, 0.1f), 0.02f, 0.04f, Color.Black);
        leftEye
.AddParent(smiley.Entity);
        rightEye
.AddParent(smiley.Entity);
}

For the mouth a simple ellipse is not going to cut it, but we can use a trick and just render 2 ellipses with the second smaller one overwriting the first one with yellow again, leaving just the mouth part in black. We should also render the eyes next. Keep in mind that doing this kind of fine-tuning is much easier with the Editor and should not be done in code, we just want to illustrate how things work here.

1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
[Test]
public void BuildSmileyEntity()
{
       
var smileyYellow = new Color(1.0f, 0.9f, 0.2f);
       
var smiley = new Ellipse2D(Vector2D.Zero, 0.25f, smileyYellow);
       
var mouth = new Ellipse2D(new Vector2D(0, -0.0225f), 0.18f, 0.165f, Color.Black);
        mouth
.AddParent(smiley.Entity);
       
var mouthOverlay = new Ellipse2D(new Vector2D(0, 0), 0.185f, 0.165f, Color.White);
        mouthOverlay
.AddParent(smiley.Entity);
       
var leftEye = new Ellipse2D(new Vector2D(-0.05f, 0.1f), 0.02f, 0.04f, Color.Black);
        leftEye
.AddParent(smiley.Entity);
       
var rightEye = new Ellipse2D(new Vector2D(0.05f, 0.1f), 0.02f, 0.04f, Color.Black);
        rightEye
.AddParent(smiley.Entity);
}

 

and we are done. Now we are free to use that entity as many times as we want. Lets put it in a method and use it as a template for many more smileys rotating and scaling around on the screen. Keep in mind we do not want to change the Smiley template entity parameters programmatically, just define it once and then change whatever you want in the derived entities based on the template.

Also notice we added a Rotate component and TapGesture trigger with a ChangeColorAction (to Orange) when clicking on a smiley. Each entity created from the template will get all these features as well and any future improvements also.

1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:

21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:

34:
35:
36:
37:
38:
[Test]
public void BuildSmileyEntity()
{
       
CreateSmiley();
}

private static Ellipse2D CreateSmiley()
{
       
var smileyYellow = new Color(1.0f, 0.9f, 0.2f);
       
var smiley = new Ellipse2D(Vector2D.Zero, 0.25f, smileyYellow);
       
var mouth = new Ellipse2D(new Vector2D(0, -0.0225f), 0.18f, 0.165f, Color.Black);
        mouth
.AddParent(smiley.Entity);
       
var mouthOverlay = new Ellipse2D(new Vector2D(0, 0), 0.185f, 0.165f, Color.White);
        mouthOverlay
.AddParent(smiley.Entity);
       
var leftEye = new Ellipse2D(new Vector2D(-0.05f, 0.1f), 0.02f, 0.04f, Color.Black);
        leftEye
.AddParent(smiley.Entity);
       
var rightEye = new Ellipse2D(new Vector2D(0.05f, 0.1f), 0.02f, 0.04f, Color.Black);
        rightEye
.AddParent(smiley.Entity);
        smiley
.Entity.AddComponent(new Rotate());
       
Scene.Current.AttachCommand(smiley.Entity, new TapGesture(),
          new ChangeColorAction());
       
return smiley;
}

[Test]
public void CreateManyRotatingAndScalingSmileys()
{
       
var smileyTemplate = CreateSmiley().ConvertToTemplate();
       
var random = Resolve<Randomizer>();
       
var allSmileys = new List<Polygon2D>();
       
for (int num = 0; num < 50; num++)
       
{
               
var smiley = new Polygon2D(smileyTemplate);
                smiley
.Position = new Vector2D(random.Get(-0.45f, 0.45f),
                   random.Get(-0.3f, 0.3f));
                smiley
.Scale = new Scale(random.Get(0.05f, 0.15f));
                smiley
.Rotation = random.Get(0, 360);
                allSmileys
.Add(smiley);
       
}
}