SneakyJoystick - Movement by certain points/tiles - iphone

I have SneakyJoystick up and running but I want to move my sprite tile by tile in a certain frequency ... I am pretty new to iphone programming and cocos2d so I don't exactly know how the whole SneakyJoystick thingy works.
I got the code from a book and again: I just want my Sprite to move like in the game Pokèmon tile by tile...
-(void)initJoystickAndButtons {
CGSize screenSize = [CCDirector sharedDirector].winSize;
CGRect joystickBaseDimensions =
CGRectMake(0, 0, 128.0f, 128.0f);
CGRect jumpButtonDimensions =
CGRectMake(0, 0, 64.0f, 64.0f);
CGRect attackButtonDimensions =
CGRectMake(0, 0, 64.0f, 64.0f);
CGPoint joystickBasePosition;
CGPoint jumpButtonPosition;
CGPoint attackButtonPosition;
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
// The device is an iPad running iPhone 3.2 or later.
CCLOG(#"Positioning Joystick and Buttons for iPad");
joystickBasePosition = ccp(screenSize.width*0.0625f,screenSize.height*0.052f);
jumpButtonPosition = ccp(screenSize.width*0.946f,screenSize.height*0.052f);
attackButtonPosition = ccp(screenSize.width*0.947f,screenSize.height*0.169f);
} else {
// The device is an iPhone or iPod touch.
CCLOG(#"Positioning Joystick and Buttons for iPhone");
joystickBasePosition = ccp(screenSize.width*0.07f,
screenSize.height*0.11f);
jumpButtonPosition = ccp(screenSize.width*0.93f,
screenSize.height*0.11f);
attackButtonPosition = ccp(screenSize.width*0.93f,
screenSize.height*0.35f);
}
SneakyJoystickSkinnedBase *joystickBase = [[[SneakyJoystickSkinnedBase alloc] init] autorelease];
joystickBase.position = joystickBasePosition;
joystickBase.backgroundSprite =[CCSprite spriteWithFile:#"dpadDown.png"];
joystickBase.thumbSprite =[CCSprite spriteWithFile:#"joystickDown.png"];
joystickBase.joystick = [[SneakyJoystick alloc]initWithRect:joystickBaseDimensions];
leftJoystick = [joystickBase.joystick retain];
leftJoystick.isDPad = YES;
[self addChild:joystickBase];
SneakyButtonSkinnedBase *jumpButtonBase =[[[SneakyButtonSkinnedBase alloc] init] autorelease];
jumpButtonBase.position = jumpButtonPosition;
jumpButtonBase.defaultSprite =[CCSprite spriteWithFile:#"jumpUp.png"];
jumpButtonBase.activatedSprite =[CCSprite spriteWithFile:#"jumpDown.png"];
jumpButtonBase.pressSprite = [CCSprite spriteWithFile:#"jumpDown.png"];
jumpButtonBase.button = [[SneakyButton alloc]initWithRect:jumpButtonDimensions];
jumpButton = [jumpButtonBase.button retain];
jumpButton.isToggleable = NO;
[self addChild:jumpButtonBase];
SneakyButtonSkinnedBase *attackButtonBase =[[[SneakyButtonSkinnedBase alloc] init] autorelease];
attackButtonBase.position = attackButtonPosition;
attackButtonBase.defaultSprite = [CCSprite spriteWithFile:#"handUp.png"];
attackButtonBase.activatedSprite = [CCSprite spriteWithFile:#"handDown.png"];
attackButtonBase.pressSprite = [CCSprite spriteWithFile:#"handDown.png"];
attackButtonBase.button = [[SneakyButton alloc]initWithRect:attackButtonDimensions];
attackButton = [attackButtonBase.button retain];
attackButton.isToggleable = NO;
[self addChild:attackButtonBase];
> }
> -(void)applyJoystick:(SneakyJoystick *)aJoystick toNode:(CCNode *)tempNode forTimeDelta:(float)deltaTime{
> CGPoint scaledVelocity = ccpMult(aJoystick.velocity, 44.0f); // 1
> CGPoint newPosition = ccp(tempNode.position.x + scaledVelocity.x * deltaTime,tempNode.position.y + scaledVelocity.y * deltaTime);
> [tempNode setPosition:newPosition];
> if (jumpButton.active == YES) {
> CCLOG(#"Jump button is pressed.");
> if (attackButton.active == YES) {
> CCLOG(#"Attack button is pressed.");
> } }
> }
>
> # pragma mark -
> # pragma mark Update Method
> -(void) update:(ccTime)deltaTime {
> [self applyJoystick:leftJoystick toNode:dude
> forTimeDelta:deltaTime];
> }

I did something similar for my game. There are many steps and cannot go much into detail.
First you need to know when is the joystick being used.
Second you need to interpet the direction of the joystick. For a game like Pokemon, you only need to check for up/down/right/left directions. It is possible to access the degrees of the joystick. Simply interpret the degrees like "if degrees are between -45 to 45, it means the joystick is mainly facing right" etc.
Third you will have to unlink the joystick from your player object. That tutorial, somewhere, makes you link both of them so that the joystick will automatically move the player. You have to undo that.
Fourth make up a schedule somewhere in your scene. The schedule will interpret the joystick direction (if it is being used), and will run a CCMoveBy action on the player. If the joystick directs to the right and the map's tile size is 32, then the CCMoveBy movement parameter would be (32,0). Remember to not run a nother action if the player is already running one.
There are many details and so much to polish. You better try to ask each thing individually instead of everything in one shot.

Related

Sprite jumping around when i use resumeSchedulerAndActions

Ok I am attempting some AI stuff here and I have been following some Ray Wenderlich tutorials. I have some strange behavior going on. Maybe I am just doing this all wrong... but here you go. When a sprite is within 75 pixels of the target it switches to the Defending AIState and i call pauseSchedulerAndActions and set it to a predetermined safe spot via getDefensePosition method. What I am trying to do is after 2 seconds resume the actions so the sprite will move around again. so I call resumeSchedulerAndActions. Now this just goes through the getDefenseMethod and it moves te sprite between these three places but this is the strange behavior i have two slog calls one before getDefenseMethod and one after the sprite is jumping around from the center of the screen then back to the new spawnPoint:
2013-03-04 20:08:14.897 10-8[2629:c07] before: {217.533, 177.32}
2013-03-04 20:08:14.898 10-8[2629:c07] spawnPoint 1
2013-03-04 20:08:14.899 10-8[2629:c07] after: {100, 100}
dont understand why it is doing that. Why does it not just start from the position it was in?
- (void)execute:(GangMembers *)player {
// Check if should change state
NSArray * enemies = [player.layer enemiesOutsideRange:75 ofPlayer:player];
if (enemies.count > 0) {
NSLog(#"outside range 75");
[player changeState:[[Attacking alloc] init]];
return;
}
[player.layer setPlayer:player attacking:NO];
// Make build decision
[player.layer unschedule:#selector(shoot:)];
[player pauseSchedulerAndActions];
NSLog(#"before: %#", NSStringFromCGPoint(player.position));
[self getDefensePosition];
player.position = spawnPoint;
NSLog(#"after: %#", NSStringFromCGPoint(player.position));
[player performSelector:#selector(resumeSchedulerAndActions) withObject:player afterDelay:2];
}
- (void)getDefensePosition {
// CGSize winSize = [CCDirector sharedDirector].winSize;
int spawnChoice = arc4random() % 3;
spawnPoint = ccp(100, 100);
if(spawnChoice == 0){
spawnPoint = ccp(100, 100);
NSLog(#"spawnPoint 1");
}
else if(spawnChoice == 1){
spawnPoint = ccp(100, 200);
NSLog(#"spawnPoint 2");
}
else {
spawnPoint = ccp(100, 300);
NSLog(#"spawnPoint 3");
}
}
FWIW, I suspect your player object has some CCMove type of actions (which you are pausing). Even though you change the position while paused, when the action resumes, the action sets the position to its current state (startPosition, endPosition, duration, time elapsed since start), which may be quite different from the position you set during the pause.
not certain of your object model/class structure, but something like this:
[player stopAllActions];
player.position = spawnPoint;
[player runAction: [CCSequence actions:
[CCDelayTime actionWithDuration:2.0],
[CCMoveTo actionWithDuration:arc4random()%5+1 position: randomPoint],
[CCCallBlock actionWithBlock:^{ [self performSelector:#selector(moveRandom:) withObject:s afterDelay:0.5]; }],
nil]
];
this way, you recreate a moveto action that will be executed from spawnPoint, and your player.position is not in contention with a running action. Written from memory, you mileage may vary :)

Sprites are disappear after some time

Here some code for Add sprite for Enemies.....
_robbers = [[CCArray alloc] initWithCapacity:kNumAstroids];
for (int i = 0; i < kNumAstroids; ++i) {
CCSprite *asteroid = [CCSprite spriteWithSpriteFrameName:#"robber.png"];
asteroid.visible = NO;
[_batchNode addChild:asteroid];
[_robbers addObject:asteroid];
}
And in Update method ........
double curTime = CACurrentMediaTime();
if (curTime > _nextRunemanSpawn) {
float randSecs = [self randomValueBetween:0.20 andValue:1.0];
_nextRunemanSpawn = randSecs + curTime;
float randY = [self randomValueBetween:80 andValue:80];
float randDuration = [self randomValueBetween:4.5 andValue:4.5];
float randDuration1 = [self randomValueBetween:1.0 andValue:1.0];
CCSprite *asteroid = [_robbers objectAtIndex:_nextRobber];
_nextRobber++;
if (_nextRobber >= _robbers.count) {
_nextRobber = 1;
}
[asteroid stopAllActions];
asteroid.position = ccp(winSize.width +asteroid.contentSize.width / 2 , randY);
asteroid.visible = YES;
[asteroid runAction:[CCSequence actions:[CCMoveBy actionWithDuration:randDuration position:ccp(-winSize.width-asteroid.contentSize.width, 0)],
[CCCallFuncN actionWithTarget:self selector:#selector(setInvisible:)],nil]];
All Sprites are Move from right to left in screen
when Sprite crosses the middle of the screen it automatically disappear
what is the reason for this problem ??
I agree with the previously mentioned statement from LearnCocos2D. It is also possible that you are adding multiple objects and reaching the end of the capacity in the line
_robbers = [[CCArray alloc] initWithCapacity:kNumAstroids];
If you try to spawn more objects than whatever number you have specified for kNumAsteroids it will remove the oldest object and use the new one in its place. I.e. if kNumAsteroids is 5, you have 5 on the screen and then add a sixth, 1 will become 6 and its position will be whatever you set it to.

How do I get a particle effect to follow my sprite in cocos2d?

I want a snow particle effect to follow my sprite and I tried some methods but all that ends up happening is the snow will just stay still instead of following. I did this one tutorial (will post as soon as I find it) thats shows how it do it with fire but didn't work out at all. Any tutorials or suggestions will be appreciated. I believe i have to add some kind of code to the snippet part where it says create enemy off screen.
[self schedule:#selector(gameLogicboss:) interval:180 ];
[self schedule:#selector(updateboss:)];
-(void)addTarget1 {
Boss *target1 = nil;
if ((arc4random() % 2) == 0) {{
target1 = [WeakAndFastBoss boss];
}} else {
target1 = [WeakAndFastBoss boss];
}
// Determine where to spawn the target along the Y axis
CGSize winSize = [[CCDirector sharedDirector] winSize];
int minY = target1.contentSize.height/2;
int maxY = winSize.height - target1.contentSize.height/2;
int rangeY = maxY - minY;
int actualY = (arc4random() % rangeY) + minY;
// Create the target slightly off-screen along the right edge,
// and along a random position along the Y axis as calculated above
target1.position = ccp(winSize.width + (target1.contentSize.width/2), actualY);
[self addChild:target1 ];
// Determine speed of the target
int minDuration = target1.minMoveDuration;
int maxDuration = target1.maxMoveDuration;
int rangeDuration = maxDuration - minDuration;
int actualDuration = (arc4random() % rangeDuration) + minDuration;
// Create the actions
id actionMove = [CCMoveTo actionWithDuration:actualDuration position:ccp(-target1.contentSize.width/2, actualY)];
id actionMoveDone = [CCCallFuncN actionWithTarget:self
selector:#selector(spriteMoveFinished:)];
[target1 runAction:[CCSequence actions:actionMove, actionMoveDone, nil]];
target1.tag = 1;
[_targets addObject:target1];
}
-(void)gameLogicboss:(ccTime)dt {
[self addTarget1];
iterations_++;
}
- (void)updateboss:(ccTime)dt {
CGRect projectileRect = CGRectMake(projectile.position.x - (projectile.contentSize.width/2), projectile.position.y - (projectile.contentSize.height/2), projectile.contentSize.width, projectile.contentSize.height);
BOOL bossHit = FALSE;
NSMutableArray *targetsToDelete = [[NSMutableArray alloc] init];
for (CCSprite *target1 in _targets) {
CGRect target1Rect = CGRectMake(target1.position.x - (target1.contentSize.width/2), target1.position.y - (target1.contentSize.height/2), target1.contentSize.width, target1.contentSize.height);
if (CGRectIntersectsRect(projectileRect, target1Rect)) {
//[targetsToDelete addObject:target];
bossHit = TRUE;
Boss *boss = (Boss *)target1;
boss.hp--;
if (boss.hp <= 0) {
_score ++;
[targetsToDelete addObject:target1];
}
break;
}
}
for (CCSprite *target in targetsToDelete) {
[_targets removeObject:target];
[self removeChild:target cleanup:YES];
_projectilesDestroyed++;
if (_projectilesDestroyed > 2) {
}
}
if (bossHit) {
//[projectilesToDelete addObject:projectile];
[[SimpleAudioEngine sharedEngine] playEffect:#"explosion.caf"];
}
[targetsToDelete release];
}
-(void)spriteMoveFinishedboss:(id)sender {
CCSprite *sprite = (CCSprite *)sender;
[self removeChild:sprite cleanup:YES];
GameOverScene *gameOverScene = [GameOverScene node];
[gameOverScene.layer.label setString:#"You Lose"];
[[CCDirector sharedDirector] replaceScene:gameOverScene];
if (sprite.tag == 1) { // target
[_targets removeObject:sprite];
} else if (sprite.tag == 2) { // projectile
[_projectiles removeObject:sprite];
}
}
I Have found this, at CCParticleSystem.h
/** #typedef tCCPositionType
possible types of particle positions
/
typedef enum {
/* Living particles are attached to the world and are unaffected by emitter repositioning. */
kCCPositionTypeFree,
/** Living particles are attached to the world but will follow the emitter repositioning.
Use case: Attach an emitter to an sprite, and you want that the emitter follows the sprite.
*/
kCCPositionTypeRelative,
/** Living particles are attached to the emitter and are translated along with it. */
kCCPositionTypeGrouped,
you should set it like
myparticleSystem.positionType=kCCPositionTypeGrouped;
Hope it helps.
You don't need to update the particle emitter's position with the sprite.
You can add a particle system to the sprite as a child.
The particle system does need to be typed as such:
CCParticleSystem * booster = [CCParticleSystem particleWithFile:#"boosterParticles.plist"];
//customize your particles' options
//assuming you have a sprite defined as _motherShip
[_motherShip addChild:booster];
/*
* now that the particles are the _motherShip's child, you must remember
* to set the position relative to the mothership's origin...
*/
particles.position = ccp(15,0);
...So now whenever _motherShip.position changes, the booster will follow. It will even rotate with the ship.
Very simple logic without getting into code:
I spawn a sprite and give it a location (x, y).
For each sprite, I also spawn a CCParticleSystem, give it the required particle type, spawn rates etc.
The CCParticleSystem location is now set to be the same (x,y) location as the sprite, and it should get updated as the sprite's (x,y) location is update.
As the sprite and the CCParticleSystem move around, this location (x, y) is getting updates constantly at random in your schedule method per the interval step time.
Hope that makes sense.
I do this
vehicleParticleSystem = [CCParticleSystemQuad particleWithFile:#"vehicleParticle.plist"];
vehicleParticleSystem.position = ccp(_ship.position.x - _ship.contentSize.width/3, _ship.position.y - _ship.contentSize.height/3);
if (UI_USER_INTERFACE_IDIOM() != UIUserInterfaceIdiomPad) {
vehicleParticleSystem.scale = 0.5;
}
[self addChild:vehicleParticleSystem z:-1];
and update its position with this
- (void) updateParticleSystem:(ccTime)dt {
vehicleParticleSystem.position = ccp(_ship.position.x - _ship.contentSize.width/3, _ship.position.y - _ship.contentSize.height/3);
}
which is called in the -(void) update:(ccTime)dt method.
The ship is moved by the user via a joypad.
hope this helps. The positioning for the particle is slightly behind the vehicle for an engine effect.
Did you tried to update your particle position taking advantage of the update method?
I'm doing something like the following lines in one of my games and it works as I think you expect
-(void) update:(CCTime)delta{
_sprite.position = CGPointMake(newXPosition, newYPosition);
_fire.position = CGPointMake(_sprite.position.x, _sprite.position.y);
}
I hope it helps!

Cocos2d game termination problem when a moving sprite goes inside the bounding box of a animating still sprite(a ball get into a hole)

Let me explain it in depth, when ever if(CGRectContainsPoint([hole1 boundingBox], ball1.position)) condition goes true, i do lots of stuffs, like unscheduled, a selector, destroying a ball body calling an animation (please refer Code below)etc. This work properly most of the time. But sometimes when ball is really near to hole(just touching the hole but but not enough to make the above condition true), or is been throws towards the hole really fast speed, then application got terminated. I have checked, by commenting many actions which are been performed in this section, but got nothing helpful, application keep terminating when some efforts are been done to make it terminate.
if(CGRectContainsPoint([hole1 boundingBox], ball1.position))
{
ballBody->SetLinearVelocity(b2Vec2(0.0f,0.0f));
ballBody->SetAngularVelocity(0.0f);
[self unschedule:#selector(tick:)];
self.isTouchEnabled = NO;
[self removeChild:ball1 cleanup:YES];
world->DestroyBody(ballBody);
// create the sprite sheet
CCSpriteSheet *spriteSheet;
GolfBallsAppDelegate *appDelegate = (GolfBallsAppDelegate *)[[UIApplication sharedApplication] delegate];
if([appDelegate.ballValue isEqualToString:#"cricketball"])
{
spriteSheet = [CCSpriteSheet spriteSheetWithFile:#"cricket_ball_strip.png"];
}
else if([appDelegate.ballValue isEqualToString:#"ironball"])
{
spriteSheet = [CCSpriteSheet spriteSheetWithFile:#"iron_ball_strip.png"];
}
else if([appDelegate.ballValue isEqualToString:#"golfball"])
{
spriteSheet = [CCSpriteSheet spriteSheetWithFile:#"golf_ball_strip.png"];
}
else if([appDelegate.ballValue isEqualToString:#"soccerball"])
{
spriteSheet = [CCSpriteSheet spriteSheetWithFile:#"soccer_ball_strip.png"];
}
else if([appDelegate.ballValue isEqualToString:#"basketball"])
{
spriteSheet = [CCSpriteSheet spriteSheetWithFile:#"basket_ball_strip.png"];
}
spriteSheet.position = ccp(hole1.position.x,60);
[self addChild:spriteSheet];
float frameWidth = 96;
float frameHeight = 84;
CCSprite *sprite = [CCSprite spriteWithTexture:spriteSheet.texture rect:CGRectMake(0, 0, frameWidth, frameHeight)];
[spriteSheet addChild:sprite];
//if(animation)
{
// create the animation
CCAnimation *spriteAnimation = [CCAnimation animationWithName:#"potting" delay:0.1f];
int frameCount = 0;
for (int x = 0; x < 6; x++)
{
// create an animation frame
CCSpriteFrame *frame = [CCSpriteFrame frameWithTexture:spriteSheet.texture rect:CGRectMake(x*frameWidth,0*frameHeight,frameWidth,frameHeight) offset:ccp(0,0)];
[spriteAnimation addFrame:frame];
frameCount++;
// stop looping after we've added 14 frames
if (frameCount == 6)
{
//[self removeChild:spriteSheet cleanup:YES];
break;
}
}
// create the action
CCAnimate *spriteAction = [CCAnimate actionWithAnimation:spriteAnimation];
//CCRepeatForever *repeat = [CCRepeatForever actionWithAction:spriteAction];
// run the action
[sprite runAction:spriteAction];
//[sprite runAction:repeat];
}
[self schedule:#selector(loading) interval:0.5];
[self schedule:#selector(holeFinish) interval:1];
//[self removeChild:spriteSheet cleanup:YES];
}
Any suggestion will be highly appreciated.
EDIT: What i found is, problem with folling lines [self removeChild:ball1 cleanup:YES];
world->DestroyBody(ballBody);
(MAY be). but as it not occurs always, (as I mentioned), thus it's being ridiculous.
I think your problem will be that you are trying to delete a body when the b2World is 'locked', (When the world is busy working out collisions).
Try flagging the object as ready for deletion, and deleting it at the start of your next loop:
Replace:
[self removeChild:ball1 cleanup:YES];
world->DestroyBody(ballBody);
with
ball1.isDead = YES;
And at the start of your next game loop:
for (Ball b in balls)
{
if (b.isDead)
world->DestroyBody(b.ballBody);
}

How to do this in Cocos2d?

Sorry about the poor question title, it's just that this seems to big for a title. So here's the dirt:
I am making a game (obviously) and I want the enemies to shoot (not necessarily at the player). I want the shoot method to be in the Enemies file, so as not to clutter up my HelloWorldLayer.m file even more. Here's what I'm using right now:
HelloWorldLayer.m
-(void)addEnemy:(BigAndStrongEnemy *)enemy {
enemy = nil;
if((arc4random() % 4) == 3) {
enemy = [BigAndStrongEnemy enemy];
} else {
enemy = [SmallAndFastEnemy enemy];
}
if(buffDude.position.y > character.position.y || buffDude.position.y < (character.position.y + 10)) {
}
int rand = arc4random() % 320;
if((arc4random() % 2 == 1)) {
[enemy setPosition:ccp(0,rand)];
}else{
[enemy setPosition:ccp(480,rand)];
}
[self animateEnemy:enemy];
[self addChild:enemy];
}
-(void)animateEnemy:(BigAndStrongEnemy *)enemy2 {
float randX = arc4random() % 480;
float randY = arc4random() % 320;
int rand = arc4random() % 320;
CGPoint moveToPoint = CGPointMake(randX, (randY - rand));
[enemies addObject:enemy2];
action = [CCSequence actions:
[CCMoveBy actionWithDuration:1 position:ccpMult(ccpNormalize(ccpSub(moveToPoint, enemy2.position)), 75)],
[CCMoveBy actionWithDuration:3 position:ccp(buffDude.position.x,buffDude.position.y)],
nil];
CCCallFuncO *a = [CCCallFuncO actionWithTarget:self selector:(#selector(shoot:)) object:enemy2];
CCSequence *s = [CCSequence actions:action,a, nil];
CCRepeatForever *repeat = [CCRepeatForever actionWithAction:s];
[enemy2 runAction:repeat];
}
And here's the Shoot info from the Enemies class:
Enemies.m:
-(void)shoot:(id)sender {
BigAndStrongEnemy *enemy = (BigAndStrongEnemy *)sender;
[enemy shoot];
}
-(void)spriteMoveFinished:(id)sender {
CCSprite *b = (CCSprite *)sender;
[self removeChild:b cleanup:YES];
}
-(void)shoot {
buffDude = [CCSprite spriteWithFile:#"bigAndStrongEnemy.gif"];
CCSprite *b = [CCSprite spriteWithFile:#"bullet.gif"];
b.position = ccp(self.position.x,self.position.y);
b.tag = 2;
[self addChild:b];
[bullets addObject:b];
CGSize winSize = [[CCDirector sharedDirector] winSize];
CGPoint point = CGPointMake((winSize.width - (winSize.width - self.position.x)),0);
[b runAction:[CCSequence actions:
[CCMoveBy actionWithDuration:0.5 position:point],
[CCCallFuncN actionWithTarget:self selector:#selector(spriteMoveFinished:)],
nil]];
}
Every time the 3 seconds goes by, the app crashes, and goes to the breakpoint in the CCCallFuncO file. I haven't touched it, is the thing. I am completely confused. Any help is greatly appreciated. Sorry about the long question. Thanks!!
It looks like your CCCallFuncO is calling [self shoot:enemy2] where self is the HelloWorldLayer object, but shoot is defined in the Enemies class.
Edit:
buffDude should be released before assigning it and retain it afterwards, like this:
Change this:
buffDude = [CCSprite spriteWithFile:#"bigAndStrongEnemy.gif"];
to this:
[buffDude release];
buffDude = [CCSprite spriteWithFile:#"bigAndStrongEnemy.gif"];
[buffDude retain];
This assumes that this is the only place where buffDude is assigned. If it is also assigned elsewhere, make sure you properly retain and release it there as well.
Although, the more I think about it, I don't understand why you create a new buffDude every time shoot is called. I'm not sure what you're doing, so I won't say it's wrong, but it doesn't look right to me anyway.
from what i see (and the fact that i only worked with cocos2d-x) i can only tell you to test whether it steps inside your shoot funciton or not, but i guess you are somhow using CCCallFuncO bad, maybe you have to call it passing enemy2 also for the actionWithTarget parameter (i can tell that becouse that's how cocos2d-x works), also check if big and small enemy types can be converted together freely.