You are browsing as a guest. Sign up (or log in) to start making projects!

Ankush

@Ankush

Joined June 14th, 2026

  • 24Devlogs
  • 3Projects
  • 2Ships
  • 30Votes
studip dude doing stupid thing
Open comments for this post

6h 18m 30s logged

Preformance Checkup + Audio System

Things I did:

  • I stress tested my game to work with 512 & 1024 entities. Ran under 3ms and 5ms. The difference maker was the number of entities currently in the screen (rendering).
  • Profiled all the “slow” parts
  • Implemented sound system, for menu and game
  • Recorded the sounds myself!! (both in-game and ui)!

Performance

I tried my best to find ways to increase speed in my game. Unfortunately, all the things that I thought were “slow” weren’t actually slow.

  • Orui UI build was like under 50micro seconds.
  • Orui Rendering was under 250micro seconds.
  • Animation system ran under 50micro for all entities combined iirc

So, for now, there has been done no performance improvements this devlog

Sound System

First I made the sound system simple, for the menu. It worked and I was happy. I made 6 different similar sounds for the hover and click actions, and I play one of them randomly when clicked.

menu_hover_sounds: [6]rl.Sound
loadMenuSounds :: proc() {
	for i in 0 ..< len(menu_hover_sounds) {
		path := fmt.ctprintf("res/audio/menu/menu_click_%d.wav", i + 1)
		menu_click_sounds[i] = rl.LoadSound(path)
	}
}

playMenuHoveredSound :: proc() {
	i := rand.int_max(len(menu_hover_sounds))
	rl.PlaySound(menu_hover_sounds[i])
}

When I went on to make the Player sounds, I noticed that I am unable to the same sound twice simultaneously. I needed that so that I can simulate multiple enemies and other stuff.

So I googled a bit, found this raylib example. And implemented it. For both menu and entities.

TOTAL_ALIASES :: 4
Sound :: struct {
	aliases: [TOTAL_ALIASES]rl.Sound,
	index:   int,
}

loadSound :: proc(path: cstring) -> Sound {
	sound: Sound
	sound.aliases[0] = rl.LoadSound(path)

	for i in 1 ..< TOTAL_ALIASES {
		sound.aliases[i] = rl.LoadSoundAlias(sound.aliases[0])
	}

	sound.index = 0
	return sound
}

playSound :: proc(sound: ^Sound) {
	rl.PlaySound(sound.aliases[sound.index])
	sound.index = (sound.index + 1) % TOTAL_ALIASES
}

playMenuClickedSound :: proc() {
	i := rand.int_max(len(menu_click_sounds))
	playSound(&menu_click_sounds[i])
}

I also stole borrowed :evilrondo: this really great background music from raylib source.

0
0
11
Open comments for this post

5h 18m 23s logged

Health System, Enemy Attack, 15 new Skin!

Summary of Features added:

  • Player/Enemy Attacks
  • Health System (Damage/Heal)
  • Health Bar shown
  • 15 new Skins!
  • Avatar Menu “Set” Selector

Avatar Set Selector

This took a lot of time than I would like. I first had to scourge through 100s of directories for each Skin (each skin has 3 “tiers”) and get the 0th “idle” animation sprite.

The next part was pretty straight forward owing to the time I took to make the architecture great :3

Health Bar

This wasn’t hard as per say. But it is mad slow. I realised it earlier but never mentioned it. orui library is slow. UI libraries aren’t meant to be this slow. Probably it is due to the rendering that makes it this much slower.

How slow? My renderer could render 50 entities under 1ms, now it takes ~5ms to render 20 entities.

Future Todos:

  • Performance. I will track down where orui is slow. If it is in the logic part, we can’t do anything as I am not smart enough to fix logic so complex. But if it is related to rendering, we can work with that.
  • Performance. It’s been a while since I diagnosed the slow parts in my code. I will deep dive into the code. Find out what is slow and try to fix them

The next few days, I will work on to squeeze as much performance as I can from this game.

0
0
29
Open comments for this post

9h 42m 24s logged

Enemy AI done + Tons more!

