Jump to content

  • Log In with Google      Sign In   
  • Create Account

Banner advertising on our site currently available from just $5!


1. Learn about the promo. 2. Sign up for GDNet+. 3. Set up your advert!


Waterlimon

Member Since 28 May 2011
Offline Last Active Today, 12:04 PM

#5126549 human intelligence

Posted by Waterlimon on 26 January 2014 - 12:30 PM

I just scrolled through this thread and, after seeing the amount of derpage in it, I think the OP may be on to something. Perhaps computers can equal the intelligence of SOME people in a few years, but certainly not MOST people.

But computers only do what you program them to do so they cant possibly be more intelligent than the programmer.

 

And you cant program consciousness because it arises from quantum mechanics.

 

QED

 

no im not serious ;_;




#5121150 When to use polymorphism

Posted by Waterlimon on 04 January 2014 - 10:38 AM

Here are some good links:

 

http://www.youtube.com/watch?v=lbXsrHGhBAU

http://www.youtube.com/watch?v=DdUSzJ8taMs

 

So polymorphism is something like inverse operation in math. It does the opposite thing. In general you could create some object as you need them but with polymorphism you would create some group of object that would usually be represented with a single object. Than you would use base class (super class) as your primary class and do specific behavior trough inherited classes. Is this correct ?

 

Just think of it as a method that allows you to deal with multiple object types as if they were the one and the same. There are many methods that allow something like that, but the built in polymorphism with virtual classes and such is general and flexible, although more specific solutions might be better in a given situation.




#5119876 float unlimited increasing rotation or use a if

Posted by Waterlimon on 29 December 2013 - 12:14 PM

Branching is when the code executed next is chosen based on a condition. This includes of course if statements but also loops, since they need to decide whether to run the loop body one more time or stop looping based on the condition.

 

Also, things being functions/macros does not make them slow, because any modern compiler will be able to inline it if the function itself is simple. Eg. with the fmod, which is a couple of arithmetic operations, it is very likely that the same machine code is produced when you write the math inline yourself or use the function.




#5119850 float unlimited increasing rotation or use a if

Posted by Waterlimon on 29 December 2013 - 10:26 AM

Performance is irrelevant here.

 

What you should be worried about is loss of precision as the float value grows bigger. It will be fine for many many rotations but eventually it will become unprecise.

 

If you expect the float value to grow big enough to become unprecise, you NEED to do something about it or the math will break.

 

You prevent such things from happening by wrapping the float to 0-360 range, which you can do using the modulus operator (% for integers, fmod for floats), or by using a loop like Vortez showed (fmod will likely be more efficient since i believe its just a couple of simple arithmetic operations, faster than a loop with branches and whatnot)




#5119836 float unlimited increasing rotation or use a if

Posted by Waterlimon on 29 December 2013 - 09:25 AM

Could this also be achieved using float unrolledRot=fmod(absoluteRot, 360.0f)?




#5118836 C++ memory questions

Posted by Waterlimon on 23 December 2013 - 05:50 AM

Hi there. I don't think it's that slow to allocate memory. My last 2d rts game I allocated all objects with new and deleted them and I had no slow downs or any thing you could notice. And that could have 8 players with 800 units each plus.

 

If you mean allocating each unit separately, it could make a huge difference if you used pool allocation instead when it comes to creating and destroying units, as well as processing them (due to cache being utilized better)

 

The creation and destruction of units probably isnt a problem here though because i doubt you would be doing thousands of allocations per second. Its more the processing part that would matter here.

 

So allocation isnt horribly slow itself, but compared to the alternatives it is.

 

As an example i had implemented my sparse quadtree using std::function (so i can use lambdas to do operations on it) and std::vector, and when i replaced std::function with a template parameter and applied some .reserve() to the vectors, the performance improved at least tenfold.




#5118618 C++ memory questions

Posted by Waterlimon on 21 December 2013 - 02:27 PM

1) This is partially correct due to cache effects (the stack is small and accessed frequently and thus more likely to be in cache, while heap allocated items are scattered in memory), however the cache effects are irrelevant because thats not what you base your decision between stack/heap. If you CAN allocate on the stack, you allocate on the stack. What makes the heap slow is that finding a free segment of memory is an extremely expensive operation, which is why you only want to allocate large blocks and prefer more "uniform" allocation strategies (stacks/pool allocators)

 

