Accelerometer cocos2d spritebuiilder cant get it to work - objective-c

I am trying to use the accelerometer in my spritebuidler cocos2d project.I tried to follow https://www.makeschool.com/gamernews/371/accelerometer-with-cocos2d-30-and-ios-7 which seems pretty straight forward but it doesnt seem to work for me. I have tried downloading their git example but the project wont build.
my code is below
#import "GameOverScene.h"
#import <CoreMotion/CoreMotion.h>
#implementation GameOverScene{
CCButton *_restartButton;
CMMotionManager *_motionManager;
CCLabelTTF *_label;
}
- (id)init
{
if (self = [super init])
{
_label= [CCLabelTTF labelWithString:#"X" fontName:#"Arial" fontSize:48];
[self addChild:_label];
_motionManager = [[CMMotionManager alloc] init];
}
return self;
}
-(void)restartButtonClicked {
CCScene *scene = [CCBReader loadAsScene:#"MainScene"];
[[CCDirector sharedDirector] replaceScene:scene withTransition:[CCTransition transitionPushWithDirection:CCTransitionDirectionLeft duration:0.25f]];
}
- (void)onEnter
{
[super onEnter];
_label.position = ccp(self.contentSize.width/2, self.contentSize.height/2);
[_motionManager startAccelerometerUpdates];
}
- (void)onExit
{
[super onExit];
[_motionManager stopAccelerometerUpdates];
}
- (void)update:(CCTime)delta {
CMAccelerometerData *accelerometerData = _motionManager.accelerometerData;
CMAcceleration acceleration = accelerometerData.acceleration;
CGFloat newXPosition = _label.position.x + acceleration.y * 1000 * delta;
newXPosition = clampf(newXPosition, 0, self.contentSize.width);
_label.position = CGPointMake(newXPosition, _label.position.y);
}
#end
What happens is i see half an x on the bottom left corner when its meant to be in the middle of the screen.i tried changing the spawn position to
_label.position = ccp(500, 300);
and that changes the y axis but it is still on 0 on the x axis when i run the project
and tilting my phone does nothing.
What am i missing?

Author of the tutorial here. Sorry for the hickup, I have updated the repository with the solution on GitHub and fixed the Cocos2D related issue, we will migrate this tutorial to Cocos2D 3.3 soon. If you download the latest version you should see everything working as expected.
Regarding your specific problem, could you inspect/print the contentSize of the scene to which you are adding the label?

Related

SceneKit App fails with EXC_BAD_ACCESS on iOS9

We've bumped into a problem with one of our apps that uses SceneKit when deployed on iOS9. The app works great on iOS8.0-8.4, but when deployed on iOS9, it immediately crashes. Looking at the crash logs, we are seeing an EXC_BAD_ACCESS exception in a thread. The specific error states com.apple.scenekit.renderingQueue.SCNView Thread 11 crashed. Thinking that it was somehow related to the complexity of the scene, we dropped the scene back to nothing but a 3d box, and the app still crashes. The code that renders the box is as follows. It seems awfully simple to be crashing. And it's very weird that this runs fine on everything prior to iOS9 and runs fine on the simulator for iOS9. It only crashes when deployed. (This is an Enterprise app).
The crash occurs on the line of code that reads:
[scene.rootNode addChildNode:boxNode];
What am I missing?? Thanks for any help.
#implementation TreasureChestViewController
#synthesize sceneView;
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
// Create the SCNView
}
-(void) viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
// Add scene an empty scene
scene = [SCNScene scene];
// Set the scene to the view
sceneView.scene = scene;
// Create and add a camera to the scene
SCNNode *cameraNode = [SCNNode node];
cameraNode.camera = [SCNCamera camera];
cameraNode.position = SCNVector3Make(0,15, 30);
[scene.rootNode addChildNode:cameraNode];
// Create and add a light to the scene
SCNLight *spotLight = [SCNLight light];
spotLight.type = SCNLightTypeSpot;
spotLight.color = [UIColor whiteColor];
SCNNode *spotLightNode = [SCNNode node];
spotLightNode.light = spotLight;
spotLightNode.position = SCNVector3Make(0, cameraNode.position.y, 20);
[cameraNode addChildNode:spotLightNode];
// A square box
CGFloat boxSide = 15.0;
SCNBox *box = [SCNBox boxWithWidth:boxSide
height:boxSide
length:boxSide
chamferRadius:0];
SCNNode *boxNode = [SCNNode nodeWithGeometry:box];
// boxNode.transform = CATransform3DMakeRotation(M_PI_2/3, 0, 1, 0);
[scene.rootNode addChildNode:boxNode];
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
return YES;
}
#end