Other things done this time around:

  • Fix: WASM build fixes
  • Feature: Added the back button in Avatar Menu (finally)
  • Fix: The character scale and position in Main/Avatar Menu acted funny in extreme dimentions (when too small)
  • Fix: Physics renderer didn’t render polygons with 4 vertices
  • Feature: Added physics colliders for all enemies!
  • Feature: Y-Sorting enabled
  • Performance: Pushed Data Oriented Design for max performance
  • Architecture: Moved the files around, where they make more sense
  • Feature: Implemented Attacking
  • Feature: Player & Enemy State machine
  • Feature: Enemy AI (super basic tbh)

Performance

All of these changes were made keeping performance in mind. As of right now the state machines need work to make them even faster!

Obstacles

State machine logic is very mind numbing, I won’t want to do that…. a lot of edge case problems. A lot of problems I never thought existed.

Y-Sorting was also in the harder side because I wanted a fast sort while also not needing to change the whole array of entities. I finally decided to use another array render_list of type []int this essentially sorts the id (or index in this case) of the entities by entity.pos.y. When rendering use the ids to render. This proved to be a more efficient way to do it, than sorting the entire array of entities.

Future Todos

  • Implement Enemy attacking
  • Implement health system (with regenability?)
  • Draw the health bar
  • Implement death

After these things are done. We I will think of further things like game win/game end amongst many others like game pause.

0
0
6
Open comments for this post

5h 39m 56s logged

Dozens of small features implemented!

  1. Migrated the End screen UI to the new UI library
  2. Brought back the physics collider with water from previously deleted code.
  3. Removed a rouge sleep call in loading phase. (Which was put there for testing :hs: )
  4. Instead of drawing rectangles in when playing. We now draw the characters! With randomly generated skins!!
  5. Migrated Playing and loading UI to the new library
  6. Code cleanup and refactored for better architecture

Culling #bd56fa

When adding Culling to player rendering, I got an optimisation of 5ms->2ms.

Animation while playing

The initial phase was very easy. What I did struggle with was flipping the image. First, I tried flipping the texture themselves.

It did work but the offset of the bones were not in place. It was fine when going right, but when I turn left. It all turns bad, the 2nd video is a demonstration of that.

It took a lot of tweaks and black magic to find out that I had to also flip the anchor position and angle too 😭

Now it is working as intented :)

0
0
8
Ship

IceKeem is a slack bot that helps me out with my channel!


This is the 2nd ship for my bot, and is on the smaller side.


This update, I added the home page for my bot, added @mention replies. There are some fun pre-determined replies for @mentions, but when none match, the input is passed down to an AI to answer.


I learnt a lot while making this bot, had a lot of fun. I got to know a lot about slack bots and how slack works.


I am really proud of the banner image I made! Apart from that, I am so happy to be able to bring back the chonky button that a user gets to press when they join my channel!

### Trying out my bot
Most of the bot commands like `/icekeem-ping`, `/icekeem-blog` and `/icekeem-help` work from anywhere, but if you want to use @mention you have to join my channel. [#ankush-loves-icecream](https://hackclub.enterprise.slack.com/archives/C09CT01115K)


You should defo join my channel :3


I hope you have fun with my bot!

### Features in a glimpse
- 3 commands `/icekeem-ping`, `/icekeem-blog` and `/icekeem-help`
- Personal channel join and leave triggers
- Button interactions
- Home page
- @mention replies

  • 1 devlog
  • 3h
  • 7.78x multiplier
  • 26 Stardust
Try project → See source code →
Open comments for this post

3h 19m 16s logged

Slack bot home page done!

Along with that I also added tags of my blogs to my carousal. Most of the hard part was debugging why my Home page wasn’t showing up properly. It was because I forgot to add error reporting :heavysob:

I also spent a long time trying to add images to my hope page. The images didn’t just work! After a lot of time googling, I think it is because the image block can’t render svg files :pf:

Lastly, I also added @mention replies to my bot. There are a few fun pre-determined replies and when the input matches none, it passes the input to a free tier model of Gemini called Gemini Lite Flash 3.1

Some BTS

I had a lot of love and passion for this bot, and such also had high expectations with the payout. But unfortunately I only got 3x multiplier. I was sad, but I was ready to improve on the mistakes I made, I wanted to know what went wrong.

After I read the reviews, I was a little bit happier. They all said my bot was really good made! But unfortunately it didn’t work.

I spent the next couple of hours trying to find out what I did wrong!



I couldn’t. I lastly resorted to asking AI, I gave it full details. And it gave me my answer… the reason my bot shut down was because I was using the --user tag while starting my bot using systemd :nooo:

I was devastated. I will never emotionally recover from this.

But the all good reviews kept motivated to keep on working. So i kept working on my other projects with full motivation! And yesterday I took some time off to complete the final few features I planned on adding to the bot.

Currently the bot is “completed” as per my book, but I will still add new features, updates when I see a interesting one!

Currently this is probably the last devlog of IceKeem in Stardance.

0
0
5
Open comments for this post

4h 18m 14s logged

Player Customisation Screen!!

RAAH, this is really done! TBH this was easier than expected. I had an
idea of how this will work out, and implemented just that. The menu
includes some smart and fancy mathematics too

// gettin the index
current_index := (int(curr_type) * num_tiers) + int(curr_tier)

// applying the changes, Lets say user pressed right arrow.
new_index := (current_index + 1) % total_options

setPartType(group, anim.CharacterType(new_index / num_tiers))
setPartTier(group, anim.CharacterTier(new_index % num_tiers))

I am really proud of the UI. Looks great. Honestly I was really lucky
with the great reference images I found in the internet :)

