Programming is proceeding apace on it, but I've recently been doing a bit of thinking about what people might actually want from it. Only some of this is programmed, and it's all able to be changed, so what I'm after is comments - from people who can conceive of using an isometric engine - as to whether this would meet your needs.
As per Py'Tom's excellent suggestion, I'm splitting the engine into two parts: a Tile Engine, which does things like display the map and sprites, let the user scroll around, and so on; and a Unit Engine on top of the Tile Engine, which does things like remove sprites when the unit's HP hits zero, make it cost movement points to move units around the map, and so on.
My aims / requirements for the Tile Engine are:
- It should integrate with Ren'Py, to allow Ren'Py commands or code without having to leave the isometric view.
- It should be usable for a few different types of game:
- A variety of types of turn-based combat games. That's what rocket and I are going to be using it for ^.^
- An RPG-style "map screen", either of a continent or of a village, triggering VN-style segments of Ren'Py when the user guides the character to certain regions, without any attacks or considerations of "movement points".
- Hopefully, quite a number of other possible isometric games like puzzle games.
- It will support commands to move sprites around on an isometric landscape. These commands will be usable both by the Game System and by the user, to do things like cutscenes.
- It'll be fairly object-oriented.
- I'm making no promises about any form of 3D, either layered or heightmaps. It's a possibility for a Version 2 feature. Current plans are just for a flat isometric plain.
- I won't be making any provision for real-time (time-sensitive) movement. I might not even code anything explicitly to let multiple units move at once, although that would probably be a straightforward customisation for someone to do if they were interested.
- Unless I can make use of the PGU level editor and tile editor, there won't be any kind of graphical "level editor" for designing maps, or indeed units. You're going to have to edit the text files.
- It should let the user store information about units: default values will include Name, HP, and so on, but others can be added too.
- It will support TBS games using either of the two models that I call MP and AP. (MP means each unit gets one move and one attack per turn, although units may have varying distances they can move, determined by Movement Points. AP means each unit has a number of Action Points, and can spend them doing any combination of attacks, moves, or whatever else is possible.)
- The user should be able to create a pretty basic TBS combat fairly simply.
- It should provide some basic form of difficulty scaling, as per Ignosco's request below.
- I'll be providing some form of AI. But it may not be very good, and may be specific to the MP model. If the user wants better AI, they can provide a function that'll get called when a computer-controlled unit gets a turn.
So, consistent with those requirements, an overview of my planned feature specification for the Tile Engine is as follows:
- The user will define one or more maps, in a python block in an .rpy file in their game.
- The map will be displayed and the player can scroll around it.
- The user can show sprites on the screen, with a sensible zorder default (on top of the map but otherwise ordered by screen y).
- It will offer some default overlay views, such as a minimap, and a view of the current unit's name, HP/MaxHP, and so on. These can be customised, either by a set of flags to turn on/off different lines of the view, or as a custom overlay function (which will just be in the form of a standard config.overlay_functions.append() call).
- The user can specify units for the player and the enemy.
- The user can define a list of actions to offer to the player for each unit, apart from moving. (Like "Attack", "Use potion", or whatever.)
- They can specify custom functions to be called on events like: player selects move mode, player moves a unit to a square, player takes an action, enemy unit takes a hit, player unit takes a hit. These can be used, for example, to trigger events when the player moves to a particular region of the map. I'll supply some examples.
- It'll provide functions to move units around the map, which will be thin wrappers around the corresponding sprite movement functions in the Tile Engine. The user can script cutscenes by calling these functions in sequence from within their Ren'Py code.
- The user can get a "map screen mode" by just giving the player one unit, with no attacks, and setting movement cost to zero. This would be used in conjunction with a function triggered on the player moving a unit.
Maps are defined as a two-dimensional array (well, an array of arrays), each element being a struct object with user-settable fields. I include an example file that shows how I'm currently defining the map and the units. Note that the types of terrain are defined beforehand, and then copied for each square of the map.
The Tile Engine will be created from the map. It will provide a number of useful fields, like these:
Code: Select all
python:
e = TileEngine(map, tileheight, tilewidth)
e.tileheight, e.tileheight # the full width and height of one tile, in pixels, as supplied
e.screenheight, e.screenwidth # pixel width and height of the viewport, in pixels
e.gxmax, e.gymax # size of the map in tiles
e.Cursor.pos # the coordinates of the square the user's cursor is on
# e.view.gx, e.view.gy # offset of the map - not so easy to get
Code: Select all
spriteObj = e.showSprite(spritename, gridx, gridy)
The Unit Engine also provides some useful fields:
Code: Select all
g.SelectedUnit # the unit that the user has selected to view details of or to issue commands to
g.Mode # Will be equal to one of the constants g.NOSELECTION, g.UNITSELECTED, g.MOVEMODE, g.ACTMODE, g.ENDOFTURN, g.VICTORY, g.DEFEAT, or a custom user mode
g.Callbacks.ModeChange, g.Callbacks.UnitMoves, g.Callbacks.UnitActs # functions that you can assign to; if not at their default value of None, will get called every time the appropriate action happens
Code: Select all
Comtron1 = Unit(
Name = "Comtron 3VT 1",
Sprite = "lightbot", # tag for images
MaxHP = 50,
MaxMP = 10, # or MaxAP
DirectionFacing = DIR_NW, # I provide these eight constants as well as DIR_NEUTRAL
Pos = (8, 8), # Define initial position here or later
CanMove = True, # These two fields will be filled in automatically if not specified
CanAct = True, # After this point you can add any game-specific fields, for example:
Weapons = [ RIFLE ],
SelectedWeapon = RIFLE,
Controller = AYAKA,
Weight = LIGHT,
VisibleByAllies = [ ],
VisibleByEnemies = [ ]
)
Regions that trigger events can be implemented in ways like this:
Code: Select all
python:
g.Callbacks.UnitMoves = checkregions
label checkregions:
# the full doc will clarify that the details are passed in Selected.Unit, g.CallbackData.
if abs(g.SelectedUnit.X - Witch.X) < 2 and abs(gSelectedUnit.Y - Witch.Y) < 2:
e "She smells terrible..."
if gSelectedUnit.X in range(10,20) and g.SelectedUnit.Y > 30:
call SeeValleyForFirstTime
return
Code: Select all
g.Config.ShowMinimapOverlay = False
g.Config.ShowUnitOverlay = True
g.Config.UnitOverlay.ShowUnitMP = False
g.Config.UnitOverlay.ShowUnitWeapons = False
# ...etc
Code: Select all
# Inside user Ren'Py code
label event_triggered: # this label might be called from an if block inside your checkregions label
$ g.CentreViewOn((15,8))
$ Witch.MoveToSquare((15,5))
witch "So, you've come to see me! I knew you would, you know."
play sound cackle
$ Player.MoveToSquare((15,4))
$ Player.DirectionFacing = DIR_N
# and so on