Now, before I start, I want to say that I am aware that there are no standard way to implement an ECS. However, there is one method that I am interested in, but confused about one particular thing.
Say you have an Entity with a TransformComponent (contains a position), and a RenderComponent (contains a Sprite), and along with this you have a RenderSystem separate from the Entity.
The RenderSystem will handle the rendering of all components with a RenderComponent, and will not care what entity it is attached to. But since a Sprite requires a position, the RenderSystem will need the TransformComponent as well.
Now comes the part I am confused about, if all components are stored in their own vector of that component type, how will I get all entities that have both a TransformComponent as well as a RenderComponent? I do not want to use the naive method of looping through all entities in every system, pulling out entities that have both these components, but rather have every component in a vector of the component type.
Also, how would the systems know 2 components belong to the same Entity? Will the components have an EntityID attached to it?
Edit: I just realized something, if RenderSystem loops through all RenderComponents and gets the entity, then checks if that entity also contains the TransformComponent, then it can render it. But that kinda ruins the whole "Systems don't care about the entity", this also requires that the component has an EntityID which I am still unsure if it should have. Someone please clarify all this for me.
This part is call Entity Handler, and it's something which can need a lot of work.
The simplest form that i know is something like that:
Move every Components into one big array (cache is King).
You'll need an enum for each Component:
enum E_Component {
Velocity,
Position,
...
};
And now your Entity is just an index and an array of component index.
struct Entity {
unsigned index;
unsigned components[NB_COMPONENTS]; // -1 if nothing
};
So if a System need to update the velocity component, all you need to do is to loop through your entities, check if there is a velocity component and update it.
==> System don't care about entities, only about components.
There is a lot of better way to do it, take a look at this article
Related
I have made a LazyRow that i now want to be able to get the scrollposition from. What i understand Scrollablerow has been deprecated. (correct me if im wrong) The thing is that i cant make a scrollablerow so i thought lets make a lazy one then. but i have no clue how to get scrollposition from the lazyrow. i know how to get index but not position if that eaven exists. here is what i have tried.
val scrollState = rememberScrollState()
LazyRow(scrollState = scrollstate){
}
For LazyScrollers, there are separate LazyStates.
I think there's just one, in fact, i.e. rememberLazyListState()
Pass that as the scroll state to the row and then you can access all kinds of info. For example, you could get the index of the first visible item, as well as its offset. There are direct properties for this stuff in the object returned by the above initialisation. You can also perform some more complex operations using the lazyListState.layoutInfo property that you get.
Also, ScrollableRow may be deprecated as a #Composable, but it is just refactored, a bit. Now, you can use the horozontalScroll() and verticalScroll() Modifiers, both of which accept a scrollState parameter, which expects the same object as the one you've created in the question.
Usually, you'd use LazyScrollers since they're not tough to implement and also are super-performant, but the general idea is that they are used with large datasets whereas non-lazy scrollers are okay for small sized lists and stuff. This is because the lazy ones cache only a small fraction of the entire list, making your UI peformant, which is not something regular scrollers do, and not a problem for small datasets.
They're like equivalents of RecyclerView from the View System
I am currently working on a small project using ECS and DirectX12 and wanted to get some advice on if there is a "preferred" way or alternative ways to solving my issue.
Let me give a very basic layout to an entity which can be rendered
<entity name = "Cube">
<component = Transform ..blah blah>
<component = Mesh = "cube.txt"> // holds data about verts/indicies etc.
<component = Materials = "Mat1"> // holds data about the materials etc.
</entity>
Approach 1
When the entities are loaded in, it would load each component. It gets to the mesh component and would now load in the mesh data and create the buffers needed and store them in the render system (by being able to get the render system from the world).
Say the next entity comes along and also wants the same mesh, it would check with the render system to see if it already exists and therefore would not need to load it in again but simply create a new copy for that entity.
Approach 2
Before loading in entities the render system would have a list of meshes to load in upfront (this means some list which would need updating each time a new mesh wants to be included into the system).
Now when the entities are loaded in they can just have a tag to match the tag on the mesh in the render system.
I am not really sure whats the best approach with this as I started working with approach 1 and find the mesh component handles the loading which does seem a simple and straightforward approach, however I have not done anything like this ECS approach before and wanted to get advice as I may have overlooked a far more preferred approach which is more effective.
The concern I am keeping in mind for work to be done later is the ability to handle batching objects using the same mesh types PSO's etc.
If you find that the first approach works for you right now, I'd say keep going with it until you need to definitively replace it with a system that can handle new functionality.
The second approach does sound like the "proper" way to do it, as in commercial game engines a list of assets is loaded in first on engine launch and most operations thereafter are carried out on the assumption of the mesh assets you need already existing (obviously not including things like procedural generation and so forth).
I'm trying to use the write_graphml function from the Boost Graph Library. The relevant things to know are that this function takes in a dynamic property map composed of property maps for each vertex and edge property, and assumes that all properties on the vertices and edges can be resolved to character types for writing to the file. This makes sense and works for most of my properties. However, I have 1 edge property that is an enum, and so it refuses to compile.
I think what I need is to create a custom PropertyMap that basically acts as a wrapper around the one for that edge property, intercepts the accesses, and returns a character representation in place of the enum values.
Is this the right way to solve this, and if so where can I look for how to define my own custom PropertyMap? I've been digging through the docs and code and so far I'm lost.
Got some help from someone else looking closer at the error messages, and it turns out defining << for std::ostream and >> for std::istream for my custom type enabled boost to write everything properly.
On my route im requesting via ember-data some records. Lets say the model-type is 'item'.
model: function(){
return this.get('store').find('item');
}
now ive got a component named 'my-foo' which should use the records to do something with the data. Therefore Im calling the component like that:
{{my-foo myItems=model}}
in my routes template. In the components js part, Im trying to get the myItems-field and iterate over them.
this.get('myItems').forEach(...);
Unfortunalety its not clear for me if the model i want to overgive to the component is an collection from records or just a single record (since on some routes the model is the result of store.find('item') on other store.find('item', 23424).
How can I check what kind of data arrives in the component.
(Also Im wondering what kind of object is it since im using ember-data. Is it a DS.recordarray or a promise or something else at this time?)
I can see two solutions to the problem:
Making component aware of the form that model receives
Checking and/or adjusting data type in component (in my opinion better default scenario)
As for making component aware - you could go with 2 approaches. Either differentiate in a way how your component take arguments, so there could be:
{{my-foo myItems=model}} - when you expect to receive multiple items
{{my-foo item=model}} - when you expect to receive single one
And then work accordingly further on, or - the second approach - is to actually split component (while extracting shared part to a different structure) so you would have my-foo for single items and my-foo-array for multiple.
Advantage of this approach is that you don't deal with what-if-multiple logic, that might grow to something unmanagable later on, yet usage of it is dependant on project requirements.
As for checking and/or adjusting - you already have data in, so could make assumption that your data is dirty and sanitize it using computed property. Below example, where single item is wrapped into an array.
export default Ember.Component.extend({
sanitizedItems: Ember.computed('items', function() {
var items = this.get('items');
if(!Array.isArray(items)) {
return [items];
} else {
return items;
}
})
});
Since you're using Ember.Data, depending on your setup, you might get a promise instead of object/array. In this case, you might want to resolve promise using this.get('items').then(function(items) { ... }) before doing sanitization, yet the idea behind is exactly the same.
You can check full example: Gist, Twiddle
Suppose you have the canonical Customer domain object. You have three different screens on which Customer is displayed: External Admin, Internal Admin, and Update Account.
Suppose further that each screen displays only a subset of all of the data contained in the Customer object.
The problem is: when the UI passes data back from each screen (e.g. through a DTO), it contains only that subset of a full Customer domain object. So when you send that DTO to the Customer Factory to re-create the Customer object, you have only part of the Customer.
Then you send this Customer to your Customer Repository to save it, and a bunch of data will get wiped out because it isn't there. Tragedy ensues.
So the question is: how would you deal with this problem?
Some of my ideas:
include an argument to the
Repository indicating which part of
the Customer to update, and ignore
others
when you load the Customer, keep it in static memory, or in the session, or wherever, and then when you receive one of the DTOs from the UI, update only the parts relevant to the DTO
IMO, both of these are kludges. Are there any other better ideas?
#chadmyers: Here is the problem.
Entity has properties A, B, C, and D.
DTO #1 contains properties for B and C.
DTO #2 contains properties for C and D.
UI asks for DTO #1, you load entity from the repository, convert it into DTO #1, filling in only B and C, and give it to the UI.
Now UI updates B and sends the DTO back. You recreate the entity and it has only B and C filled in because that is all that is contained in the DTO.
Now you want to save the entity, which has only B and C filled in, with A and D null/blank. The repository has no way of knowing if it should update A and D in persistence as blanks, or whether it should ignore them.
I would use factory to load a complete customer object from repository upon receipt of DTO. After that you can update only those fields that were specified in DTO.
That also allows you to apply some optimistic concurrency on your customer by checking last-updated timestamp, for example.
Is this a web app? Load the customer object from the repo, update it from the DTO, save it back. That doesn't seem like a kludge to me. :)
UPDATE: As per your updates (the A, B, C, D example)
So what I was thinking is that when you load the entity, it has A, B, C, and D filled in. If DTO#1 only updates B & C, that's OK. A and D are unaffected (which is the desired situation).
What the repository does with the B & C updates is up to him. If you're using Hibernate/NHibernate, for example, it will just figure it out and issue an update.
Just because DTO #1 only has B & C doesn't mean you have to also null out A & D. Just leave them alone.
I missed the point of this question at first because it is predicated on a few things that I don't think make sense from a design perspective.
Hydrating an entity from repository and then converting it to a DTO is a waste of effort. I assume that your DAL passes a DTO to your repository which then converts it to a full entity object. So converting it back to a DTO seems wasteful.
Having multiple DTOs makes sense if you have a search results page that shows a high volume of records and only displays part of your entity data. In that case it's efficient to pass that page just the data it needs. It does not make sense to pass a DTO that contains partial data to a CRUD page. Just give it a full DTO or even a full entity object. If it doesn't use all of the data, fine, no harm done.
So that main problem is that I don't think you should pass data to these pages using partial DTOs. If you used a full DTO, I would do the following 3 steps whenever the save action is performed:
Pull the full DTO from repository or db
Update the DTO with any changes made through the form
Save the full DTO back to the repository or db
This method requires an extra db hit but that's really not a significant issue on a CRUD form.
If we have an understanding that a Repository handles (almost exclusively) very rich domain Entity, then you numerous DTO's could simply map back.
i.e.
dtoUser.MapFrom<In,Out>(Entity)
or
dtoAdmin.MapFrom<In,Out>(Entity)
you would do the reverse to get the dto information back to the Entity and so on. So your repository only saves rich Entity's NOT numerous DTO's
entity.Foo = dtoUser.Foo
or
entity.Bar = dtoAdmin.Bar
entityRepsotiry.Save(entity) <-- do not pass DTO.
The whole point of DTO's is to keep things simple for the presentation or say for WCF dataTransfer, it has nothing to do with the Repository or the Entity for that matter.
Furthermore, you should never construct an Entity from DTO's... the only two ways to ever acquire an Entity is through a Factory(new) or a Repository(existing) respectively.
You mention storing the Entity somewhere, why would you do this? That is the job of your repository. It will decide where to get the Entity(db,cache,e.t.c), no need to store it somewhere else.
Hope that helps assign responsibility in your domain, it is always a challenge and there are gray area's here and there but in general, these are the typical uses of Repository, DTO e.t.c.