How to trick an OS X app into thinking the mouse is a finger?

I'm writing a Mac app that contains a collection view. This app is to be run on a large touchscreen display (55" EP series from Planar). Due to hardware limitation, the touchscreen doesn't send scroll events (or even any multitouch events). How can I go about tricking the app into thinking a "mousedown+drag" is the same as a "mousescroll"?
I got it working halfway by subclassing NSCollectionView and implementing my own NSPanGestureRecognizer handler in it. Unfortunately the result is clunky and doesn't have the feeling of a normal OS X scroll (i.e., the velocity effect at the end of a scroll, or scroll bounce at the ends of the content).
#implementation UCTouchScrollCollectionView
...
- (IBAction)showGestureForScrollGestureRecognizer:(NSPanGestureRecognizer *)recognizer
{
CGPoint location = [recognizer locationInView:self];
if (recognizer.state == NSGestureRecognizerStateBegan) {
touchStartPt = location;
startOrigin = [(NSClipView*)[self superview] documentVisibleRect].origin;
} else if (recognizer.state == NSGestureRecognizerStateEnded) {
/* Some notes here about a future feature: the Scroll Bounce
I don't want to have to reinvent the wheel here, but it
appears I already am. Crud.
1. when the touch ends, get the velocity in view
2. Using the velocity and a constant "deceleration" factor, you can determine
a. The time taken to decelerate to 0 velocity
b. the distance travelled in that time
3. If the final scroll point is out of bounds, update it.
4. set up an animation block to scroll the document to that point. Make sure it uses the proper easing to feel "natural".
5. make sure you retain a pointer or something to that animation so that a touch DURING the animation will cancel it (is this even possible?)
*/
[self.scrollDelegate.pointSmoother clearPoints];
refreshDelegateTriggered = NO;
} else if (recognizer.state == NSGestureRecognizerStateChanged) {
CGFloat dx = 0;
CGFloat dy = (startOrigin.y - self.scrollDelegate.scrollScaling * (location.y - touchStartPt.y));
NSPoint scrollPt = NSMakePoint(dx, dy);
[self.scrollDelegate.pointSmoother addPoint:scrollPt];
NSPoint smoothedPoint = [self.scrollDelegate.pointSmoother getSmoothedPoint];
[self scrollPoint:smoothedPoint];
CGFloat end = self.frame.size.height - self.superview.frame.size.height;
CGFloat threshold = self.superview.frame.size.height * kUCPullToRefreshScreenFactor;
if (smoothedPoint.y + threshold >= end &&
!refreshDelegateTriggered) {
NSLog(#"trigger pull to refresh");
refreshDelegateTriggered = YES;
[self.refreshDelegate scrollViewReachedBottom:self];
}
}
}
A note about this implementation: I put together scrollScaling and pointSmoother to try and improve the scroll UX. The touchscreen I'm using is IR-based and gets very jittery (especially when the sun is out).
In case it's relevant: I'm using Xcode 6 beta 6 (6A280e) on Yosemite beta (14A329r), and my build target is 10.10.
Thanks!
I managed to have some success using an NSPanGestureRecognizer and simulating the track-pad scroll wheel events. If you simulate them well you'll get the bounce from the NSScrollView 'for free'.
I don't have public code, but the best resource I found that explained what the NSScrollView expects is in the following unit test simulating a momentum scroll. (See mouseScrollByWithWheelAndMomentumPhases here).
https://github.com/WebKit/webkit/blob/master/LayoutTests/fast/scrolling/latching/scroll-iframe-in-overflow.html
The implementation of mouseScrollByWithWheelAndMomentumPhases gives some tips on how to synthesize the scroll events at a low level. One addition I found I needed was to actually set an incrementing timestamp in the event in order to get the scroll-view to play ball.
https://github.com/WebKit/webkit/blob/master/Tools/WebKitTestRunner/mac/EventSenderProxy.mm
Finally, in order to actually create the decaying velocity, I used a POPDecayAnimation and tweaked the velocity from the NSPanGestureRecognizer to feel similar. Its not perfect but it does stay true to NSScrollView's bounce.
I have a (dead) project on Github that does this with an NSTableView, so hopefully it will work well for an NSCollectionView.
Disclaimer: I wrote this while I was still learning GCD, so watch for retain cycles... I did not vet what I just posted for bugs. feel free to point any out :) I just tested this on Mac OS 10.9 and it does still work (originally written for 10.7 IIRC), not tested on 10.10.
This entire thing is a hack to be sure, it looks like it requires (seems to anyway) asynchronous UI manipulation (I think to prevent infinite recursion). There is probably a cleaner/better way and please share it when you discover it!
I havent touched this in months so I cant recall all the specifics, but the meat of it surely is in the NBBTableView code, which will paste snippets of.
first there is an NSAnimation subclass NBBScrollAnimation that handles the "rubber band" effect:
#implementation NBBScrollAnimation
#synthesize clipView;
#synthesize originPoint;
#synthesize targetPoint;
+ (NBBScrollAnimation*)scrollAnimationWithClipView:(NSClipView *)clipView
{
NBBScrollAnimation *animation = [[NBBScrollAnimation alloc] initWithDuration:0.6 animationCurve:NSAnimationEaseOut];
animation.clipView = clipView;
animation.originPoint = clipView.documentVisibleRect.origin;
animation.targetPoint = animation.originPoint;
return [animation autorelease];
}
- (void)setCurrentProgress:(NSAnimationProgress)progress
{
typedef float (^MyAnimationCurveBlock)(float, float, float);
MyAnimationCurveBlock cubicEaseOut = ^ float (float t, float start, float end) {
t--;
return end*(t * t * t + 1) + start;
};
dispatch_sync(dispatch_get_main_queue(), ^{
NSPoint progressPoint = self.originPoint;
progressPoint.x += cubicEaseOut(progress, 0, self.targetPoint.x - self.originPoint.x);
progressPoint.y += cubicEaseOut(progress, 0, self.targetPoint.y - self.originPoint.y);
NSPoint constraint = [self.clipView constrainScrollPoint:progressPoint];
if (!NSEqualPoints(constraint, progressPoint)) {
// constraining the point and reassigning to target gives us the "rubber band" effect
self.targetPoint = constraint;
}
[self.clipView scrollToPoint:progressPoint];
[self.clipView.enclosingScrollView reflectScrolledClipView:self.clipView];
[self.clipView.enclosingScrollView displayIfNeeded];
});
}
#end
You should be able to use the animation on any control that has an NSClipView by setting it up like this _scrollAnimation = [[NBBScrollAnimation scrollAnimationWithClipView:(NSClipView*)[self superview]] retain];
The trick here is that the superview of an NSTableView is an NSClipView; I dont know about NSCollectionView, but I suspect that any scrollable control uses NSClipView.
Next here is how the NBBTableView subclass makes use of that animation though the mouse events:
- (void)mouseDown:(NSEvent *)theEvent
{
_scrollDelta = 0.0;
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{
if (_scrollAnimation && _scrollAnimation.isAnimating) {
[_scrollAnimation stopAnimation];
}
});
}
- (void)mouseUp:(NSEvent *)theEvent
{
if (_scrollDelta) {
[super mouseUp:theEvent];
// reset the scroll animation
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{
NSClipView* cv = (NSClipView*)[self superview];
NSPoint newPoint = NSMakePoint(0.0, ([cv documentVisibleRect].origin.y - _scrollDelta));
NBBScrollAnimation* anim = (NBBScrollAnimation*)_scrollAnimation;
[anim setCurrentProgress:0.0];
anim.targetPoint = newPoint;
[anim startAnimation];
});
} else {
[super mouseDown:theEvent];
}
}
- (void)mouseDragged:(NSEvent *)theEvent
{
NSClipView* clipView=(NSClipView*)[self superview];
NSPoint newPoint = NSMakePoint(0.0, ([clipView documentVisibleRect].origin.y - [theEvent deltaY]));
CGFloat limit = self.frame.size.height;
if (newPoint.y >= limit) {
newPoint.y = limit - 1.0;
} else if (newPoint.y <= limit * -1) {
newPoint.y = (limit * -1) + 1;
}
// do NOT constrain the point here. we want to "rubber band"
[clipView scrollToPoint:newPoint];
[[self enclosingScrollView] reflectScrolledClipView:clipView];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{
NBBScrollAnimation* anim = (NBBScrollAnimation*)_scrollAnimation;
anim.originPoint = newPoint;
});
// because we have to animate asyncronously, we must save the target value to use later
// instead of setting it in the animation here
_scrollDelta = [theEvent deltaY] * 3.5;
}
- (BOOL)autoscroll:(NSEvent *)theEvent
{
return NO;
}
I think that autoscroll override is essential for good behavior.
The entire code is on my github page, and it contains several other "touch screen" emulation tidbits, if you are interested, such as a simulation for the iOS springboard arrangeable icons (complete with "wiggle" animation using NSButtons.
Hope this helps :)
Edit: It appears that constrainScrollPoint: is deprecated in OS X 10.9. However, It should fairly trivial to reimplement as a category or something. Maybe you can adapt a solution from this SO question.

