I am trying to get the sprite to regenerate itself once it moves off of the screen, but no luck.
#import "MyScene.h"
#implementation MyScene
-(id)initWithSize:(CGSize)size {
if (self = [super initWithSize:size]) {
/* Setup your scene here */
self.backgroundColor = [SKColor colorWithRed:0.05 green:0.15 blue:0.2 alpha:1.0];
SKSpriteNode *pole = [SKSpriteNode spriteNodeWithImageNamed:(#"pole")];
bamboo.position = CGPointMake (30, 0);
bamboo.size = CGSizeMake(15, 1136);
[self addChild: pole];
SKSpriteNode *pole2 = [SKSpriteNode spriteNodeWithImageNamed:(#"pole")];
pole2.position = CGPointMake (290, 0);
pole2.size = CGSizeMake(15, 1136);
[self addChild: pole2];
SKSpriteNode *spike = [SKSpriteNode spriteNodeWithImageNamed:(#"spike")];
spike.position = CGPointMake (45, 600);
spike.size = CGSizeMake(15, 75);
SKAction *moveDown = [SKAction moveByX:(0) y:(-10) duration:(.05)];
[spike runAction:[SKAction repeatActionForever:moveDown]];
[self addChild: spike];
}
return self;
}
-(void)update:(CFTimeInterval)currentTime {
/* Called before each frame is rendered */
if (_spike.position.y < 250) {
_spike.position = CGPointMake(45, 600);
}
}
#end
What could be the problem? Xcode does not give me an error, the "spike" node simply moves off the screen and does not reset itself. I have changed the values in the conditional, but the same thing happens. It's like the conditional is being ignored.
What you should do is to check Sprite's position in the update method, you can try this;
-(id)initWithSize:(CGSize)size {
if (self = [super initWithSize:size]) {
/* Setup your scene here */
_spike = [SKSpriteNode spriteNodeWithImageNamed:(#"spike")];
_spike.position = CGPointMake (45, 600);
_spike.size = CGSizeMake(15, 75);
SKAction *moveDown = [SKAction moveByX:(0) y:(-10) duration:(.05)];
[_spike runAction:[SKAction repeatActionForever:moveDown]];
[self addChild:_spike];
}
return self;
}
-(void)update:(CFTimeInterval)currentTime {
/* Called before each frame is rendered */
if (_spike.position.y < 250) {
_spike.position = CGPointMake(45, 600);
}
}
Related
I am trying to make a vehicle (in this case a train) move based on player input. If I move the train via an SKAction, the wheels do not rotate. I could use the applyForce method on its physics body, but it I need more control. I need to make it move a certain distance over a certain amount of time. How can this be accomplished?
-(void)didMoveToView:(SKView *)view {
SKTexture *trainBodyTexture = [SKTexture textureWithImageNamed:#"levelselect_trainbody"];
SKSpriteNode *trainBody = [[SKSpriteNode alloc] initWithTexture:trainBodyTexture];
trainBody.zPosition = 0;
trainBody.position = CGPointMake(300, 500);
trainBody.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:trainBody.size];
[self addChild:trainBody];
SKTexture *trainWheelTexture = [SKTexture textureWithImageNamed:#"levelselect_trainwheel"];
SKSpriteNode *trainWheel1 = [[SKSpriteNode alloc] initWithTexture:trainWheelTexture];
trainWheel1.zPosition = 1;
trainWheel1.physicsBody = [SKPhysicsBody bodyWithCircleOfRadius:trainWheel1.size.width/2];
trainWheel1.physicsBody.allowsRotation = YES;
trainWheel1.position = CGPointMake(220, 400);
[self addChild:trainWheel1];
SKSpriteNode *trainWheel2 = [[SKSpriteNode alloc] initWithTexture:trainWheelTexture];
trainWheel2.zPosition = 1;
trainWheel2.physicsBody = [SKPhysicsBody bodyWithCircleOfRadius:trainWheel2.size.width/2];
trainWheel2.physicsBody.allowsRotation = YES;
trainWheel2.position = CGPointMake(380, 400);
[self addChild:trainWheel2];
SKShapeNode *dot = [SKShapeNode shapeNodeWithCircleOfRadius:10];
dot.zPosition = 2;
dot.fillColor = [NSColor redColor];
dot.position = CGPointMake(0, -20);
[trainWheel1 addChild:dot];
SKPhysicsJointPin *pin = [SKPhysicsJointPin jointWithBodyA:trainBody.physicsBody bodyB:trainWheel1.physicsBody anchor:trainWheel1.position];
SKPhysicsJointPin *pin2 = [SKPhysicsJointPin jointWithBodyA:trainBody.physicsBody bodyB:trainWheel2.physicsBody anchor:trainWheel2.position];
[self.scene.physicsWorld addJoint:pin];
[self.scene.physicsWorld addJoint:pin2];
//[trainWheel1 runAction:[SKAction moveByX:300 y:0 duration:3]];
[trainBody.physicsBody applyForce:CGVectorMake(3000, 0)];
}
UPDATE: Implemented With A Train Class (suggested by Jaffer Sheriff)
Train.h
#import <SpriteKit/SpriteKit.h>
#interface Train : SKSpriteNode
-(void) createPhysics;
-(void) moveLeft;
-(void) moveRight;
#end
Train.m
#import "Train.h"
#interface Train()
#property SKSpriteNode *trainBody, *trainWheelFront, *trainWheelRear;
#property SKPhysicsWorld *physicsWorld;
#end
#implementation Train
-(instancetype) init {
if (self = [super init]) {
[self initTrainBody];
[self initWheels];
}
return self;
}
-(void) initTrainBody {
SKTexture *trainBodyTexture = [SKTexture textureWithImageNamed:#"levelselect_trainbody"];
_trainBody = [[SKSpriteNode alloc] initWithTexture:trainBodyTexture];
_trainBody.zPosition = 0;
_trainBody.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:_trainBody.size];
[self addChild:_trainBody];
}
-(void) initWheels {
SKTexture *_trainWheelTexture = [SKTexture textureWithImageNamed:#"levelselect_trainwheel"];
_trainWheelFront = [[SKSpriteNode alloc] initWithTexture:_trainWheelTexture];
_trainWheelFront.zPosition = 1;
_trainWheelFront.physicsBody = [SKPhysicsBody bodyWithCircleOfRadius:_trainWheelFront.size.width/2];
_trainWheelFront.physicsBody.allowsRotation = YES;
_trainWheelFront.position = CGPointMake(-80, -82);
[self addChild:_trainWheelFront];
_trainWheelRear = [[SKSpriteNode alloc] initWithTexture:_trainWheelTexture];
_trainWheelRear.zPosition = 1;
_trainWheelRear.physicsBody = [SKPhysicsBody bodyWithCircleOfRadius:_trainWheelRear.size.width/2];
_trainWheelRear.physicsBody.allowsRotation = YES;
_trainWheelRear.position = CGPointMake(80, -82);
[self addChild:_trainWheelRear];
//dot used to see if wheels are rotating, no other point
SKShapeNode *dot = [SKShapeNode shapeNodeWithCircleOfRadius:10];
dot.zPosition = 2;
dot.fillColor = [NSColor redColor];
dot.position = CGPointMake(0, -20);
[_trainWheelFront addChild:dot];
}
//this method is called after the train node is added to the scene in GameScene otherwise will get error adding joints before node is in scene
-(void) createPhysics {
SKPhysicsJointPin *pin = [SKPhysicsJointPin jointWithBodyA:_trainBody.physicsBody bodyB:_trainWheelFront.physicsBody anchor:_trainWheelFront.position];
SKPhysicsJointPin *pin2 = [SKPhysicsJointPin jointWithBodyA:_trainBody.physicsBody bodyB:_trainWheelRear.physicsBody anchor:_trainWheelRear.position];
[self.scene.physicsWorld addJoint:pin];
[self.scene.physicsWorld addJoint:pin2];
}
-(void) moveLeft {
SKAction *rotateLeft = [SKAction rotateByAngle:6*M_PI duration:0.2];
[_trainWheelFront runAction:rotateLeft];
[_trainWheelRear runAction:rotateLeft];
}
-(void) moveRight {
SKAction *rotateRight = [SKAction rotateByAngle:-6*M_PI duration:0.2];
[_trainWheelFront runAction:rotateRight];
[_trainWheelRear runAction:rotateRight];
}
#end
GameScene.m
#import "GameScene.h"
#import "Train.h"
#interface GameScene()
#property Train *train;
#end
#implementation GameScene
-(void)didMoveToView:(SKView *)view {
[self initTrain];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(keyPressed:) name:#"KeyPressedNotificationKey" object:nil]; //using notifications and custom view class to handle key presses
}
-(void) initTrain {
_train = [[Train alloc] init];
_train.position = CGPointMake(500, 300);
[self addChild:_train];
[_train createPhysics];
}
-(void)update:(CFTimeInterval)currentTime {
/* Called before each frame is rendered */
}
-(void) keyPressed:(NSNotification*)notification {
NSNumber *keyCodeObject = notification.userInfo[#"keyCode"];
NSInteger keyCode = keyCodeObject.integerValue;
NSLog(#"keycode = %lu", keyCode);
switch (keyCode) {
case 123:
[self leftArrowPressed];
break;
case 124:
[self rightArrowPressed];
break;
}
}
-(void) leftArrowPressed {
SKAction *moveLeft = [SKAction moveByX:-200 y:0 duration:0.2];
[_train runAction:moveLeft];
[_train moveLeft];
}
-(void) rightArrowPressed {
SKAction *moveRight = [SKAction moveByX:200 y:0 duration:0.2];
[_train runAction:moveRight];
[_train moveRight];
}
#end
Note: This solution causes the entire train to flip and freak out when the left/right keys are pressed. It seems like my pin joints are incorrect, but they seem correct to me :/
Default Initializer of SkSpriteNode is - (instancetype)initWithTexture:(SKTexture *)texture color:(SKColor *)color size:(CGSize)size; Try this,
#interface Train : SKSpriteNode
- (instancetype)initTrainWithColor:(UIColor *) color andSize:(CGSize) size;
-(void) animateWheelsWithTime:(float) time;
#end
#interface Train ()
{
SKSpriteNode *wheel1;
SKSpriteNode *wheel2;
NSMutableArray *wheelsArray;
}
#end
#implementation Train
- (instancetype)initTrainWithColor:(UIColor *) color andSize:(CGSize) size
{
self = [super initWithTexture:nil color:color size:size];
if (self)
{
[self addWheels];
}
return self;
}
-(void)addWheels
{
wheelsArray = [[NSMutableArray alloc]init];
wheel1 = [SKSpriteNode spriteNodeWithImageNamed:#"wheel"];
[wheel1 setPosition:CGPointMake(-(self.frame.size.width/2.0f-wheel1.frame.size.width/2.0f), - (self.frame.size.height/2.0f - wheel1.frame.size.height/2.0f))];
[self addChild:wheel1];
wheel2 = [SKSpriteNode spriteNodeWithImageNamed:#"wheel"];
[wheel2 setPosition:CGPointMake((self.frame.size.width/2.0f-wheel2.frame.size.width/2.0f), - (self.frame.size.height/2.0f - wheel2.frame.size.height/2.0f))];
[self addChild:wheel2];
[wheelsArray addObject:wheel1];
[wheelsArray addObject:wheel2];
}
-(void) animateWheelsWithTime:(float) time
{
for (SKSpriteNode *wheel in wheelsArray)
{
SKAction *act = [SKAction rotateByAngle:3*M_PI duration:time];
[wheel runAction:act];
}
}
#end
In GameScene.m add train like this,
-(void) addTrain
{
Train *train1 = [[Train alloc]initTrainWithColor:[UIColor yellowColor] andSize:CGSizeMake(150, 100)];
[train1 setPosition:CGPointMake(self.size.width/2.0f, self.size.height/2.0f)];
[self addChild:train1];
SKAction *act = [SKAction moveTo:CGPointMake(self.size.width/2.0f, self.size.height - 50) duration:2];
[train1 runAction:act];
[train1 animateWheelsWithTime:2];
}
I tried and it works.
I am taking a square cropped photo with GPUImageStillCamera and allowing the user to zoom the camera. When the user clicks to take a picture the camera jumps forward for a split second (as if the camera zoomed in even further past the area the user zoomed to and then immediately returns to the correct crop once the image is returned to screen). This only happens when the user has zoomed the camera. If they have not zoomed the camera the flicker/jump does not happen. (The image return has the correct crop whether or not the user has zoomed).
Thoughts?
Creating camera and adding square crop
//Add in filters
stillCamera = [[GPUImageStillCamera alloc] initWithSessionPreset:AVCaptureSessionPreset1280x720 cameraPosition:AVCaptureDevicePositionBack];
stillCamera.outputImageOrientation = UIInterfaceOrientationPortrait;
//Creating a square crop filter
cropFilter = [[GPUImageCropFilter alloc] initWithCropRegion:CGRectMake(0.f, (720.0f/1280.0f)/2.0f, 1.f, (720.0f/1280.0f))];
Image zoom method
-(void)imagePinch:(UIPinchGestureRecognizer *)recognizer{ //Controlling the zoom scale as the user pinches the live preview
if (recognizer.state == UIGestureRecognizerStateBegan) {
zoomOutAdder = 0.0f;
if (currentScale > 2) {
zoomOutAdder = currentScale;
}
}
float addition = (recognizer.scale - lastScale);
if (addition > 0) {
addition = addition *1.7;
}
if (addition < 0) {
addition = addition *(1.7+zoomOutAdder);
}
currentScale = currentScale +addition;
lastScale = recognizer.scale;
if (currentScale < 1) {
currentScale = 1;
}
if (currentScale > 4) {
currentScale =4;
}
if (currentScale == 1) {
zoomOutAdder = 0.0f;
}
cameraImagePreview.transform = CGAffineTransformMakeScale(currentScale, currentScale);
if (recognizer.state == UIGestureRecognizerStateEnded) {
lastScale = 1.0f;
}
Take a photo method
//Adjust crop based on zoom scale of the user
CGFloat zoomReciprocal = 1.0f / currentScale;
CGPoint offset = CGPointMake(((1.0f - zoomReciprocal) / 2.0f), (((1.0f- zoomReciprocal)*(720.0f/1280.0f)) / 2.0f) + ((720.0f/1280.0f)/2)) ;
CGRect newCrop = cropFilter.cropRegion;
newCrop.origin.x = offset.x;
newCrop.origin.y = offset.y;
newCrop.size.width = cropFilter.cropRegion.size.width * zoomReciprocal;
newCrop.size.height = cropFilter.cropRegion.size.height *zoomReciprocal;
cropFilter.cropRegion = newCrop;
*/
//Place photo inside an image preview view for the user to decide if they want to keep it.
[stillCamera capturePhotoAsImageProcessedUpToFilter:cropFilter withOrientation:imageOrientation withCompletionHandler:^(UIImage *processedImage, NSError *error) {
//Pause the current camera
[stillCamera pauseCameraCapture];
//Rest of method
ADDED METHODS
- (void) flipCamera {
if (stillCamera.cameraPosition != AVCaptureDevicePositionFront) {
[UIView animateWithDuration:.65 animations:^{
flipCamera.transform = CGAffineTransformMakeScale(-1, 1);
}];
} else {
[UIView animateWithDuration:.65 animations:^{
flipCamera.transform = CGAffineTransformMakeScale(1, 1);
}];
}
[self performSelector:#selector(rotateCamera) withObject:0 afterDelay:.2];
}
- (void) rotateCamera {
[stillCamera rotateCamera];
//Adjust flash settings as needed
[stillCamera.inputCamera lockForConfiguration:nil];
if (stillCamera.cameraPosition != AVCaptureDevicePositionFront) {
[stillCamera.inputCamera setFlashMode:AVCaptureFlashModeOff];
}
NSAttributedString *attributedFlash =
[[NSAttributedString alloc]
initWithString:#"off"
attributes:
#{
NSFontAttributeName : [UIFont fontWithName:#"Roboto-Regular" size:13.0f],
NSForegroundColorAttributeName : [UIColor colorWithWhite:1 alpha:.55],
NSKernAttributeName : #(.25f)
}];
flashLabel.attributedText = attributedFlash;
[UIView animateWithDuration:.2 animations:^{
[flash setTintColor:[UIColor colorWithWhite:1 alpha:.55]];
}];
[stillCamera.inputCamera unlockForConfiguration];
}
- (void) changeFlash {
if (stillCamera.cameraPosition == AVCaptureDevicePositionFront) {//no flash available on front of camera
return;
}
[stillCamera.inputCamera lockForConfiguration:nil];
if (stillCamera.inputCamera.flashMode == AVCaptureFlashModeOff) {
[stillCamera.inputCamera setFlashMode:AVCaptureFlashModeOn];
[self animateFlashWithTintColor:[UIColor colorWithWhite:1 alpha:1] andString:#"on"];
} else if (stillCamera.inputCamera.flashMode == AVCaptureFlashModeOn) {
[stillCamera.inputCamera setFlashMode:AVCaptureFlashModeOff];
[self animateFlashWithTintColor:[UIColor colorWithWhite:1 alpha:.55] andString:#"off"];
}
[stillCamera.inputCamera unlockForConfiguration];
}
- (void) animateFlashWithTintColor:(UIColor *)color andString:(NSString *)text {
//Set new text
NSAttributedString *attributedFlash =
[[NSAttributedString alloc]
initWithString:text
attributes:
#{
NSFontAttributeName : [UIFont fontWithName:#"Roboto-Regular" size:13.0f],
NSForegroundColorAttributeName : [UIColor colorWithWhite:1 alpha:.55],
NSKernAttributeName : #(.25f)
}];
flashLabel.attributedText = attributedFlash;
float duration = .7;
[UIView animateKeyframesWithDuration:duration delay:0 options:0 animations:^{
[UIView addKeyframeWithRelativeStartTime:0 relativeDuration:duration animations:^{
[flash setTintColor:color];
}];
[UIView addKeyframeWithRelativeStartTime:0 relativeDuration:.7/duration animations:^{
flash.transform = CGAffineTransformMakeRotation(M_PI);
}];
}completion:^(BOOL finished){
flash.transform = CGAffineTransformIdentity;
}];
}
-(void) usePhoto {
if ([ALAssetsLibrary authorizationStatus] != ALAuthorizationStatusAuthorized){
NSLog(#"Do Not Have Right To Save to Photo Library");
}
//Save Image to Phone Album & save image
UIImageWriteToSavedPhotosAlbum(takenPhoto.image, nil, nil, nil);
//Save Image to Delegate
[self.delegate saveImageToDatabase:takenPhoto.image];
[self performSelector:#selector(dismissCamera) withObject:0 afterDelay:.4];
}
Some additional code showing the creation of the the various camera elements used to capture a photo.
centerPoint = CGPointMake(self.view.frame.size.width/2, (cameraHolder.frame.size.height+50+self.view.frame.size.height)/2);
cameraImagePreview = [[GPUImageView alloc] initWithFrame:CGRectMake(0, 0, cameraHolder.frame.size.width, cameraHolder.frame.size.width)];
[cameraHolder addSubview:cameraImagePreview];
UITapGestureRecognizer *tapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(imageTouch:)];
[cameraImagePreview addGestureRecognizer:tapGesture];
UIPinchGestureRecognizer *pinchGesture = [[UIPinchGestureRecognizer alloc] initWithTarget:self action:#selector(imagePinch:)];
[cameraImagePreview addGestureRecognizer:pinchGesture];
float scaleForView = self.view.frame.size.width/720.0;
fullCameraFocusPoint = [[UIView alloc]initWithFrame:CGRectMake(0, 0, self.view.frame.size.width, 1280*scaleForView)];
fullCameraFocusPoint.center = CGPointMake(cameraHolder.frame.size.width/2, (cameraHolder.frame.size.width/2)+50);
[self.view insertSubview:fullCameraFocusPoint atIndex:0];
takenPhoto = [[UIImageView alloc]initWithFrame:cameraHolder.frame];
takenPhoto.alpha = 0;
[self.view addSubview:takenPhoto];
//Add in filters
stillCamera = [[GPUImageStillCamera alloc] initWithSessionPreset:AVCaptureSessionPreset1280x720 cameraPosition:AVCaptureDevicePositionBack];
stillCamera.outputImageOrientation = UIInterfaceOrientationPortrait;
//Creating a square crop filter
cropFilter = [[GPUImageCropFilter alloc] initWithCropRegion:CGRectMake(0.f, (720.0f/1280.0f)/2.0f, 1.f, (720.0f/1280.0f))];
//Create standard vignette filter
vignetteFilter = [[GPUImageVignetteFilter alloc] init]; //1
vignetteFilter.vignetteCenter = CGPointMake(.5, .5);
vignetteFilter.vignetteStart = 0.4f;
vignetteFilter.vignetteEnd = 1.08f;
//Add filters to photo
[cropFilter addTarget:vignetteFilter];
[stillCamera addTarget:cropFilter];
[vignetteFilter addTarget:cameraImagePreview];
[stillCamera startCameraCapture];
I have a game with a menu scene, a play scene, and a game over scene. When I am on one of them is there a way to not run the others in the background. For example on my play scene when you make contact with something it switches to the game over scene. When I'm on the menu scene the play scene runs and when it makes contact it switches to the game over scene.
So My Question is: Can I make it so that the scene won't run in the background? Or a way to delay it until I press the play button on the menu?
Here is the code for the first scene:
#import "WEMenuScene.h"
#import "WEMyScene.h"
#implementation WEMenuScene
-(id)initWithSize:(CGSize)size {
if (self = [super initWithSize:size]) {
/* Setup your scene here */
self.scaleMode = SKSceneScaleModeAspectFill;
SKSpriteNode* background = [SKSpriteNode spriteNodeWithImageNamed:#"landscape"];
background.position = CGPointMake(CGRectGetMidX(self.frame),CGRectGetMidY(self.frame));
background.zPosition = 1000;
[self addChild:background];
[self addChild:[self playButton]];
}
return self;
}
-(SKSpriteNode *) playButton {
SKSpriteNode* play = [SKSpriteNode spriteNodeWithImageNamed:#"Play"];
play.position = CGPointMake(CGRectGetMidX(self.frame), 300);
play.zPosition = 1200;
play.name = #"playButton";
return play;
}
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *touch = [touches anyObject];
CGPoint location = [touch locationInNode:self];
SKNode* node = [self nodeAtPoint:location];
if ([node.name isEqualToString:#"playButton"]) {
SKScene* playScene = [[WEMyScene alloc] initWithSize:self.size];
SKTransition* transitionPlay = [SKTransition doorsOpenVerticalWithDuration:0.5];
[self.view presentScene:playScene transition:transitionPlay];
}
}
#end
Here is the code for the second scene:
#import "WEMyScene.h"
#import "WECapturedScene.h"
#implementation WEMyScene
-(id)initWithSize:(CGSize)size {
if (self = [super initWithSize:size]) {
self.scaleMode = SKSceneScaleModeAspectFill;
[self performSelector:#selector(logs) withObject:nil afterDelay:3.0];
[self performSelector:#selector(moveBackground) withObject:nil afterDelay:0.0];
[self addChild:[self createCharacter]];
[self setUpActions];
}
return self;
}
-(SKSpriteNode *) createCharacter {
SKSpriteNode* holly = [SKSpriteNode spriteNodeWithImageNamed:#"holly1"];
holly.position = CGPointMake(CGRectGetMidX(self.frame), 185);
holly.name = #"holly";
holly.zPosition = 40;
return holly;
}
-(void) logs {
CGPoint startPoint = CGPointMake(480, 175);
SKSpriteNode* logs = [SKSpriteNode spriteNodeWithImageNamed:#"log"];
logs.position = CGPointMake(startPoint.x, startPoint.y);
logs.name = #"logs";
logs.zPosition = 40;
[self addChild:logs];
float spawnLog = arc4random_uniform(3)+ 1.4;
[self performSelector:#selector(logs) withObject:nil afterDelay:spawnLog];
}
-(void) setUpActions {
SKTextureAtlas *atlas = [SKTextureAtlas atlasNamed:#"Holly"];
SKTexture *movetex1 = [atlas textureNamed:#"holly1"];
SKTexture *movetex2 = [atlas textureNamed:#"holly2"];
SKTexture *movetex3 = [atlas textureNamed:#"holly3"];
SKTexture *movetex4 = [atlas textureNamed:#"holly4"];
SKTexture *movetex5 = [atlas textureNamed:#"holly5"];
SKTexture *movetex6 = [atlas textureNamed:#"holly6"];
SKTexture *movetex7 = [atlas textureNamed:#"holly7"];
NSArray *atlasTexture = #[movetex1, movetex2, movetex3, movetex4, movetex5, movetex6, movetex7];
SKAction* atlasAnimation =[SKAction repeatActionForever:[SKAction animateWithTextures:atlasTexture timePerFrame:0.08]];
hollyMovement = [SKAction sequence:#[atlasAnimation]];
SKSpriteNode* holly = (SKSpriteNode*)[self childNodeWithName:#"holly"];
holly.zPosition = 40;
[holly runAction:hollyMovement];
SKAction* moveUp = [SKAction moveByX:0 y:90 duration:0.50];
SKAction* wait = [SKAction moveByX:0 y:0 duration:0.4];
SKAction* moveDown = [SKAction moveByX:0 y:-90 duration:0.4];
SKAction* done = [SKAction performSelector:#selector(jumpDone) onTarget:self];
hollyUp = [SKAction sequence:#[moveUp, wait, moveDown, done]];
}
-(void) jumpDone {
isJumping = NO;
}
-(void) moveBackground {
CGPoint startPoint = CGPointMake(480, 230);
SKSpriteNode* landscape = [SKSpriteNode spriteNodeWithImageNamed:#"landscape"];
landscape.position = CGPointMake(startPoint.x, startPoint.y);
landscape.name = #"landscape";
landscape.zPosition = 1;
[self addChild:landscape];
float spawnbackground = 0.7;
[self performSelector:#selector(moveBackground) withObject:nil afterDelay:spawnbackground];
}
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
/* Called when a touch begins */
if (isJumping == NO) {
isJumping = YES;
SKSpriteNode* holly = (SKSpriteNode*)[self childNodeWithName:#"holly"];
[holly runAction:hollyUp];
}
}
-(void)update:(CFTimeInterval)currentTime {
/* Called before each frame is rendered */
SKNode* holly = [self childNodeWithName:#"holly"];
[self enumerateChildNodesWithName:#"landscape" usingBlock:^(SKNode *node, BOOL *stop) {
if (node.position.x < 0 || node.position.y < 0) {
[node removeFromParent];
}else {
node.position = CGPointMake(node.position.x - 10, node.position.y);
}
}];
[self enumerateChildNodesWithName:#"logs" usingBlock:^(SKNode *node, BOOL *stop) {
if (node.position.x < 0 || node.position.y < 0) {
[node removeFromParent];
}else {
node.position = CGPointMake(node.position.x - 10, node.position.y);
}
if ([holly intersectsNode:node]) {
SKScene *capturedScene = [[WECapturedScene alloc] initWithSize:self.size];
SKTransition* transition = [SKTransition doorsOpenVerticalWithDuration:0.5];
[self.view presentScene:capturedScene transition:transition];
}
}];
[self enumerateChildNodesWithName:#"dogCatcher" usingBlock:^(SKNode *node, BOOL *stop) {
node.position = CGPointMake(node.position.x + 10, node.position.y);
}];
}
Here is the view controller:
#import "WEViewController.h"
#import "WEMyScene.h"
#import "WEMenuScene.h"
#implementation WEViewController
- (void)viewDidLoad
{
[super viewDidLoad];
// Configure the view.
SKView * skView = (SKView *)self.view;
skView.showsFPS = YES;
skView.showsNodeCount = YES;
// Create and configure the scene.
SKScene * scene = [WEMenuScene sceneWithSize:skView.bounds.size];
scene.scaleMode = SKSceneScaleModeAspectFill;
// Present the scene.
[skView presentScene:scene];
}
- (BOOL)shouldAutorotate
{
return YES;
}
- (NSUInteger)supportedInterfaceOrientations
{
if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPhone) {
return UIInterfaceOrientationMaskAllButUpsideDown;
} else {
return UIInterfaceOrientationMaskAll;
}
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Release any cached data, images, etc that aren't in use.
}
#end
#end
Has anyone figured out (natively) how to subclass SKNode to include multiple bodies connect by joints - for instance, a car?
There doesn't seem to be a way to add the sub class's joints to the parent scene's physicsWorld property.
Also, when trying to compile and run the object below, even without the joint, I get a BAD_EXC_ACCESS error.
Thank you #Smick for the initial vehicle code as posted here:Sprite Kit pin joints appear to have an incorrect anchor
Truck Class:
#import "Truck.h"
#implementation Truck
-(id)initWithPosition:(CGPoint)pos {
SKSpriteNode *carBody = [SKSpriteNode spriteNodeWithColor:[UIColor whiteColor] size:CGSizeMake(120, 8)];
carBody.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:carBody.size];
carBody.position = pos;
carBody.physicsBody.mass = 1.0;
SKSpriteNode *carTop = [SKSpriteNode spriteNodeWithColor:[UIColor whiteColor] size:CGSizeMake(50, 8)];
carTop.position = CGPointMake(230, 708);
carTop.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:carTop.size];
carTop.physicsBody.mass = 0;
SKPhysicsJointFixed *carBodyJoint = [SKPhysicsJointFixed jointWithBodyA:carBody.physicsBody
bodyB:carTop.physicsBody
anchor:CGPointMake(0, 0)];
return self;
}
+(Truck*)initWithPosition:(CGPoint)pos {
return [[self alloc] initWithPosition:pos];
}
#end
MyScene:
sorry for late post, but just hit this myself.
Physics joints dont work unless the nodes being attached have already been added to the SKScene's scene graph.
During the initWithPosition above, that's not the case.
Passing in a SKScene also didn't work for me, I suspect because the Vehicle node still hasn't been added to the scene graph.
You can still encapsulate your physics joints within the class, but you have to call another method after the
[self addChild:car]
Here's my refinement on what you already had:
Vehicle.h
#interface Vehicle : SKNode
#property (nonatomic) SKSpriteNode *leftWheel;
#property (nonatomic) SKSpriteNode *ctop;
-(id)initWithPosition:(CGPoint)pos;
-(void)initPhysics;
#end
Vehicle.m
//
#import "Vehicle.h"
#implementation Vehicle {
SKSpriteNode *chassis;
SKSpriteNode *rightWheel;
SKSpriteNode *leftShockPost;
SKSpriteNode *rightShockPost;
int wheelOffsetY;
CGFloat damping;
CGFloat frequency;
}
- (SKSpriteNode*) makeWheel
{
SKSpriteNode *wheel = [SKSpriteNode spriteNodeWithImageNamed:#"Wheel.png"];
// wheel.physicsBody = [SKPhysicsBody bodyWithCircleOfRadius:wheel.size.width/2];
return wheel;
}
-(id)initWithPosition:(CGPoint)pos {
if (self = [super init]) {
wheelOffsetY = 60;
damping = 1;
frequency = 4;
chassis = [SKSpriteNode spriteNodeWithColor:[UIColor whiteColor] size:CGSizeMake(120, 8)];
chassis.position = pos;
[self addChild:chassis];
_ctop = [SKSpriteNode spriteNodeWithColor:[UIColor greenColor] size:CGSizeMake(70, 16)];
_ctop.position = CGPointMake(chassis.position.x+20, chassis.position.y+12);
[self addChild:_ctop];
_leftWheel = [self makeWheel];
_leftWheel.position = CGPointMake(chassis.position.x - chassis.size.width / 2, chassis.position.y - wheelOffsetY); //Always set position before physicsBody
[self addChild:_leftWheel];
rightWheel = [self makeWheel];
rightWheel.position = CGPointMake(chassis.position.x + chassis.size.width / 2, chassis.position.y - wheelOffsetY);
[self addChild:rightWheel];
//------------- LEFT SUSPENSION ----------------------------------------------------------------------------------------------- //
leftShockPost = [SKSpriteNode spriteNodeWithColor:[UIColor blueColor] size:CGSizeMake(7, wheelOffsetY)];
leftShockPost.position = CGPointMake(chassis.position.x - chassis.size.width / 2, chassis.position.y - leftShockPost.size.height/2);
[self addChild:leftShockPost];
//------------- RIGHT SUSPENSION ----------------------------------------------------------------------------------------------- //
rightShockPost = [SKSpriteNode spriteNodeWithColor:[UIColor blueColor] size:CGSizeMake(7, wheelOffsetY)];
rightShockPost.position = CGPointMake(chassis.position.x + chassis.size.width / 2, chassis.position.y - rightShockPost.size.height/2);
[self addChild:rightShockPost];
}
return self;
}
-(void) initPhysics {
chassis.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:chassis.size];
_ctop.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:_ctop.size];
SKPhysicsJointFixed *cJoint = [SKPhysicsJointFixed jointWithBodyA:chassis.physicsBody
bodyB:_ctop.physicsBody
anchor:CGPointMake(_ctop.position.x, _ctop.position.y)];
_leftWheel.physicsBody = [SKPhysicsBody bodyWithCircleOfRadius:_leftWheel.size.width/2];
_leftWheel.physicsBody.allowsRotation = YES;
rightWheel.physicsBody = [SKPhysicsBody bodyWithCircleOfRadius:rightWheel.size.width/2];
rightWheel.physicsBody.allowsRotation = YES;
leftShockPost.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:leftShockPost.size];
SKPhysicsJointSliding *leftSlide = [SKPhysicsJointSliding jointWithBodyA:chassis.physicsBody
bodyB:leftShockPost.physicsBody
anchor:CGPointMake(leftShockPost.position.x, leftShockPost.position.y)
axis:CGVectorMake(0, 1)];
leftSlide.shouldEnableLimits = TRUE;
leftSlide.lowerDistanceLimit = 5;
leftSlide.upperDistanceLimit = wheelOffsetY;
SKPhysicsJointSpring *leftSpring = [SKPhysicsJointSpring jointWithBodyA:chassis.physicsBody bodyB:_leftWheel.physicsBody
anchorA:CGPointMake(chassis.position.x - chassis.size.width / 2, chassis.position.y)
anchorB:_leftWheel.position];
leftSpring.damping = damping;
leftSpring.frequency = frequency;
SKPhysicsJointPin *lPin = [SKPhysicsJointPin jointWithBodyA:leftShockPost.physicsBody bodyB:_leftWheel.physicsBody anchor:_leftWheel.position];
rightShockPost.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:rightShockPost.size];
SKPhysicsJointSliding *rightSlide = [SKPhysicsJointSliding jointWithBodyA:chassis.physicsBody
bodyB:rightShockPost.physicsBody
anchor:CGPointMake(rightShockPost.position.x, rightShockPost.position.y)
axis:CGVectorMake(0, 1)];
rightSlide.shouldEnableLimits = TRUE;
rightSlide.lowerDistanceLimit = 5;
rightSlide.upperDistanceLimit = wheelOffsetY;
SKPhysicsJointSpring *rightSpring = [SKPhysicsJointSpring jointWithBodyA:chassis.physicsBody bodyB:rightWheel.physicsBody
anchorA:CGPointMake(chassis.position.x + chassis.size.width / 2, chassis.position.y)
anchorB:rightWheel.position];
rightSpring.damping = damping;
rightSpring.frequency = frequency;
SKPhysicsJointPin *rPin = [SKPhysicsJointPin jointWithBodyA:rightShockPost.physicsBody bodyB:rightWheel.physicsBody anchor:rightWheel.position];
// Add all joints to the array.
// Add joints to scene's physics world
[self.scene.physicsWorld addJoint: cJoint];
[self.scene.physicsWorld addJoint: leftSlide];
[self.scene.physicsWorld addJoint: leftSpring];
[self.scene.physicsWorld addJoint: lPin];
[self.scene.physicsWorld addJoint: rightSlide];
[self.scene.physicsWorld addJoint: rightSpring];
[self.scene.physicsWorld addJoint: rPin];
}
#end
and call it from MyScene.m
_car = [[DMVehicle alloc] initWithPosition:location];
[self addChild:_car];
[_car initPhysics];
Hope that helps, I know it has helped me by working through it
So here's what I came up with.
My only issue with this is that it isn't completely self contained as joints must be added to the physics world outside of the class - simple enough as you'll see using two lines of code.
Editing my answer. The suspension requires the wheels to be attached to a sliding body versus attaching the wheels via the slide joint. Doing the former allows wheels to rotate. The latter does not.
Update: I've unmarked this as the answer. Reason being is that, while it runs fine on the simulator, I receive the following error when I attempt to run it on my iPad (running iOS7). When I remove my vehicle class and place one of the vehicle's components that use that UIColor method into my main scene, the error is not thrown.
UICachedDeviceWhiteColor addObject:]: unrecognized selector sent to instance 0x15e21360
2013-12-14 22:44:19.790 SKTestCase[1401:60b] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[UICachedDeviceWhiteColor addObject:]: unrecognized selector sent to instance
For some reason, I no longer receive the UICashed... error (yes, vehicle is still a class) Now I receive:
-[PKPhysicsJointWeld name]: unrecognized selector sent to instance 0x1464f810
2013-12-15 15:28:24.081 MTC[1747:60b] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[PKPhysicsJointWeld name]: unrecognized selector sent to instance 0x1464f810'
*** First throw call stack:
(0x30eaff53 0x3b5186af 0x30eb38e7 0x30eb21d3 0x30e01598 0x3352837d 0x335284d5 0x33527b97 0x33525ca5 0x87385 0x335064f5 0x87ccb 0x33620fe1 0x332aa24b 0x332a5a5b 0x332d4b7d 0x3369e39b 0x3369ca03 0x3369bc53 0x3369bbdb 0x3369bb73 0x33694681 0x3362703f 0x3369b8c1 0x3369b38d 0x3362c21d 0x33629763 0x33694a55 0x33691811 0x3368bd13 0x336266a7 0x336259a9 0x3368b4fd 0x35ab270d 0x35ab22f7 0x30e7a9e7 0x30e7a983 0x30e79157 0x30de3ce7 0x30de3acb 0x3368a799 0x33685a41 0x8a52d 0x3ba20ab7)
libc++abi.dylib: terminating with uncaught exception of type NSException
Vehicle.h:
#import <SpriteKit/SpriteKit.h>
#interface Vehicle : SKNode
#property (nonatomic,assign) NSMutableArray *joints;
#property (nonatomic) SKSpriteNode *leftWheel;
#property (nonatomic) SKSpriteNode *ctop;
-(id)initWithPosition:(CGPoint)pos;
#end
Vehicle.m
#import "Vehicle.h"
#implementation Vehicle
- (SKSpriteNode*) makeWheel
{
SKSpriteNode *wheel = [SKSpriteNode spriteNodeWithImageNamed:#"wheel.png"];
// wheel.physicsBody = [SKPhysicsBody bodyWithCircleOfRadius:wheel.size.width/2];
return wheel;
}
-(id)initWithPosition:(CGPoint)pos {
if (self = [super init]) {
_joints = [NSMutableArray array];
int wheelOffsetY = 60;
CGFloat damping = 1;
CGFloat frequency = 4;
SKSpriteNode *chassis = [SKSpriteNode spriteNodeWithColor:[UIColor whiteColor] size:CGSizeMake(120, 8)];
chassis.position = pos;
chassis.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:chassis.size];
[self addChild:chassis];
_ctop = [SKSpriteNode spriteNodeWithColor:[UIColor greenColor] size:CGSizeMake(70, 16)];
_ctop.position = CGPointMake(chassis.position.x+20, chassis.position.y+12);
_ctop.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:_ctop.size];
[self addChild:_ctop];
SKPhysicsJointFixed *cJoint = [SKPhysicsJointFixed jointWithBodyA:chassis.physicsBody
bodyB:_ctop.physicsBody
anchor:CGPointMake(_ctop.position.x, _ctop.position.y)];
_leftWheel = [self makeWheel];
_leftWheel.position = CGPointMake(chassis.position.x - chassis.size.width / 2, chassis.position.y - wheelOffsetY); //Always set position before physicsBody
_leftWheel.physicsBody = [SKPhysicsBody bodyWithCircleOfRadius:_leftWheel.size.width/2];
_leftWheel.physicsBody.allowsRotation = YES;
[self addChild:_leftWheel];
SKSpriteNode *rightWheel = [self makeWheel];
rightWheel.position = CGPointMake(chassis.position.x + chassis.size.width / 2, chassis.position.y - wheelOffsetY);
rightWheel.physicsBody = [SKPhysicsBody bodyWithCircleOfRadius:rightWheel.size.width/2];
rightWheel.physicsBody.allowsRotation = YES;
[self addChild:rightWheel];
//------------- LEFT SUSPENSION ----------------------------------------------------------------------------------------------- //
SKSpriteNode *leftShockPost = [SKSpriteNode spriteNodeWithColor:[UIColor blueColor] size:CGSizeMake(7, wheelOffsetY)];
leftShockPost.position = CGPointMake(chassis.position.x - chassis.size.width / 2, chassis.position.y - leftShockPost.size.height/2);
leftShockPost.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:leftShockPost.size];
[self addChild:leftShockPost];
SKPhysicsJointSliding *leftSlide = [SKPhysicsJointSliding jointWithBodyA:chassis.physicsBody
bodyB:leftShockPost.physicsBody
anchor:CGPointMake(leftShockPost.position.x, leftShockPost.position.y)
axis:CGVectorMake(0, 1)];
leftSlide.shouldEnableLimits = TRUE;
leftSlide.lowerDistanceLimit = 5;
leftSlide.upperDistanceLimit = wheelOffsetY;
SKPhysicsJointSpring *leftSpring = [SKPhysicsJointSpring jointWithBodyA:chassis.physicsBody bodyB:_leftWheel.physicsBody
anchorA:CGPointMake(chassis.position.x - chassis.size.width / 2, chassis.position.y)
anchorB:_leftWheel.position];
leftSpring.damping = damping;
leftSpring.frequency = frequency;
SKPhysicsJointPin *lPin = [SKPhysicsJointPin jointWithBodyA:leftShockPost.physicsBody bodyB:_leftWheel.physicsBody anchor:_leftWheel.position];
//------------- RIGHT SUSPENSION ----------------------------------------------------------------------------------------------- //
SKSpriteNode *rightShockPost = [SKSpriteNode spriteNodeWithColor:[UIColor blueColor] size:CGSizeMake(7, wheelOffsetY)];
rightShockPost.position = CGPointMake(chassis.position.x + chassis.size.width / 2, chassis.position.y - rightShockPost.size.height/2);
rightShockPost.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:rightShockPost.size];
[self addChild:rightShockPost];
SKPhysicsJointSliding *rightSlide = [SKPhysicsJointSliding jointWithBodyA:chassis.physicsBody
bodyB:rightShockPost.physicsBody
anchor:CGPointMake(rightShockPost.position.x, rightShockPost.position.y)
axis:CGVectorMake(0, 1)];
rightSlide.shouldEnableLimits = TRUE;
rightSlide.lowerDistanceLimit = 5;
rightSlide.upperDistanceLimit = wheelOffsetY;
SKPhysicsJointSpring *rightSpring = [SKPhysicsJointSpring jointWithBodyA:chassis.physicsBody bodyB:rightWheel.physicsBody
anchorA:CGPointMake(chassis.position.x + chassis.size.width / 2, chassis.position.y)
anchorB:rightWheel.position];
rightSpring.damping = damping;
rightSpring.frequency = frequency;
SKPhysicsJointPin *rPin = [SKPhysicsJointPin jointWithBodyA:rightShockPost.physicsBody bodyB:rightWheel.physicsBody anchor:rightWheel.position];
// Add all joints to the array.
[_joints addObject:cJoint];
[_joints addObject:leftSlide];
[_joints addObject:leftSpring];
[_joints addObject:lPin];
[_joints addObject:rightSlide];
[_joints addObject:rightSpring];
[_joints addObject:rPin];
}
return self;
}
#end
MyScene.m:
#import "MyScene.h"
#import "Vehicle.h"
#implementation MyScene {
Vehicle *car;
}
-(id)initWithSize:(CGSize)size {
if (self = [super initWithSize:size]) {
/* Setup your scene here */
self.physicsBody = [SKPhysicsBody bodyWithEdgeLoopFromRect:CGRectMake(0, 0, self.size.width, self.size.height)];
}
return self;
}
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
/* Called when a touch begins */
for (UITouch *touch in touches) {
CGPoint location = [touch locationInNode:self];
car = [[Vehicle alloc] initWithPosition:location];
[self addChild:car];
// Add joints to scene's physics world
for (SKPhysicsJoint *j in car.joints) {
[self.physicsWorld addJoint:j];
}
}
}
1) Adding joints: Why don't you just have the vehicle's init method takes an SKScene object? Then you can add the joint within that method. Otherwise, what you have done with the _joints array works, but seems less clean with the extra code needed there.
2) BAD_EXC_ACCESS: I got this as well when I was learning about joints. It went away when the nodes participating in the joint were added to SKScene and not some other sub nodes. The closest info in the Apple documentation that I can find is this: "Attach the physics bodies to a pair of SKNode objects in the scene." That doesn't specify whether this means directly to the SKScene, or to any node within the node tree in the SKScene.
I had the same issue, and this way works for me:
you will receive an Exc_bad_access if you try to add the joint(defined in the truck class)from your scene. You have to run
[self.scene.physicsWorld addJoint:joint]
in your Truck class.
However, you can't add the
[self.scene.physicsWorld addJoint:joint]
into your init method of the Truck, because the Truck has not been added into your scene when running the Truck's init method in your scene.
You'll have to write another method (let's say addJointsIntoScene) in your Truck class to run
[self.scene.physicsWorld addJoint:joint].
After adding your Truck to your scene, run the 'addJointsIntoScene' method to add the joint.
for example,
Truck.m
-(instancetype)initWithPosition:(CGPoint) triggerPosition{
....
joint = .....
....
}
//and another method
-(void)addJointsIntoScene{
[self.scene.physicsWorld addJoint:joint];enter code here
}
MyScene.m
Truck *truck = [[Truck alloc]initWithPosition:triggerPosition];
[self addChild:truck];
[truck addJointsIntoScene];
So I have it set up so when the characters health is < 100 (for testing purposes) it stop the scene and goes to the game over scene.
if (playerDataManager.playerHealth < 100) {
[[CCDirector sharedDirector] replaceScene:[CCTransitionFade transitionWithDuration:3 scene: [GameLogic scene]]];
}
However when the players health drops below 100, it goes to the new scene, but the FPS drops dramatically from 60 to 5.
I get a list of OpenGL error 0x0503 in -[EAGLView swapBuffers] then it stays frozen like that for about 40 seconds, then the FPS unfreeze and goes back out to 60 and I get a list of 2012-07-13 10:37:50.234 Tilegame[93513:10a03] cocos2d: removeChildByTag: child not found!
Then I can continue with the app like normal, going back to the main menu, starting a new game, then recreate the error.
#import "HelloWorldLayer.h"
#import "Menu.h"
#import "SimpleAudioEngine.h"
#import "LogCabinMap.h"
#import "LogShedMap.h"
#import "SaveData.h"
#import "pauseM.h"
#import "Player.h"
#import "GameLogic.h"
CCSprite *player;
CGPoint newPos;
int joyDegrees;
// HelloWorldLayer implementation
#implementation HelloWorldLayer
#synthesize tileMap = _tileMap;
#synthesize background = _background;
#synthesize buildings = _buildings;
#synthesize meta = _meta;
#synthesize player = _player;
#synthesize foreground = _foreground;
#synthesize numCollected = _numCollected;
#synthesize hud = _hud;
-(void) animateEnemy:(CCSprite*)enemy {
//speed of the enemy
ccTime actualDuration = .2;
id actionMove;
int distanceFromPlayer = ccpDistance(player.position, enemy.position);
if (distanceFromPlayer < 200) { //Check whether enemy can "see" Ninja before moving towards him.
//rotate to face the player
CGPoint diff = ccpSub(player.position,enemy.position);
float angleRadians = atanf((float)diff.y / (float)diff.x);
float angleDegrees = CC_RADIANS_TO_DEGREES(angleRadians);
float cocosAngle = -1 * angleDegrees;
if (diff.x < 0) {
cocosAngle += 180;
}
enemy.rotation = cocosAngle;
actionMove = [CCMoveBy actionWithDuration:actualDuration
position:ccpMult(ccpNormalize(ccpSub(player.position,enemy.position)),10)];
} else {
actionMove = [CCMoveBy actionWithDuration:actualDuration
position:ccpMult(ccpNormalize(ccpSub(player.position,enemy.position)),0)];
}
id actionMoveDone = [CCCallFuncN actionWithTarget:self
selector:#selector(enemyMoveFinished:)];
[enemy runAction:[CCSequence actions:actionMove, actionMoveDone, nil]];
}
// callback. starts another iteration of enemy movement.
- (void) enemyMoveFinished:(id)sender {
CCSprite *enemy = (CCSprite *)sender;
[self animateEnemy: enemy];
}
-(void)addEnemyAtX:(int)x y:(int)y {
CCSprite *enemy = [CCSprite spriteWithFile:#"enemy1.png"];
enemy.position = ccp(x, y);
[self addChild:enemy];
[self animateEnemy:enemy];
}
-(void)setViewpointCenter:(CGPoint) position {
CGSize winSize = [[CCDirector sharedDirector] winSize];
int x = MAX(position.x, winSize.width / 2);
int y = MAX(position.y, winSize.height / 2);
x = MIN(x, (_tileMap.mapSize.width * _tileMap.tileSize.width)
- winSize.width / 2);
y = MIN(y, (_tileMap.mapSize.height * _tileMap.tileSize.height)
- winSize.height/2);
CGPoint actualPosition = ccp(x, y);
CGPoint centerOfView = ccp(winSize.width/2, winSize.height/2);
CGPoint viewPoint = ccpSub(centerOfView, actualPosition);
self.position = viewPoint;
}
-(id) init
{
if( (self=[super init] )) {
[[SimpleAudioEngine sharedEngine] preloadEffect:#"pickup.caf"];
[[SimpleAudioEngine sharedEngine] preloadEffect:#"hit.caf"];
[[SimpleAudioEngine sharedEngine] preloadEffect:#"move.caf"];
//[[SimpleAudioEngine sharedEngine] playBackgroundMusic:#"TileMap.caf"];
self.isTouchEnabled = YES;
self.tileMap = [CCTMXTiledMap tiledMapWithTMXFile:#"TileMap.tmx"];
self.background = [_tileMap layerNamed:#"Background"];
self.foreground = [_tileMap layerNamed:#"Foreground"];
self.buildings = [_tileMap layerNamed:#"Buildings"];
self.meta = [_tileMap layerNamed:#"Meta"];
_meta.visible = NO;
CCTMXObjectGroup *objects = [_tileMap objectGroupNamed:#"Objects"];
NSAssert(objects != nil, #"'Objects' object group not found");
//NSMutableDictionary * padPoints = [objects objectNamed:#"pad"];
NSMutableDictionary * padPoints;
SaveData * SaveDataManager = [SaveData sharedSaveDataManager];
for (int i = 0; i < 20; i ++) {
for (padPoints in [objects objects]) {
if ([[SaveDataManager.padArray objectAtIndex: i] intValue] == 1 ){
if ([[padPoints valueForKey:#"pad"] intValue] == i){
int x = [[padPoints valueForKey:#"x"] intValue];
int y = [[padPoints valueForKey:#"y"] intValue];
self.player = [CCSprite spriteWithFile:#"man.png"];
_player.position = ccp(x+16,y+16);
//[self addChild:_player];
}
}
}
}
// iterate through objects, finding all enemy spawn points
// create an enemy for each one
NSMutableDictionary * spawnPoints;
for (spawnPoints in [objects objects]) {
if ([[spawnPoints valueForKey:#"Enemy"] intValue] == 2){
int x = [[spawnPoints valueForKey:#"x"] intValue];
int y = [[spawnPoints valueForKey:#"y"] intValue];
[self addEnemyAtX:x+=16 y:y+=64];
}
}
player = [CCSprite spriteWithFile:#"man.png"];
player.position= _player.position;
[_tileMap addChild:player z: 0];
// [self addChild:player z:10];
[self setViewpointCenter:player.position];
[self addChild:_tileMap z:-1];
[self scheduleUpdate];
}
return self;
}
- (CGPoint)tileCoordForPosition:(CGPoint)position {
int x = position.x / _tileMap.tileSize.width;
int y = ((_tileMap.mapSize.height * _tileMap.tileSize.height) - position.y) / _tileMap.tileSize.height;
return ccp(x, y);
}
-(void)setPlayerPosition:(CGPoint)position {
Player * playerDataManager = [Player playerSaveDataManager];
CGPoint tileCoord = [self tileCoordForPosition:position];
int tileGid = [_meta tileGIDAt:tileCoord];
int x = player.position.x;
int y = player.position.y;
if (tileGid) {
NSDictionary *properties = [_tileMap propertiesForGID:tileGid];
if (properties) {
NSString *collision = [properties valueForKey:#"Collidable"];
if (collision && [collision compare:#"True"] == NSOrderedSame) {
//[[SimpleAudioEngine sharedEngine] playEffect:#"hit.caf"];
if (joyDegrees > 45 && joyDegrees < 135){
player.position = ccp(x,y-1);
}
if (joyDegrees > 135 && joyDegrees < 225){
player.position = ccp(x+1,y);
}
if (joyDegrees > 225 && joyDegrees < 315){
player.position = ccp(x,y+1);
}
if ((joyDegrees > 315 && joyDegrees < 360) || (joyDegrees > -1 && joyDegrees < 45)){
player.position = ccp(x-1,y);
}
return;
}
NSString *collectable = [properties valueForKey:#"Collectable"];
if (collectable && [collectable compare:#"True"] == NSOrderedSame) {
[[SimpleAudioEngine sharedEngine] playEffect:#"pickup.caf"];
[_meta removeTileAt:tileCoord];
[_foreground removeTileAt:tileCoord];
self.numCollected += 1;
[_hud numCollectedChanged:_numCollected];
playerDataManager.playerHealth -= 10;
}
NSString *Gate = [properties valueForKey:#"Gate"];
if (Gate && [Gate compare:#"1"] == NSOrderedSame) {
SaveData * SaveDataManager = [SaveData sharedSaveDataManager];
//[SaveDataManager.padArray removeAllObjects];
for (int i = 0; i < 20; i ++) {
[SaveDataManager.padArray replaceObjectAtIndex:i withObject:[NSNumber numberWithInt:0]];
}
[SaveDataManager.padArray replaceObjectAtIndex:1 withObject:[NSNumber numberWithInt:1]];
//[[CCDirector sharedDirector] replaceScene:[LogCabinMap scene]];
[[CCDirector sharedDirector] pushScene:[LogCabinMap scene]];
}
if (Gate && [Gate compare:#"2"] == NSOrderedSame) {
SaveData * SaveDataManager = [SaveData sharedSaveDataManager];
//[SaveDataManager.padArray removeAllObjects];
for (int i = 0; i < 20; i ++) {
[SaveDataManager.padArray replaceObjectAtIndex:i withObject:[NSNumber numberWithInt:0]];
}
[SaveDataManager.padArray replaceObjectAtIndex:1 withObject:[NSNumber numberWithInt:1]];
//[[CCDirector sharedDirector] replaceScene:[LogShedMap scene]];
[[CCDirector sharedDirector] pushScene:[LogShedMap scene]];
}
}
}
//[[SimpleAudioEngine sharedEngine] playEffect:#"move.caf"];
player.position = position;
}
-(BOOL) ccTouchBegan:(UITouch *)touch withEvent:(UIEvent *)event
{
return YES;
}
-(void) update:(ccTime)deltaTime {
[self setPlayerPosition:newPos];
[self setViewpointCenter:player.position];
}
// on "dealloc" you need to release all your retained objects
- (void) dealloc
{
// in case you have something to dealloc, do it in this method
// in this particular example nothing needs to be released.
// cocos2d will automatically release all the children (Label)
self.tileMap = nil;
self.background = nil;
self.foreground = nil;
self.buildings = nil;
self.meta =nil;
self.player = nil;
player = nil;
self.hud = nil;
// don't forget to call "super dealloc"
[super dealloc];
}
#end
#implementation HelloWorldHud
#synthesize background;
#synthesize background2;
#synthesize health;
#synthesize baseScaleFactor;
+(CCScene *) scene
{
// 'scene' is an autorelease object.
CCScene *scene = [CCScene node];
// 'layer' is an autorelease object.
HelloWorldHud *layer = [HelloWorldHud node];
// add layer as a child to scene
[scene addChild: layer z:2];
HelloWorldLayer *hud = [HelloWorldLayer node];
[scene addChild: hud z:1];
//layer.hud = hud;
// return the scene
return scene;
}
-(void)initJoystick {
SneakyJoystickSkinnedBase *joystickBase = [[[SneakyJoystickSkinnedBase alloc] init] autorelease];
joystickBase.backgroundSprite = [CCSprite spriteWithFile:#"JoyB.png"];
joystickBase.thumbSprite = [CCSprite spriteWithFile:#"JoyS.png"];
joystickBase.joystick = [[SneakyJoystick alloc] initWithRect: CGRectMake(0, 0, 128, 128)];
joystickBase.position = ccp(55, 55);
[self addChild:joystickBase];
leftJoystick = [[joystickBase.joystick retain] autorelease];
}
-(void) update:(ccTime)deltaTime {
Player *playerDataManager = [Player playerSaveDataManager];
CGPoint scaledVelocity = ccpMult(leftJoystick.velocity, 100);
CGPoint newPosition = ccp(player.position.x + scaledVelocity.x * deltaTime, player.position.y + scaledVelocity.y * deltaTime);
if (leftJoystick.velocity.x == 0 && leftJoystick.velocity.y == 0 ){
if (!playerDataManager.standStill) {
[player stopAllActions];
playerDataManager.walkUp = FALSE;
playerDataManager.walkDown = FALSE;
playerDataManager.walkRight = FALSE;
playerDataManager.walkLeft = FALSE;
playerDataManager.standStill = TRUE;
[player runAction:playerDataManager.standAction];
}
}
if (leftJoystick.degrees > 45 && leftJoystick.degrees < 135){
if (!playerDataManager.walkUp) {
[player stopAllActions];
playerDataManager.walkUp = TRUE;
playerDataManager.walkDown = FALSE;
playerDataManager.walkRight = FALSE;
playerDataManager.walkLeft = FALSE;
playerDataManager.standStill = FALSE;
[player runAction:playerDataManager.walkUpAction];
}
}
if (leftJoystick.degrees > 135 && leftJoystick.degrees < 225){
if (!playerDataManager.walkLeft) {
[player stopAllActions];
playerDataManager.walkUp = FALSE;
playerDataManager.walkDown = FALSE;
playerDataManager.walkRight = FALSE;
playerDataManager.walkLeft = TRUE;
playerDataManager.standStill = FALSE;
[player runAction:playerDataManager.walkLeftAction];
}
}
if (leftJoystick.degrees > 225 && leftJoystick.degrees < 315){
if (!playerDataManager.walkDown) {
[player stopAllActions];
playerDataManager.walkUp = FALSE;
playerDataManager.walkDown = TRUE;
playerDataManager.walkRight = FALSE;
playerDataManager.walkLeft = FALSE;
playerDataManager.standStill = FALSE;
[player runAction:playerDataManager.walkDownAction];
}
}
if (((leftJoystick.degrees > 315 && leftJoystick.degrees < 360) && (leftJoystick.velocity.x != 0 && leftJoystick.velocity.y != 0 )) || ((leftJoystick.degrees > -1 && leftJoystick.degrees < 45) && (leftJoystick.velocity.x != 0 && leftJoystick.velocity.y != 0 ))){
if (!playerDataManager.walkRight) {
[player stopAllActions];
playerDataManager.walkUp = FALSE;
playerDataManager.walkDown = FALSE;
playerDataManager.walkRight = TRUE;
playerDataManager.walkLeft = FALSE;
playerDataManager.standStill = FALSE;
[player runAction:playerDataManager.walkRightAction];
}
}
float scaleFactor = playerDataManager.playerHealth/baseScaleFactor;
health.scaleX = playerDataManager.playerHealth/1;
newPos = newPosition;
joyDegrees = leftJoystick.degrees;
if (playerDataManager.playerHealth < 100) {
[[CCDirector sharedDirector] replaceScene:[CCTransitionFade transitionWithDuration:3 scene: [GameLogic scene]]];
[[CCDirector sharedDirector] replaceScene: [GameLogic scene]];
}
}
-(void) scroll:(ccTime)dt
{
//move 30*dt px vertically
if (background.position.y<background2.position.y){
background.position = ccp(background.contentSize.width/2, background.position.y - 225*dt);
background2.position = ccp(background2.contentSize.width/2, background.position.y+background.contentSize.height);
}else{
background2.position = ccp(background2.contentSize.width/2, background2.position.y- 225*dt);
background.position = ccp(background.contentSize.width/2, background2.position.y+background2.contentSize.height);
}
//reset offscreen position
if (background.position.y <-background.contentSize.height/2)
{
background.position = ccp(background.contentSize.height/2,background2.position.y+background2.contentSize.height);
}else if (background2.position.y < -background2.contentSize.height/2)
{
background2.position = ccp(background2.contentSize.height/2, background.position.y+background.contentSize.height);
}
}
-(id) init
{
if ((self = [super init])) {
CGSize size = [CCDirector sharedDirector].winSize;
background = [CCSprite spriteWithFile:#"rain.png"];
background2 = [CCSprite spriteWithFile:#"rain.png"];
[background.texture setAliasTexParameters];
[background2.texture setAliasTexParameters];
//position background sprites
background.position = ccp(background.contentSize.height/2,background.contentSize.width/2);
background2.position = ccp(size.width,0);
//schedule to move background sprites
//[self schedule:#selector(scroll:)];
//adding them to the main layer
//[self addChild:background z:-1];
//[self addChild:background2 z:-1];
[[CCSpriteFrameCache sharedSpriteFrameCache] addSpriteFramesWithFile:#"GUI.plist"];
CCSpriteBatchNode *GUISpriteSheet = [CCSpriteBatchNode batchNodeWithFile:#"GUI.png"];
[self addChild:GUISpriteSheet];
CCSprite * healthBar = [CCSprite spriteWithSpriteFrameName:#"bar.png"];
CCSprite * cap = [CCSprite spriteWithSpriteFrameName:#"cap.png"];
CCSprite * endCap = [CCSprite spriteWithSpriteFrameName:#"endcap.png"];
health = [CCSprite spriteWithSpriteFrameName:#"red.png"];
healthBar.anchorPoint = ccp(0,1);
health.anchorPoint = ccp(0,1);
cap.anchorPoint = ccp(0,1);
endCap.anchorPoint = ccp(0,1);
healthBar.position = ccp(1 , size.height);
healthBar.scaleX = 25;
cap.position = ccp(0 , size.height);
int width = [healthBar boundingBox].size.width;
endCap.position = ccp(width , size.height);
health.position = ccp(1, size.height-2);
baseScaleFactor = width;
health.scaleX = baseScaleFactor;
[self addChild:healthBar];
[self addChild:cap];
[self addChild:endCap];
[self addChild:health];
CGSize winSize = [[CCDirector sharedDirector] winSize];
label = [CCLabelTTF labelWithString:#"0" dimensions:CGSizeMake(50, 20)
alignment:UITextAlignmentRight fontName:#"Verdana-Bold"
fontSize:18.0];
label.color = ccc3(0,0,0);
int margin = 10;
label.position = ccp(winSize.width - (label.contentSize.width/2)
- margin, label.contentSize.height/2 + margin);
[self addChild:label];
CCMenuItemFont * pause = [CCMenuItemFont itemFromString:#"Pause" target:self selector:#selector(pause:)];
CCMenu *menu = [CCMenu menuWithItems: pause, nil];
pause.position = ccp(206,142);
[self addChild:menu];
CCSprite *pix = [CCSprite spriteWithFile:#"pix.png"];
pix.position = ccp(size.width/2, size.height/2);
//pix.scale = 50000;
[self addChild:pix z:1];
//[pix runAction:[CCTintTo actionWithDuration:10 red:255 green:0 blue:0]];
//[pix runAction:[CCScaleTo actionWithDuration:15 scale:500]];
pix.color = ccc3(255, 255, 255);
[self scheduleUpdate];
[self initJoystick];
}
return self;
}
- (void)numCollectedChanged:(int)numCollected {
[label setString:[NSString stringWithFormat:#"%d", numCollected]];
// [label setString:[NSString stringWithFormat:#"%d", score]];
}
- (void) pause: (id) sender
{
[[CCDirector sharedDirector] pushScene:[pauseM scene]];
}
- (void) dealloc
{
self.background = nil;
self.background2 = nil;
self.health = nil;
self.meta =nil;
player = nil;
// don't forget to call "super dealloc"
[super dealloc];
}
#end
Above is the .m scene that is running when the problem occurs and below is the GameLogic.m
#import "GameLogic.h"
#import "Player.h"
#import "Menu.h"
#implementation GameLogic
+(id) scene
{
CCScene *scene = [CCScene node];
GameLogic *layer = [GameLogic node];
[scene addChild: layer];
return scene;
}
+(id) gameLogicSaveDataManager {
static id gameLogicSaveDataManager = nil;
if (gameLogicSaveDataManager == nil) {
gameLogicSaveDataManager = [[self alloc] init];
}
return gameLogicSaveDataManager;
}
-(id) init
{
if( (self=[super init] )) {
CCSprite *bg = [CCSprite spriteWithFile:#"bg.jpg"];
bg.anchorPoint = ccp(0,0);
id fadeIn = [CCFadeIn actionWithDuration:3];
[self addChild:bg];
[bg runAction: fadeIn];
CCLayer *menuLayer = [[[CCLayer alloc] init] autorelease];
[self addChild:menuLayer];
CCMenuItemImage *home = [CCMenuItemImage
itemFromNormalImage:#"bg.jpg"
selectedImage:#"bg.jpg"
target:self
selector:#selector(home:)];
CCMenu *menu = [CCMenu menuWithItems: home, nil];
home.position = ccp(0,0);
[menuLayer addChild: menu];
}
return self;
}
- (void) home: (id) sender
{
[[CCDirector sharedDirector] replaceScene:[Menu scene]];
}
- (void) dealloc
{
[super dealloc];
}
#end
OpenGL error 0x503 means GL_STACK_OVERFLOW, it means you are pushing too many things onto the opengl stack.
I see several instances of pushScene in your code, but no instances of pop anything anywhere. You cannot just keep pushing things indefinitely without popping them, or you will get this error.
We need to what is currently running in your scene, how it has been allocated and how it is released. We also need to know the same information for the new loaded scene GameLogic. Edit your question and add these data.