Adding sprite to a node - c++

I've got a SpritePlayer class, which holds my sprite.
SpritePlayer.h:
class SpritePlayer : public cocos2d::Node
{
public:
SpritePlayer();
CREATE_FUNC(SpritePlayer);
void InitSpritePlayer(std::string pathToSptire);
cocos2d::Sprite *GetSprite();
(...)
private:
cocos2d::Sprite *_sprite;
}
SpritePlayer.cpp:
void SpritePlayer::InitSpritePlayer(std::string pathToSprite)
{
_sprite = cocos2d::Sprite::create(pathToSprite);
}
cocos2d::Sprite *SpritePlayer::GetSprite()
{
return _sprite;
}
(...)
At MainScene.cpp I've got:
for (int i = 0; i < 4; i++)
{
playerSpritesList[i] = &SpritePlayer();
playerSpritesList[i]->InitSpritePlayer("ch2.png");
this->addChild(playerSpritesList[i]->GetSprite(), 0);
//SpritePlayersNode->addChild(playerSpritesList[i]->GetSprite())
}
And now the question - how could I add this sprite to a node?
Both bottom lines are causing errors, because I have to pass a Node into addChild() function.

The way you are going about it is introducing a level of abstraction that you do not need to have. The character itself can be a sprite, the way you have it your SpriteCharacter is not actually a sprite, it's a manager for a character sprite. I usually use the following pattern.
Character.h
class Character : public cocos2d::Sprite
{
public:
Character* createCharacterSprite(Vec2 position, std::string fileName);
private:
Character();
}
Character.cpp
Character* Character::createCharacterSprite(Vec2 position, std::string fileName)
{
auto character = new Character();
if(character && character->initWithFile(fileName))
{
character->autorelease();
return character;
}
}
MainScene.cpp
for (int i = 0; i < 4; i++)
{
auto character = Character::createCharacterSprite(characterPosition, "filename.png");
this->addChild(character);
}
This way you can manipulate from within CharacterSprite using 'this' instead of a pointer to your actual character sprite. Positioning and animations will also become a lot easier since you won't have another node with a possible different anchor point in between your character and your MainScene layer.

Sprite is a subclass of Node so there's not a problem with using addChild.
This line is suspicious:
playerSpritesList[i] = &SpritePlayer();
I'd remove SpritePlayer() constructor from your code, because CREATE_FUNC(SpritePlayer) creates default one, which manages memory. And then you can call playerSpritesList[i] = SpritePlayer::create();
Also you can write USING_NS_CC; in SpritePlayer (beware of Point struct - you have to write cocos2d::Point, because of namespace conflict on iOS/Mac).
Also for convention function names should start with lower case :)

Related

Custom Child Components Added But Not Visible

