Turn based and input buffering

Discuss technical or other issues relating to programming the Nintendo Entertainment System, Famicom, or compatible systems. See the NESdev wiki for more information.

Moderator: Moderators

Post Reply
User avatar
never-obsolete
Posts: 411
Joined: Wed Sep 07, 2005 9:55 am
Location: Phoenix, AZ
Contact:

Turn based and input buffering

Post by never-obsolete »

So I've been playing around with procedurally generated content and thought some sort of turn-based rogue-lite would be a good canidate because the rules and graphics are* pretty simple. The result is a sort of turn-based-action thing.

The player can pick what type of character they want to be, each having different stats. Instead of having the agility/movement stat control how many squares you can move each turn, I have it control how many turns you must wait to perform an action. Each turn can be classified as either a WAIT or an ACTION turn. WAIT frames just decrement the actors counter and return. ACTION turns can be whatever.

Originally, I had it perform one actor's turn per frame. This made the player input response lag. It would only register on NEW presses when the player was on an ACTION turn, causing a lot of NEW presses to become considered OLD by the time the player's ACTION turn came around.

I then had it execute as many turns each frame as it takes to get to the first ACTION turn for any actor. This greatly reduced the dropped input, but not completely. I'm assuming some sort of buffering would be needed. You can't buffer everything, otherwise pressing a direction would cause the player to shoot across the screen until it hit something solid. Maybe only start buffering after all buttons have been released? Maybe the entire thing is flawed. I thought about running turns until a player ACTION turn is hit, but the processing *could* take multiple frames, and would mess up the sprite0 hit.


Here's a diagram breaking down the problem. The numbers inside {} show the value of the counter after that turn is executed, ACTION denotes that the actor does something (like moving or attacking), and the "_state" denotes state changes within the actor itself.

note: All actors start in wait_state. When a player ACTION turn hits, the turn counter is not updated until the player actually does something. It will not skip the player.

Code: Select all

=====Frame[00]=====
 00: player {init=5}                      enemy1 {init=3}                      enemy2 {init=1}
 01: player {dec=4}                       enemy1 {dec=2}                       enemy2 {dec=0:action_state}
 02: player {dec=3}                       enemy1 {dec=1}                       enemy2 {reset=1:ACTION:wait_state}

=====Frame[01]=====
 03: player {dec=2}                       enemy1 {dec=0:action_state}          enemy2 {dec=0:action_state}
 04: player {dec=1}                       enemy1 {reset=3:ACTION:wait_state}
 
=====Frame[02]=====
 05:                                                                           enemy2 {reset=1:ACTION:wait_state}

=====Frame[03]=====
 06: player {dec=0:action_state}          enemy1 {dec=2}                       enemy2 {dec=0:action_state}
 07: player {reset=5:ACTION:wait_state}
 
=====Frame[04]=====
 08:                                      enemy1 {dec=1}                       enemy2 {reset=1:ACTION:wait_state}

=====Frame[05]=====
 09: player {dec=4}                       enemy1 {dec=0:action_state}          enemy2 {dec=0:action_state}
 10: player {dec=3}                       enemy1 {reset=3:ACTION:wait_state}

=====Frame[06]=====
 11:                                                                           enemy2 {reset=1:ACTION:wait_state}

=====Frame[07]=====
 12: player {dec=2}                       enemy1 {dec=2}                       enemy2 {dec=0:action_state}
 13: player {dec=1}                       enemy1 {dec=1}                       enemy2 {reset=1:ACTION:wait_state}
 
=====Frame[08]=====
 14: player {dec=0:action_state}          enemy1 {dec=0:action_state}          enemy2 {dec=0:action_state}

=====Frame[09]=====
 15: player {reset=5:ACTION:wait_state}

=====Frame[10]=====
 16:                                      enemy1 {reset=3:ACTION:wait_state}

=====Frame[11]=====
 17:                                                                           enemy2 {reset=1:ACTION:wait_state}

*can be
. That's just like, your opinion, man .
User avatar
Memblers
Site Admin
Posts: 4044
Joined: Mon Sep 20, 2004 6:04 am
Location: Indianapolis
Contact:

Re: Turn based and input buffering

Post by Memblers »

If a sprite #0 hit is needed, you could handle it near the end of the NMI routine, so it always happens. Meanwhile the processing can take as long as it needs, in the main thread. But that does limit you to putting it near the top of the screen (or else waste tons of CPU time waiting).
I then had it execute as many turns each frame as it takes to get to the first ACTION turn for any actor. This greatly reduced the dropped input, but not completely. I'm assuming some sort of buffering would be needed. You can't buffer everything, otherwise pressing a direction would cause the player to shoot across the screen until it hit something solid. Maybe only start buffering after all buttons have been released? Maybe the entire thing is flawed. I thought about running turns until a player ACTION turn is hit, but the processing *could* take multiple frames, and would mess up the sprite0 hit.
Maybe this isn't what you're asking, but I'm not sure what you mean about buffering. We could look at something like Nethack's turn system (I don't know what it does internally, just the gameplay side). I'm thinking it's probably something like this. You'd have speed rates for every actor. Say the player's rate is 1.5, enemy #1 is 1.0, enemy #2 is 3.0

turn0:
player action
enemy #1 action
enemy #2 action
enemy #2 action
enemy #2 action

turn1:
player action
player action
enemy #1 action
enemy #2 action
enemy #2 action
enemy #2 action

and so on. game waits for input on every player action (it's kind of redefining what a "turn" is). player movement confirm would be the transition of button not pressed, to button pressed (*). the enemy movement, from the players point of view just happens all at once. enemy #2 coming towards you would appear to jump several spaces at a time. if it's next to you when your turn ends, it can attack you 3 times before your next turn. Like a familiar death in Nethack - "The leocrotta hits! The leocrotta hits! The leocrotta hits! You die..". and the player being faster than other enemies allows for the tactic such as (assuming it's always moving towards you): hit, move away, move away, hit, move away, move away, etc. and it will never touch you, only chase you. until you get cornered of course, or swarmed by other enemies.

movement speed for that could be implemented with fixed-point numbers. Add the 'rate' to your 'actor time position' on every turn. If the whole number portion of the 'time position' is non-zero, make a move, subtract 1, loop. Have the fractional portion of 'time position' preserved. then do the same for every actor.

* on second thought, this could be tricky for 8-way movement. maybe if you require any directions held for some number of frames (I imagine up+left for diagonal movement will rarely be pressed in the same exact frame). not sure if that would work well, or if any games did that. otherwise there's the indicator + move button method (like NES Genghis Khan's tactical map, NES Conflict, SNES Civilzation, I didn't like those controls very much in any of those).
Post Reply