dosgame1/scenes/GameScene.cpp

282 lines
5.7 KiB
C++

#include "GameScene.h"
#include <cstdio>
#include <cstdlib>
#include "../system/Keyboard.h"
#include "../system/Timer.h"
#include "../system/Video.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 newX = _sx + _vx;
if (newX < 0) {
newX = -newX;
_vx = -_vx;
} else if (newX >= MaxX) {
auto d = newX - MaxX;
newX = MaxX - d - 1;
_vx = -_vx;
}
_mirrorX = (_vx < 0);
auto newY = _sy + _vy;
if (newY < 0) {
newY = -newY;
_vy = -_vy;
} else if (newY >= MaxY) {
auto d = newY - MaxY;
newY = MaxY - d - 1;
_vy = -_vy;
}
_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);
}