Episode Transcript
Available transcripts are automatically generated. Complete accuracy is not guaranteed.
Brooklin Myers (00:01):
Hello everyone
and welcome to the Elixir Newby
podcast.
Today I am joined by my friend,coworker and author of the
Entity Component System, ecsxFramework for Elixir, which is
for building games andsimulations and bringing that to
the Elixir ecosystem, which isincredibly exciting to see that
(00:23):
ecosystem expand.
Game development is somethingthat I think most folks haven't
traditionally thought about.
Now there are some applicationsbeing built in Elixir that are
kind of like simulation focused.
I believe there's a flightsimulator that is Elixir focused
(00:45):
on their back end, but it's notsomething that I think we
should have traditionally gonein the direction of.
So I'm really excited forAndrew's work here.
I've been getting to follow himalong on this project and see
how the library has beenevolving.
So, andrew, I'm super excitedto have you here.
Thank you so much for beinghere.
Andrew Berrien (01:05):
Thank you so
much for having me, Brooklin.
I'm glad to be here.
Brooklin Myers (01:10):
We get to chat
fairly frequently about Elixir
Dr Academy, so we both worktogether at Dockyard, but the
ECSX Framework is something thatyou have been working, I
believe, kind of like in yourspare time, finding room for it.
So how on earth do you manageboth the workload of work and
(01:35):
also develop a fully featuredlibrary at the same time?
How are you managing this?
Andrew Berrien (01:40):
Yeah, so I have
to give full credit to Dockyard.
I'm a senior Elixir engineer atDockyard and one of the things
that Dockyard does is provide wehave 32 hour workweeks, monday
through Thursday, and then onFridays we have what's called
(02:01):
Dockyard Fridays where we'reable to work on open source
contributions, work on our ownhobby projects, do independent
learning, things like thatbasically just a skill up day.
And so for me I started aprogram, a mentorship program,
(02:24):
with another Elixir engineer whois much more experienced than
me, and we were looking for aproject to work on.
And you know, at the time I wasnot particularly new to Elixir
but at the same time, like Istill was trying to approach
(02:46):
with a beginner's mind of likewhat is something that I can do
that would push me outside of myElixir comfort zone.
And you know, one of thosethings was a general usage of
OTP in projects.
Like I think a lot of Elixirdevelopers end up kind of almost
(03:12):
being forced into webdevelopment all day, every day.
You know that's like the mainuse case for for Elixir and you
know, obviously OTP plays a bigrole in Phoenix and in live view
, but I think that there'sthere's other ways where OTP is
(03:35):
such a versatile group oftechnologies that there's
there's a lot of applicationsfor it that I just had never
really done, had much experiencewith, and is, you know, is you
could still say that, like,there's there's a lot of avenues
out there, especially withregard to, like, embedded
(03:57):
systems, where you know most,most Elixir engineers have don't
really have any experience withthat, but my goal was to find
something that would push me tostretch my OTP muscles, so to
speak, but also end up with,hopefully, something that could
(04:20):
be a useful library for for theElixir community.
I was looking specifically forsomething that I felt like the
Elixir community was lacking or,at the very least, short on,
and I think that was the onething that, ever since I started
(04:42):
Elixir like, especially comingfrom object oriented languages
and and a math background too,which is, you know, like I feel
like goes really goes hand inhand with game development, and
so that was that was alwayssomething that was on my mind in
other languages.
And then, coming to Elixir,like, it's almost like you hit a
(05:03):
brick wall, like you raise you,you say the phrase game
development and everyone justlike is, like no, you like, you
don't even before the, you, the,the words even come off your
lips, people are just like, no,you, we don't do that here.
And so I think that one of oneof the things that I was really
(05:25):
thinking of was like why?
And then, what's potentialsolutions could Elixir have in
its toolkit, with, you know,having having OTP available to
us?
Like what can we, how can weuse those tools in order to get
around some of the perceivedlimitations of game development
(05:45):
in Elixir?
And that was that was a long, along process of me and my mentor
both working back and forth,like having ideas, implementing
ideas, watching those ideas fail, benchmarking different ideas,
having things that just werewere slower or harder to reason,
(06:11):
about adding unnecessarycomplexity, like trimming the
fat, like you know there was.
There was just so much like, ifyou were to see what the project
looked like at the beginning,it was really kind of a mess and
was slowly polished andpolished and polished until
eventually it was somethingusable.
And then, at that point, atthat point, it leads to several
(06:36):
other challenges which are like,okay, how to, how to get this
out there in the community, howto, how to prove it, how to how
to even sell ECS because, likeyou know some people who are
already in the game developmentspace have already heard of ECS.
(06:57):
Like maybe they're using theECS implementation in Unity and
they're like, oh, this isawesome, but I think for most
people they've they've nevereven heard of it before, so
definitely like there were.
There were several otherchallenges, even non programming
related that that it becameclear that we were going to have
(07:21):
to face in in bringing thislibrary to the community and and
finding a way that it can beuseful to people for their own
projects.
Brooklin Myers (07:30):
So with that,
it's very interesting that this
started out as what seems likekind of a learning project, like
, oh, I really want to learnabout this, and then has grown
into a okay, well now, how do weshare this with the community?
And so you're probably gettingto learn a lot of skills that
you probably hadn't even beenyour intention like.
(07:53):
How do you broadcast somethingto the community, how do you
make people aware of it?
How do you make it easy toadopt?
I know that you had me agesback go through and just play
with the system and then try itout.
That was super fun, but at thetime I don't think there was
much nearly the same level ofguides and easy entry, and so
(08:17):
I'm pretty sure I completelyflubbed it, like I had all the
things in the wrong order and II'm not sure what.
I just did things incorrectly,and I know you had mentioned
that that kind of inspired youto add more to it.
We can talk about how you'vemade adoption a lot easier, but
I really want to know what kindsof games, what kinds of tools
(08:43):
like before we get into theimplementation of ECS, and how
this this helps and what it does.
What does it let us do?
Andrew Berrien (08:53):
Yeah.
So I suppose the simplestanswer is it allows us to build
games in Elixir.
And you know, I think mostpeople in the Elixir community
who have come from otherlanguages, they we recognize
that.
You know what elix, what we doin Elixir.
(09:14):
It's not like you can't do itin other languages, like that.
That part's not really up fordebate.
But what is up for debate isthe experience that you're going
to have when building in thislanguage versus another language
, like maybe you get the sameend product, but what does it
feel like to develop?
How long does it take todevelop?
(09:35):
How many engineers did you needin order to make that happen?
And I think those are thestrengths that Elixir brings to
the table, among many others.
But I think that that's that'sreally one of the biggest deals
to people like, especially whenyou have experience in other
languages and a lot of othercode bases.
(09:57):
And then you come to Elixir andyou're like oh, okay, this is.
This actually has simplifiedthe development process quite a
bit, made the developmentprocess a lot quicker and and
taken out a lot of the foot guns, and so this kind of the same
philosophy is kind of what I wastrying to bring to ECSX.
(10:20):
Like it's not that you couldn'tbuild a game in Elixir before,
but what I want right now isthat you can build a game in
five minutes by yourself.
You know, like that's that'sreally what I'm I'm getting at
here is like the developerexperience should be, should be
number one.
Like I want people to be ableto pick this up, have a very
(10:44):
simple interface but also a verysimple design.
Architecture like this, evenoutside the ECSX framework, just
the entity component systemarchitecture as a whole is a
very, in my eyes, convenient wayof looking at a real time
(11:04):
application.
Like you have components andyou have systems.
That's that's pretty much it.
Like there's you have an entireback end just with that.
And components store your data.
Systems are the logic thatoperates on the data.
Like it's very, very simple andonce you're actually working in
(11:27):
a code base with thatarchitecture, it's it's very
simple to make changes.
Like when you need to add a newfeature, it's there's not as
much pieces of code that thatkind of touch your feature.
Like there's a lot morecompartmentalizing of what.
(11:49):
When you have a feature likeit's it's very likely that that
feature is going to have somedata that backs it and then some
logic that affects gameentities when that based on the
presence or value of thatcomponent.
(12:10):
So you have a feature, youcreate a component, you create a
system and there's your featureand you.
It is often the case that theexisting components and the
existing systems don't don'tneed to be touched.
So you get a good separation ofgame logic, you get separation
(12:36):
of data in a way that is stillvery composable, like you can
have.
I'm not sure if you want to gotoo far into like the ECS
architectural design process andin this talk, but basically if
(12:56):
you have a component like a hitpoints component, hp, you could
give that to any type of entityyou want and it will now have
hit points and it will now havesystems that operate on hit
points containing entity.
Entities with hit points willnow be included in that
(13:19):
selection.
So if you were to givesomething like a bullet some hit
points, like now, the bullet isnow it's not just this thing
that flies through the air anddeals damage, but it also is now
something that can take damagefrom things and maybe even die.
So you're you're really able toextend the entities in your
(13:44):
game really quite easily by justadding and removing components.
So instead of having like, okay, this is a player character
which always has these specificfields in the character, and
then you have this bullet andthat the bullet always has these
(14:04):
fields, you know, velocity andsuch and such it's, it takes
away all of the rigidity of thatand instead allows you to
compose components really anyway you want.
Brooklin Myers (14:18):
Yeah, the, the
composability really strikes me
is quite interesting and it'sability to bring these systems
together and bring thesecomponents together to create
this functioning game.
So I want to give a bit of anoverview of the different terms
we're using, maybe some examples, if that's possible, because
we've talked so far aboutentities, components, systems,
(14:42):
and then I know there's also afew other concepts, tags and
managers, and I think Iunderstand some of them and I
think I'm a little bit fuzzy onsome of them.
So Can we start with our, ourentity?
That is the thing that bindsour components together.
Right, that is the thing, isthat?
Andrew Berrien (15:01):
right, yeah,
well, so In a traditional game
like you would have entities andeach entity Will have a set of
data that always comes with thatentity.
If you have a player character,like it has, it's it's like a
map or a struct or whatever withthe fields inside it that make
(15:24):
up that entity.
In ECS X or any ECS game, anentity, entities, don't really
exist as data.
So if I have an entity and it'sa player character and it has,
let's say, hit points, level andclass, how that exists in the
(15:48):
database is you have a hitpoints component, a class
component and A level componentand that's it.
Like the reason why you knowthat those three thing that
there is a player character isbecause those are associated
with a particular ID.
So let's say you have theplayer characters, id is one,
(16:13):
two, three.
So the components job is twothings.
One is to store the data.
So if it has 50 hit points,like obviously has to store an
integer 50.
But then it also has to storewhat the ID of that entity that
it belongs to.
So your component now has yourID one, two, three of the entity
and then the hit points 50.
(16:33):
And same thing for the level.
Maybe it's an entity one, two,three, level three, something
like that so the entity neverreally, never really exists as
data somewhere.
The entity is just anassociation that all of the
(16:54):
components have to show whatentity that that component
belongs to, and so I thinkthat's one of the that's
probably the most difficultthing to wrap your head around
when getting into ECS is justthat data is always going to be
in the same place, is just thatdata is always components and
(17:16):
that you associate componentstowards Like a metaphysical
entity, like it doesn't actually.
Brooklin Myers (17:24):
The entity
doesn't exist in the database
somewhere, it just is right, andthat is because they're all
grouped together by some kind ofidentifier.
The entity really is theidentifier, in a way.
That's the thing that groupsall of your components together.
Your components track data,perfect.
And then let's talk about so.
(17:45):
We used hit points as ourexample of a component.
Let's continue that story tosystem.
What is a system?
Andrew Berrien (17:54):
Right.
So so we mentioned that let'ssay, a player has hit points, a
level and a class, so thesethings I'm maybe even we don't,
we don't pay so much attentionto class at first and just focus
on like hit points, even thewhole.
(18:16):
What's the whole point ofhaving hit points like that's?
That's really the question thatsystems ask is what is the
point of this component like ifyou have a piece of data that's
tied to your entity, like itsignifies that you're going to
want to use that for something,and so the system is that
(18:37):
something.
So in the case of hit points,hit points exist so that when
you get hit, you take damage, soyou like.
That right there shows what thesystem logic needs to be like.
The system logic is going tocheck for attacks that are
currently about to happen, andthen it's going to lower the
(19:01):
number that's in those hitpoints components for anyone
who's being attacked, and thenand so that's one system that's
like a damage system when youget hit, the damage system
remove Lovers, your hit points.
But hit points also serve thepurpose of when they reach zero,
(19:22):
you lose the game.
So there's that's anothersystem like what.
What this system is simplygoing to do is just look for Hit
point components that are zeroor less, and if it finds that,
then it's going to do somethingjust like the.
The damage component is like,it's trigger is An attack is
(19:48):
happening like, and so thatmight come from something else,
like in a you know a componentfor like attack, damage or
pending attack or howeverwhatever that trigger is, or
collision even, and then oncethat trigger is met, then the
system will Will deal the damagesame with the, the death system
(20:15):
like one.
The trigger is a health, a hitpoint component has gone to zero
, and then the effect of thelogic is that that entity that
has that component dies, and bytrigger.
Here I do want to clarify,because I think that that could
that could mean a few thingsconceptually when people hear
(20:36):
that word.
And here a trigger is reallyjust other component data, it's.
It's not necessarily like anevent, but if it is, if you do
have events like an attackthat's firing, like those are
still modeled with componentslike that's that's the thing,
does a lot of damage, that'sthat's the thing.
Designing with ECS is everythingis a component like.
(21:00):
You have to find some way tomake it into a component, even
if it seems like You're, you'renot really sure how do I do this
, and that's why a big part ofthis project is just teaching
the ECS design architecture.
Like you might see, you mightnot see as the user.
How is this?
(21:21):
A component like this seemslike something that should need
something special and it's likeno, there there is a way to
model this with components, andwhen you model it with
components, that's what gives itthe hook into the system.
That's what allows the systemsto know which entities to
operate on.
Which components to operate onis based on other component data
(21:42):
.
Brooklin Myers (21:45):
So I want to
clarify trigger here a bit for
myself, because my understandingis that systems will run on
every tick.
Is the trigger like a conditionthat determines if they should
Actually do something, or is atrigger outside of the system
like is this some control flowI'm writing in my system run
function, or is this somethingI'm writing outside of the
system?
Andrew Berrien (22:06):
Yeah, so this is
so once again, like ECS does a
fantastic job of simplifyingeverything.
Just like I said, when you havesome data and you don't know
how to store it, there's onlyone answer, like if your answer
isn't components, it's wrong,like so it's similar to the
actual game logic.
There's only one place for gamelogic to live and it's not
(22:28):
entities or components.
So when you have game logic,yeah, it has to be in the system
.
And what was your question?
It was about the selection ofwhat, what components, like what
is that trigger?
Brooklin Myers (22:45):
is that like a
bit of control flow?
I write inside of my system?
That's like if some Characteris in attacking range, do an
attack like, apply some damageto their, their health or
whatever it is, change acomponent in some way?
Andrew Berrien (23:02):
Right.
So generally, how?
How this is worked out for meis get all components of this
type.
So if you're something that islike, let's say, you're a system
that is going to reduce hitpoints for entities that are
(23:25):
poisoned, you know, if you'repoisoned you lose five hit
points per second, somethinglike that.
So what you're going to do isyou're going to just and this is
right in the API we have afunction it's get all, and so
you're gonna run Poison dot, getall, and you're gonna get all
of the poison components andthen from there, you know,
(23:48):
because the entities IDs arestored in those components.
Now you have a list of everyentity ID that the system needs
to operate on, and so if there'sa situation where maybe the
mere presence of the componentdoesn't signify it needs to
operate, but the value of it, soyou're fetching everything that
(24:10):
has Hit points and checking ifit's Less than ten, or maybe you
want to search for a specificvalue.
You want to find everyComponent, every hit point
component where the value iszero, like we have an API for
that as well, to search forspecific component values.
(24:32):
So really it's it's just aboutquerying components in a way
that's useful and that's why Iwould recommend that components
Should it should have a purpose,like how I said, like with hit
points, like oh, what's what'sthe purpose of hit points?
(24:53):
And it's like, well, does ittells you how much life your
character has?
But it's like that's not.
The question that I'm asking iswhy are there hit points?
Like what is the game featurethat requires hit points?
And when you think of it likethat, now hit points becomes a
trigger, now hit point and andmaybe on on the other end, hit
(25:16):
points are are going to beaffected by another trigger,
like, like I was was mentioningbefore, like attacks.
You know, maybe you have anattack that is a component like
this this attack has been madeand so when that system runs
through, it's going to look andsee what are all the pending
(25:36):
attacks.
Maybe you have a pending attackcomponent, what are all from
there?
That's the info that gives youthe information, that this that
gives the system the informationthat it needs in order to know
who, who's going to take thatdamage.
Brooklin Myers (25:52):
Okay.
So I think I roughly understandor at least I'm feeling
confident about components andsystems.
That's basically you have yourbehavior and your data and the
systems are going to run everytick.
They're going to use whatevercontrol flow they need, or maybe
they'll just get all componentsof a particular type.
Applies to operation.
Change things in your systemnow your systems change for the
(26:15):
next tick.
The thing that I think I'mfuzzy on is tags.
Can you help me understand tags, because I'm currently thinking
about them like a bullion, likeI've tagged this with poison,
but then I'm like well, whydon't I store that as a
component, as some kind of abullion field?
That's where I think I'm I'm alittle fuzzy.
Andrew Berrien (26:37):
Yeah, yeah, and
honestly you're not that fuzzy
in this case, because thatthat's that's pretty much spot
on, like a tag is basically abullion component.
So it's it's kind of a bit oflike syntactic sugar, because
you don't really need to storetrue or false, because if you
(27:02):
have the component then thevalue is always true.
You know.
So, there's no, there's nevergoing to be.
You know, oh, I'm going tostore the poison component and
have the value be false, becauseif that's the case, then just
don't add the component.
That's the magic, you know,that's still that, that thinking
from okay, well, I have acharacter and it has a field and
(27:24):
the field is poisoned Questionmark, and then it's going to say
true or false and that fieldhas to exist for every entity in
the world.
You know, it's not that likewith this, that player character
, it could have the component orit could not have the component
.
So there's not really a need tostore the Boolean value at all.
(27:46):
But that is a way that you canthink of it is like a component.
It's a component where the merepresence of the component gives
you all the data you need.
You don't actually have tostore some kind of value like an
integer or a string orsomething like that.
You know, if you have hitpoints, if you have a hit point
component with no value, thatdoesn't mean anything, it's like
(28:07):
how many, how many.
But if you have a poisonedcomponent, it's you don't really
.
A value is not going to helpthere, like you it.
If it.
Maybe you have different levelsof poison and so the component
is poison level.
That has a value.
But if the question is just areyou poisoned or not, there's no
(28:28):
value to store there and so taggives you an API that is
specific to that, because mostof the component API revolves
around the components value thatit stores.
The API around tags is just doyou have it or not?
And once again, the ability toget all and get all entities
(28:50):
that have that tag.
So if you put that poison tagon some entities like there's a
some single function, poison dot, get all and you're just going
to get all of the entities thathave that poison component.
So that's that's really goingto be the main way that like
almost for me at least, almostevery system that I write starts
(29:14):
with get all Of this type ofcomponent and that's going to be
like the trigger that tells thesystem what to operate on, and
tags tags are a perfect exampleof that.
Like it's, just get everythingthat has the tag.
That's what we want to dealwith right now.
Brooklin Myers (29:31):
So that's really
cool.
By the way, I got reallyexcited when you're talking
about not needing to store thedata of a billion.
Seems like such a like, like adough, like, like hit your head,
bop your head because you had aV8 or whatever it was Moments
like when you see, like if that,when, when people write, like
(29:53):
if variable equals equals true.
Yeah, that is one of the mostcommon patterns I have to train
students out of.
Is that like, hey, if you'rechecking if something is a bully
and just use the Boolean, so,or if you're returning true,
just use the condition that youhad or flip the condition.
If you're returning false, youdon't need all that extra?
(30:17):
So I do want to clarifysomething because it seems like
I could as a developer.
You know you can't.
You can encourage people downthe right path of development,
but they're always going to beable to write things in a weird
way.
But it doesn't make me wonder.
Are there limitations ofcomponents in terms of like what
data they can store?
I noticed we'll talk about thegenerators that you've added
(30:39):
later, I hope, I hope we havetime for that but I noticed that
you actually specify what typeof data something is going to
store in the generator, Ibelieve.
So, yeah, are there limitationsto like what type of data my
components can store, orrecommendations or like?
Because now I'm thinking, well,if I'm storing a Boolean in a
component, that's maybe a betteruse case for a tag, so what's?
(31:02):
the situation there.
Andrew Berrien (31:04):
Yeah, this is.
This is something that hasevolved over the course of ECSX
development and like what wewould find at first is that
people would create componentsand and then put like a map of a
(31:26):
bunch of different data that'srelevant to that component.
Like they might have a insteadof hit points components, they
might put like just player statsand then inside it would have
like a map that would say likehit points 50, mana 40, level
three class, rogue and so, andwhat this does really is it
(31:49):
prevents you from being able tosearch this data quite as
efficiently.
You're you're kind of couplingstuff together where it's like
okay, now when you take damageand you're going to get that,
you're going to get the playerstats component, and but now
you're getting hit points, manalevel class and you're only
(32:13):
operating on hit points.
So now you've fetched threethings and like this is this is
one of the main reasons why Ichose ECSX for elixir is because
of the downsides of messagepassing, like when you are going
to fetch some data from out ofmemory, like that's copied, like
(32:36):
a copy is made from one processheap to another and that data
has to be passed via a message.
So one of the big problems thatpeople have with game
development and elixir is thatthis has to happen like hundreds
of times per second.
You know, thousands of timesper second.
And we're basically, if we wereto take this to its logical
(33:01):
conclusion, you just get thestandard object oriented model
of like, give me the characterand you get 500 fields with it
and you only needed to operateon one of them.
So the whole goal of ECSX ingeneral is to only operate on
the field, so to speak, thatthat needs to be operated on.
(33:24):
When you want to get a piece ofdata, you only get that data.
You don't get any, anyunrelated stuff, in order to
minimize the amount of data thatis passed via message and
copied from process heap toprocess heap.
So when, when we were seeingthis kind of anti pattern of of
(33:47):
kind of like compositecomponents let's call them where
a component is storing a bunchof components inside of it, like
the, we were like OK, well, weneed a solution to this, but
also like this was a greatopportunity to introduce type
checking.
So the solution that that welanded on is components are
(34:09):
primitives.
Components are not going to bea map of data.
Components are not even goingto be a tuples of data
components are going to be aninteger or a string or like
right now I believe we also havetimestamps in there, like but
the the.
(34:29):
The goal there is to define whattype of data this component is
storing.
Like it doesn't make sense thathit points for one character
would be an integer and foranother character would be a
string.
Like when you define your hitpoints component, you're going
to define that as an integer ormaybe a float, and and
(34:53):
components should stay that way.
So when we do have typechecking for these, if you try
to create a hit points componentthat has a timestamp or a
string or something like that,then it's going to fail and and
the generators, as as you'vementioned several times, just
make this even easier.
(35:14):
Like it's already, creating acomponent is one quick line in
your terminal, but defining thattype is also just part of that
line it's.
We took took a lot ofinspiration from other
successful libraries usinggenerators like, for example,
like an Ecto, like when, whenyou're generating something in
(35:39):
Ecto, like it's, it's just oneline in a generator.
You can define the type, youcan define the different fields
in the schema, you can definereferences, etc.
And so that that was a goal forus is just to be able to spin
up a component.
Everything that component needsin one line from the generator.
Brooklin Myers (36:00):
Generators are
such a phenomenal tool and I
think they're.
They're.
Not everyone necessarily seestheir initial purpose.
I think a lot of folks think,oh generator, that'll make me
write code faster.
Right, that's the whole purpose.
That generates the code for me.
In reality, I think generatorsare an education tool first and
foremost.
They show developers here isthe style, here's how you should
write things like the Phoenixgenerators are a phenomenal
(36:23):
teaching tool showing studentshow everything connects together
for particular resource.
It's really really handy.
So I'm really excited to talkabout the kind of adoption
efforts that you've put intoECSX and helping people explore
that.
But I don't want to miss out onthe last piece of our system
that I'm still fuzzy, which isso.
(36:44):
We've talked about entities,components, systems tags, and
the last one, I believe, ismanagers.
Andrew Berrien (36:53):
Right, okay, so
when you create an ECSX
application like, we have asetup generator and basically
what the setup generator isgoing to do for you, amongst a
few other minor things, iscreate this manager, and so the
manager is the module that kindof ties everything together,
(37:17):
because we had we had gonethrough several different, more
complex designs for the, the ECS, like the underlying OTP design
, and one of the things that wefound that is not only simple
(37:41):
but also very useful is thesingle gen server, serializing
things through a single genserver and one of the big
problems with using at under thehood for storing things like it
.
I mean, there's so many amazingpositives to using at like, of
(38:04):
course, one of them being it'sin memory, so it's super
freaking fast.
But the downside is that youcan get race conditions and if
you have multiple systems thatare both trying to, you know and
and and we even kind of touchedon it a little bit, like with
hit points there's multiplereasons why your hit points
(38:27):
might go down, like it might bebecause you're poisoned, it
might be because you're gettingattacked, it might be that
that's just how the game works.
Is like hit points go down overtime, you know like there's all
sorts of reasons.
Maybe you could be gettinghealed and your hit points are
going up from a different thing.
So when when this happens, it'sdoesn't necessarily have a way
(38:50):
of handling that and not havingdata corruption, like that's
something you kind of have tobuild in yourself and most of
the time that happens by havinga gen server, basically like at
the gates, you know that youhave a guardian, that that is
all.
All traffic to and from theet's table is going to pass
(39:11):
through this gen server in orderto handle any kind of conflicts
like that.
And the thing that we reallyfound was that using a single
gen server to serialize all ofthe systems it allows allows the
developer to feel much safer indeveloping their system logic.
(39:32):
Not only is there not raceconditions, but you also now
know the order in which systemsare going to run and sometimes
that that could be.
That could be a big deal.
Like, for example, like if thedeath system, from going down to
zero hit points and losing thegame, does that happen before or
(39:55):
after you take damage?
Because if the death systemruns, says OK, you have five HP,
you're alive, and then rightafterwards you take damage.
Now this tick is ending withyou having Zero HP and still
being alive.
Maybe for some cases like,that's not good, and maybe in
(40:16):
most cases it still is, because,like, if the death is the first
thing that happens, then in thenext tick you're not gonna be
able to do anything.
You'll die first thing on thattick.
But I think that it allows youto reason about your systems in
a way that can be much moremanageable for some systems and
(40:38):
I shouldn't say system, I shouldsay for some games or
applications.
And you know that's the onething that we really want to do
is make sure that ECSX can workin whatever different use cases
people have.
Like, if you have a game idea,we really want ECSX to be able
(40:58):
to support that and not be like,oh well, it's not really a good
fit because of this and thisLike.
We want it to be able to handleas many different cases as
possible.
Brooklin Myers (41:07):
That was one of
the questions I definitely had
about, because one of the thingsthat OTP is really good at is
concurrency, but one of thethings that games need a lot of
is synchronization, and so howdo you contend with those two
things?
How do you enable that type ofmaking sure that things happen
in the order that you expectthem to and that they're
(41:29):
predictable, right?
So I'm really curious to hearmore about oh, by the way, using
the word systems man, I loveElixir, but one of the things
that makes teaching it reallyhard is our use of really common
popular words.
The number of times I've had tosay, well, the context and then
realize, oh, but not like thePhoenix context, like the
context of this is, or you know,oh.
Andrew Berrien (41:51):
So when we use
the use macro, and components is
definitely one of those too.
One component of this component, yeah, even outside ECSX, like
we're using component for toomany things.
Brooklin Myers (42:08):
And now, like
with this, it's like okay, no,
it's not a function that takes ascience and returns a HEEX
template and so, if I'munderstanding correctly this
point of synchronicity, is thatthe manager or am I
misunderstanding the kind ofexplanation here?
Andrew Berrien (42:24):
Yep.
So what the manager is going todo is it's going to keep track.
It also is something that keepstrack of all your systems and
all your components.
So you could theoreticallywrite code for a system but not
included in the manager and itwouldn't get run Like.
So that's one thing that thegenerators also do for you is,
(42:46):
if you do use the generator like, you don't really have to touch
your manager file ever, likewhen, because when you generate
a system or a component like,it's automatically going to
inject those into your manager.
So hopefully, like in mostcases, the manager is relatively
hands off and just kind of doesits job under the hood, which
(43:06):
is it's going to be the counterfor ticks.
So it's going to keep track ofwhen each tick needs to get run
and then, when it does run thoseticks, it's going to run the
systems in order, and so here wehave strict serializability,
like we can always reason aboutthe run order of systems and the
(43:28):
effects of those system runs.
However, the one thing is thatyou're not getting concurrency.
You are.
You are just running things oneafter another, single core, and
so the our goal for concurrencyis that it's within individual
(43:48):
systems where you would writeyour concurrency logic and this.
This is also a good fit forelixir because of how low the
bar is for introducingconcurrency.
It makes it extremely simple toadd concurrency in a number of
different ways in elixir.
So, yeah, your systems arerunning one after another, but
(44:11):
inside that system, like whenyou have that hit points
reducing system, like maybe youhave 100 attacks.
Now that's up to you.
How do you want to paralyzethose, do you?
Is it isn't necessary?
Maybe the system is just sofast you write right now.
Compared to your systemresources, it doesn't matter.
(44:31):
Maybe you have this world ofWarcraft kind of system where
there's 10,000 players and halfof them are attacking something
and so you have a lot of attacksand this.
This now becomes a goodcandidate for you to introduce
concurrency into that systemslogic.
(44:51):
So the systems themselves arenot concurrent, but the logic
within an individual system thatcan be made concurrent in order
to improve performance.
Brooklin Myers (45:02):
That's so cool.
I was.
So, as I was reading about thesystem, I was wondering where
the point of concurrency wouldbe, and that was where,
intuitively, it made sense that,okay, well, if you have some
system that's going to changethe health of a bunch of things,
probably the health of onething is not going to depend on
the health of another thing, andso that's where you're probably
(45:23):
not going to have difficultconditions happen where you know
, oh well, there might be somesystem where, like, oh, if this
character's health hits 50, itunleashes an EMP attack and
automatically damages everythingelse, and so you want to make
sure that that happensafterwards and that there's no
misordering there, becausethat'll affect how the math of
(45:44):
the game works out.
But applying the initial damageto get it below 50, well, that
can happen to this character orthat character and there's
really no concern there.
So the individual changes toall of your components you can
have your concurrent operationsand take advantage of some
paralyzation there.
But at the systems level, whereyou really want to be able to
(46:05):
think about things in the properorder, my damage system should
apply before my death checkingor revival system, and so being
able to still reason about it.
It's a really, really cleverapplication of OTP and kind of
that.
That's synchronicity you getfrom having things put into a
(46:26):
single gen server, so that'sreally cool.
So I think that was a questionI asked you a while ago when I'd
first started exploring this,and so it seems like you've come
to an understanding of where toleverage that concurrency.
Andrew Berrien (46:40):
Yeah, I mean
there was.
There was definitely a questionof do we introduce the
concurrent, try to find some wayof introducing concurrency of
multiple systems running at thesame time, and I'm not saying
that it's completely off thetable, but I think that for for
(47:01):
most cases it's going to besimpler to reason about systems
running with strictserializability and and putting
that on the onto the developersto implement concurrency using
the patterns from elixir inwhatever way is going to serve
(47:22):
them best, if at all, and evenin some cases, like you were
mentioning, like systems thathave side effects that could
introduce possible raceconditions, like we do.
There are ways around that aswell.
With you know, pretty muchanything any effect could
(47:42):
realistically be like delegatedto another system via the
creation of a component.
So let's say, if you're under15% health and then it sends out
an EMI which then afterwardsanother system reads EMP pending
components.
You know so if, if you are in asituation where you're in a
(48:05):
situation where you're feelinglike you're, the development or
performance is being hindered bytrying to do too much in one
system, like it can be brokenapart in order to, in order to
separate them like that, justusing components.
Brooklin Myers (48:24):
So can I have
multiple managers or is manager
like a single concept, like guyslike my application supervisor
almost?
Andrew Berrien (48:32):
Okay, so a
manager is you.
You only have one of them.
But there is the question of,you know, should there be
multiple games in oneapplication?
You know there's, there's alsothat's that's something that's
been brought up as well likebecause, yeah, there should be
(48:52):
one manager per game and formost people they're going to
have one game in theirapplication, and so that's
that's kind of where we're atright now.
And, you know, something that wecould look and are looking
towards in the future is likethe possibility of, okay, well,
(49:13):
what if you have multiple gamesrunning on the same application?
Like it's not, you can't do itwith one manager because all of
the system logic is totallyseparate.
Like you could realisticallyhave several games running on
the same manager and the systemsand the components are just
(49:33):
doing their thing in totalisolation.
There's nothing that's combiningthem into one single game like
that except, I guess, the frontend, but there is there is
thoughts about, particularlylike with the live dashboard,
like we I know we haven'ttouched upon that yet, but
(49:55):
they're like when it comes tomonitoring your, your game, like
if there's a possibility ofhaving multiple games, one
manager for each one of thosemultiple games, and so then when
you go into, let's say, ecs ECSX is live dashboard to look at
stats, to be able to organizethose statistics based on okay,
(50:19):
well, this manager is at thispercent load, this manager is at
this percent load, stuff likethat be able to say, okay, well,
I want to look at thesecomponent tables, but only the
component tables for this game,not not like in don't include
these other component tablesfrom another game, but that's
(50:39):
still something that's just onthe roadmap, like we're really,
like I said, we're really tryingto consider all the different
possibilities that people mightwant for their games.
Even if it's not something Iwould want for my game, like, I
still want this to be, you know,useful for as many people as
possible in the elixir communityand maybe even people outside
(51:01):
the elixir community.
Bring them in and show them thestrengths of elixir through
this, through this framework,like hey, you can develop your
game way quicker here than youwould in Python or whatever.
Brooklin Myers (51:16):
And leverage the
powers of concurrency and fault
tolerance within a game, whichfeels very natural to me, other
than you do need that point ofsynchronization.
But having the ability to applya bunch of computations and
parallel feels like it makessense for game development to me
.
So the problem is, you havethat synchronization process.
(51:36):
So I'm really curious if thingslike could you have systems
that could operate, you know,independently of each other,
like those could be concurrent,so they all have to finish by
the end of the tick, but youknow you could parallelize
multiple systems and say, well,these two systems definitely
don't care about each other,right, like my health system and
my plant growing system have,or those are bad examples
(51:58):
because those aren't behaviors.
My well, plant growing is notbad, but maybe my damage system,
maybe those two things havereally nothing to do with each
other.
Right, I don't care if my plantgot taller or if someone
attacked my plant.
Those things can happenindependently.
And so maybe we can leveragesome concurrency, or maybe
that's an over optimization andthat type of flexibility will
(52:20):
just make your systems harder toreason about and not really get
you that much performancebenefit.
So I'm really curious to hearhow things continue to develop
in that area.
I know we don't have too muchtime, so I really want to make
sure in the last kind of bits ofthe episode here we managed to
hit the adoption what you'vedone to make it kind of easy to
(52:40):
use.
What can people do if they wantto try out this, this framework
?
Andrew Berrien (52:47):
Yeah, ever since
the beginning, like we knew
that giving people an easy endto this new technology, like
even if elixir is not new to you, like ECS probably is, and the
API of this framework definitelyis.
So front and foremost of thisframework is its tutorial like.
(53:07):
I think that the this kind ofTutorial project is going to be
most people's entry into thegame, because it's going to
cover Not just like, okay, howdo you make a component, how do
you make a system, but like howthese really are gonna fit
together and to construct a fullback end, but also this is also
(53:33):
gonna cover on some front endstuff, and I think that that's
that's something that I wasconcerned about is like, okay,
you built a game back end andthen we just drop you off there,
and then the the you know,maybe someone who is not an
elixir person and is just tryingit out is like, oh, yeah, well,
so making the back end wasgreat, but oh, I don't know
(53:54):
anything about elixir front end.
Like they're looking aroundlike, oh, does elixir have
graphics libraries?
Like.
And then they're like, oh, man,this isn't that great, like so
part of one of the things that Iwanted to do was be able to use
something very simple likePhoenix live view in order to
create a front end that that's.
(54:15):
That's usable and not toocomplex to get set up.
So what we're doing in thetutorial is SVG like, where
you're gonna get a little bit ofthe basics of SVG if you're not
familiar with it, and usinglive view to keep that SVG up to
(54:36):
date as best it can and hookingthat up into the back end, and
so that's not to say that likethis is the way to do it, like
we're still there's.
This is a front end agnosticKind of framework like and I
have been looking into some somealternative front end choices
(54:59):
that could be added to thetutorial for those who are
looking to to stretch outside ofPhoenix live view.
But for now what we've got isyou're gonna build a back end
and then you're gonna runthrough and build a live view
front end and at the end you'llhave A demo app where you can
(55:21):
kind of sell your ship.
Around the ocean will be enemyships that try to shoot at you
and then when you get close tothem, you you shoot at them,
you've got hit points and youcan die and stuff like that.
Brooklin Myers (55:36):
That's awesome.
I hope there's at leastpictures at the upcoming Talk,
definitely so.
We've already talked a littlebit about the generators, so
those make it easier for peopleto understand how am I supposed
to work with these things,because they can just generate a
component, I think, generate asystem as well the two
generators, or there is there.
Andrew Berrien (55:55):
Yeah, so I mean
that we have four generators
total.
One of them is the setup.
When you first sit down and youmix P, h, x new and you make
your new project like you'realso gonna mix E, c, s, x, setup
and that's going to set you upwith a manager file that's
already to To start runningsystems.
(56:18):
And then the other three arecomponent, tag and system.
So component and tag are kindof the same thing, except tags
don't have a type.
So you would type E, c, s, x,gen, component and then the type
of the component and bam, youhave now that component is in
(56:40):
your game, ready to go.
Like you don't have to doAnything else at all, like you
have a full API in order toaccess, update those components
you have.
You know your type checking,you have a module in your app
and that component is module hasalso been injected into your
manager.
So everything you need to dofor that is ready to go.
(57:03):
Tag is the same way, justwithout a type, because it
doesn't.
Tags don't store data.
And then with a system, thesystem is going to do everything
except write the code.
You know it's not not not chatGPT yet, but so it's going to
create the system module.
It's going to make sure thatyour system module, like, has
(57:26):
the appropriate macro, has theappropriate function, with the
name and arity that will beexpected by the manager, and all
you need to do is just fill inthe logic of your run function.
So kind of like when you doectogen migration, something
like that, it's going to createa module at the top.
(57:46):
It's using migration and thenit's going to make that change
function, but it's just empty.
So it's up to you to say OK,what is that migration?
Do same kind of vibe here withthe system and what I found is
that it makes the design processlike for your game, like just a
series of generator commands,like you can have a whole game
(58:11):
idea in your head and just starttyping out generator commands
and before you know it you havethe whole game is ready to go,
except for the individual piecesof system logic.
And at that point it's just usethat component API, fetch the
components you need, update thecomponents you want to do, and
(58:32):
then that's it.
Your, your whole back end isdone.
Brooklin Myers (58:35):
I'm realizing it
was a very missed opportunity
for me having built connect forfor the upcoming Elixir Conf
talk.
I really should have used thatas a chance to try out this
library.
I think maybe tackling ECSX andLibya native would have been a
lot all at once, but maybethat'll have to be a future
refactor.
There's one other thing I wantto make sure that we talk about,
(58:55):
which is OK.
So there's, there's good toolsfor adoption.
We have our, our generators.
We have looking at thedocumentation it's very well
documented.
You have the guides, you havethis tutorial project, so people
can get started as well, whichis fantastic.
Once I have my app running, Ibelieve you also have built a
(59:16):
live dashboard to make it easierto kind of understand and and
observe.
Is that correct?
Andrew Berrien (59:22):
Yeah, and so,
for those who don't know,
phoenix live dashboard is aproduct, is something that comes
with Phoenix and allows you toinspect the state of a running
application with respect to anymetrics that, like telemetry
(59:45):
that the app might be emitting.
It will show the size that'sbeing like, like, if you're
using it's.
It will show the size of yourat tables.
It will show some variousthings relating to Ecto if
you're using that in your applike basically getting different
(01:00:05):
pages for different areas ofyour app that you might want to
inspect and so the goal here wasto use this technology that
pretty much everyone already has.
You know, maybe they might notbe using it, but if you're
building an app with Phoenix,you do have access to that and
so to use this technology andjust simply add another page
(01:00:30):
that will show ECSX stats, andso the statistics that we have
right now are probably the mostimportant.
Front and center is the overallload of your game.
So systems, every system runsevery tick.
So let's say that your serverruns at you know you have a 20
(01:00:54):
tick server, so it's going to be20 ticks per second, and so
that would be 50, 50milliseconds.
So every system that you writeall of your game logic has to
run within 50 milliseconds.
If it takes 51 milliseconds,now your systems and now your
(01:01:14):
game is going to start gradually.
It's going to be onemillisecond behind every single
tick and that's going to keepgrowing and growing and growing
until eventually you're like aday behind.
You know.
You basically are on the trackto system instability when you
have a tick rate and system loadthat doesn't match up.
(01:01:34):
So one of the things we want todo is say, ok, well, here's a
bar that represents your 50milliseconds, if assuming a 20
tick server, and that'sconfigurable.
So this bar represents 50milliseconds.
How much of it are youcurrently using?
So when you pop in there, ifyou see that bar is full, you
(01:01:56):
know your systems are using all50 milliseconds.
Like that's going to be rough.
What happens if you know,tomorrow your game gets more
popular and you have twice asmany users, like your apps not
going to handle that very well?
So that's going to be your signright there that you need to
either lower the tick rate sothat systems have more time to
run, or optimize your systemthrough you know concurrency, or
(01:02:20):
you know a better algorithm, orwhatever.
And so that leads me to thesecond thing that's displayed
with ECS X live dashboard is thetime of each system.
So you're going to see theaverage run time for each system
that you have.
So if you have your HP system,let's say you, you're seeing, oh
(01:02:41):
man, it's taking my system loadis very high, I need to find
something to optimize.
And you look at your HP damagesystem and it takes one
microsecond to run.
You're like, oh well, yeah, I'mprobably not going to optimize
that too much.
And then you look over at yourpath, finding you know system or
something and it takes like ayear to run and it's like, ok,
(01:03:04):
that right there, if I couldjust optimize that system I'll
be good.
You know that's the problem one.
So being able to identify theproblematic systems when you
have them, identify sources ofoptimization, and that's
something that has come up withme a lot like.
Usually there's one system thatis like doing a lot of work and
(01:03:26):
really needs to be optimized,like it needs to have the best
algorithm it needs.
You know, I've played aroundwith introducing NX for
numerical computation in orderto improve performance with some
systems that are heavy onnumerical computation.
So yeah, systems and systemoverall system load is probably
(01:03:49):
the biggest, the biggest featurefor a live dashboard right now,
but also the ability to say,hey, I want to see the HP of
every entity in the game rightnow, you know.
Or I want to just see like, hey,how, how many entries are there
in the components table ofpoison, like how many entities
(01:04:12):
are currently poisoned?
And I think that this is, youknow, not quite as useful, but
can be good when you, when youdo have a bug, like I remember
once when I had a bug that I wastrying to track down in one of
my games, and then I look, anentity like D spawns, like if
the mob is killed or somethingand dies, then the component
(01:04:34):
gets removed.
But that wasn't happening.
So what was happening is Iwould watch the size of this
component table and it wouldjust keep going up and up and
never going down and I was like,oh well, there's my bug.
Brooklin Myers (01:04:47):
That is really
cool.
Yeah, that is a phenomenalamount of observability into
your system.
I am so sad this episode has tocome to an end.
I now have minutes to get to mynext class.
That is how much fun I had atthis episode with you, andrew.
I feel like you and I can andshould talk about this more
(01:05:12):
because I think there's still alot of interest and depth and if
folks are interested inlearning more about ECSX, andrew
has an Elixir Conf talk comingup, which will be happening in
the beginning of September.
So if you want to come inperson, I'm also going to be
there speaking about Live ViewNative.
So if you'd like to meet me andAndrew in person, I hope to see
(01:05:34):
you there.
Always feel free to come up andsay hi.
I love it when people come upand talk to me at Elixir Conf.
I'll be the guy with the longhair and you'll also be able to
see Andrew there.
So, andrew, is there anythingelse before we end the episode
here that you would like toshout out to or mention for
folks, or kind of a call toaction?
(01:05:55):
Call to action here.
Andrew Berrien (01:05:59):
I think I really
just want to shout out you,
Brooklin, and the Elixir Newbiepodcast and really give give a
serious thank you for having meon here and giving me this
platform to share my work.
You know, I really appreciatethat and I hope that anyone
who's listening to this and isinterested in Elixir and might
(01:06:22):
have a game idea Give it a try.
Like this is something that youcan definitely get set up and
get your game up and running inan afternoon.
So just give it a shot and feelfree to reach out if you have
any questions or if you want toput an issue up on GitHub or
(01:06:42):
something like that.
I'm around and I'm happy tohelp with any questions that
anyone might have.
Brooklin Myers (01:06:49):
Well, I want to
say that I normally I very much
never expect anyone to shout outthe podcast, so that's very
kind of you, andrew.
I really appreciate that You'vealways been such a kind soul
and a wonderful spirit to workwith.
For folks who don't know,andrew has been very
instrumental in Dock Art Academy, has provided feedback and
(01:07:10):
always been very supportivethere.
So really, really happy to havegotten the chance to speak with
you here, really excited aboutthe work that you're doing
Expanding game development inElixir.
That is going to be it for thisepisode of the Elixir Newbie
podcast.
I want to thank all of you somuch for listening.
I hope you Elixir Newbies outthere enjoyed this episode and
(01:07:32):
learned a lot.
I know I did.
Thanks again.