mspraggs / potentia

Southampton Game Jam 2015
0 stars 0 forks source link

Level Editor #93

Open DivFord opened 8 years ago

DivFord commented 8 years ago

I've been thinking about how to make the puzzles more… puzzling.

One thing that's come up is the idea of setting up interactions between specific props. For example, the gate prop comes with an assumption that some external factor causes it to open. This could be a key pickup, a lever, a pressure plate, etc., but we need some way of linking the two (I say "need", though we could potentially have non-unique keys, and just require the player to work out the right order to open the gates in).

The caves we discussed for the mole gauntlet would also benefit from linking.

Also, the proposed Wind Turbine prop is presumably powering something, so being able to link it to that thing would be useful.

I'm stuck on how this could actually be accomplished. Within a level, I can see matching codes being a viable option, but patterns couldn't work that way. Unless we prefix the codes with an identifier for the pattern? Any ideas?

Fyll commented 8 years ago

Actually, this may be a perfect opportunity to have someone write a level editor. If we had a level editor, rather than just two character codes for each thing, we could encode so much more information into each tile (e.g. a link between two things, a specific value for a variable (such as how long a tile might last for, if it's on a timer)).

Also, it'd just be nice, generally, to have some sort of level editor thing, come the later time when we're just adding content, rather than code.

I hate to say "this is a great thing that someone else should do!", but, I'm pretty busy with work (he says, procrastinating) and collisions, so someone else would have to do this if it were to be done.

DivFord commented 8 years ago

I'm happy to give it a shot, though Matt would no doubt do a better job of it.

If we do make a level editor, we should probably decide now how we want the data it outputs to be organized. It can't just churn out the same text files we've been using, or it wouldn't actually do the things you mentioned.

Fyll commented 8 years ago

Seeing as it's going to be completely separate, you don't have to use the same system (feel free to use Unity or whatever works. Or you could be cool like us cool kids and write it from scratch :P).

The two character codes work nicely for identifying each tile (will we want more later potentially?), but if we have complete freedom in code length, we could just always use the actual names of the things. Brackets are nice for grouping things, so I was picturing a tile (e.g. a Gate) being given by (prop, gate, keycode), where keycode would be some code that matches a (pickup, key, keycode) somewhere else. a generic stone tile could just be (block, stone) (trailing commas optional). The dimensions of the level would then be given at the start of the level, and Patterns could be done by (pattern, LR, 3, 4), for a left to right, 3x4 pattern (I don't actually know how that's stored or done at the moment...), with (none) in the empty spaces.

Alternatively, you could just have a list of things, and coordinates giving their positions inside the brackets. I should probably also mention now that (provided I don't scrap this collision stuff) I've added a new Object: BlockGroup. This groups identical Blocks together, so they don't have to have separate hitboxes, and importantly, it reduces the number of Objects in a level from, e.g. for the menu screen, ~70 to ~4. Unfortunately, this has added a bit of a wait to the level loading (as may be visible in the .gif) as it has to sort all of the Blocks into groups, one by one. It'd probably be nice if the output could have things pre-grouped, but the wait isn't that bad.

Thoughts?

DivFord commented 8 years ago

I had a think about this, and I reckon I will use Unity. That lets me get something cross-platform with a usable interface done pretty fast. Guess I'm just not cool enough…

I'm not sure we do have complete freedom. The longer the block identifiers are, the larger the level files are going to be. We should probably aim to keep them compact. Given that the level editor produces the files, and the game reads them, there's no need for them to be easily readable by a human.

Your suggestion is pretty close to what I thought of. I was thinking of something like "Pg(1)" for a gate prop with key code 1. Am I right in thinking that the block loading already works as a function call?

How do your block groups handle blocks that can change (eg. dirt, ice, water)?

EDIT: I'm quite keen not to be the one to implement the in-game level loading...

Fyll commented 8 years ago

Eh, level loading is Matt's area. :P

Even before I put in BlockGroup, changing Blocks simply deleted themselves, then added a new Block in the same place. The only difference now is that Room::addBlock() checks if the new Block fits into any existing BlockGroups, instead of just adding it to the vector.

DivFord commented 8 years ago

Ah, Ok. I'll see about grouping things in the level-file then.

While we're on the topic of pre-calculating things, I thought it might be worth putting the tool requirements at the start of the file, rather than in the filename.

DivFord commented 8 years ago

Going pretty well so far. I have a toolbox and a palette. I can draw, erase and flood-fill all the block types, and I can place all the props. Just about to add the inspector for changing prop data.

Couple of questions:

  1. I'm assuming we don't need meta-data for blocks. That is, key codes and linking seem to apply only to props. Is that correct?
  2. Do the block groups include all blocks of the same type, or only contiguous regions?
Fyll commented 8 years ago

1 - We might need info for things other than linking (e.g. lifetime for the crumbling blocks from #85). They might also want to store a list of which Blocks they can connect to.

2 - Only contiguous regions. That way they can share one hitbox defined by its border.

DivFord commented 8 years ago

Aren't the crumbling 'blocks' actually props? I feel like having blocks be things that tile, but don't have metadata, is probably a good definition. Obviously has nothing to do with the fact that I've already set the editor up that way :P Actually, now that I think about it, the block groups are another good reason not to have metadata on blocks. If we did, we'd need a different group whenever blocks had different metadata.

For my output format, I'm thinking of something like this:

<PROPERTIES>
Room; 20; 10; Generic; 1

<BLOCK GROUPS>
S (0,0) (1,0) (2,0) (2,1) (3,0); S (5,0) (5,1) (6,0); D (7,0) (8,0) (9,0);

<PROPS>
C (2,2); G (7,1,1);

<ENEMIES>
L (8,1);

<PICKUPS>
K (2,3,1);

<PATTERNS>
O3 (10,0)

First section is properties, listing data type (room or pattern), width, height, zone, and required tools bit mask (in this case, 1, i.e. cannon).

Next is block groups. Each group is given as a block identifier (eg. S = stone) followed by a series of coordinates.

Then we have props. Each prop is given as a prop identifier (eg. C = crate, G = gate), followed by coordinates (for the bottom-left of the prop, in the case of multi-tile props) and any metadata. In this case, crate has no metadata, while gate has the key code (1).

Enemies have the same thing. Identifier followed by coordinates. Not sure if they should have metadata.

Pickups follow the same format as props. In this case it's a key linked to the gate.

Patterns use the notation I laid out in the design docs, followed by the coordinates of the bottom-left of the pattern.

I'm using single letter codes to save memory, but the idea is that it could be any length of string (ends at the space). That way, if we need more codes, we can have them.

Entrance and exit must be in there somewhere. Do we want to continue treating them as blocks, or as a special case?

Fyll commented 8 years ago

The current distinction between Blocks and Props is only that Blocks tile and are massless at the moment (I think). It might actually be a nice idea in the long run to just cut the Blocks out altogether, and replace them with BlockGroups, seeing as BGs rely on Blocks obeying several very specific properties (such as being a 1x1 massless square).

While it is just asking for trouble, you could probably remove the "titles" for each chunk, and just have each new object type on a new line, provided that they are always in the same order (maybe given by the order in ObjectTypes?).

Seeing as the weapons have codes, you could use those instead of the numbers. Whichever's easiest to be honest, as readability isn't all that important.

The entrance and exit are treated as special cases in the code already, so I don't see how it could hurt.

I assume this is using the same resources as the game (e.g. the same spritesheets)? If so, do you think it might be worth just linking over to the lists from the game itself (or moving the list files and the gfx and audio folders into a new "resource" folder or something)? That way, if we add a new Block to the game it would automatically be in the editor, and vice versa.

DivFord commented 8 years ago

Yeah, it is using the same resources. I was planning to add in a "test" version of blocks, props, etc. so as to have something to represent new content until it's added to the editor, but shared data files would definitely be a better solution.

At the moment, the editor has all the data hardcoded into static classes, so it would be fairly easy to get it to read external data files instead. I think I'll hold off on actually doing it though, since setting up the level-parser is likely going to involve changing those list files. I don't want to go to the trouble of getting regex working only to have the format change and muck it up.

Speaking of list files, should they stay as .cpp files, or do we want them to be .json or something like that?

Fyll commented 8 years ago

Well, seeing as they still need to be read by the C++ game, I don't think making them java files would be a good idea (correct me if there's something more to this).

I should probably get back to work on this... :(

DivFord commented 8 years ago

Derp. Not .json. I meant .xml. You know, one of those formats meant for storing data, rather than code.

Fyll commented 8 years ago

The question is, would it be compilable into the executable? If it's going to be kept outside, we may as well just use a .txt.

DivFord commented 8 years ago

My take on it is; for development purposes, we want an easy to change data file that we can share between the game itself and the editor. When it comes to shipping (if?) we'll probably want to compile it into the executable, but presumably not until then. Having a development mode that ran directly from the data files would save us compiling whenever we want to test something.

Fyll commented 8 years ago

Can C++ read .xml though? Otherwise, surely it's easier if one of the programs can read the file, rather than both having to interpret it?

DivFord commented 8 years ago

Yeah… It's just that the current file looks pretty intimidating to parse. A compromise might be preferable.

That's just me trying to make things easier for me though...

Fyll commented 8 years ago

Well, the editor won't need some of the info that the game does, and vice versa (I'd imagine), so a common file would have the advantage of not loading the game down with useless info... Feel free to have a go, but I think this is one of those times where our lack of forethought has come back to bite us.

DivFord commented 8 years ago

I'm not ready to start on the import-export stuff yet, so by all means, let's discuss this further before diving in.

The editor cares which zones things can be used in (eg. lizards go in the desert). I think that's the only thing it wants that the game doesn't. Potentially the game could use that info, if we ever want to have random props/enemies/pickups.

To be honest, the main thing I'd want is to integrate the sprite coordinates into the main block data. It feels weird having them in separate functions, and the getBlockSpriteMap looks hard to parse.

Fyll commented 8 years ago

From a quick Google around, it looks like java can call C++ functions using libraries like JNI, JNA, or SWIG. Would that solve the problem?

DivFord commented 8 years ago

Possibly. Unity script is a weird variant of javascript, but it does have some C++ integration. I'll have a look.

DivFord commented 8 years ago

I can access the command line from Unity… Not sure if that helps.

I reckon txt files are the best solution. Maybe with a python script to write them into headers, similar to what Matt made for the level files.

Fyll commented 8 years ago

Hmm. Well, if we were to write a separate program that could somehow supply whoever asked with everything they wanted, then both the editor and the game would be able to call it. That way, we'd be able to have all of the lists in one place, but be available to both programs.

EDIT: Bleh, didn't fully read your two line post. Writing in .txt files, then converting to headers does seem fine. Now we need to think of a common syntax for the lists.

DivFord commented 8 years ago

I assume the data types we can pass out of a program are fairly limited. String, int, float and boolean should be doable, but we won't be able to pass out your vector class. I suppose we'd just have to have separate calls for fetching the x and the y coordinate.

DivFord commented 8 years ago

Is air included in the block groups system?

mspraggs commented 8 years ago

If I can chime in:

  1. There are libraries to read XML files with C++, such as tinyxml and libxml2 (the former is probably sufficient for our purposes),
  2. Let's not confuse Java (cross platform general purpose programming language created by Sun Microsystems) with Javascript (originally a scripting language for the web, now used for a fair few things). I believe Unity uses a variation of Javascript, no?

Depending on how sophisticated the block and/or level data is going to get, I think having some structured way of storing it outside the program would be beneficial. We can always progress to some more compact format if/when it comes to incorporating the block data into a format to be distributed with the main program.

EDIT: I have some experience with melding different languages, primarily Python and C++. If this is the path you decide to go down I can offer some advice if needed.

EDIT2: We can output any object from the program as text if there's a corresponding iostream function for the type we want to output. For the vector case we could easily implement one ourselves. Here's an example: https://msdn.microsoft.com/en-us/library/1z2f6c2k.aspx. Similarly you overload the >> operator to pipe a string into an object.

DivFord commented 8 years ago

People have definitely made xml readers for Unity, so that's a viable option.

As for the txt route, if I were to write up a list of all the data the level editor needs to access, could you create an interface with which I could access them? Outputting text would be fine.

Fyll commented 8 years ago

In response to your earlier question, yes, air Blocks get grouped together to.

DivFord commented 8 years ago

I've set things up so that multi-block entities (eg. patterns, props) are situated according to their bottom-left corner. So in:

  0 1 2
2 BsBsBs
1 BsPgBs
0 BsPgBs

the gate (Pg) is located at (1,0), and has dimensions of (1,2).

I can see this causing some problems when it comes to flipping patterns round. Would it be worthwhile flipping them in the level-editor, and exporting both versions, rather than trying to do it in-engine?

Obviously this increases the size of the pattern files, but it would make our lives easier, and might reduce loading times, which is probably more important.

mspraggs commented 8 years ago

I can do my best. I'm pretty busy these days, but I'll try to find the time. Could this just be a simple program that generates a text file with all the block data?

DivFord commented 8 years ago

Yeah. Hang on, I'll write a list of the data I need to access.

mspraggs commented 8 years ago

I have to admit I'm a little confused. The block data is all in one of the source files. Could you not just look at that? Or is this more about having some consistent data format for use by both the game and the level editor?

DivFord commented 8 years ago

Sorry, our discussion meandered a bit. The aim is to have some way for the level editor to access the block, prop, enemy and pickup data from the game files, so that it automatically stays up to date. As I see it, our options are:

Your call on which is the better solution. Not urgent, since Iain is still overhauling the engine, and the level editor can run on the data I've hard-coded into it for now.

Below is the list of data I need.

Blocks:

Props:

Enemies:

Pickups - Since there aren't any yet, we may as well ignore them for now. PickupList does exist though, so if you want to add them, this is what I'll (eventually) need.

mspraggs commented 8 years ago

Okay. Personally I think storing it independently of the game executable is going to make things easier in the long run, particularly since we could potentially edit the text file without having to recompile the game. If we eventually get to distribution, then we could invent some format where this is stored within the binary or some such.

DivFord commented 8 years ago

Seems sound. The only problem I see is that we would no longer be able to refer to constants. This bit from BlockLists.cpp, for example.

false,
getConstant<float>("AIR_DRAG"),
0.0f,
mspraggs commented 8 years ago

Ah... yes good point. I'll have a think...

mspraggs commented 8 years ago

I guess the solution would be to move all game constants and settings into a text file. Not sure how you guys feel about this. It would make tweaking settings and so forth easier in the long run.

Fyll commented 8 years ago

Would you need that though? Surely the editor wouldn't need to know the drag on the blocks.

DivFord commented 8 years ago

The editor wouldn't, but the whole point is that the game uses the same files, and it would.

@mspraggs Honestly, that sounds like a good idea generally. Constants are another of those things that we fiddle with, so not re-compiling every time we adjust them would be nice.

mspraggs commented 8 years ago

@DivFord What do you mean by Y-index and allowed zones?

DivFord commented 8 years ago

Allowed zones isn't in the data at the moment. I thought we should sort items by where they can be used. For example, lizards can go in the desert, but wouldn't go in whatever zones we add later on. Currently, there is only one zone, so this is just planning for the future.

Y-index is the y coordinate of the sprite sheet lookup. I believe that in:

BlockData("Air",
    ",,",

    false,
    false,
    getConstant<float>("AIR_DRAG"),
    0.0f,

    0,
    getBlockSpriteMap(0),

    std::vector<EffectResult> { }),

The "0" before "getBlockSpriteMap(0)" is the y-index.

EDIT: No, wait. The 0 in the bracket of "getBlockSpriteMap(0)" is the y-index.

mspraggs commented 8 years ago

Hmm... according to the code that 0 actually refers to the layer that the block is rendered into, so basically the z-index.

DivFord commented 8 years ago

Did you see my edit?

mspraggs commented 8 years ago

Ah yeah, no I didn't. Thanks!

EDIT: I think that's actually going to be a bit tricky to extract from the program without just going through the code and manually extracting that information. Perhaps I can automate with Python in some way.

DivFord commented 8 years ago

Are we going to want metadata for enemies? I can't think of any cases where we would.

Fyll commented 8 years ago

Which way they initially face?

DivFord commented 8 years ago

Good point. That must apply to all enemies. Are we ever likely to need to add data for a specific type of enemy? Stuff like patrol paths, I suppose.

Fyll commented 8 years ago

While patrol paths may be nice in one or two places, I don't think it'll be worth the effort of twisting everything around to fit them in. The closest thing I can think of would be to orbit around a given point in some way, but that would be more easily done as metadata I'd think.

DivFord commented 8 years ago

Umm… I think we have a misunderstanding somewhere. With props, I'm setting it up so that a prop in the level file is written as a prop code, followed by the coordinates, then any metadata. So a crate might be Pc(0,0), and a gate Pg(0,0,1), with the third value being the key code. For this to work, the prop data file (the part Matt is working on) needs to be able to return a string listing the metadata categories for the prop. In the case of the crate, it would return "", because there is no metadata, while for the gate, it would return "Keycode". The point of this being that each metadata field in the editor will be labelled, so we won't have to dig around finding what value it's meant to be.

With the enemies, every enemy would need coordinates and facing. That is, facing isn't metadata in the same way that key codes are. Since every enemy has it, we don't need the data files to tell the editor to include it. So my question was: will any enemy ever require us to set values unique to that enemy type? If so, we need to include that information in the data files, and I need to add a metadata editing feature for enemies.

Hope that clarifies things. It's hard to explain without explaining the entire editor...

Fyll commented 8 years ago

I think I understand.

Orbiting enemies are the closest thing to an enemy with metadata that I can think of (the extra data being the position of the point to orbit around, as well as the inner and outer radii possibly).