4
\$\begingroup\$

I am using Java and libgdx to create a game and have decided to go a data driven approaching with Jython for this refactoring (just picked up Jython, have used Java for a while). The game is a turn/tile based game where each ability will store prototype values and references to other scripts to actually execute the mechanics. I am hardcoding basic mechanics such as changing health, moving units between tiles, placing (de)buffs on units/tiles, and turn order. Everything else will be handled in softcode like deciding where to actually deal damage for aoe, how much damage to deal, what the buff behavior is, etc. I understand ideally I would script the entire game, except for things like rendering and I/O. But this is a solo project, and I don't really care.

Previously in development I hardcoded all the abilities. When an ability was casted it would call a function with the targeted tile and the entire gameboard. The function would then find the proper locations/objects on the gameboard and manipulate their state directly. However, I recognize this is terrible design. I figure some sort of API system would be better. But I am unsure how to design it.

  1. API gives references to the objects on gameboard and gamestate variables directly. Scripts can manipulate the objects. Seems straightforward, but unsafe with possible illegal operations like moving a piece to a location that does not exist. Scripts could also be written to error check, but that seems counter productive to the idea of scripting.
  2. APIs only give values of objects and gamestates. This may cause the script to need many variables that are normally grouped into one object, or to reconstruct the object. Also API could pass a purely data object. API calls are then also used back to the hardcode to manipulate the object. Safer as hardcode could easier contain illegal operation checking and debugging. But I guess I should learn debugging in Jython also. Also seems like a high memory overhead and extra API calls.
  3. A mix of 1 and 2. The APIs give scripts references to the objects directly, but the scripts can only get data out of the objects. Any manipulation must be done through an API call. So scripts could use getHealth(), but not setHealth(var). I have no idea of this is even possible. I like this solution the best, but it seems a little convoluted.
\$\endgroup\$

1 Answer 1

2
+100
\$\begingroup\$

Part of this answer is going to depend on the specific scripting language and implementation. Passing objects vs values can have different performance characteristics for different languages and which you choose may well depend on your scripting language. I don't know Jython personally but if in doubt you can perform tests to see if there is any significant issue either way.

Assuming performance is similar between both, focus on what makes things easier to develop with. If you strongly prefer a procedural-style interface, use that. Java and Jython are ideally setup for an object-oriented interface, however, and you may find it more natural to use that.

Usually with most scripting systems you explicitly choose which methods are exported so you can ensure that "unsafe" methods are not available to scripts. If this isn't possible with Jython, one option may be to use wrapper/proxy objects that are exported to the script which offer only the methods you want the script to have (and may offer additional convenience methods the "real" object does not). There may be significant overhead to this approach; again, something you need to test with your specific implementation and needs. Using a procedural API as in your option 3 may be the easiest way to efficiently allow restricted access to objects.

I would note that in many cases you might want to just ignore the "unsafe" aspects. The scripting language may have full access to Java's state anyway. Modders can typically modify Java bytecode relatively easily, too. Focus on ease of use, not safety. If you're worried that some method exposed might be dangerous then at the very least name it appropriately. It's not uncommon to have something like set vs set_unsafe with the former doing checks and raising errors while the later does not.

Yet another (far more complicated) option is to use a more tailored scripting system. General-purpose scripting languages are powerful and easy to integrate but often are a poor match for what game logic really needs. An event-driven game language or a declarative language may make what you're trying to do much easier.

If you're aiming for a very data-driven system then one might note that simply moving code from one procedural/OOP language to another does not make it any more or less data-driven. Whether or not you even need a scripting language when you're already working in a high-level language like Java is not a foregone conclusion. Your statement that ideally you would script the entire game is not necessarily all that ideal; scripts (especially ones in dynamic languages) can be a huge source of hard-to-debug issues. There are some native-code games that have actually used Java as their scripting language.

My recommendation would be to just expose your objects to Jython as-is and not worry so much about distrusting your script code. Keep the script code limited to high-level game logic and event handling.

\$\endgroup\$
1
  • \$\begingroup\$ I can't believe this question is already 6 months old. I have changed my set-up so much since then. In case you were curious, since its a solo project I have dropped scripting all together. Too much work for not enough return. Now I just inherent a base entity object that holds various components. Instead of manipulating the components directly, the entity holds a ton of convenience functions that access the components and act as API functions for the subclass. \$\endgroup\$
    – mobo
    Commented Nov 30, 2013 at 21:57

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .