• Advertisement
Sign in to follow this  

C++ Gameplay in C++

Recommended Posts

Who writes gameplay in C++?

I recently wrote an article in codeproject which describes some benefits of this (from a more general purpose perspective), but I'm curious for other thoughts on the subject.

If you write engine code in C++ but the gameplay in another language, what made you take this decision?

If you do write gameplay in C++, are you happy with your decision? Share some cool stories about it.

Bonus points if you write gameplay code in C++ and engine code in another language :D 

Share this post


Link to post
Share on other sites
Advertisement
7 hours ago, Bleys said:

Who writes gameplay in C++?

Unreal Engine, for one.

 

Also, moving to the Lounge.

Share this post


Link to post
Share on other sites

In my experience, the most common reason to write gameplay code in C++ is that you already have an engine or base framework in C++ and don't want to deal with another language.

Even if you have a well-working scripting layer, there is power and convenience in being able to write and debug the whole game from top to bottom using just a C++ IDE.

This is of course not just the case with C++ but with any language.

Share this post


Link to post
Share on other sites

I write my game code in C++, engine is also C++.   If I need to allow scripting outside of IDE then I'd also still use C++ with something like Runtime Compiled C++.   

If your scripting is being done totally in-house, then I dont see much benefit of a non-engine language for the gameplay code.  You're just creating more complexity, less performance, more difficulty in maintenance, debugging, and optimization, and basically separating your programmers into two groups that will generally not interact or understand each other much of the time.

Share this post


Link to post
Share on other sites
2 hours ago, 0r0d said:

If your scripting is being done totally in-house, then I dont see much benefit of a non-engine language for the gameplay code.  You're just creating more complexity, less performance, more difficulty in maintenance, debugging, and optimization, and basically separating your programmers into two groups that will generally not interact or understand each other much of the time.

The last big developer that I worked for did engine in C++, tools / data compilers in C#, and gameplay in Lua and C++. 

Lua and C# were used because they're more productive languages. Code is less complex than equivalent C++ translations, which makes maintenance easier and development/debugging quicker. Moreover different paradigms/features are available, such as duck typing, garbage collection,  mixins or the prototype pattern. Things that require silly/complex "component frameworks" in C++ can just be don't out of the box in Lua. Things like reference counting and weak pointers don't require a library :)

Most gameplay code isn't performance sensitive, but the bits that show up on the profiler would be ported to C++ and given some love. All the programmers are C++ coders who are taught Lua - you wouldn't bother hiring a Lua-only coder for a programmer's role. 

 

In my current game, we do most of the gameplay in C++, but pulling all tweakables/configuration data from Lua. Lua can be used to configure the game at a high level (plugging different components/systems together) and then the real frame-to-frame logic happens in C++. This gives us a lot of flexibility that you could get from something like ECS, without having to actually make a C++ component framework.

