Jump to content

  • Log In with Google      Sign In   
  • Create Account

Juliean

Member Since 29 Jun 2010
Online Last Active Today, 07:48 AM

#5188321 Is there a way for me to see my game`s performance or frame rate?

Posted by Juliean on 21 October 2014 - 09:33 AM

Fraps for example:

http://www.fraps.com/

The trial-version will do, just start it & you should note a yellow frame-counter in one of the edges of your application/screen.




#5187674 Can you give me an example shows the meaning of the concept?

Posted by Juliean on 17 October 2014 - 11:05 AM


so you are talking about the human not the teacher ,, between the bracket i type the object right ??

so now saying human has-a name not teacher right ?

 

In the bracket, you type the current classes parent class, so thats "is-a". See https://docs.python.org/2/tutorial/classes.html chapter 9.5.




#5187656 Can you give me an example shows the meaning of the concept?

Posted by Juliean on 17 October 2014 - 09:26 AM

I can't think of any practical example for "is-a" in programming right now, but conceptually, take this:

 

A teacher is a human. This can be modelled by having a class inheritance:

class Human

class Teach(Human)

A teacher also might have a schoolbook. This is a "has-a" relation, as the teacher doesn't derive of schoolbook, but instead uses it:

class Human

class Schoolbook

class Teacher(Human)

    def __init__(self)
        self.book = Schoolbook()

This is achieved via aggregation, as I've shown here. Thats whats meant by "reference each other". The Teacher references a Schoolbook, in that it posses & possibly uses it.

 


def __init__(self, name):

self.name = name

why we must type this line ?? (self.name = name)

 

__init__ is a function, executed with a bunch of parameters. at that point "name" is merely a local variable, but you want to use it as a class variable. So in order to do that, you have to assign the local "name" variable to the instance of the class ("self"), by calling "self.name" (this instances "name" variable) "= name" (is assigned the local "name").




#5186922 How to Separate the Rendering Code from the Game Code

Posted by Juliean on 14 October 2014 - 08:48 AM


The problem is, what if I want to port my DirectX game onto another platform that uses say OpenGL? My rendering code is so embedded into the game code that it'll be a major job to port it.

 

The keywords to a possible solution for this are: Interfaces, and Aggregation.

 

The way I'm handling this in my engine is that I first of all have a lot of Interfaces for my graphics classes, which are implemented out for the actual renderer under the hood:

// this is used in the game code
class ITexture
{
public:
    // just an example method
    virtual void Resize(int width, int height) = 0;
};

// those are two possible implementations

class TextureDX11 : public ITexture
{
    void Resize(int width, int height) override;

private:

    ID3D11Texture2D* m_pTexture;
}

class TextureGL4 : public ITexture
{
    void Resize(int width, int height) override;

private:

   GLInt m_texture;
}

Whever you create a texture, you do it via a Factory, which eigther creates DX11 or GL4 variante. And all code uses the ITexture-interface, so it doesn't matter which backend you actually use. Note that using an actual interface might not even be the optimal solution due to virtual-function overhead, you could just use typedefs etc... instead.

 

Secondly, with such (or any similar) system you can have your game objects just determine what is being rendered, not how. For example, you can have your game-object use a mesh-object & texture-objects:

class GameObject
{
	void Draw(Renderer& renderer)
	{
		for(auto pTexture : m_pTextures)
		{
			renderer.BindTexture(pTexture);
		}
		
		renderer.BindMesh(*m_pMesh);
		
		renderer.DrawInstance();
	}
	
private:
	
	IMesh* m_pMesh;
	std::vector<ITexture*> m_pTextures;
}

This way, you only have very limited information about rendering in your game-objects. You can further seperate that if you want or feel it is waranted.




#5186133 Transparent backbuffer

Posted by Juliean on 10 October 2014 - 03:14 AM

Nevermind, I figured it out. I'll post a step-by-step solution for anyone who might stumble across this, since direct gathered information seems to be very sparse on that topic:

 

- Make sure swapchain-buffer format is set to DXGI_R8G8B8A8_UNORM.

- Call DwmExtendFrameIntoClientArea with the created windows metrics.

- Clear the backbuffer to (0, 0, 0, 0) at the beginning of every frame (read: whenever there is something redrawn)

 

This should show the content of whats behind the empty parts of the backbuffer. The next steps will now result in being able to actually interact with whats behind that:

 

- Calculate the bounding-rects of all your visible elements on the screen.

- Create a HRGN that covers all those areas by using CreateRectRgn for each element, and then CombineRgn(last, last, this, RGN_OR) them into one another

- At the end, set this region with SetWindowRgn(hwnd, rgn, true)

 

