Out of Memory - Title, Menu, & Character Selection Screens

Bruce

Active member
Hello everyone,

I've posted my question regarding to this issue in another topic, but I think it is better for me to create a topic and post all my code.
I started learning how to add backgrounds and animations with arraylist to the title, menu, and character selection screens.
If I just start the game normally, there is no issue.
If I just loop the title, menu, then character selection screens back and forth for a while (40-50 times),
it would cause out of memory. I know that no one would be crazy enough to loop the screens back and forth like this,
but still it should not be out of memory if it was coded correctly.
Furthermore, if I start the game and then quit the game, and repeat the loop above, it causes out of memory alot quicker.
Also, if I don't comment out these 2 functions in the title screen
Code:
ClearGlobalArrays();  
SetupArrayLists();
and
Code:
ClearGlobalArrays()  in inLevelLoop(),
it causes out of memory alot quicker. It seems like it adds more stuff to the memory instead of removing them when I start looping back and forth , but why?????

Obviously, I didn't code it correctly....
Please any help, advises, comments to help me with better coding/route/understanding, would be greatly appreciated

Video link: Out of memory at the end of the video
Notice: this is just a tryout...

updated.c
Code:
#include "data/scripts/common/constants.h"
#include "data/scripts/story/story_clear.c"
#include "data/scripts/story.c"
#include "data/scripts/gettick.c"
#include "data/scenes/ScreenAnim.c"

#define BG_TITLE1          0
#define BG_TITLE2          1
#define BG_MENU1           2
#define BG_MENU2           3
#define BG_SELECT1         4
#define BG_BLK             5

//       ANIM_TITLE0       0   // NOT USED
#define ANIM_TITLE1        1                        
#define ANIM_TITLE2        2
#define ANIM_TITLE3        3
#define ANIM_TITLE4        4
#define ANIM_SELECT1       5
#define ANIM_SELECT2       6



void oncreate(){  
    InitializeVariables();
}

void ondestroy(){
    log("LOG: ON_DESTROY \n");
    ClearGlobalArrays();
    clearStory();
    clearglobalvar();
    clearlocalvar();
}

void main()
{
    if(openborvariant("current_scene")=="data/levels/scenes/credits/credits.txt")
    {
        clearStory();
        InitializeVariables();
    }
   
    mainLoop();
   
    if(openborvariant("in_selectscreen")){
        int TitleCounter = getlocalvar("TitleCounter");
        if(TitleCounter > 0){
    /*    ClearGlobalArrays();   //these causing the out of memory much quicker!
            SetupArrayLists();  */
            setlocalvar("TitleCounter", 0);
            void TitleAnimList = getglobalvar("List_TitleAnim");
            if(TitleAnimList != NULL())
            {               // GlobalVarIndex, Entity, XYZ
               SpawnScreenAnim(ANIM_SELECT1, "SelectAnim1", 961, 541, -2000);
               SpawnScreenAnim(ANIM_SELECT2, "SelectAnim2", 800, 500, 1);
            }  
        }
        void BG_List = getglobalvar("List_TitleBG");
        void SelectBG = get(BG_List, BG_SELECT1);
        if(SelectBG != NULL()){
            changedrawmethod(NULL(), "alpha", 0);
            drawsprite(SelectBG, 0, 0, 0);
        }
    }
}