hosted here

0
0
6
Open comments for this post

7h 5m 46s logged

UI Overhaul - Done!

So I changed the entire UI, game UI is tough, even more so when you have a lot of moving components.

I never had ever use any library like orui so it was fun, but at the same time - confusing at times. Like for example: there are only 2 components for drawing (container and label). I mean there’s also element, but that is just an empty container.

Also I’ve tried everything but you can’t just get hover information for the container element.

I need some color suggestions for the buttons in options menu, they look kinda dull…

All the colors are taken from pallets at coolors.co!

Icons!!

So while at it, I wanted to add icons. This was hell. A very bad idea. Let me tell you why - orui doesn’t support icons by default, so you’ve got to load another font to draw the icons.

Now, Raylib can’t draw icon fonts, until you specify all the individual codepoints…here’s the code required to load a font with 3 icons:

icon_codepoints := [?]rune {
    0xe048, // ICON_LUCIDE_ARROW_LEFT
    0xe049, // ICON_LUCIDE_ARROW_RIGHT
    0xe14d, // ICON_LUCIDE_SAVE
    0xe18e, // ICON_LUCIDE_TRASH_2
}

icon_font = rl.LoadFontEx(
    "./res/fonts/lucide.ttf",
    32,
    &icon_codepoints[0],
    len(icon_codepoints),
)

Animation Blending

Made the animation transition buttery smooth!! Look at the video!!

0
0
6
Open comments for this post

8h 16m 38s logged

Implemented Animation blending + UI library changed

I wanted the player to be rendered in the main_menu and in the avatar menu. But also wanted the animations to be looping randomly.

When I implemented random looping I found out that, the animations wouldn’t behave properly due to snapping. So I implemented animation blending.

It was not at all easy, had to implement another angle_lerp function specifically for blending angles.

Character customisation

Due to me working hard earlier, changing character sprites is a cakewalk. In the attatched video. The head sprite is of tier 2 while the rest is from tier 1

GUI

I really wanted to like raygui, but it was really bad. A lot of maths required for very simple things! I didn’t like it at all. So in search of a new UI library I found this niche library orui!

This fits my needs perfectly:

  • Immediate mode
  • Super fast
  • (Not what I was looking for but a plus) Uses raylib
  • Doesn’t depend on me to do the maths
  • Actually customisable

You can see the updated GUI in the video, looks good right :) it also supports animations and transitions!

0
0
23
Open comments for this post

11h 40m 22s logged

Fully functional animation parser and engine!

The entire thing started by me searching for assets to use for my game, then I found these super cute chibi characters that too FOR FREE!!

I downloaded one of the free ones and saw that they use .scml file for animations. They do have pre-rendered png images in sequence too, but that is too easy, not fun and doesn’t look good!

So, I planned to make a .scml parser, my own animation engine. And see how it goes.

