Indivisible on NES (Playable ROM inside/Image Heavy)

Discussion in 'Indivisible' started by Kasumi, Dec 15, 2015.

  1. Kasumi

    Kasumi Better known as NEScoder

    There's a small but important difference! My text does not share horizontal lines with the "level" while Castlevania II's textbox has the "level" to the left and right of it. This is also related to why they chose to have only uppercase letters, while I have uppercase and lowercase letters. If they didn't care about the textbox having map around it, they could have chosen to have a textbox like mine, but it still would have been harder for them to program. (Note that that only applies to Castlevania II. Dracula II: Noroi no Fuuin (ドラキュラII 呪いの封印) was FDS which I think would have entirely prevented them from doing what I did. I'd actually have to research that.)

    Castlevania II came out (in Japan) before it was probably possible for them to use the hardware setup that Indivisible uses. In fact what we got even used a different hardware setup than that release, because we never got FDS.

    That's a silly thing about NES... the hardware that made a lot of the things possible in late generation games like Kirby's Adventure was not available for games like Super Mario Bros. despite it all being on NES.

    If you're familiar with the N64 Expansion Pack which added RAM, it's a bit like that. Except instead of the extensions being attached directly to the console, they were inside each game's cartridge. If you wanted to use something really cool, you had to eat the cost for every cartridge you wanted to use it in, so some developers went with worse hardware than what was currently available just to maximize profit or charge the consumer less. Even if the extra hardware cost only a dollar, or 50 cents when you pay for 200,000 of them it starts to matter!

    There's definitely over 50 different types of existing cartridge hardware, and new types are still being developed to this day. This is part of what makes it so hard to answer questions about what NES can do. It can play Game Boy games, sure. Even if you only limit to what was available in the era, there's still a lot of different possibilities. Even given two games that were released at the same time, each one might have something the other could not do or could not do as easily.

    Dunno if that's too much information or whatever. If people do have NES questions, I can probably answer them.

    Edit: Hello page two T_T
    Last edited: Jun 2, 2016
  2. Kasumi

    Kasumi Better known as NEScoder

    This is... not dead. Although it kind of was for a bit. I've been doing other things.

    Not a big update, though. All non background graphics are done and in the game. This is the HUD and other miscellaneous things. The HUD isn't programmed, just its graphics are in a format the NES can recognize. The HUD and refactoring the axe display text (I hacked it into the main loop, but it's meant to be an object) are the next things on the list. I think with those graphics done, updates should be more frequent, but no promises. ;)
  3. Goodbye18000

    Goodbye18000 Let's Player / Sonic Show Member / Canadian

    Edmonton, Alberta, Canada
    Big Band
    Hey man, life comes before video games. Those are always top priority.

    but still nice to see it's not dead
    Fumako, KaboomKid, SkullMan and 2 others like this.
  4. Kasumi

    Kasumi Better known as NEScoder

    Got some other things done before the things I mentioned in the last post. It's actually going pretty well now that I can code again, but here's a fun gif from a mistake I quickly corrected.

    ajnaglitchinaround2.gif ajnafreak2.gif
    You do you, Ajna.
    Last edited: Jul 18, 2016
    jam1220 and Broseidon Rex like this.
  5. Kit Ballard

    Kit Ballard Well-Known Member

    Murfreesboro, TN
    Ӄit ßallarɖ
    Kit Ba11ard
    Ms. Fortune
    Replying to sub thread, while saying I laughed pretty hard at the gif showing off your Mouse Enemy Code.. Those Rotis was fun to watch XD
  6. SweetShark

    SweetShark Member

    Hello there. I am new here and I see you put a lot of work for this retro prototype game.
    Can you please summarise your progress you have done so far for the game?
    Also what kind of programm you use for the pixel art?
    Thank you.
  7. Kasumi

    Kasumi Better known as NEScoder

    Tanner: Whoops, kinda missed you. Thanks for the constant support throughout this. Likes are cool, but replies are even cooler! :D

    Kit Ballard: Glad you liked the Roti spam! Thanks for subscribing, hopefully I don't fill your inbox too much with all these updates.


    I've got:
    Level Display (A basic barely compressed file format and functions to store/load/display various maps at runtime)
    Object Loading (An object is a non background thing. Like Ajna, or Roti. They're loaded with the maps.)
    A complete temple tileset (that I haven't shown because I'm probably redoing it.)
    More than 41 animations
    Technology that can display all of that animation on a console significantly slower than your phone.
    All of Ajna's out of battle abilities except for Heruka Dash. (I think?)
    All the "staple" enemies (Hungry Ghost, Ahp, Belu) have had their AI replicated reasonably carefully. (Any recolored enemy/resized enemy is not and probably will not be in the game)
    Light interaction with those enemies to be filled out later. (Ajna can be hit, die, attack them, etc)
    Frame-accurate timer that keeps track of playtime.
    "You got the axe" overlay text.
    A HUD as of hours ago. (I may make it vertical because of the sprites per scanline limit, but it's not really more work to do that)
    Various secret things
    Playable Roti

    I won't be doing:
    Anything battle system related. Sorry. Lots of reasons, will probably post them on release.

    What I don't have done is a significantly shorter list. Enemies can't die, can't detect what they're being hit with (axe vs hands)... There are only two code things left that might be hard and it's none of these. Just... NES stuff. There's also a fair amount of polish left.

    To get an idea of what "polish" is, here are some things from the known issues list.
    Known Issues (open)
    If Ajna is hit in the air, it's possible for her to face the wrong direction when she gets out of hitstun.

    If you axe hang just above a pair of Hungry Ghosts, when they attempt to lick you, they'll go into each other. (Only the hop and idle states do an action based on collision, and there's no transfer of speed between objects).

    If you get hit while doing an axe hang, your Y speed will be set like you did an axe jump. (Maybe only during debug getting hurt?)

    Perhaps force Belus to stay in the roll state for more than once frame. (The transition frame displays for 6, and it can be like 6->1->6, which is jarring)

    Consider giving jump a higher priority than attack. (If B and A are pressed on the same frame when grounded in idle, the grounded attack comes out instead of the jumping attack.)

    At 255:59.98 the timer goes to 255:00.00 instead of remaining capped.

    Refactor Vitality to actually use the vitality variable. Currently the HUD copies the vitality from Ajna's RAM to this variable. Ideally Ajna should use that byte directly, it shouldn't be part of her RAM.

    The above is about half of it, so it's not huge... but lots of small things can add up.

    There's also no music or sound effects, and I'm very likely to be redoing the only background graphics that exist. I'm not posting it because historically I've been way off, but I've got a date in my head where I want to finish the code, ignoring the polish. The music/background graphics are things I don't have data to estimate for, so still no real idea when the whole thing is coming.

    My pixel art program is Aseprite. You can see demonstrations of its features on that page by scrolling down and mousing over them. I also tried but failed to not to write a lot here. tl;dr: It's a great program, I can't recommend it enough. If you're looking to not spend any money, you can get Graphics Gale which lets you animate for free (and load/save an animated file in a proprietary format), but not save a .gif. (This you must pay for.) It can save non animated images in .png in the free version.

    Aseprite Love Letter (open)
    I have gone out of my way to try probably every pixel art program that works on Windows, supports animation, and doesn't cost #madmoney. (I've tried Pro Motion, Graphics Gale, Pyxel Edit, and freaky stuff no one has heard of like Moai or Paint of Persia or JPixel or Project Dogwaffle) This is far from an exhaustive list...

    It is my opinion that Aseprite soundly beats everything I've tried and it is not a small list. Aseprite has been in active development for 15 years, even if people have only really started hearing about it recently. Aseprite is an ~8MB download you don't have to install that lets you color replace with tolerance across frames and layers, manipulate RGB images (as opposed to just pixelly indexed images), freely move layers and frames, have multiple animations in the same file that can be tagged and exported with a command line interface.

    Layers and frames are separate concepts. (A lot of programs used to animate by making each layer a frame, so you either got layers OR you got frames. This general practice is slowly changing.) You can add 100 layers to a 200 frame huge animation, and the program won't crash. Aseprite's cel concept means it's effectively adding no image data to the file until something is drawn on those layers in each frame.

    Other programs (Pro Motion in particular) seem to do more, but they lose their user friendliness as they add features. Aseprite has managed to keep a streamlined workflow despite being pretty disgustingly feature rich.

    Aseprite does not have pressure support for tablets (though it does have opacity support) nor antialiased brushes. If it got those things I'd use it over Krita, or GIMP, or Fire Alpaca. Probably Photoshop too, but I haven't used enough of that to really know because it falls in the #madmoney category. Aseprite is not just a good "pixel" program. It's a good program in general. I paid more than it costs now for it when it was still free because it was that good. Now it's significantly better than it was then.

    The primary complaint I hear about the program... people don't like that way it looks. Whelp...

    Aseprite is free if you're a programmer and can compile it because it's open source! Otherwise, it's $15. There is a trial version that disables saving so you can explore its features. There is an old version that isn't limited in any way, and is actually still better than a lot of stuff out there. (But DO NOT USE IT if you are a Mac user. It didn't play all that well with macs at that point in its development.) Just... be aware the old version will crash sometimes, and the interface is slightly less intuitive if you go that route.

    If you can't compile, and don't want to spend money (I know the struggle), you can get Graphics Gale for free. The free version of Graphics Gale locks you out of saving and loading .gif files, but you can still animate. You just have to save in a proprietary format, and export image sequences for compilation in something else. (The free old version of Aseprite can probably do this depending on how Gale saves the png sequence, but I haven't tried it specifically.)
  8. Kit Ballard

    Kit Ballard Well-Known Member

    Murfreesboro, TN
    Ӄit ßallarɖ
    Kit Ba11ard
    Ms. Fortune
    Spam away mate
  9. missingno

    missingno Bird/Normal

    Robo Fortune
    Man this all looks so rad!
  10. KaboomKid

    KaboomKid Sure would be nice. ...TUNA FISH!

    Wow, lots of cool info! As always, take your time, man. We're just chillin' here.
    I think you mentioned this on the last page, yeah? No need to apologize. We're cool with whatever you decide to do.
    Hey, I think I might have used this before. The UI looks very familiar.

    Nice review on Aseprite too. I'll definitely need to try it out sometime. The pixel-perfect stroke and tiling features look pretty handy.
  11. SweetShark

    SweetShark Member

    Thank you for telling us your progress.
    You know, to being able to create your own pixel art, why don't you create your own enemies for the game? I would love what kind of imagination you have for your own.
  12. Kasumi

    Kasumi Better known as NEScoder

    Will do, Kit. And thanks, missingno.
    KaboomKid: I just mentioned it again because a summary of everything was requested.
    SweetShark: No problem. I have original projects I may share things from when this is done, but the goal of this is primarily to mimic the original as closely as is reasonable on the platform.

    So I've got a gettable axe now. None of this is really new, but it's tying things together.
    The t and g are connected in the text, I know. :( Input display is on so you can see me press select and not switch to the axe. Switching to hands does work once you've got the axe, but that's not shown. Just trust me. ;) The enemies/Ajna stopping movement during the axe text is one more thing I worry about causing instability. I'll write on that later, though.

    I'm working on vines/pausing next. Vines require knowing what they're hit by (axe vs hands), which is a thing enemies will also need to know. After that is tweaking the movement to hopefully better suit the different kind of gameplay present without RPG battles. Then I have to change enemies a bit based on this and make them killable. And with that, we're reasonably close to a thing I can send to my small elite team of testers. (Heh.)
    jam1220, KaboomKid and SkullMan like this.
  13. Kasumi

    Kasumi Better known as NEScoder

    Man... nearly daily updates. My plan is to make a giant post at the end with real detail about the challenges this project faced/technical stuff. But this time I'll give that sort of update, and probably just repeat myself in said giant post.

    Let's talk about about vines and collision detection. In Real Indivisible, Ajna's path is occasionally blocked by vines. Vines are solid. Ajna can't move through them, enemies very likely can't either. (I say very likely because I haven't actually checked and I've been surprised before.)

    But they're also... removable based on a condition. The way "solid" collision in Indivisible NES works is, there's a map of tiles (square graphics) that's grid aligned in ROM. A tile is solid or not. You use a position, find the tile that's there, and check if it's solid so Ajna could say... wall jump off it.

    But because the map is never in RAM, it can't be modified at run time. (Simplified a bit...) Something like a vine is incompatible with this. It needs to not only be solid when it appears, it needs to be not solid after it is hit and stay that way. Since the map can't be modified at run time, something else has to be added.

    Here's where it gets tricky: Vines should basically behave as walls so that all the code that has been verified to probably keep things out of walls can be reused and I can be about as sure she can't skip vines as I am she can't be in walls (Which isn't necessarily even 80% sure ;) ). Ideally, I could add code to check for vines to the same function that checks if a background point is solid.

    But a vine in Indivisible NES is an object, much like the Hungry Ghosts, Ahps, or Ajna herself. Unlike a tile, an object can be rectangular instead of square, and it can be placed on any pixel, rather than having to start exactly (tilesize) pixels away from another tile. This tends to mean object collision is a bit more CPU intensive to handle. But there's an even larger problem: There isn't a fixed number of objects.

    Hypothetically if I added code to the function that checks background points, CPU time would be used to check if every object was "solid" like a vine, and then do a more CPU intensive object collision check between it and the object. This sounds alright, except NES has a slow CPU. It also gets rid of one of the benefits of object collision. Vines are larger than a tile. If an object wanted to check three points in different tiles, it would have to look up vines, and then check them three times. (Well...the lookup step could be done once per frame with some cleverness.)

    Mostly a horizontal line of pixels is used to check walls. But you could do one check (if the line is in the vine) rather than the three point checks. Adding code to the point function removes one of the benefits of object collision.

    Doing the vine collision with the standard object collision loops presents some problems too. An object's position is considered "final" for the frame before that object collision loop is run. Further ejection might push them in a wall which might cause problems next frame. Changing the object's speed to one that will move it closer to outside the vine next frame is a simple approach, but it'd look a little messy. (Ajna could visually be inside the vine for several frames.) There's a secondary problem with this. The enemy bounds for object collision are not necessarily the same as the bounds for background collision, and them being different is yet another thing that might allow a vine to push an object into a wall.

    Another option is having the vines check for collisions with other objects and have the vine update them, rather than vice versa. But one design philosophy I try to follow (particularly for NES games) is objects shouldn't really modify each other except in ultra controlled ways. An object can request another object to modify itself, but the other object can totally ignore that. Vines could request that the other object move itself, but that requires RAM (how far? Which direction?) and NES doesn't... have a lot of RAM. Also remember that the bounding box the enemy leaves in RAM for other objects to collide with may not represent its solid position that well, so such a request may cause strangeness.

    It's worth noting at this point in time that for Indivisible, I've basically... not cared at all about the code I'm writing speed wise. My other NES game does... some really impressive stuff, and everything it does basically needs to be lightning fast. Indivisible was started as a break from that game... I didn't want to worry about optimizing every little thing. (If you were to disassemble the Indivisible rom, you'd find some funny code, but if you just play things should work fine which is what really matters.)

    My solution for vines (for now) is to do an object check for them inside the X ejection logic of each object, before the the function that checks the points is called. But this solution can make the game slow down. Not considerably, not more than many other NES games, but enough to make me not like it. There are more things (like music playback) which will add to the CPU load, so light frame drops now might get heavier closer to the end. I think... if I had optimized every little thing like my other game, I wouldn't have a problem with this solution. It'd be heavy, but not push-over-frame-time heavy. And maybe optimizing other parts of the game is one solution.

    I'll say... the easy part was getting Ajna to collide with vines. The hard part was the enemies, since they vary much more in object vs. "solid" collision boxes. I could just let enemies move through vines, but that's... probably kind of unacceptable.

    Writing this post has given me some ideas of other solutions. I think the solution might be hacking something into the point function after all. The more I think about it... even if the vines are objects they'll be grid aligned and I think checking an array of "fake tiles" vines have added in the point collision function is less intensive than any kind of object collision.

    Here is a gif as a reward if you read all that (or a tease if you didn't):

    There's button display again to show something interesting. Unlike Real Indivisible, Ajna can't wall jump off of vines. Wall jumping does need to check if points are solid, but the vine code isn't in the "are points solid" function. The code that checks for them is currently before general wall ejection logic. If I add "fake points" to the point check function, she would immediately be able to wall jump off a vine.

    There's no animation for cutting the vine, and it can actually be cut down with bare hands. I didn't get far enough to make a distinction, and I certainly didn't get to pausing. I knew vine-as-wall collision wasn't going to be easy, but I didn't think it'd present as many problems as it did. I kind of forgot about how enemies do all sorts of weird stuff with their position/collision boxes for display.

    Hope that was interesting. Hope I don't run into anything else except the couple things I expect to be hard.

    Writing this has given me a taste of just how long the big post might be. Yikes... Luckily some of it is already written.
    Last edited: Jul 19, 2016
  14. Kit Ballard

    Kit Ballard Well-Known Member

    Murfreesboro, TN
    Ӄit ßallarɖ
    Kit Ba11ard
    Ms. Fortune
    Brings into perspective on how nes tech was handled for things like wall chicken in Castlevania
    Goodbye18000 and KaboomKid like this.
  15. KaboomKid

    KaboomKid Sure would be nice. ...TUNA FISH!

    Yeah, I was immediately thinking about Castlevania too. I wonder if it was just as tricky to set up things like climbing vines in Super Mario, or the tadpole rooms in Megaman 3, where multiple tiles were quickly being altered and had certain actions attached to their state.

    Does it make a difference if the destructible objects are treated as individual segments rather than a big continuous object that gets removed when hit?
  16. Kasumi

    Kasumi Better known as NEScoder

    Most games wouldn't have faced this exact challenge. Most games do have a map in RAM, and things like vines are easyish when you have that. The reason why Indivisible NES doesn't is that Indivisible NES does things that would make its map use too much RAM. I have another game with a similar setup to Indivisible. Part of why I took a break on it to start Indivisible is because it does have its map in RAM, and this presented a challenge I'm still not 100% sure how I want to solve.

    I might risk greatly over-answering these questions, but there will be cool gifs!
    This is an NES project I made in two weeks for a game jam. On the left is part of the game's map. On the right are its RAM values. A one means solid, a zero means means walkable. It's color coded so you can see which sets of ones corresponds to which piece of the environment. Note that this is just how this particular game does things.

    RAM values can be written to by the program while it is running, as opposed to ROM (read-only memory) that can only be read. Most games read a piece of the map from ROM, and place it in RAM so it can be modified. (Or maybe to store an uncompressed version of it.)

    Here's is me modifying the RAM of the above game in real time. The Light Blue square is the player.

    The second I paste the row of ones, our cube buddy can not go down where he once could, even though the wall is not visible. (I have to refresh the screen to make it visible, because in this game once the level is drawn it's expected not to visually change. I rigged the screen refresh to the start button for debugging.)

    If Indivisible had its map in RAM, all vines would have to do is write ones to the map when they weren't cut down, and zeroes when they were. (Simplified.) The background collision would take care of the rest and there would be no problems. Both enemies and Ajna already collide with the background safely.

    But Indivisible's map cannot be modified by vines (or anything else), because it isn't copied to RAM. It remains in ROM at all times.

    Let's take a look at a more famous game:
    Look near where the highlighted value is. You'll see 52s change to 00s as the blocks are destroyed. The NES' limited RAM is part of why Super Mario Bros. only scrolls in one direction. If you wanted to allow the player to go back and see previous parts of the level, you would need to store the state of every block in it. There's not that much room (for Super Mario Bros.). Effectively things that pass the left edge of the screen get overwritten by the new things coming in offscreen on the right. You can even see this happening if you check the top three rows of values while the game scrolls right. Wait... there's a 5D among all those 52s... A HIDDEN BLOCK?! ;)

    (Games can add more RAM, as Super Mario Bros. 3 did. This is how it accomplishes free scrolling AND destructible environments. Indivisible NES does not currently use extra RAM.)

    As far as specifically wall chicken... well...
    I have a theory that it works a bit like how I described vines could work if I were using RAM. There's an "object" there that when struck, writes a value to that part of the map (and pushes a screen update). If you leave this area (down the stairs) after breaking these blocks, and then return, they reappear and you can no longer break them. So said object removes itself from play once triggered (otherwise you could keep getting wall chicken if you got hit in the next area). But... just a guess. I haven't actually checked.

    Much like my two week game, Mario immediately responds to the new collision, but doesn't draw it. (Tough to update the screen in real time on NES, and doing this skips the update buffer.)

    And now the questions.
    Vines in Super Mario Bros. are not too tough, and Indivisible could totally do this in a few different ways. What makes Real Indivisible vines so tough is that they're basically background collision, enemies must collide with them, and they must be togglable in a background collision system that doesn't use RAM. For a climbing vine, I'd just use an object since it doesn't need to behave particularly backgroundy, and only Ajna would need to interact with them.

    The Tadpole rooms are probably similar to wall chicken. Wall destroyed, spawn object. (Though I'd actually doubt each egg is an "object" for collision, so spawning the tadpole might be a background collision event.)

    Individual segments can mean even more collision checking, but it depends on how it's handled. I could have a row of four coins as an one object, and have the row of coins itself check with the player. If it's a miss, there's just one check. If it's a hit, more checks have to be done to find out which coins of the four I'm touching. This is better in the most common case (the player is not touching the coins) than four separate coin objects, but worse in the rare case since there'd always be an extra check. Usually stuff like coins is more of a background collision thing.

    For vines if I do add them to BG point somehow, it could be five checks as opposed to one. But the checks themselves might be faster. I'm still thinking on it. Not much has happened with Indivisible NES, but hopefully this was still a cool post and not too long.
    Last edited: Jul 20, 2016
  17. Goodbye18000

    Goodbye18000 Let's Player / Sonic Show Member / Canadian

    Edmonton, Alberta, Canada
    Big Band
    I am genuinely intruiged and am learning from all this. This is the best thread on Skullheart.

    even better than the Yogurt one
    Kit Ballard likes this.
  18. Kit Ballard

    Kit Ballard Well-Known Member

    Murfreesboro, TN
    Ӄit ßallarɖ
    Kit Ba11ard
    Ms. Fortune
    @Wall Chicken talk: Sounds about right to me. If I was some kind of programmer, I would of done the "Entity Hit, change Flag to load new map instead of old" thing. But that's my poor experience talking. Last time I sat and made a game, was back in 1991 for my Science fair.
  19. Kasumi

    Kasumi Better known as NEScoder

    Thanks, Tanner.

    I think... I'm not making what was my goal deadline for having code (sans polish) done. Vines weren't the problem. Everything else is. :D

    NES has a 1.78MHz processor. There is time for ~29780 "cycles" in a 1/60th of a second frame. Each thing (instruction) the CPU can do takes anywhere between 2 and 7 cycles. (Ignoring the "illegal" ones). However instructions are very simple, and even something simple like adding two variables and storing the result can take 4 instructions. One thing I actually like about 6502 assembly language is that most of the instructions have an immediate and obvious result. I actually think because of this, it's easy to learn. (But... hard to do things with. Even if you understand the simple instructions, it can be hard to figure out how to chain them together to do a large task.) Although... even if 6502 assembly language itself is easy, talking to NES hardware... is not easy. 6502 assembly language is a general purpose CPU that NES uses, but it's used in many other things.

    clc;Clear the carry flag
    ;You can skip that if you know it's already clear
    lda variable;loading the value of the first variable into the location I can do math on
    adc variable2;adding the value of variable2 to the value of variable
    sta variable;storing the result of the add into variable
    This code takes 11 cycles at its fastest. (9 if you know the carry flag is already clear). It can take more time depending on if the variables are in fast or slow RAM.

    I just benchmarked my code.
    Ajna's gameplay logic takes 1724 cycles when she's just standing there which is very good. Ajna's best case is actually a mere 560 cycles for game play logic. (Doing an axe hang. There's no animation playing, she doesn't move, and there are much fewer state transitions to check for than in idle.)
    It takes 2677 cycles to render her just standing there. 4401 cycles total, or about 14% of the total time in a frame. Not bad. (There's actually about 600 cycles here that belong to the logic that runs all the objects, but let's ignore that)

    A hungry ghost's gameply logic takes around 3600 cycles. Generally more than double a standing Ajna. Yikes.
    A hungry ghost rendering takes about 2276 cycles. There are usually fewer sprites to draw than Ajna, so that makes sense.

    The Ahp and Belu more or less match these times. Except a standing Belu takes about 4179 cycles to render. It makes sense, because there's a lot of sprites there. When he's rolling, it's only about 2574. Even less than Ajna.

    What does all this mean? Say I have three Hungry Ghosts and Ajna on screen. (3600+2276)*3 = 17628 for the hungry ghosts. 4401 + 17628 = 22029 is already nearly 74% of frame time. But the game is usually doing a lot more than just running object logic. It's drawing the HUD, updating the map, playing music (the game has a music engine running, even if there's no music done) and some other stuff. There are even other objects like doors. They're not CPU intensive, but all the small things add up. Add a few vines to this, and we're over frame time, but the vines themselves aren't the specific problem. (They're definitely more CPU intensive than I'd like, but... not what I should look at optimizing right now.)

    I actually can't do much about the rendering. It was written to be reasonably fast already. Making it faster is certainly possible, but at the expense of time I really would rather not spend. I've looked at the enemy logic, and there's unfortunately nothing super obvious to optimize. I've thought of a few ways to optimize the vines, but I think generally I've gotta nickel and dime in a bunch of places, rather than getting a dollar in one place. I'm... not super happy about this, but I'll persevere.

    Just to have an image, here's what I use to benchmark. Cyc is the number of cycles between when I start and stop the timer. I start it by writing to a specific location, and I stop it by writing someplace else. This has the timer set to count more or less the whole frame, but it misses some stuff that's hard to grab because of the program structure. The music engine, and certain graphical updates mainly.
    KaboomKid, Fumako and North888 like this.
  20. Kasumi

    Kasumi Better known as NEScoder

    I've totally ignored the vine/performance issues. And instead made small amounts of progress elsewhere. The game now has pausing (err... harder than you'd expect), and enemies know what they've been hit by. There's some stuff to say about pausing, but I'm honestly just gonna wait.
    Nothing much new there, but oh well.
    I'm going to start on the last hard things (vines/performance excluded) a bit later today. We'll see how hellish it'll be. When that stuff is done, I'll have some semblance of an actual game.
  21. Kasumi

    Kasumi Better known as NEScoder

    Things are actually going well, there's just not much to show visually. The hard things are basically done. One of them was very hard, the other took less than a day. (At least, hours wise. I started yesterday and should finish today.) Next on the list is hitstop and enemy death. I've been avoiding hitstop for a while, because it was a bit of a pain to think through with limited RAM. What I'll end up doing is a cheat based off of what will actually be in the demo, rather than a "real" solution. Enemy Death should be pretty easy, I just haven't allocated the RAM most of them will need for health. I've tried to be very conservative with RAM because of the music engine (which I didn't personally write), but I think it has ended up being kind of a non factor.

    After all that (hopefully tomorrow, or later today if I'm super good.), I'll begin reworking how Ajna moves. I've been unhappy with it for a very long time. It was thrown together for a thing where there were no enemies that could hurt you. This could take a while. It's a lot of little things, rather than one big or clearly hard thing. There is a third hard thing, but I can only really do it once the way Ajna moves is closer to final.

    So it's not only a text post... Background updates on NES are hard.
    Epilepsy/Flashing Light Warning I guess (open)

    Don't worry, it's now fixed.
  22. Kasumi

    Kasumi Better known as NEScoder

    Game development is full of problems you don't see during planning. "It would be easy if game developer just did X!" Nah.

    When sitting down to actually implement my plan for hitstop (or hitpause or freeze frames, or whatever the cool kids are calling it these days), I realized... an input buffer is probably helpful? That's a touch more RAM.

    Ajna has a one-two punch. This is the only thing in the game that has an input buffer, currently. (It's a super basic one.) You press B to start the punch. You can then press B at any point during that animation to start the second punch. But it actually waits to start the second punch if the first punch isn't far enough into the animation. If it just interrupted immediately, it wouldn't really be... buffered. It'd just be an input.

    Anyway, here's what this looks like:
    There's a frame counter.
    In between frames 16001 and 16002, I press B to start the first punch.
    In between frames 16002 and 16003, I release B.
    In between frames 16003 and 16004, I press B again.
    After that, I release B and don't press it again.

    The actual second part of the attack starts on frame 16011, far after I released B. It's buffered.

    And naturally, it responds immediately to the input later in the animation than that frame:
    Between frames 1000 and 1001, I press B to start the first punch.
    Between frames 1001 and 1002, I release B.
    Between frames 1019 and 1020, I press B to start the second punch. This is during a part of the animation you don't even see in the first .gif. Since it's after the cut off, the second attack starts basically immediately. (Frame 1021)

    "What does any of that have to do with hitstop?"

    Let's say there wasn't an input buffer. Imagine if Ajna hit an enemy with that first punch.
    If my plan was to not run her logic in the ensuing "freeze frames" if I pressed B during them, it would get ignored. There's no buffer to make it happen later in this hypothetical example.
    Or, a little better. I could respond to the input even without a buffer. But this means her animation frame could change during hitstop which isn't desirable.

    The above was hypothetical, of course. For the one-two punch, there's totally an input buffer, and it's basically already directly compatible with hitstop. I can run no logic except checking for B in her first punch. What a second press of B does during that state is set a bit. "B was pressed during this punch." It's not the press of B that does something, but that bit being set. So when hitstop ends, the logic that checks the bit will run again and the right animation will play and all of that good stuff. Whether it was pressed during hitstop is a non factor.

    What got me a bit worried is something like... hitstop and a potential Heruka dash state. The input buffer for the one-two punch can be simple, because there's only one action that can be buffered. From a dash you can start a jump, a punch, an axe swing, a crouching punch, a crouching axe swing, just a crouch, etc.

    All of those inputs would be valid during hitstop, so they would all need to be buffered (or... you could try to jump and it'd just... not work). Whether or not I even decide to do Heruka dash remains to be seen. (And... for all I know the original game might not do hitstop during the dash either.) To be honest, I had considered and might still consider just not doing hitstop.

    However input buffers are nice to have even without hitstop. Here's a case in Indivisible NES where you might think your jump input got eaten.
    Really, it got pressed too early. I may add a jump input buffer, but then I'd feel like I need to buffer all the other stuff... (Why can you press A to jump on that frame, but not B to swing the axe again? Then again... why can you already buffer the one-two punch and NOTHING else? I guess I thought people wouldn't mash.) I'll think on it... Almost nothing here is NES specific, except the 2KB of RAM makes me think twice about adding these things that would be free in modern stuff.

    A slightly off topic thought: If you're making games and you're not playing them frame by frame looking for stuff, you're messing up.

    So ends this "thoughts" post. I think I've given up trying to save everything for one giant mega post at the end. There will probably still be a mega post, but with links to these posts interrupting it, since writing about some of this twice would be silly.
    KaboomKid likes this.
  23. Kit Ballard

    Kit Ballard Well-Known Member

    Murfreesboro, TN
    Ӄit ßallarɖ
    Kit Ba11ard
    Ms. Fortune
    crazily enough, this applies to 3D animation too. While it's animations is a bit easier to manage, there's still things you have to watch for, and might have to add more keyframes too XD
  24. Kasumi

    Kasumi Better known as NEScoder

    I can definitely see that for 3D animation! People got super picky about a tiny bit of hair clipping through Elsa in poor Frozen.

    Very slightly after making my "frame by frame" statement, I found a bug doing that. But the explanation of that one will have to wait for the mega post.

    I'm pretty dumb and should have done hitstop a long time ago so I wasn't walking on eggshells to add it. But I guess Ajna's code is a lot of the trouble. It was written without expecting there to be enemies at all ¯\_(ツ)_/¯

    Hitstop's not really done yet, but the problems are more input buffery for potential Heruka dash and less "It's possible to get stuck in hitstop forever." (That is still a concern, though. It's possible with conditions that should be functionally impossible in the demo, but I will very likely still put a failsafe in for it and hope the failsafe doesn't fail.)

    It's subtle:
    Regular Hit:
    This delay was originally this long for testing so I could see, but it's grown on me a bit. It will probably still be made less long, but maybe not by much.
    Double Hit:

    This... one's interesting. Making this gif made me think and I realized that the part of the game that makes double hits possible is something I planned to change. (Ajna's hitbox code should not be run when it's being run.) It also highlights a bug. When both are hit, it uses the shorter hitstop value, rather than the longer Ajna hit value. I think it would be cool to have them with a special exception for it (longer hitstop than both hit and attack). I probably wouldn't do the Third Strike thing and have characters keep their attack frame rather than stun, though. Well... we'll see if double hits make it into the final game in the first place.

    Currently only the Hungry Ghost can be put into hitstop. (Ajna currently freezes herself when she hits Ahps and Belus, but they are unaffected.) Even the Hungry Ghost doesn't vibrate when hit (Like Ajna does in the not glitched double hit scenario).

    There may also be a way to miss enemies with frame perfect input. If so, it's actually a bit similar to Ness' Yo-Yo glitch (which is a cool demonstration of how some hit stuff can wrong in general).
    The bat doesn't hit because the game is trying to prevent an attack from hitting twice (just... said attack has been thoroughly glitched). Anyway, if it's possible in Indivisible NES, I'll try to fix it. Seems possible in theory, need to really try.

    I've been watching too much of the Olympics, so not much getting done here.
    Last edited: Aug 15, 2016
  25. Kit Ballard

    Kit Ballard Well-Known Member

    Murfreesboro, TN
    Ӄit ßallarɖ
    Kit Ba11ard
    Ms. Fortune
    Being a 3D animator, it does drive me nuts sometimes when I see bad animation that clip into themselves. I try to avoid that at all costs, even if it wouldn't be seen hehe. Mo-Cap animations are cool, but many forget to clean them up as the models will clip a lot and ignore "physical" boundaries of their clothing/armour. That's when I really get annoyed lol. The hand thing in that link, that's a render issue. I've seen it a few times in my own. Sometimes a motion is too fast and it lands on a half frame, causing it to split off

    Anyways, looking good, as always XD
  26. Kasumi

    Kasumi Better known as NEScoder

    The Olympics are over.
    AAAAAAHHHH! Everything that could have possibly gone wrong with hitstop did. But now it's done. Double hits lock stuff in hitstop longer, and everything else.

    And enemies being killed is done.

    And something else is done.

    But the list of things that are not done is still quite long. I gotta tell y'all: I just played through the game and it weirds me out that stuff is killable now. That hasn't been true for a very, very long time...

    There's a lot of cool stuff related to enemy death. In Real Indivisible it's pretty easy to tell when you've killed something. You see its life bar deplete, or the battle ends. In Indivisible NES, on the final hit (or for any hits after the final hit) the enemy flashes a different color.


    In Real Indivisible you can juggle enemies seemingly indefinitely after they're dead. I could have allowed that in Indivisible NES, but I didn't because there's potential for abuse. (There can't be a hundred things on screen like Real Indivisible.)

    HOWEVER! You can still totally knock 'em around a little. I'm not evil. There's a timer you don't have control over that counts down, and the enemy is destroyed when it reaches zero. But there's another timer that only counts down when the dead enemy is grounded. If you want, you can hit an enemy to reset that one a few times before the global timer decides that enemy has got to get to going. The enemy flashes, then flashes differently when a timer is about to expire. (Yes, either one! I thought of that!)
    (Also there's a double hit in that gif! Didn't plan for it.)

    Next up is a lot of gameplay refinement. And a touch of screenshake, probably.
    Last edited: Aug 27, 2016
  27. North888

    North888 Doesn't know what he's talking about

    Big Band
    So much technical stuff. Honestly comparing this to what's in the real game is really amazing. Gonna show this thread to a few friends to show how hard programming for different systems for the same game can be.
  28. Kasumi

    Kasumi Better known as NEScoder

    North888: Share away! Though I'm not sure it's the best way to show it. If Indivisible ends up using 2GB of RAM, that's 1,048,576 times the 2KB of RAM NES has. It's not quite like comparing Xbox 360 vs PS3 or something.

    Indivisible NES now has an input buffer. You may remember a gif I shared in an earlier post about pressing A very slightly before the axe swing animation ends and not getting a jump. Here's a before and after:

    In both, B is pressed on frame 1000 and A is pressed on frame 1036 while the axe animation is still playing. The second one gets the jump due to the input buffer.

    There's a lot I want to write about it, but it may not actually stay unless I can make it play nicely with pausing. There's some other things I'm not too sure about. If it ends up staying, I'll write more. I've got some cool thoughts.

    edit: Shortly after this post, I figured out the main thing I wasn't sure about. But making it work with pausing is still going to require thought. Pausing... has been a very tricky thing to work with since I put it in.
    Last edited: Aug 31, 2016
  29. SweetShark

    SweetShark Member

    Sup once again.
    A question I have, do you have plans to inform a well-known gaming site for your time if you are comfortable with the results?
  30. Kasumi

    Kasumi Better known as NEScoder

    @SweetShark: I hadn't really thought about it. I have a nebulous plan to send word of its completion to Lab Zero some way, and post it on two forums I'm active on. I also got an offer for promotion from a software dev with a okay amount of reach who I contacted for an unrelated reason. Getting the thing playable start to finish is the current goal. I'll think more about specifically press when I send it out to testers, probably.

    Let's talk about input and input buffers. This will be a long post, much of which isn't specifically about Indivisible. It's actually... kind of a dumping ground of thoughts for things I talk about often.

    In the few game communities I'm active in, I'm known for being a bit of a stickler about input. I do hold my own games to that standard, though. Even before I was considering adding an input buffer to Indivisible, I took pains to make sure you got what you pressed.
    That's me running right with bare hands selected, then pressing left, down, attack and switch weapon in the same frame, then releasing all buttons the very next frame. I get a crouching, left facing, axe attack. And you might think, "Well, Kasumi, that's what's supposed to happen." But I've played games where I'd get a crouching, left facing, hands attack because the weapon switch was processed later on the frame. Or I'd get a standing, right facing attack because I wasn't yet facing right, and wasn't yet crouching when the attack button is pressed. Worse, I've played games where my press of attack doesn't trigger any kind of attack, because switching direction (or something else) ended logic for the object for that frame.

    One of the particular things I get on people about is filtering left+right and up+down. If you have code that's like, "If button right is held, add acceleration to character" and "if button left is held, subtract acceleration from character" this means if I'm running at any speed and press the opposite direction, the net of those two things is zero and I can move at a steady, slow rate. An else if fixes that particular problem but...

    If you have the code for acceleration in one place, and the code for which direction to face in another you can have the left facing run animation play while you're moving right. Here's Super Mario Bros:

    Now, it might seem like you can just fix animation logic. "I get a left facing animation while running right in my game. I'll just switch the if statement priority for left and right in the code that controls the animation direction."

    But no. Don't do that. Do it when you read the buttons. Because then you only have to do it ONCE, instead of having to think about the order for everything that handles right/left in your game.

    Up+Down can provide the same hassles.

    (I promise I'm not picking on Super Mario Bros, it's just a game where I know this happens that isn't an unreleased indie game I'm not comfortable sharing.)

    A lot of older games don't filter left+right, because... there's a d-pad. The d-pad should PHYSICALLY prevent it from happening. Here's the lesson: Never trust hardware when you're a programmer. Never trust user input. Only pass input to anything once you've verified it's clean.

    Yoshi's Island doesn't filter left+right. It's part of why you can skip to the last level basically immediately:

    (You can also skip some courses in Wario Land the same way.)

    As I said, old games kind of had an excuse. If you are making a game that can be played with a keyboard and you are not filtering left+right, you are making a mistake.

    It's very easy. After you read the buttons, if left and right are both held (or up and down are both held), make neither of them held. You avoid so many problems this way. If you wanna go hardcore, some games take the last one pressed if both are. I am holding right. I press left while still holding right. The character starts moving left. And I am holding left. I press right while still holding left. The character starts moving right.

    I did that for a fast paced Tetris game I made. The reason for doing things this way is that if a user has a separate finger on left and right, when switching directions they may press left before releasing right. This would result in dead input for a frame or two, rather than just getting left.

    One of the first things I do when someone gives me a game to play is press left+right to see if anything odd happens. If something odd happens, I smell blood in the water and assume I will able to find a LOT of bugs in the game.

    (Before anyone says anything: Yes! I'm totally aware the first release of the Indivisible rom has two input problems described in this post. It doesn't filter left+right, and if you press B+A in the same frame you get standing axe instead of jumping axe. I hope you can forgive this because it was finished hours before it was to be shown, and I only touched it up a little assuming I wouldn't continue to work on it.)

    A user of a game can move PHYSICAL THINGS to pass information to a game. Buttons, analog sticks, whatever. Most everything a game does is based on this input. If there were no input, the same thing would happen every time. There would not be a game.

    In the case of a non pressure sensitive button, there are just two options. Held down, and not held down.

    Assume this was the only information you had. You could press and hold the jump button. The character would jump. When they landed they would jump again despite you not having pressed the button again. The game only has information about the state of the buttons for the current frame, so it doesn't know if you pressed the button while the character was still in the air, or after they landed or whatever.

    That anatomy of a button press is very simple. The button is held down this frame, but it wasn't held down last frame. A release is the opposite. The button is not held down this frame, but it was held down last frame.

    This is one of the first things game makers who aren't specifically given libraries that differentiate between a press and a hold learn. You can see this here in slow motion:
    Just so this input display is clear:
    A = A button
    B = B button
    S = Select Button
    T = Start Button
    U = Up
    D = Down
    L = Left
    R = Right

    The top row is the most recent input the game has read. Each row below that is the input from a frame before the column above it. A 1 in a column means that button was held that frame. A 0 means that button was not held that frame.

    The actual controller layout below the table is the raw input being provided, but the game does not get it immediately. It usually matches, except for left+right and up+down. Just in case you're not familiar with the NES button layout, here's a gif of each button being pressed. (As well as left+right and up+down so you can see how the raw input can differ from what the game actually uses.)
    buttonpresses allbuttons.gif

    Now let's talk about input buffers. I always had an idea about them, and how I'd do them. But I recently had a realization about them, and I haven't seen it described this way "out there".

    It's very simple: "Any game that can detect a button press already has a one frame input buffer." A press is held this frame, not held last frame. So you need to know the state of the buttons last frame. If you had the state of the buttons from two frames ago, you could detect a press from a frame ago. If you had the state of the buttons from seven frames ago and up, you could detect a button press six frames ago.

    We already know what a press looks like. With a one frame input buffer, checking for one is simple.
    Is the button held this frame?
       No, the button is not held this frame.
         Then it's not a press.
       Yes, the button is held this frame.
         Was the button held last frame?
           Yes, the button was held last frame.
             Then it's not a press.
           No, the button was not held this frame.
             It's a press!
    Checking further back is not much harder. If the first check succeeds, you've found a press. Otherwise, you check one frame back. Was THAT frame a press? Was the frame before that one?
    You can imagine that you could just keep going back on each failure for hundreds of frames looking for a press if you had an array with all previous presses. The reason why when you have eight frames of input you can only check back seven frames for a press instead of eight is because you need to know if the button was held or not held the frame BEFORE the frame you're checking too.

    So, input buffers are easy to add by themselves. Especially for me the "checking for a press needs a one frame input buffer" made them appear really easy. And if I can do it on NES, you can probably do it on something more modern.

    One of the most common stated reasons to have an input buffer is so that you don't miss a jump even if you press the button slightly before you land. But I found... you could solve that without really buffering input. If A was pressed in the air, you could start a timer that counts down. If it's still non zero on landing the jump happens. You don't need to store the state of it every frame, just how long it has been since it was last pressed. It might seem like a pedantic distinction, but thinking about things this way is why I never quite... got it.

    Anyway, it's easy to add, have and read from an input buffer. But they do present some interesting cases to think about that a one frame input buffer game (one that can detect a press and a hold for the current frame) don't have to pay attention to.

    Imagine that on the ground, idled, if you press A and B in the same frame you get a jumping axe attack. Now imagine a game with an eight frame input buffer. I am in the middle of an attack, not in idle. I press B button three frames before the attack will end. I press A button two frames before the attack will end.

    On the first frame when I return to idle, a press of both A and B are detectable. But should I get jumping axe or standing axe? If I pressed B one frame, then A the next frame in idle I would get standing axe. (A jump cannot interrupt an axe swing, which B would has started since it was pressed in idle.) It's easy to detect that the B button came first (the game had to seek back more frames to find it), but I'm actually still deciding what to do here. Currently, you do get jumping axe.

    Another small challenge is that if you buffer presses, and check for buffered presses two things that use the same button close together will always happen together without extra checks.

    I knew this would happen, but made the gif to show it off. I jump close to the wall. Wall jump uses the same button as jump, and the press that started the jump is still in the buffer. This would never happen with a one frame input buffer because by the frame she was airborne, the press would become a hold and the unheld frame before is not available to check for that press.


    To fix it in Indivisible NES, I modify the input buffer directly to turn the button press that triggered an action into a hold. You'll notice that it modifies all the previous frames to held (1). That's... probably not how I'd solve it on not NES. >_> Honestly it's bad for a lot of reasons.

    Finally, there's this thing:
    So, Ajna is facing left. She starts an axe swing in idle by pressing right and B at the same time. Before the axe swing animation is complete, she presses left+B for a frame. The code that starts the axe swing only changed the direction if a button is held when the axe swing starts, otherwise it uses the current facing direction.

    So... I made it find out how far back in the buffer the press was. And check which direction was held then. Except...:

    Now she presses left+B, then right after, but before returning to idle. This is similar to the standing axe vs jumping axe case above. I thought really hard about it, and decided that since the initial axe check code used to check which button was held when the swing started (in addition to some stuff I'm doing a bit later), that she should just face right.


    Now it looks for the LAST DIRECTION PRESSED if any, otherwise uses the current facing direction.
    There's a final weird case. If instead of pressing and releasing right, she presses and releases down... she doesn't get crouching axe unless she's still holding it when the swing starts. I thought for a bit about this. If you press and release left, you are facing left until you press right. If you press and release down, you are standing, not crouching.

    There's a lot of weird stuff with deciding on crouching vs. standing axe that I wouldn't have to consider if I didn't buffer anything. I will probably use whether you were holding down on the actual frame of the B press. Even though that's inconsistent with how left+right are done. (But crouching vs not crouching does work differently than changing direction. hold vs press or hold.)

    (Disclaimer: The input buffer for the game is currently much longer than it will end up for easy spotting of bugs and demonstration for this post. The smaller the input buffer, the less a lot of it matters. Consider that for a one frame input buffer, almost none of it matters.)

    That... was a long post. tl;dr: I think good input is important. Filter left+right. If the user presses a bunch of buttons in the same frame, think about what they probably wanted and make that thing happen, even if it's hard for you to do.

    Yes, the user is probably not gonna press a bunch of buttons in the same frame, then release them next frame, and yes, people won't necessarily notice if they get a different direction because they themselves may not really know if they pressed left or B first in a 2/60th of a second period. But there aren't a lot of reasons why it shouldn't work.

    There has not been a lot of progress on Indivisible. I obviously... did all this input buffer stuff. But haven't done anything in a few days. I need to buffer dashing still. (It won't be as good as Real Indivisible because my buffer can't be as long.) Then I need to fix dashing. There have been a lot of weird problems with it since I put it in NINE MONTHS AGO. There's a lot of other weird things I need to fix with her movement.

    After that, I fix some AI things. Then testing. I'll probably never get there. ;_; Until next time. o7
    Last edited: Sep 3, 2016
    KaboomKid and missingno like this.
  31. Fumako

    Fumako Jimbob

    The Medici's Cellar
    Big Band
    Show Spoiler


    I can barely, if at all, understand these technicalities-heavy posts.

    Is there anywhere we can check-out / download any of your other works?
    I mostly want this for fast-paced tetris, though :P

    Keep up the goodwork~! ^-^
  32. Kasumi

    Kasumi Better known as NEScoder

    @Fumako: Hmm... Basically nothing else I've done is online. I've got another NES game out, but it's... not that good. I made an RPG Makerish thing for PSP homebrew that was released and if someone has it hosted still I wasn't able to find it. I never released my Tetris because both the subseries it's based on and the Tetris company themselves aren't... huge fans of clones. It was made as a training tool for Tetris Grand Master 2's Death Mode (Not My Gameplay):

    Death is... haaaaard to get into, because you lose very quickly. So I thought: "What if you just couldn't lose?" Here's a gif of the gimmick:
    I was really proud of this idea, but I'll probably never release it because of that thing I said. Could definitely have done better with the camera.

    To this day, I still can't play Death so my tool didn't help. But I'm okay at Shirase (My Gameplay):

    The whole series has a fighting game learning curve. They're the most rewarding single player games I've ever played. Shirase is faster, but Death doesn't have hold piece, and the way the pieces move is slightly less forgiving.

    Slap anyone who thinks all Tetris games are the same. The Grand Master series makes some super intelligent design choices. Related to the previous post, the Grand Master games handle input in a SMART SMART way. It's fast, but VERY FAIR. NES Tetris is probably harder, but it's harder for the wrong reasons.

    Sadly Grand Master style is not the direction The Tetris Company is moving the new releases. I have a lot to say about Tetris, but I probably shouldn't start. (I guess I kind of did.)

    If you'd like to get into this series: is a cool place. You can get a free clone of most TGM modes here:

    Play with Classic rotation. There's probably better clones out, but that one's fine to start. Also, don't be scared of the above videos. The first game (normal mode in Texmaster) will let you play for a bit before the speed turns up to 11. (Also not me)

    To get an idea of how this series is different from other Tetris games, and strategy try here:

    When you get to IRS and you'll begin to understand how it's playable at the speeds it reaches, and why I respect the design decisions so much. Most other Tetris games are a mess by comparison. Well that was off topic, but I don't really mind. Feel free to ask Tetris questions here, heh.
    KaboomKid and missingno like this.
  33. Fumako

    Fumako Jimbob

    The Medici's Cellar
    Big Band
    Daaamn, I thought I was good at tetris (I'm not) but I can't even process what's going on here, do the pieces even "exist" before they touch other blocks? I mean, I used to be able to SSJ on reaction to the fastest normal in SG but I can't even see these pieces.

    And what's the difference between Death and Shirase? They looked... pretty much the same to my untrained eye.
    also, it only really struck me now but you're a real nerd, ain't ya? :P
    In a good, lovable maybe way too passionate sometimes way, though~
  34. Kasumi

    Kasumi Better known as NEScoder

    In most Tetris games, a piece will drop one grid cell every few frames. Then they get fast enough to maybe drop one grid cell every frame.

    TGM games get fast enough where they drop 20 grid cells every frame. The well itself is twenty grid cells high. One way to look at it is they start at the bottom. But really it's that they fall to the bottom on the very first frame they appear. They are drawn after gravity is processed, so you never see the pieces not at the bottom.

    Unlike classic Tetris games, the pieces don't lock when they hit the floor, this instant falling couldn't work that way. So the question is, "How does the game still get faster when the gravity is literally maxed?" What TGM games do is once a piece hits the floor, there's a timer counting down before the piece locks. This is called lock delay. In TGM1 throughout, lock delay is 30 frames, or half a second. Even if the pieces fall instantly, you still have a full half a second to move them so it's nothing to panic over. If the piece falls a single grid cell, lock delay is reset.

    Death and Shirase both start the pieces with the highest gravity.
    Death starts with a half second of lock delay like TGM, but at its fastest speed lock delay is a quarter of a second. (15/60)
    Shirase starts barely slower than Death's fastest lock delay(18/60th of a second) and gets to 8 frames. 8/60th of a second. The well is 10 cells wide. You could not even move a piece from the right side of the well to the left moving horizontally 1 cell every frame without resetting lock delay. Shirase's fastest speed is absolutely diabolical.

    Shirase throughout is nearly twice as fast as death, and death is not a slow mode. Shirase (and TGM3 in general) gives you more piece previews so you can plan ahead further. It has got hold piece so you can switch a piece you can't place well with one you have in stock. It has slightly better piece mobility (but that's harder to explain briefly).

    The better placement options and hold piece make it easier to play and get far, but Shirase's way harder to clear.

    And yes, I'm a bit of a nerd. Kinda gotta be to program in assembly language for fun.
    Fumako likes this.
  35. missingno

    missingno Bird/Normal

    Robo Fortune
    Oh man, that TGM training mode looks awesome! I only ever managed to beat TGM2 Normal mode, would love to try that out and see if it helps me improve faster.
  36. Goodbye18000

    Goodbye18000 Let's Player / Sonic Show Member / Canadian

    Edmonton, Alberta, Canada
    Big Band
    please write a book, I would read it forever
    Kasumi, Fumako and missingno like this.
  37. Kasumi

    Kasumi Better known as NEScoder

    I will probably not release that Tetris. Two people have it, both on PSP because then I didn't have to think about control remapping.

    There are definitely things I could write on game design, and Tetris, and Tetris game design but it seems empty when my own work is not really available for scrutiny. I could release this, and people could find loads of input bugs, and it'd make that thing I just wrote about input seem pretty stupid!

    And now... a post.

    Buffering dashes got kind of stupid.

    So! Indivisible NES has an eight frame input buffer. Expecting the user to press a button twice in eight frames is kind of mean. It's pretty fast, so we can't rely on checking for two presses in the input buffer.

    One thing the initial release lets you do is press left, then right to trigger a dash. (As opposed to the expected left, left or right, right.) Now... that's not a huge problem, but I thought it would be simple to fix.

    I thought: First I will check for left in the input buffer. If left is pressed, I will start a left facing dash timer. If left is not pressed, I will check for right. But that breaks. If left and right are both in the input buffer, left always wins, even if right was pressed more recently. (Left succeeding skips checking right AT ALL.)

    So it became: First I will check for left in the input buffer. If left is pressed, I will check right. If right is also pressed, find which one was more recent. If right is more recent, turn the right press into a hold in the input buffer. If left is more recent, turn the left press into a hold in the input buffer.

    Except: Remember, a press of both is in the input buffer. So if I turn the more recent press into a hold one frame, the next frame the other direction is very likely still in the input buffer and then it gets used. So this generally succeeds in using the press that isn't most recent. So I have to turn both presses into holds.

    In the last post, I said modifying the input buffer to turn presses into holds isn't all that cool and I probably wouldn't do it off NES. This... was a good example of why. Because a more recent press got consumed, a less recent press got processed. Even the "solution" of eating both presses is bad, because in theory that left (or right) press could have been needed for ANOTHER action. Forcing it to a hold stops it from being used by other things that might need presses. (Which is the goal of turning them into presses, but it's not always wanted.)

    It would also have been an easier thing to do if I just had a long enough input buffer to check for an entire double tap within. Also, didn't... really... have to use the input buffer or deal with any of this, because there aren't frames where the dash input wouldn't be recognized. But it was a good learning experience.

    (Dashing in Indivisible has... a lot of nuance to it besides the things above.)

    25% speed to show the effect.

    I am not 100% sure that's staying. There are P R O B L E M S there that I'm not showing. I actually... just realized I haven't even made sure buffering them works, wow. They uh... work unbuffered.

    The End.
  38. Kasumi

    Kasumi Better known as NEScoder

    Hi Skullheart. I guess... the Heruka dash is staying after all the work that was done on it...

    The collision exceptions it needs are kind of insane, and I totally think there's probably still a bug lurking... even if there isn't, it's still not done. But none of the remaining things should be even remotely as hard as making this not happen was:

    Hopefully the next post is that Ajna's movement is done, and hopefully that post isn't very far away...
    KaboomKid and Goodbye18000 like this.
  39. Goodbye18000

    Goodbye18000 Let's Player / Sonic Show Member / Canadian

    Edmonton, Alberta, Canada
    Big Band

    you got this!
    Kasumi and Kit Ballard like this.
  40. KaboomKid

    KaboomKid Sure would be nice. ...TUNA FISH!

    Whoa, is that a stunlock kill? That might be kinda cool to leave in the game if it only works in certain areas.

Share This Page


Users Viewing Thread (Users: 0, Guests: 1)