Since this will also hide the window parts that are not in the region, you can potentially skip the first three steps if all you have is rectangular structures without transparency, though this can lead to visible artifacts when moving elements around the screen.

 

Hope this helps someone who might have the same problem as I did.




#5185950 Unresolved External Symbols

Posted by Juliean on 09 October 2014 - 04:19 AM

Static member variables have to be defined in the c++-file like this:

Shader* Program::shaders[3];
GLuint Program::program = 0; // assigns the value of "0" initially

EDIT: Ninja'd :D




#5185598 If you ever used a vector in c++ could you show...

Posted by Juliean on 07 October 2014 - 01:19 PM


If you could post examples you feel would help me best understand how vectors work, that would be helpful. Vectors seems to be something very helpful use so I thought I might get the best understanding of it by seeing how their used by you guys at GDevs. I might have a few questions.

 

Have you used dynamic arrays before? Like this:

int* pIntegers = new int[100];
for(int i = 0; i < 100; i++)
{
    pIntegers[i] = i;
}

for(int i = 0; i < 100; i++)
{
    std::cout << pIntegers[i];
}
delete[] pIntegers;

std::vector is pretty much the same thing - just much safer (i.e. no memory-leaks), and with some additional out-of-the-box-functionality. You can (and possibly should) use them wherever you have been using plain "new type[count]" and so on until now:

std::vector<int> vIntegers;
vIntegers.reserve(100); // we know the amount of values beforehands, so we can tell this the vector to safe performance
for(int i = 0; i < 100; i++)
{
    vIntegers.push_back(i); // inserts i as the last element
}

for(auto integer : vIntegers) // c++11 range based for-loop, "integer" holds the current value in the vector
{
    std::cout << integer;
}

This code works identical to the first one. There is a few specialities to vectors which you can see here - like the way you can iterate them, "reserving" the memory before inserting a known amount of values, etc... but you'll learn them as you go.

 

Just a few (negativ-ish) things to keep in mind when using vectors:

 

- They can greatly reduce performance in debug-mode, when iterator debuggin is turned on and when you are iterating over them in a loop. Performance in "release" in Visual studio and likewise is identical to a plain array, so no need to worry here - just don't feel confused when you suddenly see a decrease in performance while debugging when changing from pointers/arrays to vector.

 

- As they are templates, they can slow down compile-time and increase EXE size. This does not happen in a huge extent anymore, and is not a huge problem anymore today - though using precompiled header files and using extern template declaration might help, if you are experiencing any of those problems (and have access to c++11 for the extern thingy).

 

Hope that helps.




#5185231 Two Questions about DirectX 11 (XMVECTOR & Creating Input Layouts)

Posted by Juliean on 06 October 2014 - 02:10 AM


ID3D11Device:: CreatInputLayout wants to check our vertex shader for compatibility with the defined vertex layout, so it is necessary to have a vertex shader at mesh creation time. While one may use the layout with different shaders, what is the necessity of this rule and is there any way to get rid of that?

 

You can just create a dummy-shader in code and use that to create the input-layout. The shader just needs to look like this:

struct VS_INPUT
{
    Arg1 : SV_POSITION;
    // and so on
};

void VS_MAIN(VS_INPUT In)
{
}

You should easily be able to create such a thing in code from your expected input signature.




#5181120 c++ Performance boost needed

Posted by Juliean on 17 September 2014 - 03:15 PM


My question is: is the vector slowing my program down here, compared to using a simple array? I read somewhere, that the [] operator of the vector is defined as inline, and when it's called too often (fe. inside a loop), the compiler doesn't inline it and thus the access is slowed down. Is that right? I'm calling that function from inside a 0..1326 loop.

 

Vector is *almost* the same performance as a pure array - in release/optimized mode (debug mode at least in visual studio is horrible - vector can slow you down from 1000 to 8 FPS if you are not careful), since there happens almost no range checks, and most calls are inlined/optimized out.

 

I'm suprised operator[] is mentioned as being slow - actually, [] is faster than at() because [] does not perform range checks, at least for map-classes - at map, .at() will check if the index is valid, whereas [] will return a valid element eigther way, if the key didn't exist before, it will insert it. I assume it will behave similarily for vector too.

 

Anyways, for static arrays (int variables[256]), vector is quaranteed to be slower, since it requires at least an additional redirection. Don't use a vector here, eigther stick with pure arrays or use std::array, which is a new std container class for static arrays - vector is dynamic and therefore has certain overhead that doesn't exists for static arrays.




#5179037 (Tower Defense) Template metaprogramming or Factory functions to avoid class...

Posted by Juliean on 09 September 2014 - 02:59 AM

Why even have a templated/base class? Whats wrong with