void mainLoop()
{
    if(openborvariant("in_level")){
        inLevelLoop();
    }
    else
    {
        if(openborvariant("current_scene") == "data/scenes/intro.txt"){
            int TitleCounter = getlocalvar("TitleCounter");
            if(TitleCounter == NULL() || TitleCounter > 0){
                setlocalvar("TitleCounter", 0);
            }
        }

        else if(openborvariant("in_titlescreen")){
            int TitleCounter = getlocalvar("TitleCounter");
            if(TitleCounter != 1){
                clearStory();
                // InitializeVariables();
                playwebm("data/scenes/Press_Start_Screen.webm", 0);  // 0 = skippable
               
                void TitleAnimList = getglobalvar("List_TitleAnim");
                if(TitleAnimList != NULL())
                {
                    void SelectAnim1 = get(TitleAnimList, ANIM_SELECT1);
                    if(SelectAnim1 != NULL()){
                        killentity(SelectAnim1);
                    }
                    void SelectAnim2 = get(TitleAnimList, ANIM_SELECT2);
                    if(SelectAnim2 != NULL()){
                        killentity(SelectAnim2);
                    }
                }
                   
                if(TitleAnimList != NULL())
                {               // GlobalVarIndex, Entity, XYZ
                   SpawnScreenAnim(ANIM_TITLE1, "TitleAnim1", 500, 500, -1);
                   SpawnScreenAnim(ANIM_TITLE2, "TitleAnim2", 800, 500, -1);
                }              
               
                setlocalvar("TitleCounter", 1);
                playmusic("data/music/Title.ogg", 1);
            }
           
            drawstring(20,20,0, "TITLE");
            void BG_List = getglobalvar("List_TitleBG");
            void TitleBG = get(BG_List, BG_TITLE1); // see SetupArrayLists() for details
            if(TitleBG != NULL()){
                changedrawmethod(NULL(), "alpha", 0);
                drawsprite(TitleBG, 0, 0, -2);
            }
            void BlackMask = get(BG_List, BG_BLK);
            if(BlackMask != NULL()){
                changedrawmethod(NULL(), "alpha", 6);  // 50% transparency
                drawsprite(BlackMask, 0, 0, -1);
            }          
        }
       
        else if(openborvariant("in_menuscreen")){
            drawstring(20,20,0, "MENU");
            int TitleCounter = getlocalvar("TitleCounter");
             if(TitleCounter != 2)
            {
                setlocalvar("TitleCounter", 2);
                playmusic("data/music/Menu.ogg", 1);

                void TitleAnimList = getglobalvar("List_TitleAnim");
                if(TitleAnimList != NULL())
                {
                    void TitleAnim1 = get(TitleAnimList, ANIM_TITLE1);
                    if(TitleAnim1 != NULL()){
                        killentity(TitleAnim1);
                    }
                    void TitleAnim2 = get(TitleAnimList, ANIM_TITLE2);
                    if(TitleAnim2 != NULL()){
                        killentity(TitleAnim2);
                    }
                }
             }    
   
            void BG_List = getglobalvar("List_TitleBG");
            void MenuBG = get(BG_List, BG_MENU1);
            if(MenuBG != NULL()){
                changedrawmethod(NULL(), "alpha", 0);
                drawsprite(MenuBG, 0, 0, -1);
            }
            void BlackMask = get(BG_List, BG_BLK);
            if(BlackMask != NULL()){
                changedrawmethod(NULL(), "alpha", 6);  // 50% transparency
                drawsprite(BlackMask, 0, 0, -1);
            }
        }
    }
}

void InitializeVariables()
{
    setglobalvar("LevelFirstStart", 1);
    SetupArrayLists();
}

void inLevelLoop()
{
    turnWhite();
    storySystem();
    int LevelFirstStart = getglobalvar("LevelFirstStart");
    if(LevelFirstStart > 0)
    {
        setglobalvar("LevelFirstStart", 0);
        // ClearGlobalArrays();
    }
}
   
