Games - Super Mario Bros game device from Gogin

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