Fenix - Doing The Basics: Graphics, Save/load, Display Text


DavidBeoulve

GP2X by EvilDragon OC's to 280-300MHz
Joined
May 10, 2006
Messages
427
Age
48
Location
USA
Website
www.gamersgonebad.com
I can't believe I've spent all Sunday morning on this *chuckles* but there ain't much in the way of documentation.

Here is what I have found that is useful:
  1. Fenix Manual - sadly doesn't list all functions or things like IF statements but it lists the most functions of any command reference I have found.
  2. Boolean Soup's Fenix Forum - They appear to be alive...
  3. Fenix Wiki - Lists stuff the Manual doesn't, like NET commands, loops (that's good) and using graphics (ooo!)
  4. Fenix On Fire - has a lot of English samples, many from Moogle and Quiest. Snippets are neat.
  5. FenixPenix - I mean Pixel! Just checking if y'all are readin' ;)
    They uh... they're into translating Fenix Documents. A lot of their command entries have no description - hardly useful.
Okay so - now that I have contributed to the cause, I feel I can ask questions without remorse.

Using as a base what Danko posted here, I have labored to produce...
CODE
program AMERYTH; // you can omit this if you want
// Global variables
global
int g_Hero;
int g_Bg;
int g_Icon;
int m_Athena;
int g_Border;
int exit;
end


Self explanatory. Ameryth is copyright. The "G_" variables are integers that will store the number of a graphic so they can be referred to by name.

CODE

// Main process (entry point)
begin
// Sets the graphic mode to 320x240, 16bpp, windowed
set_mode(320, 240, 16);
// FPS and maximum auto frameskip
SET_FPS(50,10);

// Load graphics. Load_XXX function return an int value
// which can be used later to refer to loaded resources
g_Hero = load_png("PNGs_320x240_max_WB\PNG_swordman3.png");
g_Bg = load_png("PNGs_Backgrounds\bg.png");
g_Icon = load_png("PNGs_Utility\base.fpg");
g_Border = load_png("PNGs_Utility\border_exact.png");

//Set the Icon up
set_icon(0,g_Icon);

Here the rendering mode is set, and that works. The graphics are loaded, and that works. The ICON thing doesn't work.

CODE

//Set up background Music
m_Athena = LOAD_SONG("Music\Athena.ogg");
PLAY_SONG(m_Athena,0);

Quiest mentioned using MP3's, then everyone at Boolean Soup started playing Alphabet Soup with his post, and I have no idea how he did it.

CODE

// Put a background image
put_screen(0, g_Bg);

Apparenty this is an important difference from other, hitherto unknown methods of pasting graphics on the screen.

CODE

// Call the hero process
hero();

// Call the Status Process
status_screen();

Fenix uses multithreading of some kind, I think; at least it uses separate processes. Anyway, HERO is one process, and STATUS_SCREEN the other. Case in names doesn't seem to matter.

CODE

write(0,160,160,4,"Press [Start] To Start ");

I just put the the text in to see what that looks like - it's a very big font, but specifying a font other than "0" (the first number) doesn't work... how do I get more fonts?

CODE

// Main loop
repeat
frame;
until (key(_esc))

// Destroy all running processes
let_me_alone();

// Unload resources
unload_map(0, g_Hero);
unload_map(0, g_Bg);
unload_map(0, g_Icon);
unload_map(0, g_Border);
end

That main loop runs the program - since each process is responsible for looping itself. Everything else is clean-up as the program closes.

CODE
// This is the process of our hero. It controls
// it movement with keyboard
process hero()
begin
graph = g_Hero;
x = 320/2;
y = 240/2;
loop
if (key(_right)) x+=1; end
if (key(_left)) x-=1; end
if (key(_up)) y-=1; end
if (key(_down)) y+=1; end
frame;
end
end

This works just fine, for what it is. Eventually I'll be doing something completely different.

CODE

process Status_Screen()
begin
DRAWING_COLOR(12);
DRAW_BOX(10,10,100,40);
end


