C# Artemis Entity System Tutorial


Artemis is a high performance Entity System framework for games, originally written in Java by Arni Arent and Tiago Costa, now ported to C#.
Its goal is to provide a clean API to abstract your game world organization into entities, components and systems.
Artemis has no dependencies (for PC, in Xbox and Windows Phone 7 we have one) and can be used with any game framework or library, 2D or 3D, and even multiplatform, if you use it with Mono/MonoTouch/Mono4Android.

Differences from the original version

We support all the features included in the original Java version, but we’ve also added the following features:

  • Multithreading Support (two ways of doing this)
  • Specialized System templates for your multithreading needs
  • Communication between Systems using a Blackboard approach
  • Bugs fixed, performance improvements
  • Xbox/WP7/Mono(Android/Linux/Mac/iOS) support
  • Events for intercepting adding/removal of entities/components
  • Blackboard for sharing common objects between systems
  • Entity Pool (to make objects reusable, minimize garbage collection activity, improve performance)
  • Small goodies, like feeding the EntityWorld with whole Entities(maybe loading from external resources), enabling/disabling systems and entities, getting Entity tag, API shortcuts(see unit tests for more on this), etc.

Getting Started

  • Entities are only an aggregation of Components, identified by a unique id
  • Components are only data
  • Systems publish/subscribe to Components, creating behavior

There is much more to tell about this paradigm and we already have rich articles which inspired this framework. Some of them:

And many more can be found here.

Your components must inherit from the class Component or ComponentPoolable if you want it to use the Artemis Component Pool. Example:

//Add this Attribute and extend ComponentPoolable if you want your Component to use Artemis Component Pool
[Artemis.Attributes.ArtemisComponentPool(InitialSize=5,Resizes=true, ResizeSize=20, isSupportMultiThread=false)]
class Velocity : ComponentPoolable
{
        private float velocity;
        private float angle;

        public Velocity() { }

        public Velocity(float vector)
        {
            velocity = vector;
        }

        public Velocity(float velocity, float angle)
        {
            this.velocity = velocity;
            this.angle = angle;
        }

        public float Speed {
            get { return velocity;}
            set { velocity = value; }
        }

        public float Angle
        {
            get { return angle; }
            set { angle = value;}
        }

        public void AddAngle(float a)
        {
            angle = (angle + a) % 360;
        }

        public float AngleAsRadians
        {
            get { return (float)Math.PI * angle / 180.0f; }
        }

        //obligatory for poolable Components
        public void Cleanup()
        {
             coords = Vector3.Zero;
        }
}

A sample for entity assembling:

Entity e = world.CreateEntity(); // you can pass an unique ID as first parameter.
e.AddComponent(new Transform(200,400));
e.AddComponentFromPool(new Velocity(2.4f,0.9f)); // use AddComponentFromPool if the Component extend from ComponentPoolable
e.Refresh();// always call Refresh() when adding/removing components!

Your systems should inherit from one of the following templates:

  • EntitySystem – the simplest system template, not tied to components, good for stuff like collision
  • EntityProcessingSystem – a template for processing many entities, tied to components
  • IntervalEntitySystem – a simple system template, not tied to components, process periodically, based on world delta.
  • IntervalEntityProcessingSystem – a template that process entities periodically, based on world delta, tied to components.
  • ParallelEntityProcessingSystem – a template to leverage your multicore CPU for processing many entities, tied to components
  • ProcessingSystem – a template that process whichever logic you desire, without being tied to components
  • QueueProcessingSystem – instead of filter by components, this system process entities that are added to its public queue
  • HybridQueueProcessingSystem – process entities by queue and components
  • QueueProcessingSystemThreadSafe – process entities by a public static thread safe queue
  • FQueueSystemProcessingThreadSafe – process anything (not only entities) added to its public static thread safe queue
  • TagSystem – a simple system template, not tied to components, process a tagged entity
  • IntervalTagSystem – a simple system template, not tied to components, process a tagged entity periodically, based on world delta.
  • DelayedEntitySystem – a simple system template that starts process after a given time, based on world delta.
  • DelayedEntityProcessingSystem – a template that starts processing entities after a given time, based on world delta. Tied to components

And here is a system example, using Velocity and Transform components to create the Movement behavior:

//Add this attribute so the EntityWorld knows the systems it should execute, use the Layer to determine execution order
[Artemis.Attributes.ArtemisEntitySystem(ExecutionType = ExecutionType.UpdateSynchronous, Layer = 1)]
public class MovementSystem : EntityProcessingSystem {

    public MovementSystem() : base(Aspect.All(typeof(Transform), typeof(Velocity))) { }

    public override void Initialize() {}