2) The stack is limited in most cases, which is why you usually allocate on the heap if you need a huge chunk of memory (especially if the cost of allocation is overwhelmed by the processing of that huge memory chunk). You can usually change the size of the memory chunk reserved for stack though.

 

3) Dynamic STL containers use the heap to store the objects because they are dynamic, you cant really resize memory allocated on the stack. A std::vector will allocate a contiguous chunk of memory from the heap where it stores your array of objects (and reallocates if needed). If the type is Object, the array contains Objects, if the type is Object*, the array contains Object pointers (however you need to make sure the pointers actually point somewhere!). The containers dont really care what the type is, they just blindly store them. If you were to separately allocate these Objects (to fill the Object* container) on the heap, they would be scattered all around the memory instead of being stored in a contiguous chunk, which is very bad for cache.

 

4) Normal arrays are stored on the stack, because their size is known at compile time and thus they can be. std::array also allocates on stack because its size is known at compile time, so not all std containers store their elements on the heap.

 

5) Classes and structures in memory are simply their members stored in a single chunk of memory. So, in your example, Entity in memory is exactly the same as Object in memory. Thus, when you allocate an Entity on the heap, Object must be on the heap too (because its integrated as a part of the memory representation of Entity)

Eg. if we had struct RGB {char r,g,b;}, in memory we would have

[             RGB             ]

which is the same as

[char r][char g][char b]

which is the same as

[imagine 24 bits here]

A pointer would simply be a number (which you may interpret to be a Object*) so if Entity had Object* instead, the bytes of the pointer would be in heap, but the Object could be anywhere in memory (heap,stack,wherever you put it). That is, if Entity has Object*, it doesnt mean Object* points to the heap. You can point to an Object stored on the stack, too.

 

6) Theres nothing wrong with the heap itself, its the allocation that is the problem. If you were to use a fixed size array (and reusing spaces for old objects) you are basically implementing a custom allocator which is most likely more efficient than the general allocator provided by the OS. You can combine these two, use the general allocator to get the large blocks of memory, and then use custom allocators to efficiently allocate your objects within these memory blocks. This way you get both fast allocation as well as nonlimited space (if you allow allocating more of these big memory chunks using the general allocator as needed)

Its a compromise between wasted space and performance in many cases.




#5118149 How to set up a audimentary AI?

Posted by Waterlimon on 19 December 2013 - 10:23 AM

 

Random choices seems like a good place to start.

struct Agent {
  Action pick_action(std::vector<Action> const &actions) {
    return actions[std::rand() % actions.size()];
  }
};

Now write whatever code you need to in order to make this AI work. You need to be able to determine what the AI's available actions are and how to execute them.

 