In the added video there’s the working part and the non-working part, which I found pretty funny.

1. Image loader

First I made a image loader that dynamically loads all the sprites that are in use. Later I will add the abitily to drop the sprites from memory when not in use.

2. Mapping the data

This was, tough. Very, very tough that I had originally anticipated. Making this parser included me staring at a file with 9k lines for hours. Trying to figure out what each elements do and how to use them interconnectedly. I first made a scml_data.odin where I one by one mapped all the required data to odin structs.

3. .scml parser

I created a new file scml_parser.odin and in it I loaded the .scml file with Odin’s built in xml parser. The parsing took a big chunk of time too, as there are not good docs or examples available out here. But there was one single forum post that got me going and I never had any problems thereafter. I parse the file and save the values in my global private data variable defined in scml_data.odin.

I read each elements and added all the necessary ones. I observed all the attributes, data and values very carefully earlier so I had an idea of some repetitive values that I could skip. I think almost 50% of the file was repetition, which ofc I didn’t save.

4. The engine

Now that I had all the data with me in, the only thing I had to do was use that.

With a given time t I have to find the timeline that it lands on and interpolate the time, linearly lerp the values and issue a draw command for the single sprite.

I was unable to do two specific things and had to take help from AI:

  1. Lerping Angle: angle lerping is different as there can be a case where we have to learp from 350 to 10, normal lerp functions would just lerp it 350->200->10 instead of 350->360->10
  2. Using the parent bones to calculate the final position of the child node. The particular function ai generated is here.

Debugging

After making the engine, we got to fix the engine.

It had bugs, I debugged for a long time and then fixed them. Pretty stupid things like not pushing the timeline keys after initialising them, flipped y-axis, and angle clockwise order.

Final thoughts

Finally the thing is working now, I still have to polish it and make it play nicely with my entire game. There are other optimisation opportunities available but I’ll put that for later.

I will now work on the avatar menu, so user can mix different things.

0
0
9
Open comments for this post

6h 41m 40s logged

Nothing much this time.

  • Added options menu
  • Added physics collider to the player (finally, phew..)
  • Notify mobile users to play in landscape mode.

That’s about it.

All of them were relatively easy. What I did try and haven’t pushed to upstream is a failed attempt to detect entry and exit from water bodies by the entities in an economical way.

0
0
14
Open comments for this post

6h 8m 5s logged

Drops and drops together make an ocean. Did nothing major just some small stuff


  • Added buttons (RayGUI) for navigation #7608e9


  • Made the game fully self-contained. The game executable requires no dlls, no other libraries or assets either. Everything is bundled together in a single executable!

For this to work, I used #load("file_source") function. It returns []u8 or in C terms *uint8_t.

But this won’t work with the raygui style loader function rl.GuiLoadStyle() that requires the ‘filename’ and not the data.

So for that reason. I read the source code of raygui an d implemented their function in Odin since they don’t expose the function to the user.

That’s about it tho!

0
0
11
Open comments for this post

8h 40m 13s logged

From bare metals to web. A rough road.

My game is now available to play in bs-odin.onkush.dev

I built my application for the Web and it works. Probably the most dirty work I had to do in this project overall. I probably have read all available Odin/WASM templates.


Setting the Sail

I knew what WASM is, I once to compile one of my C++ games to WASM too, but seeing more than 500+ errors in the first try took a big toll on me and I didn’t bother. I don’t want this project to end up like that.

I didn’t have to search much to find a template that builds Odin + raylib in WASM. So I started to implement ‘Offline Mode’ for my game. Didn’t take much time tbh, easy work. So I went to sleep and assigned WASM implementation to future me.

Thunderstorm