void SetupArrayLists()
{
    void TitleBG_List = getglobalvar("List_TitleBG");
    if(!TitleBG_List || TitleBG_List == NULL())
    {
        TitleBG_List = array(2);  //array(2) means total of 3 items
        set(TitleBG_List, BG_TITLE1, loadsprite("data/scenes/TitleScreen.png"));
        set(TitleBG_List, BG_TITLE2, NULL());
        set(TitleBG_List, BG_MENU1, loadsprite("data/scenes/MenuScreen.png"));
        set(TitleBG_List, BG_MENU2, NULL());
        set(TitleBG_List, BG_SELECT1, loadsprite("data/bgs/select.png"));
        set(TitleBG_List, BG_BLK, loadsprite("data/scenes/black.gif"));
        setglobalvar("List_TitleBG", TitleBG_List);
    }

    void AnimList = getglobalvar("List_TitleAnim");
    if(!AnimList || AnimList == NULL())
    {
        AnimList = array(3);  //array(3) means total of 4 items
        set(AnimList, 0, NULL());  //  NOT USED
        set(AnimList, ANIM_TITLE1, NULL());  // Title Animation 1
        set(AnimList, ANIM_TITLE2, NULL());
        set(AnimList, ANIM_TITLE3, NULL());
        set(AnimList, ANIM_TITLE4, NULL());
        set(AnimList, ANIM_SELECT1, NULL());
        set(AnimList, ANIM_SELECT2, NULL());
        setglobalvar("List_TitleAnim", AnimList);
    }
}  
   
void ClearGlobalArrays()
{
    int i;
    void BG_List = getglobalvar("List_TitleBG");

    if(BG_List)
    {
        for(i=0; i<size(BG_List); i++)
        {
            set(BG_List, i, NULL());
        }
        free(BG_List);
        setglobalvar("List_TitleBG", NULL());
    }
    void Anim_List = getglobalvar("List_TitleAnim");
    if(Anim_List)
    {
        for(i=0; i<size(Anim_List); i++)
        {
            set(Anim_List, i, NULL());
        }
        free(Anim_List);
        setglobalvar("List_TitleAnim", NULL());
    }
}

ScreenAnim.c:
Code:
void SpawnScreenAnim(int ArrayIndex, void AnimatedEntity, int X, int Y, int Z)
{
        void vSpawn;
        void subent;

        void AnimList = getglobalvar("List_TitleAnim");
        if(AnimList != NULL())
        {
            void TitleAnim = get(AnimList, ArrayIndex);
            if(TitleAnim != NULL()){
               killentity(TitleAnim); //Kill previous spawned enity to avoid duplicated entities
            }
        }
       
        loadmodel(AnimatedEntity); // name of the entity to be loaded
        clearspawnentry(); // clean the spawn entry
        setspawnentry("name", AnimatedEntity); // define the entity to be spawn
        setspawnentry("coords", X, Y, Z); // set the position of the entity
        subent=spawn();  //  spawn the entity
        if(AnimList != NULL())
        {
            set(AnimList, ArrayIndex, subent);
            setglobalvar("List_TitleAnim", AnimList);
        }
        changeentityproperty(subent, "position", X, Y, Z);//for safe, set again the position

}

SelectAnim1.txt
Code:
name         SelectAnim1
health         1
type         panel
speed         10
shadow     0
setlayer     -2000
facing         1

anim idle
    loop 1 1
    offset    961 541
    delay    15
    @cmd changeentityproperty getlocalvar("self") "direction" 1
    frame    data/scenes/SelectAnim/SelectAnim01.png
    @cmd changeentityproperty getlocalvar("self") "setlayer" -2000
    frame    data/scenes/SelectAnim/SelectAnim02.png
    frame    data/scenes/SelectAnim/SelectAnim03.png
    frame    data/scenes/SelectAnim/SelectAnim04.png
    frame    data/scenes/SelectAnim/SelectAnim05.png
    frame    data/scenes/SelectAnim/SelectAnim06.png
    frame    data/scenes/SelectAnim/SelectAnim07.png
    frame    data/scenes/SelectAnim/SelectAnim08.png
    frame    data/scenes/SelectAnim/SelectAnim09.png
    frame    data/scenes/SelectAnim/SelectAnim10.png
    frame    data/scenes/SelectAnim/SelectAnim11.png
    frame    data/scenes/SelectAnim/SelectAnim12.png
    frame    data/scenes/SelectAnim/SelectAnim13.png
    frame    data/scenes/SelectAnim/SelectAnim14.png
    frame    data/scenes/SelectAnim/SelectAnim15.png
    frame    data/scenes/SelectAnim/SelectAnim16.png
    frame    data/scenes/SelectAnim/SelectAnim17.png
    frame    data/scenes/SelectAnim/SelectAnim18.png
    frame    data/scenes/SelectAnim/SelectAnim19.png
    frame    data/scenes/SelectAnim/SelectAnim20.png
    frame    data/scenes/SelectAnim/SelectAnim21.png
    frame    data/scenes/SelectAnim/SelectAnim22.png
    frame    data/scenes/SelectAnim/SelectAnim23.png
    frame    data/scenes/SelectAnim/SelectAnim24.png
    frame    data/scenes/SelectAnim/SelectAnim25.png
    frame    data/scenes/SelectAnim/SelectAnim26.png
    frame    data/scenes/SelectAnim/SelectAnim27.png
    frame    data/scenes/SelectAnim/SelectAnim28.png
    frame    data/scenes/SelectAnim/SelectAnim29.png
    frame    data/scenes/SelectAnim/SelectAnim30.png

