How to display a timer in a Cocos2d game? - cocos2d-iphone

I'm trying to display a timer in a cocos2d game which shows the number of minutes:seconds:milliseconds a user has spent on a level. I've searched for examples and found that I should definitely NOT be using NSTimer. I understand that I should be using the CCTimer class, but I'm having a tough time finding decent examples.

//Declare this in interface
CCLabelTTF *mTimeLbl;
float               mTimeInSec;
//Init this in onEnter
mTimeInSec = 0.0f;
[self schedule:#selector(tick:)];
//Function Used
-(void)tick:(ccTime)dt
{
if(self.isGamePaused || self.isGameOver)
return;
mTimeInSec +=dt;
float digit_min = mTimeInSec/60.0f;
float digit_hour = (digit_min)/60.0f;
float digit_sec = ((int)mTimeInSec%60);
int min = (int)digit_min;
int hours = (int)digit_hour;
int sec = (int)digit_sec;
[mTimeLbl setString:[NSString stringWithFormat:#"%.2d:%.2d:%.2d",hours, min,sec]];
}

Inside your CCLayer class just create a variable that holds the data and increment it through the timer or through a normal update. I'm giving you some example code but it's just to give you the idea:
static long ticks = 0;
-(void)timerTick
{
++ticks;
[(CCLabelBMFont*)[self getChildByTag:TAG_TIMER_STRING] setString:[NSString stringWithFormat:#"%lu"]];
}
-(id)init {
..
[self schedule:#selector(timerTick) interval:1.0];
}

Related

After adding some points to QtChart it gets slow

I need help. Here is my code (i show main part):
// Arduino Reader
serial.setPortName("/dev/ttyACM0");
serial.open(QIODevice::ReadWrite);
serial.setBaudRate(QSerialPort::Baud9600);
serial.setDataBits(QSerialPort::Data8);
serial.setParity(QSerialPort::NoParity);
serial.setStopBits(QSerialPort::OneStop);
serial.setFlowControl(QSerialPort::NoFlowControl);
connect(&serial,SIGNAL(readyRead()),this,SLOT(getNewData()));
...
void MainWindow::getNewData()
{
std::clock_t starter = std::clock();
QByteArray data = serial.readAll();
QDataStream in(serial.readAll());
getData = getData + data;
int start = getData.indexOf(":START:");
int end = getData.indexOf(":END:",start);
QString nowWork = getData.mid(start,end-start+5);
if (nowWork.startsWith(":START:") && nowWork.endsWith(":END:")){
QStringList mod = nowWork.remove(":START:").remove(":END:").split(":");
int xPoint = mod[0].toInt();
int yPoint = mod[1].toInt();
int zPoint = mod[2].toInt();
int aPoint = mod[3].toInt();
int bPoint = mod[4].toInt();
int cPoint = mod[5].toInt();
addQuery(1,xPoint,yPoint,zPoint);
addQuery(2,aPoint,bPoint,cPoint);
getData = getData.right(end+5);
}
std::clock_t ender = std::clock();
ui->ping->setText(QString::number( (ender-starter)/ (double)CLOCKS_PER_SEC *100));
return;
}
...
void MainWindow::addQuery(int to, int x, int y, int z){
seriesAllD1->append(now, (x+y+z)/3 );
seriesXD1->append(now,x);
seriesYD1->append(now,y);
seriesZD1->append(now,z);
seriesAllD1->remove(0);
seriesXD1->remove(0);
seriesYD1->remove(0);
seriesZD1->remove(0);
chartAllD1->axisX()->setRange(now-100,now);
chartX->axisX()->setRange(now-100,now);
chartY->axisX()->setRange(now-100,now);
chartZ->axisX()->setRange(now-100,now);
now++;
return;
}
I try to describe code:
1) It gets data from arduino (Like a ":START:X:Y:Z:A:B:C:END::START:...").
2) It gets indicates from 2-sensors (3-axis accelometr). And draws Graphs.
I show some code block. After adding ~900 point it gets slow from 60 ms to 1000 ms. I think it is related to QtChart (i use them in project) or addind points to series. Please help me(
This is an old topic - however I also ran into it when working with QtCharts - so: for others who will stumble on the same problems with QtCharts and would also like to use QtCharts here are my solutions:
Use OpenGL:
call setUseOpenGL(true) on the series in the plot (will only work with QLineSeries and QScatterSeries) - unfortunately this is not the default, but it could be a problem on some systems
When not using OpenGL (i.e. also using QAreaSeries):
do not use AntiAliasing
when adding large amounts of data in one loop to the series use rather replace than add - see https://stackoverflow.com/a/52334549/2056545
And this special trick a colleague came up with when working with real time data:
set all series to signalsBlocked(true), start a timer when blocking, unblock after a second, block again and start timer when adding new data again - this will update the plots on (about) every second, but the performance impact is low

Box2D, Contact Listener: Never calling BeginContact

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.

Detecting which extended sprited i touched

I want detect which object of Card I touched. Card is custom Class which extends cocos Sprite.
I would like to call member methods on card. Something like this: if (target is Card) target.openCard();
Thank you very much in advance.
Main Class Body
bool HelloWorld::init()
{
... some init code, generating card arrays, shuffling
// draw memory cards
int count = 0;
for (int i = 0; i < 5; i++)
{
for (int j = 0; j < 4; j++)
{
auto card = Card::createCard();
card->customInit(cardsPictures[count]);
this->addChild(card);
card->setPosition(100 + i*100, 600 - j*100);
count++;
}
}
// register event listener
auto touchListener = EventListenerTouchOneByOne::create();
touchListener->onTouchBegan = CC_CALLBACK_2(HelloWorld::onTouchBegan, this);
touchListener->onTouchEnded = CC_CALLBACK_2(HelloWorld::onTouchEnded, this);
touchListener->onTouchMoved = CC_CALLBACK_2(HelloWorld::onTouchMoved, this);
touchListener->onTouchCancelled = CC_CALLBACK_2(HelloWorld::onTouchCancelled, this);
_eventDispatcher->addEventListenerWithSceneGraphPriority(touchListener, this);
return true;
}
bool HelloWorld::onTouchBegan(Touch* touch, Event* event)
{
auto target = event->getCurrentTarget();
if (target is Card) target.openCard(); // not working
return true;
}
(target is Card)
That doesn't look like C++ to me. What is it ? :D
First:
Is target a pointer ? If so do:
target->openCard(); // instead of target.openCard();
Anyway, if you want to call methods on an object that you are CERTAIN is of type card, perhaps you should do :
Card* myCard = static_cast<Card*>(target);
myCard->openCard();
To be honest unless you actually post the relevant code it would be hard for anyone to help you. What does Card even look like ? (I don't care! XD)

How to animate through an a container for windows.draw()?

I have a container of objects:
std::vector<sf::Drawable> gameObjects;
My goal is to iterate through these objects and draw them:
for (auto it : gameObjects)
{
window.draw(*it);
}
You can assume these methods are already implemented. What I mean by 'animate': I want these objects drawn one at a time, rather than all at once immediately.
void Run::render()
{
window.clear(colorWindow);
for (auto it : gameObjects)
{
window.draw(*it);
}
window.display();
}
That is, have every render() draw an additional object in the container. Do you know how I can go about doing this? Thank you in advance.
edit: I've tried something unconventional - I dont think it's good practice, but it works:
int count = 0;
int countReset = 1;
...
while (countReset > count)
{
objects.at(count++).draw(window);
}
countReset++;
count = 0;
You should never make decisions about your game in your rendering. You should have an update method somewhere, that makes decisions on how input and time passed affect your game world. Rendering should only do one thing: rendering. No decision making, no data manipulation.
You could for example use a compound class to indicate which object should be drawn or you could derive your own base class from sf::Drawable and implement a bool IsVisible() const; method. Either way, the decision if it's drawn is made elsewhere, the rendering is only executing commands what to render specifically:
struct MaybeDrawn
{
bool IsVisible;
sf::Drawable Object;
};
...
std::vector<MaybeDrawn> gameObjects;
...
void Run::render()
{
window.clear(colorWindow);
for (auto it : gameObjects)
{
if(it->IsVisible)
{
window.draw(it->Object);
}
}
window.display();
}
Your decision, how and when to set the bool to true should happen in your Update/ChangeWorld method. Maybe you want to have a look here for a general description on how to structure a game and how to build a timer.
Alternatively, you could leave your program as it is and insert and/or delete from your vector in your decision making method.
Use a static counter for your index in list of objects. Measure time and incremente the counter if a time period has elapsed. So next time is drawn next object in list.
#include <chrono>
void Run::render()
{
// actual time
std::chrono::high_resolution_clock::time_point actTime = std::chrono::high_resolution_clock::now();
// remember time
static bool init = false;
std::chrono::high_resolution_clock::time_point lastTime;
if ( !init )
{
lastTime = actTime;
init = true;
}
// delta time
long microseconds = std::chrono::duration_cast<std::chrono::duration<long, std::micro> >( actTime - lastTime ).count();
double deltaTms = ((double)microseconds) / 1000.0;
window.clear(colorWindow);
static size_t actObjInx = 0;
window.draw(gameObjects[actObjInx]);
// increment object index if time period has elapsed
if ( deltaTms > 100.0 ) // 0.1 seconds
{
lastTime = actTime;
actObjInx ++;
if ( actObjInx == gameObjects.size() )
actObjInx = 0;
}
window.display();
}

How to use the CCTimer class in Cocos2d android?

I want to use CCTimer class for the Timer but I can't sort out. After I use to manually create a function for this but it seems not effective .
protected GameLayer(ccColor4B color)
{
super(color);
schedule(new UpdateCallback() {
#Override
public void update(float d) {
countTime(d);
}
},0.99f);
}
public void countTime(float scr) {
if(_label != null){
this.removeChild(_label,true);
}
j=j-(int)scr;
CGSize winSize = CCDirector.sharedDirector().displaySize();
_label = CCLabel.makeLabel("Time Left :" + j, "Verdana", 20);
_label.setColor(ccColor3B.ccGREEN);
_label.setPosition(155f, winSize.height - 15);
addChild(_label);
if(j<=0){
CCDirector.sharedDirector().pause();
}
}
it run from 1 to the the point which i want to stop ... !!!
what should i do to use the CCTimer class to resolve this problem ?
CCTimer is available but I haven't tried this earlier but you can do this thing through Timer class :
Timer timer = new Timer();
timer.scheduleAtFixedRate( new TimerTask(){
public void run() {
updateTimeLabel();
}
public void updateTimeLabel() {
float time += 1;
String string = CCFormatter.format("%02d:%02d", (int)(time /60) , (int)time % 60 );
CCBitmapFontAtlas timerLabel = (CCBitmapFontAtlas) getChildByTag(TIMER_LABEL_TAG) ;
timerLabel.setString(string);
}