    public override void Process(Entity e) {
        Velocity velocity = e.getComponent();
        float v = velocity.Speed;

        Transform transform = e.getComponent();

        float r = velocity.AngleAsRadians;

        float xn = transform.X + (TrigLUT.Cos(r) * v * world.Delta);
        float yn = transform.Y + (TrigLUT.Sin(r) * v * world.Delta);

        transform.SetLocation(xn, yn);
    }
}

On your game initialization, create a new EntityWorld and initialize it:

var world = new EntityWorld();
world.InitializeAll(true); // pass true/false to enable/disable DataAttributes on Systems

Update or Draw the World:

world.Update();
world.Draw(); // do this on a different loop, e.g: every 15 ms

And you are good to go. The Entity object has some intuitive methods like Delete(), GetComponent(), RemoveComponent(), which you can see in action on the example game.

Aspects

Aspects are used in the constructor of your entity systems to tell them which components they should be interested. At the moment we have three methods to build Aspects:

  • Aspect.All(params Type[] types) – Most of the time you will use this option, so the system processes entities which have all components of the Aspect.
  • Aspect.One(params Type[] types) – The system will process entities which have at least one of the components of the Aspect.
  • Aspect.Exclude(params Type[] types) – The system will not process entities which have at least one of the components of the Aspect.

You can also compose your Aspect utilizing these methods together, example:

public LogEnemySystem() : base(Aspect.All(typeof(Health)).One(typeof(Koopa),typeof(Goomba),typeof(Magikoopa)).exclude(typeof(Ghost))) {}

Extending Systems

It’s quite simple to extend the EntitySystem with your own logic, an example can be found here, which gives us less setup on systems which only uses Aspect.All(), example:

[Artemis.Attributes.ArtemisEntitySystem(ExecutionType = ExecutionType.UpdateSynchronous, Layer = 1)]
public class MovementSystem : EntityComponentProcessingSystem {
    public override void Process(Entity e,Transform transform, Velocity velocity) {
        float v = velocity.Speed;
        float r = velocity.AngleAsRadians;

        float xn = transform.X + (TrigLUT.Cos(r) * v * world.Delta);
        float yn = transform.Y + (TrigLUT.Sin(r) * v * world.Delta);

        transform.SetLocation(xn, yn);
    }
}

Templates

Create your entity templates to avoid manually creating and configuring entities:

[Artemis.Attributes.ArtemisEntityTemplate("BulletExplosion")]
public EnemyTemplate : Artemis.IEntityTemplate {
	public Entity BuildEntity(Entity e,EntityWorld entityWorld, params object[] args) {
		e.AddComponent(new Transform(200,400));
		e.AddComponent(new Velocity(2.4f,0.9f));
	}
}

Create your entities with the template applied:

var enemy = world.CreateEntityFromTemplate("BulletExplosion",array_of_parameters); // you can also use an alternative signature passing a custom unique id as the first parameter.
enemy.Refresh();

Blackboard

You can easily share common objects between systems using the blackboard, here is a XNA example, on the game initialization:

EntitySystem.BlackBoard.SetEntry("ContentManager", Content);
EntitySystem.BlackBoard.SetEntry("GraphicsDevice", GraphicsDevice);
EntitySystem.BlackBoard.SetEntry("SpriteBatch", spriteBatch);

Then you can retrieve the objects inside systems like this:

this.device = EntitySystem.BlackBoard.GetEntry("GraphicsDevice");
this.spriteBatch = EntitySystem.BlackBoard.GetEntry("SpriteBatch");
this.contentManager = EntitySystem.BlackBoard.GetEntry("ContentManager");

Games created with Artemis C#

Magnetic by Nature – by Tripleslash Studios. They also have a Kickstarter running for the game, support it!

Discussion, issues, suggestions

We have a forum section here.

 Use It !!!

