To aid me in making games, I decided that I wanted to make some a library with code that I would otherwise have to write multiple times across different projects.

So, I'm going to call it "Janus," because that's the Greek god of all beginnings [of my game projects Evil or Very Mad ].

Right now, its features include:
► Simple key debouncing
► Quick way to get frame delta time
► A system for positional easing with the following eases: LINEAR, QUAD_IN, QUAD_OUT, and QUAD_IN_OUT
► A system for drawing animated sprites with variable frame lengths
► A system for updating and drawing a "QuickUI" for rapid prototyping.
► A method for quick and easy screen-shakes.
► A limited physics system

I'll add more features as I use it in more projects, but these features are the sorts of things that I'd like to start off with.

Demo (Animated PNG):


Github (Demo Code & Program + Library): https://github.com/slimeenergyreal/janus

This was fun to make, and I'm excited to add more features that I think up while I use it.

Latest Screenshot:



In the future, I want to create a quick-start guide for using various features of Janus in games, though until then the documented janus.h header file will have to do.
Well, it's time to add more useful things to this.

Today, I've added:

► Quick UIs (A very quick way to get an interface running for a prototype)
► Screenshake (What calculators lack for audio, they make up for in shacking the screen!)

Here are those eye-candy screenshots that you expect Smile .

UI with 3 options:


QuickUIs have an enum called "QuickUILayoutStyle" which determines the way the second column of options falls into place (if applicable). The options are...

UI Style: Uniform


UI Style: Stack


UI Style: Elastic


Now, how quick are these Quick UIs?

Pretty quick. For the demo file, these were the lines needed for the UI:

Code:

/*Line 21*/
struct janus_QuickUI ui;

/*Line 40; initialized in demo struct*/
{ELASTIC,"Janus Library Demo",0,0,0xFF,0x00,0xEC,0,20,{"Play","Options","Credits","4","5","6","7","8","9","10","11","12","13","14","15","16","17","18","19","20"}}

/*Lines 49->51*/
kb_Scan();
janus_UpdateDebouncedKeys();

/*Line 65*/
bool selected;

/*Lines 83->88*/
selected = janus_UpdateQuickUI(&demo->ui);
   
if(selected) {
    demo->lastSelected = demo->ui.cursorPosition;
    janus_Screenshake(4,4,2);
}

/*Line 102*/
janus_RenderQuickUI(&demo->ui);


Animation is the hot topic of today's update.

What's the goal? First, I'm going to make an animation:

Now, the goal is to put this animation onto my calculator, and I want the ability to have variable frame lengths, so I will not need to duplicate frames and waste extra space on the calculator.

Thankfully, Janus already has a quick way to get the delta time, or time since the last frame, so this process of enabling animation in the library will be quick.

Previously, there was a struct named "janus_Animation" which animated eases, so that and any code related to it have had "animation" changed with "ease" or "easing."

Now that I can create an animation struct and its respective functions with name duplicates out of the way, I will first create a structure with all the things I need:

Code:

struct janus_Animation {
    uint24_t frameCount; // Number of frames
    gfx_sprite_t* frames[JANUS_ANIMATION_MAX_FRAMES]; // List of pointers to gfx_sprites
    bool useVariableTimings; // If true, each frame will have their own timing, specified in "variableTimings." Otherwise, each frame will have a constant framerate
    float variableTimings[JANUS_ANIMATION_MAX_FRAMES]; // Used if useVariableTimings is true - List should specify number of seconds for each respective frame
    float constantTiming; // Used if useVaraibleTimings is false - Each frame will last for this amount of time
    bool loop; // Whether or not to loop animation
    float currentElapsed; // Current progress (in seconds) in the animation; initialize at zero for most cases
    uint24_t currentFrame; // Current frame in the animation; initialize at zero for most cases
};


Then, all I need to do is create a simple implementation for updating it.

I can define the animation like this:

Code:

{
    12,{wizard_tile_0,wizard_tile_1,wizard_tile_2,wizard_tile_3,wizard_tile_4,wizard_tile_5,wizard_tile_6,wizard_tile_7,wizard_tile_8,wizard_tile_9,wizard_tile_10,wizard_tile_11},
    true,{2.0f,0.1f,1.0f,0.1f,0.1f,0.1f,0.5f,0.1f,0.1f,0.1f,0.2f,0.2f},
    0.0f,true,0.0f,0
}

