1 module prova.core.entity;
2 
3 import prova;
4 
5 ///
6 class Entity
7 {
8   ///
9   Vector3 position;
10   ///
11   Quaternion rotation;
12   ///
13   Vector3 scale = Vector3(1, 1, 1);
14   ///
15   Vector3 velocity;
16   /// Velocity is multiplied by (1 - friction) every tick
17   float friction = 0;
18   package bool isSetup = false;
19   package Scene _scene;
20   package LinkedList!(Collider2D) colliders2d;
21   package LinkedList!(Audio) audioSources;
22   private LinkedList!(int) tags;
23 
24   ///
25   this()
26   {
27     colliders2d = new LinkedList!(Collider2D);
28     audioSources = new LinkedList!(Audio);
29     tags = new LinkedList!(int);
30   }
31 
32   ///
33   final @property Scene scene()
34   {
35     if(!_scene)
36       throw new Exception("Entity is not attached to a scene");
37     return _scene;
38   }
39 
40   /// Shortcut for scene.game
41   final @property Game game()
42   {
43     return scene.game;
44   }
45 
46   /// Shortcut for scene.game.input
47   final @property Input input()
48   {
49     return scene.game.input;
50   }
51 
52   ///
53   final Matrix getLocalTransformMatrix()
54   {
55     Matrix transform = Matrix.identity;
56     transform = transform.scale(scale);
57     transform = transform.rotate(rotation);
58     transform = transform.translate(position);
59 
60     return transform;
61   }
62 
63   ///
64   final void addTag(int tag)
65   {
66     tags.insertBack(tag);
67   }
68 
69   ///
70   final void removeTag(int tag)
71   {
72     tags.remove(tag);
73   }
74 
75   ///
76   final bool hasTag(int tag)
77   {
78     return tags.contains(tag);
79   }
80 
81   ///
82   final void attach(Collider2D collider)
83   {
84     if(collider.entity != this)
85       throw new Exception("Collider can not be attached to non owner entity");
86 
87     if(colliders2d.contains(collider))
88       throw new Exception("Collider already added");
89 
90     if(scene)
91       scene.collider2DMap.add(collider);
92 
93     colliders2d.insertBack(collider);
94   }
95 
96   ///
97   final void remove(Collider2D collider)
98   {
99     if(scene)
100       scene.collider2DMap.remove(collider);
101 
102     colliders2d.remove(collider);
103   }
104 
105   ///
106   final void attach(Audio source)
107   {
108     if(source.channels == 2)
109       throw new Exception("Source must use a mono format");
110 
111     if(source.entity)
112       throw new Exception("Remove the audio before attaching it to a new entity");
113 
114     if(scene)
115       scene.audioSources.insertBack(source);
116 
117     audioSources.insertBack(source);
118     source.entity = this;
119   }
120 
121   ///
122   final void remove(Audio source)
123   {
124     if(scene)
125       scene.audioSources.remove(source);
126 
127     audioSources.remove(source);
128     source.entity = null;
129   }
130 
131   /// Called when first attached to a scene
132   void setup(){}
133   /// Called when attached to a scene
134   void start(){}
135   /// Called every update tick
136   void update(){}
137   /// Called every draw tick (skipped if update loop is behind)
138   void draw(RenderTarget renderTarget, Matrix transform){}
139 
140   ///
141   void onCollisionEnter2D(Collider2D collider, Collider2D other){}
142   ///
143   void onCollision2D(Collider2D collider, Collider2D other){}
144   ///
145   void onCollisionExit2D(Collider2D collider, Collider2D other){}
146 }