Next morning, I looked at how the {template](https://github.com/karl-zylinski/odin-raylib-web/) works - really simple and straightforward. I copied their code with proper attribution ofc. After fixing some build bugs, I ran my build.sh and…It didn’t work. But nothing works the first time…

Spoiler, it didn’t work in the 69th time either.

Tsunami

By evening, I was able to make it compile, I won’t get into the specifics but it had to do with multiple definition of functions within Odin core libraries.

So, after it compiled. I had a huge sigh of relief, I ran it in my browser and bam! A fully dark screen! Wait…What? NOO

I opened up the console… and Alas! Errors, not 500 errors, only one error Uncaught (in promise) InternalError: too much recursion

I couldn’t find what caused this error, how to fix it, how to narrow it down. Lastly I gave up and went to sleep. After I woke up! I one by one tested each file and their dependency. Lastly I found the culprit…it was Box2D :agasp:

After I dug deeper I found the fix, but it was concerned with changing the source code of Odin…so virtually no one can compile my game to WASM but me…

I’ll try to find a workaround for it, till then - if it works, it works.

The arrival to the forbidden Island

After a lot of hardwork, I got the fruits of my labour. This journey was not as much fun, but seeing my game run in my browser is so much worth it!

I fixed few visual glitches and frame time capture fixes. And then I pushed it into my domain :)

0
0
19
Open comments for this post

10h 32m 48s logged

Implemented Physics, generated islands form the terrain + Server side Seed generation.

Performance

Performance is out of the window, the algorithm that generates the islands is O(n^3)!! This disgusts me, but I wasn’t even able to come up with this solution! AI made the entire function…unfortunately I was not able to come up with the solution by myself…

I understand how the function works, but I don’t know how I could improve it anyway. The one upside to this is that, this function will only run once - during the game start.

My beloved physics engine Box2D can easily handle all these complex islands with no problem at all! So that helps :)

Time

What took 10hrs? Most of the time was trying to generate the islands, another huge chunk of time was spent making the renderer for Box2D #510535.

IDK how, but the server side seed generation that I though would take less time took about 2hrs…#4bac51

My state of mind

I am currently disappointed in myself, multiplayer is hard. Server side seed generation taking so much time destroyed my confidence. Not being able to generate the islands broke me… I am having doubts of being competent enough to complete this project.

My current plan is to focus on single player - offline mode. I will handle multiplayer with server later. Currently I will focus on things that are fun and actually have meaning. First I’ll make it work fully in web, then I will do character…

0
0
39
Open comments for this post

5h 45m 56s logged

Frame Time so low, we’re drawing the future.

Last devlog I said Raylib was slow. It is on me, I am dumb. I didn’t have to look more into it, DrawMesh did the exact thing I required!

Currently, the frame renders in my laptop under 0.9ms instead of 3-4ms earlier and in this devlog I document the changes I made.

Batch Rendering

Earlier I iterated over all the vertices and rendered them.

for v in vertices {
    rlgl.Color4ub(v.color.r, v.color.g, v.color.b, v.color.a)
    rlgl.Vertex2f(v.pos.x, v.pos.y)
}

That was very slow, when I profiled it I saw that just iterating over the vertices took about 1.4ms. Drawing took another 1.5ms.

So I changed the vertices data:

// old
vertex :: struct {
    pos: rl.Vector2,
    color: rl.Color,
}
vertices: [dynamic]vertex

// new
vertices_pos: [dynamic]rl.Vector3
vertices_col: [dynamic]rl.Color

Then I generate a terrain_mesh using these arrays in this function. And use that to render everything at once!

if mesh_initialised && terrain_mesh.vaoId != 0 {
    rl.DrawMesh(terrain_mesh, default_material, default_transform)
}

Results

Went from 3-4ms to 0.5ms. But when we move we have to generate the vertices at each frame! So if we don’ t move it is 0.5ms but if we move it is 4.0+ms!!!

Chunking

Since our terrain doesn’t change, we can store the results in GPU memory and render them at will.
But if we try to render a texture of size 5120x5120, our gpu will suffer really bad. So we chunk.

We divide the terrain in chunks, load them into gpu and show only the parts that are visible currently.

Sounds easy. But for stupid ppl like me it is hard, took me a long while to fight the memory, logic and silly mistakes.

But finally, it did work.

Results

It renders about 0.8ms avg and 1ms in high load, sometimes goes down to 0.6ms too! That too while moving!

2
0
344
Open comments for this post

6h 24m 31s logged

Reworked my entire Rendering and Windowing System…

Raylib - The unfortunate switch

