sprite copy functionality
This commit is contained in:
parent
b46b5a907d
commit
1f52458057
|
@ -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();
|
||||
}
|
|
@ -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();
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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) |
|
||||
|
|
|
@ -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() {
|
||||
|
|
Loading…
Reference in New Issue