...which says there are 12 frames and points to all of those frames, says to use variable frame lengths and defines all of those frame lengths per frame, sets the non-variable frame length to zero as it's not using it, sets "loop" to true so the animation loops, and sets the initial time elapsed and frame to zero as that will work best for most cases.

Then, I acquire the elapsed time since the previous frame by calling this at the top of my update function and update the animation, and after that I can render it:
(Full demo program here)

Code:

float elapsedTime = janus_GetElapsedTime();
/*
...
*/
janus_UpdateAnimation(&demo->animation,elapsedTime);
/*
...
*/
gfx_ScaledTransparentSprite_NoClip(janus_GetAnimationFrame(&demo->animation),LCD_WIDTH/2-wizard_tile_0->width*2,LCD_HEIGHT-(wizard_tile_1->height*4),4,4);


So, this is the resulting animation with custom timings:



This is what the animation would look like without custom timings (a lot worse, in my opinion):



And this is what the entire demo program looks like:


P.S.
If needed, the user can increase the maximum number of frames in the janus.h header file; I couldn't find a way to make it easy for the user to set up while also allowing them to use as many frames as they might be able to fit.
Looking good Smile You should avoid using floats wherever possible -- they are quite slow!

Also, I'm pretty sure janus_GetElapsedTime could be replaced by the clock() function.

EDIT: as for your maximum frames issue, have you considered just proving a pointer? Then the user can have as many as they want.
Time for buggy Physics

This time around I've added a simple, limited physics system to Janus. I may re-make this in the future because it's not exactly where I want it to be at, but that will probably be when I use this engine and find I need a certain functionality.

Overall, it works well enough for simple platforming, however when more than three objects are colliding, it starts to act undesirably.

To start, I created three important structures:

Code:

struct janus_Vector2 {
    int24_t x;
    int24_t y;
};

struct janus_Rect {
    struct janus_Vector2 position;
    struct janus_Vector2 size;
};

struct janus_PhysicsObject {
    struct janus_Rect rect; //Position and size of object
    struct janus_Vector2 velocity; //Velocity of object
    int24_t resistance; //How willing an object is to move against other physics objects. The higher the value, the more it will move when pushed by an object with lower value.
    bool anchored;
};

These are what the physics system uses to run.

There's a lot under the hood, but let's just take a look at how the demo implements physics using Janus. Note that object1 is the player object that can move and jump.

Here's the demo's result:


Now, you likely noticed the one ~~bug~~ feature in the physics system: collisions involving three objects do not properly resolve themselves.


If I find a reason to, I'll try to fix this, however I don't mind the bug yet because the system already does quite a lot that I needed it to. The hard part will probably be maintaining reasonable performance while supporting a robust-enough physics system to not have this ~~bug~~ feature.




How does the demo accomplish this using Janus?

First, it defines two physics objects and two static walls to collide with.

Code:

        .object1 = {
            .rect = {{10,80},{40,40}},
            .velocity = {0,0},
            .resistance = 1,
            .anchored = false
        },
        .object2 = {
            .rect = {{100,30},{40,40}},
            .velocity = {0,0},
            .resistance = 5,
            .anchored = false
        },
        .walls = {
            {.position = {0,140}, .size = {200,10}},
            {.position = {120,70}, .size = {10,70}}
        }


Then, each frame it updates the physics.

Step by step, it:

Applies the previous frame's physics object velocities to the objects' positions,

Code:

janus_ApplyVelocity(&demo->object1, deltaMS);
janus_ApplyVelocity(&demo->object2, deltaMS);


Adds gravity to each physics object's velocity,

Code:

janus_AddForce(&demo->object1,&(struct janus_Vector2) {0,7});
janus_AddForce(&demo->object2,&(struct janus_Vector2) {0,7});


Uncollides each physics object from the static walls (note: if handleObject returns true, that means the first object passed is pushing down on the other),

Code:

for(i = 0; i < WALL_COUNT; i++) {
    if(janus_HandleObjectRectCollision(&demo->object1,&demo->walls[i]))
        ableToJump = true;

    janus_HandleObjectRectCollision(&demo->object2,&demo->walls[i]);
}


Uncollides each physics object from each other,

Code:

if(janus_HandleObjectObjectCollision(&demo->object1,&demo->object2))
    ableToJump = true;


