Files
mazegame/projects/samples/s_game.c
T

356 lines
9.5 KiB
C

// ____________________________
// ██▀▀█▀▀██▀▀▀▀▀▀▀█▀▀█ │ ▄▄▄ ▄▄
// ██ ▀ █▄ ▀██▄ ▀ ▄█ ▄▀▀ █ │ ▀█▄ ▄▀██ ▄█▄█ ██▀▄ ██ ▄███
// █ █ █ ▀▀ ▄█ █ █ ▀▄█ █▄ │ ▄▄█▀ ▀▄██ ██ █ ██▀ ▀█▄ ▀█▄▄
// ▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀────────┘ ▀▀
// Game module sample
//─────────────────────────────────────────────────────────────────────────────
//=============================================================================
// INCLUDES
//=============================================================================
#include "msxgl.h"
#include "game/state.h"
#include "game/pawn.h"
#include "math.h"
#include "debug.h"
//=============================================================================
// DEFINES
//=============================================================================
// Physics values
#define FORCE 24
#define GRAVITY 1
#define GROUND 192
// Library's logo
#define MSX_GL "\x02\x03\x04\x05"
// Function prototypes
bool State_Initialize();
bool State_Game();
bool State_Pause();
//=============================================================================
// READ-ONLY DATA
//=============================================================================
// Font
#include "font/font_mgl_sample8.h"
// Sprites data by GrafxKid (https://opengameart.org/content/super-random-sprites)
#include "content/data_sprt_layer.h"
#include "content/data_bg.h"
// Sign-of-life character animation data
const c8 g_ChrAnim[] = { '|', '\\', '-', '/' };
// Pawn sprite layers
const Pawn_Sprite g_SpriteLayers[] =
{// X Y Pattern Color Option
{ 0, 0, 0, COLOR_BLACK, PAWN_SPRITE_BLEND }, // Black sprite alternated each frame
{ 0, 0, 4, COLOR_WHITE, 0 },
{ 0, 0, 8, COLOR_LIGHT_RED, 0 },
};
// 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[] =
{
{ 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[] =
{
{ 3*16, 4, NULL },
{ 8*16, 4, NULL },
};
// Fall animation frames
const Pawn_Frame g_FramesFall[] =
{
{ 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 },
};
//=============================================================================
// MEMORY DATA
//=============================================================================
Pawn g_PlayerPawn; // Player's pawn data structure
bool g_bFlicker = TRUE; // Activate sprite colorflickering
bool g_bMoving = FALSE; // Is player moving?
bool g_bJumping = FALSE; // Is player jumping?
i8 g_VelocityY; // Current player velocity
u8 g_PrevRow8 = 0xFF; // Previous keyboard 8th row value
i8 g_DX = 0; // Current X movement
i8 g_DY = 0; // Current Y movement
u8 g_LastEvent = 0; // Last triggered event
u16 g_Level = 0; // Current map level
bool g_bEnable = TRUE; //
//=============================================================================
// FUNCTIONS
//=============================================================================
// Physics callback
void PhysicsEvent(u8 event, u8 tile)
{
tile;
switch (event)
{
case PAWN_PHYSICS_BORDER_DOWN:
case PAWN_PHYSICS_BORDER_RIGHT:
g_LastEvent = event;
break;
case PAWN_PHYSICS_COL_DOWN: // Handle downward collisions
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 < 8);
}
//-----------------------------------------------------------------------------
// Draw the current level
void DrawLevel()
{
Print_SetPosition(25, 0);
Print_DrawInt(g_Level);
// Background
loop (i, 24-2)
VDP_FillVRAM((i == 12) ? 9 : (i < 12) ? 16 : 8, g_ScreenLayoutLow + (i+2) * 32, 0, 32);
// Ground
Math_SetRandomSeed16(g_Level);
loop (i, 8)
{
if (i == 7)
Math_SetRandomSeed16(g_Level + 1);
u8 y = Math_GetRandom16() & 0x07 ;
loop (j, y)
{
VDP_FillVRAM((j == (y - 1)) ? 1 : 3, g_ScreenLayoutLow + ((23 - j) * 32) + (i * 4), 0, 4);
}
}
// Plateforms
loop (i, 12)
{
u8 rnd = Math_GetRandom16();
VDP_FillVRAM(1, g_ScreenLayoutLow + ((rnd & 0x0F) + 2) * 32 + (rnd >> 3), 0, 2);
}
}
//-----------------------------------------------------------------------------
// Initialize the game
bool State_Initialize()
{
// Initialize display
VDP_EnableDisplay(FALSE);
VDP_SetColor(COLOR_BLACK);
// Initialize pattern
VDP_FillVRAM(0x00, g_ScreenPatternLow, 0, 256*8); // Clear pattern
VDP_WriteVRAM(g_DataBackground, g_ScreenPatternLow, 0, 24*8);
Print_SetTextFont(g_Font_MGL_Sample8, 32);
Print_SetColor(0xF, 0x1);
// Initialize color
VDP_FillVRAM(0xF0, g_ScreenColorLow, 0, 32); // Clear color
VDP_Poke_16K(0xF7, g_ScreenColorLow + 0);
VDP_Poke_16K(0x54, g_ScreenColorLow + 1);
VDP_Poke_16K(0xF5, g_ScreenColorLow + 2);
VDP_Poke_16K(0x99, g_ScreenColorLow + 3);
// 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_SetPosition(&g_PlayerPawn, 16, 16);
Pawn_SetColorBlend(&g_PlayerPawn, g_bFlicker);
Pawn_InitializePhysics(&g_PlayerPawn, PhysicsEvent, PhysicsCollision, 16, 16);
// Initialize text
Print_SetPosition(0, 0);
Print_DrawCharX(' ', 32);
Print_SetPosition(0, 0);
Print_DrawText(MSX_GL " GAME SAMPLE Lvl");
Print_DrawLineH(0, 1, 32);
// Initialize layout
DrawLevel();
VDP_EnableDisplay(TRUE);
Game_SetState(State_Game);
return FALSE; // Frame finished
}
//-----------------------------------------------------------------------------
// Update the gameplay
bool State_Game()
{
// VDP_SetColor(COLOR_DARK_GREEN);
// 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);
// VDP_SetColor(COLOR_DARK_BLUE);
Pawn_Update(&g_PlayerPawn);
// VDP_SetColor(COLOR_DARK_RED);
Pawn_Draw(&g_PlayerPawn);
// VDP_SetColor(COLOR_BLACK);
// Character animation
Print_SetPosition(31, 0);
Print_DrawChar(g_ChrAnim[g_PlayerPawn.Counter & 0x03]);
// Background horizon blink
if (g_bFlicker)
VDP_FillVRAM(g_PlayerPawn.Counter & 1 ? 9 : 10, g_ScreenLayoutLow + (12+2) * 32, 0, 32);
// Handle collision events
switch (g_LastEvent)
{
case PAWN_PHYSICS_BORDER_DOWN:
// @todo: handle game over...
break;
case PAWN_PHYSICS_BORDER_RIGHT:
g_LastEvent = 0;
Pawn_SetPosition(&g_PlayerPawn, 0 + 4, g_PlayerPawn.PositionY);
g_Level++;
DrawLevel();
break;
}
// Update movement
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;
}
if (IS_KEY_PUSHED(row8, g_PrevRow8, KEY_HOME))
{
g_bFlicker = 1 - g_bFlicker;
Pawn_SetColorBlend(&g_PlayerPawn, g_bFlicker);
}
if (IS_KEY_PUSHED(row8, g_PrevRow8, KEY_DEL))
{
g_bEnable = !g_bEnable;
Pawn_SetEnable(&g_PlayerPawn, g_bEnable);
}
g_PrevRow8 = row8;
if (Keyboard_IsKeyPressed(KEY_ESC))
Game_Exit();
return TRUE; // Frame finished
}
//-----------------------------------------------------------------------------
// Pause the game
bool State_Pause()
{
return TRUE; // Frame finished
}
//=============================================================================
// MAIN LOOP
//=============================================================================
//-----------------------------------------------------------------------------
// Programme entry point
void main()
{
BIOS_SetKeyClick(FALSE);
Game_SetState(State_Initialize);
Game_Start(VDP_MODE_GRAPHIC1, FALSE);
BIOS_Exit(0);
}