Sam’s First Steps in SCREEN 2 – Tiles and Collisions (Part 1)
- MoltS Xalats
- Aug 10
- 13 min read

Introduction
After the article Creating and Moving Sprites, where Sam first came to life, we now let him roam around his world: a stage made of 8×8 tiles built in SCREEN 2 mode.
Our feline protagonist takes his first steps among walls, water, and yellow balls, bouncing left and right while we explore how to draw stages, animate him, and detect collisions.
This is just the beginning… and yes, he really doesn’t like water!
Article Goal
En aquest primer passeig d’en Sam pel món de SCREEN 2, aprendrem a:
Construir un escenari amb tiles de 8x8, perquè el nostre gat pugui caminar amb estil.
Carregar a la VRAM tot el necessari: patrons, colors i la taula que diu quin tile va on.
Fer que en Sam es mogui d’esquerra a dreta, animat i atent a les parets on no vol xocar.
Deixar-ho tot a punt per a la següent aventura: fer scroll horitzontal i ampliar el seu món.
In this first stroll through SCREEN 2, we’ll learn how to:
Build a stage with 8×8 tiles so our cat can walk in style.
Load everything needed into VRAM: patterns, colors, and the table that tells which tile goes where.
Make Sam move left and right, animated and alert to the walls he doesn’t want to bump into.
Prepare everything for the next adventure: horizontal scrolling to expand his world.
What is SCREEN 2?
SCREEN 2 is one of the classic graphic modes of the MSX, ideal for creating game stages with a modular layout—that is, built from small, reusable graphic pieces (tiles) that allow us to assemble the stage efficiently.
It works at a resolution of 256×192 pixels, arranged in a grid of 32×24 tiles, each 8×8 pixels in size.
Unlike more modern modes like SCREEN 5, here we don’t draw pixels one by one; instead, we construct the screen using tile, small reusable graphic pieces.
Patterns and Tilemap: the mosaic world
A pattern is an 8×8-pixel graphic, usually monochrome with a second color assigned through the color table. In SCREEN 2 we can have up to 768 different patterns, divided into three banks of 256. These patterns don’t have a fixed position; instead, they are placed on screen through the Name Table.
Each on-screen tile therefore consists of:
A graphic (Pattern)
An associated color (Color Table)
A position (Name Table)
Pattern Colors
SCREEN 2 allows us to define a foreground color and a background color for each tile.
This information is stored in the VRAM Color Table.
Cada byte d’aquesta taula conté:
Els 4 bits més alts (nibble alt) → color de fons
Els 4 bits més baixos (nibble baix) → color de dibuix (foreground)
Each byte in this table contains:
The upper 4 bits (high nibble) → background color
The lower 4 bits (low nibble) → foreground (drawing) color
Example 1:
If a byte has the value 0x47, this means:
Background color: 4 (blue)
Foreground color: 7 (light blue)
When a tile is drawn, each line of 8 pixels comes from one byte of the Pattern Table:
Each bit 0 means "paint with the background color"
Each bit 1 means "paint with the foreground color"
This lets us reuse the same tile with different color combinations, saving space and making the stage graphics more varied.
Example 2:

0b00111100 // ..####..
0b01111110 // .######.
0b11011011 // ##.##.##
0b11111111 // ########
0b11111111 // ########
0b11011011 // ##.##.##
0b01111110 // .######.
0b00111100 // ..####..
unsigned char ball_pattern[8] = {
0x3C, 0x7E, 0xDB, 0xFF,
0xFF, 0xDB, 0x7E, 0x3C
};
Memory Structure in SCREEN 2
SCREEN 2 divides the VRAM into three main areas:
VRAM Area | Contents | Starting Address |
Pattern | Tile Graphics (8×8) | 0x0000 |
Color | Tile Colors | 0x2000 |
Name | Which Tile Goes in Each XY Position | 0x1800 |
Table: VRAM Memory Layout
Each on-screen tile points to a pattern number from 0 to 255 (per bank). This allows us to easily reuse graphics and build modular stages.
And the screen… can it be divided?
Yes! An interesting feature of SCREEN 2 is that we can split the screen into three horizontal sections, each 8 lines of tiles tall (8 lines × 8 pixels = 64 pixels). This is done by assigning different pattern banks to each third of the screen.
This technique is very useful for:
Creating HUDs or info panels only at the bottom
Separating the playable stage from game information
Reusing patterns without conflicts between areas

