Custom edit game GUI appears under selected slot

Started by Giacomo, Tue 21/03/2023 13:16:11

Previous topic - Next topic

Giacomo

Hi, people of community.
I'd like to ask you help to create a custom edit game function.

I created a button on gui menu called "edit game".

To save/load/delete a slot push the button "edit game".

If there's no saved slot and game has not began yet, display the message: "You can't edit any game now!"

Else 3 rectangles appear(available slots).

Each rectangle, when clicked, let show max 3 buttons: save, load, delete

These 3 buttons appear only when needed, under the selected slot rectangle;
if game has not began and there are saved slot, you can only load or delete them for example,
as you can't load or delete an empty slot. If you started playing you can only save on empty rectangles.

I thought to build a function for which the position of 3 buttons depends from selected slot position,as it should appear right down the rectangle once it's clicked.

Each action depends from selected rectangle, for this I thought to insert some booleans to determine which rectangle was selected before any action is triggered; once button is pressed, action is triggered and let you save/load/delete game on selected slot.
When done, reset booleans.

Thank you,
Giacomo

Khris

#1
(This answer is regarding game design with respect to save games, not addressing the technical implementation, so feel free to ignore it)

I'm wondering how suitable this approach is in general. Typically, three save slots are used for games that auto-save progress but want to allow up to three people to play simultaneously.
Since that isn't the case here, you're instead limiting the player to three slots instead of the usual hundred or so. Whether this makes sense depends entirely on the game though, i.e. whether it has story-affecting choices and/or dead ends. If yes, the limit of three seems much too small. If no, you don't really need more than one slot.

TL;DR: I can't think of any scenario in which three save slots really make sense (with the exception maybe of knowing in advance that there's going to be some epic part of the game which you want to re-play through again later).

Giacomo

Thank you, Khris.

I wanted 3 slot only because the game is a kind of prologue and it's quite short.
There's no multiple end but player's game is evaluated in the end, so I thought he might wish to try some quests again and so doesn't have to start the game from beginning.

Anyway, I have no clear idea about save/load functions yet and I would be happy to semplify the script; this is the only point for which I don't see a clear solution.

Eventually, using a single slot is a good idea. Indeed, playing the game following a walktrough would take less than an hour to complete it so maybe multiple slots are useless. Autosave is also a good idea, but if the player wants to obtain a better evalutation when game ends he will have to restart it from the beginning...

I will rephrase my idea and make it simpler.
Should post be deleted? It ended up being quite useless...

Cheers,
Giacomo

Khris

If it takes almost an hour with a walkthrough, it's at least as long as Day of the Tentacle :)

Anyway, three slots sounds fine for the type of game you describe.

To do this, have each button's click
a) store the slot in a global variable
b) show a 2nd GUI with load/save/delete buttons
These buttons in turn will do the appropriate thing based on the stored slot number: 1, 2 or 3.

You can use for instance Game.GetSaveSlotDescription(1) != null to check if slot #1 exists,l then simply not display the load and delete buttons when you setup the GUI and then turn it visible.

You can use a variable to find out if the game has started yet: simply declare a bool like game_has_started, then set it to true in the first room. That way you can do if (game_has_started) during the savegame GUI setup.

Giacomo

Thanks Khris!
Ok, maybe it takes less...haha

Thanks for the tip, I have tried something similar, but I'm still missing a lot of info! I will try it soon!


Giacomo

#5
Hi people.

I created some custom functions that can be used to open and edit the selected slot in a multiple slots GUI.
Slots are stored as buttons.
Functions are working fine so far and I hope they could be helpful.

First of all I declared two global variables:
Spoiler
Code: ags
Button* selectedButton;
int selectedSlot;
[close]

In menu GUI a button open the slot menu.
Spoiler
Code: ags
function btnEditGame_OnClick(GUIControl *control, MouseButton button)
{
  _isSlotAvailable(); //check if there is any saved slot
  if(firstMenu && !slotAvailable) player.SayAt(160, 100, 60, "You can't do anything now!");  
  
  else 
  {
    gOpenSlot.Visible = true; //my way to open slot GUI
    gMenu.Clickable = false;
  }
}
[close]

