pouët.net

Game logic and software engineering principles.

category: code [glöplog]
 
Hey all,

I've started working on my fourth or fifth smaller game production. For the first ones, I've been coding with a very compact and expressive coding style, where I could get to do a lot in a few lines of code.

The problem has been, however, that I tend to mix different levels of abstraction in the same functions / classes, which tends to hurt interpretability. I've started to care a lot about writing solid code, and less about being "smart" about the way I write it.

I work with games in Unity3D, Android and Objective C, and I would very much like to reach a point where I can split my code into a MVC kind of thing.

When it comes to pure game logic, I'm becoming more and more fond of state machines (Inspired by Play Maker). I'd like to have one state machine for each "concept" in our game. For example: Audio, the monster that chases you, the overall state of the game, your current spot in the story, and so on. Then I'd like to hook them up with "signals" that I can send among them (events, delegates, function calls, whatever). On top of that, I'd like to write my game logic so that it ports straight between C#, Java, and Objective C (lots of switch statements), and then I can defer higher level concepts (audio) to native code and API calls.


SO ANYWAY, that's just my thought process right now... Seeing that there are some people on pouët who have been part of coding AAA titles, how did you approach your game logic and core concepts from a software engineering point of view? What worked for you? FSMs, something with a more mixed level of abstraction that seemed more natural to your game engine/environment?
[/quote]I'd like to write my game logic so that it ports straight between C#, Java, and Objective C (lots of switch statements)[/quote]

I'm not really getting this part. Unity is quite cross platform already, and if you do need to do specific stuff for a specific platform (which of course des happen), you can do the following:

- create a common interface, and implement interfaces for each platform.
- maybe even create a "handler" that handles whatever you need to have done on the specific platform, and let the handler select which implementation of the inferfae to use
- use preprocessor tags for encapsulating platform specific code - better than switches, and shouldn't give you problem, when changing the platform in Unity.

The above is based on calling native (iOS and/or Android) functions and classes that are either in the general API or that you have put in the Assets/Plugins/<platform> folder.
added on the 2013-07-09 12:24:33 by Puryx Puryx
Oh, sorry, I was unclear. What I meant was, that since all the languages (C#, Java and Objective C) are heavily inspired by C's syntax, then I should be able to code my game logic with a common subset of all those languages, so that I can port it directly, in order to improve consitency. This means that I won't be using C#'s yield statement to code state machines, though it often feels very natural to do.

We're doing a game which is supposed to run in the background of the phone, so that rules out pure Unity3D solutions :(. Wish there was a way to call the game loop from the background while sound is running.
That sounds quite awkward. I've mostly written my commercial AAA game logic code with C++ and #ifdef PLATFORM_PS3-kind of preprocessor tags if necessary, just like Puryx suggests.

I am not quite sure what you mean by game logic (do you mean the general engine, or just the gameplay code?), but would something like writing it into a library with pure C work, or using an interpreted language like Lua or Python or Javascript? I don't see a single sourcebase compiling into Java, C# and native code as anything but trouble. You might get away with generating the code from a common root in C or whatever (I've worked with a tool like that once), but that approach brings its own problems and is a lot of work.
added on the 2013-07-09 14:11:40 by Preacher Preacher
Ah of course we should use LUA! I didn't even think of that :-).

I'm talking about gameplay code when I mean gameplay logic. We're doing a game that doesn't require realtime graphics, it's mostly just sound and external user input. I just need a few hooks for sound, time, and external input, and that's all :). It will be pretty straight forward to write LUA bindings for it, I guess, as soon as we have something that works for Android and iOS (any suggestions?).
This sounds like something where you do not want to use Unity3D at all. Android can handle c-libraries, and so can iOS, so it might be possible to store some of your not-platform specific code (game logic code?) in c-libraries.
added on the 2013-07-09 14:59:24 by Puryx Puryx
We're dealing with pretty similar issues at our company, too. We're thinking about using REST style API as interface between the business logics (in your case game logics) and the platform dependent back end. the platform specific layer must be kept as thin as possible and be define a common interface between all platforms available. by REST style i don't mean to run an HTTP server on the phone and send requests to that but calling functions by there name and a set of parameters. This way it is possible to abstract from any native back end implementation except for the one calling mechanism.
added on the 2013-07-09 16:03:58 by skomp skomp
That's not REST, it's RPC. But other than that it's a good idea. :)
added on the 2013-07-09 17:49:11 by kb_ kb_
depends on the general functions you implement ;). for us it's caching database access, so it's basically rest implementing GET POST PUT and DELETE, thus RESTful. others, like in this case game developers, might want to do implement different functionality, for instance for registering callbacks to be able to handle user input. The inspiration from rest was basically: keep the state in the game logics and have a uniform interface between platform code and non platform code. also treating everything as resource is actually not the worst to do.
added on the 2013-07-09 18:24:17 by skomp skomp
Ah, yeah, and before you throw that at me kb_ ;) I'm aware that implementing GET POST PUT and DELETE is not defining REST.
added on the 2013-07-09 18:25:42 by skomp skomp
Man, for the matter of portability, I just decided to use C/C++. In my point of view, it's the most market indepent language. So take some time, write some portable code, abstract what you can and that's it: Write once and for all.

About the game logic, I am taking lots of readings and thinkings about it too and I can't really give you any good advice now. So, good luck! :)
added on the 2013-07-12 05:05:36 by Danguafer Danguafer
i;m not in the same field but i write commercial software and device drivers. low level, reused stuff as you say is best in C with as simple as possible API.

i'm a huge fan of having a function hit repeatedly 100s of times (not per second, just in general) rather than having something thats called once in a blue moon.

i've also started designing things in a "state machine" fashion, I think it really does help me to develop clean software.

my demoesque tinkerings at home are in pure c, with as much code reuse as possible. I try to think "helper functions" or "helper libraries" instead of "engine". helps keep things that don't need to be connected separated.
added on the 2013-07-12 15:13:15 by Canopy Canopy
As was said, this all sounds like an awkward experiment rather than a sound approach.

Abstract your platform dependent functionality (file system, rendering, audio, input, anything OS/HW dep. basically) through interfaces (or a "common API" if you will). Defer any exotic language use down to the platform implementation (e.g. building an app. outer shell in a bit of ObjC for iOS stuff).

Write the common part in C/CPP or whatever your main language is. Make distinctions in there based on compile time platform flags and whatever else may make sense, but keep it to a practical minimum. Perhaps defer higher level logic to a scripted language (thereby possibly making it data) like LUA.

Lastly data. Author in raw/high quality formats. Use a tool (will become a toolchain over time) to convert them into binary blobs, preprocessed by a converter that readies them for the platform backend you've written for that particular platform (e.g. convert a huge PSD into a block of memory more or less directly loadable texture, ideally just memcpy()'d to catch my drift). Common runtime handles them as opaques, platform impl. knows what to do with it. Make a distinction between this and common data, though outside of script and a few other things there really shouldn't be much of that.

Pack data in bundles or whatever granularity makes sense (this will be different for minigames, streaming worlds, purely level based stuff et cetera).

bla bla bla bla
need coffee. incoherent.
added on the 2013-07-13 13:14:45 by superplek superplek

login