class Tower
{
     Tower(int attack, float range);

private:

     int m_attack;
     float m_range;
}

And then instead of typedefing you could in the simpliest case use an enum and factory function:

enum class TowerType
{
    ARROW, MAGIC, BOMB
};

Tower& createTower(TowerType type)
{
    switch(type)
	{
	case TowerType::ARROW:
		return *new Tower(100, 50);
	case TowerType::MAGIC:
		return *new Tower(50, 100);
	case TowerType::BOMB:
		return *new Tower(300, 25);
	default:
		assert(false);
	}
}

And now for the attacking part, you can use composition, to derive different attack components:

class IAttack
{
	virtual void Attack() = 0;
}

class DefaultAttack : public IAttack
{
	void Attack() override;
};

class SplashAttack : public IAttack
{
	void Attack() override;
};

class SlowAttack : public IAttack
{
	void Attack() override;
};

Which you can then add to the tower class via dependency injection:

class Tower
{
     Tower(int attack, float range, IAttack& attack);

private:

     int m_attack;
     float m_range;
     IAttack* m_pAttack;
}

And your pretty much done. Now your tower can have a non-virtual "Attack"-method which calls the "components" virtual Attack(). You can (and probably will want to) grant access to the tower to the attack-component, eigther by adding "Tower& tower" to the IAttack::Attack()-method declaration, in which case you can share the attack-component with all towers that use the same type. Or you make another "IAttack::SetTower(Tower& tower)"-method and create a attacker-instance per tower.




#5177212 How to organize your code and design your system

Posted by Juliean on 31 August 2014 - 08:44 AM


I usually find overlapping or ambiguous place. Like, when I want to move a character on the map, logically it should be a function in the game engine, which take a character model and move it inside the map model, right? But then it feel like everything else fall into the game engine: changing turn, deciding which action is allowed, calculating damage, etc. and the game engine as I call it ends up being too large, and should be split into smaller parts. So I stuck there, at that point, don't know how do I break that game engine into smaller parts.

 

I think you have to ease up your thinking. Why does the game engine have to move the character? In a simple system, why can't the character move itself? Why does it have to be moved inside the map "model"? Can't the "map" just have a list of characters and display them at their position?

 

Also one very cheap technique for seperating logic, if you feel your game engine is getting too heavy, is to just split it into different classes that you compose the game engine of

class GameEngine
{
	// theres like 50 of these
	void DoPhysicsStuff(void);
	
	// another 30 of those
	void DoRenderStuff(void);
}


class PhysicsModule
{
	// theres your 50 physics-methods
	void DoStuff(void);
}

class RenderModule
{
	// here are the 30 render methods
	void DoStuff(void);
}


// now you can compose the engine:

class GameEngine
{
private:
		
	PhysicsModule physics;
	RenderModule render;
}

The engine class in this example can still handle all the connections, like passing the world-state to the renderer & physics-module, but at least now its logically seperated. In case you have been using the GameEngine-class in your other code to call specific methods, you can now make getter-functions for the different modules. Then you can do this:

// thats how it would have looked like

void PhysicsDebugDisplay(GameEngine& engine)
{
        auto& vBodies = engine.GetBodies();

        // ...
}

PhysicsDebugDisplay(engine);

// thats how you can change it

void PhysicsDebugDisplay(PhysicsModule& physics)
{
      auto& vBodies = phyics.GetBodies();

      // ...
}


auto& physics = engine.GetPhysics();
PhysicsDebugDisplay(physics);

Now you can write your code depending only on the modules, not the whole engine. If you ever remove the engine or find a better structure, this code will go unnotified of.




#5175219 Destructor in vector called too often

Posted by Juliean on 21 August 2014 - 03:52 AM


Just a thought, but try changing the optimization settings. At work we've found some bugs in GCC (reported) using -O3 and had to manually add the flags -O3 adds minus the one that was causing the issue.

 

You where right. Totally doesn't happen in release mode. So now all I have to do is find the relevant setting and report it to microsoft. I quess I'll just #ifdef the nullptr-set for debug mode until they fix it, but its really something that shouldn't be happending.

 

EDIT: Ok, now it isn't happening at all anymore. Appears he just didn't compile after starting VS with the update 3, quess it was fixed in one of the updates. Going to confirm this on my home-PC, but I'm optimistic (even though I swear I was on the most recent update, weird). Thanks all for the help though!




#5174723 So... C++14 is done :O

Posted by Juliean on 19 August 2014 - 08:00 AM


That's the problem. The compiler will deduce what the type should be, and so you lose compile time checks of type-mismatches. The programmer will never get compilation error, even in cases where the behavior changed significantly.

 

Its really half-bad. The programmer will get a compilation-error in case:

 

