Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
363 lines
13 KiB
C
363 lines
13 KiB
C
// ____________________________
|
|
// ██▀▀█▀▀██▀▀▀▀▀▀▀█▀▀█ │ ▄▄▄ ▄▄
|
|
// ██ ▀ █▄ ▀██▄ ▀ ▄█ ▄▀▀ █ │ ▀█▄ ▄▀██ ▄█▄█ ██▀▄ ██ ▄███
|
|
// █ █ █ ▀▀ ▄█ █ █ ▀▄█ █▄ │ ▄▄█▀ ▀▄██ ██ █ ██▀ ▀█▄ ▀█▄▄
|
|
// ▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀────────┘ ▀▀
|
|
// Software tiles module sample
|
|
//─────────────────────────────────────────────────────────────────────────────
|
|
|
|
//=============================================================================
|
|
// INCLUDES
|
|
//=============================================================================
|
|
#include "msxgl.h"
|
|
#include "game/pawn.h"
|
|
#include "tile.h"
|
|
#include "debug.h"
|
|
|
|
//=============================================================================
|
|
// DEFINES
|
|
//=============================================================================
|
|
|
|
// Library's logo
|
|
#define MSX_GL "\x02\x03\x04\x05"
|
|
|
|
#define OOO 0
|
|
|
|
// Physics values
|
|
#define FORCE 20
|
|
#define GRAVITY 1
|
|
|
|
//=============================================================================
|
|
// READ-ONLY DATA
|
|
//=============================================================================
|
|
|
|
// V9990 4-bits background data
|
|
#include "content/tile/data_bg_4b.h"
|
|
|
|
// Sprites by GrafxKid (https://opengameart.org/content/super-random-sprites)
|
|
#include "content/data_sprt_layer.h"
|
|
|
|
// Fonts
|
|
#include "font/font_mgl_sample8.h"
|
|
|
|
// Sample level tiles map
|
|
const u8 g_TileMap[] =
|
|
{
|
|
OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO,
|
|
OOO, OOO, OOO, 132, 133, 134, 135, OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO,
|
|
OOO, OOO, OOO, 164, 165, 166, 167, OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, 132, 133, 134, 135, OOO, OOO, OOO, OOO, OOO, OOO, OOO,
|
|
OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, 136, 137, OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, 164, 165, 166, 167, OOO, OOO, OOO, OOO, OOO, OOO, OOO,
|
|
OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, 168, 169, OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, 136, 137, OOO,
|
|
OOO, OOO, OOO, OOO, OOO, OOO, 136, 137, OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, 168, 169, OOO,
|
|
OOO, OOO, OOO, OOO, OOO, OOO, 168, 169, OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, 136, 137, OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO,
|
|
OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, 168, 169, OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO,
|
|
OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO,
|
|
OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO,
|
|
OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO,
|
|
OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO,
|
|
OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO,
|
|
OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO,
|
|
OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO,
|
|
OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, 28, 29, OOO, OOO, OOO,
|
|
OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, 32, 33, 34, 35, OOO, OOO, OOO, OOO, OOO, OOO, 59, 60, 61, 62, OOO, OOO,
|
|
OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, OOO, 96, 97, 98, 99, OOO, OOO, OOO, OOO, OOO, 90, 91, 92, 93, 94, 95, OOO,
|
|
OOO, OOO, OOO, OOO, OOO, OOO, 32, 33, 34, 35, OOO, OOO, OOO, OOO, OOO, OOO, 64, 65, 66, 67, OOO, OOO, OOO, OOO, OOO, 122, 123, 124, 125, 126, 127, OOO,
|
|
OOO, OOO, OOO, OOO, OOO, OOO, 96, 97, 98, 99, OOO, OOO, OOO, OOO, OOO, OOO, 96, 97, 98, 99, OOO, OOO, OOO, OOO, OOO, 154, 155, 156, 157, 158, 159, OOO,
|
|
OOO, OOO, OOO, OOO, OOO, OOO, 64, 65, 66, 67, OOO, OOO, OOO, OOO, OOO, OOO, 64, 65, 66, 67, OOO, OOO, OOO, OOO, OOO, OOO, OOO, 188, 189, OOO, OOO, OOO,
|
|
33, 34, 33, 34, 33, 34, 8, 97, 98, 69, 33, 34, 33, 34, 33, 34, 8, 97, 98, 69, 33, 34, 33, 34, 33, 34, 33, 34, 33, 34, 33, 34,
|
|
66, 65, 66, 65, 66, 65, 66, 65, 66, 65, 66, 65, 66, 65, 66, 65, 66, 65, 66, 65, 66, 65, 66, 65, 66, 65, 66, 65, 66, 65, 66, 65,
|
|
98, 97, 98, 97, 98, 97, 98, 97, 98, 97, 98, 97, 98, 97, 98, 97, 98, 97, 98, 97, 98, 97, 98, 97, 98, 97, 98, 97, 98, 97, 98, 97,
|
|
66, 65, 66, 65, 66, 65, 66, 65, 66, 65, 66, 65, 66, 65, 66, 65, 66, 65, 66, 65, 66, 65, 66, 65, 66, 65, 66, 65, 66, 65, 66, 65,
|
|
98, 97, 98, 97, 98, 97, 98, 97, 98, 97, 98, 97, 98, 97, 98, 97, 98, 97, 98, 97, 98, 97, 98, 97, 98, 97, 98, 97, 98, 97, 98, 97,
|
|
};
|
|
|
|
const u8 g_TreeTileMap[] =
|
|
{
|
|
OOO, OOO, 28, 29, OOO, OOO,
|
|
OOO, 59, 60, 61, 62, OOO,
|
|
90, 91, 92, 93, 94, 95,
|
|
122, 123, 124, 125, 126, 127,
|
|
154, 155, 156, 157, 158, 159,
|
|
OOO, OOO, 188, 189, OOO, OOO,
|
|
};
|
|
|
|
// Pawn sprite layers
|
|
const Pawn_Sprite g_SpriteLayers[] =
|
|
{// X Y Pattern Color Option
|
|
{ 0, 0, 0, 1, PAWN_SPRITE_BLEND }, // Black (pattern alternated each frame)
|
|
{ 0, 0, 4, 9, 0 }, // White
|
|
{ 0, 0, 8, 15, 0 }, // Orange
|
|
};
|
|
|
|
// Idle animation frames
|
|
const Pawn_Frame g_FramesIdle[] =
|
|
{// Pattern Time Function
|
|
{ 6*16, 48, NULL },
|
|
{ 7*16, 24, NULL },
|
|
};
|
|
|
|
// Move animation frames
|
|
const Pawn_Frame g_FramesMove[] =
|
|
{// Pattern Time Function
|
|
{ 0*16, 4, NULL },
|
|
{ 1*16, 4, NULL },
|
|
{ 2*16, 4, NULL },
|
|
{ 3*16, 4, NULL },
|
|
{ 4*16, 4, NULL },
|
|
{ 5*16, 4, NULL },
|
|
};
|
|
|
|
// Jump animation frames
|
|
const Pawn_Frame g_FramesJump[] =
|
|
{// Pattern Time Function
|
|
{ 3*16, 4, NULL },
|
|
{ 8*16, 4, NULL },
|
|
};
|
|
|
|
// Fall animation frames
|
|
const Pawn_Frame g_FramesFall[] =
|
|
{// Pattern Time Function
|
|
{ 9*16, 4, NULL },
|
|
};
|
|
|
|
// Actions id
|
|
enum ANIM_ACTION_ID
|
|
{
|
|
ACTION_IDLE = 0,
|
|
ACTION_MOVE,
|
|
ACTION_JUMP,
|
|
ACTION_FALL,
|
|
};
|
|
|
|
// List of all player actions
|
|
const Pawn_Action g_AnimActions[] =
|
|
{ // Frames Number Loop? Interrupt?
|
|
{ g_FramesIdle, numberof(g_FramesIdle), TRUE, TRUE },
|
|
{ g_FramesMove, numberof(g_FramesMove), TRUE, TRUE },
|
|
{ g_FramesJump, numberof(g_FramesJump), TRUE, TRUE },
|
|
{ g_FramesFall, numberof(g_FramesFall), TRUE, TRUE },
|
|
};
|
|
|
|
// Sign-of-life animation
|
|
const u8 chrAnim[] = { '|', '\\', '-', '/' };
|
|
|
|
//=============================================================================
|
|
// MEMORY DATA
|
|
//=============================================================================
|
|
|
|
// V-synch variables
|
|
u8 g_VBlank = 0;
|
|
u8 g_Frame = 0;
|
|
|
|
// Player pawn data
|
|
Game_Pawn g_PlayerPawn;
|
|
|
|
// Input variables
|
|
bool g_bMoving = FALSE;
|
|
bool g_bJumping = FALSE;
|
|
i8 g_VelocityY;
|
|
u8 g_LastEvent = 0;
|
|
u8 g_PrevRow8 = 0xFF;
|
|
i8 g_DX = 0;
|
|
i8 g_DY = 0;
|
|
|
|
//=============================================================================
|
|
// FUNCTIONS
|
|
//=============================================================================
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// VBlank interrupt
|
|
void VBlankHook()
|
|
{
|
|
g_VBlank = 1;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Wait for V-Blank period
|
|
void WaitVBlank()
|
|
{
|
|
while (g_VBlank == 0) {}
|
|
g_VBlank = 0;
|
|
g_Frame++;
|
|
}
|
|
|
|
// Physics callback
|
|
void PhysicsEvent(u8 event, u8 tile)
|
|
{
|
|
tile;
|
|
switch (event)
|
|
{
|
|
case PAWN_PHYSICS_BORDER_LEFT:
|
|
case PAWN_PHYSICS_BORDER_RIGHT:
|
|
DEBUG_LOG("Touch border!");
|
|
DEBUG_BREAK();
|
|
g_LastEvent = event;
|
|
break;
|
|
|
|
case PAWN_PHYSICS_COL_DOWN: // Handle downward collisions
|
|
if (g_bJumping)
|
|
{
|
|
DEBUG_LOGNUM("Velocity", g_VelocityY);
|
|
DEBUG_LOG("Land on ground!");
|
|
}
|
|
g_bJumping = FALSE;
|
|
break;
|
|
|
|
case PAWN_PHYSICS_COL_UP: // Handle upward collisions
|
|
g_VelocityY = 0;
|
|
break;
|
|
|
|
case PAWN_PHYSICS_FALL: // Handle falling
|
|
if (!g_bJumping)
|
|
{
|
|
g_bJumping = TRUE;
|
|
g_VelocityY = 0;
|
|
}
|
|
break;
|
|
};
|
|
}
|
|
|
|
// Collision callback
|
|
bool PhysicsCollision(u8 tile)
|
|
{
|
|
return (((tile >= 32) && (tile <= 35)) || ((tile >= 96) && (tile <= 99)) || ((tile >= 64) && (tile <= 67)));
|
|
}
|
|
|
|
//=============================================================================
|
|
// MAIN LOOP
|
|
//=============================================================================
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Programme entry point
|
|
void main()
|
|
{
|
|
DEBUG_INIT();
|
|
DEBUG_LOG("Start debug session!");
|
|
DEBUG_PRINT("Print: %c %s %i %d %u %f %x %X %%", '*', "Example game", -1234, -1234, -1, -0.123, -1, 0xABCD);
|
|
DEBUG_PRINT("Align: [%04i] [% 4d] [%-4u] [%+i] [%04X] [%016b]", 123, 123, 123, 123, 123, 1234);
|
|
|
|
// Initialize VDP
|
|
VDP_SetMode(VDP_MODE_SCREEN5);
|
|
VDP_SetColor(6);
|
|
VDP_SetPage(0);
|
|
|
|
// Load tiles data
|
|
Tile_SetBankPage(2);
|
|
Tile_FillBank(0, 6);
|
|
Tile_FillBank(1, 7);
|
|
Tile_FillBank(2, 8);
|
|
Tile_FillBank(3, 9);
|
|
Tile_LoadBank(0, g_DataBG4b, sizeof(g_DataBG4b) / TILE_CELL_BYTES);
|
|
Tile_LoadBank(2, g_DataBG4b, sizeof(g_DataBG4b) / TILE_CELL_BYTES);
|
|
for (u8 i = 0; i < 15; ++i)
|
|
VDP_SetPaletteEntry(i + 1, *(u16*)&g_DataBG4b_palette[i*2]);
|
|
|
|
// Draw level
|
|
Tile_SetDrawPage(0);
|
|
Tile_SelectBank(0);
|
|
Tile_FillScreen(6);
|
|
Tile_DrawMapChunk( 0, 15, g_TreeTileMap, 6, 6); // Draw tree tilemap
|
|
Tile_DrawMapChunk( 3, 15, g_TreeTileMap, 6, 6);
|
|
Tile_DrawMapChunk(11, 15, g_TreeTileMap, 6, 6);
|
|
Tile_DrawScreen(g_TileMap); // Draw the whole screen tilemap
|
|
Tile_DrawBlock(10, 8, 4, 4, 4, 2); // Draw a cloud (4x2 tiles)
|
|
|
|
// Draw title
|
|
Print_SetBitmapFont(g_Font_MGL_Sample8);
|
|
Print_SetColor(0x11, 0x66);
|
|
Print_SetPosition(0, 0);
|
|
Print_DrawText(MSX_GL " SOFTWARE TILE SAMPLE");
|
|
|
|
// Initialize sprite
|
|
VDP_SetSpriteFlag(VDP_SPRITE_SIZE_16);
|
|
VDP_LoadSpritePattern(g_DataSprtLayer, 0, 13 * 4 * 4);
|
|
VDP_DisableSpritesFrom(3);
|
|
|
|
// Init player pawn
|
|
Pawn_Initialize(&g_PlayerPawn, g_SpriteLayers, numberof(g_SpriteLayers), 0, g_AnimActions);
|
|
Pawn_SetTileMap(g_TileMap);
|
|
Pawn_SetPosition(&g_PlayerPawn, 100, 100);
|
|
Pawn_SetColorBlend(&g_PlayerPawn, TRUE);
|
|
Pawn_InitializePhysics(&g_PlayerPawn, PhysicsEvent, PhysicsCollision, 16, 16);
|
|
|
|
BIOS_SetKeyClick(FALSE);
|
|
BIOS_SetHookCallback(H_TIMI, VBlankHook);
|
|
VDP_EnableVBlank(TRUE);
|
|
|
|
bool bContinue = TRUE;
|
|
while (bContinue)
|
|
{
|
|
WaitVBlank();
|
|
|
|
PROFILE_FRAME_START();
|
|
|
|
Print_SetPosition(247, 0);
|
|
Print_DrawChar(chrAnim[g_Frame & 0x03]);
|
|
|
|
if (Keyboard_IsKeyPressed(KEY_1))
|
|
VDP_SetPage(0);
|
|
if (Keyboard_IsKeyPressed(KEY_2))
|
|
VDP_SetPage(1);
|
|
if (Keyboard_IsKeyPressed(KEY_3))
|
|
VDP_SetPage(2);
|
|
if (Keyboard_IsKeyPressed(KEY_4))
|
|
VDP_SetPage(3);
|
|
|
|
g_DX = 0;
|
|
g_DY = 0;
|
|
u8 row8 = Keyboard_Read(8);
|
|
if (IS_KEY_PRESSED(row8, KEY_RIGHT))
|
|
{
|
|
g_DX++;
|
|
g_bMoving = TRUE;
|
|
}
|
|
else if (IS_KEY_PRESSED(row8, KEY_LEFT))
|
|
{
|
|
g_DX--;
|
|
g_bMoving = TRUE;
|
|
}
|
|
else
|
|
g_bMoving = FALSE;
|
|
|
|
if (g_bJumping)
|
|
{
|
|
g_DY -= g_VelocityY / 4;
|
|
|
|
g_VelocityY -= GRAVITY;
|
|
if (g_VelocityY < -FORCE)
|
|
g_VelocityY = -FORCE;
|
|
|
|
}
|
|
else if (IS_KEY_PRESSED(row8, KEY_SPACE) || IS_KEY_PRESSED(row8, KEY_UP))
|
|
{
|
|
g_bJumping = TRUE;
|
|
g_VelocityY = FORCE;
|
|
}
|
|
g_PrevRow8 = row8;
|
|
|
|
// Update player animation & physics
|
|
u8 act = ACTION_IDLE;
|
|
if (g_bJumping && (g_VelocityY >= 0))
|
|
act = ACTION_JUMP;
|
|
else if (g_bJumping)
|
|
act = ACTION_FALL;
|
|
else if (g_bMoving)
|
|
act = ACTION_MOVE;
|
|
|
|
Pawn_SetAction(&g_PlayerPawn, act);
|
|
Pawn_SetMovement(&g_PlayerPawn, g_DX, g_DY);
|
|
|
|
PROFILE_SECTION_START(1, 10, "UPDATE");
|
|
Pawn_Update(&g_PlayerPawn);
|
|
PROFILE_SECTION_END(1, 10, "UPDATE");
|
|
|
|
PROFILE_SECTION_START(1, 20, "DRAW");
|
|
Pawn_Draw(&g_PlayerPawn);
|
|
PROFILE_SECTION_END(1, 20, "DRAW");
|
|
|
|
PROFILE_FRAME_END();
|
|
}
|
|
|
|
DEBUG_LOG("End debug session!");
|
|
BIOS_Exit(0);
|
|
} |