I am stuck on this for several hours now which seems like a very simple task. I have an SKSpriteNode call Ball which is declared below:
-(instancetype) initWithType:(BallType) ballType
{
if(ballType == UserBall) {
self = [super initWithImageNamed:USER_BALL_IMAGE];
self.physicsBody.categoryBitMask = BBPhysicsCategoryUserBall;
self.physicsBody.contactTestBitMask = BBPhysicsCategoryRedBall | BBPhysicsCategoryWorld;
self.physicsBody.collisionBitMask = 0;
}
// setup physical aspects of the ball
self.physicsBody = [SKPhysicsBody bodyWithCircleOfRadius:self.size.width/2];
self.physicsBody.friction = 0.0f;
self.physicsBody.dynamic = YES;
return self;
}
I create another SKSpriteNote "redBall" as below:
SKSpriteNode *redBall = [[SKSpriteNode alloc] initWithImageNamed:RED_BALL_IMAGE];
redBall.physicsBody.categoryBitMask = BBPhysicsCategoryRedBall;
redBall.physicsBody.contactTestBitMask = BBPhysicsCategoryUserBall;
redBall.physicsBody = [SKPhysicsBody bodyWithCircleOfRadius:redBall.size.width/2];
redBall.physicsBody.friction = 0.0f;
redBall.position = CGPointMake(self.size.width/2 , self.size.height/4);
[self addChild:redBall];
[redBall.physicsBody applyImpulse:CGVectorMake(0.0, 0.5)];
My GameScene inherits from SKScene and implements the SKPhysicsContactDelegate protocol. I assign the contactDelegate as follows:
-(void) setupPhysicsWorld {
self.physicsBody = [SKPhysicsBody bodyWithEdgeLoopFromRect:self.frame];
self.physicsWorld.gravity = CGVectorMake(0.0f, 0.0f);
self.physicsBody.friction = 0.0f;
self.physicsBody.categoryBitMask = BBPhysicsCategoryWorld;
self.physicsWorld.contactDelegate = self;
}
But for some reason the didBeginContact is NEVER CALLED!!! I am going crazy as why it is not being called?
-(instancetype) initWithType:(BallType) ballType
{
if(ballType == UserBall) {
self = [super initWithImageNamed:USER_BALL_IMAGE];
self.physicsBody.categoryBitMask = BBPhysicsCategoryUserBall;
self.physicsBody.contactTestBitMask = BBPhysicsCategoryWorld;
self.physicsBody.collisionBitMask = 0;
}
// setup physical aspects of the ball
self.physicsBody = [SKPhysicsBody bodyWithCircleOfRadius:self.size.width/2];
self.physicsBody.friction = 0.0f;
self.physicsBody.dynamic = YES;
return self;
}
SKSpriteNode *redBall = [[SKSpriteNode alloc] initWithImageNamed:RED_BALL_IMAGE];
redBall.physicsBody.categoryBitMask = BBPhysicsCategoryRedBall;
redBall.physicsBody.contactTestBitMask = BBPhysicsCategoryUserBall;
redBall.physicsBody = [SKPhysicsBody bodyWithCircleOfRadius:redBall.size.width/2];
redBall.physicsBody.friction = 0.0f;
redBall.position = CGPointMake(self.size.width/2 , self.size.height/4);
[self addChild:redBall];
[redBall.physicsBody applyImpulse:CGVectorMake(0.0, 0.5)];
you are setting redBall.physicsBody.contactTestBitMask twice
Related
I'm new to sprite kit and game physics in general. I want my character to stand up upright whenever he falls over or knocked down. A bit like a floor-mounted punch bag. Here's my current code:
#import "MyScene.h"
#interface MyScene () <SKPhysicsContactDelegate> {
SKSpriteNode *_body;
SKSpriteNode *_leg1;
SKSpriteNode *_leg2;
SKSpriteNode *_foot1;
SKSpriteNode *_foot2;
}
#end
#implementation MyScene
-(id)initWithSize:(CGSize)size {
if (self = [super initWithSize:size]) {
//self.backgroundColor = [SKColor greenColor];
self.physicsWorld.gravity = CGVectorMake(0, -2.0);
self.physicsWorld.contactDelegate = self;
self.physicsBody = [SKPhysicsBody bodyWithEdgeLoopFromRect:self.frame];
SKSpriteNode *button = [SKSpriteNode spriteNodeWithColor:[SKColor redColor] size:CGSizeMake(50, 50)];
button.position = CGPointMake(40, 40);
button.zPosition = 10;
button.name = #"button";
[self addChild: button];
[self createCharacter];
}
return self;
}
-(void)createCharacter {
// Add sprites
_body = [SKSpriteNode spriteNodeWithColor:[SKColor purpleColor] size:CGSizeMake(40, 60)];
_body.position = CGPointMake(CGRectGetMidX(self.frame), CGRectGetMidY(self.frame));
[self addChild: _body];
_leg1 = [SKSpriteNode spriteNodeWithColor:[SKColor purpleColor] size:CGSizeMake(14, 60)];
_leg1.position = CGPointMake(_body.position.x+20-7, _body.position.y-65);
[self addChild:_leg1];
_foot1 = [SKSpriteNode spriteNodeWithColor:[SKColor purpleColor] size:CGSizeMake(20, 10)];
_foot1.position = CGPointMake(_leg1.position.x-2.5, _leg1.position.y-40);
[self addChild:_foot1];
_leg2 = [SKSpriteNode spriteNodeWithColor:[SKColor purpleColor] size:CGSizeMake(14, 60)];
_leg2.position = CGPointMake(_body.position.x-20+7, _body.position.y-65);
[self addChild:_leg2];
_foot2 = [SKSpriteNode spriteNodeWithColor:[SKColor purpleColor] size:CGSizeMake(20, 10)];
_foot2.position = CGPointMake(_leg2.position.x-2.5, _leg2.position.y-40);
[self addChild:_foot2];
// Add physics bodies to sprites
_body.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:_body.size];
_leg1.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:_leg1.size];
_foot1.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:_foot1.size];
_foot1.physicsBody.mass = 1;
_leg2.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:_leg2.size];
_foot2.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:_foot2.size];
_foot2.physicsBody.mass = 0.5;
// Add joints
SKPhysicsJoint *hipJoint = [SKPhysicsJointFixed jointWithBodyA:_body.physicsBody bodyB:_leg1.physicsBody anchor:_leg1.position];
SKPhysicsJoint *ankleJoint = [SKPhysicsJointFixed jointWithBodyA:_leg1.physicsBody bodyB:_foot1.physicsBody anchor:_foot1.position];
SKPhysicsJointPin *hipJoint2 = [SKPhysicsJointPin jointWithBodyA:_body.physicsBody bodyB:_leg2.physicsBody anchor:CGPointMake(_leg2.position.x, CGRectGetMaxY(_leg2.frame))];
[hipJoint2 setShouldEnableLimits:YES];
[hipJoint2 setLowerAngleLimit:-M_PI_2];
[hipJoint2 setUpperAngleLimit:0.0];
SKPhysicsJoint *ankleJoint2 = [SKPhysicsJointFixed jointWithBodyA:_leg2.physicsBody bodyB:_foot2.physicsBody anchor:_foot2.position];
[self.scene.physicsWorld addJoint:hipJoint];
[self.scene.physicsWorld addJoint:ankleJoint];
[self.scene.physicsWorld addJoint:hipJoint2];
[self.scene.physicsWorld addJoint:ankleJoint2];
}
-(void)characterJump {
CGFloat radianFactor = 0.0174532925;
CGFloat rotationInDegrees = _body.zRotation / radianFactor;
CGFloat newRotationDegrees = rotationInDegrees + 90;
CGFloat newRotationRadians = newRotationDegrees * radianFactor;
CGFloat r = 500;
CGFloat dx = r * cos(newRotationRadians);
CGFloat dy = r * sin(newRotationRadians);
[_body.physicsBody applyImpulse:CGVectorMake(dx, dy)];
NSLog(#"leg2 rotation: %f", _foot2.zRotation / radianFactor);
}
-(void)characterKick {
NSLog(#"Kick..");
}
-(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:#"button"]) {
[self characterJump];
[self characterKick];
}
}
-(void)update:(CFTimeInterval)currentTime {
}
#end
Run the code and tap the button to make him jump and eventually fall over. Also, the joint limits don't work as it breaks through the limits sometimes.
Help would be really appreciated.
I resolved this issue by checking the _body SKSpriteNode's 'y' position in the scene's update method. If the 'y' position was below a certain limit, I applied an impulse to the body's physicsBody from below to stand it up again.
This worked as required/desired.
-(void)update:(CFTimeInterval)currentTime {
if(_body.position.y < 30) {
[self upOnYourFeet];
}
}
-(void)upOnYourFeet {
[_body.physicsBody applyImpulse:CGVectorMake(0, 80)];
}
I am creating a game where a ball is suppose to bounce off from platforms. I have set up physics properties for the ball and the platform(platform only attains physics property when it's below the ball). My problem is: the ball is not bouncing (I have applied impulse in didbegincontact method) when the ball makes contact with the platform, it however detects contact.
Here is my didBeginContact Code:
- (void) didBeginContact:(SKPhysicsContact *)contact {
SKSpriteNode *firstNode, *secondNode;
firstNode = (SKSpriteNode*) contact.bodyA.node;
secondNode = (SKSpriteNode*) contact.bodyB.node;
if ((contact.bodyA.categoryBitMask == ballCategory) && (contact.bodyB.categoryBitMask == solidPlatformCategory)) {
NSLog(#"Platform Hit");
CGPoint contactPoint = contact.contactPoint;
[_ball.physicsBody applyImpulse:CGVectorMake(0, 4) atPoint:contactPoint];
}
}
///// Here is the code for SKSpriteNode Ball
- (void) addBall {
_myBall = [SKSpriteNode spriteNodeWithImageNamed:#"ball.png"];
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
_myBall.scale = 0.4;
} else {
_myBall.scale = 0.3;
}
_ball.position = CGPointMake(self.frame.size.width/2, _solidPlatform.position.y + 2.5*_ball.size.height);
_ball.zPosition = 2;
_ball.name = #"doodle";
_ball.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:_myDoodle.frame.size];
_ball.physicsBody.mass = 1.0;
_ball.physicsBody.restitution = 0.8;
_ball.physicsBody.dynamic = YES;
_ball.physicsBody.allowsRotation = NO;
_ball.physicsBody.usesPreciseCollisionDetection = YES;
_ball.physicsBody.categoryBitMask = ballCategory;
_ball.physicsBody.collisionBitMask = solidPlatformCategory;
_ball.physicsBody.contactTestBitMask = solidPlatformCategory;
//SKAction *moveUpAction = [SKAction moveByX:0.0 y:8*numberOfPlatforms duration:0.5];
[self addChild:_ball];
}
////Platform has been defined as (not a complete code):
_solidPlatform7.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:_solidPlatform7.frame.size];
_solidPlatform7.physicsBody.dynamic = NO;
_solidPlatform7.physicsBody.affectedByGravity = NO;
_solidPlatform7.physicsBody.usesPreciseCollisionDetection = YES;
_solidPlatform7.physicsBody.categoryBitMask = solidPlatformCategory;
PS: I am not getting any collusion detection if I define platform as bodyWithEdgeFromRect
difficult to answer without seeing some code, but I'll try:
If the ball does not bounce at all, check the restitution property. Higher values provide a higher "bounciness":
ball.physicsBody.restitution=0.8;
If you want the ball to bounce endless between bottom and ceiling you can invert the gravity after each collision:
self.physicsWorld.gravity = CGVectorMake(0, self.physicsWorld.gravity.dy * (-1));
Hope that helps. If not, please share some code.
I've tried your code. With some smaller changes it works:
- (void) addBall {
// Bottom platforms
for (int i=0; i<10; i++) {
SKSpriteNode *mySprite = [SKSpriteNode spriteNodeWithColor:[UIColor redColor] size:CGSizeMake(40, 20)];
CGPoint location = CGPointMake(i*40+60, 10);
//mySprite.size =CGSizeMake(20, 40);
mySprite.position=location;
mySprite.physicsBody=[SKPhysicsBody bodyWithRectangleOfSize:mySprite.size];
mySprite.physicsBody.dynamic=false;
mySprite.physicsBody.categoryBitMask=solidPlatformCategory;
[self addChild:mySprite];
}
_ball = [SKSpriteNode spriteNodeWithImageNamed:#"ball.png"];
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
_ball.scale = 0.4;
} else {
_ball.scale = 0.3;
}
_ball.position = CGPointMake(self.frame.size.width/2, self.frame.size.width/2);
_ball.zPosition = 2;
_ball.name = #"doodle";
//_ball.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:_myDoodle.frame.size];
_ball.physicsBody=[SKPhysicsBody bodyWithCircleOfRadius:_ball.size.width/2];
_ball.physicsBody.mass = 1.0;
_ball.physicsBody.restitution = 1;
_ball.physicsBody.dynamic = YES;
_ball.physicsBody.allowsRotation = NO;
_ball.physicsBody.usesPreciseCollisionDetection = YES;
_ball.physicsBody.categoryBitMask = ballCategory;
_ball.physicsBody.collisionBitMask = solidPlatformCategory;
_ball.physicsBody.contactTestBitMask = solidPlatformCategory;
//SKAction *moveUpAction = [SKAction moveByX:0.0 y:8*numberOfPlatforms duration:0.5];
[self addChild:_ball];
}
I have very simple code:
-(id)initWithSize:(CGSize)size {
if (self = [super initWithSize:size]) {
/* Setup your scene here */
self.backgroundColor = [SKColor whiteColor];
self.anchorPoint = CGPointMake(0.5, 0.5);
self.physicsWorld.gravity = CGVectorMake(0, -1.0);
self.physicsBody = [SKPhysicsBody bodyWithEdgeLoopFromRect:self.frame];
self.physicsBody.dynamic = YES;
self.physicsBody.affectedByGravity = NO;
self.physicsBody.categoryBitMask = wallCategory;
self.physicsBody.collisionBitMask = nodeCategory;
self.physicsBody.contactTestBitMask = nodeCategory;
self.physicsWorld.contactDelegate = self;
SKSpriteNode *node1 = [SKSpriteNode spriteNodeWithColor:[UIColor redColor] size:CGSizeMake(50, 50)];
SKSpriteNode *node2 = [SKSpriteNode spriteNodeWithColor:[UIColor greenColor] size:CGSizeMake(20, 20)];
node2.position = CGPointMake(0, -node1.frame.size.height/2+node2.frame.size.height/2);
node1.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:node1.frame.size];
node1.physicsBody.dynamic = YES;
node1.physicsBody.categoryBitMask = nodeCategory;
node1.physicsBody.collisionBitMask = wallCategory;
node1.physicsBody.contactTestBitMask = wallCategory;
node1.physicsBody.restitution = 1.0;
node1.physicsBody.friction = 0.0;
node1.physicsBody.linearDamping = 0.0;
node1.physicsBody.angularDamping = 0.0;
[node1 addChild:node2];
[self addChild:node1];
}
return self;
}
Yet the node1 just falls through(affected by gravity) the screen without bouncing off the bottom. What am I doing wrong?
Give node1 a position:
node1.position = CGPointMake(self.frame.size.width/2,self.frame.size.height/2);
This is the orbivoid tutorial GameScene.m. So my problem is that, enemies spawning is just located somewhere in the lower left due to the CGPointMake. I want to make them already spawned outside of the screen at the start of the game with a definite number, randomly located(ex. 10 enemies already spawned outside of the screen at different locations). Can somebody please help me (some code, tips or something to implement for this)? I did not change anything in the GameScene.m so for the convenience of those who wants to help me. Thanks!
#implementation GameScene
{
BOOL _dead;
SKNode *_player;
NSMutableArray *_enemies;
SKLabelNode *_scoreLabel;
}
-(id)initWithSize:(CGSize)size {
if (self = [super initWithSize:size]) {
/* Setup your scene here */
self.backgroundColor = [SKColor colorWithRed:0.15 green:0.15 blue:0.3 alpha:1.0];
self.physicsWorld.gravity = CGVectorMake(0.0f, 0.0f);
self.physicsWorld.contactDelegate = self;
_enemies = [NSMutableArray new];
_player = [SKNode node];
SKShapeNode *circle = [SKShapeNode node];
circle.path = [UIBezierPath bezierPathWithOvalInRect:CGRectMake(-10, -10, 20, 20)].CGPath;`
circle.fillColor = [UIColor blueColor];
circle.glowWidth = 5;
SKEmitterNode *trail = [SKEmitterNode orb_emitterNamed:#"Trail"];
trail.targetNode = self;
trail.position = CGPointMake(CGRectGetMidX(circle.frame), CGRectGetMidY(circle.frame));
_player.physicsBody = [SKPhysicsBody bodyWithCircleOfRadius:10];
_player.physicsBody.mass = 100000;
_player.physicsBody.categoryBitMask = CollisionPlayer;
_player.physicsBody.contactTestBitMask = CollisionEnemy;
[_player addChild:trail];
_player.position = CGPointMake(size.width/2, size.height/2);
[self addChild:_player];
}
return self;
}
- (void)didMoveToView:(SKView *)view
{
[self performSelector:#selector(spawnEnemy) withObject:nil afterDelay:1.0];
}
-(void)spawnEnemy
{
[self runAction:[SKAction playSoundFileNamed:#"Spawn.wav" waitForCompletion:NO]];
SKNode *enemy = [SKNode node];
SKEmitterNode *trail = [SKEmitterNode orb_emitterNamed:#"Trail"];
trail.targetNode = self;
trail.particleScale /= 2;
trail.position = CGPointMake(10, 10);
trail.particleColorSequence = [[SKKeyframeSequence alloc] initWithKeyframeValues:#[
[SKColor redColor],
[SKColor colorWithHue:0.1 saturation:.5 brightness:1 alpha:1],
[SKColor redColor],
] times:#[#0, #0.02, #0.2]];
[enemy addChild:trail];
enemy.physicsBody = [SKPhysicsBody bodyWithCircleOfRadius:6];
enemy.physicsBody.categoryBitMask = CollisionEnemy;
enemy.physicsBody.allowsRotation = NO;
enemy.position = CGPointMake(50, 50);
[_enemies addObject:enemy];
[self addChild:enemy];
if(!_scoreLabel) {
_scoreLabel = [SKLabelNode labelNodeWithFontNamed:#"Courier-Bold"];
_scoreLabel.fontSize = 200;
_scoreLabel.position = CGPointMake(CGRectGetMidX(self.frame),
CGRectGetMidY(self.frame));
_scoreLabel.fontColor = [SKColor colorWithHue:0 saturation:0 brightness:1 alpha:0.5];
[self addChild:_scoreLabel];
}
_scoreLabel.text = [NSString stringWithFormat:#"%02d", _enemies.count];
// Next spawn
[self runAction:[SKAction sequence:#[
[SKAction waitForDuration:5],
[SKAction performSelector:#selector(spawnEnemy) onTarget:self],
]]];
}
-(void)dieFrom: (SKNode*)killingEnemy
{
_dead = YES;
SKEmitterNode *explosion = [SKEmitterNode orb_emitterNamed:#"Explosion"];
explosion.position = _player.position;
[self addChild:explosion];
[explosion runAction:[SKAction sequence:#[
[SKAction playSoundFileNamed:#"Explosion.wav" waitForCompletion:NO],
[SKAction waitForDuration:0.4],
[SKAction runBlock:^{
// TODO: Revove these more nicely
[killingEnemy removeFromParent];
[_player removeFromParent];
}],
[SKAction waitForDuration:0.4],
[SKAction runBlock:^{
explosion.particleBirthRate = 0;
}],
[SKAction waitForDuration: 1.2],
[SKAction runBlock:^{
ORBMenuScene *menu = [[ORBMenuScene alloc] initWithSize:self.size];
[self.view presentScene:menu transition:[SKTransition doorsCloseHorizontalWithDuration:0.4]];
}],
]]];
}
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
[self touchesMoved:touches withEvent:event];
}
-(void)touchesMoved: (NSSet *) touches withEvent:(UIEvent *)event
{
[_player runAction:[SKAction moveTo:[[touches anyObject] locationInNode:self] duration:.01]];
}
-(void)update:(CFTimeInterval)currentTime
{
CGPoint playerPos = _player.position;
for(SKNode *enemyNode in _enemies)
{
CGPoint enemyPos = enemyNode.position;
/* Uniform speed: */
CGVector diff = TCVectorMinus(playerPos, enemyPos);
CGVector normalized = TCVectorUnit(diff);
CGVector force = TCVectorMultiply(normalized, 4);
[enemyNode.physicsBody applyForce:force];
}
_player.physicsBody.velocity = CGVectorMake (0, 0);
}
-(void)didBeginContact:(SKPhysicsContact *)contact
{
if(_dead)
return;
[self dieFrom:contact.bodyB.node];
contact.bodyB.node.physicsBody = nil;
}
#end
This is only an educated guess, since I can’t test my code.
I think in your didMoveToView method you can do this
for (int i = 0; i < 10; i++)
[self performSelector:#selector(spawnEnemy) withObject:nil afterDelay:1.0];
to spawn 10 enemies at once.
In your spawnEnemy method you set the position of the enemies similar to this:
CGFloat x = arc4random() % 100 + size.width/2;
CGFLoat y = arc4random() % (int)size.height;
if (arc4random() % 2 == 0)
x = size.width/2 + x;
else
x = size.width/2 - x;
enemy.position = CGPointMake(x, y);
This should spawn the enemies beyond the left and right side of the screen, but within 100 points of the edge of the screen.
Of course you need to tweak this to your needs.
I am having trouble with the core-plot library, if I try to add a point I get the an error. I dont know how to fix this issue.
It is the following block which does not complete:
-(void)addNewData:(NSArray*)data{}
Can someone please help me resolve this problem, thanks.
My error:
I get the following error:
2012-09-24 14:51:09.790 sense_01[6719:907] ACC Connect
2012-09-24 14:51:15.270 sense_01[6719:907] *** Assertion failure in -[CPTScatterPlot reloadDataInIndexRange:], /Users/eskroch/Projects/Core Plot/framework/Source/CPTPlot.m:442
2012-09-24 14:51:15.272 sense_01[6719:907] *** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Invalid parameter not satisfying: NSMaxRange(indexRange) <= [self.dataSource numberOfRecordsForPlot:self]'
*** First throw call stack:
(0x394702a3 0x31d8f97f 0x3947015d 0x383da2af 0xaba75 0xaeccb 0xabcbb 0xaefeb 0xa7235 0xa360f 0x363df0ad 0x363df05f 0x363df03d 0x363de8f3 0x363dede9 0x363075f9 0x362f4809 0x362f4123 0x352f15a3 0x352f11d3 0x39445173 0x39445117 0x39443f99 0x393b6ebd 0x393b6d49 0x352f02eb 0x36348301 0xa2795 0xa2730)
libc++abi.dylib: terminate called throwing an exception
(lldb)
My code:
//
// SingleSensorViewController.m
// sense_01
//
// Created by Morten Ydefeldt on 9/21/12.
// Copyright (c) 2012 ydefeldt. All rights reserved.
//
#import "SingleSensorViewController.h"
#interface SingleSensorViewController ()
#end
#implementation SingleSensorViewController
#synthesize plot,graphView,label,SingleGraphView,portNumberForGraph,plotValues,plotLine;
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
SingleGraphView = self.view;
CATransition *transition = [CATransition animation];
transition.duration = .5;
transition.type = kCATransitionMoveIn; //choose your animation
transition.subtype = kCATransitionFromTop;
[SingleGraphView.layer addAnimation:transition forKey:nil];
plotLine = [plot plotWithIdentifier:#"1"];
}
return self;
}
-(void)addNewData:(NSArray*)data{
plotValues = [NSMutableArray arrayWithArray:data];
int i = [plotValues count];
[plotLine insertDataAtIndex:[plotValues count]-1 numberOfRecords:1];
NSLog(#"DONE");
}
-(void)pointReceived:(NSNumber *) point{
NSLog(#"some number");
}
-(NSUInteger)numberOfRecordsForPlot:(CPTPlot *)plot{
return [plotValues count];
}
-(NSNumber *)numberForPlot:(CPTPlot*)plot field:(NSUInteger)fieldEnum recordIndex:(NSUInteger)index{
if (fieldEnum == CPTScatterPlotFieldX){
return [NSNumber numberWithInt:[plotValues count]];
}else{
//return [plotValues objectAtIndex:plotValues.count-1];
return [NSNumber numberWithInt:[plotValues count]];
}
}
-(id)getView{
return SingleGraphView;
}
//-(CGPoint)plotSpace:(CPTPlotSpace *)space willDisplaceBy:(CGPoint)proposedDisplacementVector
//{
// NSLog(#"PLOT SPACE");
//
//return CGPointMake(proposedDisplacementVector.x, proposedDisplacementVector.y);
//
//}
//
//-(CPTPlotRange *)plotSpace:(CPTPlotSpace *)space willChangePlotRangeTo:(CPTPlotRange *)newRange forCoordinate:(CPTCoordinate)coordinate
//{
//
//
//
// // if (coordinate == CPTCoordinateY) {
// // newRange = ((CPTXYPlotSpace*)space).yRange;
// // }
// NSLog(#"NEW RANGE");
// return newRange;
//
//
//}
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view from its nib.
plot = [[CPTXYGraph alloc] initWithFrame:CGRectMake(100, 10, 800, 180)];
//CPTGraphHostingView *layerHostingView = [[CPTGraphHostingView alloc] initWithFrame:CGRectMake(100, 10, 800, 180)];
graphView.collapsesLayers = NO;
graphView.hostedGraph = plot;
CPTXYPlotSpace *plotSpace = (CPTXYPlotSpace* )plot.defaultPlotSpace;
plotSpace.allowsUserInteraction = YES;
plotSpace.delegate = self;
plotSpace.xRange = [CPTPlotRange plotRangeWithLocation: CPTDecimalFromDouble(0.0) length: CPTDecimalFromDouble(20.0)];
plotSpace.yRange = [CPTPlotRange plotRangeWithLocation: CPTDecimalFromDouble(0.0) length: CPTDecimalFromDouble(50.0)];
CPTScatterPlot *line = [[CPTScatterPlot alloc]init];
CPTMutableLineStyle *lineStyle = [CPTMutableLineStyle lineStyle];
//Fill colors
float c= 0.2;
plot.fill = [CPTFill fillWithColor:[CPTColor colorWithComponentRed:c green:c blue:c alpha:0]];
plot.plotAreaFrame.fill = [CPTFill fillWithColor:[CPTColor colorWithComponentRed:c green:c blue:c alpha:0.3]];
plot.plotAreaFrame.borderLineStyle = nil;
//Plot border
lineStyle.lineColor = [CPTColor grayColor];
lineStyle.lineWidth = 1.2;
//plot.borderLineStyle = lineStyle;
//Plot padding
plot.paddingBottom = 5;
plot.paddingLeft = 5;
plot.paddingRight = 5;
plot.paddingTop = 5;
//axis range
CPTXYAxisSet *axisSet = (CPTXYAxisSet *)plot.axisSet;
CPTXYAxis *y = axisSet.yAxis;
CPTXYAxis *x = axisSet.xAxis;
x.orthogonalCoordinateDecimal = CPTDecimalFromString(#"0.0");
y.orthogonalCoordinateDecimal = CPTDecimalFromString(#"0.0");
y.labelingPolicy = CPTAxisLabelingPolicyAutomatic;
x.labelingPolicy = CPTAxisLabelingPolicyAutomatic;
x.axisConstraints = [CPTConstraints constraintWithLowerOffset:15.0];
y.axisConstraints = [CPTConstraints constraintWithLowerOffset:35.0];
y.minorTickLength = 0;
y.majorTickLength = 0;
x.minorTickLength = 0;
x.majorTickLength = 0;
//axis theming
c = 0.4;
lineStyle.lineColor = [CPTColor colorWithComponentRed:c green:c blue:c alpha:1];
lineStyle.lineWidth = 0.7f;
y.axisLineStyle = lineStyle;
x.axisLineStyle = lineStyle;
//label theming
CPTMutableTextStyle *textStyle = [CPTMutableTextStyle textStyle];
textStyle.color = [CPTColor whiteColor];
textStyle.fontName = #"Helvetica-Bold";
x.labelTextStyle = textStyle;
y.labelTextStyle = textStyle;
//grid theming
c = 0.3;
lineStyle.lineColor = [CPTColor colorWithComponentRed:c green:c blue:c alpha:1];
lineStyle.lineWidth = 0.1f;
x.minorGridLineStyle = lineStyle;
y.minorGridLineStyle = lineStyle;
//curve theming
lineStyle.miterLimit = 1.0f;
lineStyle.lineWidth = 1.5f;
lineStyle.lineColor = [CPTColor whiteColor];
line.dataLineStyle = lineStyle;
line.identifier = #"1";
line.dataSource = self;
//plotsymbol
CPTPlotSymbol *plotSymbol = [CPTPlotSymbol ellipsePlotSymbol];
CPTGradient *blueGradient = [CPTGradient gradientWithBeginningColor:[CPTColor colorWithComponentRed:62.0f/255.0f green:112.0/255.0f blue:184.0f/255.0f alpha:1] endingColor:[CPTColor colorWithComponentRed:43.0f/255.0f green:63.0/255.0f blue:153.0f/255.0f alpha:1]];
lineStyle.lineColor = [CPTColor whiteColor];
lineStyle.lineWidth = 1.0f;
plotSymbol.lineStyle = lineStyle;
plotSymbol.fill = [CPTFill fillWithGradient:blueGradient];
plotSymbol.size = CGSizeMake(11.0, 11.0);
line.plotSymbol = plotSymbol;
line.delegate = self;
line.plotSymbolMarginForHitDetection = 5.0f;
[plot addPlot:line];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (void)viewDidUnload {
[self setGraphView:nil];
[self setLabel:nil];
[self setIconimage:nil];
[super viewDidUnload];
}
- (IBAction)addPoint:(id)sender {
NSLog(#"ADD POINT");
}
#end
Since you're replacing the entire data array, use the -reloadData method instead of - insertDataAtIndex:numberOfRecords:. You insert data when you need to add data points to an existing data set.
You need to retain the plotValues array. Otherwise, the array might be deallocated by the time Core Plot tries to read it and you'll get junk data or a crash.
I found that the problem that causes this issue, is that the view is not necessary when I try to add a point on the graph, so if I include
[self addNewData:[NSArray arrayWithObject:#"23"]];
In the end of viewdidload the point is added, and everything works!