I am new to the play-clj, and I am confused about [screen entities] as arguments for all of the functions. I went through the tutorial, but am still not getting it i think, what these for all of the functions shared arguments are and what are they containing? I know screen is a map (a record more precisely) containing various functions for the main faunction and entitites is a vector containing aspects about the objects in the game.
What kind of values are the entities and screen holding, are they dependent on the functions we define? I would be very thankful if someone could give me some declarations and examples.
Well, the question is quite general, so I'll give a general answer. If you want specific details, feel free to ask.
Although play-clj supports functional game development, the base elements backing it are Java classes; accessed, set up, and modified in an imperative way. That means you will cause a huge amount of side effects using play-clj. And some behaviour may feel out of your hand when you're used to Clojure, but it sure makes some sense.
Despite the name, screen contains a custom instance of the complete libGDX engine, that is it wraps Java-objects for sound, graphics, physics, and asset management. It gets mutated in an imperative way, by calling commands followed by a bang.
For example(let [screen (update! screen :world (box-2d))] (...)) will add a 2d physics engine to your game which will exist from that point of time, even after you leave the binding. Its functions may also mutate entities as side effects, like dropping a ball by applying gravity.
All the entities on the other hand will get treated as properly as possible by functions like step! (mutating their states by applying physics if appropriate) or render!. They are maps, and their treatment is based on properties. :body means, they need physics, :shape means they need to be drawn as a primitive, :x, :y, :width, :height etc. do what you'd expect, and so on. You can add other properties and work with them as usual.
Functions expecting these two arguments have one thing in common: If you give them a return value, the game uses this return value as entities-vector from that point of time. So don't just modify and return a single entity unless you want to leave the poor bugger on the screen all alone...
Also make sure to read the docs at https://oakes.github.io/play-clj/, they explain a lot.
Related
For quite some time I have been interested in perfomance in C ++.
A lot of things keep coming up, whether in conferences or in books:
Do not use a virtual function, have the data in the cache, the branches etc.
There are many benchmarks with examples of video games to show the differences in performance.
The thing is, the examples are always very simple.
How does that really work in code that is more than 20 lines? in AAA video games, finance etc.
If I have 100 types of objects that have different update, different behavior and other joys, it's easy to set up via polymorphism or function pointers.
Now, by following the advice given to make a powerful code, the above options are not possible.
We will therefore prefer to have 100 arrays that we will update separately.
We will have good access to the cache, the functions will probably be inline etc. in short, the performance will in principle be better.
So, I have 100 arrays and 100 differents functions that i will have to call at each frame.
The tables dynamically change depending on what happens, new players appear, a monster dies etc.
Some array will have 0 elements active, others 10...
I would call functions that will have no work (array without active element) but I have no choice, I have to have a flag or look if elements are active or not in my array.
I end up with something like this:
obj1update ();
obje2update ();
....
obj1behavior ();
obj2behavior ();
....
obj1render ();
obj2render ();
.....
objectxy ();
....
Of course, there will undoubtedly be a function which manages all the update calls on the objects, one for the behavior etc but to simplify it gives as above.
To stay in the video game, if the x action of a player causes the arrival of y monsters, there are several types of monsters which have different functions.
We will therefore put the monsters in our tables and this time the functions dealing with these monsters will have work.
We can use the ECS pattern or a derivative but they will potentially have very different behaviors (an ia that directs them or other), different components and therefore different functions will be needed to process them.
They will be called hard in the code since we don't have polymorphism or function pointers and we will have to check at each frame if they have something to process or not.
Is it really done that way? suppose i have 500 types? 1000 ?
Edit:
Lots of comments so I'll get back to you here.
As Federico said, I want to know if these recommendations are good for books but less so in practice.
Several resources that I have looked at:
https://www.agner.org/optimize/#testp
Great suite of several books
www.youtube.com/watch?v=WDIkqP4JbkE&t
Scott Meyers talk on memory
https://people.freebsd.org/~lstewart/articles/cpumemory.pdf
On memory
www.youtube.com/watch?v=rX0ItVEVjHc&t
Data-oriented programming
https://www.dataorienteddesign.com/dodbook/
data oriented design book
There are also other resources but it already gives you an idea on what I'm basing
No, real programs are not written like that. Real programs are written by noticing that all the monsters have a bunch of things in common, and using the same code to do those things. They all pathfind, but they have different distances they can walk? Great. Add a max_walking_distance variable and call the same function each time.
All your monsters have a 3D model? Then you don't need a virtual render method. You can just render the model.
You don't have to divide up your data according to "sensible" boundaries. You don't have to have a struct monster. You can have a struct monster_pathfinding and a struct monster_position and a struct monster_3d_model. Even if you just put these in parallel arrays (i.e. monster 123 has its pathfinding info in monsters_pathfinding[123] and its position in monster_positions[123]) this can make more efficient use of the data cache, because the pathfinding code doesn't load the 3D model pointers into the cache. You can get cleverer by skipping entries if some monsters don't pathfind or don't render. Essentially it is recommended for performance that you group data together according to how it's used, not according to your mental model of the things in the game. Yes, skipping entries makes it way more difficult to delete monsters. But you tick monsters a lot, and you don't delete monsters very often, right?
Maybe only a few monsters shoot guns at the player (the rest try to eat the player). You can have a struct monster_gun_data {int ammunition; int max_ammunition; int reload_time; monster_position *position;}; and then if you have 200 monsters, but only 10 of them have guns, your monstersShootGunsAtPlayers function only has to iterate over the 10 entries in the monster_gun_data array (and load their positions via pointers). Or, you might profile that and find out that because most monsters in your game have guns, it's slightly faster to iterate over all the monsters and check their MONSTER_HAS_GUN flag instead, than to access the position through a pointer which can't be prefetched as easily.
How do you do different kinds of monster attacks? Well, if they're completely different (melee vs ranged), you probably do them with different functions as you have described. Or you might only check the attack type after you decide the monster wants to attack the player. You seem to suggest monsters use different attack code, but I bet this works for almost all of them:
if(wantsToAttack(monster, player)) {
if((monster->flags & HAS_RANGED_ATTACK) && distance(monster, player) > monster->melee_attack_distance)
startRangedAttack(monster, player);
else
startMeleeAttack(monster, player);
}
And what's really different between a monster with a gun, and a monster with a bow and arrow? The attack speed, the animation, the speed the projectile moves at, the projectile's 3D model, and the amount of damage it does. That's all data. That isn't different code.
Finally, if you have something completely different, you might consider making it a "strategy object" with a virtual function. Or just a plain function pointer, if you can. Note that the Monster object is still not polymorphic, because if it was, we couldn't have an array of them and that would slow down all the common code. Only the specific parts of the monster that we're saying are polymorphic are actually polymorphic.
void SpecialBossTickFunction(Monster *monster) {
// special movement, etc
}
// ...
monster->onTick = &SpecialBossTickFunction;
// monster is still not polymorphic except for this one field
You could also do:
struct SpecialBossTickStrategy : TickStrategy {
void onTick(Monster *monster) override {...}
// then you can also have extra fields if needed
// but you also have more indirection
};
monster->onTick = new SpecialBossTickStrategy;
And don't do stuff unnecessarily. Try to be event-driven instead of doing stuff every tick:
// bad because we're calling this function unnecessarily every tick
void SpecialUndeadMonsterTickFunction(Monster *monster) {
if(monster->isDead) {
// do some special reanimation sequence
}
}
monster->onTick = &SpecialUndeadMonsterTickFunction;
// better (for performance)
void SpecialUndeadMonsterTickWhileDeadFunction(Monster *monster) {
// do some special reanimation sequence
if (finished doing whatever) {
monster->onTick = NULL;
}
}
void SpecialUndeadMonsterDeathFunction(Monster *monster) {
monster->onTick = &SpecialUndeadMonsterTickWhileDeadFunction;
}
// ...
monster->onDead = &SpecialUndeadMonsterDeathFunction;
// Also better (for performance)
void DoUndeadMonsterReanimationSequences() { // not virtual at all, called from the main loop
for(Monster *monster : special_undead_monsters_which_are_currently_dead) {
// do some special reanimation sequence
}
}
// Not great, but perhaps still less bad than the first one!
void DoUndeadMonsterReanimationSequences() { // not virtual at all, called from the main loop
for(Monster &monster : all_monsters) {
if(monster.type == TYPE_SPECIAL_UNDEAD_MONSTER && monster.isDead) {
// do some special reanimation sequence
}
}
}
Note that in the third example you have to keep this array special_undead_monsters_which_are_currently_dead up to date. That's okay, because you only have to change it when a monster spawns, disappears, dies, or un-dies. And those are relatively rare events. You are doing a bit more work in these events, in order to save work every tick.
Finally, keep in mind these are techniques that may or may not improve performance in your actual program. I see DOD as a grab-bag of ideas. It doesn't say you must write your program in exactly a certain way, but it is offering a bunch of unconventional suggestions, the theory to explain why they work, and examples of how other people have managed to use them in their programs. Since DOD usually suggests that you complete reorganize your data structures, you may only want to implement it in the performance-critical areas of your program.
Just to add some more perspective on the top-level question:
Big projects that require very good performance really don't use polymorphism?
You're missing out an entire category of polymorphism.
I often mix all three of the below styles in a project, because not all code has the same performance requirements:
setup and configuration code doesn't generally need to be (very) fast. Use OO style and runtime polymorphism all you want for properties, factories, whatever.
Runtime polymorphism broadly means virtual functions.
steady-state code that does need to be fast can often use compile-time polymorphism. This works well for a statically-known (and ideally small) collection of types with similar interfaces.
Compile-time polymorphism means templates (function templates, type templates, replacing the run-time Strategy pattern with the equivalent Policy, etc.)
the code with the tightest performance requirements may need to be data-oriented (ie, designed around cache friendliness).
This isn't all the code in the project, and probably isn't even all the code that needs to be fast. It's all the code that needs to be fast and where performance is dominated by cache effects.
If you only have one copy of an object, you may well inline as much as possible (and try to fit it into the fewest cache lines possible), but splitting it into four different arrays with only one element each won't achieve much.
The Clojure official spec doc states:
Most systems for specifying structures conflate the specification of
the key set (e.g. of keys in a map, fields in an object) with the
specification of the values designated by those keys. I.e. in such
approaches the schema for a map might say :a-key’s type is x-type and
:b-key’s type is y-type. This is a major source of rigidity and
redundancy.
And in this SO question: clojure.spec human readable shape?
The following example is given:
(s/def ::car (s/keys :req [::tires ::chassis]))
(s/def ::tires (s/coll-of ::tire :count 4))
(s/def ::tire (s/or :goodyear ::goodyear}
:michelin ::michelin))
My question is: how is this not ridig and not redundant? By opposition to that, what would be and example (in Java?) of something rigid and redundant?
As I see it you still cannot define a car that'd be, say, a dragster with 6 wheels because ::tires must have 4 elements. You cannot either define a floating car whose rear wheels would be propellers.
How's the above example different from, say, static typing from the standpoint of rigidity and redundancy? How's that different from a Java car class that'd be constructed using a tires instance itself containing four tire instance?
Basically I think what I don't get is that you're spec'ing the map by telling which keys are required. So far so good. But then the keys are themselved spec'ed, so the values designated by those keys are specified too no!? How are things "not conflated" here?
Just for a moment, zoom back out and think about software development as a practice. We'll get to spec at the bottom.
As engineers, one of our most important skills is the ability to define and think in abstractions.
Think about how function composition simplifies the construction of complex software. It simplifies the definition of a complex function by allowing us to think more broadly about what is happening. A nice benefit of this is that it also allows for the smaller functions which compose the larger one to be reused when writing similar, but slightly different, complex functions.
Of course, you don't need functions at all. You can write an entire project in one function. However, this is a bad idea primarily because it conflates the intent of a function with the specification of the function.
For example, a function make-car calls build-engine, build-drivetrain, install-interior, and a lot more. Sure, you can take the code from each of those and paste them inside make-car. But the result is that you have lost abstraction. make-car cannot be improved or changed except in the make-car code itself. The code for how to build an engine cannot be improved or reused to make any other car. Why? Because the knowledge of how to build that engine for that particular specification of car is embedded in the make-car function.
So, make-car should not define how to build the engine (or any other components of the car); it simply specifies what components make up the car, and how they work together. The specifics of those components do not belong to the working knowledge embedded in make-car.
The comparison to spec should now be clear:
In a similar fashion, spec allows you to define entities as abstractions. Could you embed the knowledge of an entity within a specification/schema? Certainly. Can you directly substitute the specification of the individual components into the entity definition itself? Yes. But in doing so, you are conflating the entity with the definition of its components. The loss is the same as with the above: you lose the abstraction of what the entity is, as now you must change the definition of the entity in order to change details about the entity that are really details of its components; and, you have lost the ability to reuse definitions for similar, but distinct, entities.
I am trying to make an architecture for a MMO game and I can't figure out how I can store as many variables as I need in GameObjects without having a lot of calls to send them on a wire at the same time I update them.
What I have now is:
Game::ChangePosition(Vector3 newPos) {
gameobject.ChangePosition(newPos);
SendOnWireNEWPOSITION(gameobject.id, newPos);
}
It makes the code rubbish, hard to maintain, understand, extend. So think of a Champion example:
I would have to make a lot of functions for each variable. And this is just the generalisation for this Champion, I might have have 1-2 other member variable for each Champion type/"class".
It would be perfect if I would be able to have OnPropertyChange from .NET or something similar. The architecture I am trying to guess would work nicely is if I had something similar to:
For HP: when I update it, automatically call SendFloatOnWire("HP", hp);
For Position: when I update it, automatically call SendVector3OnWire("Position", Position)
For Name: when I update it, automatically call SendSOnWire("Name", Name);
What are exactly SendFloatOnWire, SendVector3OnWire, SendSOnWire ? Functions that serialize those types in a char buffer.
OR METHOD 2 (Preffered), but might be expensive
Update Hp, Position normally and then every Network Thread tick scan all GameObject instances on the server for the changed variables and send those.
How would that be implemented on a high scale game server and what are my options? Any useful book for such cases?
Would macros turn out to be useful? I think I was explosed to some source code of something similar and I think it used macros.
Thank you in advance.
EDIT: I think I've found a solution, but I don't know how robust it actually is. I am going to have a go at it and see where I stand afterwards. https://developer.valvesoftware.com/wiki/Networking_Entities
On method 1:
Such an approach could be relatively "easy" to implement using a maps, that are accessed via getters/setters. The general idea would be something like:
class GameCharacter {
map<string, int> myints;
// same for doubles, floats, strings
public:
GameCharacter() {
myints["HP"]=100;
myints["FP"]=50;
}
int getInt(string fld) { return myints[fld]; };
void setInt(string fld, int val) { myints[fld]=val; sendIntOnWire(fld,val); }
};
Online demo
If you prefer to keep the properties in your class, you'd go for a map to pointers or member pointers instead of values. At construction you'd then initialize the map with the relevant pointers. If you decide to change the member variable you should however always go via the setter.
You could even go further and abstract your Champion by making it just a collection of properties and behaviors, that would be accessed via the map. This component architecture is exposed by Mike McShaffry in Game Coding Complete (a must read book for any game developer). There's a community site for the book with some source code to download. You may have a look at the actor.h and actor.cpp file. Nevertheless, I really recommend to read the full explanations in the book.
The advantage of componentization is that you could embed your network forwarding logic in the base class of all properties: this could simplify your code by an order of magnitude.
On method 2:
I think the base idea is perfectly suitable, except that a complete analysis (or worse, transmission) of all objects would be an overkill.
A nice alternative would be have a marker that is set when a change is done and is reset when the change is transmitted. If you transmit marked objects (and perhaps only marked properties of those), you would minimize workload of your synchronization thread, and reduce network overhead by pooling transmission of several changes affecting the same object.
Overall conclusion I arrived at: Having another call after I update the position, is not that bad. It is a line of code longer, but it is better for different motives:
It is explicit. You know exactly what's happening.
You don't slow down the code by making all kinds of hacks to get it working.
You don't use extra memory.
Methods I've tried:
Having maps for each type, as suggest by #Christophe. The major drawback of it was that it wasn't error prone. You could've had HP and Hp declared in the same map and it could've added another layer of problems and frustrations, such as declaring maps for each type and then preceding every variable with the mapname.
Using something SIMILAR to valve's engine: It created a separate class for each networking variable you wanted. Then, it used a template to wrap up the basic types you declared (int, float, bool) and also extended operators for that template. It used way too much memory and extra calls for basic functionality.
Using a data mapper that added pointers for each variable in the constructor, and then sent them with an offset. I left the project prematurely when I realised the code started to be confusing and hard to maintain.
Using a struct that is sent every time something changes, manually. This is easily done by using protobuf. Extending structs is also easy.
Every tick, generate a new struct with the data for the classes and send it. This keeps very important stuff always up to date, but eats a lot of bandwidth.
Use reflection with help from boost. It wasn't a great solution.
After all, I went with using a mix of 4, and 5. And now I am implementing it in my game. One huge advantage of protobuf is the capability of generating structs from a .proto file, while also offering serialisation for the struct for you. It is blazingly fast.
For those special named variables that appear in subclasses, I have another struct made. Alternatively, with help from protobuf I could have an array of properties that are as simple as: ENUM_KEY_BYTE VALUE. Where ENUM_KEY_BYTE is just a byte that references a enum to properties such as IS_FLYING, IS_UP, IS_POISONED, and VALUE is a string.
The most important thing I've learned from this is to have as much serialization as possible. It is better to use more CPU on both ends than to have more Input&Output.
If anyone has any questions, comment and I will do my best helping you out.
ioanb7
I've been recently assigned to code a Entity-component-system based framework. As I'm not experienced in that matter, I have a simple question:
Can I assume, that an entity can have maximum of one component of each type? I mean like:
int COMPONENT_COUNT; //number of different components available
class Entity
{
COMPONENT* component_list[COMPONENT_COUNT];
}
then adding a component would be like
component_list[component.id]=&component; //can't add more components of this type
Is that a correct assumption? I can't think of any situation when an entity would need two or more components of the same type.
I'm going to bring up my holy bible and say, yes, an entity should only have one component type! It is blasphemous to do otherwise!
Thou shalt not create entities with more than one component of the same type or else thou shalt face eternal damnation.
I'm normally pretty loose about this stuff but when you allow your system to have more than one component of a given type attached to an entity, that complexity spreads to every single corner of your systems.
Now every system has to work against the assumption that there could be more one component of the same type attached to an entity for any component type, at which point you're constantly faced with design questions like what a physics system should do when an entity has 14 position components attached. And what happens when a rendering system finds an entity with 15 motion components but only 4 sprites, expecting a matching motion component for each sprite component? Which motion components are used for which sprite?
Life becomes a whole lot simpler when you just say, "one component instance of one component type per entity."
If you want to aggregate, then just make your component a collection of something. Instead of Bone component, make it a Skeleton component which stores a list of bones. Instead of a Pixel component, make it an Image component which stores a collection of pixels. That's all fine, and doesn't require you to violate and defile the sacred commandment above.
Well, there isn't a holy bible of entity component systems. But many implementations I'm aware of don't make any provision for this, they allow entities to have or not have some kind of component but don't support multiplicity. Likewise, from a design perspective it seems like a rather bad idea (lots of complexity for naught). You could make it work, but neither you nor I can come up with a use case. KISS and YAGNI apply, this is a reasonable assumption. And if you do later need to add a component twice or thrice, it's easy to emulate by having two or three different kinds of components. Only with variable arity you need to change the innards of the system, but that seems even more outlandish.
Urho3D allows multiple same type components - and their components derive more than once sometimes - ie StaticModel from Drawable from Component
When you make a new component type - you can add as many of them as you want to a "Node" (same thing as Entity). This was pretty much a nuisance when using Urho - always thinking about "Wait, how many of these things does this Node have?".. For what?
Like others have mentioned, seems hard to justify all those extra for/while loops that go for 1 iteration always.. With Urho I got around it by just making it my own rule to never add more than one component of a type to the node... just too confusing otherwise
I have a class that wraps around a list called ExplosionGroup (previously called AllExplosions for reasons I'll explain) which is a list of 'Explosion's (another class).
My original design choice, and what ran for awhile, was to have an ExplosionGroup in the 'Level' class that runs all the levels. Any classes (like ships or bosses) that had functions that would cause them to explode would have this ExplosionGroup passed to those functions. So basically, the Level's ExplosionGroup was sucking in all of the explosions created (hence it was then called AllExplosions).
void Foo::Explode( AllExplosions &explosions ) {
...// Create the explosion
explosions.Add( newExplosions );
}
Recently I ran into a problem where this solution wouldn't work since I needed to create an explosion outside one of these functions, and just putting the code in those functions would a) not make any sense and b) not work correctly.
Thus I came up with the idea to have each of the classes that exploded have their own explosion group. This would allow the classes to deal with explosions however they want, not just in a function where an ExplosionGroup was passed. Then I wrote a TakeExplosions function for ExplosionGroup (which just uses std::list's splice) which took an ExplosionGroup parameter and sucked all of the explosions out of that group. This would be used by Level in unison with an accessor for each classes' ExplosionGroup.
void Foo::TakeExplosions( ExplosionGroup &explosions ) {
m_Explosions.splice( m_Explosions.end(), explosions );
}
I thought this was great, but I've realized that if I use this technique I'll want to use it for all classes that can explode to be consistent. However, there are a few special cases in which I'll need to do this indirectly in order to get the explosions to the Level's explosions. For example, a Boss class holds a BlockWall (a list of blocks), and blocks explode.
Thus, the block wall would need to extract explosions from its blocks, the boss would need to extract explosions from the block wall, and the level would need to extract explosions from the Boss (unless I provided an accessor for the Boss' wall, which I have no intention of doing).
I really don't want to use a global container for explosions so that all of the classes can just add in explosions as they please and be done with it, so I'm asking for any recommendations or ideas towards this issue. I've also considered ditching handling explosions in the Level class and having each class handling in completely on its own, but that seems like a bad abstraction to me.
someBlockWall.ShowExplosions( p_Buffer );
playerShip.ShowExplosions( p_Buffer );
// etc. Seems ugly?
P.S. I understand that its hard to answer a question like this without knowing how animations in the game work, etc. I'm also being tempted to use a global container because I'm slightly worried that all of this playing with lists could have performance implications. However, I haven't done any profiling so I'm trying not to even consider it.
I have no answers, just some questions that would help others (and maybe also yourself) to find a good answer.
What are the exact steps that have to be performed in order to show an explosion?
What are my invariants here? (e.g. are all explosions the same, are the object-specific, dependant on time or position on the level)
Which objects are involved in showing an explosion (renderer, clock, explodable object, etc.)?
There are many possible solutions, but it is hard to choose without knowing all the forces involved.