I wanted to make a game accessible to many people. And the most accessible platform is Web. So I had to compile my application in WASM. While my previous renderer, SDL_Renderer was able to render in Web it was not meant to be used intensively, it doesn’t support shaders among many other flaws. So I looked for other rendering libraries to use for my game.

bgfx - no bindings for Odin
sokol - I never used it, I had to ask myself if the complexity it brings with it is worth it. Very sweet option otherwise.
Vulkan - No WASM
SDL_GPU - No WASM

Raylib comes with it’s own downsides tho - It is slow, just changing to it added 2ms to my render time, it was 1ms with SDL Renderer. But it’s simplicity keeps me in awe.

Right now I’ve decided to settle with my slower Raylib and focus on important stuff like offline mode, bots, characters.

5
0
48
Open comments for this post

7h 28m 58s logged

A massive overhaul of game architecture.

Architecture

I think it’s safe to say that this time I unscrambled the spaghetti code that I have been writing. These things are hard but very important for a project of this scale. Else, the developer burden piles up and motivation to complete the game is dead. #883172.

Performance

I implemented a simple performance hack to my terrain generation. This fix gives almost 100% faster terrain generation and rendering! I’ve documented the fix in the comments of the code here. #f2a07a

Camera

Till now the camera didn’t follow the player, but now it does. The math again, wasn’t easy. I introduced another bug that I caught days later. #393da8

Others

  1. Added a feature to ping server at any moment #da64b7
  2. Enforced naming convention
  3. Out of bounds array access fix
0
0
13
Open comments for this post

3h 19m 15s logged

Implemented Marching Squares!

Brief intro to marching squares

This is a technique commonly used in 2d terrain generation models. It converts the rigid ‘blocky’ tiling of squares to smth more organic by adding triangles to the mix. The end result is even more good looking when you add linear interpolation!

The implementation

Took everything from me. I feel exhausted and tired, I need sleep. The implementation took a lot of hand written logic, here and here. But idk how but the lookup table was perfect, and required no changes! Sure took some time to make it but the results speak for themselves I think.

What was indeed the problem…

this code in github

	_bl := bl > threshold ? 0b0010 : 0
	_br := br > threshold ? 0b0001 : 0

The fix?

	_bl := bl > threshold ? 0b0001 : 0
	_br := br > threshold ? 0b0010 : 0

I had these two swapped from what the standard says! Oh my gawd, this took forever to debug.

Performance

The current implementation is using Painter's Algorithm, this works but there is a heck ton of overdraw! I hate it and probably will try to find a fix to it soon!

0
0
43
Open comments for this post

3h 50m 43s logged

Made rendering more than 4000% faster!

Premature optimisation is the root…

So initially my renderer drew all the cells, even when not in view. There were only 64x64 cells so it was no problem for my lappy at all! But when I increased it to 512x512 my laptop took huge load (45ms rendering time)! Currently after implementing a camera thingy it is now not an issue.

The terrain is generated once and only the visible part (80x45 cells) is rendered in the screen!

This change lead to render times go below 1ms again :)

The maths behind camera thing was really logical error prone, and took a lot of time + I had a rough time working with dynamic arrays of Odin. Apparently you got to use raw_data(array) function to get the underlying data from the array. This is not documented anywhere neither did LSP find me this function when I did try to find it!

Other stuff

I also changed the colours of the terrain.

Added background to the fps and frame_time texts

2
0
27
Open comments for this post

5h 29m 18s logged

Procedural Terrain Generation is working now!

Maths

I kinda learnt a lot of maths for Perlin and simplex noise generations! Watched a lot of tutorials to get an idea of how it is generally implemented to generate terrain. It is very easy when you don’t have to code the noise functions yourselves…

Resources: 1, 2

Opensource helping

while at it I also added imgui as a dependency. When imgui was building I saw a two big libraries (the actual imgui and sdl3 repos) clone. They were more than 100mb each. I made some simple code changes build.py of the original repo which brought it down to 1-2mb each.

I made an issue in the original bindings repo. Let’s hope it goes well.

Rendering

I changed the rendering technique of the tiles of the generated terrain twice. It was real hard work. This probably took most of the time. There were many errors in maths and logic during the making of terrain renderer.

0
0
43
Loading more…

Followers

Loading…