LoginLogin

Gauging interest - Platforming Engine

Root / Programming Questions / [.]

NeatNitCreated:
Hi, I'm designing a general-purpose platforming engine. It is designed to be completely generic, meaning: * No pre-defined AI that you'd be stuck with * Similarly, no pre-defined player input - YOU have control of how your game input feels like * Lightweight, easy to use, does not conflict with anything you might want to do I've already created a draft for the design goals - you can find it here, and you can comment on it: https://docs.google.com/document/d/17_8dE8Y_nHBOPx4LAJH01oKAqgV-x5BSX10lvk8miN8/edit?usp=sharing But let me repeat some of that information here. What it is: A sprite-to-background collision and physics engine A generic and easy-to-implement way to add good platformer physics to your game. A losslessly-saved fixed-point format. Handles all SPOFS and BGOFS operations Future-er versions: Engine-side implementation of save/load Slopes Multiplayer What is isn’t: A sprite-to-sprite engine - unless one of the sprites is a platform which the other can't pass through. A graphical engine - this API does not change the appearance of sprites or backgrounds in any way besides their positions. It works via SPCOL only. SBPE does NOT simulate gravity on its own. Just add to VY every frame if you need it. SBPE can counteract/ignore gravity while standing/walking/running on platforms. Now, I'm just posting it to get some sense for who would use this engine. I think I'll make it either way (there's stuff that I plan to do with it), but it'd be nice to know that anyone else would also like to use it. I haven't started work on it yet for one simple reason: SmileBASIC has not yet been released in the UK. It's very annoying, I hope it gets released soon so I can work on this engine. Expect version 1 to be pretty barebones, but I've planned ahead already so future versions should be completely backwards-compatible with whatever code was written for v1. If you have any suggestions, criticism, or insults, please post them so I can take them into consideration! It's best to post them before the UK/EU release, because the design can be changed completely before I start work on it but afterwards it's a bit of a pain.

Sounds like a great project

Sounds like a great project
Thanks! I also figured I could try to code this in notepad / npp or something, without testing, in preparation for the eventual release. But I have a few too many PC-based projects at the moment, was kind of counting on programming SBPE on-the-go right on the 3DS itself. We'll see, I might just do that.

It's nice that you 're making this project. One question... how do you handle physics? Can I add vector to the sprites?

This sounds like an awesome library to mesh up with what I'm working on. I'm coding a library that handles the main game state machine and implements a stage with input events such as dragging and holding. I'd love to coordinate with you and make thing as compatible as possible. It looks like you have a pretty sane API; the tick and render commands will make it easy to introduce into a game loop. I'm excited for this!

Great idea man, I'm certainly interested as one of my main goals is to learn how to do this exact kind of thing.

It's nice that you 're making this project. One question... how do you handle physics? Can I add vector to the sprites?
The main way to control sprites (player, enemy, bullet) after their initialization, would be to set their velocity. So if you want the player (let's say sprite 25) to move diagonally down and left, down at speed 15 and left at speed 30, you'd use: SBPE_SPVELOCITY 25, -30, 15. You set each sprite's velocity in your main loop, according to your logic (can be very simple or very complex, whatever you want!), and then you use SBPE_TICK - which would internally calculate the new X and Y positions for each sprite. The collision with the map - in my opinion the most difficult thing to get right - is done within the engine, so you can rest easy that your sprite CANNOT go through walls no matter what velocity you give it. The internally-stored velocity value will also be modified to accommodate - so if you hit the floor, VY will become 0, and you can (and should!) acquire this data by using SBPE_GETVELOCITY 25 OUT VX, VY on the next iteration. Please note that all command names are temporary and will likely be changed before release - for example, SBPE_GETVELOCITY is way too long, I'll probably make it shorter.
This sounds like an awesome library to mesh up with what I'm working on. I'm coding a library that handles the main game state machine and implements a stage with input events such as dragging and holding. I'd love to coordinate with you and make thing as compatible as possible. It looks like you have a pretty sane API; the tick and render commands will make it easy to introduce into a game loop. I'm excited for this!
Thank you! Unfortunately, since work hasn't started yet and there's not ETA for SmileBASIC in EU, I can't recommend that you twirl your thumbs and wait for this. However I would love to get some feedback! Feel free to point out anything you think you might need, or is missing, or could be done differently or more conveniently. Edit: and of course, if you contribute good code, I'll gladly accept it and of course credit you as well ;)

One of my first thoughts was how are you thinking about storing the sprite entities you are keeping track of? Should this data be used as if it was publicly available? E.g. Can we access or update the array of VX? Would a Stage's Actor list be able to point to the same array as the active sprite IDs? Could the library operate with a passed in array?

Edit: forgot to answer your first question...
One of my first thoughts was how are you thinking about storing the sprite entities you are keeping track of?
Well, there's plenty of ways, but I think I'll keep an array for each type of info: Mode, X, Y, VX, VY There are 512 sprites at most, so to keep code simple I would make each array 512 long, and I'm working with integers only so I would be using up 512 x 5 = 2560 ints' worth of memory. Hopefully that is not a large footprint.. If it is, I'll look into other ways. Also, it is possible for the inner workings to completely change between versions, as long as the exposed commands still work the same. Therefore if v1 is released and after that I discover (or someone suggests) a better way to store data, even if it's drastically different, it could be implemented for v2.
Should this data be used as if it was publicly available? (E.g. Can we access or update the array of VX?)
Good question! There are two planned ways to use this library: 1. Have it in a separate slot, activate it with USE and EXEC at the top of your program 2. Import all functions into your main program, which doesn't take up any other slot and IMHO simplifies code If you use option 1, you will have no way to directly access the internal variables and arrays. If you use option 2, you can directly access them since they'll be global, but it's not recommended - especially not recommended that you write to them. SBPE has functions to return any data you might need, so there should never be a reason to access them. However I imagine that reading directly off of them might give you a slight performance boost, so you could do that. I intend to have all variable names start with SBPE_ to make it impossible to clash with any of your own variables or functions.
Would a Stage's Actor list be able to point to the same array as the active sprite IDs? Could the library operate with a passed in array?
I don't quite follow your question.. Can you rephrase?

I want to make sure that the Google Docs comment thing is working, so can anyone just write any comment on there? Thanks ^^ I am going to bed now, so if anyone posts here don't be surprised if I don't answer right away :) Overall I am very excited to see that you guys are interested!