I am using the JUCE framework to create an audio plugin. I have created a Knob class which inherits from the Component class. My Knob class contains references to a Slider & a Label.
In my AudioProcessorEditor class, I initialize several Knob objects. However, none of the Components are visible at run-time. Am I doing something wrong or missing a step?
I have tried declaring Slider & Label objects directly inside of my AudioProcessorEditor class. When I do that, I am able to see the Slider & Label objects successfully at run-time. So I get the feeling that the issue involves my Knob class.
Knob.h
#pragma once
#include "../JuceLibraryCode/JuceHeader.h"
class Knob : public Component
{
public:
Knob(String, AudioProcessorEditor*);
~Knob();
void paint (Graphics&) override;
void resized() override;
String Name;
Label *KnobLabel;
Slider *KnobSlider;
AudioProcessorEditor *APE;
private:
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Knob)
};
Knob.cpp
#include "Knob.h"
Knob::Knob(String name, AudioProcessorEditor *ape)
{
// In your constructor, you should add any child components, and
// initialise any special settings that your component needs.
this->Name = name;
APE = ape;
KnobLabel = new Label(name);
KnobLabel->setColour(0x1000281, Colours::antiquewhite);
KnobLabel->setAlwaysOnTop(true);
KnobLabel->setFont(10);
KnobSlider = new Slider();
KnobSlider->setAlwaysOnTop(true);
addAndMakeVisible(KnobLabel);
addAndMakeVisible(KnobSlider);
}
void Knob::paint (Graphics& g)
{
/* This demo code just fills the component's background and
draws some placeholder text to get you started.
You should replace everything in this method with your own
drawing code..
*/
g.setColour(Colours::white);
g.fillAll();
}
void Knob::resized()
{
// This method is where you should set the bounds of any child
// components that your component contains..
auto bounds = getLocalBounds();
KnobSlider->setBounds(bounds.removeFromTop(getHeight()*8));
KnobLabel->setBounds(bounds);
}
PluginEditor.h
#pragma once
#include "../JuceLibraryCode/JuceHeader.h"
#include "PluginProcessor.h"
#include "Knob.h"
#include "Model.h"
class MoonlightAudioProcessorEditor : public AudioProcessorEditor
{
public:
MoonlightAudioProcessorEditor (MoonlightAudioProcessor&);
~MoonlightAudioProcessorEditor();
void paint (Graphics&) override;
void resized() override;
Knob *OrbitKnob;
Knob *SpaceKnob;
Knob *InertiaKnob;
void ConfigureUI();
private:
OwnedArray<Knob> Knobs;
ComponentBoundsConstrainer ResizeBounds;
ResizableCornerComponent *Resizer;
MoonlightAudioProcessor& processor;
};
PluginEditor.cpp
#include "PluginProcessor.h"
#include "PluginEditor.h"
MoonlightAudioProcessorEditor::MoonlightAudioProcessorEditor (MoonlightAudioProcessor& p)
: AudioProcessorEditor (&p), processor (p)
{
setSize (400, 300);
ConfigureUI();
}
void MoonlightAudioProcessorEditor::ConfigureUI()
{
OrbitKnob = new Knob("Orbit", this);
SpaceKnob = new Knob("Space", this);
InertiaKnob = new Knob("Inertia", this);
Knobs.add(OrbitKnob);
Knobs.add(SpaceKnob);
Knobs.add(InertiaKnob);
for (Knob *knob : Knobs)
{
knob->KnobSlider->addListener(this);
addAndMakeVisible(knob);
knob->setAlwaysOnTop(true);
}
ResizeBounds.setSizeLimits(DEFAULT_WIDTH,
DEFAULT_HEIGHT,
MAX_WIDTH,
MAX_HEIGHT);
Resizer = new ResizableCornerComponent(this, &ResizeBounds);
addAndMakeVisible(Resizer);
setSize(processor._UIWidth, processor._UIHeight);
}
void MoonlightAudioProcessorEditor::paint (Graphics& g)
{
g.setColour (Colours::black);
g.fillAll();
}
void MoonlightAudioProcessorEditor::resized()
{
int width = getWidth();
int height = getHeight();
auto bounds = getLocalBounds();
auto graphicBounds = bounds.removeFromTop(height*.8);
auto orbitBounds = bounds.removeFromLeft(width/3);
auto spaceBounds = bounds.removeFromLeft(width/3);
if (OrbitKnob != nullptr)
{
OrbitKnob->setBounds(orbitBounds);
}
if (SpaceKnob != nullptr)
{
SpaceKnob->setBounds(spaceBounds);
}
if (InertiaKnob != nullptr)
{
InertiaKnob->setBounds(bounds);
}
if (Resizer != nullptr)
{
Resizer->setBounds(width - 16, height - 16, 16, 16);
}
processor._UIWidth = width;
processor._UIHeight = height;
}
Also, I have been using the AudioPluginHost application provided with JUCE to test my plugin. A lot of times the application will crash from a segmentation fault. Then I rebuild the plugin without changing anything and it will work.
I ended up figuring it out.
My components were being initialized after I set the size. A lot of the display logic was in the resize() function so I needed to set the size after component initialization.
You left out a call to Component::Paint(g) in Knob::Paint(Graphics& g)

class *object = new class[size]

