I am working through the cocos2d-x SimpleGame project, and I am stuck in chapter 5, http://www.cocos2d-x.org/projects/cocos2d-x/wiki/Chapter_5_-_How_to_Detect_the_Collisions.
What I found is that CCMutableArray is deprecated in favor of CCArray. But how do I need to modify the following, to make it work with CCArray (which apparently does not support templates)?
HelloWorldScene.h
cocos2d::CCMutableArray<cocos2d::CCSprite*> *_projectiles;
HelloWorldScene.cpp
// in init()
// Initialize arrays
_projectiles = new CCMutableArray<CCSprite*>;
HelloWorld::~HelloWorld()
{
if (_targets)
{
_projectiles->release();
_projectiles = NULL;
}
}
HelloWorld::HelloWorld()
:_projectiles(NULL)
{
}
void HelloWorld::update(float dt)
{
CCArray *projectilesToDelete = new CCArray<CCSprite*>;
CCMutableArray<CCSprite*>::CCMutableArrayIterator it, jt;
for (it = _projectiles->begin(); it != _projectiles->end(); it++)
{
CCSprite *projectile = *it;
// (...)
}
// (...)
}
I think it is
CCArray* array1 = CCArray::create();
and later on to use it:
CCObject* arrayItem;
CCARRAY_FOREACH(array1, arrayItem){
CCSprite* pItem = (CCSprite*)(arrayItem);
//your code here
}
I use std::list<> instead, it works well.
just delete may some inefficient.
I'm cocos2d-x beginner yet, I don't know why they "re-inventing the wheel" (just in my beginner opinion) like CCMutableArray, CCArray... thing.
try to use std::vector it is good enough :)
http://en.wikipedia.org/wiki/Sequence_container_(C%2B%2B)
http://www.codeguru.com/cpp/cpp/cpp_mfc/stl/article.php/c4027/C-Tutorial-A-Beginners-Guide-to-stdvector-Part-1.htm
Related
So, I've this code below:
foreach (QLineSeries* series, lineSeriesMap.values())
{
// ...
}
And I will modify series objects in this loop and I don't want to modify the original one, but create a new edited one. I'm extremely new to C++ and Qt so, I want something as the Java code below:
QLineSeries editedSeries = new QLineSeries(series);
I'm deleting elements, editing and re-ordering them from series by the way. But, as I said I need them both.
EDIT:
I've tried your answers but best way I believe is putting the code. This is a project made by some co-worker who changed jobs so its not my code, as i said I dont know C++.
chartwidget.h
void fillAreaSeries();
//...
QHash<QString,QLineSeries*> lineSeriesEntersMap;
QHash<QString,QLineSeries*> lineSeriesExitsMap;
chartwidget.cpp
void ChartWidget::fillAreaSeries() {
foreach (QLineSeries* seriesEnter, lineSeriesEntersMap.values())
{
if (lineSeriesExitsMap.contains(seriesEnter->name())) {
QLineSeries* seriesExit = lineSeriesExitsMap.value(seriesEnter->name());
if (!((seriesEnter->points().size() == 1) && (seriesExit->points().size() == 1))) {
for(int i = seriesEnter->points().size() - 1; i > 0; i--)
{
if (seriesEnter->points().at(i - 1).y() > seriesEnter->points().at(i).y())
{
seriesEnter->removePoints(i, 1);
}
}
for (int i = seriesExit->points().size() - 1; i > 0; i--)
{
if (seriesExit->points().at(i - 1).y() < seriesExit->points().at(i).y())
{
seriesExit->removePoints(i-1, 1);
}
}
QVector<QPointF> editPoints = seriesExit->pointsVector();
std::sort(editPoints.begin(),editPoints.end(), [] (const QPointF & p1, const QPointF & p2)
{
return p1.y() < p2.y();
});
seriesExit->replace(editPoints);
qDebug() << "__Swap:__";
qDebug() << seriesEnter->points().at(0).y();
qDebug() << seriesExit->points().at(0).y();
qDebug() << seriesEnter->points().at(1).y();
qDebug() << seriesExit->points().at(1).y();
QAreaSeries* series = new QAreaSeries(seriesEnter, seriesExit);
series->setName(seriesEnter->name());
series->setOpacity(0.50);
series->setPen(Qt::NoPen);
series->setPointLabelsFormat(seriesEnter->name().split("-").at(0));
areaSeriesMap.insert(series->name(), series);
}
}
}
}
Edit 3:
So, QLineSeries contains QPointF list. I've the code below:
foreach (QLineSeries* seriesEnter, lineSeriesEntersMap.values())
{
QLineSeries* entersToBeEdited = new QLineSeries(chart);
entersToBeEdited->setName(seriesEnter->name());
entersToBeEdited->points().append(seriesEnter->points());
//...
append doesnt work and returns 0 points. But I can set a name. I also tried appending by looping through items and adding it by
entersToBeEdited->points().push_back(seriesEnter->points().at(i));
and still nothing. I also tried << and += but no luck.
Looking at the class definition of QLineSeries, I don't see any simple way to copy your instance in order to duplicate it.
Thus you will have first to create a new instance :
QLineSeries editedSeries;
and manually copy the content of your original series in it.
editedSeries.append(originalSeries.points());
As you cannot modify the data once it is in the QLineSeries object, I would recommend to subclass QLineSeries or modify the QList<QPointF> obtained via originalSeries.points() before adding it to your new chart.
QLineSeries is not copyable, so you can't do what you want by modifying a copy. You will need to create a new QLineSeries from scratch.
I've tried looking for a solution for this issue everywhere to no avail. I've also tried many different approaches to try and resolve this problem myself but, nothing worked.
Everytime I try to delete a body from the world, I get a read access violation at the IsLocked method in Box2d.
I have tried creating a vector list and then deleting all of the bodies from the world that are in that list. Before deleting I make sure to check that I'm not stepping the world and that there are no duplicates in my list and that the world isn't locked.
I add them to the list like so:
for (size_t i = 0; i < m_PlankObjects.size(); i++)
{
m_Game->m_DestroyObjectList.push_back(m_PlankObjects[i].GetBody());
}
This is the GetBody() method:
b2Body * GameObject::GetBody()
{
return m_Body;
}
m_Body is defined like so:
b2Body* m_Body;
And destroy like so:
if (m_UpdateWorld)
{
World.Step(1 / 60.f, 8, 3);
}
else
{
if (!World.IsLocked())
{
if (m_DestroyObjectList.size() != 0)
{
for (size_t i = 0; i < m_DestroyObjectList.size(); i++)
{
World.DestroyBody(m_DestroyObjectList[i]);
m_DestroyObjectList.erase(m_DestroyObjectList.begin() + i);
}
}
}
}
After a night's sleep I went back to the issue and debugged it. I found out that I was not clearing the m_PlankObjects array and therefore in the next game loop update it was being accessed again, but since there were no bodies to access, Box2d was throwing an exception.
I've been trying to implement Box2D into this code, and I've been extremely stuck on this. I've searched high and low for an answer but could not find anything that would fix this problem. I looked at guides and tried fixes that helped other users such as doing b2World->SetAllowSleeping(false).
I start by creating the world and setting the contact listener. The World class contains the b2World, therefore I get the world and set the contact listener. To add, both pointers are stored within a scene class.
m_World = new World();
m_ContactListener = new ContactListener(m_World);
m_World->GetB2World()->SetContactListener(m_ContactListener);
I return the pointer and store it in my scene just in case it will be necessary later on.
My Contact Listener class is basically just the basics that every tutorial has said. I put a few lines of code into the BeginContact() to put a break point and try to see if it's working but so far it has not been working.
Here is the ContactListener.h:
#pragma once
class ContactListener : public b2ContactListener
{
private:
World* m_World;
public:
ContactListener(World* aWorld);
~ContactListener();`
virtual void BeginContact(b2Contact* aContact);
virtual void EndContact(b2Contact* aContact);
void SetWorld(World* aWorld) { m_World = aWorld; }
World* GetWorld() { return m_World; }
};
And here is the ContactListener.cpp file:
#include "pch.h"
ContactListener::ContactListener(World* aWorld)
{
m_World = aWorld;
}
ContactListener::~ContactListener()
{
}
void ContactListener::BeginContact(b2Contact* aContact)
{
b2Fixture* fixtureA = aContact->GetFixtureA();
b2Fixture* fixtureB = aContact->GetFixtureB();
void* userDataA = fixtureA->GetUserData();
std::string nameA = ((GameObject*)userDataA)->GetName();
void* userDataB = fixtureB->GetUserData();
std::string nameB = ((GameObject*)userDataB)->GetName();
}
void ContactListener::EndContact(b2Contact* aContact)
{
}
Like I said previously I added lines of code just to try and put a break point. The guides I read said to simply override the functions and everything should work. Any help with this issue would be appreciated and if you need anymore info I will gladly add any.
For the bodies, I have created two. One static and one dynamic.
Here's the function I use to create the bodies:
b2Body* World::CreateBody(b2Vec2 aPosition, float aRotation, BodyType aType, GameObject* aOwner)
{
b2BodyDef bodyDef;
bodyDef.position = aPosition;
bodyDef.angle = aRotation;
if (aType == KinematicBody)
{
bodyDef.type = b2_kinematicBody;
}
else if (aType == DynamicBody)
{
bodyDef.type = b2_dynamicBody;
}
else
{
bodyDef.type = b2_staticBody;
}
bodyDef.userData = aOwner;
return m_b2World->CreateBody(&bodyDef);
}
Then after I create the two bodies I was previously talking about:
((PlayerObject*)m_pGameObjects["Floor"])->AddBody(m_World->CreateBody(aPosBlock, aRotationBlock, World::BodyType::StaticBody, m_pGameObjects["Floor"]));
((PlayerObject*)m_pGameObjects["Player"])->AddBody(m_World->CreateBody(aPos, aRotation, World::BodyType::DynamicBody, m_pGameObjects["Player"]));
I took a look at my code once again and the tutorials and have figured out that my issue was missing fixtures. Just goes to prove that if you try to rush your code you'll always miss something. Thanks to everyone who had tried to help me with this issue.
I've got a button that I need to be a toggle button for the sound of a game. I'm using the MenuSpriteItem class.
auto menuSoundOn = Sprite::createWithSpriteFrameName("soundOn.png");
auto menuSoundOff = Sprite::createWithSpriteFrameName("soundOff.png");
auto menuSoundBtn = MenuItemSprite::create(menuSoundOn, menuSoundOff, CC_CALLBACK_1(LevelsLayer::shutSound, this));
menuSoundBtn->setTag(0);
_mainMenu = Menu::create(menuSoundBtn, nullptr);
this->addChild(_mainMenu);
//Then in my shutSound method
auto menuSoundBtn = _mainMenu->getChildByTag(0);
if (_ifSound){
_ifSound = false;
//Do some stuff to shut the sound
menuSoundBtn->setSelectedImage("noSound.png");
}
else{
_ifSound = true;
//Do some stuff to bring the sound back
menuSoundBtn->setSelectedImage("sound.png");
}
The problem is that getting the Btn from his parent with getChildByTag(0) method I receive a Node according with the documentation, but setSelectedImage is not part of the Node class and there is an error telling me so, so what is the right way to access MenuSpriteItems from their Parents and then manipulate them as in this case by changing the Normal Image?
Greetings.
I've got the answer and It's really powerful and simple.
auto menuSoundBtn = dynamic_cast<MenuItemSprite*>(_mainMenu->getChildByTag(0));
This is the explanation from the guy:
This code will get the child with tag 0 and turn it into a MenuItemSprite* object if it is a MenuItemSprite* object, or it returns null if the object was not a MenuItemSprite*.
Hope it helps someone. Greetings.
How to implement transition between several scenes that use opengl?
I have 2 different scenes. each create its frame and render buffers and bind it. But then I try to switch between these scenes - nothing happens... I tried to delete all buffers when swithing but it's doesn't work. The First scene is still visible..
Well, in my experience you may need to dispose of the textures for the first scene's visuals.
A quick idea is using psm studio's approach to OpenGLES.
public TitleScene ()
{
this.Camera.SetViewFromViewport();
_texture = new Texture2D("Application/images/title.png",false);
_ti = new TextureInfo(_texture);
SpriteUV titleScreen = new SpriteUV(_ti);
titleScreen.Scale = _ti.TextureSizef;
titleScreen.Pivot = new Vector2(0.5f,0.5f);
titleScreen.Position = new Vector2(Director.Instance.GL.Context.GetViewport().Width/2,
Director.Instance.GL.Context.GetViewport().Height/2);
this.AddChild(titleScreen);
public override void Update (float dt)
{
base.Update (dt);
var touches = Touch.GetData(0).ToArray();
if((touches.Length >0 && touches[0].Status == TouchStatus.Down) || Input2.GamePad0.Cross.Press)
{
Director.Instance.ReplaceScene(new MenuScene());
}
}
~TitleScene()
{
_texture.Dispose();
_ti.Dispose ();
}
}
I hope this will give you some help on what you are missing.