Whenever you want to replace this dummy AI with something more reasonable, you may want to pass a view of the game state as well, or you may want to beef up the `Action' class so it contains enough information for the agent to decide which action is his favorite. This will naturally lead you to a utility-based AI architecture, which is my favorite paradigm for AI in general, and which lends itself very well to implementing personalities.

 

I can understand your point, but I can't understand your code. I only know Python, so can you explain that code a bit?

 

 

The object Agent (the AI) is given a pile of possible actions it can take, out of which a random one is chosen.




#5114861 Bullet physics undefined behavior with a dummy simulation

Posted by Waterlimon on 06 December 2013 - 09:06 AM

Make sure its not caused by the object going into a sleeping state.


#5113772 SOLVED Asking for help for Efficient code/Fast to use, ideas/suggestions

Posted by Waterlimon on 02 December 2013 - 09:44 AM

1. Map format

Ok, theres two things here. One, how do you store your maps on disk to save, load and build them. Second, what is the actual data structure of the map.

For the first one you have (how to store map on file):

-Store the map as a picture (eg. png) where pixel color corresponds to tile type. Works for simple maps. You can edit it in an image editor. But its limited and you will eventually need to move forward when you need more features.

-Binary format. Create a protocol for storing the map as bits and bytes. This is the most flexible feature wise. It is not practical to edit this by hand, youll need to make an editor. It is also more vulnerable to bugs because you cant really see what you are doing.

-Human readable text format (like the xml shown by exOfde). Same benefits as binary excepts its in a human readable form, and thus easier to work with. The only problem is that it is not very compact in memory and thus will take more space than a binary format as well as likely take longer to load.

-An already existing format with editors available. This might be a good choice, so you dont have to worry about editing your map. Of course, being somewhat out of your control, you might at some point face limitations in what the format or editor for the format can do.

 

The second one, theres not so many ways you can arrange your data in memory. Its more about what features you need:

-Grid in memory (X*Y tiles). Use a format like this for the tile data, to tell what material each tile is.

*Use this only for data that most tiles have

*You can also add an ID to the tile data, and store the actual data in a different place. Eg if a tile has a list of objects contained, you want to store it in a separate structure because you dont know how many items there are. You dont want each tile to have space for 1000 items. You want each tile to point to a list of items that is resized to fit the items.

*Later you might want to be able to have multiple grids (chunks) which form a continuous grid made of many parts. This allows it to be easily resized by adding or removing chunks. This is if you want procedurally generated terrain, or if you want to load only a part of the terrain in at a time from disk or network.

 

-Freely placed objects (list of objects, each has x,y position)

*Consider this for things that are not really a part of a tile or are rare

*Players, other moving objects...

*Some special locations like spawns so you dont have to scan each tile to find what tile is the spawn in

 

 

 

2. Map access

The access pattern you described is easily achieved by flood filling limited to an amount of steps which is the range. Specifically:

-Have 2 list, one for tiles in range and second for recently flooded tiles.

a) From the center tile (the player) flood all the neighboring tiles. Add them to the list of tiles in range and the recently flooded tiles.

b) Treat all tiles in recently flooded tiles as center. Clear the recently flooded tiles list and flood from the tiles that were in it further out (dont flood back to tiles we already covered)

c) Repeat until RANGE steps

or something similiar. Google on flood fill algorithm. This isnt exactly filling because we terminate after X steps but the logic is the same.

 

3. Customization of player

The game logic of this should be simple, your player has slots you can equip stuff to (eg a WeaponType member, which you can use to find the weapon details such as appearance and damage. As in WeaponTypes[player.WeaponType.getID()].getDamage())

The appearance is more complicated. The weapon you can probably just draw as a separate sprite to the correct position when it exists. For smaller details you might need to do something like programmatically color the ring in the players hand or have a ton of sprites to cover all the possible combinations of things the player can wear.

The best would be to just figure out how to compose a player from multiple sprites so you can swap them easily.




#5113523 Good old multi account problem

Posted by Waterlimon on 01 December 2013 - 12:38 PM

Would you punish someone who has a friend living somewhere else, doing whatever the multiers do? (eg "sacrificing" the other account to boost the first one. The friend might want to help the person in the game or something.)

 

It is the unfair activity that you should prevent, not a single player controlling multiple accounts, because the activity works just as well when multiple people are cooperating with their own single accounts.

 

So focus on that instead. Of course it makes sense to add some basic limitations to weed out any totally unrealistic situations (1000 accounts on the same computer/email)




#5113499 light rendering in shaders, slow.

Posted by Waterlimon on 01 December 2013 - 10:02 AM

1) Find if the high number of texture samples is the culprit (try setting the constant to like 5)

 

2) If it is, try:

a) Running it over a lower resolution input (take your scene, downsample it to lets say halve the dimensions)

b) Reducing the constant (this should not affect the quality as negatively if you do a. If you halve the dimensions of the input, i think you should halve the constant too)

c) Reducing the resolution of the output (eg render this effect onto a low resolution buffer, then render that on top of your scene)




#5113460 light rendering in shaders, slow.

Posted by Waterlimon on 01 December 2013 - 06:17 AM

Does the lag significantly reduce if you lower the constant (which currently is set at 100) in the shader?

 

Also your render function, go through it and make sure that everything in it actually needs to be done every frame. If theres stuff that only needs to be done once, move it outside.

 

Also how big is that model of yours?




#5113244 Victorian era province names

Posted by Waterlimon on 30 November 2013 - 06:17 AM

Perhaps you could write a name generator for each type of name, such that the set of names used will be different each game?

 

It could be very simple. For example, you could make a big list of words (or endings and such) and then just combine them randomly. Experiment until you no longer get names that look wrong.

 

Eg. With the province names, you could list english words (like corn, hill, black, shire as in your example), possibly add in an ending (s) and then run some checks to make sure they are not impossible to spell. With foreign country names, you can just throw together a couple of random letters and be done with it.




#5113072 Does this approach to pass frequent method parameters implicitly seem evil?

Posted by Waterlimon on 29 November 2013 - 03:37 PM

(excuse any mistakes in the code - i have not actually tried this yet and because globals are evil, im probably unaware of how to use them correctly. Will try to fix any problems.)

Imagine the following case:

We have a pile of game entities, each having logic, and each often needing access to the scene object so they can interact with the surroundings.

We then have code to update all these different entities as in:

void Scene::update()
{
    runMachines(*this); //Lots of moving parts - may affect surroundings
    growGrass(*this); //Need to check other objects - grass may impale those who stand on it while its 
    growing
    glowLight(*this); //Heat the neighbors
    for each object do
    {
        for each otherobject do
        {
            checkCollisions(*this)
            doGravity(*this)
            sayHi(*this)
        }
    }
    etc.
}

As you can see, quite a lot of Scene in there. I realize that this is not much. But if we take the hypothetical situation where the number of such objects is 4 (since we dont want to combine everything into a single scene object for example) and the logic is a lot more complicated, this gets quite redundant. In most practical situations, scene could be considered a global. We dont do that, because two scenes should be able to exist, and making it a global would remove ALL passing of Scene around.

 

So, what if there was a compromise such that:

-Scene is still passed around as a parameter where it does not feel like mindless repetition of a fact the code should understand (im basically looking for a statement like "using Scene" here)

-It is still obvious where scene might be passed. If its a global, we have no control over where scene can be accessed.

-It does not limit the amount of scenes to 1.

 

So, i was thinking of a class that sets a scope-limited global, which can be set in a scope, and then accessed from whatever methods you call from that scope as it were a global.

 

Implementation:

template<typename T, int identifier=0>
class Using
{
public:
    Using(T* ptr) : prevImplicit(implicit), implicit(ptr)
    {
    }

    ~Using()
    {
        implicit=prevImplicit;
    }

    static T* get()
    {
        assert(implicit!=nullptr);
        return implicit;
    }

private:
    static T* implicit=nullptr;
    T* prevImplicit;
}

Usage:

 

Using the example, instead of passing Scene to each method, we set a temporary scope limited global:

    Using<Scene> scene(*this);

And within the methods needing access to the scene we do:

    Scene* scene = Using<Scene>::get();

and then use it to apply whatever logic needed. The scene thus does not have to be passed in as a parameter, it is now a less evil global! :DD

 

Now, to explain some details.

We might have a scope using Using to apply a scope limited global. But what if a method is called from this scope, which also uses Using to also set a global of type Scene?

We have two mechanisms to handle this case:

1) We store the previously set value in the temporary Using class. When we return back to the first scope from the subscope, the value of the global will be reset to what it was before. Please do note that there might be some corner cases related to threads and lambdas and those might need special approaches.

2) We have a second template parameter, identifier, which allows us to have more than one such "implicit parameter". This is more for cases where you want to use implicit parameters, but have two or more of the same type. If you are handling eg. an array of them, it does no longer make sense to try to pass them as implicit parameters. Enums can be created to have eg PRIMARY_SCENE and SECONDARY_SCENE. I cant come up with any better examples of when youd need this, but the important thing is that it is trivial to pass in multiple objects of the same type.

 

So, the example update method would look as follows:


void Scene::update()
{
    Using<Scene> scene(this);
    runMachines(); //Lots of moving parts - may affect surroundings
    growGrass(); //Need to check other objects - grass may impale those who stand on it while its
growing
    glowLight(); //Heat the neighbors
    for each object do
    {
        for each otherobject do
        {
            checkCollisions()
            doGravity()
            sayHi()
        }
    }
    etc.
}

 

Is there anything wrong with this approach? Please do remember that i wanted to try and find a compromise between being explicit about dependencies, while at the same time allowing this kind of gameplay code to be less strict, since it is likely to change more rapidly and such (which is why we use scripting languages for that kind of code - it does not need to be so strict)

 

In most cases this does not really help much, but im sure there are cases where such a construct might be useful. 






PARTNERS