I have tried loading a dithered PNG (every other pixel is transparent) but it always turns up GREEN. The (opaque) colored pixels, be they black or blue, turn green (which is the predominant color of the background image. But transparency works. Exporting this in different PNG formats, or even putting it inside an FPG using FPG EDIT (Fenix's image packer/editor) doesn't change this. HUH?

Basically, I need to set up a status screen for your typical RPG - where you see your character's status bars at the bottom and there's some enemy in front of you. I can ungay that later once you see the finished product, but for now it will sound like it just came out of a California parade. ;)

Any and all help is appreciated. Here's the code again - simply comment out the music and change the PNGs to load whatever you want.

CODE
program AMERYTH; // you can omit this if you want

// Global variables
global
int g_Hero;
int g_Bg;
int g_Icon;
int m_Athena;
int g_Border;
int exit;
end

// Main process (entry point)
begin
// Sets the graphic mode to 320x240, 16bpp, windowed
set_mode(320, 240, 16);
// FPS and maximum auto frameskip
SET_FPS(50,10);

// Load graphics. Load_XXX function return an int value
// which can be used later to refer to loaded resources
g_Hero = load_png("PNGs_320x240_max_WB\PNG_swordman3.png");
g_Bg = load_png("PNGs_Backgrounds\bg.png");
g_Icon = load_png("PNGs_Utility\base.fpg");
g_Border = load_png("PNGs_Utility\border_exact.png");

//Set the Icon up
set_icon(0,g_Icon);

//Set up background Music
m_Athena = LOAD_SONG("Music\Athena.ogg");
PLAY_SONG(m_Athena,0);

// Put a background image
put_screen(0, g_Bg);

// Call the hero process
hero();

// Call the Status Process
status_screen();

write(0,160,160,4,"Press [Start] To Start ");

// Main loop
repeat
frame;
until (key(_esc))

// Destroy all running processes
let_me_alone();

// Unload resources
unload_map(0, g_Hero);
unload_map(0, g_Bg);
unload_map(0, g_Icon);
unload_map(0, g_Border);
end

// This is the process of our hero. It controls
// it movement with keyboard
process hero()
begin
graph = g_Hero;
x = 320/2;
y = 240/2;
loop
if (key(_right)) x+=1; end
if (key(_left)) x-=1; end
if (key(_up)) y-=1; end
if (key(_down)) y+=1; end
frame;
end
end

process Status_Screen()
begin
DRAWING_COLOR(12);
DRAW_BOX(10,10,100,40);
end
 
Just so y'all can see how HORRIBLE my coding is...

Quiest mentions how easy it is to load and save structures - only - it's not. That save command won't overwrite an existing file, and using Fclose(0); beforehand makes the game CTD.

How do I get the save command to overwrite an existing file?

CODE
program AMERYTH; // you can omit this if you want

// Global variables
global
int g_Hero;
int g_Bg;
int g_Icon;
int m_Athena;
int g_BorderNormal;
int g_BorderSelected;
int g_BorderPerformingAction;
int g_BorderAttacked;
int g_BorderTurnOver;
int exit;

// In reality we fill this in with the active heroes...
int HeroSlot[6];

struct HEROES[50];
name = "No Name";
HP_max = 0;
HP = 0;
MANA_max = 0;
MANA = 0;
attribute_STR = 0;
attribute_CON = 0;
attribute_DEX = 0;
attribute_INT = 0;
attribute_WIS = 0;
attribute_CHR = 0;
skillpoints = 0;
inParty = false;
class = 0;
level = 0;
gender = "N"; // M is male, F is female
activeTurn = false;
selected = false;
// 1-doing action, 2-getting hit, 3-turn over, 4-selected, 0-normal
turnStatus = 0;end
end

// Main process (entry point)
begin
// Sets the graphic mode to 320x240, 16bpp, windowed
set_mode(320, 240, 16);
// FPS and maximum auto frameskip
SET_FPS(50,10);

// Load graphics. Load_XXX function return an int value
// which can be used later to refer to loaded resources
g_Hero = load_png("PNGs_320x240_max_WB\PNG_swordman3.png");
g_Bg = load_png("PNGs_Backgrounds\bg.PNG");
g_Icon = load_png("PNGs_Utility\PNG_ICON_32x32.png");
g_BorderNormal = load_png("PNGs_Utility\border_105x34y.png");
g_BorderSelected = load_png("PNGs_Utility\border_105x34y_blue.png");
g_BorderPerformingAction = load_png("PNGs_Utility\border_105x34y_green.png");
g_BorderAttacked = load_png("PNGs_Utility\border_105x34y_red.png");
g_BorderTurnOver = load_png("PNGs_Utility\border_105x34y_gray.png");

//Set the Icon up
set_icon(0,g_Icon);

// initialize
Initialization();

//Set up background Music
m_Athena = LOAD_SONG("Music\Athena.ogg");
PLAY_SONG(m_Athena,0);

// Put a background image
put_screen(0, g_Bg);

// Call the hero process
hero();

// Call the Status Process
status_screen(53,185,HeroSlot[0]);
status_screen(160,185,HeroSlot[1]);
status_screen(266,185,HeroSlot[2]);
status_screen(110,220,HeroSlot[3]);
status_screen(215,220,HeroSlot[4]);

//write(0,160,160,4,"Press [Start] To Start ");

// Main loop
repeat
frame;
until (key(_esc))

save("characters.AMY",HEROES);

// Destroy all running processes
let_me_alone();

// Unload resources
unload_map(0, g_Hero);
unload_map(0, g_Bg);
unload_map(0, g_Icon);
unload_map(0, g_BorderNormal);
unload_map(0, g_BorderSelected);
unload_map(0, g_BorderPerformingAction);
unload_map(0, g_BorderAttacked);
unload_map(0, g_BorderTurnOver);
end

// This is the process of our hero. It controls
// it movement with keyboard
process hero()
begin
graph = g_Hero;
x = 320/2;
y = 240/2;
z = 1;
loop
if (key(_right)) x+=1; end
if (key(_left)) x-=1; end
if (key(_up)) y-=1; end
if (key(_down)) y+=1; end
write(0,50,10,4,"X:"+x+" Y:"+y);
frame;
DELETE_TEXT(0);
end
end

process Status_Screen(plusX, plusY,HeroNumber)
begin
if (HEROES[HeroNumber].turnStatus = 4)
graph = g_BorderSelected;
else
graph = g_BorderNormal;
end
x=plusX;
y=plusY;
loop
//NAME
write(0,plusX,(plusY-10),4,HEROES[HeroNumber].name);
//HP
write(0,plusX,(plusY),4,"HP:"+HEROES[HeroNumber].HP);
//MP
write(0,plusX,(plusY+10),4,"MANA:"+HEROES[HeroNumber].MANA);
frame;
end
//DRAWING_COLOR(12);
//DRAW_BOX(10,10,100,40);
end

process Initialization()
private HeroCounter = 0,
tempCounter = 0,
PartyCounter = 0;

begin
if(FILE_EXISTS("characters.AMY"))
load("characters.AMY",HEROES);
else
save("characters.AMY",HEROES);
end

for (HeroCounter = 0; HeroCounter < 50; HeroCounter+=1)
if (HEROES[HeroCounter].inParty)
HeroSlot[PartyCounter] = HeroCounter;
PartyCounter+=1;
end
end
if (PartyCounter < 4)
for (tempCounter = 0; tempCounter < 5; tempCounter+=1)
HeroSlot[tempCounter] = tempCounter;
HEROES[tempCounter].name = "Moogle";
HEROES[tempCounter].HP = 10;
HEROES[tempCounter].MANA = 10;
end
end
end
 
I also use structures and have never had the problem of it not being able to overwrite the file. One thing I did notice though which will cause you problems is the fact that you have strings as part of the structure. There is a bug in the gp2x version of fenix which will cause a crash when loading or saving strings to a file. To get around it you have to convert the string to it's individual ascii codes and then save it out - then do the reverse when you load it in to get the string back. It's a real pain but I don't think there is any other way to work around it.
 
ruckage said:
I also use structures and have never had the problem of it not being able to overwrite the file. One thing I did notice though which will cause you problems is the fact that you have strings as part of the structure. There is a bug in the gp2x version of fenix which will cause a crash when loading or saving strings to a file. To get around it you have to convert the string to it's individual ascii codes and then save it out - then do the reverse when you load it in to get the string back. It's a real pain but I don't think there is any other way to work around it.
This is good to know!

Sam... okay but if you haven't saved recently - I'm not sure that the file existing or not at that point matters - you need to save the current game and overwrite what was there, if anything. Anyway I uhh, not sure what to do about that one. There isn't a delete file either, that I've found.

Here's the latest awful code.

All I'm happy with is that the menu system lets you move across the top three or bottom two character screens. Pressing up and Down yields different results. Pressing SPACE brings up a character picture.

Currently I've found that FENIX fires processes and keeps moving so I'm trying to think about how to bring up a character creation screen if the user has no data. Right now I just initialize some dummy placeholders so I can see the menu screen at the bottom work.
CODE
program AMERYTH; // you can omit this if you want

// Global variables
global
/* for when we are in separate menu functions... */
string keylock;

/* graphics we always need */
int g_Bg;
int g_Icon;
int g_BorderNormal;
int g_BorderSelected;
int g_BorderPerformingAction;
int g_BorderAttacked;
int g_BorderTurnOver;

/* The Sound of Music */
int m_BGM; // opening music
int s_Menu; // menu sound
int s_Select;
int s_DeSelect;

int exit;

/* which character is currently selected */
int charSelected;

/* the delay before accepting another key command ...
remember that FPS settings affects the timing here */
int delay;
int delayAmount = 20;

// In reality we fill this in with the active heroes...
int HeroSlot[6];

/* structure of hero save game (and active) information */
struct HEROES[50];
name = "No Name";
HP_max = 0;
HP = 0;
MANA_max = 0;
MANA = 0;
attribute_STR = 0;
attribute_CON = 0;
attribute_DEX = 0;
attribute_INT = 0;
attribute_WIS = 0;
attribute_CHR = 0;
skillpoints = 0;
inParty = false;
class = 0;
level = 0;
gender = "N"; // M is male, F is female
activeTurn = false;
selected = false;
// 1-doing action, 2-getting hit, 3-turn over, 4-selected, 0-normal
turnStatus = 0;end
end

// Main process (entry point)
begin
// Sets the graphic mode to 320x240, 16bpp, windowed
set_mode(320, 240, 16);

// FPS (50) and maximum auto frameskip (10)
SET_FPS(50,10);

// Load graphics. Load_XXX function return an int value
// which can be used later to refer to loaded resources
g_Bg = load_png("PNGs_Backgrounds\bg.PNG");
g_Icon = load_png("PNGs_Utility\PNG_ICON_32x32.png");
g_BorderNormal = load_png("PNGs_Utility\border_105x34y.png");
g_BorderSelected = load_png("PNGs_Utility\border_105x34y_blue.png");
g_BorderPerformingAction = load_png("PNGs_Utility\border_105x34y_green.png");
g_BorderAttacked = load_png("PNGs_Utility\border_105x34y_red.png");
g_BorderTurnOver = load_png("PNGs_Utility\border_105x34y_gray.png");

//Set the Icon up - DOESN'T WORK
set_icon(0,g_Icon);

// initialize
Initialization();

//Set up background Music
m_BGM = LOAD_SONG("Music\Athena.ogg");

//Sounds we hear frequently
s_Menu = LOAD_WAV("Sounds\menu.wav");
s_Select = LOAD_WAV("Sounds\select.wav");
s_DeSelect = LOAD_WAV("Sounds\deselect.wav");

//PLAY_SONG(m_Athena,0);

// Put a background image
put_screen(0, g_Bg);

// Call the hero process
hero();

// Call the Status Process
status_screen(53,185,HeroSlot[0]);
status_screen(160,185,HeroSlot[1]);
status_screen(266,185,HeroSlot[2]);
status_screen(110,220,HeroSlot[3]);
status_screen(215,220,HeroSlot[4]);

//write(0,160,160,4,"Press [Start] To Start ");

// Main loop
repeat
frame;
until (key(_esc))

save("characters2.AMY",HEROES);

// Destroy all running processes
let_me_alone();

// Unload resources
unload_map(0, g_Bg);
unload_map(0, g_Icon);
unload_map(0, g_BorderNormal);
unload_map(0, g_BorderSelected);
unload_map(0, g_BorderPerformingAction);
unload_map(0, g_BorderAttacked);
unload_map(0, g_BorderTurnOver);
end

/* this is where we grab key commands to select characters
- not much else currently */
process hero()
begin
keylock="Hero";
loop
/*********************************************************
ARROW KEYS
********************************************************/
if(keylock=="Hero")
if (key(_right) && delay == 0)
delay = delayAmount;
HEROES[charSelected].selected = false;
charSelected += 1;
if (charSelected >= 5)
charSelected = 0;
end
PLAY_WAV(s_Menu,0);
HEROES[charSelected].selected = true;
end
if (key(_left) && delay == 0)
delay = delayAmount;
HEROES[charSelected].selected = false;
charSelected -= 1;
if (charSelected < 0)
charSelected = 4;
end
PLAY_WAV(s_Menu,0);
HEROES[charSelected].selected = true;
end
if (key(_up) && delay == 0)
delay = delayAmount;
HEROES[charSelected].selected = false;
SWITCH (charSelected)
CASE 0:
charSelected = 3;
END
CASE 1:
charSelected = 3;
END
CASE 2:
charSelected = 4;
END
CASE 3:
charSelected = 0;
END
CASE 4:
charSelected = 1;
END
end
PLAY_WAV(s_Menu,0);
HEROES[charSelected].selected = true;
end
if (key(_down) && delay == 0)
delay = delayAmount;
HEROES[charSelected].selected = false;
SWITCH (charSelected)
CASE 0:
charSelected = 3;
END
CASE 1:
charSelected = 4;
END
CASE 2:
charSelected = 4;
END
CASE 3:
charSelected = 1;
END
CASE 4:
charSelected = 2;
END
end
PLAY_WAV(s_Menu,0);
HEROES[charSelected].selected = true;
end
/*********************************************************
BUTTONS
********************************************************/

/*********************************************************
START / SELECT KEYS
********************************************************/
IF (key(_SPACE) && delay == 0)
delay = delayAmount;
PLAY_WAV(s_Select,0);
runCharacterStatusScreen(charSelected);
END
write(0,60,10,4,"X:"+x+" Y:"+y + " ["+charSelected+"]");

if(delay > 0)
delay--;
end
end
frame;
DELETE_TEXT(0);
end
end

/* this is where we look at one character in detail */
PROCESS runCharacterStatusScreen(charSelected)
private g_Hero;
BEGIN
keylock = "Character Status Screen";

g_Hero = load_png(g_Fighter);
g_Hero = load_png("PNGs_320x240_max_WB\PNG_swordman3.png");
graph = g_Hero;
x = 320/2;
y = 240/2;
z = 1;
repeat
frame;
if(delay > 0)
delay--;
end
until (key(_SPACE) && delay == 0 || keylock!="Character Status Screen")
keylock = "Hero";
delay = 20;
PLAY_WAV(s_DeSelect,0);
END

/* this is what draws each status screen */
process Status_Screen(plusX, plusY,HeroNumber)
begin
x=plusX;
y=plusY;
loop
if (HEROES[HeroNumber].selected)
graph = g_BorderSelected;
else
graph = g_BorderNormal;
end
//NAME
write(0,plusX,(plusY-10),4,HEROES[HeroNumber].name);
//HP
write(0,(plusX-48),(plusY),3,"HP:"+HEROES[HeroNumber].HP);
//MP
write(0,(plusX-48),(plusY+10),3,"MANA:"+HEROES[HeroNumber].MANA);
//SELECTION STATUS
//write(0,plusX,(plusY+20),4,"Sel:"+HEROES[HeroNumber].turnStatus+" ["+HeroNumber+"]");
frame;
end
//DRAWING_COLOR(12);
//DRAW_BOX(10,10,100,40);
end

/* init data and game */
process Initialization()
private HeroCounter = 0,
tempCounter = 0,
PartyCounter = 0,
foundActive = false,
createTeam = 0;

begin
if(FILE_EXISTS("characters.AMY"))
load("characters.AMY",HEROES);
else
save("characters.AMY",HEROES);
end

for (HeroCounter = 0; HeroCounter < 50; HeroCounter+=1)
if (HEROES[HeroCounter].inParty)
HeroSlot[PartyCounter] = HeroCounter;
PartyCounter+=1;
foundActive = true;
HEROES[tempCounter].selected = false;
end
end

if (foundActive == false)
// there are no active members in the party!
for (HeroCounter = 0; HeroCounter < 50; HeroCounter+=1)
if (HEROES[HeroCounter].name != "No Name" && createTeam < 5)
HeroSlot[createTeam] = HeroCounter;
HEROES[HeroCounter].inParty = true;
HEROES[HeroCounter].selected = false;
foundActive = true;
createTeam++;
end
end
IF (foundActive == false)
// THERE IS NO PARTY!!
goCreateTeam();
END
end

for (tempCounter = 0; tempCounter < 5; tempCounter+=1)
HeroSlot[tempCounter] = tempCounter;
HEROES[tempCounter].name = "Moogle " + (tempCounter+1);
HEROES[tempCounter].HP = 10;
HEROES[tempCounter].MANA = 10;
HEROES[tempCounter].Class = tempCounter;
HEROES[tempCounter].selected = false;
end

// cut bunch of stuff where image names are put into variables for some stupid reason, prolly don't need that

HEROES[HeroSlot[0]].selected = true;
end

PROCESS goCreateTeam()
BEGIN
/*
// Main loop
repeat
write(0,180,40,4,"Please assemble your party of adventurers.");
frame;
until (key(_Q))

FRAME;
*/
END
 
Last edited by a moderator:
You don`t need any fopen, etc stuff for saving & loading structures, just use save and load... it should overwrite the file fine o_O

There is also a command called file_exists("file"), which returns 1 if the file is there, maybe that`ll help you ( if(file_exists("save1.dat")load("save1.dat",struct);end; )

For fonts, you get more by creating them in FNT Edit (search sourceforge), you can load them in Fenix with like f_font1=load_font("font1.fnt") and then use f_font1 instead of the 0 in the write commands.
 
Quiest said:
You don`t need any fopen, etc stuff for saving & loading structures, just use save and load... it should overwrite the file fine o_O

There is also a command called file_exists("file"), which returns 1 if the file is there, maybe that`ll help you ( if(file_exists("save1.dat")load("save1.dat");end; )

For fonts, you get more by creating them in FNT Edit (search sourceforge), you can load them in Fenix with like f_font1=load_font("font1.fnt") and then use f_font1 instead of the 0 in the write commands.
Awesomeness, I have FNT EDIT, found it next to FPG EDIT on some DIV coding site. What an awful acronym to use - Google doesn't understand.

I'm aware of FILE_EXISTS() - I'll check more on the files.

I'm told that GP2X Fenix hates saving strings. Does it have the same issues with text files? Because the goal is to make an RPG that runs primarily off of text files so that folks can customize anything they want in the game - from maps to stats. With the idea being that - from there - additions can be added to make doing that on a GP2X possible.
 
Last edited by a moderator:
Hmm I don't think its the same for text files... you would have to use fopen, fclose etc. for that.
Take a look at the gp32 file archive and look for sliders32 or something (made by racemaniac), he has the source included and theres a text file reading engine included, that could help a lot.

btw, something went wrong when you added me to msn I think o_O I used to use Trillian, tho I installed MSN Messenger today, and I think I clicked something wrong... you are not in my contact list...
 
QUOTE
I also use structures and have never had the problem of it not being able to overwrite the file. One thing I did notice though which will cause you problems is the fact that you have strings as part of the structure. There is a bug in the gp2x version of fenix which will cause a crash when loading or saving strings to a file. To get around it you have to convert the string to it's individual ascii codes and then save it out - then do the reverse when you load it in to get the string back. It's a real pain but I don't think there is any other way to work around it.


I just stumbled upon this bug and I'm trying to find a way to get around it. Currently, I have a structure which looks like this :

struct Names[24]
string Name;
end

Any idea how I could save this struct? As it is now, it won't save it correctly. (It crashes the next time it tries to load it). Do you have an example of how to convert the string to it's individual ascii codes as mentioned above? Any help would be appreciated!
 
Chen-Kenichi-icon.gif

Moogle's Cookbook

Today we'll be making a quick but fulfilling bite of Structs with the tingling flavour of freshly chopped up Strings. Before we start cooking, let's see what the local FenixMart has to offer in the character department. Here is a list of the ingredients:

Main Ingredients:
Struct - Basis of our dinner, everyone should already be acquinted with the basic rules
Strings - A nicely sized String, make sure it's fresh!
Bytes - We will need something to put the String in, of course.

Flavourings:
Byte ASC(String text) - ASC returns the ASCII number of the first character of a given String as a Byte(data type like int, range spans 0-255)
String CHR(Byte value) - CHR does the opposite, you feed it an ASCII number and it returns a String with the corresponding character
String SUBSTR(String text, Int start, Int length) - Returns a part of string defined by the character to start at and the length of the part to return.

Preparation:
First we need to declare the struct. Since we can't put a String in there, we use an array of Bytes for each String. As an array needs to have a defined size we need to think of the maximum length the String can be. For this example, let's say the String can be 100 characters at most. If we want to save just 1 String the struct can look like this:
CODE

struct SaveString
byte string[100];
end


If we'd want to store more than one String we could make 'string' a multi-dimensional array, which would look like this(for 11 strings):
CODE

struct SaveString
byte string[10][100];
end


Note that this is for 11 Strings, as the number 10 makes Fenix declare 11 'places', ranging from 0 to 10. Anyway, now that we've done the preparations it's time to do some cooking. For this we'll use the first struct(the one for just 1 String). First we want to have a function that takes in a String, chops it up into characters and puts each character in the 'string' field of the declared struct 'SaveString'. We'll do this with a for(;;) loop, which we'll repeat for as many times as there are characters in the String. Then each repetition we'll convert the first character to it's ASCII value and store it on the spot in the byte array of it's position in the String. Ergo:
CODE

process convertToStruct(String text)
private
int i;
string stringPart;
begin
//Clear the previous string
for(i=0;i<=100;i++)
SaveString.string = 0;
end
//And put in the new one
for(i=0;i<len(text) and i<=100;i++)
stringPart = substr(text,i,1);
SaveString.string = asc(stringPart);
end
end


Right, so that was part one. Now the String is all chopped up it's time put the meal together again. So, after we've marinated our struct with whatever fields you might like, we put it away in the filesystem until we've had some beer. Ah! That's refreshing. Now, let's turn up the heat and see what it boils down to!

So, now to piece the string back together again. This is a little more difficult as getting a Fenix process to return a string is risky business. Therefore for now we'll use a GLOBAL declared string under the name 'recoveredString'. I hope you all know how this works. Then it's the same procedure we had before. We loop through the indexes of the byte array until we come to the end of the string(the first index with the value 0 in it). Id Est:
CODE

process convertToString()
private
int i = 0;
begin
recoveredString = "";
while(SaveString.string != 0)
recoveredString += chr(SaveString.string);
i++;
end
end



Bon Appetit!

PS: Could've done with a little less text, but hey, I had some spare time :)
 
Thanks for that! Hopefully my game can now have names together with highscores, once I'm done implementing it.
 
Tried it, but now it crashes when using the substr command instead. I did it this way :

These are my two structs :

CODE
struct Names[34]
string Name;
end

struct SaveNames[34]
byte Letter1;
byte Letter2;
byte Letter3;
end


In the beginning of the program, I load the byte-struct and convert it to the string-struct like this :

CODE
i=0;
while (i<35)
TempString="";
TempString=chr(SaveNames.Letter1)+chr(SaveNames.Letter2)+chr(SaveNames.Letter3);
Names.Name=TempString;
i++;
end


In the end, before saving the byte-struct, I convert the string-struct back into the byte-struct like this :

CODE
i=1;
while (i<34)
TempString="";
TempString=Names.Name;
SaveNames.Letter1=asc(substr(TempString,0,1));
SaveNames.Letter2=asc(substr(TempString,1,1));
SaveNames.Letter3=asc(substr(TempString,2,1));
i++;
end


And then the program crashes. It seems the substr-command causes the crash. Am I using it the wrong way? I tried to do it like this :

CODE
i=1;
while (i<34)
TempString="";
TempString=Names.Name;
SaveNames.Letter1=asc(substr(TempString,1,1));
SaveNames.Letter2=asc(substr(TempString,2,1));
SaveNames.Letter3=asc(substr(TempString,3,1));
i++;
end


But that didn't help either. Any ideas?
 
Why dont you hand the string as a character array and the save names as an integer array like this:

CODE

struct Names[34]
char Name[3];
end

struct SaveNames[34]
int letters[3];
end



CODE

for(i=0;i<35;i++)
for(j=0;j<3;j++)
Names.Name[j]=SaveNames.Name[j];
end
end



infact you may not need asc for this so it would just be:

CODE

for(i=0;i<35;i++)
for(j=0;j<3;j++)
SaveNames.Letter[j]=Names.Name[j];
end
end
 
Thanks. That worked on my computer, but not on the GP2X. The GP2X just displays numbers instead of letters. (Or rather, some kind of garbage). You think I need to use the asc-command anyway?

I also tried saving the struct with the chars directly, but that gave the same result. Perhaps the GP-version of Fenix simply cannot save structs with many elements in...
 
No, that SHOULD work fine. I use it in my game for displaying the highscores, and saving them.

Let me paste my code to write my highscores to the screen so you can compare how you are achieving it:

CODE

for(i=0;i<10;i++)
for(j=0;j<3;j++)
name[j] = scores[menu_option].name[j];
end
write(fonts[3],100,(i*15)+50,0,name);
write_int(fonts[3],220,(i*15)+50,2,&scores[menu_option].score);
end


name is the char array
scores.name is the int array in the struct
scores.score is the score in the struct
 
Back
Top