Did you know…?
The division of the SCREEN 2 display into three thirds isn’t just a visual trick: it’s an optimization designed for the MSX’s memory and its Z80 processor, an 8-bit CPU.
Cada terç (64 línies) pot utilitzar un banc de 256 patrons (tiles), cosa que encaixa perfectament amb un byte (de 0 a 255). Aquesta divisió fa més fàcil i ràpid que el sistema gràfic (el VDP) accedeixi als patrons i colors, estalviant càlculs i temps en una màquina amb recursos molt limitats.
Each third (64 lines) can use one bank of 256 patterns (tiles), which fits perfectly into a single byte (0–255). This setup makes it easier and faster for the graphics system (the VDP) to access patterns and colors, saving calculations and time on a machine with very limited resources.
Thanks to this, with just 8 bits you can manage modular, reusable stages on a 192-line screen... a true example of retro engineering!
Building the Tilemap
Our stage is defined with a two-dimensional array called tilemap[15][32]. This array acts like a blueprint indicating which tile should go in each position of the 32-column by 15-row grid (remember, SCREEN 2 allows up to 24 tile rows, but we’re only using 15 to leave room for HUDs or future experiments).
const unsigned char tilemap[MAP_HEIGHT][MAP_WIDTH] = {
{1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1},
{1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,2,2,2,2,2,2,1}, {1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,2,2,2,2,2,2,1}, {1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,2,2,2,2,2,2,1}, {1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,2,2,2,2,2,2,1}, {1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,2,2,2,1}, {1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,2,2,2,1}, {1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1}, {1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1}, {1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1}, {1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1}, {1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1}, {1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1}, {1,0,0,0,0,0,0,0,0,0,0,0,3,0,3,0,3,0,3,0,0,0,0,0,0,0,0,0,0,0,0,1},
{1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1}
};
This array contains numeric values that represent the different types of tiles available.
In our example, we have defined:
0 | Black background |
1 | Wall |
2 | Water |
3 | Ball |
Table: Tile Types
To draw this map on the screen, we loop through the array and, for each position, call the function print_tile(x, y, tile_id), which writes directly to VRAM using Vpoke().
void draw_tilemap() {
for (int y = 0; y < 15; y++) {
for (int x = 0; x < 32; x++) {
print_tile(x, y, tilemap[y][x]);
}
}
}
This function copies the contents of the tilemap from RAM to the Name Table in VRAM.
It’s important to understand that defining the map in RAM is not enough: you must explicitly transfer it to video memory.
Sam Steps In
Once we’ve drawn the stage with tiles, it’s time for our main character, Sam, to join the action.
Sam is a 16×16-pixel sprite made up of four 8×8 sprites placed next to each other.
In this first example, we’ll make him walk automatically from left to right and right to left, bouncing back when he hits a wall.
The movement is done step by step, and the collision detection is very simple: before moving Sam, we check which tile is at his future position using the function get_tile(x, y).
unsigned char get_tile(char x, char y) {
unsigned int vram_address = 0x1800 + (y * 32) + x;
return Vpeek(vram_address);
}
If the tile is a wall (value 1), Sam changes direction:
if (tile == 1) {
d = -1; // Change Direction to the Left
}
And when he bumps into a wall on the other side…
if (tile == 1) {
d = +1; // Change Direction to the Right
}
The variable d tells us the movement direction:
If d = +1, Sam moves to the right
If d = -1, Sam moves to the left
In each frame, we increment or decrement the X coordinate according to this value:
This gives us a bouncing movement, very typical of classic games—Sam goes back and forth across the screen while the stage remains unchanged.
x = x + d;
Loading patterns and colors
SCREEN 2 can hold up to 768 patterns (tile graphics) and their associated colors, distributed across three banks of 256. Each tile occupies 8 bytes and is repeated in three VRAM sections to ensure compatibility across the entire screen.
To load these patterns and colors, we use two functions:
Graphic Patterns
void load_patterns(void) {
unsigned int base_addresses[TILE_REPEAT] = {0x0000, 0x0800, 0x1000};
int section, tile, i;
for (section = 0; section < TILE_REPEAT; section++) {
VpokeFirst(base_addresses[section]);
for (tile = 0; tile < TILE_COUNT; tile++) {
for (i = 0; i < TILE_SIZE; i++) {
VpokeNext(patterns[tile][i]);
}
}
}
}
Associated Colors
void load_colors(void) {
unsigned int base_addresses[TILE_REPEAT] = {0x2000, 0x2800, 0x3000};
int section, tile, i;
for (section = 0; section < TILE_REPEAT; section++) {
VpokeFirst(base_addresses[section]);
for (tile = 0; tile < TILE_COUNT; tile++) {
for (i = 0; i < TILE_SIZE; i++) {
VpokeNext(colors[tile][i]);
}
}
}
}
These two functions write the patterns and colors to VRAM three times to cover the three horizontal thirds of the screen (64 lines each). This ensures that all tiles display correctly, regardless of their vertical position.
Why 8 bytes per tile?
Each SCREEN 2 tile is an 8×8 pixel square. Since each line of 8 pixels is represented by 1 byte (8 bits), we need 8 bytes per tile:
1 byte per line of 8 pixels
8 lines per tile
⇒ 8 × 1 = 8 bytes per tile
This format applies both to the Pattern Table (which defines the tile’s shape) and to the Color Table (which defines the foreground and background color of each line).
Therefore, a full bank of 256 tiles takes up:
256 × 8 = 2048 bytes (2 KB) for patterns
256 × 8 = 2 KB for colors
Everything fits perfectly into the defined VRAM regions:
0x0000–0x17FF → Patterns (3 × 2 KB)
0x2000–0x37FF → Colors (3 × 2 KB)
Key Concept: tilemap in RAM vs. VRAM
When we define a tilemap in our code, we usually store it in an array variable, such as:
unsigned char tilemap[15][32];
This tilemap lives in the MSX’s RAM, that is, the main memory where the code runs. But for those tiles to appear on screen, there’s a crucial step: explicitly copying the information to VRAM, the video memory controlled by the VDP.
VRAM is the only memory the video chip uses to draw the screen. So even if the tilemap is perfectly defined in RAM… the MSX won’t display it unless we perform that transfer!
How do we do it?
We iterate over the tilemap and write each tile to its corresponding position in the Name Table in VRAM:
void draw_tilemap(void) {
for (int y = 0; y < 15; y++) {
for (int x = 0; x < 32; x++) {
print_tile(x, y, tilemap[y][x]);
}
}
}
The print_tile(x, y, tile_id) function figures out the correct VRAM position and performs a Vpoke() with the right value.
This gives us flexibility!
This RAM → VRAM model lets us:
Easily modify the tilemap in code without immediately affecting the screen.
Rewrite only specific parts of the stage when needed (for optimization).
Keep a “logical” copy of the stage in memory for lookups or collision checks, as get_tile() does.
What’s next?
In this article we built a simple yet complete scene: a modular, tile-based stage, our animated main sprite, and basic collisions that give it behavior.
But this is just the beginning.
SCREEN 2 has much more potential. In the next article we’ll see how to expand the map and make it move with horizontal scrolling, extending our world beyond the initial 32 columns to 64… or more! All without losing smoothness or breaking Sam’s illusion of continuous motion.
Challenge time!
Now that you have a working foundation, why not make Sam jump? You only need:
A new state or jump variable
A check for free space above
Simulated gravity and falling
Up for it?
Click here to see the example running.
Click here to watch Sam moving in SCREEN 2.
You can download the project code here.
Project Code
//Documentation section
//
// part1.c
// Fusion-C SCREEN 2 tiles example
// Here we will learn how to populate SCREEN 2 with tiles
// MoltSXalats 2025
//
// Preprocessor section
#include "fusion-c/header/vdp_graph2.h"
#include "fusion-c/header/msx_fusion.h"
#include "fusion-c/header/vdp_sprites.h"
#define MAP_WIDTH 32
#define MAP_HEIGHT 15
#define TILE_COUNT 41
#define TILE_REPEAT 3
#define TILE_SIZE 8
const unsigned char tilemap[MAP_HEIGHT][MAP_WIDTH] = {
{1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1},
{1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,2,2,2,2,2,2,1},
{1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,2,2,2,2,2,2,1},
{1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,2,2,2,2,2,2,1},
{1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,2,2,2,2,2,2,1},
{1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,2,2,2,1},
{1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,2,2,2,1},
{1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1},
{1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1},
{1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1},
{1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1},
{1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1},
{1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1},
{1,0,0,0,0,0,0,0,0,0,0,0,3,0,3,0,3,0,3,0,0,0,0,0,0,0,0,0,0,0,0,1},
{1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1}
};
const unsigned char patterns[TILE_COUNT][TILE_SIZE] = {
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 0 background
{0x00,0x7F,0x7F,0x7F,0x00,0xF7,0xF7,0xF7}, // 1 brick
{0xFD,0xEE,0xDF,0x33,0xFD,0xEE,0xDF,0x33}, // 2 water
{0x3C,0x7F,0xDB,0xFF,0xFF,0xDB,0x7E,0x3C}, // 3 ball
{0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF}, // cursor
{0x02,0x06,0x0E,0x1E,0x3E,0x76,0xE6,0x76}, // letters
{0xFE,0xCC,0xD8,0xFE,0xCC,0xD8,0xF0,0xE0},
{0x7E,0xFC,0xC0,0xC0,0xC0,0xC0,0xFC,0x7E},
{0xFE,0xFE,0xCC,0xD8,0xF0,0xE0,0xC0,0x80},
{0xFE,0xFE,0x00,0xFE,0xFE,0x00,0xFE,0xFE},
{0xFF,0xFE,0xC0,0xFC,0xF8,0xC0,0xC0,0x80},
{0x7E,0xFC,0xC0,0xC0,0xC2,0xC6,0xFE,0x7F},
{0xC6,0xC6,0xC6,0xFE,0xFE,0xC6,0xC6,0x84},
{0x38,0x38,0x38,0x38,0x38,0x38,0x30,0x20},
{0x02,0x06,0x06,0x06,0x06,0x06,0x7E,0xFE},
{0xCE,0xDC,0xF8,0xF0,0xF8,0xDC,0xCE,0x86},
{0x40,0xC0,0xC0,0xC0,0xC0,0xC0,0xFE,0xFC},
{0x82,0xC6,0xEE,0xFE,0xFE,0xD6,0xC6,0xC6},
{0xC6,0xE6,0xF6,0xFE,0xDE,0xCE,0xC6,0x42},
{0x7C,0xFE,0xC6,0xC6,0xC6,0xC6,0xFE,0x7C},
{0xFC,0xFE,0x06,0xFE,0xFC,0xC0,0xC0,0x80},
{0x7C,0xFE,0xC6,0xC6,0xD6,0xFE,0x7C,0x10},
{0xC8,0xDC,0xCE,0xDC,0xF8,0xDC,0xCE,0x86},
{0xFE,0xFE,0x80,0xFE,0xFE,0x02,0xFE,0xFE},
{0xFE,0xFC,0x30,0x30,0x30,0x30,0x30,0x20},
{0x82,0xC6,0xC6,0xC6,0xC6,0xC6,0xFE,0x7C},
{0x03,0x06,0xCC,0xD8,0xF0,0xE0,0xC0,0x80},
{0xC6,0xC6,0xD6,0xFE,0xFE,0xEE,0xC6,0x82},
{0x86,0xCE,0xFC,0x78,0x3C,0x7E,0xE6,0xC2},
{0x87,0xCE,0xFC,0x78,0x30,0x30,0x30,0x20},
{0x7E,0xFE,0x1C,0x38,0x70,0xE0,0xFE,0xFC},
{0x7C,0x86,0x8A,0x92,0xA2,0xC2,0x7C,0x00}, // numbers
{0x10,0x30,0x50,0x90,0x10,0x10,0xFE,0x00},
{0x7C,0x82,0x02,0x0C,0x70,0x80,0xFE,0x00},
{0x7C,0x82,0x02,0x0C,0x02,0x82,0x7C,0x00},
{0x0C,0x14,0x24,0x44,0xFE,0x04,0x04,0x00},
{0xFE,0x80,0xF8,0x04,0x02,0x04,0xF8,0x00},
{0x3C,0x40,0x80,0xFC,0x82,0x82,0x7C,0x00},
{0xFE,0x82,0x04,0x08,0x10,0x10,0x10,0x00},
{0x7C,0x82,0x82,0x7C,0x82,0x82,0x7C,0x00},
{0x7C,0x82,0x82,0x7E,0x02,0x04,0x78,0x00}
};
const unsigned char colors[TILE_COUNT][TILE_SIZE] = {
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // background
{0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60}, // brick
{0x47,0x47,0x47,0x47,0x47,0x47,0x47,0x47}, // water
{0xA0,0xA0,0xA0,0xA0,0xA0,0xA0,0xA0,0xA0}, // ball
{0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0}, // cursor
{0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0}, // letters
{0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0},
{0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0},
{0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0},
{0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0},
{0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0},
{0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0},
{0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0},
{0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0},
{0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0},
{0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0},
{0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0},
{0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0},
{0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0},
{0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0},
{0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0},
{0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0},
{0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0},
{0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0},
{0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0},
{0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0},
{0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0},
{0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0},
{0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0},
{0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0},
{0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0}, // numbers
{0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0},
{0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0},
{0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0},
{0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0},
{0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0},
{0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0},
{0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0},
{0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0},
{0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0}
};
static const unsigned char body_idle_pattern_right_1[] = {
0b00000000,
0b00000000,
0b00000000,
0b00000000,
0b00000000,
0b00000000,
0b00011000,
0b00100000
};
static const unsigned char body_idle_pattern_right_2[] = {
0b00100000,
0b00100011,
0b00011111,
0b00001111,
0b00000111,
0b00000110,
0b00000010,
0b00000000
};
static const unsigned char body_idle_pattern_right_3[] = {
0b00000000,
0b00000000,
0b00000000,
0b00000000,
0b00000000,
0b00000000,
0b00000000,
0b00000000
};
static const unsigned char body_idle_pattern_right_4[] = {
0b00010100,
0b10011010,
0b11110000,
0b11110000,
0b11110000,
0b00111000,
0b00100000,
0b00000000
};
static const unsigned char detail_idle_pattern_right_1[] = {
0b00000000,
0b00000000,
0b00000000,
0b00000000,
0b00000000,
0b00000000,
0b00000000,
0b00000000
};
static const unsigned char detail_idle_pattern_right_2[] = {
0b00000000,
0b00000000,
0b00000000,
0b00000000,
0b00000000,
0b00000001,
0b00000000,
0b00000000
};
static const unsigned char detail_idle_pattern_right_3[] = {
0b00000000,
0b00000000,
0b00000000,
0b00000000,
0b00000000,
0b00000000,
0b00000000,
0b00000000
};
static const unsigned char detail_idle_pattern_right_4[] = {
0b00000000,
0b00000100,
0b00001110,
0b00001110,
0b00001100,
0b10000100,
0b10011000,
0b00000000
};
static const unsigned char body_walk_pattern_right_1[] = {
0b00000000,
0b00000000,
0b00000000,
0b00000000,
0b00000000,
0b00000000,
0b00000000,
0b00110000
};
static const unsigned char body_walk_pattern_right_2[] = {
0b01000000,
0b01000001,
0b00100011,
0b00011111,
0b00001111,
0b00011100,
0b00110000,
0b00100000
};
static const unsigned char body_walk_pattern_right_3[] = {
0b00000000,
0b00000000,
0b00000000,
0b00000000,
0b00000000,
0b00000000,
0b00000000,
0b00010100
};
static const unsigned char body_walk_pattern_right_4[] = {
0b00011010,
0b00010000,
0b10110000,
0b11110000,
0b11111000,
0b11101100,
0b00000100,
0b00000000
};
static const unsigned char detail_walk_pattern_right_1[] = {
0b00000000,
0b00000000,
0b00000000,
0b00000000,
0b00000000,
0b00000000,
0b00000000,
0b00000000
};
static const unsigned char detail_walk_pattern_right_2[] = {
0b00000000,
0b00000000,
0b00000000,
0b00000000,
0b00000000,
0b00000010,
0b00001100,
0b00001000
};
static const unsigned char detail_walk_pattern_right_3[] = {
0b00000000,
0b00000000,
0b00000000,
0b00000000,
0b00000000,
0b00000000,
0b00000000,
0b00000000
};
static const unsigned char detail_walk_pattern_right_4[] = {
0b00000100,
0b00001110,
0b00001110,
0b00001100,
0b00000100,
0b00000010,
0b00000010,
0b00000000
};
static const unsigned char body_idle_pattern_left_1[] = {
0b00000000,
0b00000000,
0b00000000,
0b00000000,
0b00000000,
0b00000000,
0b00000000
0b00000000
};
static const unsigned char body_idle_pattern_left_2[] = {
0b00101000,
0b01011001,
0b00001111,
0b00001111,
0b00001111,
0b00011100,
0b00000100,
0b00000000
};
static const unsigned char body_idle_pattern_left_3[] = {
0b00000000,
0b00000000,
0b00000000,
0b00000000,
0b00000000,
0b00000000,
0b00011000,
0b00000100
};
static const unsigned char body_idle_pattern_left_4[] = {
0b00000100,
0b11000100,
0b11111000,
0b11110000,
0b11100000,
0b01100000,
0b01000000,
0b00000000
};
static const unsigned char detail_idle_pattern_left_1[] = {
0b00000000,
0b00000000,
0b00000000,
0b00000000,
0b00000000,
0b00000000,
0b00000000,
0b00000000
};
static const unsigned char detail_idle_pattern_left_2[] = {
0b00000000,
0b00100000,
0b01110000,
0b01110000,
0b00110000,
0b00100001,
0b00011001,
0b00000000
};
static const unsigned char detail_idle_pattern_left_3[] = {
0b00000000,
0b00000000,
0b00000000,
0b00000000,
0b00000000,
0b00000000,
0b00000000,
0b00000000
};
static const unsigned char detail_idle_pattern_left_4[] = {
0b00000000,
0b00000000,
0b00000000,
0b00000000,
0b00000000,
0b10000000,
0b00000000,
0b00000000
};
static const unsigned char body_walk_pattern_left_1[] = {
0b00000000,
0b00000000,
0b00000000,
0b00000000,
0b00000000,
0b00000000,
0b00000000,
0b00101000
};
static const unsigned char body_walk_pattern_left_2[] = {
0b01011000,
0b00001000,
0b00001101,
0b00001111,
0b00011111,
0b00110111,
0b00100000,
0b00000000
};
static const unsigned char body_walk_pattern_left_3[] = {
0b00000000,
0b00000000,
0b00000000,
0b00000000,
0b00000000,
0b00000000,
0b00000000,
0b00001100
};
static const unsigned char body_walk_pattern_left_4[] = {
0b00000010,
0b00000010,
0b11000100,
0b11111000,
0b11110000,
0b00111000,
0b00001100,
0b00000100
};
static const unsigned char detail_walk_pattern_left_1[] = {
0b00000000,
0b00000000,
0b00000000,
0b00000000,
0b00000000,
0b00000000,
0b00000000,
0b00000000
};
static const unsigned char detail_walk_pattern_left_2[] = {
0b00100000,
0b01110000,
0b01110000,
0b00110000,
0b00100000,
0b01000000,
0b01000000,
0b00000000
};
static const unsigned char detail_walk_pattern_left_3[] = {
0b00000000,
0b00000000,
0b00000000,
0b00000000,
0b00000000,
0b00000000,
0b00000000,
0b00000000
};
static const unsigned char detail_walk_pattern_left_4[] = {
0b00000000,
0b00000000,
0b00000000,
0b00000000,
0b00000000,
0b01000000,
0b00110000,
0b00010000
};
static const unsigned char player_pattern[] = {
0x38,
0x7C,
0xFE,
0xFE,
0xFE,
0x7C,
0x38,
0x00
};
// Definition section of function prototypes
void load_patterns(void);
void load_colors(void);
void load_names(void);
void FT_Wait(int);
void print_tile(char,char,unsigned char);
unsigned char get_tile(char,char);
void draw_tilemap(void);
/* --------------------------------------------------------- */
void main( void ) {
char x;
char y;
int d;
x=8;
y=80;
d=1;
if(ReadMSXtype()==3) // IF MSX is Turbo-R Switch CPU to Z80 Mode
{
ChangeCPU(0);
}
SetColors(15,1,1);
Screen(2);
SpriteReset();
// The 16 x 16 pixels Sprite is made of 4 patterns
SetSpritePattern( 0, body_idle_pattern_right_1,8 );
SetSpritePattern( 1, body_idle_pattern_right_2,8 );
SetSpritePattern( 2, body_idle_pattern_right_3,8 );
SetSpritePattern( 3, body_idle_pattern_right_4,8 );
SetSpritePattern( 4, detail_idle_pattern_right_1,8 );
SetSpritePattern( 5, detail_idle_pattern_right_2,8 );
SetSpritePattern( 6, detail_idle_pattern_right_3,8 );
SetSpritePattern( 7, detail_idle_pattern_right_4,8 );
SetSpritePattern( 8, body_walk_pattern_right_1,8 );
SetSpritePattern( 9, body_walk_pattern_right_2,8 );
SetSpritePattern( 10, body_walk_pattern_right_3,8 );
SetSpritePattern( 11, body_walk_pattern_right_4,8 );
SetSpritePattern( 12, detail_walk_pattern_right_1,8 );
SetSpritePattern( 13, detail_walk_pattern_right_2,8 );
SetSpritePattern( 14, detail_walk_pattern_right_3,8 );
SetSpritePattern( 15, detail_walk_pattern_right_4,8 );
SetSpritePattern( 16, body_idle_pattern_left_1,8 );
SetSpritePattern( 17, body_idle_pattern_left_2,8 );
SetSpritePattern( 18, body_idle_pattern_left_3,8 );
SetSpritePattern( 19, body_idle_pattern_left_4,8 );
SetSpritePattern( 20, detail_idle_pattern_left_1,8 );
SetSpritePattern( 21, detail_idle_pattern_left_2,8 );
SetSpritePattern( 22, detail_idle_pattern_left_3,8 );
SetSpritePattern( 23, detail_idle_pattern_left_4,8 );
SetSpritePattern( 24, body_walk_pattern_left_1,8 );
SetSpritePattern( 25, body_walk_pattern_left_2,8 );
SetSpritePattern( 26, body_walk_pattern_left_3,8 );
SetSpritePattern( 27, body_walk_pattern_left_4,8 );
SetSpritePattern( 28, detail_walk_pattern_left_1,8 );
SetSpritePattern( 29, detail_walk_pattern_left_2,8 );
SetSpritePattern( 30, detail_walk_pattern_left_3,8 );
SetSpritePattern( 31, detail_walk_pattern_left_4,8 );
SetSpritePattern( 32, player_pattern,8 );
load_patterns();
load_colors();
draw_tilemap();
//load_names();
Sprite16();
// Player 2
//PutSprite (3,32,8,8,2);
// Pilota
//print_tile(28, 13, 3);
while (Inkey()!=27)
{
x=(x+d)&255;
char tile_x = x / 8;
char tile_y = y / 8;
if (d==1) {
// Movement
if( x % 2 == 0)
{
PutSprite (1,0,x,y,4);
PutSprite (2,4,x,y,14);
}
if( x % 2 == 1)
{
PutSprite (1,8,x,y,4);
PutSprite (2,12,x,y,14);
}
// Collisions
unsigned char tile = get_tile(tile_x + 2,tile_y);
if (tile == 1) {
// It's a wall → can't walk through
d = -1;
//break;
} else if (tile == 2) {
// It's water → lose a life
} else if (tile == 3) {
// Yellow ball → collect it
}
} // if (d==1) {
if (d==-1) {
//Movement
if( x % 2 == 0)
{
PutSprite (1,16,x,y,4);
PutSprite (2,20,x,y,14);
}
if( x % 2 == 1)
{
PutSprite (1,24,x,y,4);
PutSprite (2,28,x,y,14);
}
//Collisions
unsigned char tile = get_tile(tile_x,tile_y);
if (tile == 1) {
// It's a wall → can't walk through
d = -1;
//break;
} else if (tile == 2) {
// It's water → lose a life
} else if (tile == 3) {
// Yellow ball → collect it
}
} // if (d==-1) {
FT_Wait(3000);
} // while
Screen(0);
Exit(0);
} // main
// User defined functions section
void load_patterns(void) {
unsigned int base_addresses[TILE_REPEAT] = {0x0000, 0x0800, 0x1000};
int section, tile, i;
for (section = 0; section < TILE_REPEAT; section++) {
VpokeFirst(base_addresses[section]);
for (tile = 0; tile < TILE_COUNT; tile++) {
for (i = 0; i < TILE_SIZE; i++) {
VpokeNext(patterns[tile][i]);
}
}
}
}
void load_colors(void) {
unsigned int base_addresses[TILE_REPEAT] = {0x2000, 0x2800, 0x3000};
int section, tile, i;
for (section = 0; section < TILE_REPEAT; section++) {
VpokeFirst(base_addresses[section]);
for (tile = 0; tile < TILE_COUNT; tile++) {
for (i = 0; i < TILE_SIZE; i++) {
VpokeNext(colors[tile][i]);
}
}
}
}
void load_names(void) {
int x, y;
unsigned int vram_address = 0x1800; // Name Table start for SCREEN 2
VpokeFirst(vram_address); // Initialize VRAM write operation
for (y = 0; y < MAP_HEIGHT; y++) {
for (x = 0; x < MAP_WIDTH; x++) {
VpokeNext(tilemap[y][x]); // Write the corresponding tile
}
}
}
void draw_tilemap(void) {
int y, x;
for (y = 0; y < MAP_HEIGHT; y++) {
for (x = 0; x < MAP_WIDTH; x++) {
print_tile(x, y, tilemap[y][x]);
}
}
}
void FT_Wait(int cicles) {
unsigned int i;
for(i=0;i<cicles;i++)
{}
}
void print_tile(char x, char y, unsigned char tile_id) {
unsigned int vram_address = 0x1800 + (y * 32) + x;
Vpoke(vram_address, tile_id);
}
unsigned char get_tile(char x, char y) {
unsigned int vram_address = 0x1800 + (y * 32) + x;
return Vpeek(vram_address);
}
Comments