acme_pjz {l Wrote}:Now swapping block is implemented, and when you enter the checkpoint or swapping block, you need to press 'DOWN' key to activate them. Also added the sound effect. And ImageManager which prevents loading same image multiple time ... and a menu of editor
acme_pjz {l Wrote}:Now breakable block is implemented, feel free to change or modify the graphics (or code) of checkpoint/swapping block/fragile block ...
acme_pjz {l Wrote}:In order to implement moving blocks and spikes, a change of level format is needed. I don't know if anybody have ideas and opinions ... How about you, Edward_Lii?
800 600 0 0 0 0 0 50 0 0 100 0 0 150 0 0 200 0 0 250 0 50 250 0 100 250 0 150 250 0 200 250 0 250 250 0 300 200 0 350 150 0 400 150 0 450 150 0 500 200 0 500 250 0 550 250 0 600 250 0 650 250 0 650 200 0 650 150 0 650 100 0 650 50 0 650 0 3 600 200 1 100 200 2 50 200
size = 800,600
spawn = 20,20
spawn_s = 40,20
block = 0, 0, 0
block = 0, 0, 50
exit = 100, 200
portal = 45,80
moving_block = 40,40,100,20,30,1
size = 800, 600
block(0, 50) {
image = block1.png
}
death(50, 50) {
image = spikes.2png
#control = <TYPE>,<X-Movement>,<Y-movement>,<time>,<loopmode>
control = move,100,20,30,1
#Or:
control(move) {
movement = 100,20
time = 30
loopmode = 1
}
}
<LevelWidth> <LevelHeight> <LevelPropertiesCount> <LevelPropertiesName1> <LevelPropertiesValue1> ... <LevelPropertiesNameN> <LevelPropertiesValueN>
<ObjectType> <ObjectX> <ObjectY> <ObjectPropertiesCount> <ObjectPropertiesName1> <ObjectPropertiesValue1> ... <ObjectPropertiesNameN> <ObjectPropertiesValueN>
<ObjectType> <ObjectX> <ObjectY> <ObjectPropertiesCount> <ObjectPropertiesName1> <ObjectPropertiesValue1> ... <ObjectPropertiesNameN> <ObjectPropertiesValueN>
... ... ... ...
Edward_Lii {l Wrote}:Suggestion #2:
This one is a bit complexer:
...
acme_pjz {l Wrote}:Now moving blocks/spikes is implemented, although moving blocks are buggy (the physics need to change a bit) ... Currently in editor press Ctrl+O to open file, press Ctrl+S to save file (you can also press ESC for menu ) and press ENTER key to edit the moving block's properties when the mouse cursor is on it ...
During playing, press Ctrl+E to edit current level (ripped from Frogatto & Friends )
As for the file format, currently I changed the file format to:
- {l Code}: {l Select All Code}
<LevelWidth> <LevelHeight> <LevelPropertiesCount> <LevelPropertiesName1> <LevelPropertiesValue1> ... <LevelPropertiesNameN> <LevelPropertiesValueN>
<ObjectType> <ObjectX> <ObjectY> <ObjectPropertiesCount> <ObjectPropertiesName1> <ObjectPropertiesValue1> ... <ObjectPropertiesNameN> <ObjectPropertiesValueN>
<ObjectType> <ObjectX> <ObjectY> <ObjectPropertiesCount> <ObjectPropertiesName1> <ObjectPropertiesValue1> ... <ObjectPropertiesNameN> <ObjectPropertiesValueN>
... ... ... ...
acme_pjz {l Wrote}:A disadvantage is the property name and value can't contain spaces Anyway, the file format can always be changedEdward_Lii {l Wrote}:Suggestion #2:
This one is a bit complexer:
...
Your suggestion reminds me XML or the file format of Battle for Wesnoth ... It's a little difficult to implement because we would likely to meet a lot of bugs ...
description =[b][u] [/u][/b]Description bla blah blah
thing(1, Description with whitespaces, 102)
Edward_Lii {l Wrote}:I think it could do for now, but I think we could also go for an XML like format.
Maybe we could use a C/C++ xml parser?
acme_pjz {l Wrote}:XML parser is possible, for example libexpat ... But I think the question is do we need to use XML file format? If we use XML then the level file will be much larger IMHO ...
acme_pjz {l Wrote}:About white-spaces, I have a bad idea that is unescape the whole string, for example convert to hex like 203A3E4F ...
acme_pjz {l Wrote}:BTW, a good news is I managed to config the SVN client to use the HTTPS proxy ... and now I can and would like to join the project My SourceForge user name is acme-pjz ...
Bodsda {l Wrote}:If you are planning on changing the level file format, in my opinion, it would be far better to spend a good amount of time doing it properly; creating something robust, customizable and extendable, rather than mashing something together that works for now.
Bodsda {l Wrote}:If you are planning on changing the level file format, in my opinion, it would be far better to spend a good amount of time doing it properly; creating something robust, customizable and extendable, rather than mashing something together that works for now.
Bodsda {l Wrote}:I personally like the style of Suggestion #2 from Edward_Lii
acme_pjz {l Wrote}:I know I prefer XML format, but some people says that XML is not good for game file format ... Anyway, in my own project TurningPolyhedron I use XML format I have already written a simple and buggy XML reader/writer/DOM, but it's in Visual Basic, not C++ ... so I think we should try some existing XML library ...
Edward_Lii {l Wrote}:Bodsda {l Wrote}:I personally like the style of Suggestion #2 from Edward_Lii
Me too (because I use it in PoA )!
Edward_Lii {l Wrote}:acme_pjz {l Wrote}:I know I prefer XML format, but some people says that XML is not good for game file format ... Anyway, in my own project TurningPolyhedron I use XML format I have already written a simple and buggy XML reader/writer/DOM, but it's in Visual Basic, not C++ ... so I think we should try some existing XML library ...
I have nothing against XML in games, but somehow I prefer a more human readable format.
But using an existing xml-parser will reduce bugs in the loading, since you don't have to write it yourself, on the other side it adds another dependency to the project.
acme_pjz {l Wrote}:Well, I admit that I don't know your format at all Do you have reading/writing module already?
//Open the scene file.
BufferedReader reader = new BufferedReader(new FileReader(new File("Data" + File.separator + "Scenes" + File.separator + name + File.separator + name + ".scn")));
//The current line.
String line = "";
//Read every line of the scene file.
while((line = reader.readLine()) != null) {
//Remove all white-space in the line.
line = line.trim().replace(" ", "");
//Check the lines.
}
if(line.toLowerCase().startsWith("night") && !line.toLowerCase().contains("color")) {
//Set if the state has a night (time).
state.setNight(Boolean.valueOf(line.split("=")[1]));
}
acme_pjz {l Wrote}:IMHO XML is human readable too, compare with other formats...
As for the parser, use a self-written simple XML parser is not bad (but not good enough), although it doesn't support all XML features ...
cplusplus.com {l Wrote}:This function is not defined in ANSI-C and is not part of C++, but is supported by some compilers.
A standard-compliant alternative for some cases may be sprintf:
Edward_Lii {l Wrote}:...
The concept is pretty straight forward, first you loop the file with a while loop.
In Java I use these lines:
...
move,100,20,30,1
Edward_Lii {l Wrote}:As you can see I rely on a lot of Java methods including trim(), replace("", ""), startsWith(""), toLowerCase(), etc..
So I don't know if there's an easy way to do this in C++?
Edward_Lii {l Wrote}:BTW, I don't have a writing module since I still write my scene files by hand.
I hope I'll find the time to make an editor for PoA soon!
Edward_Lii {l Wrote}:When compiling I had some problems with the itoa() functions, although I succeeded in getting it to compile it might be worth it to consider using an alternative?
As stated here http://cplusplus.com/reference/clibrary/cstdlib/itoa/ itoa is not part of C++:cplusplus.com {l Wrote}:This function is not defined in ANSI-C and is not part of C++, but is supported by some compilers.
A standard-compliant alternative for some cases may be sprintf:
acme_pjz {l Wrote}:Maybe you can post an EBNF description of your file format, or I can invent one after observing your examples
block { //No additional parameters
property = value //Properties of the block.
block(parameter0, parameter1) //Sample block without parameters
block(parameter0, parameter1) {
property = value //Properties of the block.
}
} //Closing block
puzzle(6, 19, ConnectPuzzle) {
images = green.png, green_done.png
condition = TreeWater,false,true
notification = While_you_bind_the_roots_together,_the_water_begins_to_rise.
parameters = Tree
#Field size
parameters = 1, 2, 20, 20
#Marker <X> = <startX>, <startY>, <goalX>, <goalY>
parameters = 2, 5, 15, 19
parameters = 2, 10, 20, 18
parameters = 1, 15, 25, 17
#Obstacles
parameters = 1, 7, Plank.png
}
acme_pjz {l Wrote}:And a question:
- {l Code}: {l Select All Code}
move,100,20,30,1
Does this mean an array of strings, or just a string and its value is "move,100,20,30,1"?
acme_pjz {l Wrote}:Don't laugh, when I'm using Visual Basic, I heavily use these functions, too Of course if we want to write a universal reader/writer we don't need to use these function, because the parser is scanning the input stream consecutively, and put the data read to different buffer depend on what character it read. Finally, a tree-like hierarchical data structure is built.
acme_pjz {l Wrote}:So ... I think itoa() is in stdlib.h, and I don't know whether it's in cstdlib, too ... At least in Visual Studio it works, although produce a lot of warning, too ... I have to admit that I have a bad habit that mixing C headers with C++ headers ...
size = 800, 600
1,2,3=4,5
1,2=3,4,5
1,2,3=4,5,6
7,8,9=l,k,s,c,t{
LK=SCT
}
block(0, 50) {
image = block1.png
}
block(100,100)
death(50, 50) {
image = spikes.2png
#control = <TYPE>,<X-Movement>,<Y-movement>,<time>,<loopmode>
control = move,100,20,30,1
#Or:
control(move) {
movement = 100,20
time = 30
loopmode = 1
}
}
puzzle=6, 19, ConnectPuzzle {
images = green.png, green_done.png
condition = TreeWater,false,true
notification = "While you bind the roots together, the ""water"" begins to rise."
parameters = Tree
#Field size
parameters = 1, 2, 20, 20
#Marker <X> = <startX>, <startY>, <goalX>, <goalY>
parameters = 2, 5, 15, 19
parameters = 2, 10, 20, 18
parameters = 1, 15, 25, 17
#Obstacles
parameters = 1, 7, Plank.png
}
AttributeName=size
AttributeValue=800,600
AttributeName=1
AttributeValue=4
AttributeName=2
AttributeValue=5
AttributeName=3
AttributeValue=
AttributeName=1
AttributeValue=3
AttributeName=2
AttributeValue=4,5
AttributeName=1
AttributeValue=4
AttributeName=2
AttributeValue=5
AttributeName=3
AttributeValue=6
AttributeName=7
AttributeValue=l
AttributeName=8
AttributeValue=k
NewNode
NodeName=9
NodeValue=s,c,t
AttributeName=LK
AttributeValue=SCT
EndNode
NewNode
NodeName=block
NodeValue=0,50
AttributeName=image
AttributeValue=block1.png
EndNode
NewNode
NodeName=block
NodeValue=100,100
EndNode
NewNode
NodeName=death
NodeValue=50,50
AttributeName=image
AttributeValue=spikes.2png
AttributeName=control
AttributeValue=move,100,20,30,1
NewNode
NodeName=control
NodeValue=move
AttributeName=movement
AttributeValue=100,20
AttributeName=time
AttributeValue=30
AttributeName=loopmode
AttributeValue=1
EndNode
EndNode
NewNode
NodeName=puzzle
NodeValue=6,19,ConnectPuzzle
AttributeName=images
AttributeValue=green.png,green_done.png
AttributeName=condition
AttributeValue=TreeWater,false,true
AttributeName=notification
AttributeValue=While you bind the roots together, the "water" begins to rise.
AttributeName=parameters
AttributeValue=Tree
AttributeName=parameters
AttributeValue=1,2,20,20
AttributeName=parameters
AttributeValue=2,5,15,19
AttributeName=parameters
AttributeValue=2,10,20,18
AttributeName=parameters
AttributeValue=1,15,25,17
AttributeName=parameters
AttributeValue=1,7,Plank.png
EndNode
acme_pjz {l Wrote}:I have invented the file format which is slightly different from your format And upload a reader to SVN. The file format (more or less) is:
size = <width>,<height>
block(<x>, <y>) {
image = <image-file>
}
block(<x>, <y>) {
image = <image-file>
deathly = <boolean>
}
death(<x>, <y>) {
image = <image-file>
}
acme_pjz {l Wrote}:
- {l Code}: {l Select All Code}
1,2,3=4,5
1,2=3,4,5
1,2,3=4,5,6
7,8,9=l,k,s,c,t{
LK=SCT
}
p1,p2=3
p3,p4=3,3,4
Edward_Lii {l Wrote}:I assume we both agree that for the size of the level we use the property size:
- {l Code}: {l Select All Code}
size = <width>,<height>
Edward_Lii {l Wrote}:And a block can stay an block:
- {l Code}: {l Select All Code}
block(<x>, <y>) {
image = <image-file>
}
Then there are the spikes, we could handle it as a special block like this:
- {l Code}: {l Select All Code}
block(<x>, <y>) {
image = <image-file>
deathly = <boolean>
}
But then again, in M&MS it's handled as a different object type so this would make sense to:
- {l Code}: {l Select All Code}
death(<x>, <y>) {
image = <image-file>
}
tile(block,50,50)
tile(spike,50,100)
tile(playerstart,200,200)
tile(movingblock,300,300){
MovingPosCount=3
x0=...
y0=...
t0=...
...
}
Edward_Lii {l Wrote}:Although I like the way that 1 is assigned to 3 and 2 to 4,5 I think the use of it is insignificant.
For me it would make more sense if some writes this:
- {l Code}: {l Select All Code}
p1,p2=3
p3,p4=3,3,4
That both p1 and p2 will be set to three and in the second example both p3 and p4 will be set to 3,3,4.
What do you think?
acme_pjz {l Wrote}:Edward_Lii {l Wrote}:I assume we both agree that for the size of the level we use the property size:
- {l Code}: {l Select All Code}
size = <width>,<height>
I'm sorry, but I don't quite agree "size = <width>,<height>", I prefer "width = <width> height = <height> LevelName= <LevelName>" Anyway, "size = <width>,<height>" is not bad ... so it's a deal
spawn = <x>,<y>
spawn_x= <x>
spawn_y = <y>
acme_pjz {l Wrote}:IMHO every type of objects share a common node name is better, say: tile(<type>,<x>,<y>){ <additional parameters> } , for example:
- {l Code}: {l Select All Code}
tile(block,50,50)
tile(spike,50,100)
tile(playerstart,200,200)
tile(movingblock,300,300){
MovingPosCount=3
x0=...
y0=...
t0=...
...
}
You're right, maybe it's better to call them all tile.
But I think we should allow to add an image property to every tile, like this:
- {l Code}: {l Select All Code}
tile(block,50,50)
tile(spike,50,100) //Default spike image is used
tile(spike,100,100) {
image = spike2.png //Default spike2 image is used
}acme_pjz {l Wrote}:I think probably we will never use this feature, at least in file writer this format can't appear ...
size = 800,600 //No problem only one word
movingPosCount = 3 //We could start the following words capitals.
movingposcount = 3 //Or completely lower case.
moving_pos_count = 3 //Or even add an underscore between the words.
acme_pjz {l Wrote}:I have commited the converted file, and the size is "size = <width>,<height>" Due to the limitation of file writer, the actual properties are "size"="800","600" , a bit ugly ... Anyway, if you write size=800,600 the reader can still read the data correctly, so if you have spare tile feel free to fix this bug
acme_pjz {l Wrote}:About the image property, currently it's unsupported, but keep an unused property in file won't cause compatibility problems
acme_pjz {l Wrote}:As for the capitals, if you want to change them, you have to update all level files again
Edward_Lii {l Wrote}:acme_pjz {l Wrote}:I have commited the converted file, and the size is "size = <width>,<height>" Due to the limitation of file writer, the actual properties are "size"="800","600" , a bit ugly ... Anyway, if you write size=800,600 the reader can still read the data correctly, so if you have spare tile feel free to fix this bug
I'll see what I can do!
switch(c){
case ' ':
break; //Instead of returning we just suppress this character.
case EOF:
case '\r':
case '\n':
case '\t':
return;
case ',':
case '=':
case '(':
case ')':
case '{':
case '}':
case '#':
fin.unget();
return;
default:
s.push_back(c);
}
c=fin.get();
...
/home/edward/Programming/MeAndMyShadow/src/TreeStorageNode.cpp:81:31: error: cast from ‘void*’ to ‘unsigned int’ loses precision
unsigned int i=(intptr_t)lpUserData;
Edward_Lii {l Wrote}:
...
Committed a fix, it's only one line long and it seems to work.
I added this line in the ReadString method:
- {l Code}: {l Select All Code}
switch(c){
case ' ':
break; //Instead of returning we just suppress this character.
...
I hope this doesn't break the loading system in anyway, from the tests I did it seems to work fine.
aaa=bbb ccc=ddd eee=fff
aaa=bbb
ccc=ddd
eee=fff
Edward_Lii {l Wrote}:Oh and there was a problem I had when compiling.
I got this error:
- {l Code}: {l Select All Code}
/home/edward/Programming/MeAndMyShadow/src/TreeStorageNode.cpp:81:31: error: cast from ‘void*’ to ‘unsigned int’ loses precision
This only happens on 64-bit systems, I changed it into this:
- {l Code}: {l Select All Code}
unsigned int i=(intptr_t)lpUserData;
Edward_Lii {l Wrote}:BTW, how do you define which of the three different solid blocks a tile is?
AFAIK you only say tile("Block", <x>, <y>)
acme_pjz {l Wrote}:Unfortunately, it DOES break the loading system (but don't worry, it won't make mistake if you just restricted to read the file which is writer generated), because In my design the following file:
- {l Code}: {l Select All Code}
aaa=bbb ccc=ddd eee=fff
is equal to
- {l Code}: {l Select All Code}
aaa=bbb
ccc=ddd
eee=fff
After your change everything goes wrong ... Anyway, The write can't generate this kind of file
acme_pjz {l Wrote}:There is really a problem, even in Visual Studio it produces a warning, too ... Maybe I'm too lazy, I think that the pointer type can contains an integer, so I reused the pointer, avoiding create a new variable ...
acme_pjz {l Wrote}:I just didn't changed the block load code, now it's still depending on random number And I think it's convenient to use random number instead of reading from file ... I have an idea: the picture will be random if you don't specify the picture file, otherwise it will use the given picture file. Is it OK?
Users browsing this forum: No registered users and 1 guest