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 AVATAR_ROTATION_DIFF 300
#define MAX_AMOUNT_OF_BULLETS 40 #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() { std::vector<Background *> FoodScene::backgrounds() {
return {}; return {};
} }
std::vector<Sprite *> FoodScene::sprites() { std::vector<Sprite *> FoodScene::sprites() {
std::vector<Sprite*> sprites = { std::vector<Sprite*> sprites;
avatar.get() // order is important for affine transformations because of updateSpritesInScene() // 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) { 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; return sprites;
} }
void FoodScene::removeBulletsOffScreen() { void FoodScene::removeBulletsOffScreen() {
// TODO crashes after this
bullets.erase( bullets.erase(
std::remove_if(bullets.begin(), bullets.end(), [](std::unique_ptr<Sprite> &s) { return s->isOffScreen(); }), std::remove_if(bullets.begin(), bullets.end(), [](std::unique_ptr<Sprite> &s) { return s->isOffScreen(); }),
bullets.end()); bullets.end());
@ -41,35 +41,46 @@ void FoodScene::removeBulletsOffScreen() {
void FoodScene::tick(u16 keys) { void FoodScene::tick(u16 keys) {
avatar->animateToFrame(0); 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(bullets.size()) + std::string(" bullets"), 1, 1);
TextStream::instance().setText(std::to_string(bulletCooldown) + std::string(" cooldown"), 2, 1);
if(keys & KEY_LEFT) { if(keys & KEY_LEFT) {
avatarRotation -= AVATAR_ROTATION_DIFF; avatarRotation -= AVATAR_ROTATION_DIFF;
} else if(keys & KEY_RIGHT) { } else if(keys & KEY_RIGHT) {
avatarRotation += AVATAR_ROTATION_DIFF; avatarRotation += AVATAR_ROTATION_DIFF;
} }
if(keys & KEY_A) { if((keys & KEY_A) && allowedToShoot) {
if(bullets.size() < MAX_AMOUNT_OF_BULLETS) { avatar->animateToFrame(1);
avatar->animateToFrame(1);
bullets.push_back(createBullet());
engine->updateSpritesInScene(); if(bullets.size() < MAX_AMOUNT_OF_BULLETS) {
//addSprite(bullets.at(bullets.size() - 1).get()); bulletCooldown = BULLET_COOLDOWN_START;
bullets.push_back(createBullet());
bulletAdded = true;
auto &b = bullets.at(bullets.size() - 1);
} }
} }
avatar->rotate(avatarRotation); avatar->rotate(avatarRotation);
if(bulletAdded) {
engine->updateSpritesInScene();
}
} }
std::unique_ptr<Sprite> FoodScene::createBullet() { std::unique_ptr<Sprite> FoodScene::createBullet() {
// TODO shared bullet data tiles return spriteBuilder->withVelocity(1, 1)
return this->spriteBuilder->withData(bullet_data, sizeof(bullet_data))
.withSize(SIZE_16_16)
.withVelocity(1, 1)
.withLocation(avatar->getX(), avatar->getY()) .withLocation(avatar->getX(), avatar->getY())
.buildPtr(); .buildWithDataOf(*someBullet.get());
} }
void FoodScene::load() { void FoodScene::load() {
@ -88,4 +99,8 @@ void FoodScene::load() {
avatar->stopAnimating(); avatar->stopAnimating();
avatarRotation = 0; 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 { class FoodScene : public Scene {
private: private:
std::unique_ptr<AffineSprite> avatar; std::unique_ptr<AffineSprite> avatar;
std::unique_ptr<Sprite> someBullet;
std::vector<std::unique_ptr<Sprite>> bullets; std::vector<std::unique_ptr<Sprite>> bullets;
int avatarRotation; int avatarRotation;
u32 bulletCooldown;
std::unique_ptr<SpriteBuilder<Sprite>> spriteBuilder; std::unique_ptr<SpriteBuilder<Sprite>> spriteBuilder;
std::unique_ptr<Sprite> createBullet(); std::unique_ptr<Sprite> createBullet();

View File

@ -25,8 +25,8 @@ public:
void setAffineIndex(int index) { this->affIndex = index; } void setAffineIndex(int index) { this->affIndex = index; }
void identity(); void identity();
void rotate(u16 alpha); 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; friend class SpriteManager;
}; };

View File

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

View File

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

View File

@ -12,6 +12,14 @@ void AffineSprite::identity() {
obj_aff_identity(this->affine.get()); 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) { void AffineSprite::rotate(u16 alpha) {
obj_aff_rotate(this->affine.get(), alpha); obj_aff_rotate(this->affine.get(), alpha);
} }
@ -48,7 +56,6 @@ void AffineSprite::buildOam(int tileIndex) {
rebuildOamAttr1ForAffineIndex(); rebuildOamAttr1ForAffineIndex();
if(!affine) { if(!affine) {
TextStream::instance() << "building";
this->affine = std::unique_ptr<OBJ_AFFINE>(new OBJ_AFFINE()); this->affine = std::unique_ptr<OBJ_AFFINE>(new OBJ_AFFINE());
identity(); identity();
} }

View File

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

View File

@ -72,10 +72,15 @@ void SpriteManager::copyOverSpriteOAMToVRAM() {
} }
void SpriteManager::copyOverImageDataToVRAM(Sprite *sprite) { void SpriteManager::copyOverImageDataToVRAM(Sprite *sprite) {
const auto allocated = Allocator::allocateObjectTiles(sprite->imageSize); if(!sprite->data && sprite->imageSize == 0) {
dma3_cpy(allocated.pointer(), sprite->data, allocated.size); // 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() { void SpriteManager::copyOverImageDataToVRAM() {