I'm trying to learn how to use classes but I am having a hard time trying to understand it so I tried to create a game.
I want to access my 10 players in the heap and I want to initialize the skills of each 10 players. I really don't know what I'm doing please help me. If you think the structure of my program is garbage please tell me and tell me how to properly do it. Thanks
main.cpp
int main()
{
Player *p = new Player[10];
p->createPlayer(&p,10);
}
Header file
class Player
{
public:
Player();
~Player();
int genRanNum(int);
void createPlayer(Player *, int);
private:
int plyrSkill1,plyrSkill2,plyrSkill3;
int plyrId;
};
CPP File
Player::Player()
{
}
int Player::genRanNum(int num)
{
return 1+(rand()%num);
}
void Player::createPlayer(Player *p, int si)
{
for(int i = 0; i < si; i++)
{
*p->staId = i;
*p->staSkills1 = genRanNum(10);
*p->staSkills2 = genRanNum(10);
*p->staSkills3 = genRanNum(10);
}
}
The first line in main Player *p = new Player[10]; is creating an array of 10 players on the heap.
It seems that that you want to 'initialize' these 10 players with the second line p->createPlayer(&p,10); but the code is wrong :
The loop in createPlayer() function always works on the same player (it increments i but p is always the same).
try this :
class Player
{
public:
Player(); /// can be private if players can be instantiated only by createPlayer()
~Player();
static int genRanNum(int);
static Player* createPlayer(int);
private:
int plyrSkill1,plyrSkill2,plyrSkill3;
int plyrId;
};
createPlayer() and getRanNum() are static because they are class method (it's not related to one instance in particular)
Player * Player::createPlayer(int si)
{
Player *player = new Player();
player->staId = si;
player->staSkills1 = genRanNum(10);
player->staSkills2 = genRanNum(10);
player->staSkills3 = genRanNum(10);
return player;
}
Finally in main :
int main()
{
std::vector<Player *> p(10);
for (int iPlayer=0; iPlayer<10; iPlayer++)
{
p[iPlayer] = Player::createPlayer(iPlayer);
}
...
/// Don't forget to delete players
}
I'm trying to learn how to use classes but I am having a hard time
trying to understand it so I tried to create a game.
Since you want to create a game, visualize all the characters and scenes or anything that you want.
Model your idea/view of the game..
Example:
Once you have determined all the classes that you need and the relationships between them, you can now start coding them up in any language you want to.
I know this will take time but it is a better way to learn designing and these skills will be helpful in the long run.

replaceScene() messes up a public variable

I am porting a game from cocos2d-iphone 2.x to cocos2d-x 3.x.
Have to solve a few problems, including a major crash - the subject of this post.
It has been determined that the crash happens because SOMETIMES, my replaceScene call results in a messed-up important public variable.
My class:
class Player : public cocos2d::Sprite
{
public:
....
cocos2d::Vec2 desiredPosition;
....
My Layer methods:
Scene* GameLevelLayer::createScene()
{
// 'scene' is an autorelease object
auto scene = Scene::create();
// 'layer' is an autorelease object
auto layer = GameLevelLayer::create();
// add layer as a child to scene
scene->addChild(layer);
// return the scene
return scene;
}
bool GameLevelLayer::init()
{
// super init first
if ( !Layer::init() )
{
return false;
}
....
player = (Player*) cocos2d::Sprite::create("sprite_idle_right#2x.png");
player->setPosition(Vec2(100, 50));
player->desiredPosition = player->getPosition();
....
this->schedule(schedule_selector(GameLevelLayer::update), 1.0/60.0);
....
return true;
}
void GameLevelLayer::endGame(bool won) {
....
MenuItem* display;
if (currentLevel < lastLevel && won) {
++currentLevel;
display = MenuItemImage::create("next.png" ,"next.png" ,"next.png",
CC_CALLBACK_1(GameLevelLayer::replaceSceneCallback, this));
} else {
// Lost the game
currentLevel = 1;
display = MenuItemImage::create("replay.png", "replay.png", "replay.png",
CC_CALLBACK_1(GameLevelLayer::replaceSceneCallback, this));
}
....
}
void GameLevelLayer::replaceSceneCallback(Ref* sender) {
Director::getInstance()->replaceScene(this->createScene());
}
The member being messed is the desiredPosition. It is changed inside update() method. The problem is that update() gets an already messed-up desired position. It is only messed-up after a scene was being replaced. The problem happens once in 10 runs, or so. It even appears that when update() is called first time after the scene has been replaced, desiredPosition set to some garbage. is I was unable to learn more.
My Player class does not have a separate constructor.
Please advise.
I forgot to initialize another instance variable. That instance variable is used to calculate the desiredPosition.

cocos2d-x ver3 action blink in Sequence doesn't executes , single action does

i have strange situation where i try to run blink action as part of Sequence
on sprites Although the method getNumberOfRunningActions returns 1 the sprite dosn't blink.
where pMatchedSymbolArray is array of ReelSymbol Sprite extendet class
class ReelSymbol :public Sprite
{
public:
CREATE_FUNC(ReelSymbol);
ReelSymbol();
virtual bool init();
void setup();
static ReelSymbol* createWithSpriteFrameName(const std::string& spriteFrameName);
private:
int getIntFromName(std::string key);
Settings* pSettings;
};
for(ssize_t a=0; a<pMatchedSymbolArray->count();a++)
{
auto actionBlink = Blink::create(2, 5);
auto repeat = Repeat::create(actionBlink, 2);
ReelSymbol* symbol = ((ReelSymbol*)pMatchedSymbolArray->getObjectAtIndex(a));
auto actionSequence = Sequence::create(
actionBlink,
DelayTime::create(2),
CallFunc::create( std::bind(&LinesManager::AnimationUnitCallback, this, symbol,pMatchedSymbolArray->count()) ),
NULL);
ReelSymbol* thisReelSymbol = ((ReelSymbol*)pMatchedSymbolArray->getObjectAtIndex(a));
thisReelSymbol->runAction(actionSequence);
int no = thisReelSymbol->getNumberOfRunningActions();
CCLOG("getNumberOfRunningActions: %d",no);
}
void LinesManager::AnimationUnitCallback(Node* sender,int iMatchedSymbolArrayCount)
{
}
the sprite blink only if i run:
auto actionBlink = Blink::create(2, 5);
....
....
thisReelSymbol->runAction(actionBlink );
what can be wrong here ?
If this is problem with only recent version then workaround might be using two actions simultaneously.
Blink action with duration.
Sequence with Delay of Blink action and followed by other actions.

Store an array of SDL_Surface items in a class?

I want to store all my SDL_Surface variables in an array, and to hold that array in a class. The reason is that I want to be able to reload all SDL_Surfaces based on events.
I think it should be something like this, I'm probably wrong though:
class Imgs_Arr{
private:
int pos;
public:
// DECLARE THE ARRAY
Imgs_Arr();
void addItem(char * path);
void changeItem(int pos);
};
Imgs_Arr::Imgs_Arr(){
// CREATE ARRAY
}
void Imgs_Arr::addItem(char * path){ // ADD ITEM IN LAST ARRAY POSITION
vec[pos] = load_image(path);
if( vec[pos] == NULL ) exit(5);
pos++;
}
void Imgs_Arr::changeItem(int p){ // ADD ITEM IN LAST ARRAY POSITION
vec[p] = load_image(path);
if( vec[p] == NULL ) exit(5);
}
I'm looking for an example of how to do it. But any information will be useful. Thanks
Your problem is somewhat specific, since SDL_Surface* is an opaque handle. You must never know the actual SDL_Surface object which it points to. So, you need a dynamic array of opaque handles. For the main array, we just use std::vector, so I'd do it like this:
#include <memory>
#include <vector>
#include <SDL.h>
class Arr_Images
{
using sdl_handle = std::unique_ptr<SDL_Surface, void(*)(SDL_Surface*)>;
sdl_handle wrap_unique_surface(SDL_Surface * s)
{
return sdl_handle(s, SDL_FreeSurface);
}
std::vector<sdl_handle> surfaces;
public:
void addImg(char const * path)
{
if (SDL_Surface * p = load_image(path))
{
surfaces.push_back(wrap_unique_surface(p));
}
else
{
// failed to load
}
}
};