In Component based game engine, I have trouble when it come to relation between game objects / components.
Where to store the relation , and how to delete them?
To keep it simple, here is an example.
A Gradius-clone game consists of 2 types of game object:-
Rocket = Main Body Component + Turret Component
Floating turret = Turret Component (alone)
The component detail are :-
Main Body Component = one physical body + one graphical body
Turret Component = one physical body + one graphical body
Turret Component is designed to have a relation (physical constraint or ownership) with to Main Body Component.
There is a requirement that the relation must be removed BEFORE both component.
For example, the relation in this case also contains physical constraint implemented by external Physic Library, e.g. Bullet Physics.
These are quite an example-specific description, provided just in case ....
Steps to delete Rocket have to be in this order :-
delete constraint
delete Main Body Component and Turret Component (any order is ok)
The relation should also be removed when a Main Body Component is deleted, leaving Turret Component alone, so let it become Floating turret.
Where should the relation be stored? (All seem ok, but related to next question.)
inside a new component in a new dedicated game object (new entity)
inside a new component in the same entity as Rocket
inside a new manager system that keep a list of this specific kind of relation
How should relation be deleted? (Both seem to be bad ideas.)
create a flag to check for a impending deletion of Main Body Component or Rocket, then call a new dedicated system to delete relation just before delete others component, it must be called before other manager systems every time step.
let's other existing manager call a new dedicated system when it want to delete Main Body Component or Rocket
I expected answers for general cases where there are a lot of types of relation. (between Game Objects or Components)
Edit 1: The proposed solution about making ownership and adding code in Rocket's destructor directly is quite against Component Based design.
It will make the three components (include constraint) very couple.
Furthermore, components should not have non-trivial function.
I believe the destructor is one of them, that should be avoided.
(I once has bloating destructor of some objects, it destroy all good modularity.)
In your example of the Rocket game object, the relation is an ownership and should be kept in the Rocket. If your game engine architecture allows it, the relation can be deleted by a destructor function in the game objects called by the manager system prior their deletion.
EDIT:
If you don't want the objects or components to have any knowledge of their ownership or relations, I think the best choice would be to keep a list ( as you suggested) of the relation with a reference to the owner of the relation. That way you can check the list first, to see if your game object (Rocket) can be deleted or if it has any relation/s to delete first.
Related
That's obvious that for the diffing algorithm in React keys are essential. But I was wandering, why React just can't automatically generate keys based on the content we iterate over?
I also assume that items can share some similarity, or cab be identical in terms of content, but isn't it possible to generate keys once user open a page and somehow attach them to the items, so it is stable?
Or maybe there where attempts to solve the problem, if so, I would be grateful if you share it to me.
Update
Thank you guys for your answers, I've learnt a lot!
Also a thing I had in mind: what we developers do when there is no stable id (e.g. user added an item which is not yet saved into DB). In the cases we just generate id, and attach it to the object, or element in an array, but we do not generate ids on a fly, so it remains stable over time.
What if React just generate ids for all arrays which are involved into rendering process, in other words, arrays which are directly used in render function?
It can be done only once, during phase Commit phase, or whatever. Also I believe, the id can be readonly, or something, so user can't erase the id.
p.s.s
While I was writing p.s. question above, I realized, autogenerating id for arrays wouldn't work, since I've missed two things. All side effect react can do only during the Commit phase, but not Render phase. But that's not the main problem.
The main problem is when we use filtering or sorting on a back-end side. Since we receive a new array, filtered one, we would need to regenerate ids for those elements, but basically, that's the same html elements, in which we can change content to match filtering order. That's the same as Slava Knyazev mentioned.
React can't generate keys, because the entire point of keys is for you to help React track elements during it's tree-diffing stage.
For example, lets say you have the following code, where you naively use content instead of identifiers for your keys:
const people = usePeople(); // [{ id: "1", name: "James"}, {id: "2", name: "William"}]
return <ul>{people.map(p => <li key={p.name}>{p.name}</li>}</ul>
The above code will function and behave as you would expect. But what happens if the name of a person changes? To understand it, lets look at the tree it generates:
ul
li(James) James
li(William) William
If James becomes Josh between renders, the new tree will look like this:
ul
li(Josh) Josh
li(William) William
React will compare the two results and conclude the following:
li(James) is to be removed
li(Josh) is to be added
However, if we set our key prop to p.id, then the old and new tree will look as follows, respectively:
ul
li(1) James
li(2) William
ul
li(1) Josh
li(2) William
And when React compares the two, it will identify that James has become Josh, and needs only the text adjusted.
In the first scenario, the <li> component is completely destroyed, and a completely new component takes its place. Both of these actions run a complete React lifecycle for the component. In the second, it remains untouched, and only the text inside changes.
While in this contrived scenario, the performance penalty in the first case in minimal, it may be very significant with complex components.
I believe, unless your data is 100% certainly going to sort in one way and never change, key={index} isn't a good key (which is what I assume you want your auto-generated keys to be). You'd ideally want something that is unique to each item, regardless of the order.
It's explained in more detail in the new beta react docs https://beta.reactjs.org/learn/rendering-lists#where-to-get-your-key
I think what you are implying is React could potentially choose to use something like a stable hash (say sha1 on a serialised string or something) on the object to generate a unique key. I think this actually would work in many cases, and even gave me pause for thought for a while! Your question is actually a really good one, and a deep one.
However, it wouldn't work in every case. I think it would work only on a static object which has no methods or anything attached. On a JS object, not all properties are enumerable. Hashing something could only ever happen on the enumerable objects of properties, but the dev may have non-enumerable yet-still-unique methods attached to these objects. In fact, even enumerable methods cant really be serialised reliably and they could be what makes the object unique. Not to mention the complexities of reliably hashing something with prototypical inheritance involved.
I suspect there's also a performance aspect to this. Hashing is cheap, but no that cheap. Most cases can be keyed by just referencing a unique ID in the object, which is vastly cheaper. When enumerating a very large number of objects, these things matter, and so its better to defer to the developer. After all, if you really do want to hash it, its just one function call in userland -- and this saves great confusion on developer side when it doesn't work. The Principle of least astonishment comes to mind.
There's also an aspect of how this would limit the power of how expressive JSX can be due to it basically allowing free-form JS. You would probably have to supply some low level <React.Map> component primitives in order for react to supply this default key handling which implies you are a bit more restrained on what you can and can't do (complex functional chains).
I am not able to understand why Flutter objects are immutable. I tried it in the Flutter docs but they weren't that helpful. If anyone can help me with this, I'll be thankful.
Also, I just started flutter 2 days ago and it's awesome.
From https://api.flutter.dev/flutter/widgets/StatefulWidget-class.html
StatefulWidget instances themselves are immutable and store their
mutable state either in separate State objects that are created by the
createState method, or in objects to which that State subscribes, for
example Stream or ChangeNotifier objects, to which references are
stored in final fields on the StatefulWidget itself.
The framework calls createState whenever it inflates a StatefulWidget,
which means that multiple State objects might be associated with the
same StatefulWidget if that widget has been inserted into the tree in
multiple places. Similarly, if a StatefulWidget is removed from the
tree and later inserted in to the tree again, the framework will call
createState again to create a fresh State object, simplifying the
lifecycle of State objects.
A StatefulWidget keeps the same State object when moving from one
location in the tree to another if its creator used a GlobalKey for
its key. Because a widget with a GlobalKey can be used in at most one
location in the tree, a widget that uses a GlobalKey has at most one
associated element. The framework takes advantage of this property
when moving a widget with a global key from one location in the tree
to another by grafting the (unique) subtree associated with that
widget from the old location to the new location (instead of
recreating the subtree at the new location). The State objects
associated with StatefulWidget are grafted along with the rest of the
subtree, which means the State object is reused (instead of being
recreated) in the new location. However, in order to be eligible for
grafting, the widget must be inserted into the new location in the
same animation frame in which it was removed from the old location.
Performance considerations
There are two primary categories of
StatefulWidgets.
The first is one which allocates resources in State.initState and
disposes of them in State.dispose, but which does not depend on
InheritedWidgets or call State.setState. Such widgets are commonly
used at the root of an application or page, and communicate with
subwidgets via ChangeNotifiers, Streams, or other such objects.
Stateful widgets following such a pattern are relatively cheap (in
terms of CPU and GPU cycles), because they are built once then never
update. They can, therefore, have somewhat complicated and deep build
methods.
The second category is widgets that use State.setState or depend on
InheritedWidgets. These will typically rebuild many times during the
application's lifetime, and it is therefore important to minimize the
impact of rebuilding such a widget. (They may also use State.initState
or State.didChangeDependencies and allocate resources, but the
important part is that they rebuild.)
"Flutter objects" is quite broad. There are different kinds of objects.
State and widget are split and they have different lifecycles. Immutability is used for performance reasons. If the widget needs to change, create a new instance set up accordingly.
It's quicker to check if two instances are identical than if their state is the same.
This is one of the reasons const is used often. It ensures that identical instances are used if the constructor parameters are the same.
From the docs linked to above
Use const widgets where possible. (This is equivalent to caching a widget and re-using it.)
Immutability is the cornerstone of many programming languages and using immutable data can be more efficient flutter Take this advantage to rebuild the immutable view tree for every frame
In general, we should confide rebuilding to the subtrees that actually change
The widget tree is an immutable description of the user interface. How can we rebuild part of that without reconstructing it from the root? Well, in truth, the widget tree is not a materialized tree structure with references from parent widget to child widget, root to leaf. In particular, StatelessWidget and StatefulWidget don’t have child references. What they do provide are build methods (in the stateful case, via the associated State instances). The Flutter framework calls those build methods, recursively, while generating or updating an actual runtime tree structure, not of widgets, but of Element instances referring to widgets. The element tree is mutable, and managed by the Flutter framework.
So what actually happens when you call setState on a State instance s? The Flutter framework marks the subtree rooted at the element corresponding to s for a rebuild. When the next frame is due, that subtree is updated based on the widget tree returned by the build method of s, which in turn depends on current app state
Suppose I have a timer structured so that you can view and time multiple projects at once, and within each project you can view and time multiple tasks. Since this is a timer, you can only time one task at a time, and therefore one project at a time.
Because of these restrictions, I've separated the timer into three separate structures:
TimerContainer (outer, holds and displays all project objects)
ProjectContainer (middle level, holds only one project, with all tasks associated with the project)
TaskContainer (inner level, holds only one task).
Only the TimerContainer and ProjectContainer hold state.
TimerContainer:
The TimerContainer doesn't know anything about the tasks, but it does the initial API call to seed all projects and tasks with starting values.
The TimerContainer is also concerned with which project is currently tracking time (i.e. holds a projectID value for whichever project is currently timing).
ProjectContainer:
Each ProjectContainer holds information about which task is currently timing (if any), and updates (both here and via an API call) the time spent on each task after they've completed timing.
At that time it informs the TimerContainer it (that project) is no longer timing.
As props the TimerContainer is giving ProjectContainer the currently tracking project ID, list of tasks and their seed values, and various project information.
Here is my question:
If I update the TimerContainer's "Currently Tracking ProjectID" value, it will trigger a re-rendering of all the ProjectContainers, including the one that just updated one of its tasks' times. That, in my mind, seems to revert it back to the original seed value of that task unless I update the (now static) seed information held in the TimerContainer for that specific task.
If I do that, it makes me think that I have to set the state for both the seed information and the currently tracking projectID with the same call, because if I do it sequentially I'm not sure if it will get to the second state change request.
If this is indeed a problem (and please feel free to say otherwise), I imagine it could be alleviated by Redux or Flux, but given an already established architecture I would like to see if there are clean ways of handling this without bringing in another library first.
Bottom line, how is this solved cleanly without another library?
Update:
It seems as if I was confused about the way re-rendering affected state initialization (namely, it doesn't). I modified Adam's example below to prove that to myself
(link here )
After that realization, the solution to my problem simply becomes writing up a function that would handle "Currently Tracking ProjectID" prop value change on each of the ProjectContainers.
Another thing to implement is the shouldComponentUpdate function (thanks again) by checking if the ProjectID was related to that ProjectContainer.
A component re-rendering shouldn't cause that component to lose it's internal state. Here's an example: the child component re-renders because the parent changes state and passes the child new props, but the child keeps its own internal state.
As far as design options in general, there are a bunch. Here are a few I'd consider:
Re-rendering is a performance hit, so consider customizing the shouldComponentUpdate function for child components to keep them from rerendering
Try to make as many child components stateless or pure as possible
Consider not persisting the "seed" values in the parent component - not sure if there's value to knowing the initial value, but if you just pass that down to the child components, they can store and increment that
On the whole though, it sounds like you might benefit from a store. Being able to separate out organization of state from functionality can be helpful.
I am relatively new to React and Redux after spending a lot of time in the .net mvc and knockoutjs world. What I am having trouble understanding is how the store is used and how props are passed down between parent and child components.
My first question: if an array of values get sent down from parent to children components via props, do these components do a deep copy and create their own version of this array? If we have a rather large array of values that we want multiple children to have access to, and we send it as props, are we unnecessarily creating extra data or are they just simply referencing the same array?
I'm not sure exactly how the store is used, but could it be used to help the scenario above? If we have some values like a larger array that we want accessed by multiple component children, they could pull them from this globally accessible store?
I would appreciate if somebody could help me wrap my head around these concepts. In my scenario I'm working on we have a table of 30 students each of which gets sent an array of data to help fill in some rows. What I'm afraid we're doing though is giving each student a large amount of data that they don't need if they could pull from the parent or this global store.
<StudentTable
onSelectAllStudents={this.props.handleSelectAllStudents}
handleLoadStudentResponses={this.props.handleLoadStudentResponses}
structures={this.props.structures}
lessons={this.props.lessons}
activities={this.props.activities}
students={this.props.students} />
They are creating a table, where each row is a student. The table contains a large amount of data (which is a whole other problem) however what essentially we are doing is for each student we are showing whether they completed a particular activity or not. As you can see in the screenshot they build out a rather complex table. In the StudentTable they loop through students and create a Student component for each row which gets sent in the list of activities so that in the table they can color in a cell based on if the activity is published or not. My main fear was that with each Student component getting the list of activities it was adding a ton of data to memory as opposed to those numerous Student components just referencing some parent array.
Based on the syntax I've seen, children receive a pointer. Not a new object. Regarding your question about giving 30 students the entire array, you're not approaching data passing correctly. Show us a code snippet and I'll be able to comment more.
Also, redux is not helpful. It can be used, but it's overkill and adds needless complexity. Components with a child-parent relationship can very easily be handled with normal React prop passing. Redux is the go-to option if the components do not have any direct relation.
edit: When referencing elements in an obj, primitives are copied and objects are pointed.
const obj = {arrayObject: [], primitiveBoolean: true}
const primitive = obj.primitiveBoolean
const array = obj.arrayObject
primitive = false
console.log(obj.primitiveBoolean); //still true
array.push(10)
console.log(obj.arrayObject); // [10] push changed object's array
I have a scenario to design a database for Java API Documentation, in which I have to present the information about every class and method in a given piece of code. For example, consider:
1. main()
2. {
3. String foo="test";
4. foo.substring(1,2);
5. }
Here, I have to show documentation for class String and method substring from Java docs (The classes/methods can be any valid class/method).
My Observations:
The classes may repeat in various packages, so they can't be unique. Same goes for methods.
The method name foo() can be :
1) The method of this class
2) Overrides the method of some parent class
3) Simply inherits the a method.
With this info, I have following tables:
1)
CREATE TABLE "JAVACLASSDESCRIPTION"
( "CLASSFULLNAME" VARCHAR2(400) NOT NULL ENABLE,
"CLASSNAME" VARCHAR2(400),
"CLASSDEFINATION" CLOB,
"CLASSDECLARATION" CLOB,
"INHERITEDCLASSES" CLOB,
CONSTRAINT "JAVACLASSDESCRIPTION_PK" PRIMARY KEY ("CLASSFULLNAME") ENABLE
) ;
INHERITEDCLASSES is a multi-valued attribute.I know it's a really poor thing, but I have reasons.
1) 1st check if the method is available in JAVAMETHODDESCRIPTION table (Either as the class method itself, or a override method ).
2) If not, it has to be a method which is inherited for some parent class. So we have to show the documentation of method of this parent class.To save multiple searching, the value INHERITEDCLASSES contains is as follows(for some random class):
java.lang.Object: clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
so that it's parent class is java.lang.Object followed by the list of methods, so that it's easy to match the method name.
2)
CREATE TABLE "JAVAMETHODDESCRIPTION"
( "CLASSFULLNAME" VARCHAR2(400) NOT NULL ENABLE,
"METHODNAME" VARCHAR2(400) NOT NULL ENABLE,
"METHODDECLARATION" VARCHAR2(400),
"METHODDEFINATION" CLOB
) ;ALTER TABLE "JAVAMETHODDESCRIPTION" ADD CONSTRAINT "JAVAMETHODDESCRIPTION_FK" FOREIGN KEY ("CLASSFULLNAME")
REFERENCES "JAVACLASSDESCRIPTION" ("CLASSFULLNAME") ON DELETE CASCADE ENABLE;
Sample output:
I know there are lot of design issues.How can I improve my database design?
EDIT:
About the multi-valued entry, if decomposed to another table may result into redundant entries.For eg. Object class is the super class for all.
Link for documentation page
hard to tell everything because a lot of things is unspecified, but:
a few things to consider: loaded java class is identified by unique full name (x.y.z.Myclass$Inner.class) and it's classloader. if you don't care about loaded class but only the source code (javadoc) then you can probably skip classloader.
javadoc can be at method, class, package and field level (each of them can be uniquely identified by signature)
if you want to support javadoc for inherited methods then you need to model multiple inheritance (javadoc can be inherited also from interfaces) and in your application traverse that tree top on request to display the javadoc. other option is to do the traversing during saving the content to db
another thing is versioning of library and jdk. don't know if you want to support different versions.
The best method for going about something like this, is to get to the 3rd normal form. You may not stay there, but at least by "seeing it" you learn a few things along the way about your system, the relationships, and such.
http://en.wikipedia.org/wiki/Third_normal_form
Once you get to that stage, then start looking at what you have, and ask yourself how it will behave with your specific situation. ie how are you accessing it .. is it going to perform poorly, would it help to denormalize things a little to help improve query performance, etc, etc.