Thank you very much
 
@Bruce

As @O Ilusionista said, you should never cut sprites with all that baked in special effect crap, for many, many reasons - and I already explained this to you at length. On top of that, unless I am mistaken, you're using Final Fight LNS as a base, which we also explained is a problem. So essentially, you ignored our advice and now you're having issues because of it. Do you see the disconnect? I'm not trying or wanting to be unfriendly, but there are simply too many moving parts here for us to help you.

It is NOT the black color - OpenBOR doesn't even know what an RGB value is, and it doesn't care. The first color in a table is the transparent color, full stop.

It is NOT the sprite size - OpenBOR can address up to 2GB of RAM. 70 sprites at 200KB each is roughly 1% of that, and that's before the engine's triming and auto optimizing.

Maybe someone else would have some guesses, but at this point there's nothing more I can offer here. I would consider looking at a copy of your game privately and seeing what I can do with it, but I would have to charge you for my time.

DC
 
As @O Ilusionista said, you should never cut sprites with all that baked in special effect crap, for many, many reasons - and I already explained this to you at length. On top of that, unless I am mistaken, you're using Final Fight LNS as a base
I do apologize. I realized FF LNS wasn't a good go_by and I actually took you guys advice not to use FF LNS as the go_by and decided to make my own game by learning as much as I can from this forum.
I have no intention to ignore you guys advice as you guys have so many years of experience.
Please let me explain:
Devil May Cry, Final Fantasy, Marvel, etc.. series were one of the best games I liked. Sadly there are no good HD sprites for them, so I decided to look into the UMVC3 (which has a lot of characters that I like) to see if there is a way for me to get the sprites off it. I found a way to change the stage background color and turn most effects off although the sprites don't look perfect, but they are good enough for me as I am not a professional game creator. Therefore, I can not expect my game to be perfect and I also always love high resolution graphics stuff....
However, supers and some others are the sprites that I am having problem with since I can not find a way to change the stage black background color to some thing else.

It is NOT the black color - OpenBOR doesn't even know what an RGB value is, and it doesn't care.
What I meant about the black color background is that there is no way for me to remove the black color background to make it transparency because it would ruin the sprites.
The first color in a table is the transparent color, full stop
Can you please help me understand this? sorry I am still newbie on this. Does this mean the sprite has to have the transparent color as the first color or else the game won't work properly?
How do I make the first color as the transparent color when the sprite is full of stuff in it. For example the menu Screen Sprite, etc.. please attachment as an example.


Regardless, I still very appreciate for all your help anyway.
Thank you and God bless you
 

Attachments

  • Frame00342.png
    Frame00342.png
    1.9 MB · Views: 1
Does this mean the sprite has to have the transparent color as the first color
Yes, like the example below where the pink color will never appear in the game.

1719438392172.png