Background position alternating position every time I build in Xcode 5

I am just beginning programming games in Xcode 5 using cocos2D and found this pretty strange. I'm starting out fresh on a menu scene and was importing a background and a button. The following code positions my background just fine sometimes, but then other times it's adjusted upwards about 50 pixels (my simulator is on it's side, or it's length is lying horizontal, so technically it's shifting about -50 pixels in the "width" direction, although to the simulator it shifts upwards).
Note I found that every time I run my program, it alternates between being properly aligned and shifted. Why would this be happening ugh! Below is the code I'm using.
Note 2 I'm using Kobold2D and the framework I'm using has a config.lua that's a little beyond my scope for me to understand everything. The config.lua code is located here http://snipt.org/BEt6
-(id) init
{
if ((self = [super init]))
{
CCSprite *sprite = [CCSprite spriteWithFile:#"background.png"];
sprite.anchorPoint = CGPointZero;
[self addChild:sprite z:-1];
sprite = [CCSprite spriteWithFile:#"button.png"];
sprite.anchorPoint = CGPointZero;
sprite.position = CGPointMake(200,200);
[self addChild:sprite z:0];
}
return self;
}
The only problem with your code is that you are initializing sprite twice, which is NOT very good.
I would think it is causing your problem.
Try this code:
-(id) init
{
if ((self = [super init]))
{
CCSprite *sprite = [CCSprite spriteWithFile:#"background.png"];
sprite.anchorPoint = CGPointZero;
[self addChild:sprite z:-1];
CCSprite *sprite2 = [CCSprite spriteWithFile:#"button.png"];
sprite2.anchorPoint = CGPointZero;
sprite2.position = CGPointMake(200,200);
[self addChild:sprite2 z:0];
}
return self;
}

Rotating, scaling Cocos2d inherited layer with 2 sprites as children

Straight to the point, I have a class which is basically inherited from CCLayer and has 2 sprites as children.
some_layer.h
#interface some_layer : CCLayer {
CCSprite *back;
CCSprite *front;
}
some_layer.mm
// on "init" you need to initialize your instance
-(id) init
{
if( (self=[super init])) {
back = [CCSprite spriteWithFile:#"back.png"];
front = [CCSprite spriteWithFile:#"front.png"];
[front setOpacity:0];
[self addChild:back];
[self addChild:front];
//this is after modification
back.positionInPixels = CGPointMake(winSizeInPixels.width/2,winSizeInPixels.height/2);
front.positionInPixels = CGPointMake(winSizeInPixels.width/2,winSizeInPixels.height/2);
}
return self;
}
//after the edit
-(void) setPositionInPixels:(CGPoint)positionInPixels {
[super setPositionInPixels:CGPointMake(positionInPixels.x -(winSizeInPixels.width/2), positionInPixels.y -(winSizeInPixels.height/2))];
}
-(void) setPosition:(CGPoint)position {
[super setPosition:CGPointMake(position.x -(winSize.width/2), position.y -(winSize.height/2))];
}
Of course that is not all the implementation of the layer, but that code is the only one related to the problem, let me know if you think you need more.
Now in some part of the parent layer am trying to do this
float x = winSizeInPixels.width/2;
float y = winSizeInPixels.height/2;
[self setPositionInPixels:CGPointMake(x, y)];
mylayer = [[some_layer alloc] init];
[mylayer setPositionInPixels:CGPointMake(-offset, -offset)];
[self addChild:mylayer];
[mylayer runAction:[CCEaseInOut actionWithAction:[CCRotateTo actionWithDuration:speed*20 angle:angle] rate:4]];
The output of this code, is that I can see the sprites rotating, but not around the center of some_layer, I want them to rotate and stay in their place (rotate around themselves), what am trying to do is rotate, scale them at the same time while keeping their positions the same on screen,
The sprites are keeping in rotating around some random point ( Maybe around parent of their parent which is self in the last code )
BTW, I'm not touching the sprites back and front positions, I only deal with that "some_layer", I tried setting their positions to (0,0)
The only time the position of "some_layer" is correct is when it's rotation angle is 0, and it's scale is 1.0, if there's something unclear please let me know, thanks a lot, I can provide some screen shots
Edit : I modified the code above, it works properly as a workaround, but I think this is not the right way of doing it!!! Please check the comments, I don't know what's strange happening!!
Thank you!
Edit 2: Answer found
Answer to my self
Add this to the init method of some_layer.mm
[self setContentSize:CGSizeMake(0, 0)];
Thanks for everyone who tried to help me :)
Analysing the code is the best solution!
BTW I deleted the overridden methodes for both setPos and deleted the code that changes the Sprites positions, it's like this now
// on "init" you need to initialize your instance
-(id) init
{
if( (self=[super init])) {
back = [CCSprite spriteWithFile:#"back.png"];
front = [CCSprite spriteWithFile:#"front.png"];
[front setOpacity:0];
[self addChild:back];
[self addChild:front];
[self setContentSize:CGSizeMake(0, 0)];
}
return self;
}
Are you setting some anchorPoint for the Layer or Sprite which you are using. if yes then please check that the anchor point should be set at center :
someSprite.anchorPoint=ccp(0.5,0.5);
For more details : http://www.qcmat.com/understanding-anchorpoint-in-cocos2d/

Updating the centre point & zoom of MKMapView (iPhone)

I have been trying to centre the map view on the users location. This should also update as and when a change in location is registered. The issue I'm having is upon loading the app I can't get hold of the current latitude and longitude to apply the centring & zooming.
These are the key bits of code I have so far...
- (void)viewDidLoad
{
self.locationManager = [[CLLocationManager alloc] init];
locationManager.delegate = self;
locationManager.desiredAccuracy = kCLLocationAccuracyBest;
[locationManager startUpdatingLocation];
[self updateMapZoomLocation:locationManager.location];
[super viewDidLoad];
}
The idea being that it should create an instance of the location manager, then start updating the location. Finally it should run the function I wrote to update the map view accordingly...
- (void)updateMapZoomLocation:(CLLocation *)newLocation
{
MKCoordinateRegion region;
region.center.latitude = newLocation.coordinate.latitude;
region.center.longitude = newLocation.coordinate.longitude;
region.span.latitudeDelta = 0.1;
region.span.longitudeDelta = 0.1;
[map setRegion:region animated:YES];
}
However this doesn't seem to happen. The app builds and runs ok, but all that gets displayed is a black screen - it's as if the coordinates don't exist?!
I also have a delegate method that deals with any updates by calling the function above...
- (void)locationManager:(CLLocationManager *)manager
didUpdateToLocation:(CLLocation *)newLocation
fromLocation:(CLLocation *)oldLocation
{
[self updateMapZoomLocation:newLocation];
}
I have tried looking at several of the other similar questions that have been asked & answered previously however I still can't seem to find the solution I'm after.
Any help on this would be really appreciated; I've spent hours and hours trawling the internet in search of help and solutions.
ps. 'map' is the mapView.
You want to use the MKMapViewDelegate callback so you only zoom in once the location is actually known:
Here's some swift code to handle that:
var alreadyZoomedIn = false
func mapView(mapView: MKMapView!, didUpdateUserLocation userLocation: MKUserLocation!) {
if(!alreadyZoomedIn) {
self.zoomInOnCurrentLocation()
alreadyZoomedIn = true
}
}
func zoomInOnCurrentLocation() {
var userCoordinate = mapView?.userLocation.coordinate
var longitudeDeltaDegrees : CLLocationDegrees = 0.03
var latitudeDeltaDegrees : CLLocationDegrees = 0.03
var userSpan = MKCoordinateSpanMake(latitudeDeltaDegrees, longitudeDeltaDegrees)
var userRegion = MKCoordinateRegionMake(userCoordinate!, userSpan)
mapView?.setRegion(userRegion, animated: true)
}
You shouldn't call updateMapZoomLocation during your viewDidLoad function because the location manager has not yet go a location. If/when it does it'll call the delegate function when it's ready. Until then your map won't know where to center. You could try zooming as far out as it goes, or remembering where it was last looking before the app was shutdown.