chrismaltby / gb-studio

A quick and easy to use drag and drop retro game creator for your favourite handheld video game system
https://www.gbstudio.dev
MIT License
8.54k stars 469 forks source link

Add event: Change Background priority of Actor (sprite) #1181

Open sttng opened 2 years ago

sttng commented 2 years ago

Is your feature request related to a problem? Please describe. I want to change the background priority of sprites programmatically, in order for them to move in front or behind the background as it suits the game.

Describe the solution you'd like Ideally there is an event where I can set the priority of a sprite to "in front" or "behind"

Describe alternatives you've considered My current way of achieving this is a workaround: I keep 2 copies of the same sprite, but one has tiles set "in front" and the copy has tiles set "behind". Now I use a trigger to and the change sprite sheet event to update the sprite as needed. As such I am wasting precious tile memory, but it works.

Additional context Add any other context or screenshots about the feature request here.

RichardULZ commented 2 years ago

Use animation States instead of copies of the sprite sheet. Same method as recommended for using multiple palette slots, or a flashing damaged state. This new anim state would be identical to your default state, but with each sprite configured to show behind.

Animation states count to the 255 max frames per sheet, but are very fast to change, can be reused between actors on screen (as long as they don't set sheet, forcing them to reserve unique vram), and keep the same unique tile count.

It is not practical to expose Background priority of a metasprite externally, because it will permanently decrease performance on all metasprite rendering, every sprite tile will have to modify the sprite priority bit on the fly, instead of cheaply copying it directly from the frame/state in rom.

sttng commented 2 years ago

First of all, thanks for the extensive reply. Just for understanding, it'll mean I have to "double" animation states ? Such as for example: Attack State - front, Attack State - back, Hit - front, Hit - back, .... ?

Also don't get all animation states loaded into Tile Memory and as such count against tile limitations ?

RichardULZ commented 2 years ago

That is correct, All animation states are loaded into vram, if the sheet uses it, it has to be immediately accessible without swapping. Since all you are changing is the priority bit, the duplicate states do not count towards the unique tile count, as they are already used in the sheet on another state.

I understand it becomes more complex if you have multiple custom action states, but that's my recommendation so oam data is still read as fast as possible.

Directly modifying the sprite properties was feasible in 2.0 when every actor was 16x16, but i'm not sure if it's a worth while trade off with custom actors and flipping per sprite. Set sprite sheet is still usable in this case, but the hitch as it loads vram might be hard to get rid of.

It may theoretically be possible to "set sprite sheet" without replacing vram or marking as unique, only updating the animation pointers... I don't know if that's a current possibility through gbvm, or any ideal way to expose a niche feature like that.

sttng commented 2 years ago

Since all you are changing is the priority bit, the duplicate states do not count towards the unique tile count, as they are already used in the sheet on another state.

Ok understood. In that case, I agree that (for me) a specific event isn't needed - but maybe an easier way to copy animation states in sprite sheets and setting the priority bit would be most welcome :)

sttng commented 2 years ago

Just a small update: After thinking and trying I'm not 100% sure creating a separate animation state for background priority is better vs creating a separate sprite.

If I create a separate animation state, I have to add extra variables to keep track in which state I'm currently in (ie. Default State vs Default Background State vs Attack State vs Attack Background State vs Crouching State vs Crouching Background State .....).

In a separate sprite I don't have to deal with this logic.

RichardULZ commented 2 years ago

Yep, if set sprite is working for you, that will be easier to manage, my initial reply didn't account for multiple states already being in use, it was also a recommended use case when states were introduced by toxa.

You won't see any graphical issues with set sheet because the vram is identical, there's no worry of more vram usage either (If it's for the player) since it remains unique (duplicated actors would be an issue). You may unfortunately see minor lag as it switches the vram, if this is based on a trigger, using gbvm VM_UNLOCKbefore the switch may improve this, as it keeps the thread unlocked instead of as a cutscene.

The theoretical idea of a "set sprite sheet" event that would not change vram, but still loads new "background priority" metasprite animations, could have further investigation.

yuesubi commented 2 years ago

Hi, Sorry for asking this here, as I don't know where to ask this: You have been talking about background priority but where do you change it ? I searched everywhere I could think of in gb studio and the docs but I wasn't able to find it. I have some sprites that overlap with each over in my scenes, and if I understand correctly this background priority thing would be very helpful.

sttng commented 2 years ago

Hi, Sorry for asking this here, as I don't know where to ask this: You have been talking about background priority but where do you change it ? I searched everywhere I could think of in gb studio and the docs but I wasn't able to find it. I have some sprites that overlap with each over in my scenes, and if I understand correctly this background priority thing would be very helpful.

its in the Sprite Editor on the upper right. Select the tiles in the Frame Canvas and then in the upper right you have the option to display in front or back and to change palette (OBP0 and OBP1).

https://gbstudiocentral.com/tips/basics-the-sprite-editor/

yuesubi commented 2 years ago

I tried to switch between OBP0/OBP1 but nothing changes, and the buttons "bring to front"/"bring to back" only change the priority of tiles in a same sprite. The player is sometimes above or under the same sprite.

maxoakland commented 2 years ago

I tried to switch between OBP0/OBP1 but nothing changes, and the buttons "bring to front"/"bring to back" only change the priority of tiles in a same sprite. The player is sometimes above or under the same sprite.

OBP0/1 change a palette on DMG. You’re looking for the background priority option

Q-Bert-Reynolds commented 3 weeks ago

The way I handled this was by ejecting the engine and modifying actor.c to use move_metasprite_ex instead of move_metasprite and passing it an the sprite property override I wanted. Bit 7 is the object priority flag, so I passed 128 as the base_prop value to bring a metasprite that's normally in the background to the front. I added uint8_t base_props; to the struct actor_t in gbs_types.h so I could pass that value to move_metasprite_ex. Looks like this:

allocated_hardware_sprites += move_metasprite_ex(    // move_metasprite is obsolete anyway, this is the way
    *(sprite->metasprites + actor->frame),
    actor->base_tile,
    actor->base_props,                                                  // this is the bit that overrides metasprite props
    allocated_hardware_sprites,
    screen_x,
    screen_y
);

I use the extra collision flags to mark areas as in front. If I find that flag, actor.base_props = 128.