In your case, it's the black color.

1719438490263.png

And if I just change the first color in your table, this is how your sprite will look like (without the pink color, of course). Note that you still have some dark tones, usually if you make the special effects separate from the characters, like @O Ilusionista suggested, you will have a much better control due to individual management.

Sometimes I use alpha mode 1 for special effects and it can remove all the darker tones, once alpha 1 prioritizes brighten colors. But in your case the effects are mixed with the character, I think it will not solve your problem.

1719438569436.png
 
Yes, like the example below where the pink color will never appear in the game.

View attachment 8417

In your case, it's the black color.

View attachment 8418

And if I just change the first color in your table, this is how your sprite will look like (without the pink color, of course). Note that you still have some dark tones, usually if you make the special effects separate from the characters, like @O Ilusionista suggested, you will have a much better control due to individual management.

Sometimes I use alpha mode 1 for special effects and it can remove all the darker tones, once alpha 1 prioritizes brighten colors. But in your case the effects are mixed with the character, I think it will not solve your problem.

View attachment 8419
So basically, my sprite already has a black color transparent color as the first color?
Even if I change the black color to pink, it still overloads the memory when I have 150+ of these sprites. This is what I don't understand. Converting 24rgb to 8-bit index is always tricky for me.
I've even followed DC's index conversion instruction and set bright color as the first color, it still overloads the memory.
I'm wondering if I need to remove the black color background to make transparent first before adding pink color to it.

Thank you
 
it does but sometimes its not actually THAT BLACK color that is used for background, if you have multiple black colors and you will from this type of image - you will get black background that is not filled with first color in the palette but with some other black from the palette , so make sure the actual background is filled with first color in the palette.Does not even have to be black cause it will be invisible anyways.
 
Even if I change the black color to pink, it still overloads the memory when I have 150+ of these sprites
I don't think this is the cause, SORX has 9000+ sprites with many different palettes and never overloaded the memory. I still think you may have a script issue somewhere.
Question, what engine build are you using? Is this some non official version?

1719441081160.png
 
I don't think this is the cause, SORX has 9000+ sprites with many different palettes and never overloaded the memory. I still think you may have a script issue somewhere.
Question, what engine build are you using? Is this some non official version?

View attachment 8421
it is OpenBOR Build 6.3.9.1, and I downloaded it from this forum, so it should be official build.
thank you
 
Your res is 960x480... i dont know, maybe its just too much for the engine to display fullscreen png sequences like this for a long time.
Try to use just 2 frames from sequences, see if its happening as well.
 
Your res is 960x480... i dont know, maybe its just too much for the engine to display fullscreen png sequences like this for a long time.
Try to use just 2 frames from sequences, see if its happening as well.
My game resolution is 1080P (1920 x 1080), not 960x480. DC said the engine can handle thousands and thousands of high resolution.
For those super sprites, I was not able to remove the background to make them transparency first before converting them to the 8-bit index. Maybe this could be an issue.
thank you
 
I have one game at 1080, i tested 4k, 1080 and inbetweens, settled for 720p now , try sequence with 2 frames.
Transparency will eat ton of CPU processing.

Openbor "can" handle even over 9000p , so DC was right in theory - in practice the game will run until you start adding effects - it will start losing fps even on GPU from the future.
So you will get like 15fps and what kind of experience is that - which is why idisagree with DC on this.
Runs ? Yes , but is it managable to build a game with that resolution ?

Not really , maybe if you have only 1 bg/fglayer, not many effects, then maybe. 1080p isnt that demanding.But "thousands of high resolutions" is just a theory.

There arent many people who did hires games with openbor, im one of them and i dont know anyone else who did 1080 besides you.

Openbor is not using GPU, im on RTX3090 but still get frame drops with a couple fglayers .

Always test ahead before diving and spending time creating big assets.

Id say try to test your sequences in game, on stage to see if youll get performance drops.Try with 10 frames, try with 2 frames.
You will get to the core of the problem fast if You will test like this.
 
