diff --git a/demos/demo3-foodthrowing/src/food_scene.cpp b/demos/demo3-foodthrowing/src/food_scene.cpp index f5d83b7..7f79620 100644 --- a/demos/demo3-foodthrowing/src/food_scene.cpp +++ b/demos/demo3-foodthrowing/src/food_scene.cpp @@ -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 &engine) : Scene(engine) {} +FoodScene::FoodScene(const std::shared_ptr &engine) : Scene(engine), bulletCooldown(BULLET_COOLDOWN_START) {} std::vector FoodScene::backgrounds() { return {}; } std::vector FoodScene::sprites() { - std::vector sprites = { - avatar.get() // order is important for affine transformations because of updateSpritesInScene() - }; + std::vector 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 &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 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(); } \ No newline at end of file diff --git a/demos/demo3-foodthrowing/src/food_scene.h b/demos/demo3-foodthrowing/src/food_scene.h index dd70955..77234b9 100644 --- a/demos/demo3-foodthrowing/src/food_scene.h +++ b/demos/demo3-foodthrowing/src/food_scene.h @@ -13,8 +13,10 @@ class FoodScene : public Scene { private: std::unique_ptr avatar; + std::unique_ptr someBullet; std::vector> bullets; int avatarRotation; + u32 bulletCooldown; std::unique_ptr> spriteBuilder; std::unique_ptr createBullet(); diff --git a/engine/include/libgba-sprite-engine/sprites/affine_sprite.h b/engine/include/libgba-sprite-engine/sprites/affine_sprite.h index ed55e59..e4b5620 100644 --- a/engine/include/libgba-sprite-engine/sprites/affine_sprite.h +++ b/engine/include/libgba-sprite-engine/sprites/affine_sprite.h @@ -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; }; diff --git a/engine/include/libgba-sprite-engine/sprites/sprite.h b/engine/include/libgba-sprite-engine/sprites/sprite.h index fefc7fc..91aa32f 100644 --- a/engine/include/libgba-sprite-engine/sprites/sprite.h +++ b/engine/include/libgba-sprite-engine/sprites/sprite.h @@ -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 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; diff --git a/engine/include/libgba-sprite-engine/sprites/sprite_builder.h b/engine/include/libgba-sprite-engine/sprites/sprite_builder.h index 19b16df..86f7f8c 100644 --- a/engine/include/libgba-sprite-engine/sprites/sprite_builder.h +++ b/engine/include/libgba-sprite-engine/sprites/sprite_builder.h @@ -9,13 +9,14 @@ template 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 buildPtr(); + std::unique_ptr buildWithDataOf(const Sprite &other); }; -template std::unique_ptr SpriteBuilder::buildPtr() { - auto s = new T(this->imageData, this->imageSize, this->x, this->y, this->size); +template std::unique_ptr SpriteBuilder::buildWithDataOf(const Sprite &other) { + auto s = new T(other); + s->moveTo(this->x, this->y); + setProperties(s); + + reset(); + return std::unique_ptr(s); +} + +template void SpriteBuilder::setProperties(T* s) { s->setVelocity(this->dx, this->dy); if(this->numberOfFrames > 0) { s->makeAnimated(this->numberOfFrames, this->animationDelay); } s->setStayWithinBounds(stayWithinBounds); +} + +template std::unique_ptr SpriteBuilder::buildPtr() { + auto s = new T(this->imageData, this->imageSize, this->x, this->y, this->size); + setProperties(s); + reset(); return std::unique_ptr(s); } template T SpriteBuilder::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; diff --git a/engine/src/sprites/affine_sprite.cpp b/engine/src/sprites/affine_sprite.cpp index 9a52f25..7020e78 100644 --- a/engine/src/sprites/affine_sprite.cpp +++ b/engine/src/sprites/affine_sprite.cpp @@ -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(new OBJ_AFFINE()); identity(); } diff --git a/engine/src/sprites/sprite.cpp b/engine/src/sprites/sprite.cpp index d7f924e..5a2f95f 100644 --- a/engine/src/sprites/sprite.cpp +++ b/engine/src/sprites/sprite.cpp @@ -8,8 +8,12 @@ #include #include +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(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) | diff --git a/engine/src/sprites/sprite_manager.cpp b/engine/src/sprites/sprite_manager.cpp index 3449511..3db7c01 100644 --- a/engine/src/sprites/sprite_manager.cpp +++ b/engine/src/sprites/sprite_manager.cpp @@ -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() {