,

  1. #1 by http://www.ljusihus.se/moncleroutlet.aspx on 21 de julho de 2017 - 8:56 am

    The supplement ended up being in that great amount I by no means thought your high quality is so exceptional. Its gorgeous. This mother is going to prefer that in Xmas morning where she starts present and it styles as though I invested a lot more, still rates ended up being just very good!!

  2. #2 by http://www.cozy-time.co.uk/londonprice.asp on 21 de julho de 2017 - 8:57 am

    We have purchased this one brand of bracelet a few times. Every a person is very cute, prepared well, cannot tarnish then meaningful based on which kind of one you purchase and/or just who people present it in order to.

  3. #3 by gedvna on 21 de julho de 2017 - 12:01 pm

    「中国を混乱に陥れる最善の策は深い関わりを築くことだと、アメリカのエリートたちは考えている」と、中国のある軍関係者は語る。 )というように……eショップ・eコマースの普及という…… 差し止め件数が過去最高を更新したのは3年連続。 [url=http://austain.fun-so.com/unpiu/moncler_1/index.html]モントレー ル ダウン[/url]
    北九州市の雑居ビルで5千点を超える偽ブランド服が見つかった。 後任の経産相、法相にそれぞれ内定した宮沢洋一自民党政調会長代理(64)と上川陽子元少子化担当相(61)は、21日午前の皇居での認証式を経て正式に就任する。
    [url=http://ibbotechnologies.com.br/lucie/moncler_1/index.html]モンクレール ダウン コピー[/url] 丈も長めなので、インナーにワンピース等も合わせ易くオケージョンを選ばず使えますね。 ★カラー ネイビー ★ロングコートモデルの【GRIMBERT】ビジネスシーンでも活躍しそうなチェスタータイプのデザインです。
    [url=http://aladimma.com/jackets/moncler_1/index.html]{モンクレール ダウン ニット|モンクレール ダウン ワッペン|ブランド 財布 クリーニング|モンクレール ダウン ニット|ダウン ジャケット モンクレール メンズ|モンクレール メンズ サイズ|モンクレール ロング ダウン メンズ|モンクレール メンズ ダウン コート|レディース ダウン 人気|ダウン ジャケット アウトレット}[/url]
    個人が安さにつられて偽物と気づかないまま注文するケースがあるという。 お電話でのご注文の場合、代金引換のみ、送料はお客様負担となります。 [url=http://www.solveproblem.in/jersey/moncler_1/index.html]モンクレール ダウン ロング メンズ[/url]
    部屋でメールを確認したんですが、それまでカンカンだった奥さん、急に静かになりました♪「お前のミスやないかい!」と、思いっきり突っ込みたかったボクですが、今後のことを考えて、そ~っとしておきました(笑)。 「キム着」と同じように「奈良着」という言葉も生まれた。
    [url=http://imc-sanko.xsrv.jp/montp/moncler_1/index.html]モンクレール ダウン[/url] お電話でのご注文の場合、代金引換のみ、送料はお客様負担となります。 東京・銀座にある資生堂の直営店「ザ・ギンザ」に23日、空中にバラの映像が浮かんで咲くアートディスプレー「ミラージュローズ」がお目見えした。
    [url=http://austain.fun-so.com/unpiu/moncler_1/index.html]モンクレール レザー ダウン[/url]

  4. #4 by PHP Programmer on 21 de julho de 2017 - 12:03 pm

    The information talked about inside the write-up are a number of the most beneficial available

  5. #5 by http://www.ja-trax.com/fr/soledshoes.asp on 21 de julho de 2017 - 12:31 pm

    This particular goods had been at such a awesome price I not thought that grade would be quite excellent. It’s striking. That mama will likely love they regarding Holiday early morning once she opens present and it appearances like I spent alot more, but rates had been simply great!!

  6. #6 by Dedirbug on 21 de julho de 2017 - 12:59 pm

    generic cialis rechnung

    [url=http://cheapcialistyonline.com/]cialis generic[/url]

    cheap cialis

    esiste il cialis da 5 mg

  7. #7 by Brawl Stars hack 2015 Android on 21 de julho de 2017 - 1:38 pm

    I’ve learn several excellent stuff here. Certainly value bookmarking for revisiting.
    I surprise how a lot attempt you set to make such a magnificent informative web site.

  8. #8 by my site on 21 de julho de 2017 - 1:40 pm

    Excellent . ostrich eggovercom! I would like to beginner even as anyone modify your internet site, how will i subscribe for the site web page? The profile solved the problem the appropriate package. My partner and i ended up touch knowledgeable with this your own transmit given bright translucent concept

  9. #9 by CharlesDiado on 21 de julho de 2017 - 1:41 pm

    wh0cd422174 [url=http://neurontin.us.org/]Order Neurontin Online[/url] [url=http://buyampicillin.us.org/]generic ampicillin[/url] [url=http://cialis20mg.us.org/]cialis 20mg[/url]

  10. #10 by http://www.cheapmoncler.xyz/ on 21 de julho de 2017 - 2:08 pm

    I’ve purchased this brand name concerning bracelet a number of circumstances. Every single a person is very sweet, done very well, cannot tarnish then important depending on what an individual you buy additionally just who you render information technology in order to.

  11. #11 by cheap nike roshe run on 21 de julho de 2017 - 2:48 pm

    I’ve purchased it brand name regarding bracelet various days. Every single a person is ultra adorable, established well, cannot tarnish as well as important based on that single you purchase plus that shoppers present it and.

  12. #12 by http://www.paradis-haver.dk/laboutin.asp on 21 de julho de 2017 - 2:49 pm

    We have purchased the brand name concerning bracelet a number of circumstances. Every a person is ultra pretty, done very well, cannot tarnish furthermore meaningful depending on what any you purchase then that shoppers provide this at.

1 876 877 878
(não será publicado)