I am developing a 2d game in which on my game screen I have to implement a reverse timer from 30 sec till 0 sec and if a player does not move his character he will win otherwise he will lose and the game will be over.
This is my init method:
-(id)init
{
if(self==[super init])
{
self.isTouchEnabled=YES;
self.isAccelerometerEnabled=YES;
CGSize size=[[CCDirector sharedDirector] winSize];
screenwidth=size.width;
screenheight=size.height;
west_pic=[CCSprite spriteWithFile:#"west_pic.png"];
west_pic.anchorPoint=ccp(1, 1);
west_pic.scaleX=1.4;
west_pic.position=ccp(size.width, size.height);
[self addChild:west_pic];
label1=[CCLabelTTF labelWithString:#"Level One" fontName:#"Arial" fontSize:20];
label1.position=ccp(size.width/3.8,size.height/1.2);
[self addChild:label1];
label2=[CCLabelTTF labelWithString:#"Lives :" fontName:#"ArcadeClassic" fontSize:18];
label2.position=ccp(size.width/1.5,size.height/8.2);
[self addChild:label2];
player=[CCSprite spriteWithFile:#"player.png"];
player.position=ccp(size.width/1.7, size.height/2);
player.scale=0.2;
player.tag=2;
player.anchorPoint=ccp(1, 0);
[self addChild:player];
[self schedule:#selector(updateplayer:) interval:1.0f/60.0f];
}
return self;
}
for example, you can have an instance with number of seconds, that player must not to move character, then you must have ssome event methods to know when the character begins and stops movement, create updatable label(if you want to show the rest of the time to player) and schedule timer, which will decrease number of seconds. smth like this
- (void) onEnter
{
[super onEnter];
// if player character not move on start
[self schedule:#selector(reduceRestTime) interval:1.f];
}
- (void) onExit
{
[self unscheduleAllSelectors];
[super onExit];
}
- (void) onCharacterStop
{
m_restTime = // your time left. in your case, 30 sec
// if you have time label
[self updateRestTimeLabel];
[self schedule:#selector(reduceRestTime) interval:1.f];
}
- (void) onCharacterBeginMovement
{
[self unscheduleSelector:#selector(reduceRestTime)];
}
- (void) reduceRestTime
{
m_restTime--;
// if you have time label
[self updateRestTimeLabel];
if( m_timeLeft == 0 )
{
[self unscheduleSelector:#selector(reduceRestTime)];
// your win code
}
}
- (void) updateRestTimeLabel
{
[m_timeLabel setString:[NSString stringWithFormat:#"Time left: %d", m_timeLeft]];
}
Related
As a very beginner in Cocos2D i´m trying to make an iPhone game where some cows move randomly around the screen. I used the code for moving the sprites from here: highoncoding.com/.../. I´m adding the sprites in the init method wia an addAnimal method:
-(void) addAnimal {
animal = [CCSprite spriteWithFile:#"cow.png"];
animal.position = [self generateRandomCoordinates];
[self addChild:animal];
[self startAnimation:animal];
}
My problem:
When i add more than one cow to my game, they move from that random spawn position to another random position and then the first cow stops and the other cow goes on correctly. The startAnimation command in the finishedMoving method goes always to the last sprite. That means i need better control over my sprites but how to da that right?
You can try to implement animal class, that will contain your sprite and incapsulate random movement. Smth like
#implementation Cow
- (id) init
{
self = [super init];
if( self != nil )
{
CCSprite* cowSprite = [CCSprite spriteWithFile:#"cow.png"];
[self addChild: cowSprite];
}
return self;
}
- (void) onEnter
{
[super onEnter];
[self makeRandomMovement];
}
- (void) makeRandomMovement
{
id randomMoveAction = // create your random move action here
id moveEndCallback = [CCCallFunc actionWithTarget: self selector: #selector(makeRandomMovement)];
id sequence = [CCSequence actionOne: randomMoveAction two: moveEndCallback];
[self runAction: sequence];
}
#end
In such way after ending random movement part, method makeRandomMovement will be called again to generate and start new random movement part.
then remake your addAnimal method to smth like
- (void) addAnimal
{
Cow* newCow = [Cow node];
[newCow setPosition: [self generateRandomPosition]];
[self addChild: newCow];
}
I'm new to Objective C and app development so please go easy on me!
I'm trying to make a basic game and need to move a sprite left or right continuously while the user's finger is on the screen - left side to go left, right to go right...
I'm trying to use update to repeat movements of a few pixels every 1/60th second. So far, this is what I have (and sorry about the formatting):
#import "GameplayLayer.h"
#implementation GameplayLayer
-(id)init {
self = [super init];
if (self != nil) {
CGSize screenSize = [CCDirector sharedDirector].winSize;
// enable touches
self.isTouchEnabled = YES;
blobSprite = [CCSprite spriteWithFile:#"blob.png"];
[blobSprite setPosition: CGPointMake(screenSize.width/2, screenSize.height*0.17f)];
ball = [CCSprite spriteWithFile:#"ball.png"];
[ball setPosition:CGPointMake(10, screenSize.height*0.75f)];
[self addChild:blobSprite];
[self addChild:ball];
[self schedule:#selector(update) interval:1.0f/60.0f];
}
return self;
}
-(void) update:(ccTime)dt{
if (_tapDownLeft == YES){
blobSprite.position.x==blobSprite.position.x-5;
}
if (_tapDownRight == YES){
blobSprite.position.x==blobSprite.position.x+5;
}
}
-(void) ccTouchesBegan:(UITouch*)touch withEvent: (UIEvent *)event{
CGPoint touchLocation = [touch locationInView:[touch view]];
touchLocation = [[CCDirector sharedDirector] convertToGL:touchLocation];
if (touchLocation.x > 400) {
if ((blobSprite.position.x+10)<460){
_tapDownRight = YES;
}
}
if (touchLocation.x < 200) {
if ((blobSprite.position.x-10>20)){
_tapDownLeft = YES;
}
}
else {
_tapDownLeft = NO;
_tapDownRight = NO;
}
}
-(void)ccTouchEnded:(UITouch *)touch withEvent:(UIEvent *)event{
_tapDownLeft = NO;
_tapDownRight = NO;
}
-(void) registerWithTouchDispatcher{
[[CCTouchDispatcher sharedDispatcher]addTargetedDelegate:self priority:0 swallowsTouches:YES];
}
#end
Am I on the right lines with this? At the moment it's giving me 'expression result unused' in update. Could anyone tell me what I'm missing? Any help would be greatly appreciated.
Thanks,
Patrick
i see a few things here:
not certain your selector will call update : #selector(update:)
I would not rely on dt being either exactly 1/60th of a second, nor being constant. I would favor defining a speed constant (in points per second) and compute the deltaX in points based on the desired speed and dt, at each update cycle.
I dont see a 'registerWithTouchDispatcher' call (i try to place them in onEnter and onExit) methods.
Somewhere in there, make certain you remove your children (either in dealloc, or better in a local cleanup method (dont forget to invoke [super cleanup]).
Remove the argument in the update function
I have my NSTimer embedded in a class that plays image sequences. Basically it loops and changes a UIImageView. Everything goes well if I let the image sequence finish but... on it's own if I try to stop the timer while it is playing I get a sigabrt. Edit: No longer a sigabrt but now a DeAlloc I can't explain.
The "stop" at the end of a frame sequence is the same stop I am calling mid sequence.
So what might cause an NSTimer to break mid function and DeAlloc. More to the point what might I look at to fix it.
Thanks.
I am using some example code from here: http://www.modejong.com/iOS/PNGAnimatorDemo.zip
Edit: I'll add what I believe to be the pertinent code here.
// Invoke this method to start the animation
- (void) startAnimating
{
self.animationTimer = [NSTimer timerWithTimeInterval: animationFrameDuration target: self selector: #selector(animationTimerCallback:) userInfo: NULL repeats: TRUE];
[[NSRunLoop currentRunLoop] addTimer: animationTimer forMode: NSDefaultRunLoopMode];
animationStep = 0;
if (avAudioPlayer != nil)
[avAudioPlayer play];
// Send notification to object(s) that regestered interest in a start action
[[NSNotificationCenter defaultCenter]
postNotificationName:ImageAnimatorDidStartNotification
object:self];
}
- (void) animationTimerCallback: (NSTimer *)timer {
if (![self isAnimating])
return;
NSTimeInterval currentTime;
NSUInteger frameNow;
if (avAudioPlayer == nil) {
self.animationStep += 1;
// currentTime = animationStep * animationFrameDuration;
frameNow = animationStep;
} else {
currentTime = avAudioPlayer.currentTime;
frameNow = (NSInteger) (currentTime / animationFrameDuration);
}
// Limit the range of frameNow to [0, SIZE-1]
if (frameNow < 0) {
frameNow = 0;
} else if (frameNow >= animationNumFrames) {
frameNow = animationNumFrames - 1;
}
[self animationShowFrame: frameNow];
// animationStep = frameNow + 1;
if (animationStep >= animationNumFrames) {
[self stopAnimating];
// Continue to loop animation until loop counter reaches 0
if (animationRepeatCount > 0) {
self.animationRepeatCount = animationRepeatCount - 1;
[self startAnimating];
}
}
}
- (void) stopAnimating
{
if (![self isAnimating])
return;
[animationTimer invalidate];
self.animationTimer = nil;
animationStep = animationNumFrames - 1;
[self animationShowFrame: animationStep];
if (avAudioPlayer != nil) {
[avAudioPlayer stop];
avAudioPlayer.currentTime = 0.0;
self->lastReportedTime = 0.0;
}
// Send notification to object(s) that regestered interest in a stop action
[[NSNotificationCenter defaultCenter]
postNotificationName:ImageAnimatorDidStopNotification
object:self];
}
Edit2: So I commented out an NSAssert in DeAlloc, commenting that out shed a bit more light. Now getting to self.animationTimer = nil; and saying *** -ImageAnimator setAnimationTimer:]: Message sent to deallocated instance.
DeAlloc is being called right when I invalidate the timer... so I'm a bit confused here.
I have a solution which is working but not optimal.
I just added another function to set the frame it's on to the last frame and it ends the sequence as I need.
But it doesn't solve the question of why it's doing it's crashing if I try to stop the sequence mid run.
Well, I wrote this code so I can assure you that it should be working just fine :) You need to invoke stopAnimating before you are done with the view, the only way you would have got the assert in dealloc is if the view was deallocated while it was still animating. That should not happen, which is exactly why there way an assert there. There is also a big comment explaining the assert, what is unclear about that?
- (void)dealloc {
// This object can't be deallocated while animating, this could
// only happen if user code incorrectly dropped the last ref.
NSAssert([self isAnimating] == FALSE, #"dealloc while still animating");
self.animationURLs = nil;
self.imageView = nil;
self.animationData = nil;
self.animationTimer = nil;
[super dealloc];
}
Just call:
[view stopAnimating];
Before you remove the view from its superview and everything will be just fine.
Please, I need help in making this code work. I intend to do an animation with a sprite I added using cocos2d and box2d in xcode. But for some odd reasons I cannot get the sprite to animate repeatedly.
This code builds successfully but animates only once. Can anyone help and tell me what I am not doing right?
The implementation file are as follows:
#import "Mosquito.h"
#import "Box2DHelpers.h"
#implementation Mosquito
#synthesize flyingAnim;
- (void) dealloc{
[flyingAnim release];
[super dealloc];
}
-(void)initAnimations {
flyingAnim = [self loadPlistForAnimationWithName:#"flyingAnim"
andClassName:NSStringFromClass([self class])];
[[CCAnimationCache sharedAnimationCache] addAnimation:flyingAnim
name:#"flyingAnim"];
}
-(void)changeState:(CharacterStates)newState {
[self stopAllActions];
id action = nil;
// id flyingAction = nil;
//CGPoint newPosition;
[self setCharacterState:newState];
switch (newState) {
case kStateIdle:
[self setDisplayFrame:
[[CCSpriteFrameCache sharedSpriteFrameCache]
spriteFrameByName:#"Mosquito_anim_1.png"]];
break;
case kStateFlying:
action = [CCAnimate actionWithAnimation:flyingAnim
restoreOriginalFrame:NO];
break;
case kStateTakingDamage:
action = [CCBlink actionWithDuration:1.0 blinks:3.0];
break;
default:
//CCLOG(#"Unhandled state %d in Mosquito", newState);
break;
}
if (action != nil) {
[self runAction:action];
}
}
- (id)initWithWorld:(b2World *)theWorld atLocation:(CGPoint)location {
if ((self = [super init])) {
world = theWorld;
[self setDisplayFrame:[[CCSpriteFrameCache
sharedSpriteFrameCache]
spriteFrameByName:#"Mosquito_anim_1.png"]];
gameObjectType = kMosquitoType;
characterHealth = 100.0f;
[self createBodyAtLocation:location];
[self initAnimations];
}
return self;
}
- (void) updateStateWithDeltaTime:(ccTime)deltaTime
andListOfGameObjects:(CCArray *)listOfGameObjects {
//CGPoint oldPosition = self.position;
if ((characterState == kStateDestroyed) &&
([self numberOfRunningActions] > 0)) {
return;
}
if (characterState != kStateFlying &&
[self numberOfRunningActions] == 0) {
[self changeState:kStateFlying];
}
}
#end
Thanks.
id repeatAnimation = [CCRepeatForever actionWithAction:action];
To repeat forever, you need to do that, otherwise you need to just do:
[self runAction:action];
again.
Also, you might want to consider not reassigning action to CCBlink and make another action and call
[self stopAllActions];
id blinkAction = [CCBlink actionWithDuration:1.0 blinks:3.0];
[self runAction:blinkAction];
This may Help you.
One of the easiest ways for sprite animation.
https://sites.google.com/site/rajanallathambi1/cocos2d-tutorials/sprite-animation-without-plist-file
Here is a piece of code that I'm having problems with:
-(IBAction) nextRegister {
[DSBezelActivityView newActivityViewForView:self.view.superview];
previousPosition = (NSInteger *) currentPosition;
currentPosition = (NSInteger *) ((int)currentPosition + (int) 1 );
[currentRegistry updateOnServer];
[self loadNewRegisterInfos];
[DSBezelActivityView removeViewAnimated:YES];
}
Line by line, here is what this snippet does (or should do):
Show a DSBezelActivityView (from this: http://www.dejal.com/developer/dsactivityview)
Previous position receives actual position (since this will move to the next)
Next is current + 1;
Updates record in server (this takes ~1s)
Loads new record and renders on screen (this takes 1~3s, tops)
This line removes the DSBezelActivityView.
So, when I tap the button to load next record, it is supposed to show the ActivityView, load the data, then update the screen and release the ActivityView.
But what happens is: It freezes the app for 3s, shows and dismisses the activity view in less than a second and then finishes the routine.
What is wrong?
[Edited]
Resolved! Its a thread issue.
Split among 4 methods:
-(IBAction) nextRegister {
[NSThread detachNewThreadSelector:#selector(openActivityView) toTarget:self withObject:nil];
[self viewNextRegister];
[self removeView];
}
-(void)viewNextRegister{
previousPosition = (NSInteger *) currentPosition;
currentPosition = (NSInteger *) ((int)currentPosition + (int) 1 );
[currentRegister setScoreOnServer];
// [NSThread detachNewThreadSelector:#selector(loadRegisterInfo) toTarget:self withObject:nil];
[self loadRegisterInfo];
}
-(void)openActivityView{
[DSBezelActivityView newActivityViewForView:self.view.superview];
}
-(void)removeView {
[DSBezelActivityView removeViewAnimated:YES];
}
Rather than a separate thread which can cause issues if you aren't careful you can also do:
-(void) doNextRegister {
previousPosition = (NSInteger *) currentPosition;
currentPosition = (NSInteger *) ((int)currentPosition + (int) 1 );
[currentRegistry updateOnServer];
[self loadNewRegisterInfos];
[DSBezelActivityView removeViewAnimated:YES];
}
-(IBAction) nextRegister {
[DSBezelActivityView newActivityViewForView:self.view.superview];
[self performSelector:#selector(doNextRegister) withObject:nil afterDelay:0.0];
}