Sounds like you know what you're doing. Sucks that theres no release date in Europe yet.
so to keep code simple I would make each array 512 long
Just a nitpick that you might know: you can initialize arrays to be of length 0, and then push to it and smilebasic will increase the length in chunks.
I don't quite follow your question.. Can you rephrase?
For the stages I am coding, I maintain an array of sprite IDs to interact with the active sprites. As you've described it, your library will be doing the same thing. I can think of two ways of sharing the same data to reduce overhead; what do you think of either?: A - Pass the array (LDG_sprites%) to something like SBPE_INIT B - "monkey patch" SBPE_sprites% to point to my LDG_sprites% (set it equal to my array) Are there better ways to do this? I could almost spin off a simple library that IS just a list of sprites, and it could be common between the projects. Possibly a more abstracted stage.

so to keep code simple I would make each array 512 long
Just a nitpick that you might know: you can initialize arrays to be of length 0, and then push to it and smilebasic will increase the length in chunks.
I'm aware of this, but since I'm using the actual sprite index as used by SmileBASIC, and not my own internal index, I need to be able to add or access values to an arbitrary index between 0 and 511 at a moment's notice. There is no guarantee that sprites will be added in order (0, 1, 2...) and I don't want to require users of this API to do so. And I think of SBPE as an extension to the SmileBASIC language, so I definitely want to use the same sprite IDs as used by SPANIM or any other sprite command, rather than some other form of ID.
For the stages I am coding, I maintain an array of sprite IDs to interact with the active sprites. As you've described it, your library will be doing the same thing. I can think of two ways of sharing the same data to reduce overhead: A - Pass the array (LDG_sprites%) to something like SBPE_INIT B - "monkey patch" SBPE_sprites% to point to my LDG_sprites% (set it equal to my array) Are there better ways to do this? Should I be adapting my library to use an external library thats common between ours?
If I understand correctly, you are giving each sprite (or actor) an ID different from the sprite's management number. As I explained above, my library won't do that (not even internally). If I misunderstood feel free to correct me. it is very late and I am prone to misunderstandings :P

No worries. I'm not making much understanding either. My criticism is that to do what you're doing, you will always have to have the maximum amount of memory allocated. I get around having to have a N*512 byte array by pushing the sprite management number (external id) into an array and having a different internal id. My library does not need to expose its internal id, as the properties are set on the sprite itself, and can be accessed using the external id and the built-in sprite commands. In my update functions, I can then loop through that array and use only the external IDs that are active with SPOFS etc. Avoiding unnecessary updates on unused sprites. Do you update all 512 entries when you simulate collision? The only way I can think of not storing 512*N attributes with only an internal id is doing a lookup for the external id, but for things like getting velocity, without a separate ID, that would be a linear search through your array, which you wouldn't want for speed reasons. So I'm not sure what you can do to save space. Your choices really are just: allocating all the memory, or returning a new and possibly different management number... I can see why you wouldn't want to have a new ID, but I think the performance benefits are worth it.

