I wasn't sure I would be able to play on mobile but I was pleasantly surprised by the simple controls and managed to reach the third scene of chapter 1 before getting stuck, so, good job.

I don't think anything needs to change with the controls, the people saying that aren't the audience and don't have the genre literacy to know what this type of control setup is doing(for those watching: Jump King, Getting Over It both have the same kind of ruthless difficulty).

Regarding the technology, it's healthy to simplify the architecture - I've played a lot with the same kinds of thought processes of adding a lot of abstraction and gradually moved towards simpler answers. You already have a lot of answers that work, but my own take is that games of this type and scale need, roughly, these pieces:

* A "god object" entity model(every entity is one struct containing all necessary state for all possible behaviors). Going beyond that adds memory savings that you don't need for modern machines, or modularity that will introduce more to debug.

* State machine formalisms to describe what screen to draw, how to transition between them, what animations to play, and other behaviors. All control flow logic encompasses the behavior of a state machine, so you have to decide which formalism is best to use for the context and will aid debugging. That's why people sometimes gravitate towards coroutines and other high-level abstractions. Simple "scripting languages" that just describe a sequence of opcodes are something that frequently appear in old games.

* A simple constraint solver for the platforming physics. The problem that all physics systems have to solve is "there are multiple possible solutions that will resolve this motion: which one is the best?" This tends to be obfuscated in platforming physics by a convention of throwing away information about potential solutions early(e.g. moving on the x axis and resolving collision there, then doing the same on the y axis). Instead I recommend breaking down the motion into multiple permutations of "x then y" vs "y then x", then sorting and ranking the outcomes relative to a heuristic of unimpeded free movement. It's a more expensive check that also gives a better-feeling result.

* A pipeline to load the graphics, collision and scene assets. Although you can hard-code a lot of these things in a simple game, it can be convenient to export them from a spreadsheet and make it data-driven. Things like describing what "chapter 1" is are basically asset problems. I noticed that you have dialogue boxes described with a tileset and code to draw the tiles. This is how I would have done things once, since it is "how they used to do it" - today I would be likely to turn everything at runtime into an image, and to build the text itself, compile pre-baked images of text in the build process using tools like imagemagick. That makes the runtime simpler and reduces the kinds of assets it tracks, while allowing total freedom with the content of dialogues.

Sometimes with these projects, the engine development is being used to avoid content work. I suggest a physical graph paper notebook to create a location for that content to be designed, and to engage in some blind contour sketching to warm up to doing anything visually-oriented. When you have a whole storyboard for the game it becomes easier to conceptualize what code is necessary to get the effect, and do exactly that instead of generalizing it.

Two commercial "back in the day" games I would also look at for more inspiration: Xargon, Little Big Adventure 1. Both written in C, original source code is available. Studying those will give you a sense of where you are relative to finished work.