#include "GameScene.h" #include #include #include "../system/Keyboard.h" #include "../system/Video.h" #include "../audio/AudioPlayer.h" #include "../assets.h" #include "../util/Bmp.h" #include "../util/Gbm.h" #include "../util/Log.h" class TestSprite : public Sprite { public: enum { Width = 20, Height = 16, Frames = 12 }; explicit TestSprite(Bitmap *image) { _bitmap = image; _w = Width; _h = Height; SetX(10 + rand() % (SCREEN_WIDTH - 20 - Width)); SetY(10 + rand() % (SCREEN_HEIGHT - 20 - Height)); int velXSign = ((rand() & 1) << 1) - 1; int velYSign = ((rand() & 1) << 1) - 1; _vx = (rand() % 128 + 64) * velXSign; _vy = (rand() % 128 + 64) * velYSign; } void Tick() override { if (++_ticks >= 15) { _ticks = 0; if (++_frame >= Frames) { _frame = 0; } } auto playAudio = false; auto newX = _sx + _vx; if (newX < 0) { newX = -newX; _vx = -_vx; playAudio = true; } else if (newX >= MaxX) { auto d = newX - MaxX; newX = MaxX - d - 1; _vx = -_vx; playAudio = true; } _mirrorX = (_vx < 0); auto newY = _sy + _vy; if (newY < 0) { newY = -newY; _vy = -_vy; playAudio = true; } else if (newY >= MaxY) { auto d = newY - MaxY; newY = MaxY - d - 1; _vy = -_vy; playAudio = true; } if (playAudio) audioPlayer.playAudio(Assets::flaunch, 6, 0); _sx = newX; _sy = newY; } protected: int _vx{0}, _vy{0}; unsigned _ticks{0}; const int MaxX = (SCREEN_WIDTH - Width) << 8; const int MaxY = (SCREEN_HEIGHT - Height) << 8; }; class PlayerSprite : public Sprite { public: enum { Width = 24, Height = 32, Frames = 4, Speed = 480 }; explicit PlayerSprite(Bitmap *image) { _bitmap = image; _w = Width; _h = Height; SetX(20); SetY((SCREEN_HEIGHT - Height) / 2); } void Tick() override { if (++_ticks >= 15) { _ticks = 0; if (++_animationStep >= Frames) { _animationStep = 0; } _frame = _animationMap[_animationStep]; } if (keyboard.keyState[KeyLeft]) { _sx -= Speed; if (_sx < 0) _sx = 0; } if (keyboard.keyState[KeyRight]) { _sx += Speed; if (_sx > MaxX) _sx = MaxX; } if (keyboard.keyState[KeyUp]) { _sy -= Speed; if (_sy < 0) _sy = 0; } if (keyboard.keyState[KeyDown]) { _sy += Speed; if (_sy > MaxY) _sy = MaxY; } } protected: unsigned _ticks{0}; unsigned _animationStep = 0; const int MaxX = (SCREEN_WIDTH - Width) << 8; const int MaxY = (SCREEN_HEIGHT - Height) << 8; const unsigned _animationMap[4] = { 0, 1, 2, 1 }; }; GameScene::GameScene() { } GameScene::~GameScene() { } void GameScene::run() { if (_firstFrame) { Rect bgRect{0, 0, SCREEN_WIDTH, SCREEN_HEIGHT}; for (auto y = 0; y < SCREEN_HEIGHT; y++) { auto yOffset = y * SCREEN_WIDTH; for (auto x = 0; x < SCREEN_WIDTH; x++) { _fb[yOffset + x] = _bg.GetPixel(x, y); } } video.UpdateRect(bgRect); _firstFrame = false; } // Redraw background for (auto &sprite : _sprites) { clearSprite(sprite); } clearSprite(_playerSprite); // Update and paint all sprites after update for (auto &sprite : _sprites) { sprite->Tick(); drawSprite(sprite); } _playerSprite->Tick(); drawSprite(_playerSprite); } void GameScene::enter() { DefaultLog.log("Entering GameScene\n"); _fb = static_cast(video.GetFB()); _cow = Gbm::loadFromFile("cow.gbm"); _witch = Gbm::loadFromFile("witch.gbm"); _bg = Bmp::loadFromFile("bg.bmp"); _playerSprite = new PlayerSprite(&_witch); _playerSprite->SetPalette(14); for (auto &sprite : _sprites) { sprite = new TestSprite(&_cow); sprite->SetPalette(15); } // Load bg palette for (auto i = 0u; i < 64; i++) { video.SetPaletteEntry(i, _bg.GetPaletteEntry(i)); } // Load sprite palette for (auto i = 0u; i < 16; i++) { video.SetPaletteEntry(i + 240, _cow.GetPaletteEntry(i)); } // Load player sprite palette for (auto i = 0u; i < 16; i++) { video.SetPaletteEntry(i + 224, _witch.GetPaletteEntry(i)); } _firstFrame = true; } void GameScene::exit() { DefaultLog.log("Exiting GameScene\n"); for (auto &sprite : _sprites) { delete sprite; } delete _playerSprite; _cow.clear(); _bg.clear(); _witch.clear(); } void GameScene::clearSprite(Sprite *sprite) { auto rect = sprite->GetRect(); rect.clamp(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT); for (auto y = rect.y1; y < rect.y2; y++) { auto yOffset = y * SCREEN_WIDTH; for (auto x = rect.x1; x < rect.x2; x++) { _fb[yOffset + x] = _bg.GetPixel(x, y); } } video.UpdateRect(rect); } void GameScene::drawSprite(Sprite *sprite) { auto rect = sprite->GetRect(); rect.clamp(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT); auto rx = rect.x1; auto ry = rect.y1; auto rx2 = rect.x2; auto ry2 = rect.y2; auto paletteOffset = sprite->GetPalette() << 4; auto bitmap = sprite->GetBitmap(); auto syoff = sprite->GetYOffset(); if (sprite->isMirroredY()) { for (auto y = ry; y < ry2; y++) { auto yOffset = y * SCREEN_WIDTH; auto offy = ry2 - y - 1; if (sprite->isMirroredX()) { for (auto x = rx; x < rx2; x++) { auto offx = rx2 - x - 1; auto pv = bitmap->GetPixel(offx, offy + syoff); if (!(pv & 0x80)) _fb[yOffset + x] = (pv & 0x7f) + paletteOffset; } } else { for (auto x = rx; x < rx2; x++) { auto offx = x - rx; auto pv = bitmap->GetPixel(offx, offy + syoff); if (!(pv & 0x80)) _fb[yOffset + x] = (pv & 0x7f) + paletteOffset; } } } } else { for (auto y = ry; y < ry2; y++) { auto yOffset = y * SCREEN_WIDTH; auto offy = y -ry; if (sprite->isMirroredX()) { for (auto x = rx; x < rx2; x++) { auto offx = rx2 - x - 1; auto pv = bitmap->GetPixel(offx, offy + syoff); if (!(pv & 0x80)) _fb[yOffset + x] = (pv & 0x7f) + paletteOffset; } } else { for (auto x = rx; x < rx2; x++) { auto offx = x - rx; auto pv = bitmap->GetPixel(offx, offy + syoff); if (!(pv & 0x80)) _fb[yOffset + x] = (pv & 0x7f) + paletteOffset; } } } } video.UpdateRect(rect); }