- He passes the "auto" variable to any non-template function that doesn't take it as an argument.

- He calls any method on the "auto" variable that its real type does not understand.

- Does pretty much everything else with the variable that requires a certain type other than what the "auto" variable really has.

 

If two classes have the same method-signature in their public interface:

class MyString
{
public:
     const char* GetChars(void) cons
     {
         return m_pChars;
     }

private:
     char* m_pChars;
}

class YourString
{
public:
     const char* GetChars(void) const
     {
         return m_chars.GetData(); // don't recall how to get unique_ptrs data correctly, you get the idea
     }

private:

     std::unique_ptr<char> m_chars;
}

class ThirPartyString
{
public:
const StringView* get_string_view(void) const
{
return StringView(m_pChars);
}

private:

char* m_pChars;
}

// might change this method to "YourString" or "ThirdPartyString"
MyString createString(const char* str)
{
    return MyString(str);
}

// in code
const auto& string = createString("Test"); // will still compile

std::cout << string.GetChars(); // also compiles for "YourString", and why not, it works
                                // "ThirdPartyString" will obviously generate a compiler error, since it doesn't have a GetChars-method

which shouldn't even happen in practice, unless on purpose - then why should the caller code care for whether he calls "GetChars" on Type "MyString" or "YourString"? The caller shouldn't have to bother about the implementation of the class, but the interface. So unless the other class e.g. returns a new pointer to a char-pointer that must be cleaned up, usage will be no different (and that would be crazy on its own) - and whether auto or not, you don't get a compliation error anyways. In the former cases I listed, you get an error regardeless - its not in the assignment to the variable but in the call, but compile-time safe nevertheless. I would even go as far as to say that auto makes for a better type-safety than without - because now you have "interface"-typesafety instead of "implementation"-type-safety, which makes the code potentially more flexible.




#5174680 So... C++14 is done :O

Posted by Juliean on 19 August 2014 - 05:13 AM


Why would you use any of those examples when the idiomatic version from the past 2 or 3 decades still works, is understood by everyone, and generates the same ASM? laugh.png

 

Lots of things from the past still works, which still doesn't mean its the most optimal way of doing things. One can still send letters for written communication, but using online services is just a tad bit quicker ;)

 

Also while probably most people understand the old version, doesn't mean its easy to read. In fact, let alone the different variants, like having to explicitely store the end-condition and post/pre-increment validates a fixed solution for me.

 

More prone to error comes to mind, too. Especially for nested loops. Have lost count of how many times I mistakenly incremented the wrong variable or some stuff like that.

 

And as I already mentioned: Less code to type each time around - for the cost of what? That someone who hasn't seen this kind of loop might have to get used to reading it? From my personal view, the range-based loop is way easier to read, especially if you are new to the language - would anyone want to argue that a beginner would have an easier time with the old explicit loop?

 

Although generally, based on the old/new discussion, the question shouldn't be "what do I gain by using the new way" but rather "what do i lose by doing so?". People tend to favor that which they are used to, so unless there is a huge loss and virtually no gain for doing it with a new option, I'd say pick the new one.

 

EDIT:


nullptr is just about the only feature of C++11 I actually use (though I was fine with the plain-old NULL). Ctr delegation is also nice, but again - syntactic sugar.

 

Varadic templates are also very useful. Reduces code complexity on things like signal/slots, delegates etc... by a drastic amount, also allowing for perfect forwarding.




#5174644 So... C++14 is done :O

Posted by Juliean on 19 August 2014 - 02:35 AM


Range based loops, however, added nothing. The old method was still there, and it is still there. The result is that instead of the traditional 'minimalist' approach, there is duplication. It did not enable any new thing. It did not add a feature. It did not do something that could not be trivially done before. It obscures details, adds an additional interface, but doesn't add any functionality. It is syntactic sugar, it is language bloat.

 

Range-based for loops basically implemented for-each loops, which in my book is good enough to warrant it. In my personal opinion, I totally love them. Sure, you could possibly do the same thing with a macro before, but its much cleaner that way:

std::vector<Class*> vValues;

for(auto pValue : vValues)
{
    pValue->DoSomething();
}

for(auto itr = vValues.begin(); itr = vValues.end(); ++itr)
{
    (*itr)->DoSomething(); // i totally loved having to do that itr-dereferencing as well before on vector<pointer>
}

I see your argument about not implementing something totally new, but fail to see why this is a bad thing. Everything that allows you to write code faster and cleaner at the same time, while not being forced upon, is IMHO a decent thing. Why would anyone ever prefer to write the loop the second way (and thats the nice version already using "auto")? Unless you want to delete something from the loop, yeah, quess that counts.






PARTNERS