sprite copy functionality

This commit is contained in:
wgroeneveld 2018-08-09 12:35:05 +02:00
parent b46b5a907d
commit 1f52458057
8 changed files with 112 additions and 62 deletions

View File

@ -12,28 +12,28 @@
#define AVATAR_ROTATION_DIFF 300
#define MAX_AMOUNT_OF_BULLETS 40
#define BULLET_COOLDOWN_START 20
FoodScene::FoodScene(const std::shared_ptr<GBAEngine> &engine) : Scene(engine) {}
FoodScene::FoodScene(const std::shared_ptr<GBAEngine> &engine) : Scene(engine), bulletCooldown(BULLET_COOLDOWN_START) {}
std::vector<Background *> FoodScene::backgrounds() {
return {};
}
std::vector<Sprite *> FoodScene::sprites() {
std::vector<Sprite*> sprites = {
avatar.get() // order is important for affine transformations because of updateSpritesInScene()
};
std::vector<Sprite*> sprites;
// TODO order is important for affine transformations because of affinity - those always last!
// some kind of affine bug depending on the order of sprites added in OAM
for(auto& b : bullets) {
if(!b->isOffScreen()) {
sprites.push_back(b.get());
}
sprites.push_back(b.get());
}
sprites.push_back(someBullet.get());
sprites.push_back(avatar.get());
return sprites;
}
void FoodScene::removeBulletsOffScreen() {
// TODO crashes after this
bullets.erase(
std::remove_if(bullets.begin(), bullets.end(), [](std::unique_ptr<Sprite> &s) { return s->isOffScreen(); }),
bullets.end());
@ -41,35 +41,46 @@ void FoodScene::removeBulletsOffScreen() {
void FoodScene::tick(u16 keys) {
avatar->animateToFrame(0);
bool bulletAdded, allowedToShoot;
//removeBulletsOffScreen();
if(bulletCooldown > 0) {
bulletCooldown--;
} else if(bulletCooldown == 0) {
allowedToShoot = true;
}
removeBulletsOffScreen();
TextStream::instance().setText(std::to_string(bullets.size()) + std::string(" bullets"), 1, 1);
TextStream::instance().setText(std::to_string(bulletCooldown) + std::string(" cooldown"), 2, 1);
if(keys & KEY_LEFT) {
avatarRotation -= AVATAR_ROTATION_DIFF;
} else if(keys & KEY_RIGHT) {
avatarRotation += AVATAR_ROTATION_DIFF;
}
if(keys & KEY_A) {
if(bullets.size() < MAX_AMOUNT_OF_BULLETS) {
avatar->animateToFrame(1);
bullets.push_back(createBullet());
if((keys & KEY_A) && allowedToShoot) {
avatar->animateToFrame(1);
engine->updateSpritesInScene();
//addSprite(bullets.at(bullets.size() - 1).get());
if(bullets.size() < MAX_AMOUNT_OF_BULLETS) {
bulletCooldown = BULLET_COOLDOWN_START;
bullets.push_back(createBullet());
bulletAdded = true;
auto &b = bullets.at(bullets.size() - 1);
}
}
avatar->rotate(avatarRotation);
if(bulletAdded) {
engine->updateSpritesInScene();
}
}
std::unique_ptr<Sprite> FoodScene::createBullet() {
// TODO shared bullet data tiles
return this->spriteBuilder->withData(bullet_data, sizeof(bullet_data))
.withSize(SIZE_16_16)
.withVelocity(1, 1)
return spriteBuilder->withVelocity(1, 1)
.withLocation(avatar->getX(), avatar->getY())
.buildPtr();
.buildWithDataOf(*someBullet.get());
}
void FoodScene::load() {
@ -88,4 +99,8 @@ void FoodScene::load() {
avatar->stopAnimating();
avatarRotation = 0;
someBullet = spriteBuilder->withData(bullet_data, sizeof(bullet_data))
.withSize(SIZE_16_16)
.withLocation(GBA_SCREEN_WIDTH + 20, GBA_SCREEN_HEIGHT + 20)
.buildPtr();
}

View File

@ -13,8 +13,10 @@
class FoodScene : public Scene {
private:
std::unique_ptr<AffineSprite> avatar;
std::unique_ptr<Sprite> someBullet;
std::vector<std::unique_ptr<Sprite>> bullets;
int avatarRotation;
u32 bulletCooldown;
std::unique_ptr<SpriteBuilder<Sprite>> spriteBuilder;
std::unique_ptr<Sprite> createBullet();

View File

@ -25,8 +25,8 @@ public:
void setAffineIndex(int index) { this->affIndex = index; }
void identity();
void rotate(u16 alpha);
AffineSprite(const void* imgData, int imgSize, int xC, int yC, SpriteSize spriteSize) : Sprite(imgData, imgSize, xC, yC, spriteSize), affIndex(0) {
}
explicit AffineSprite(const AffineSprite& other);
explicit AffineSprite(const void* imgData, int imgSize, int xC, int yC, SpriteSize spriteSize);
friend class SpriteManager;
};

View File

@ -47,11 +47,12 @@ private:
protected:
const void *data;
int x, y, priority, dx, dy;
int w, h, size_bits, shape_bits;
u32 x, y, priority, dx, dy;
u32 w, h, size_bits, shape_bits;
bool stayWithinBounds;
int imageSize, tileIndex;
int animationDelay, amountOfFrames, currentFrame, animationCounter;
u32 imageSize, tileIndex;
SpriteSize spriteSize;
u32 animationDelay, amountOfFrames, currentFrame, animationCounter;
bool animating;
std::unique_ptr<OBJ_ATTR> oam;
@ -61,6 +62,7 @@ protected:
void setAttributesBasedOnSize(SpriteSize size);
public:
explicit Sprite(const Sprite& other);
explicit Sprite(const void *imageData, int imageSize, int x, int y, SpriteSize size);
virtual ~Sprite() {}
@ -85,13 +87,14 @@ public:
void flipVertically(bool flip);
void flipHorizontally(bool flip);
int getDx() { return dx; }
int getDy() { return dy; }
int getX() { return x; }
int getHeight() { return h; }
int getWidth() { return w; }
int getY() { return y; }
int getCurrentFrame() { return currentFrame; }
u32 getTileIndex() { return tileIndex; }
u32 getDx() { return dx; }
u32 getDy() { return dy; }
u32 getX() { return x; }
u32 getHeight() { return h; }
u32 getWidth() { return w; }
u32 getY() { return y; }
u32 getCurrentFrame() { return currentFrame; }
bool isOffScreen();
friend class SpriteManager;

View File

@ -9,13 +9,14 @@
template<typename T> class SpriteBuilder {
private:
int imageSize;
u32 imageSize;
bool stayWithinBounds;
const void *imageData;
int x, y, dx, dy;
int numberOfFrames, animationDelay;
u32 x, y, dx, dy;
u32 numberOfFrames, animationDelay;
SpriteSize size;
void setProperties(T* sprite);
void reset() {
imageSize = x = y = dx = dy = numberOfFrames = animationDelay = 0;
imageData = nullptr;
@ -40,7 +41,7 @@ public:
return *this;
}
SpriteBuilder& withLocation(int x, int y) {
SpriteBuilder& withLocation(u32 x, u32 y) {
this->x = x;
this->y = y;
return *this;
@ -56,27 +57,38 @@ public:
}
T build();
std::unique_ptr<T> buildPtr();
std::unique_ptr<T> buildWithDataOf(const Sprite &other);
};
template<typename T> std::unique_ptr<T> SpriteBuilder<T>::buildPtr() {
auto s = new T(this->imageData, this->imageSize, this->x, this->y, this->size);
template<typename T> std::unique_ptr<T> SpriteBuilder<T>::buildWithDataOf(const Sprite &other) {
auto s = new T(other);
s->moveTo(this->x, this->y);
setProperties(s);
reset();
return std::unique_ptr<T>(s);
}
template<typename T> void SpriteBuilder<T>::setProperties(T* s) {
s->setVelocity(this->dx, this->dy);
if(this->numberOfFrames > 0) {
s->makeAnimated(this->numberOfFrames, this->animationDelay);
}
s->setStayWithinBounds(stayWithinBounds);
}
template<typename T> std::unique_ptr<T> SpriteBuilder<T>::buildPtr() {
auto s = new T(this->imageData, this->imageSize, this->x, this->y, this->size);
setProperties(s);
reset();
return std::unique_ptr<T>(s);
}
template<typename T> T SpriteBuilder<T>::build() {
T s(this->imageData, this->imageSize, this->x, this->y, this->size);
s.setVelocity(this->dx, this->dy);
if(this->numberOfFrames > 0) {
s.makeAnimated(this->numberOfFrames, this->animationDelay);
}
s.setStayWithinBounds(stayWithinBounds);
setProperties(&s);
reset();
return s;

View File

@ -12,6 +12,14 @@ void AffineSprite::identity() {
obj_aff_identity(this->affine.get());
}
AffineSprite::AffineSprite(const AffineSprite &other) : Sprite(other), affIndex(other.affIndex) {
}
AffineSprite::AffineSprite(const void *imgData, int imgSize, int xC, int yC, SpriteSize spriteSize) : Sprite(imgData, imgSize, xC, yC, spriteSize), affIndex(0) {
}
void AffineSprite::rotate(u16 alpha) {
obj_aff_rotate(this->affine.get(), alpha);
}
@ -48,7 +56,6 @@ void AffineSprite::buildOam(int tileIndex) {
rebuildOamAttr1ForAffineIndex();
if(!affine) {
TextStream::instance() << "building";
this->affine = std::unique_ptr<OBJ_AFFINE>(new OBJ_AFFINE());
identity();
}

View File

@ -8,8 +8,12 @@
#include <libgba-sprite-engine/sprites/sprite.h>
#include <libgba-sprite-engine/gba_engine.h>
Sprite::Sprite(const Sprite &other) : Sprite(nullptr, 0, other.x, other.y, other.spriteSize) {
tileIndex = other.tileIndex;
}
Sprite::Sprite(const void *imageData, int imageSize, int x, int y, SpriteSize size)
: x(x), y(y), data(imageData), imageSize(imageSize),
: x(x), y(y), data(imageData), imageSize(imageSize), spriteSize(size),
animationDelay(0), amountOfFrames(0), currentFrame(0), animationCounter(0) {
setAttributesBasedOnSize(size);
}
@ -17,7 +21,9 @@ Sprite::Sprite(const void *imageData, int imageSize, int x, int y, SpriteSize si
void Sprite::moveTo(int x, int y) {
this->x = x;
this->y = y;
syncOam();
if(oam) {
syncOam();
}
}
bool Sprite::isOffScreen() {
@ -125,19 +131,19 @@ void Sprite::buildOam(int tileIndex) {
if(!oam) {
this->oam = std::unique_ptr<OBJ_ATTR>(new OBJ_ATTR());
}
this->oam->attr0 = ATTR0_Y(this->y) |
ATTR0_MODE(0) |
(GFX_MODE << 10) |
(MOSAIC_MODE << 12) |
(COLOR_MODE_256 << 13) |
(this->shape_bits << 14);
this->oam->attr1 = this->x |
(AFFINE_FLAG_NONE_SET_YET << 9) |
(HORIZONTAL_FLIP_FLAG << 12) |
(VERTICAL_FLIP_FLAG << 13) |
(this->size_bits << 14);
this->oam->attr0 = ATTR0_Y(this->y) |
ATTR0_MODE(0) |
(GFX_MODE << 10) |
(MOSAIC_MODE << 12) |
(COLOR_MODE_256 << 13) |
(this->shape_bits << 14);
this->oam->attr1 = this->x |
(AFFINE_FLAG_NONE_SET_YET << 9) |
(HORIZONTAL_FLIP_FLAG << 12) |
(VERTICAL_FLIP_FLAG << 13) |
(this->size_bits << 14);
}
this->oam->attr2 = ATTR2_ID(tileIndex) |
ATTR2_PRIO(priority) |

View File

@ -72,10 +72,15 @@ void SpriteManager::copyOverSpriteOAMToVRAM() {
}
void SpriteManager::copyOverImageDataToVRAM(Sprite *sprite) {
const auto allocated = Allocator::allocateObjectTiles(sprite->imageSize);
dma3_cpy(allocated.pointer(), sprite->data, allocated.size);
if(!sprite->data && sprite->imageSize == 0) {
// assume it's copied over from another sprite
sprite->buildOam(sprite->tileIndex);
} else {
const auto allocated = Allocator::allocateObjectTiles(sprite->imageSize);
dma3_cpy(allocated.pointer(), sprite->data, allocated.size);
sprite->buildOam(allocated.getTileLocation());
sprite->buildOam(allocated.getTileLocation());
}
}
void SpriteManager::copyOverImageDataToVRAM() {