Ludum Dare 51 September 30–October 3, 2022

My mind is melting help

Terry cavanagh recommends my ld game!?!?! aaaaaaaaaa this is the same guy that made dicey dungeons and vvvvvv......

https://twitter.com/terrycavanagh/status/1580942525329641473

I just can't right now

I wanna play your games!

Send them in the comments.

Maybe you could also check out my game :)))

Streaming your LD games!

This'll be my first stream of the LD season, so drop your game into the queue and I'll give it a try! Can only stream for an hour or maybe two, but I expect it'll be fairly quiet this late into the rating period.

Add to queue here

Check the queue over here

And come watch along on twitch!

Hope to see you there! :v:

Piggy’s Adventure

A glorious adventure is awaiting for our sneaky pig !

Hello everyone !! We are a group of students that created a game for the first time as well as participating in ludum dare. Therefore, after 2 challenging days we managed to make a platoformer game , nice and simple, in which the main character , a cute pig , needs to survive in the wild , eating exotic fruits and running away from predators.

We hope you’re going to play in our game and like it as much as we do . FFF32DCA-F793-471F-A33E-8976330950BC.png https://ldjam.com/events/ludum-dare/51/piggys-adventure

Do you like horror games?

Are you a horror enthusiast? Do you enjoy fun past-time activities such as looking through camera security systems, windows and doorholes? Do you like tasing mentally unstable people?

Then Peekaboo sounds like something for you: https://ldjam.com/events/ludum-dare/51/peekaboo unknown.png

How to build a rhythm game with Unity and Wwise

This is the second part of a devlog about Line Momentum, a rhythm game made for the Ludum Dare 51. The first part was about how the dynamic music system was implemented using Wwise. In this one, we'll see how to use scripts to keep track of the position in the music, and validate players input according to the rhythm. Of course, you're more than welcome to play the game.

screenshot_2.gif

So far, we've been able to send events to Wwise in order to play the music, and make it evolve with the game. But now we need the other way around: we need information coming from Wwise in order to be alerted when a beat or a new bar happen. And at each frame, we need to know with precision where we are in the track.

This is initialized at the line where we send the event to start the music. Let's write it step by step. The most basic usage is just to send the event (named StartEvent) to Wwise.

All scripts in this article are from several Game Objects. For the sake of simplicity, I won't describe their names, structure or relations. Just consider that all variables and functions declared are available to any scripts.