Selecting any slot triggers the same function _openSlots(int mySelectedSlot, Button* mySelectedButton):
for example:
Spoiler
Code: ags
function btnEditSlot1_OnClick(GUIControl *control, MouseButton button)
{
  if(firstMenu && Game.GetSaveSlotDescription(1) == null) player.SayAt(160, 100, 60, "Empty slot!");
//if game has not started yet and slot is empty you can't open it 
  else _openSlots(1, btnEditSlot1);
}
[close]

Function to open selected slot:
Spoiler
Code: ags

function _openSlots(int mySelectedSlot, Button* mySelectedButton)
{
  selectedButton = mySelectedButton;
  selectedSlot = mySelectedSlot;

  gEditGame.X = mySelectedButton.X; //whatever you want
  gEditGame.Y = mySelectedButton.Y+102; //whatever you want

  if(Game.GetSaveSlotDescription(selectedSlot) != null) 
  {
    btnEditGameLoad.Visible = true;
    btnEditGameDelete.Visible = true;
  }
  
  if(!firstMenu) btnEditGameSave.Visible = true;
    
  gEditGame.Visible = true;
  gEditGame.Clickable = true;
  gOpenSlot.Clickable = false;
}
[close]

Function to edit selected slot. On header I declared an enum:
Spoiler
Code: ags
enum MyEventType {
  eLoad,
  eSave,
  eDelete, 
};

function _editSelectedSlot(  MyEventType myEvent)
{
  if(myEvent == eLoad)  RestoreGameSlot(selectedSlot);
  else if(myEvent == eSave)
  {
    SaveGameSlot(selectedSlot, dateTimeFormat);
    _slotBackground(); //function to get image for saved game, for which I'll soon ask a question!
  }
  else if(myEvent == eDelete) DeleteSaveSlot(selectedSlot);
  
  selectedSlot = 0;
  gMenu.Clickable = true;
  gOpenSlot.Clickable = true;
  btnEditGameDelete.Visible = false;
  btnEditGameLoad.Visible = false;
  btnEditGameSave.Visible = false;
} 
[close]

Function to check if any slot is available:
Spoiler
Code: ags
function _isSlotAvailable()
{
  slotAvailable = false;
  for (int k = 1;  k<4;  k++) //I use slots from 1 to 3
    if (Game.GetSaveSlotDescription(k) != null) slotAvailable = true;
}
[close]

Giacomo

#6
I would like to ask one more thing...

I'd like to fill the slot buttons image with a custom frame.

I have tried a lot with dynamic sprites and drawing surfaces functions,
but I'm not able to create an image containing a little part of the background(around player position),
including player and characters.


I've found an interesting function made by Khris but can't find the topic anymore.
Anyway, it wasn't perfectly suitable with my case and I've modified it do some tries.

I'm not able to merge background frame and player current frame and put them in slot graphic.
I was able to create them separetely and I wonder if it's possible to merge two dynamic sprites somehow.

Also, when I load game and open slots menu, no image appears.

Can you please help me?

Thanks,
Giacomo




Khris

You can let AGS take a screenshot and put it in the savegame, then use that image: DynamicSprite.CreateFromSaveGame

Or take a screenshot directly: DynamicSprite.CreateFromScreenShot

You can then crop the resulting sprite based on the player's position.

Giacomo

Thanks Khris, I have tried it but the result of the sprite was weird;

If you say it works I will try it again, maybe I made some errors!





Giacomo

#9
I've tried again and it works fine if I insert integers in params: myDynSprite.Crop(80, 75, 80, 50); //this works
If I write player.x and .y,likewise as cRoger or character as array it ends up returning a messed up draw.

I wonder if this is fixable, either I'll have to find another somethig else.

[EDIT] Maybe this method cannot read character position because the coordinates it takes has nothing to do with player's coordinates.
I ensured to get the right x and y before cropping.
I had already tried storing player coordinates in two integers before calling Crop but neither it worked.


Khris

You can't just insert the coordinates directly, you need to calculate appropriate values and clamp them to the screen edges.
Like if you want to use an 80 x 50 pixel image, you'd use player.x - 40 for the x coordinate and player.y - 30 or something suitable like that for the y coordinate. You also need to check if the result is too small or too big because the player is close to the edge.
As in:
Code: ags
  x = player.x - 40;
  if (x < 0) x = 0;
  if (x >= 240) x = 240;

Giacomo

Thank you Khris... I am an idiot!

SMF spam blocked by CleanTalk