My Platformer Framework

This is an archive of a topic from NESdev BBS, taken in mid-October 2019 before a server upgrade.
View original topic
My Platformer Framework
by on (#242541)
Hi!

Based on my Physics Demo, I've been writing an object oriented platformer framework in C.
My goal is to achieve the highest possible performance while at the expense of having a high level of human-readable and maintainable code.
It's too early to open-source it, but I will do so as soon as it's stable enough.

Image Image Image

Please test it out and let me know how the controls feel... :)
The collision detection is not perfect yet, but I hope there won't be any problems.

PS: I did the sprites as well. :mrgreen:

Roadmap:
Code:
[X] Object-oriented code
[X] Text-based game menus
[X] Collision detection with simplified physics
[X] Smooth player movement
[>] Support metatiles and metasprites
[ ] Sprite collision detection
[ ] Background scrolling
[ ] Many other features...


Controls: L/R Move, A Jump, B Run

EDIT: I added a new version with idle animation.
Re: Unnamed Platformer Framework
by on (#242544)
Good work so far!

Quote:
Please test it out and let me know how the controls feel...

The jump physics do feel a little odd to me. Maybe a little too fast vertically in comparison to the horizontal velocity? I'm not sure.
Re: My Platformer Framework
by on (#242580)
This looks really cool! Have you found any issues in performance or rom space developing in C as opposed to assembly?

How do you do your collision detection? With so many objects and platforms on screen, the fact that it stays at 60 fps is what I find most impressive. :)

BTW, How do you even debug your C code? I've only ever coded for NES in assembly..
Re: Unnamed Platformer Framework
by on (#242633)
gauauu wrote:
Good work so far!
The jump physics do feel a little odd to me. Maybe a little too fast vertically in comparison to the horizontal velocity? I'm not sure.

Thanks!! Indeed, I'm still not fully satisfied with the current velocity/acceleration values, there's still a lot of room for improvement. :)


pwnskar wrote:
This looks really cool! Have you found any issues in performance or rom space developing in C as opposed to assembly?

Thank you so much! I'm really glad you like it! Well, I've never coded in assembly so I'm not sure how much of a performance hit is the fact that I am writing it in C.
Nevertheless, I believe my C code is as tight as it can possible be, while keeping an high level of abstraction.

pwnskar wrote:
How do you do your collision detection? With so many objects and platforms on screen, the fact that it stays at 60 fps is what I find most impressive.

It took me around one month to come-up with this algorithm and make it work fast in the NES. Normally I would use sin(), cos() and atan2(), but since the <math.h> is not really available in this context, I had to wrap my head around it and come up with an entirely different solution. I'm attaching my collision detection module, but bear in mind that it's still a work in progress.

pwnskar wrote:
BTW, How do you even debug your C code? I've only ever coded for NES in assembly...

Well, first of all, I wrote my own printf(), so I can do stuff like print_at(3, 3, "Vx: %d", actor.vx);.
Second, I always check the generated assembly code in the compiler listings (both locally and on 8bitworkshop).
Finally, for benchmarking, I'm using the methods suggested in this thread: How can I benchmark my C code?
Re: Unnamed Platformer Framework
by on (#242645)
wonder wrote:
It took me around one month to come-up with this algorithm and make it work fast in the NES. Normally I would use sin(), cos() and atan2(), but since the <math.h> is not really available in this context, I had to wrap my head around it and come up with an entirely different solution. I'm attaching my collision detection module, but bear in mind that it's still a work in progress.

Thanks for sharing the attachment! I had a look at it but I'm ashamed to admit most of it went above my head! :D Will try to read through it some more though, as I'm sure there's lots I can learn from it.

Do each entity check it's collision against whatever tiles are loaded into the nametables behind them? Is that what you're doing when using your P2B() function? Or do you keep a buffer of collision boxes that gets updated with every nametable change?

I do a buffer kind of solution myself, but I only load in platforms that you can land on. For collision between entities I think maybe we're doing some things similarly. What I do is I take the coordinates for the collision box of entity_1, add all the sides to the collision box of entity_2, but mirrored and flipped upside down, then I compare the result of that to the pivot (or "hot spot" if you will) of entity_2. The result would be the same as comparing all corners of entity_1 to each side of entity_2 to see if they intersect, but this way I only check one point instead of four.

Code:
Screen space collision boxes:
(p = pivot)
                        +-------------+
       +----------+     |  entity_2   |
       | entity_1 |     |       :     |
       |     :    |     |       :     |
       |-----p----|     |-------p-----|
       |     :    |     +-------------+
       +----------+
-------------------------------------------

Screen space collision boxes added together:

+------------------------+ entity_2 pivot
|     +----------+       |      |
|     | entity_1 |       |      |
|     |     :    |       |      V
|-----|-----p----|-------|      p
|     |     :    |       |
|     +----------+       |
|                        |
|  enity_1 padded with   |
| dimensions of entity_2 |
+------------------------+

-------------------------------------------

Does entity_2's pivot overlap the combined collision box?

Anyways, since you shared so much of your code I thought I'd share the principle of mine. The actual assembly code is even more confusing even to myself, so I'll spare you that.. :)

I'm looking forward to see how your engine comes along!

Cheers! :beer:
Re: My Platformer Framework
by on (#242653)
Hello again!

Quote:
Do each entity check it's collision against whatever tiles are loaded into the nametables behind them?

Yes, but I'm not using the nametable itself. I'm using a grid object char matrix[x][y] = {{...}, {...}, ...};.

Quote:
Is that what you're doing when using your P2B() function?

P2B means "pixel-to-block", it gives me the result of the given pixel-coordinate divided by 8 (block size).

Quote:
Or do you keep a buffer of collision boxes that gets updated with every nametable change?

I'm not sure what you mean, but I'm guessing that the answer is no.

I've drafted a PDF on which I try to explain my reasoning in more detail, see attached. :)
Re: My Platformer Framework
by on (#242659)
wonder wrote:
Quote:
Or do you keep a buffer of collision boxes that gets updated with every nametable change?

I'm not sure what you mean, but I'm guessing that the answer is no.

Perhaps buffer wasn't the right word. What I meant was if you were keeping a representation of all the collision boxes in RAM and then update them accordingly whenever there's a change to the nametables. If your char matrix[x,y] is kept in RAM, then this would be that. But I'm guessing you're keeping it in ROM, since it should need 960 bytes for each full screen and keeping it in RAM would take up almost half the available RAM on NROM.
Re: My Platformer Framework
by on (#242668)
pwnskar wrote:
If your char matrix[x,y] is kept in RAM, then this would be that. But I'm guessing you're keeping it in ROM, since it should need 960 bytes for each full screen and keeping it in RAM would take up almost half the available RAM on NROM.

Yep! That's right, I'm keeping it in ROM (in C all I had to do was declare it as const char). :)