FIT CTU
Adam Vesecký
vesecky.adam@gmail.com
Lecture 4
Components
Game model is a model of a domain in which the simulated world takes place.
Domain Model
Presentation Model
Physics model
AI model
Networking model
Chessmaster 2000 (1986)
Chessmaster 11 (2007)
Chessmaster 2000 | Chessmaster 11 | |
---|---|---|
Domain model | Board, pieces, time, game rules | Board, pieces, time, game rules |
Presentation model | CGA Sprites, beep sounds | Animated 3D objects, 3D sounds |
Physics model | None | Rigidbody engine |
AI model | David Kittinger's engine | King engine |
Networking model | None | Move commands |
Heroes of Might and Magic
Belegost (1989)
Polda (1998-2020)
Dreamfall Saga (1999-2016)
This may work for attributes but not for game logic
Summary
Entity
Attribute
Property
Component
System
Stage
Maze
GameManager
BoxBehavior
PacmanBehavior
Simple games
Complex games
By modifying the container object's state
By direct calls
By using a message broker
Unicast
Multicast
Broadcast
1 | void Object::SendEvent(StringHash eventType, VariantMap& eventData) { |
2 | SharedPtr<EventReceiverGroup> group(context->GetEventReceivers(this, eventType)); |
3 | if (group) { |
4 | group->BeginSendEvent(); |
5 | |
6 | for (unsigned i = 0; i < group->receivers_.Size(); ++i) { |
7 | Object* receiver = group->receivers_[i]; |
8 | // Holes may exist if receivers removed during send |
9 | if (!receiver) continue; |
10 | |
11 | receiver->OnEvent(this, eventType, eventData); |
12 | |
13 | // If self has been destroyed as a result of event handling, exit |
14 | if (self.Expired()) { |
15 | group->EndSendEvent(); |
16 | context->EndSendEvent(); |
17 | return; |
18 | } |
19 | processed.Insert(receiver); |
20 | } |
21 | group->EndSendEvent(); |
22 | } |
23 | } |
1 | public interface ICustomMessageTarget : IEventSystemHandler |
2 | { |
3 | // functions that can be called via the messaging system |
4 | void Message1(); |
5 | void Message2(); |
6 | } |
7 | |
8 | public class CustomMessageTarget : MonoBehaviour, ICustomMessageTarget |
9 | { |
10 | public void Message1() |
11 | { |
12 | // handle message |
13 | } |
14 | |
15 | public void Message2() |
16 | { |
17 | // handle message |
18 | } |
19 | } |
20 | |
21 | // sending message |
22 | ExecuteEvents.Execute<ICustomMessageTarget>(target, null, (x,y) => x.Message1()); |
Artemis framework
Atomic Game Engine
Unity
Unreal Engine
Godot Engine
1 | // new component |
2 | public class Health extends Component { |
3 | public int health; |
4 | public int damage; |
5 | } |
6 | |
7 | // new archetype |
8 | Archetype dragonArchetype = |
9 | new ArchetypeBuilder() |
10 | .add(Flaming.class).add(Health.class).build(world); |
11 | |
12 | public class MovementSystem extends EntityProcessingSystem { |
13 | public MovementSystem() { super(Aspect.all(Position.class, Velocity.class)); } |
14 | } |
15 | |
16 | // create new transmuter |
17 | this.transmuter = new EntityTransmuterFactory(world) |
18 | .add(FrozenFlame.class).remove(Flaming.class).build(); |
19 | |
20 | // apply transformation to entity |
21 | this.transmuter.transmute(entity); |
1 | public sealed class GameObject : Object { |
2 | public static extern GameObject CreatePrimitive(PrimitiveType type); |
3 | public unsafe T GetComponent<T>(); |
4 | public T[] GetComponents<T>(); |
5 | |
6 | public extern Transform transform { get; } |
7 | public extern void SetActive(bool value); |
8 | public extern string tag { get; set; } |
9 | public static extern GameObject FindGameObjectWithTag(string tag); |
10 | |
11 | public void SendMessage(string methodName, object value); |
12 | public void BroadcastMessage(string methodName, object parameter); |
13 | |
14 | public Scene scene {get;} |
15 | |
16 | public Component rigidbody {get;} |
17 | public Component rigidbody2D {get;} |
18 | public Component camera {get;} |
19 | public Component light {get;} |
20 | public Component animation {get;} |
21 | public Component renderer {get;} |
22 | public Component audio {get;} |
23 | |
24 | public void PlayAnimation(Object animation); |
25 | public void StopAnimation(); |
26 | } |
1 | // RocketComponent |
2 | void OnTriggerEnter2D (Collider2D col) { |
3 | // If it hits an enemy... |
4 | if(col.tag == "Enemy") { |
5 | // ... find the Enemy script and call the Hurt function. |
6 | col.gameObject.GetComponent<Enemy>().Hurt(); |
7 | // Call the explosion instantiation. |
8 | OnExplode(); |
9 | // Destroy the rocket. |
10 | Destroy (gameObject); |
11 | } |
12 | // Otherwise if it hits a bomb crate... |
13 | else if(col.tag == "BombPickup") { |
14 | // ... find the Bomb script and call the Explode function. |
15 | col.gameObject.GetComponent<Bomb>().Explode(); |
16 | |
17 | // Destroy the bomb crate. |
18 | Destroy (col.transform.root.gameObject); |
19 | |
20 | // Destroy the rocket. |
21 | Destroy (gameObject); |
22 | } |
23 | } |
Unity DOTS
EnTT
Entitas
A-Frame
ECSY
1 | var world = new World(); |
2 | world |
3 | .registerSystem(MoveSystem) |
4 | .registerSystem(RendererSystem); |
5 | |
6 | class MoveSystem extends System { |
7 | execute(delta, time) { |
8 | this.queries.moving.results.forEach(entity => { |
9 | let pos = entity.getMutableComponent(Position); |
10 | pos.x += entity.getComponent(Velocity).x; |
11 | }); |
12 | } |
13 | } |
The weak suffer. I endure.Planescape Torment