291 lines
5.9 KiB
C++
291 lines
5.9 KiB
C++
#include "GameScene.h"
|
|
|
|
#include <cstdio>
|
|
#include <cstdlib>
|
|
|
|
#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<uint8_t *>(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);
|
|
}
|