Is there a reason you can't use SPVAR entries for the associated variables? Technically I think those are stored as floating-point values, but you could just as easily store fixed-point integers since there's enough bit space. On the other hand, if you use your own arrays then I suppose it would be good for allowing users to use all 8 of those variables for their own purposes. Allocating several 512-entry arrays definitely isn't a terrible idea. And I think what kldck_hul is saying is that you need to keep track of which sprites are currently active in the engine, because you probably don't want to iterate over 512 booleans to check whether each sprite is active or not. But that's probably easy enough to do by just pushing each sprite onto an internal array when registering it. So you're planning to use a combination of SPCOL, SPCOLVEC, SPHITRC, and SPHITINFO for handling collisions with the background? I haven't tried those out personally yet, but they seem really powerful. Like, I guess you could call SPHITRC for each potential BG tile collision and then use the minimum collision time and associated position from SPHITINFO.

Is there a reason you can't use SPVAR entries for the associated variables? Technically I think those are stored as floating-point values, but you could just as easily store fixed-point integers since there's enough bit space.
Yep. Those variables should be available to end-users. There's also the fact that I'm here talking about compatability, and we'd have to start divvying up sprite slot numbers to different libraries and keeping it fair would be hard.
And I think what kldck_hul is saying is that you need to keep track of which sprites are currently active in the engine, because you probably don't want to iterate over 512 booleans to check whether each sprite is active or not. But that's probably easy enough to do by just pushing each sprite onto an internal array when registering it.
Exactly. From the sounds of it, NeatNit has considered this, but doesn't want to use different IDs. I edited my comment to try to be more clear about the fact that as soon as you don't use sprite slots, you have to expose your internal IDs.

Well, consider that there is little to no sprite-sprite interaction in this engine, and thus there is no reason to have internal IDs. The minimum that's necessary is having a list of management numbers in case you want to have a function that iterates over every active sprite. Instead of indexing an internal array for the core functions you can just pass around the actual management numbers. Another thing you could do to entirely avoid keeping a list is to make the user call the update function on every sprite they want to run physics on individually (which is a natural thing to do if the user is using SPFUNC and CALL SPRITE).

make the user call the update function on every sprite they want to run physics on individually
That leaves the concept of "THESE sprites need to be updated this frame" to a 3rd party (my library in my case). This might make it great for managing sprites in a fixed update time loop.

So much to say, so little time...
Is there a reason you can't use SPVAR entries for the associated variables? Technically I think those are stored as floating-point values, but you could just as easily store fixed-point integers since there's enough bit space. On the other hand, if you use your own arrays then I suppose it would be good for allowing users to use all 8 of those variables for their own purposes. Allocating several 512-entry arrays definitely isn't a terrible idea.
You pretty much got it right. Initially I did intend to use SPVARs, but then I figured "what if the user wants to use all 8 SPVARs?", so I thought up a SBPE_NOSPVARS command, which would switch to using arrays instead of SPVARs. That would mean two modes of operation to accomplish the same thing. Then I realized that I'd just be making things more complicated for me to develop, to debug and to optimize, so it's better to just focus on one method and optimize it to work fastest.
No worries. I'm not making much understanding either. My criticism is that to do what you're doing, you will always have to have the maximum amount of memory allocated. I get around having to have a N*512 byte array by pushing the sprite management number (external id) into an array and having a different internal id. My library does not need to expose its internal id, as the properties are set on the sprite itself, and can be accessed using the external id and the built-in sprite commands. In my update functions, I can then loop through that array and use only the external IDs that are active with SPOFS etc. Avoiding unnecessary updates on unused sprites. Do you update all 512 entries when you simulate collision? The only way I can think of not storing 512*N attributes with only an internal id is doing a lookup for the external id, but for things like getting velocity, without a separate ID, that would be a linear search through your array, which you wouldn't want for speed reasons. So I'm not sure what you can do to save space. Your choices really are just: allocating all the memory, or returning a new and possibly different management number... I can see why you wouldn't want to have a new ID, but I think the performance benefits are worth it.
I think what kldck_hul is saying is that you need to keep track of which sprites are currently active in the engine, because you probably don't want to iterate over 512 booleans to check whether each sprite is active or not. But that's probably easy enough to do by just pushing each sprite onto an internal array when registering it.
That's a lot of food for thought! One possible solution is to have one 512-sized array, and 6 dynamic sized arrays:
DIM MANAGEMENT_TO_INTERNAL[512]
DIM INTERNAL_TO_MANAGEMENT[0]
DIM MODE[0]
DIM X[0]
DIM Y[0]
DIM VX[0]
DIM VY[0]

