Super Mario Bros. At the party CAFe'2019 was presented demo version of the gameSuper Mario Bros. 128Kfrom Gogin (Sergei Smirnov). This demo supports the main features of the original games, including swimming, eating mushrooms, battles with Bowser and, of course, the "prin" scene cession in another castle." At the same time, it’s wonderful operates at a frequency of 50 fps. And according to Wed─ in addition to the 2002 version from the same author's engine was completely rewritten - now in color. This is not just a game, but also a specialty─ regulated resource preparation system. In particular, there is an option"COVID edition" with different graphics. Our editors were interested in how the word─ the game engine was built from the inside, andSergeyagree─ I wanted to give an interview. * * * Alone Coder> Hello! Tell us how your engine works─ jok Mario?We wrote withShiru a similar engine, but without attributes, there are no─ only what was not empty was redrawn. As I understand, you have some products─ wigs both in terms of attributes and in terms of inner─ loops, and in terms of managing all this. In the original SMB (whichported inNedoOS) in RAM there is a map of visible meta─ tiles exactly like metatiles, what about you? list of objects? How is the level stored? B original SMBthere are standard columns and large objects. At one time I thought about how to store a map entirely made up of objects that are allowed─ scrolls in all directions. But in the end it’s like this and didn’t decide how to do it quickly, and returned to metatiles... Gogin> My map is initially presented grid 256x16. Next I will compile this grid─ It is in two blocks of bytes. -The first block is a byte stream for drawing the map on the screen. In it datalaid out so that it is immediately clear─ It’s clear which sprite (tile) to print in which line of the screen, and how many are identical tiles in a row need to be printed. Format storage byte card was developed by several only months, in fact, it began with him second reincarnation of the engine in 2016 Due to the fact that byte stream decompression cards are implemented only in one direction, then you can only scroll to the right. If so─ women scroll in both directions, then this method doesn't fit. But it allows for a very small number clock cycles prepare all register pairs to print tiles. Enemies that appear (created) on the right side of the screen - also are directly programmed into this card. -The second block byte is a regular table 256x16,which stores physical properties tiles, and is used only for processing─ keys of logic and collisions in the game. Image (sprite) tile and its physical properties - these are different things. They contact at the stage level descriptions from tiles, through properties the tiles themselves. Essentially, any block in Mario is a certain─ second “sign” of activity/inactivity + sprite name. And the palette is set for the entire location, in connection with the name block. So I can have four times─ blocks: brick1, brick2, brick3, brick4. They may look the same (using─ the same sprite), but the first one will be "kicked out", the second will be the background, the third will contain a prize or coins, and four─ it can be colored or striped, because that the palette is registered only for the block brick4. One of the most difficult places in everything tile engine is removing a block from the map, restoring a block in the card or replacing it one block to another. These operations are there are spot changes in two cars at once─ tah - in bytecode for rendering and in tab─ personal card for logic processing. And if with a table map, in principle, everything is clear, then to change the byte stream for rendering - in the end, quite non-trivial─ The algorithms turned out to be perfect. Alone Coder> Is it possible to implement on your engine for example, the gameNorth Star ? Gogin> Yes, it's easy to do. Don't change anything necessary. You just have to rewrite the seal tiles 2x2 for printing tiles3x3.Work logic and all calculations in the coordinate system world - will not change. Alone Coder> And what does the output innerloop look like, including metatile selection? (Ed.: innerloop - the innermost loop.) Gogin> In a loop, we print tiles into the screen one by one─ nkam from left to right, tiles are “cleaned” themselves yourself, so the overlap goes left and right. The tile printing innerloop looks like this: - read the bytecode from the card, directly in it it says: what tile to print where and how─ only once in a row. In bytecode, every bit there has a meaning: 1 bit - command sign: or print tile, or create an enemy; 4 bits -tile number; 3 bits - number of tile repetitions; 4 bits - vertical familiarity number; 2 bits - offset of the first block in the chain, relative to the current column; 1 bit -color clearing marker after blocks (if required). Bits in bytecodelocated in such a way at once, what not to dorrcaorrlca, to drag them to a “comfortable” position for use. Next: - received all the information; - display several tiles of one at once procedure; there are different options for procedures for different numbers of identical ones in a row tiles; - color the first column on the left (vertical strip 2 familiar places); - clear the last column on the right, 2 familiar places, if the corresponding one is set flag; - if the bytecode "next" is encountered column", we move two places and repeat... - until we hit the right one screen border. Alone Coder> How many bits of subpixel coordinates Does the hero have enemies? In the original SMB the hero's subpixels are somehow strange and seem to affect speed. (Ed.: subpixels - fractional part of coordinates (smaller than a pixel).) Gogin> Everything is calculated in the system fixed point 12.4: 12 integer bit, 4 fractional bit. If we take the hex coordinate #abcd in world, then: - #ab is the tile coordinate, - c - pixel number in the tile, - d - subpixel number Alone Coder> How does Mario enter the pipe? In the original y each sprite had a mode - print by─ top of the background or below the background. Gogin> All sprites are printed in my engine always on top of tiles, by OR. Mario enters pipe exactly the same as the Piranha Plant from this pipe comes out. Decreases in cycle height of the runtime object, and moves down vertical coordinate. Prints on the screen─ This is a sprite cut off from the bottom. Alone Coder> How to enter the pipe on the side? Or just forcounting the output order, and when this should be a guarantee that the pipe is dug. not familiar? Gogin> We don’t know how to enter side pipes :) This not implemented. Basically, if we note zones where this is possible, and implement it in engine, then: - only at the time of the animation of entering the work─ boo - change the printing order (chapters first─ new hero, then tiles), - tiles are printed head-on, without any OR, so they will completely block the part hero, - for beauty, so that there are 100% no clashes─ ha, you can align the map to familiarity in moment of entry, - or you don’t have to level it, since the poppy─ the hero's maximum escape to the right and so you─ matched by familiarity, and to get clashing, you will need to run to the right first a little further than the pipe, then return back, and then climb into it. Here's a chance DO NOT get into a familiar place - high. Alone Coder> How side clipping works top, bottom? Gogin> There is no left-right clipping at all. Top and bottom clippingit works like this the same as going into a pipe and like plants. Simply Part of the sprite is printed, cut off at the top or below. Alone Coder> How memory is allocated for sprites and tiles? Gogin> Distribute memory for tiles and sprites─ is carried out fully automatically, and upon completion build, I basically don’t know where the sprites are are lying. The compiler is responsible for this, which automatically calculates everything and distributes according to free memory. When the sprites for a level are compiled, then at the input: descriptors of all entities in the game world (resources department─ but, sprites separately), world map and differences─ These settings are also resources. It turns out a kind of relational mo─ del games. Having loaded the world model into memory, you can directly calculate which sprites are needed─ are being built, and in what objects they will be used─ used. All this is automatically converted into necessary─ format suitable for the engine, folds into pa─ memory, displacement tables are built. If the object can move pixel by pixel and slowly, then 8 copies of the sprite with sme are created for it─ grievances. If the speed of the object is a multiple of two, then 4 copies are created with sm─ lenitions, etc. As a result, within one location at the exit─ where we have readyjars with sprites and go─ general tables for all tile sprites and all objects. Sprites, of course, are used─ reused if possible. Alone Coder> If the graphics are on the page, then how is it displayed on two screens? Gogin> Graphics for the 5th screen lie in the 5th page and partially in the 4th page. Graphics for the 7th screen lies in the 7th page and cha─ sticheskiy in the 2nd page. Alone Coder> How does the engine get the required sprite? Pros─ then by number, by generated label or there is a multi-level system of object class - animation number - phase number? Gogin> When the level is compiled, the entire hierarchy─ the chemistry of objects unfolds as much as possible into flat structures, down to the physical sprite addresses. For enemies, prizes and others objects - sprite addresses (physical) lie openly in immutable structures, like static properties in a class. For Thai─ catching sprite addresses is easytable, in which the sprite address depends on the number tile and the current position of the world map on screen. Here is a piece of the object processing pipeline. DY = DY + Gravity; Y = Y + DY; X = X + DX; and then animation by timer. ;Process Y = Y + dY wpf_process_y: ld e,a ;A = (ix+RO_Y) ld d,0 bit 7,e jr z,wpf_process_y_2 dec d ;DE = object dY (12.4) wpf_process_y_2: ld hl,(ix+RO_Y) ;HL=object Y (12.4) add hl,de ld (ix+RO_Y),hl ;check out of screen below ld a,h cp #fe ;Y = -32px jp z,wpf_delete_object ;Process X = X + dX wpf_process_x: ld hl,(ix+RO_X) ;coord X (12.4) ld c,l ;C = coord X low -> will ;be used below for animation ld e,(ix + RO_DX) ;dX (4.4) ld b,e ;B = dX -> will ;be used below for animation ld d,0 bit 7,e ;move left or right jr z,wpf_process_x_2 dec d ;D = #ff wpf_process_x_2: add hl,de ;X = X + dX ;check out of map at left ld a,h inc a ;cp #ff jp z,wpf_delete_object ld (ix+RO_X),hl ;Process animation wpf_process_animation: ifdef OPTIMIZE_RUNTIME_OBJECTS ld a,(internal_timer) and %00000011 jr nz,wpf_process_updown endif ;B = dX (4.4), set above ;B<=0 - move left, B>0 - move right ld d,RDEF_SPRITE_NO_LEFT_1 ld a,b dec a rla ifdef BACKWARDS ccf endif jr c,wpf_pa_1 inc d inc d ;D = RDEF_SPRITE_NO_RIGHT_1 wpf_pa_1: ;check dX == 0 ? ld a,b and a jr nz,wpf_pa_2 ;use timer if dX == 0 ld a,(internal_timer) rlca rlca rlca rlca ld c,a wpf_pa_2: ;C = coord X, set above ;bit 7 of C = sprite 1/2 bit 7,c jr nz,wpf_pa_3 inc d wpf_pa_3: ld a,d ;A = sprite cell index ;in definition ld hl,(ix+RO_DEF_ADDR) or l ld l,a ld a,(hl) ld (ix+RO_SPRITE_NO),a ;Process 'updown slide' bit wpf_process_updown: Alone Coder> А почему в версии,которая была предста─ влена на CAFe, иногда оставалось белое familiar when little Mario hit from below by brick? Gogin> This restoration does not work correctly tile background color if the player first took running, then hit his head on the block, and then slowed down. If during this time the world map has time go too far to the left, then the middle of the first block remains unpainted. The position of the knocked out block will be strongly differ slightly from the position of the same block earlier, and the attributes are restored not in in the place where they should. The bug only appeared in motion and with takeoff run There was a similar bug with the right side─ tile damage when you need to clean the attribute─ you are after the tiles. This can be corrected by redrawing the stripe attributes in their entirety, in length equal to the offset cards during the “bouncing” of the block. * * * Now Gogin is writing a new game for the world─ brand new engine. We are waiting for something no less interesting!
Share your thoughts about the article