Making the bullet Fire -Cocos2d - objective-c

My code has two Bullet-related classes. Bullet and BulletCache. The BulletCache creates a certain number of
I have moved on to just creating a new bullet creating method meant to shoot off the bullets. I used the CCFuncN method but the game is currently throwing NSException errors:
CCAction* action = [CCSequence actions:
[CCAnimate actionWithAnimation:[profile getAnimation:#"attack" index:currentDir]],
[CCCallFuncN actionWithTarget:self selector:#selector(shootBulletFrom:)],
nil];
NSInvalidArgumentException', reason: '-[Player shootBulletFrom:]: unrecognized selector sent to instance 0x703ec70'
edit:
For further help and advice here is the shootBulletFrom method in the BulletCache.
This method is in the BulletCache
-(void) shootBulletFrom:(CGPoint)startPosition velocity:(CGPoint)velocity frameName:(NSString*)frameName
isPlayerBullet:(bool)isPlayerBullet
{
CCArray* bullets = [batch children];
CCNode* node = [bullets objectAtIndex:nextInactiveBullet];
NSAssert([node isKindOfClass:[Bullet class]], #"not a Bullet!");
Bullet* bullet = (Bullet*)node;
[bullet shootBulletAt:startPosition velocity:velocity frameName:frameName
isPlayerBullet:isPlayerBullet];
nextInactiveBullet++;
if (nextInactiveBullet >= [bullets count])
{
nextInactiveBullet = 0;
}
}
I was also recommended to change the [CCCallFuncN] call at the bottom to:
[CCCallFuncN actionWithTarget:self selector:#selector(shootBulletFrom:shotPos velocity:velocity frameName:#"bullet1big.png" isPlayerBullet: YES)],
But then I got the compile Error: Expected ':' before Velocity

You have not mentioned the code for shootBulletFrom, and the error denoted that there is some mistake in the same. May be you have not declared the function in .h file or some other. So if possible mention so.
You can go through this and this links. They are having good examples for bullet firing apps. Hope that helps you.

Related

CCActionDelay not working as expected

What I have is a method that creates CCSprites:
-(void)createDebrisAtPosition:(CGPoint)position{
NSInteger numberOfPieces = [random randomWithMin:5 max:20];
for (int i=0; i<numberOfPieces; i++) {
CCSprite *debris = [CCSprite spriteWithImageNamed:#"debri.png"];
debris.position = position;
debris.physicsBody = [CCPhysicsBody bodyWithRect:CGRectMake(0, 0, debris.contentSize.width, debris.contentSize.height) cornerRadius:0];
debris.physicsBody.collisionType = #"debris";
debris.name = #"Debris";
CCActionRemove *removeAction = [CCActionRemove action];
CCActionSequence *sequence = [CCActionSequence actions:[CCActionDelay actionWithDuration:2.0], removeAction, nil];
[physics addChild:debris];
//physics is a CCPhysicsNode here
[debris runAction:sequence];
}
}
This method then gets invoked during specific collision events:
-(BOOL)ccPhysicsCollisionBegin:(CCPhysicsCollisionPair *)pair enemy:(EnemyNode*)enemy projectile:(ProjectileNode*)projectile
{
[enemy removeFromParent];
[projectile removeFromParent];
[self createDebrisAtPosition:enemy.position];
return NO;
}
Expected behavior: CCSprites should appear and then get removed only after 2.0 secs.
Actual behavior: CCSprites appear for a split-second, then instantly get removed.
I also tried CCActionInterval, CCActionEaseOut, but they didn't work (And they shouldn't, according to the docs, but CCActionDelay — should, but not working). I changed the order of method invocation (runAction after and before addChild), as well as the order of action invocation this didn't work as well. Don't mind the CCActionDelay declaration directly in the CCActionSequence — I tried to declare it as a separate variable, with zero luck.
What am I misunderstanding here?
I'm new here so I'm not allowed to comment yet (this would perhaps be better suited as a comment) but: I haven't been able to recreate your problem. The problem is not related to CCActionDelay or the actions you are running on the debris sprite. You can test this yourself by running your sequence in a different setup. Ergo: there must be a problem somewhere else in your code. I'm sorry, but I cannot help any further based on the example code you've posted.

cocos2d v3 exception thrown removing sprite from scene

so im trying to make a tower defense game, (Towers shoot bullets at advancing enemies), so the problem is when i try to remove the bullet from the scene after it hit the enemy, it throws an exception, with no error in the debugger.
Here is the code:
-(void)shootWeapon
{
CCSprite * bullet = [CCSprite spriteWithImageNamed:#"snowball.png"];
[theGame addChild:bullet];
[bullet setPosition:mySprite.position];//Todo offset snowball to the right of the tower
[bullet runAction:[CCActionSequence actions:[CCActionMoveTo actionWithDuration:0.3
position:chosenEnemy.mySprite.position],[CCActionCallFunc actionWithTarget:self
selector:#selector(damageEnemy)],[CCActionCallFunc actionWithTarget:self
selector:#selector(removeBullet:)], nil]];
}
-(void)removeBullet:(CCSprite *)bullet
{
[bullet.parent removeChild:bullet cleanup:YES];
}
-(void)damageEnemy
{
[chosenEnemy getDamaged:damage];
}
if anyone has an idea why this is going on, any help would be greatly appreciated.
cheers
The bullet is not being passed, hence the exception on removeBullet: method.
This line is the problem:
[CCActionCallFunc actionWithTarget:self
selector:#selector(removeBullet:)]
Add breakpoint to [bullet.parent removeChild:bullet cleanup:YES]; and po bullet on the debugger and you will probably get nil.
My solution would be to use a block action, for example:
CCAction *blockAction = [CCActionCallBlock actionWithBlock:^{
[bullet removeFromParentAndCleanup:YES];
}];

How to run two methods in sequence at time delay?

[self goToStage:currentStage];
[actor deathAnimation];
I have these two methods. I want to call it one by one in sequence. When one is completed after second one is started.
//this method used in nsobject subclass
-(void)deathAnimation {
//Play death animation
}
//this method in cclayer subclass
-(void)goToStage:(int)stage {
//changing scene
}
IN my tick function at particular event i want to call in seqeuence
I use following code but it not working
[CCSequence actions:[CCCallFunc actionWithTarget:actor selector:#selector(deathAnimation)], [CCDelayTime actionWithDuration:4.0], [CCCallFuncN actionWithTarget:self selector:#selector(goToStage:)], nil];
Now what i do? Please tell me.. Is there something wrong?
You can use CCDelayTime, that is used to give a delay, and CCCallBlock,to pass a method to be invoked, like this:
[self runAction:[CCSequence actions:[CCDelayTime actionWithDuration:1],
[CCCallBlock actionWithBlock:^{[self goToStage:currentStage];}],
[CCDelayTime actionWithDuration:1],
[CCCallBlock actionWithBlock:^{[actor deathAnimation}], nil]];
Define a block in you inteface as e.g.
typedef void(^MyCompletion)(void);
edit you deathAnimation to take a block parameter as
- (void)deathAnimationWithCompletion:(MyCompletion)finish {
//..death animation
//...
//when animation finishes
finish(); // This will call your completion block
}
Call this method as
[self deathAnimationWithCompletion:^{
[self goToStage:2];
}];
You can read up on blocks at Ray Wenderlichs fantastic blog.
Hope it helps!
EDIT DUE TO COMMENT
In cocos2d I think you can also make a sequence like this
id aFuncCall = [CCCallFunc actionWithTarget:self selector:#selector(deathAnimation)];
id antoherFuncCall = [CCCallFunc actionWithTarget:self selector:#selector(goToSecondStange:)];
CCSequence *sequence = [CCSequence actions:aFuncCall,anotherFuncCall, nil];
[self runAction:sequence];
But my cocos2d programming skills are bit outdated so not sure if this works...
You can call
[actor deathAnimation];
at the end of the goToStage function, that way it will execute everything in goToStage before calling deathAnimation.
You could put a delay timer in the goToStage if you require it to wait for a specific amount of time.

This animation is not functioning in this method

I'm having a lot of trouble figuring this one out. This method is imported from another class into my viewController.m It works fine if I copy the code into an IBAction in the same file. And the "test midi" is logging when it is supposed to. So the IBOutlets and animation code seem OK but for some reason this method does not do what it is supposed to
- (void) source:(theSource*)data dataReceived:(const dataList *)theList
{
led.animationImages = [NSArray arrayWithObjects:[UIImage imageNamed:#"led-highlighted.png"],[UIImage imageNamed:#"led-passive.png"],nil];
led.animationDuration = 0.3;
led.animationRepeatCount = 20;
[led startAnimating];
NSLog(#"test");}
it also doesn't work if I simply put this to swap the image. The method is being called because it is logging to console.
midiLed.image = [UIImage imageNamed:# "led-highlighted.png"];
The problem may lie in how you are calling this method. It should be on the main thread, and after calling it, your code should return to the run loop (i.e. your code should be "done") before changes to the user interface will have effect.
If this doesn't help you find it, please share the code calling this method.
What thread is -source:dataReceived: being called on? If you're using CoreMIDI, your MIDI-received function will get called on a separate, high-priority thread.
You should not touch the UI from a non-main thread, because UIKit isn't thread safe.
Here's one way to get the UI running on the main thread:
- (void) source:(theSource*)data dataReceived:(const dataList *)theList
{
dispatch_async(dispatch_get_main_queue(), ^{
led.animationImages = [NSArray arrayWithObjects:[UIImage imageNamed:#"led-highlighted.png"],[UIImage imageNamed:#"led-passive.png"],nil];
led.animationDuration = 0.3;
led.animationRepeatCount = 20;
[led startAnimating];
NSLog(#"test");
});
}

Confounding Cocoa problem — program hangs unless there’s an unrecognised method call

Bear with me, this one is hard to explain. I hope some hero out there knows what’s going on here. Some history needed;
One of my cocoa objects, “Ball” represents a small graphic. It only makes sense within a view. In some of the Ball’s methods, it asks the view to redraw. Most importantly, it asks the view to redraw whenever the Ball’s position parameter is set. This is achieved in the setter.
Here’s the mouthful, as suggested:
In View.m
- (void)mouseUp:(NSEvent *)theEvent {
if (![runnerPath isEmpty]) {
[walkPath removeAllPoints];
[walkPath appendBezierPath:runnerPath];
[runnerPath removeAllPoints];
[[self held] setStep:0];
[[self held] setPath:walkPath];
[NSTimer scheduledTimerWithTimeInterval:.01 target:[self held] selector:#selector(pace) userInfo:nil repeats:YES];
}
}
In Ball.m
- (void)pace {
CGFloat juice = 10;
BOOL loop = YES;
while (loop) {
if ([self step] == [[self path] elementCount]) {
if ([[self timer] isValid]) {
[[self timer] invalidate];
}
[[self path] removeAllPoints];
// #throw([NSException exceptionWithName:#"test" reason:#"reason" userInfo:nil]);
}
if (loop) {
CGFloat distance;
NSPoint stepPoint;
if ([[self path] elementCount] > 0) {
NSPoint returnPoints[2];
[[self path] elementAtIndex:[self step] associatedPoints:returnPoints];
stepPoint = returnPoints[0];
distance = pixelDistance([self position], stepPoint);
}
if (distance <= juice) {
[self setPosition:stepPoint];
if (distance < juice) {
juice -= distance;
loop = YES;
[self setStep:[self step]+1];
} else {
loop = NO;
}
} else {
NSPoint cutPoint = moveAlongBetween([self position], stepPoint, juice);
[self setPosition:cutPoint];
loop = NO;
}
}
}
}
could you also tell how you handle exceptions? since normally an unrecognized selector will end your program. Maybe you need an exception rather than an unrecognized selector. Try:
#throw([NSException exceptionWithName:#"test" reason:#"reason" userInfo:nil]);
If this would fix it as well, you're doing something after this code which freezes the app.
edit: thanks for the code update.
There's some weird stuff going on here! I'm not going to rewrite the whole thing, so here's some pointers:
first of all: you're looping inside some routine that is called from a timer loop. Is that intended? There is no way to pause execution within that while() loop, so it will happen in a blink anyway. You would need to keep some state information in the class. E.g. adding a loop counter every time pace is called.
second: if you start a timer, it will call your selector with the timer as an argument. So define the function as -(void)pace:(NSTimer*)timer, and use timer, not [self timer] (the latter will not be your timer anyway, if you don't assign it!)
third: you're firing 100 times a second. That is a lot, and presumably higher than the refresh rate of any device you're writing this for. I think 20/sec is enough.
fourth: to be sure, if you change it to -(void)pace:(NSTimer*)timer, don't forget to use #selector(pace:) (i.e. don't forget the :)
fix those things, and if it's still broken, update your question again and put in comment so we will know. Good luck!
Try calling
for (NSView *each in [self views]) {
...
}
I'm assuming that views is an array, so fast enumeration applies to it directly and there is no need to call allObjects.
A couple of other points.
Have you set a Global breakpoint of objc_exception_throw? This will apply to all Xcode projects and is so useful I'm surprised it isn't set by default.
You say you looked at the Console for errors. I take it, then, that you didn't set a breakpoint on the code and step into it to see exactly what is happening when your execution reaches that point? Have a look at the Xcode Debugging Guide