'adding a sprite:
DEF ADD_SPRITE ID%
VAR NEW_ID% = LEN(INTERNAL_TO_MANAGEMENT)
PUSH INTERNAL_TO_MANAGEMENT, ID%
MANAGEMENT_TO_INTERNAL[ID%] = NEW_ID
PUSH X, 0
PUSH Y, 0
PUSH VX, 0
PUSH VY, 0
END

Getting info using either number:
VAR MANAGEMENT_NUMBER% = 17 'for example
VAR INTERNAL_ID% = MANAGEMENT_TO_INTERNAL[MANAGEMENT_NUMBER%]
XX = X[INTERNAL_ID%]
YY = Y[INTERNAL_ID%]
'etc


'Removing a sprite (is there a more efficient way?)
DEF REMOVE_SPRITE ID%
VAR INTERNAL% = MANAGEMENT_TO_INTERNAL[ID%]
MANAGEMENT_TO_INTERNAL[ID%] = -1 ' the "unassigned" value

VAR LENGTH = LEN(X)-2 'can check any of the same-length arrays..
FOR I = INTERNAL% TO LENGTH
    ' move all sprites above it ahead to fill in the gap
    INTERNAL_TO_MANAGEMENT[I] = INTERNAL_TO_MANAGEMENT[I+1]
    MODE[I] = MODE[I+1]
    X[I] = X[I+1]
    Y[I] = Y[I+1]
    VX[I] = VX[I+1]
    VY[I] = VY[I+1]
    MANAGEMENT_TO_INTERNAL[INTERNAL_TO_MANAGEMENT[I]] = I
NEXT
POP(INTERNAL_TO_MANAGEMENT)
POP(MODE)
POP(X)
POP(Y)
POP(VX)
POP(VY)

END
Possible alternative: to adding and removing (maybe more efficient):
DIM MANAGEMENT_TO_INTERNAL[512]
DIM INTERNAL_TO_MANAGEMENT[0]
DIM X[0]
DIM Y[0]    'cba for the rest of them
DIM FREE_INTERNAL[0]

DEF ADD_SPRITE ID%
VAR NEW_ID%

IF LEN(FREE_INTERNAL) == 0 THEN
    NEW_ID% = LEN(INTERNAL_TO_MANAGEMENT)
    PUSH INTERNAL_TO_MANAGEMENT, ID%
    PUSH X, 0
    PUSH Y, 0
ELSE
    NEW_ID% = SHIFT(FREE_INTERNAL)  'can use POP instead, is there a performance difference?
    INTERNAL_TO_MANAGEMENT[NEW_ID%] = ID%
    X[NEW_ID%] = 0
    Y[NEW_ID%] = 0
ENDIF

MANAGEMENT_TO_INTERNAL[ID%] = NEW_ID%
END

'and removing, much simpler:
DEF REMOVE_SPRITE ID%
VAR INTERNAL% = MANAGEMENT_TO_INTERNAL[ID%]
MANAGEMENT_TO_INTERNAL[ID%] = -1 ' the "unassigned" value
PUSH FREE_INTERNAL, INTERNAL%

INTERNAL_TO_MANAGEMENT[INTERNAL%] = -1

END
A lot less overhead, but if a large number of sprites is removed then it leaves a lot of gaps which will be iterated/skipped over and they'll never be cleaned up.
So you're planning to use a combination of SPCOL, SPCOLVEC, SPHITRC, and SPHITINFO for handling collisions with the background? I haven't tried those out personally yet, but they seem really powerful. Like, I guess you could call SPHITRC for each potential BG tile collision and then use the minimum collision time and associated position from SPHITINFO.
Yup, exactly! However, in Petit Computer, SPHIT commands had one minor flaw - if the sprite was moving too fast, they'd give some slightly-off results. This MAY be a problem if it's still the case (SBPE is intended to work for bullets as well), so if I find that it is, I'll have to implement my own version of SPHITRC. That should be fun..

Alright, I've decided that I can start working on this before the actual UK release. I've already configured Notepad++ to work reasonably well with SmileBASIC code, and will probably have time tomorrow to get to work. Wish me luck :)

A losslessly-saved fixed-point format.
Can you give details on this point? Thanks.