Last edited:
@Bruce When using sprites for custom title and select menus you need to be very careful to keep freeing up the sprites on every cycle. here is the code from my custom menu. on the code notice I run ondestroy(); towards the end of the script to free up all sprites.

Greatly appreciated as I am still newbie and learning on how to clear stuff out of the memory after it is done.
I will take at it when I get home, thank you so much.
 
I have one game at 1080, i tested 4k, 1080 and inbetweens, settled for 720p now , try sequence with 2 frames.
Transparency will eat ton of CPU processing.

Openbor "can" handle even over 9000p , so DC was right in theory - in practice the game will run until you start adding effects - it will start losing fps even on GPU from the future.
So you will get like 15fps and what kind of experience is that - which is why idisagree with DC on this.
Runs ? Yes , but is it managable to build a game with that resolution ?

Not really , maybe if you have only 1 bg/fglayer, not many effects, then maybe. 1080p isnt that demanding.But "thousands of high resolutions" is just a theory.

There arent many people who did hires games with openbor, im one of them and i dont know anyone else who did 1080 besides you.

Openbor is not using GPU, im on RTX3090 but still get frame drops with a couple fglayers .

Always test ahead before diving and spending time creating big assets.

Id say try to test your sequences in game, on stage to see if youll get performance drops.Try with 10 frames, try with 2 frames.
You will get to the core of the problem fast if You will test like this.
Thank you very much for all the tips.
How do I perform the core test?
Right now I am still using the Opebor template stages which is in low resolution and it seems to run fine without the effects.
I am afraid you are right that it is going to be low fps once I start building HD stages and adding skill effects.
When I have time, I film all the moves I have right now and put it on Youtube for you to check out and see if it is ok.

Thank you
 
Openbor is not using GPU, im on RTX3090 but still get frame drops with a couple fglayers .
According to some DC's explanation in this post, OpenBOR runs in software mode, which means that only the CPU power will be used no matter your GPU. But in Bruce's case it seems that there's a memory leak somewhere maybe due to scripts.

1719514530097.png


@msmalik681 Buddy, how is the correct usage of oncreate/ondestroy in the update/updated.c? I tried to use it sometimes but it crashes, the only way it worked was when I disabled the "alwaysupdate" in the script.txt, but it will break other things in my case.
 
This file I uploaded is a ondrawscript for a entity. as explained in my video at the start of my game I move to a level set and spawn a entity custom_menu with that ondrawscript.
 
oncreate/ondestroy
Excuse me for newbie question. Please help me understand these functions.
When I did the log tests, it looked like - for oncreate: it only triggered when the game first started. For ondestroy, it only triggered when the game completely shut down.
That's what showed on the logs...
If the game is shutting down, why would we care to reset stuff in the ondestroy?
Thank you
 
Excuse me for newbie question. Please help me understand these functions.
When I did the log tests, it looked like - for oncreate: it only triggered when the game first started. For ondestroy, it only triggered when the game completely shut down.

On destroy runs when a script is unloaded. Different scripts unload at different times.

If the game is shutting down, why would we care to reset stuff in the ondestroy?

Because there might be resources that need removal, and if you don't the engine is left wondering, so it does the cleanup itself - but will put warnings into the log by design, and your game will look very unprofessional.

DC
 
Gameplay sample. It'ss still in very early stage - no effects and a lot of things need to be adjusted, etc.

Gameplay sample

Updated: My computer is a non-gamer computer - bought it 3-4 years for $500-600, and it is running fine so far, I think even with effects and stuff, it should be still fine in 1080P. However, I think the game would run a lot smoother with better graphics card and cpu though.
 
Last edited:
4-Player Mode Performance Test in 1080P Resolution.
I didn't spend much time creating the palettes, so please ignore the character palettes.
It seems to run very well in 1080p on 4-5 years old non-gamer computer.

 
Last edited by a moderator:
Back
Top Bottom