(c#) StartEvent.Post(gameObject); An event is always linked to a Game Object, hence why we gives the instance as the first argument.

Now we need a callback for each "music sync" events: beats, bar, etc. This is done by specifying two more arguments to the function: the type of events we want to be triggered for, and the callback function to call. For the first one, while we could be called only for bars, it's better to specify all kind of events related to music. We'll see later how to read the event's type. The next argument is a new function that we'll call OnMusicEvent, which we'll describe below.

(c#) StartEvent.Post(gameObject, (uint)AkCallbackType.AK_MusicSyncAll, OnMusicEvent);

Wait, why is the CallbackType parsed as an uint? Well, good question actually. The Post method only accepts uint, and the constant provided by Wwise happens to be a int, therefore it must be converted. Why isn't it directly the right type? I don't know, but I'm sure there must be a logical reason. For now, remember that it must be implemented that way.

Now, how does our OnMusicEvent look like?

(c#) void OnMusicEvent(object in_cookie, AkCallbackType in_type, AkCallbackInfo in_info) {

  • The first argument, in_cookie, are additional data sent with the original event. We don't use it at all here.
  • The second one in_type is the type of the event. It's with it that we'll know if the event triggered is a beat, a bar, or something else.
  • Finally in_info provides useful data about the music track itself, such as the position in seconds, or the length of a bar.

In Line Momentum, we only react to the bar events. But know that there are many more that can be useful! For example, you could have animations triggered on the beats. It's even possible to have a time unit smaller than the beat, called "grid" in Wwise, which can be configured to be aligned with quarter notes, eight notes, or others fragments.

The best pattern to sync actions from your game with music events is to use UnityEvents. A Unity Event will have several object's methods subscribed to them, and will call all of them when it is triggered. This is super useful for code organization, because it means that your objects are not dependent between each other, and can easily be plugged and unplugged to events. Personally, I even like to use a Scriptable Object as a Store with UnityEvents that any Script can subscribe to. I bet you can also scale even better with plugins such as UniRx.

But for the sake of this article, let's keep it simple, and just declare our events locally. In the music event callback, we will check the type of the event, then invoke the corresponding Unity Event.

```(c#) public UnityEvent onBar = new UnityEvent(); public UnityEvent onBeat = new UnityEvent();

void OnMusicEvent(object incookie, AkCallbackType intype, AkCallbackInfo ininfo) { if (ininfo is AkMusicSyncCallbackInfo) { if (intype is AkCallbackType.AKMusicSyncBar) { onBar.Invoke(); } else if (intype is AkCallbackType.AKMusicSyncBeat) { onBeat.Invoke(); } } } ```

Now any function can be subscribed to beat or bar events! Either from the editor GUI, or through code (using onBar.AddListener).

That's not enough though! Reacting on beats is one thing, but we still need to know at every frame what is the position in the bar! There are several use cases for it, but our first one will be to update the position of the visual indicator.

dot-movement.gif

Sure, we could use an animation or a tween for this, and make sure that it's approximately the same time as the bar. But there's a non neglectable risk that it falls out of sync eventually. Depending of the nature of your game, you might need to handle longer durations than a single bar, and there are cases where you want to be precise. You're never immune to a small lag or a music interruption. Thus your timing must always comes from the music data. Never use timers or scripted animations, unless it's not for a critical purpose (such as a short visual animation). For Line Momentum, the indicator is here to help the player get the right timing, so it must be precise!

_(Plus, doing this way means that you can pause the music and still keep everything in sync with no worries!)

Let's get back to the post of the StartMusic event! We need to track more than beats and bar. We want to be able to read directly the time position at any time. For this, we can pass the AK_EnableGetMusicPlayPosition constant as a second argument. Since we already pass AK_MusicSyncAll, we have to use a Bitwise OR (|) between the two. This option will allow us to track the music position from the player. However, we need a player ID for this. We must thus retrieve it from the Post result.

```(c#) private uint PlayerID;

// [...] When starting the music: PlayerID = StartEvent.Post(gameObject, (uint)AkCallbackType.AKMusicSyncAll | (uint)AkCallbackType.AKEnableGetMusicPlayPosition, OnMusicEvent); ```

Now, in the FixedUpdate, we can read the position in the bar by creating a SegmentInfo! For the reference, it is the same type we receive as in_info from our callback. Only this time, it's available at any time in the music.

(c#) private void FixedUpdate() { AkSegmentInfo segmentInfo = new AkSegmentInfo(); AkSoundEngine.GetPlayingSegmentInfo(PlayerID, segmentInfo, true); print(segmentInfo.iCurrentPosition); // --> position in ms }

The i in iCurrentPosition stands for int. There are other measurements in SegmentInfo that are prefixed with f, for float. Thus it indicates that it is not in milliseconds, but in seconds! This is important, because you'll want to choose one single unit when comparing values. And unfortunately, some values are only available in milliseconds, others only in seconds. So remember to convert them when needed!

Okay we have the time position in seconds now, but it's not super useful as it is. If we want to position the dot on the line, we need a value going from 0 to 1, so that we we'll never have to worry about the size of the line in pixels. We need to know the duration of a bar. Now that's something we could actually calculate by hand, using the BPM and the time signature. But what if those change during the development of the game? Your composer can have a change of mind after all. Or you could even have several tracks, with different tempo! It's better to just read them from Wwise data. While we're at it, we will also register the duration of a beat, because this data will be very useful.

We can do that in our Callback function! It will be triggered at the very start of the song for the first bar. Note that we only need to write those values once.

(c#) void OnMusicEvent(object in_cookie, AkCallbackType in_type, AkCallbackInfo in_info) { if (in_info is AkMusicSyncCallbackInfo) { AkMusicSyncCallbackInfo musicInfo = (AkMusicSyncCallbackInfo )in_info; if (in_type is AkCallbackType.AK_MusicSyncBar) { onBar.Invoke(); if (setDurations) { barDuration = musicInfo.segmentInfo_fBarDuration; beatDuration = musicInfo.segmentInfo_fGridDuration; // In Line Momentum, I used quarter notes as a "beat" setDuration = false } } // [...] } }

In FixedUpdate, we can now register the position in the bar for the dot indicator to use:

(c#) float fCurrentPosition = (float)segmentInfo.iCurrentPosition / 1000f barPosition = fCurrentPosition / barDuration

Alright, now let's tackle the big section: player interaction. The system in Line Momentum is quite simple: there are 10 beats (quarter notes) in a bar, the player must click on a selection of them. For example, on the first level, the player must click on beats number 2, 6 and 8 (beats going from 0 to 9). On level 2 it's 1, 3, 4, 6, and 8. And so on for other levels. Let's say those values are in an array called levelBeats. If the player correctly clicks on all the beats, they succeeds, if not, they fail.

Now I won't describe the whole logic of the game, because there's just too much. Instead, I'll focus on the rhythm logic that can be used for any kind of rhythm game: how to read input from the player, and also how to detect when they miss.

The first thing we need to do is to prepare the next beat that must be hit. Remember: always schedule! So, when the bar starts, we must setup the position (in seconds) of the next beat in the bar. This is calculated with the duration of a beat that we initialized earlier.

```(c#) private uint nextBeatIndex; private float nextBeatPosition;

void onBarStart() { updateNextBeatPosition(0) }

void updateNextBeatPosition(uint index) { nextBeatIndex = index; nextBeatPosition = levelBeats[index] * beatDuration; } ```

This is not the only way to write this value. Another approach is to use relative times, especially useful if you deal with long segments, where time can create delay between the theoretical beat position and their actual value. Basically it consist of reading the current position on a beat event callback, then setup the position with nextBeatPosition = currentPosition + (nbBeatsRemaining * beatDuration).

We now know exactly when the player should hit for the next beat. So when they will trigger an input, we will compare the current time to that value, which will determine if they hit correctly. However, it's absolutely impossible for players to be that precise! We need a margin error. It's a small time duration before and after the beat in which we consider the timing as still valid. It means that the time the player has to react will be twice the margin. With that in mind, let's write a function to compare if the current time is approximately the desired one:

```(c#) public float Precision = 0.08f; // Gives a 0.16 time of reaction

void isCloseTo(float time) { return Math.Abs(time - currentTime) < Precision } ```

But wait, there's a catch! Suppose that the next beat to validate is at position 0 (the very first beat). Since the bar is looping, what will happen if the player hits just before the end? That should be validated, because we are close enough to the start of the next bar. But our current algorithm will return false, because the time between 0 and the very end of the bar is, well, way higher than 0.08! I'd like to present you a one-line formula to solve this problem. If you have an idea, please share it. But as of today, we have to handle this special case.

```(c#) public bool IsCloseTo(float time) { if (Math.Abs(time - currentTime) < Precision) { return true; }

// Time is at 0
if (time < Precision) {
    return Math.Abs(barDuration - currentTime) < Precision;
}
// Time is at the end of the bar
else if ((barDuration - time) < Precision) {
   return currentTime < Precision;
}
return false;

} ```

Alright! Using this, we can now register players' input:

(c#) if (Input.GetMouseButtonDown(0) { if (IsCloseTo(nextBeatPosition)) { onValidateBeat(); // Do whatever you need to do when the player scores updateNextBeatPosition(nextBeatIndex + 1); } else if (!IsCloseTo(0f)) // Fail only if we're not close to the end of the bar { onFail(); // Register a failure } }

We're now able to detect when the player succeeds! But not when they fail. There are two ways for a player to miss a beat:

  • They clicked too soon. This is what we have already implemented: when they are not close to a targeted beat, we register the failure.
  • They clicked too late, or didn't click at all. This is what we need to implement now.

To register that a beat have been missed, we need a new function similar to IsCloseTo, to know if a time is considered as passed (that is, after the error margin).

(c#) public bool IsPassed(float time) { return currentTime > time && (currentTime - time) > Precision; }

Simple enough. But... Remember how we had issues with the start and end of the loop? Well, it's the same here. But it's mostly because of Wwise this time. As counter intuitive as it seems, currentTimer can sometime be above barDuration! But it's supposed to loop on the bar though, right? Yes, but timing in music is not an exact science. But the worse is: this can happen after the new bar event! So when we reach a new loop, after we have initialized our first target beat, there are few frames where the current time is not reset at 0, but instead slightly above the loop length. This completely breaks our calculation (because we consider being at the start of a new loop, and currentTime is still at the end). So, for this special case, the best is just to ignore the curentTime if it's near the end. Because it means that we're at the beginning, and thus no time could possibly be passed!

(c#) public bool IsPassed(float time) { return Math.Abs(barDuration - currentTime) > Precision && currentTime > time && (currentTime - time) > Precision; }

We are now able to detect when a player miss a beat! We just need to do the check in a FixedUpdate:

(c#) void FixedUpdate() { if (IsPassed(nextBeatPosition)) { onMiss(); updateNextBeatPosition(nextBeatIndex + 1); } } }

And there it is, you now have the basics to build a rhythm game! You know how to subscribe to music events, how to read the exact position in the track, how to validate a player input, and how to detect when a beat has been missed.

Naturally, there is more to it. I spared you the part of the logic that are inherent to the game's rules. There will always be exceptions, special cases to check, values to update at only precise moments, and many flags to know in which state we are. The code shared in this article are only the very basic bricks for building a rhythm game.

One last advice I could give is to use flags and Unity Events to schedule actions on timed events only. In line Momentum, there are a lot of visual updates that only happen at the start of the bar. So instead of calling an update function immediately, I usually schedule it so that it happens on the next bar.

```(c#) private bool doStuffOnNextBar = false;

void OnStart() { MusicManager.onBar.AddListener(BarTrigger) }

void OnThingHappen() { doStuffOnNextBar = true; }

void BarTrigger() { if (doStuffOnNextBar) { doStuffOnNextBar = false; DoStuff(); } } ```

Bonus exercise: you can probably use IEnumerator to yield instructions until the next bar or beat! I didn't have to do that in Line Momentum, but I had some logics like this in Godot games. Trust me, it offers really clean code!

If you're interested in the logic behind of Line Momentum, it is now available in open-source! You can check out its code, or open it with Unity or Wwise and see how it is structured.

I hope this guide was helpful to you. Those information, while available in various places in the Wwise documentation, are certainly the ones I wish I had when working for this game! Making rhythm games is tricky, but not too difficult if you have the right tools, and know how to proceed.

LD Score Chasers Winner's POV Stream

The tournament is going to start in about 30 minutes.

If you want to see the winner, come here: https://twitch.tv/kuviman

winner.png

Important moments ✨

So many things happen in our life path. Some good things happen, some bad things happen. We constantly meet different people on our way. Someone leaves and does not come back, and someone stays with us for a long time. The same is waiting for our main character.

zXieWT.png

Walk this path with our hero here or Itch

Hello

Hello

Thanks to everyone's review and feedback.

It was a pleasant surprise to wake up and see that Burger Rush is on the first page of games (well, under the Smart catagory), and just reach my personal goal of getting 50 reviews. I would like to thank everyone that gave my game a look.

If you all are still curious, give the game a good and start you Saturday off with some frantic burger construction. As for myself, I look to continue review all the other great entries in the jam.

FeLHr4eUUAA3BWX.png

Just release a post-jam update on SONAR

Hey guys, we saw how actively you commented and analyzed our game, thanks for that, it meant a lot to us! Because of that, we decided that we want to do a little post-jam update to apply your suggestions and also, make a MacOS build for those who couldn't try it on their devices.

You can find it through our jam page: https://ldjam.com/events/ludum-dare/51/sonar

or

Directly at itch.io: https://imagination-port.itch.io/sonar

About Character Development and Creation

Hi everyone, I am the artist from Call It a Day. First of all, I am very glad to hear that a lot of you love our art and graphics, and thank you all for your appreciation and feedback. I would like to share a bit about our creation process on character and animation.

The character design and creation were done by me and my teammate, fionamok05, a very talented illustrator. After confirming our main gameplay and mood, she quickly drew some sketches of the characters to give us a basic image of how they will look like.signal-2022-10-09-231328.jpg

After that, it's the real drawing time! Fiona made all the characters in AI, of course, with a lot of trial and error.Screenshot 2022-10-15 230821.png

After a few hours and some debats, we have our final.final.final version:All_char.jpg

We have all characters done on our first day of the game jam, and what remained was making them alive, which was my job. Unfortunately, I am a 3D artist with only a little bit of experience in 2d animation, so I choose the most simple way to do the job - the Unity Sprite Editor. sprite.jpg (However, I don't think that the Sprite Editor in Unity would be the best choice when it comes to 2d rigging, maybe next time I should try some other software)

Once the rig was done, it was time for animation! Also, it's my first time doing game animation, I looked up a lot of references online on game animation such as idle, walk, hurt, die, etc. Luckily, I managed to complete all the in-game animation on the second day. Here are some of them: (For the spawn animation I just made it in After Effects)Animtion_preview.gif

That's all about character creation and animation. After all, I just need to pass the files to our excellent programmers to make the game complete.

Finally, I would like to thank my amazing teammates for joining the game jam together with me. It was a very fulfilling 72 hours and I enjoyed it very very much!

Shabadoo

https://ldjam.com/events/ludum-dare/51/shabadoo

4fa8b.png

Hello. Today I have the time in order to rate games - and also explain how I created my project - Shabadoo. Its main particularity is the template which I made so as to simplify the game development. At first I thought that the OLC::PixelGameEngine (Javidx9) could be an interesting way to create my game. I don't know if you know it, but it is a single header file in pure C++ without any dependencies using OpenGL as a way to create inside a GDI+ frame a single texture on which you control every pixel. I quickly resumed how it works, but it is a great tool with many functions and a clever ECS system which reminds us of some Unity script including an appUpdate() section. However (like with Pico-8) there are harsh limitations. Ok! Let's go...

I said to myself that it could be fun to create my own Template for GameJam(s). Fundamentally it is not too hard to create a 2d game engine from scratch in pure C++ and inspired by the PGE template. The core can be developed in less than 500 code lines, but after this work I struggled hard in order to draw, shape and compute game objects. If we can understand easily what a line is (x1,y1 to x2, y2), just a moment think about a hexagon or a filled non-regular polygon... At first, I show you what is a pixel structure according to this template - and how it draws them on screen : ```(c++) struct Pixel { union { // opaque black pixel uint32_t n = 0xFF000000;

        struct
        {
            uint8_t r;
            uint8_t g;
            uint8_t b;
            uint8_t a; // alpha
        };
    };
};

(...)

bool xGameEngine::Draw(const gck::vi2d& pos, Pixel p)
{
    if (!pDrawTarget) 
        return false;

    Pixel d = pDrawTarget->GetPixel(pos);
    // escape quickly if the pixel has the same color
    if (p == d) 
        return false;

    float a = (float)(p.a / 255.0f);
    float c = 1 - a;
    float r = a * (float)p.r + c * (float)d.r;
    float g = a * (float)p.g + c * (float)d.g;
    float b = a * (float)p.b + c * (float)d.b;
    // new pixel at pos
    return pDrawTarget->SetPixel(pos, Pixel((uint8_t)r, (uint8_t)g, (uint8_t)b));
}

When I started my project canvas, I thought about a clean font in-game without any third part. I remembered a script which I made under Unity in order to write text as a single sprite. If you remember TakeYourMedsDarling (a previous entry for the LD 49), I used a system like this... How does it work? In fact, it is more or less similar to the Chip-8 font system (lol). Imagine a sprite 5x7 pixels (chip-8 used a 4x4 pixels size). Imagine now 5 bytes and their bits. For each column the function reads a hexadecimal value and each converted bit 1 becomes a colored pixel - a bit 0 becomes an alpha null pixel. So the letter A can be write with the bits : std::vector keyA{ 0x7E, 0x09, 0x09, 0x09, 0x7E }; For each letter, number or special char, I created them using 5 hexadecimal values. I wasted many time, but this font is mine – and it works as expected giving retro vibes to the game. Take a look at the function – notice how it converts a char to booleans : void xGameEngine::DrawString(gck::vi2d pos, std::string &str, gck::Pixel p, int32_t scale) { // our letters scale - only 5x7 pixels short fontX = 5; short fontY = 7; short pp = pos.x;

    if (stamp == nullptr) 
        DrawFont(fontX, fontY);
    // only lower case
    std::vector<unsigned char> byte;
    transform(str.begin(), str.end(), str.begin(), ::toupper);

    for (size_t i = 0; i < str.length(); i++)
    {
        if (str[i] == '

') { pos.y += (fontY + 1) * scale; pos.x = pp * scale; continue; }

        byte = checkChar(str[i]);

        for (int x = 0; x < fontX; x++)
            for (int y = 0; y < fontY; y++)
                if ((byte[x] >> y) & 0x1)
                    stamp->SetPixel(gck::vi2d(x, y), p); // this one !!!
                else
                    stamp->SetPixel(gck::vi2d(x, y), gck::BLANK);

        DrawSprite(pos, stamp, scale);
        pos.x += (fontX + 1) * scale; // shift to the next char
    }
}

The main difficulty had been to draw some non-regular polygons - the levels on which rebounds the colored balls. It was not too hard to draw a shape, just lines using a main **std::vector** with coordinates (x,y). I could use **std::pair**, but no... However I had no clue how I could fill shapes. There are many ways in order to fill a shape, but they wasted my tiny CPU resources - and as I said I had to use them carefully. Then I saw a raylight in the darkest fog! According to the same **std::vector** I implemented a function which checks all pixels and stores them if they are inside a non-regular polygon coordinates. However I called this function in the appCreate() section - so storing pixels during the first frame, drawing them in the appUpdate() section. The renderer was really smooth - and the resources were saved. // function in order to check if a point is inside a polygon bool xGameEngine::isPointInsidePolygon(std::vector vertices, gck::vi2d pos) { bool isInside = false; auto num_verts = vertices.size();

    for (size_t i = 0, j = num_verts - 1; i < num_verts; j = i++)
    {
        double x1 = vertices[i].x;
        double y1 = vertices[i].y;
        double x2 = vertices[j].x;
        double y2 = vertices[j].y;

        if (((y1 > pos.y) != (y2 > pos.y)) && (pos.x < (x2 - x1) * (pos.y - y1) / (y2 - y1) + x1))
            isInside = !isInside;
    }

    return isInside;
}

``` Sans titre.png

I really like the background under some games developed using Pico-8. It is like a canvas or a curtain. In my template, I had a function in order to apply a single color to each pixel so as to « clean » the main screen, but I wanted more...

In C++, we can use some ternary operator and I really like it. It is more than a simple condition variable – it allows us to develop some behavior according to a condition. I said to myself that using coordinates I could apply another color to the pixel if it has a particular feature. So I check pixels using this ternary operator :

So I got vertical lines according to the width. Then I found a tip. Simply I add +1 pixel to my game X resolution and it shifts everything on screen. Again I used a ternary operator. Finally I have some zebra lines. Sometimes a little thing can change everything...
``` // clear the entire sprite (or screen) according a specific color void xGameEngine::Clear(Pixel p, Pixel pp, int stripe) { int pixels = pDrawTarget->width * pDrawTarget->height; Pixel* m = GetDrawTarget()->GetData();

    for (int i = 0; i < pixels; ++i)
        stripe != 0 ? (i % stripe ? m[i] = p : m[i] = pp) : m[i] = p;
}

At the end, my template was able to draw many shapes. below you can see every declaration which are explicit : /////////////////////////////////////////////////////// // useful functions declarations /////////////////////////////////////////////////////// inline float map(int s, float a1, float a2, float b1, float b2); inline float computeDistance(const gck::vi2d& p1, const gck::vi2d& p2); inline float lerp(float a, float b, float f); inline vf2d GetVector(int32t nIndex, int32t fRadius, int32t fFactor); vi2d rotatePoint(gck::vi2d p, gck::vi2d axis, float angle); bool inTriangle(const gck::vi2d& p, const gck::vi2d& pos1, const gck::vi2d& pos2, const gck::vi2d& pos3); bool isPointInsidePolygon(std::vector vertices, gck::vi2d px); /////////////////////////////////////////////////////// // functions declarations in order to draw everything /////////////////////////////////////////////////////// virtual bool Draw(const gck::vi2d& pos, Pixel p = gck::WHITE); void DrawLine(const gck::vi2d& pos1, const gck::vi2d& pos2, Pixel p = gck::WHITE); void DrawFrame(const gck::vi2d& pos1, const gck::vi2d& pos2, Pixel p = gck::WHITE, bool fill = false); // simple rectangle void DrawRect(const gck::vi2d& pos, const int32t w, const int32t h, const int& angle = 0, Pixel p = gck::WHITE, bool fill = false); // rotation available void DrawTris(const gck::vi2d& pos1, const gck::vi2d& pos2, const gck::vi2d& pos3, const int& angle, Pixel p = gck::WHITE, bool fill = false); void DrawCircle(const gck::vi2d& pos, const int& fRadius, Pixel p = gck::WHITE, bool fill = false, const int& thickness = 0); void DrawPolygon(const gck::vi2d& pos, const int& fRadius, int32t fFactor, const int& angle, Pixel p = gck::WHITE, bool fill = false); // regular polygon void DrawPolygon(const std::vector vertices, Pixel p = gck::WHITE, bool fill = false); // no regular polygon void DrawSprite(const gck::vi2d& pos, Sprite* sprite, uint32t scale = 1); void DrawFont(int32t x, int32t y); // in order to write string std::vector checkChar(char c); void DrawString(gck::vi2d pos, std::string &str, gck::Pixel p = gck::WHITE, int32t scale = 1); void Clear(Pixel p, Pixel pp = VERYDARKGREY, int stripe = 0); // to clear screen each frame ``` And it is enough so as to create a game :golf:

Among all these functions I really like this one which allows to draw a regular polygon. One single function to draw a square, a pentagon, a hexagon, a heptagon or an octagon - really useful. Take a look at the way in order to fill them. Each edge has two points and the third is the center of the polygon. Then I fill these triangular shapes (as you can see, there is a function to rotate each shape or point) : ``` // check if a point is inside a triangle (used to fill regular polygons) bool xGameEngine::inTriangle(const gck::vi2d& p, const gck::vi2d& pos1, const gck::vi2d& pos2, const gck::vi2d& pos3) { int s = (pos1.x - pos3.x) * (p.y - pos3.y) - (pos1.y - pos3.y) * (p.x - pos3.x); int t = (pos2.x - pos1.x) * (p.y - pos1.y) - (pos2.y - pos1.y) * (p.x - pos1.x);

    if ((s < 0) != (t < 1) && s != 0 && t != 1)
        return false;

    int d = (pos3.x - pos2.x) * (p.y - pos2.y) - (pos3.y - pos2.y) * (p.x - pos2.x);

    return d == 0 || (d < 0) == (s + t <= 0);
}

(...)

// draws a regular polygon according to a single point, a factor and a radius
void xGameEngine::DrawPolygon(const gck::vi2d& pos, const int& fRadius, int32_t fFactor, const int& angle, Pixel p, bool fill)
{
    if (fFactor > 8) 
        fFactor = 8; // beyond 8 it's almost a circle no ?
    // sometimes a point at the center is required
    if (fill) 
        Draw(pos, p);

    for (int i = 0; i < fFactor; i++)
    {
        gck::vf2d vPoint = rotatePoint(GetVector(i, fRadius, fFactor) + pos, pos, static_cast<float>(angle));
        gck::vf2d pPoint = rotatePoint(GetVector(i - 1, fRadius, fFactor) + pos, pos, static_cast<float>(angle));

        fill ? DrawTris(pos, vPoint, pPoint, 0, p, true) : DrawLine(vPoint, pPoint, p);
    }
}

``` I could continue to explain many, many, many things about this template - and especially how I developed the physics for Shabodoo, but I guess that for now it is enough. You can try Shabadoo - and of course you can rate it. Leave a comment - I really appreciate it, and then I have a link in order to rate your own project. I hope that you liked those explanations. If I can improve some parts of my template I will share it on GitHub, but right now it is still bugged and not clearly coded. Stay tuned ++

https://ldjam.com/events/ludum-dare/51/shabadoo

Day 2 of Playing your games LIVE

Come hang out and submit your game for me to play on stream: https://www.twitch.tv/oddlyspecificgames

Play My Game: Returnal

https://ldjam.com/events/ludum-dare/51/returnal Fixed Double Jump Bug reby1.PNGrby2.PNG