Allows the player to move and jump,

Code:

if(kb_Data[7] & kb_Right) {
    janus_AddForce(&demo->object1,&(struct janus_Vector2){PLAYER_SPEED,0});
}
if(kb_Data[7] & kb_Left) {
    janus_AddForce(&demo->object1,&(struct janus_Vector2){-PLAYER_SPEED,0});
}
if(kb_Data[7] & kb_Up && ableToJump) {
    janus_AddForce(&demo->object1,&(struct janus_Vector2){0,PLAYER_JUMP});
}


And dampens the velocities of the objects so they don't slide forever.

Code:

janus_DampenVelocity(&demo->object1,&(struct janus_Vector2){3,32});
janus_DampenVelocity(&demo->object2,&(struct janus_Vector2){3,32});


Here's a link to the update function code for physics in the demo




MateoConLechuga wrote:
Looking good Smile You should avoid using floats wherever possible -- they are quite slow!

Also, I'm pretty sure janus_GetElapsedTime could be replaced by the clock() function.

EDIT: as for your maximum frames issue, have you considered just proving a pointer? Then the user can have as many as they want.


Thank you a lot for the tips! I've completely removed floats from the code and now measure delta time in milliseconds. The clock function definitely simplified the janus_GetDeltaTime function a lot and it's a lot neater now.

I considered using a pointer for animation frames, however initializing the frames when they are a static array is easier and doesn't require the user to allocate any memory themselves like a pointer seems to. I think it's worth having an array for the quicker and easier setup.


Also, thanks to calc84maniac as well for providing tips and answers to my questions regarding pointers and arrays.




I'm really itching for a good reason to pull out this library. Right now I have a few projects going, but none of them are calculator-related aside from this one. A Cemetech Contest would be a perfect reason to pull out this library, so it's time to pray to the multitude of calculator gods that we get one 🙏.
First let me say that I think this is a spectacular project. Props, kudos, well done,... you pick the phrase. I'm blown away by what you've pulled off.

slimeenergy wrote:

I'm really itching for a good reason to pull out this library. Right now I have a few projects going, but none of them are calculator-related aside from this one. A Cemetech Contest would be a perfect reason to pull out this library, so it's time to pray to the multitude of calculator gods that we get one 🙏.

I do believe that with contests, it cannot be a project you started or worked on before the contest was announced.
ACagliano wrote:
First let me say that I think this is a spectacular project. Props, kudos, well done,... you pick the phrase. I'm blown away by what you've pulled off.

slimeenergy wrote:

I'm really itching for a good reason to pull out this library. Right now I have a few projects going, but none of them are calculator-related aside from this one. A Cemetech Contest would be a perfect reason to pull out this library, so it's time to pray to the multitude of calculator gods that we get one 🙏.

I do believe that with contests, it cannot be a project you started or worked on before the contest was announced.


Thank you a lot!

For the contests, it should be fine to use libraries, should it not? Otherwise the clibs would be off the table. I don’t mean to submit the library demo but rather use it to create a game.
slimeenergy wrote:
ACagliano wrote:
First let me say that I think this is a spectacular project. Props, kudos, well done,... you pick the phrase. I'm blown away by what you've pulled off.

slimeenergy wrote:

I'm really itching for a good reason to pull out this library. Right now I have a few projects going, but none of them are calculator-related aside from this one. A Cemetech Contest would be a perfect reason to pull out this library, so it's time to pray to the multitude of calculator gods that we get one 🙏.

I do believe that with contests, it cannot be a project you started or worked on before the contest was announced.


Thank you a lot!

For the contests, it should be fine to use libraries, should it not? Otherwise the clibs would be off the table. I don’t mean to submit the library demo but rather use it to create a game.


I'm pretty sure that last I heard it was okay to use libraries, provided that they were fully available to the public before the contest.
  
Register to Join the Conversation
Have your own thoughts to add to this or any other topic? Want to ask a question, offer a suggestion, share your own programs and projects, upload a file to the file archives, get help with calculator and computer programming, or simply chat with like-minded coders and tech and calculator enthusiasts via the site-wide AJAX SAX widget? Registration for a free Cemetech account only takes a minute.

» Go to Registration page
Page 1 of 1
» All times are UTC - 5 Hours
 
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum

 

Advertisement