C++ is an extremely dangerous language though, and has to be written with care. The more projects I ship, the more I come to fear C++ for its ability to create extremely subtle yet extremely dangerous bugs, mostly revolving around memory management :( So, we use a lot of discipline around pointers to help mitigate these risks, such as templates that: tag raw pointers with ownership semantics (and do leak checks in dev builds), tag pointers with array semantics (and do range checks in dev builds), zero initialise pointers (and do uninitiated read checks in dev builds), etc, etc... We also use scope-stack allocations for most things rather than heap allocations to make leaks impossible at a semantic level. 

Share this post


Link to post
Share on other sites
38 minutes ago, Hodgman said:

The last big developer that I worked for did engine in C++, tools / data compilers in C#, and gameplay in Lua and C++. 

Lua and C# were used because they're more productive languages. Code is less complex than equivalent C++ translations, which makes maintenance easier and development/debugging quicker. Moreover different paradigms/features are available, such as duck typing, garbage collection,  mixins or the prototype pattern. Things that require silly/complex "component frameworks" in C++ can just be don't out of the box in Lua. Things like reference counting and weak pointers don't require a library :)

 

The last big developer I worked for did the engine in C++ and "gameplay" in Lua, and it was a nightmare and pretty much the opposite of what you just described.  The Lua code was crap, it was hard to write so that it wasnt full of bugs, it was slow and constantly had to be ported to C++, it was difficult to maintain or even understand what it was doing, and pretty much abused at every possible opportunity.  At one point the debugger we were using stopped working because of conflicts with how the project worked (dont ask me, I'm still not sure what the problem was) and from that point on debugging amounted to using logging to find the problems.  Awesome!  The entire project would have finished with better performance, better overall code quality, happier engineers, and way faster if all that code had been C++ instead of Lua... or at least a better scripting language.

I would never willingly volunteer to ever work on Lua code again.  Yes it's easy to write the code, but it will be shit code and some obvious bugs (like, you misspelled a variable) will only show up later when that code runs, and god help you if the first time it runs is after the game ships and that code path was never tested during development.  

Most gameplay code isn't performance sensitive, but the bits that show up on the profiler would be ported to C++ and given some love. All the programmers are C++ coders who are taught Lua - you wouldn't bother hiring a Lua-only coder for a programmer's role. 

 

If you're counting on re-writing code to C++ later, that automatically kills some of the productivity gains you think Lua gave you.  Training programmer... more productivity loss.  Then you lose additional productivity debugging code across the gameplay-engine interface, or just general debugging because honestly debugging Lua code sucks bigtime.  And if you're relying on the Lua code to not be performance sensitive, then I hope you're enforcing that very strictly.  That project I was on didnt and the result was that all the high level code, as well as most of the low level code, was all done in Lua.  Oh, joy!  I wish I could get back the months of my life I wasted learning, debugging, re-writing, optimizing, and porting shitty Lua code.

Hey, if someone out there actually likes writing Lua code, awesome for them.  Go to it.  But, I would only force someone I really hated to work on Lua.

Share this post


Link to post
Share on other sites
9 hours ago, 0r0d said:

The last big developer I worked for did the engine in C++ and "gameplay" in Lua, and it was a nightmare and pretty much the opposite of what you just described.

Hah, sorry for your dev-hell :(

I'd be interested to know their setup though. It sounds like whoever made that decision at this company didn't bother to flesh out the workflow and forced a terrible mess onto everyone ;(

I'd think that C was horrible if the coding environment consisted of notepad and mingw too! 

We had an IDE with full debugging (line by line stepping, locals, auto, watches, breakpoints, etc), visual studio integration, hot reloading of code, assertions with cross Lua/C call stacks, etc. Often if you hit a bug, you'd fix it while the game was still in the background, reload the code and continue running from the failed call. 

To avoid mis-naming bugs, you can modify the global-variable table to assert on writes, and should also use a good linter to catch them during compile time (most typos like that would fail the build for us, not be lurking timebombs waiting to fail at runtime). The same features that let you do breakpoints also let you collect code coverage stats, so you can tell if you're shipping code that's never been tested.

On top of that, our build server would build/lint your code, and run it on every platform with AI players to test for bugs, BEFORE allowing it to be committed to the master branch. It was pretty hard to break the build with obviously broken C++ or Lua code :)

Off the shelf C++/Lua bindings are pretty sucky, and yeah it did take us a few iterations to make our own that didn't suck, but binding is simple for us now and doesn't cause any issues. 

The vanilla VM is pretty slow (but still super fast compared to other scripting languages), so we used LuaJIT instead. On PC it's got great performance, and on console where JITing is banned, it's still 2x faster than vanilla Lua even with JIT compilation disabled. AFAIK we did have to sponsor the LuaJIT dev into supporting PPC and x64 CPUs though. We did a shitload of math in Lua and usually the only things that need to be ported are enginey-type systems, such as animation controllers, intense AI internals, etc, or stuff where you're doing math on a huge embarrassingly parallel dataset and the SIMD/threading benefits are obvious. Usually these kinds of systems were a natural fit for engine land anyway, so we ended up with a pretty natural C++ systems / Lua rules fit. 

This is off topic though - so to bring it back around, I still write C++ gameplay on my current project because I'm comfortable with it!  :DWe also use a 600Hz fixed update rate for accurate simulation on this project so I'm pretty performance sensitive... 

Another story - at the company before that one, we wrote the gameplay in C++, but the engine was mandated to have a C interface to force simplicity. Some of the engine used C++ internally in some modules, but still hid it behind a C API. The game would often then wrap up those simple C APIs in more C++ code to make them easier to use!! 

Share this post


Link to post
Share on other sites
14 hours ago, 0r0d said:

The last big developer I worked for did the engine in C++ and "gameplay" in Lua, and it was a nightmare and pretty much the opposite of what you just described.  The Lua code was crap, it was hard to write so that it wasnt full of bugs, it was slow and constantly had to be ported to C++, it was difficult to maintain or even understand what it was doing, and pretty much abused at every possible opportunity.  At one point the debugger we were using stopped working because of conflicts with how the project worked (dont ask me, I'm still not sure what the problem was) and from that point on debugging amounted to using logging to find the problems.  Awesome!  The entire project would have finished with better performance, better overall code quality, happier engineers, and way faster if all that code had been C++ instead of Lua... or at least a better scripting language.

This is not too dissimilar from my own experience, actually. Better tooling would have made things a lot more manageable. So far as I'm aware, nobody had any kind of debugger available, and because of the way scripts were included in the content it was often impossible to even verify that the scripts compiled without booting up the game, never mind have working IntelliSense or refactoring tools or anything nice like that. We couldn't even do "go to definition" or the like - there wasn't any kind of unified "Lua project" where we could trace where particular symbols were defined, and different Lua files got used in different scenarios so it was a matter of searching through ALL Lua scripts for the symbol you wanted, then guessing which one was the one that would actually get used at the point where you were going to use it.

Our workflow basically boiled down to "write some Lua in a text editor, start the game, see if it worked (it probably didn't).  Writing actual gameplay code in C++ was much smoother, despite long compile times and... well, C++.

Investing in workflow and tooling is a must if you're going to use any kind of scripting language. What I take from this is that if you don't have (or your higher-ups aren't willing to put in) the resources to do that, I'd say it's better to not introduce extra languages, as they're another platform you have to support and if you're going to support something, you should support it properly. At the very least, make sure you have a debugger that works and code is searchable. If your scripting system forces me to rely on printf debugging or putting breakpoints in the C++ that is called by the scripting system, I'm going to be inclined to go back to C++ and my nice Visual Studio debugger. :P

Edited by Oberon_Command

Share this post


Link to post
Share on other sites

I wrote my first game in C++. It is called Bluejay's Quest. It is right here: https://sourceforge.net/projects/bluejay-quest/
This game is the first real project that I completed from start to end. I created it in C++ instead of Java or Python because of concerns of speed. At the time C++ was probably the best way to go if you wanted something that wouldn't lag or something like that but I think I was too paranoid. Anyways, the other reason I used C++ in this case was because it was the language that I know best at the time and Java had it's issues with being ported to Linux. I wanted something that was standalone - no need to download runtime which is just a bunch of BBQ sauce.

So with scripting I had a plan and that plan became Platformisis. Platformisis is a game maker that I wrote in JavaScript so that it can run in the web browser but the original version, which was never created, was supposed to be done in C++. That is, I was to code the engine, I/O module, editors, and scripting engine in C++. This was to be full independent C++ which would even encapsulate any library I was to use so that it could be ported out to any device. Yep, it was going to be exciting but I chose JavaScript instead. So to continue with the story if I were to have built this thing I would have implemented a scripting language called C-Lesh which would talk to the engine and the I/O via the memory mapper. That can be found here: http://www.codeloader.net/readme.html Well, it's a description and tutorial of the language.

Currently, I am creating an interpreter for the C-Lesh language in C++ because C++ is fast and because C++ is a bit too bare for me. The thing about C++ is it's incredible portability. People are always talking about how Java and other stuff is super portable but (this is an important point) I say that's a crock. C++ is probably the most portable language because my different compilers have been written for various architectures and C++ has been strong for a while and it's is nothing but C with added stuff. C is ancient and is better than Basic and Fortran because I said so. But the point is portability potentially allows me to port my interpreter to any device and, thus ditch C++ for gaming. Don't get me wrong, I don't give a bucket of fried chicken or a bottle of BBQ sauce about C++ because I believe it sucks and I maintain that - end of argument but, anyways, it's portability rules and now I will create games in C-Lesh because it is everything that I want in a language.

That's my story, anyways. Just in case you're wondering I am programming Bluejay's Quest (again) in C-Lesh and under the game maker Platformisis.

Nah, this project is good experience. No one can question that.

Edited by francoisdiy

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this  

  • Advertisement
  • Advertisement
  • Popular Tags

  • Advertisement
  • Popular Now

  • Similar Content

    • By francoisdiy
      So I wrote a programming language called C-Lesh to program games for my game maker Platformisis. It is a scripting language which tiles into the JavaScript game engine via a memory mapper using memory mapped I/O. Currently, I am porting the language as a standalone interpreter to be able to run on the PC and possibly other devices excluding the phone. The interpreter is being written in C++ so for those of you who are C++ fans you can see the different components implemented. Some background of the language and how to program in C-Lesh can be found here:

      http://www.codeloader.net/readme.html
      As I program this thing I will post code from different components and explain.
    • By isu diss
      I'm trying to duplicate vertices using std::map to be used in a vertex buffer. I don't get the correct index buffer(myInds) or vertex buffer(myVerts). I can get the index array from FBX but it differs from what I get in the following std::map code. Any help is much appreciated.
      struct FBXVTX { XMFLOAT3 Position; XMFLOAT2 TextureCoord; XMFLOAT3 Normal; }; std::map< FBXVTX, int > myVertsMap; std::vector<FBXVTX> myVerts; std::vector<int> myInds; HRESULT FBXLoader::Open(HWND hWnd, char* Filename, bool UsePositionOnly) { HRESULT hr = S_OK; if (FBXM) { FBXIOS = FbxIOSettings::Create(FBXM, IOSROOT); FBXM->SetIOSettings(FBXIOS); FBXI = FbxImporter::Create(FBXM, ""); if (!(FBXI->Initialize(Filename, -1, FBXIOS))) { hr = E_FAIL; MessageBox(hWnd, (wchar_t*)FBXI->GetStatus().GetErrorString(), TEXT("ALM"), MB_OK); } FBXS = FbxScene::Create(FBXM, "REALMS"); if (!FBXS) { hr = E_FAIL; MessageBox(hWnd, TEXT("Failed to create the scene"), TEXT("ALM"), MB_OK); } if (!(FBXI->Import(FBXS))) { hr = E_FAIL; MessageBox(hWnd, TEXT("Failed to import fbx file content into the scene"), TEXT("ALM"), MB_OK); } FbxAxisSystem OurAxisSystem = FbxAxisSystem::DirectX; FbxAxisSystem SceneAxisSystem = FBXS->GetGlobalSettings().GetAxisSystem(); if(SceneAxisSystem != OurAxisSystem) { FbxAxisSystem::DirectX.ConvertScene(FBXS); } FbxSystemUnit SceneSystemUnit = FBXS->GetGlobalSettings().GetSystemUnit(); if( SceneSystemUnit.GetScaleFactor() != 1.0 ) { FbxSystemUnit::cm.ConvertScene( FBXS ); } if (FBXI) FBXI->Destroy(); FbxNode* MainNode = FBXS->GetRootNode(); int NumKids = MainNode->GetChildCount(); FbxNode* ChildNode = NULL; for (int i=0; i<NumKids; i++) { ChildNode = MainNode->GetChild(i); FbxNodeAttribute* NodeAttribute = ChildNode->GetNodeAttribute(); if (NodeAttribute->GetAttributeType() == FbxNodeAttribute::eMesh) { FbxMesh* Mesh = ChildNode->GetMesh(); if (UsePositionOnly) { NumVertices = Mesh->GetControlPointsCount();//number of vertices MyV = new XMFLOAT3[NumVertices]; for (DWORD j = 0; j < NumVertices; j++) { FbxVector4 Vertex = Mesh->GetControlPointAt(j);//Gets the control point at the specified index. MyV[j] = XMFLOAT3((float)Vertex.mData[0], (float)Vertex.mData[1], (float)Vertex.mData[2]); } NumIndices = Mesh->GetPolygonVertexCount();//number of indices MyI = (DWORD*)Mesh->GetPolygonVertices();//index array } else { FbxLayerElementArrayTemplate<FbxVector2>* uvVertices = NULL; Mesh->GetTextureUV(&uvVertices); int idx = 0; for (int i = 0; i < Mesh->GetPolygonCount(); i++)//polygon(=mostly triangle) count { for (int j = 0; j < Mesh->GetPolygonSize(i); j++)//retrieves number of vertices in a polygon { FBXVTX myVert; int p_index = 3*i+j; int t_index = Mesh->GetTextureUVIndex(i, j); FbxVector4 Vertex = Mesh->GetControlPointAt(p_index);//Gets the control point at the specified index. myVert.Position = XMFLOAT3((float)Vertex.mData[0], (float)Vertex.mData[1], (float)Vertex.mData[2]); FbxVector4 Normal; Mesh->GetPolygonVertexNormal(i, j, Normal); myVert.Normal = XMFLOAT3((float)Normal.mData[0], (float)Normal.mData[1], (float)Normal.mData[2]); FbxVector2 uv = uvVertices->GetAt(t_index); myVert.TextureCoord = XMFLOAT2((float)uv.mData[0], (float)uv.mData[1]); if ( myVertsMap.find( myVert ) != myVertsMap.end() ) myInds.push_back( myVertsMap[ myVert ]); else { myVertsMap.insert( std::pair<FBXVTX, int> (myVert, idx ) ); myVerts.push_back(myVert); myInds.push_back(idx); idx++; } } } } } } } else { hr = E_FAIL; MessageBox(hWnd, TEXT("Failed to create the FBX Manager"), TEXT("ALM"), MB_OK); } return hr; } bool operator < ( const FBXVTX &lValue, const FBXVTX &rValue) { if (lValue.Position.x != rValue.Position.x) return(lValue.Position.x < rValue.Position.x); if (lValue.Position.y != rValue.Position.y) return(lValue.Position.y < rValue.Position.y); if (lValue.Position.z != rValue.Position.z) return(lValue.Position.z < rValue.Position.z); if (lValue.TextureCoord.x != rValue.TextureCoord.x) return(lValue.TextureCoord.x < rValue.TextureCoord.x); if (lValue.TextureCoord.y != rValue.TextureCoord.y) return(lValue.TextureCoord.y < rValue.TextureCoord.y); if (lValue.Normal.x != rValue.Normal.x) return(lValue.Normal.x < rValue.Normal.x); if (lValue.Normal.y != rValue.Normal.y) return(lValue.Normal.y < rValue.Normal.y); return(lValue.Normal.z < rValue.Normal.z); }  
    • By Karol Plewa
      Hi, 
       
      I am working on a project where I'm trying to use Forward Plus Rendering on point lights. I have a simple reflective scene with many point lights moving around it. I am using effects file (.fx) to keep my shaders in one place. I am having a problem with Compute Shader code. I cannot get it to work properly and calculate the tiles and lighting properly. 
       
      Is there anyone that is wishing to help me set up my compute shader?
      Thank you in advance for any replies and interest!
    • By fishyperil
      I'm looking for some references that could help me learn how to program some really basic 2D enemy behaviours.
      I wasn't sure whether to post this here or in the AI section but I think it might be more suitable to be posted here since it has more to do with basic maths than any AI related algorithms.
      Could anyone help recommend some resources (books, posts, videos) that could help me understand how to properly implement the basics of enemy movement in 2d games ? So far I've only managed to get them to chase the player character and to stop moving on collision, but the movement is pretty unrealistic and once the collision occurs the enemies all "pile up" on the player character. I'm doing this in C++ so no guides that explain how to script this using an engine api please.
    • By Ovicior
      Hey,
      So I'm currently working on a rogue-like top-down game that features melee combat. Getting basic weapon stats like power, weight, and range is not a problem. I am, however, having a problem with coming up with a flexible and dynamic system to allow me to quickly create unique effects for the weapons. I want to essentially create a sort of API that is called when appropriate and gives whatever information is necessary (For example, I could opt to use methods called OnPlayerHit() or IfPlayerBleeding() to implement behavior for each weapon). The issue is, I've never actually made a system as flexible as this.
      My current idea is to make a base abstract weapon class, and then have calls to all the methods when appropriate in there (OnPlayerHit() would be called whenever the player's health is subtracted from, for example). This would involve creating a sub-class for every weapon type and overriding each method to make sure the behavior works appropriately. This does not feel very efficient or clean at all. I was thinking of using interfaces to allow for the implementation of whatever "event" is needed (such as having an interface for OnPlayerAttack(), which would force the creation of a method that is called whenever the player attacks something).
       
      Here's a couple unique weapon ideas I have:
      Explosion sword: Create explosion in attack direction.
      Cold sword: Chance to freeze enemies when they are hit.
      Electric sword: On attack, electricity chains damage to nearby enemies.
       
      I'm basically trying to create a sort of API that'll allow me to easily inherit from a base weapon class and add additional behaviors somehow. One thing to know is that I'm on Unity, and swapping the weapon object's weapon component whenever the weapon changes is not at all a good idea. I need some way to contain all this varying data in one Unity component that can contain a Weapon field to hold all this data. Any ideas?
       
      I'm currently considering having a WeaponController class that can contain a Weapon class, which calls all the methods I use to create unique effects in the weapon (Such as OnPlayerAttack()) when appropriate.
  • Advertisement