In my game I have a "rocket" type and I want to run a sequence of actions on it. At first it must run an explosion animation and then remove itself from the game. For this I used the following code, but it does not work and results in a runtime error.
Rocket class:
void Rocket::movingRocket(float dt)
{
// some codes ...
if(rocketIsCollideWithEnemy()) // run only one time
{
this->stopAllActions();
CCAnimation *animation = CCAnimation::create();
for (int i = 0; i < EXPLOSION_FRAME_NUMBER; i++)
{
CCString *str = CCString::createWithFormat("/explosion-%d.png", i);
animation->addSpriteFrameWithFileName(str->getCString());
}
animation->setDelayPerUnit(0.06f);
CCAnimate *animate = CCAnimate::create(animation);
CCCallFuncN* remove_rocket = CCCallFuncN::create(this, callfuncN_selector(Rocket::removeRocket));
this->runAction(CCSequence::create(animate,remove_rocket, NULL));
this->unschedule(schedule_selector(Rocket::movingRocket));
}
}
And for removing a rocket I use:
void Rocket::removeRocket(CCObject *pSender)
{
((CCNode*)pSender)->removeFromParentAndCleanup(true);
}
And when I run the above, an error occurs in the following code, part Cocos2d, at line 4:
void CCAnimate::update(float t)
{
// some codes...
if( splitTime <= t )
{
CCAnimationFrame* frame = (CCAnimationFrame*)frames->objectAtIndex(i);
frameToDisplay = frame->getSpriteFrame();
((CCSprite*)m_pTarget)->setDisplayFrame(frameToDisplay);
CCDictionary* dict = frame->getUserInfo();
if( dict )
{
//TODO: [[NSNotificationCenter defaultCenter] postNotificationName:CCAnimationFrameDisplayedNotification object:target_ userInfo:dict];
}
m_nNextFrame = i+1;
}
// some codes...
}
What could be causing my problem?
Related
I am trying to get my animation to cycle through two images when a directional key is pressed. Currently it switches images on each key press. I have been looking at tutorials and understand that I need some kind of timer to measure each frame time but everything I have tried to implement in to my code so far has failed so I am just posting my code that works at the moment.
Could anyone explain to me how to go about implementing this please?
void Frog::up(sf::Event event)
{
sf::IntRect frogUpAnimation[iNumFrames];
frogUpAnimation[0] = sf::IntRect(13, 362, 21, 23);
frogUpAnimation[1] = sf::IntRect(46, 367, 21, 23);
if (event.type == sf::Event::KeyPressed && event.key.code == sf::Keyboard::Up)
{
audio.frogjumpsound();
frogSprite.move(0.0f, -55.0f);
iScoreCounter = iScoreCounter + 10;
iCurrentFrame++;
if (iCurrentFrame >= iNumFrames) iCurrentFrame = 0;
frogSprite.setTextureRect(frogUpAnimation[iCurrentFrame]);
}
}
int main()
{
sf::RenderWindow window(sf::VideoMode(800, 800), "Frogger");
window.setFramerateLimit(60);
sf::Clock timer;
float fFrameTime = 1.0f / 60.0f;
float fElapsedTime;
sf::Event event;
Game game;
Frog frog;
Timer countdown;
Text text;
Audio gameaudio;
gameaudio.music();
while (window.isOpen())
{
while (window.pollEvent(event))
{
if (event.type == sf::Event::Closed)
{
window.close();
}
if (event.type == sf::Event::KeyPressed)
{
game.processKeyPress(event.key.code);
}
frog.up(event);
frog.down(event);
frog.left(event);
frog.right(event);
} // Event loop
countdown.gametime();
fElapsedTime = timer.getElapsedTime().asSeconds();
if (fElapsedTime > fFrameTime)
{
timer.restart();
}
//Update
game.checkPads(&frog);
game.checkWin();
game.gameOver();
frog.scorecounter(&countdown);
frog.update(fElapsedTime);
game.update(fElapsedTime);
text.update(fElapsedTime);
countdown.update(fElapsedTime);
game.collision(&frog);
// Drawing
window.clear();
window.draw(game);
window.draw(frog);
window.draw(countdown);
window.draw(text);
window.display();
} // main loop
}
First, I would only call 'frog.up()', 'frog.left()', etc. when the proper key is pressed. Otherwise, you're calling potentially 4 functions each iteration which do absolutely nothing.
if(sf::Keyboard::isKeyPressed(sf::Keyboard::Right) {
frog.right();
}
else if(sf::Keyboard::isKeyPressed(sf::Keyboard::Left) {
frog.left();
}
As for your timer issues, your fElapsedTime and fFrameTime look a little funky. Take a look at https://en.sfml-dev.org/forums/index.php?topic=10913.0 but I really recommend this guide: https://github.com/SFML/SFML/wiki/Source:-AnimatedSprite
I have a little cocos2d-x v3 Windows project and I want an animated sprite. The sprite I have in an object named Worker with other parameters. To run the animation I tried the following, but it always gives a segmentation fault:
//worker.cpp:
...
void Worker::initAnimationWalk() {
spritebatch = cocos2d::SpriteBatchNode::create("robo.png");
auto cache = cocos2d::SpriteFrameCache::getInstance();
cache->addSpriteFramesWithFile("robo.plist");
worker = cocos2d::Sprite::createWithSpriteFrameName("robot1.png");
//spritebatch->addChild(worker);
Vector<SpriteFrame *> animFrames(3);
char str[100] = {0};
for(int i = 1; i <= 3; i++)
{
sprintf(str, "robot%i.png", i);
cocos2d::SpriteFrame* frame = cache->getSpriteFrameByName( str );
animFrames.pushBack(frame);
}
animation = cocos2d::Animation::createWithSpriteFrames(animFrames, 0.2f);
}
cocos2d::Animation *Worker::getAnimationWalk() {
return animation;
}
...
//Worker.h
#ifndef __WORKER_H__
#define __WORKER_H__
#include "cocos2d.h"
class Worker
{
public:
...
void initAnimationWalk();
cocos2d::Animation *getAnimationWalk();
private:
cocos2d::Animation *animation;
cocos2d::Sprite *worker;
cocos2d::SpriteBatchNode *spritebatch;
};
#endif
//Now i want the animation in my scene:
//HellowWorldScene.cpp
void HelloWorld::setMyAction() { //all Worker Objects in an vector
vector<Worker>::iterator it = workerVector.begin();
for(int i = 0; i<workerVector.size();i++) {
it->getWorker()->stopAllActions();
auto actionAnim = Animate::create(it->getAnimationWalk());
if(it->getWorker()->getPosition().x > 0.50*2*p.x) {
auto action = cocos2d::MoveTo::create(it->getSpeed(),Point(0,it->getWorker()->getPosition().y));
auto sp = Spawn::createWithTwoActions(action, actionAnim);
it->getWorker()->runAction(sp);
it->getWorker()->setFlipX(true);
} else {
auto action = cocos2d::MoveTo::create(it->getSpeed(),Point(2*p.x,it->getWorker()->getPosition().y));
auto sp = Spawn::createWithTwoActions(action, actionAnim);
it->getWorker()->runAction(sp);
it->getWorker()->setFlipX(false);
}
}
it++
}
Any help?
SpriteAnimation auto change images using Animation.
Animation *animation2=Animation::create();
animation2->setDelayPerUnit(0.7f);//Time Duration change Images
animation2->addSpriteFrameWithFile("img_1.png");
animation2->addSpriteFrameWithFile("img_2.png");
animation2->addSpriteFrameWithFile("img_3.png");
AnimationCache::getInstance()->addAnimation(animation2, "animation2");
SpriteName->runAction(Sequence::create(Animate::create(animation2),NULL));//this animation Only One time
OR
SpriteName->runAction(RepeatForever::create(Sequence::create(Animate::create(animation2),NULL)));//If Repeate this animation write it..
SpriteAnimation auto change images using Animation.
Animation *anim=Animation::create();
anim->setDelayPerUnit(0.7f);//Time Duration change Images
anim->addSpriteFrameWithFile("img_01.png");
anim->addSpriteFrameWithFile("img_02.png");
anim->addSpriteFrameWithFile("img_03.png");
AnimationCache::getInstance()->addAnimation(anim, "anim");
SpriteNM->runAction(Sequence::create(Animate::create(anim),NULL));//this animation Only One time
OR
SpriteNM->runAction(RepeatForever::create(Sequence::create(Animate::create(anim),NULL)));//If Repeate this animation write it..
I am trying to stream audio data from disk using OpenAL's buffer queueing mechanism. I load and enqueue 4 buffers, start the source playing, and check in a regular intervals to refresh the queue. Everything looks like it's going splendidly, up until the first time I try to load data into a recycled buffer I got from alSourceUnqueueBuffers(). In this situation, alBufferData() always sets AL_INVALID_OPERATION, which according to the official v1.1 spec, it doesn't seem like it should be able to do.
I have searched extensively on Google and StackOverflow, and can't seem to find any reason why this would happen. The closest thing I found was someone with a possibly-related issue in an archived forum post, but details are few and responses are null. There was also this SO question with slightly different circumstances, but the only answer's suggestion does not help.
Possibly helpful: I know my context and device are configured correctly, because loading small wav files completely into a single buffer and playing them works fine. Through experimentation, I've also found that queueing 2 buffers, starting the source playing, and immediately loading and enqueueing the other two buffers throws no errors; it's only when I've unqueued a processed buffer that I run into trouble.
The relevant code:
static constexpr int MAX_BUFFER_COUNT = 4;
#define alCall(funcCall) {funcCall; SoundyOutport::CheckError(__FILE__, __LINE__, #funcCall) ? abort() : ((void)0); }
bool SoundyOutport::CheckError(const string &pFile, int pLine, const string &pfunc)
{
ALenum tErrCode = alGetError();
if(tErrCode != 0)
{
auto tMsg = alGetString(tErrCode);
Log::e(ro::TAG) << tMsg << " at " << pFile << "(" << pLine << "):\n"
<< "\tAL call " << pfunc << " failed." << end;
return true;
}
return false;
}
void SoundyOutport::EnqueueBuffer(const float* pData, int pFrames)
{
static int called = 0;
++called;
ALint tState;
alCall(alGetSourcei(mSourceId, AL_SOURCE_TYPE, &tState));
if(tState == AL_STATIC)
{
Stop();
// alCall(alSourcei(mSourceId, AL_BUFFER, NULL));
}
ALuint tBufId = AL_NONE;
int tQueuedBuffers = QueuedUpBuffers();
int tReady = ProcessedBuffers();
if(tQueuedBuffers < MAX_BUFFER_COUNT)
{
tBufId = mBufferIds[tQueuedBuffers];
}
else if(tReady > 0)
{
// the fifth time through, this code gets hit
alCall(alSourceUnqueueBuffers(mSourceId, 1, &tBufId));
// debug code: make sure these values go down by one
tQueuedBuffers = QueuedUpBuffers();
tReady = ProcessedBuffers();
}
else
{
return; // no update needed yet.
}
void* tConverted = convert(pData, pFrames);
// the fifth time through, we get AL_INVALID_OPERATION, and call abort()
alCall(alBufferData(tBufId, mFormat, tConverted, pFrames * mBitdepth/8, mSampleRate));
alCall(alSourceQueueBuffers(mSourceId, 1, &mBufferId));
if(mBitdepth == BITDEPTH_8)
{
delete (uint8_t*)tConverted;
}
else // if(mBitdepth == BITDEPTH_16)
{
delete (uint16_t*)tConverted;
}
}
void SoundyOutport::PlayBufferedStream()
{
if(!StreamingMode() || !QueuedUpBuffers())
{
Log::w(ro::TAG) << "Attempted to play an unbuffered stream" << end;
return;
}
alCall(alSourcei(mSourceId, AL_LOOPING, AL_FALSE)); // never loop streams
alCall(alSourcePlay(mSourceId));
}
int SoundyOutport::QueuedUpBuffers()
{
int tCount = 0;
alCall(alGetSourcei(mSourceId, AL_BUFFERS_QUEUED, &tCount));
return tCount;
}
int SoundyOutport::ProcessedBuffers()
{
int tCount = 0;
alCall(alGetSourcei(mSourceId, AL_BUFFERS_PROCESSED, &tCount));
return tCount;
}
void SoundyOutport::Stop()
{
if(Playing())
{
alCall(alSourceStop(mSourceId));
}
int tBuffers;
alCall(alGetSourcei(mSourceId, AL_BUFFERS_QUEUED, &tBuffers));
if(tBuffers)
{
ALuint tDummy[tBuffers];
alCall(alSourceUnqueueBuffers(mSourceId, tBuffers, tDummy));
}
alCall(alSourcei(mSourceId, AL_BUFFER, AL_NONE));
}
bool SoundyOutport::Playing()
{
ALint tPlaying;
alCall(alGetSourcei(mSourceId, AL_SOURCE_STATE, &tPlaying));
return tPlaying == AL_PLAYING;
}
bool SoundyOutport::StreamingMode()
{
ALint tState;
alCall(alGetSourcei(mSourceId, AL_SOURCE_TYPE, &tState));
return tState == AL_STREAMING;
}
bool SoundyOutport::StaticMode()
{
ALint tState;
alCall(alGetSourcei(mSourceId, AL_SOURCE_TYPE, &tState));
return tState == AL_STATIC;
}
And here's an annotated screen cap of what I see in my debugger when I hit the error:
I've tried a bunch of little tweaks and variations, and the result is always the same. I've wasted too many days trying to fix this. Please help :)
This error occurs when you trying to fill buffer with data, when the buffer is still queued to the source.
Also this code is wrong.
if(tQueuedBuffers < MAX_BUFFER_COUNT)
{
tBufId = mBufferIds[tQueuedBuffers];
}
else if(tReady > 0)
{
// the fifth time through, this code gets hit
alCall(alSourceUnqueueBuffers(mSourceId, 1, &tBufId));
// debug code: make sure these values go down by one
tQueuedBuffers = QueuedUpBuffers();
tReady = ProcessedBuffers();
}
else
{
return; // no update needed yet.
}
You can fill buffer with data only if it unqueued from source. But your first if block gets tBufId that queued to the source. Rewrite code like so
if(tReady > 0)
{
// the fifth time through, this code gets hit
alCall(alSourceUnqueueBuffers(mSourceId, 1, &tBufId));
// debug code: make sure these values go down by one
tQueuedBuffers = QueuedUpBuffers();
tReady = ProcessedBuffers();
}
else
{
return; // no update needed yet.
}
I'm trying to print out text when a user touches a sprite, however, even though I get no errors when building and running the code, the code refuses to printout the text and I cannot understand what I am doing wrong. Please help me understand why it does not print.
It prints the debug text when I touch the sprite, but not the GUI text with total.
This is the code:
#pragma strict
function Start () {
OnGUI();
}
function OnGUI(){
//var total = 0;
//GUI.Label( myRect, total.ToString() ); // Displays "10".
//GUI.Label( myRect, "" + bullets ); // Displays "10".
// GUI.Label(Rect(0,0,Screen.width,Screen.height),"Total:"+total);
}
//function Update () {
//}
var platform : RuntimePlatform = Application.platform;
function Update(){
if(platform == RuntimePlatform.Android || platform == RuntimePlatform.IPhonePlayer){
if(Input.touchCount > 0) {
if(Input.GetTouch(0).phase == TouchPhase.Began){
checkTouch(Input.GetTouch(0).position);
}
}
}else if(platform == RuntimePlatform.WindowsEditor){
if(Input.GetMouseButtonDown(0)) {
checkTouch(Input.mousePosition);
}
}
}
function checkTouch(pos){
var total = 0;
var wp : Vector3 = Camera.main.ScreenToWorldPoint(pos);
var touchPos : Vector2 = new Vector2(wp.x, wp.y);
var hit = Physics2D.OverlapPoint(touchPos);
if(hit){
GUI.Label(Rect(0,0,Screen.width,Screen.height),"Total:");
Debug.Log(hit.transform.gameObject.name);
hit.transform.gameObject.SendMessage('Clicked',0,SendMessageOptions.DontRequireReceiver);
//total = total +1;
}
}
You cannot put a gui item outside the OnGUI Method. You need to set a boolean to turn on the label.
Something along these lines.
OnGUI(){
if(labelbool)
GUI.Label ....
}
check(){
labelbool = true;
}
I have written code for a game in which some birds are flying. I created array of CCSprite and added them on Scene. Now it assign a scheduler to each bird object for moving in random direction in screen. All are working. Now i am getting trouble in getting collision in birds.
i am trying to run a CCARRAY_FOREACH loop on array but its giving error.
0xC0000005: Access violation reading location 0xfeeefeee.
Please help me how i can get get collision detection in array element while they are moving. updateCollison method is not executing.
My Code is:
#include "HelloWorldScene.h"
using namespace cocos2d;
CCScene* HelloWorld::scene()
{
CCScene * scene = NULL;
do
{
// 'scene' is an autorelease object
scene = CCScene::create();
CC_BREAK_IF(! scene);
// 'layer' is an autorelease object
HelloWorld *layer = HelloWorld::create();
CC_BREAK_IF(! layer);
// add layer as a child to scene
scene->addChild(layer);
} while (0);
// return the scene
return scene;
}
// on "init" you need to initialize your instance
bool HelloWorld::init()
{
//srand(time(NULL));
CCSize size = CCDirector::sharedDirector()->getWinSize();
birds = CCArray::create();
for(int j = 0; j<5; j++){
CCSprite *bird = CCSprite::create("twitter_square.png");
bird->setTag(j);
int max = rand() % 480;
int min = rand() % 320;
bird->setPosition(ccp(max, min));
this->addChild(bird);
birds->addObject(bird);
bird->schedule( schedule_selector(HelloWorld::moveBird), 5.0 );
bird->schedule( schedule_selector(HelloWorld::updateCollison), 5.0 );
}
return true;
}
void HelloWorld::menuCloseCallback(CCObject* pSender)
{
CCDirector::sharedDirector()->end();
}
void HelloWorld::moveBird(float dt)
{
CCSize size = CCDirector::sharedDirector()->getWinSize();
int max = rand() % (int)size.width;
int min = rand() % (int)size.height;
CCActionInterval* actionTo = CCMoveTo::actionWithDuration(5, ccp(max,min));
this->runAction(actionTo);
}
void HelloWorld::updateCollison(float dt)
{
CCObject *obj;
for(int i=0; i < birds->count(); i++)
{
CCLOG("$$$$$$$$$$$$$$$$$$$$$$$");
}
}
It's better to do things in one update function ...for example make one update in that call MoveBird Function which will contain your moving bird code
Secondly now call check Collision function
void update (float dt) {
MoveBird(); // Move how many birds you want to move
CheckCollision();
}
Now how to check collision of your birds
In your collision function forLoop your birds Array check
if(mBirdsArray[i]->boundingBox().containsPoint(mBirdsArray[j]->getPosition()))
and vice versa ...
I hope this will work .. .there maybe better logic than this ..