I'm working on a sprite kit game and I want to integrate a twitter sharing module at the end of gameplay.
This was the BASIC code I tried on an empty scene to test things:
#implementation gameOverScene
-(id)initWithSize:(CGSize)size {
if (self = [super initWithSize:size]) {
/* Setup your scene here */
self.backgroundColor = [SKColor orangeColor];
}
return self;
}
-(void)showTweetSheet {
//Create an instance of the tweet sheet
SLComposeViewController *tweetSheet = [SLComposeViewController composeViewControllerForServiceType:SLServiceTypeTwitter];
tweetSheet.completionHandler = ^ (SLComposeViewControllerResult result) {
switch (result) {
//the tweet was canceled
case SLComposeViewControllerResultCancelled:
break;
//the user hit send
case SLComposeViewControllerResultDone:
break;
}
};
//sets body of the tweet
[tweetSheet setInitialText:#"testing text"];
//add an image to the tweet
if (![tweetSheet addImage:[UIImage imageNamed:#"name.png"]]) {
NSLog(#"Unable to add the image!");
}
//add a URL to the tweet, you can add multiple URLS:
if (![tweetSheet addURL:[NSURL URLWithString:#"url.com"]]) {
NSLog(#"Unable to add the URL!");
}
}
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
/* Called when a touch begins */
for (UITouch *touch in touches) {
CGPoint location = [touch locationInNode:self];
//presents the tweet sheet to the user
[self presentViewController:tweetSheet animated:NO completion:^{
NSLog(#"tweet sheet has been presented");
}];
}
}
But I keep getting the error "use of undeclared identifier" when trying to present the tweetSheet view controller when the user taps on the scene.
How can I properly integrate the social framework into my project? is it possible on sprite kit?
First of all, since you have created a method, you do not need to present it from the touch delegate. Instead, call the showTweetSheet method.
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
/* Called when a touch begins */
for (UITouch *touch in touches) {
CGPoint location = [touch locationInNode:self];
//presents the tweet sheet to the user
[self showTweetSheet];
}
}
You can present it using the following code:
-(void)showTweetSheet
{
.
.
.
//Your initialisation as before
[self.view.window.rootViewController presentViewController:tweetSheet animated:YES completion:^{}];
}
Since this is an SKScene, it cannot present a viewController by itself. You need to present the viewController from another viewController, which can be accessed using the self.view.window.rootViewController property.
Related
I'm trying to subclass UIView and design a transparent view. This view will sit on top of many other views and it's only task is to capture and record user touches (tap and pan). I have tried many different methods, explained in different questions asked by other users with no luck. This is what I have done so far in my implementation file:
#import "touchLayer.h"
#implementation touchLayer
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) [self commonInit];
return self;
}
- (id)initWithCoder:(NSCoder *)aDecoder
{
self = [super initWithCoder:aDecoder];
if (self) [self commonInit];
return self;
}
- (void)commonInit
{
self.userInteractionEnabled = YES;
self.alpha = 0.0;
}
- (id)hitTest:(CGPoint)point withEvent:(UIEvent *)event
{
id hitView = [super hitTest:point withEvent:event];
if (hitView == self)
{
UITouch *touch = [[event allTouches] anyObject];
if (touch.phase == UITouchPhaseBegan) NSLog(#"touchesBegan");
else if (touch.phase == UITouchPhaseMoved) NSLog(#"touchesMoved");
else if (touch.phase == UITouchPhaseEnded) NSLog(#"touchesEnded");
return nil;
}
else
return hitView;
}
#end
Now this code works just fine, and I see see the touches in the lower layers, but I cannot differentiate between touchBegan, touchMoved, and touchEnded. [[event allTouches] anyObject] returns nil. Do you have any idea how I can capture tap and pan on a UIView without blocking the touches? Thanks a lot.
After investigating, actually i can't find solution to detect touch using hitTest method with a touchLayer. But your question is about capturing and recording user touches, so i have another for this issue.
My solution is
Subclass UIWindow
Replace window of UIAppDelegate with a new one which is created with your window class.
Override sendEvent method of UIWindow, capture and record user touches in this method.
This is my subclass of UIWindow to detect touch. I tried and it work.
#implementation DetectTouchWindow
- (void)sendEvent:(UIEvent *)event {
UITouch *touch = [[event allTouches] anyObject];
switch ([touch phase]) {
case UITouchPhaseBegan:
NSLog(#"Touch Began");
break;
case UITouchPhaseMoved:
NSLog(#"Touch Move");
break;
case UITouchPhaseEnded:
NSLog(#"Touch End");
break;
case UITouchPhaseCancelled:
NSLog(#"Touch Cancelled");
break;
default:
break;
}
[super sendEvent:event];
}
#end
For more detail and easier, i created a demo repo to check it. You can take a look at this link https://github.com/trungducc/stackoverflow/tree/recording-touch-events
Hope this helps ;)
I am attempting to programmatically take a screenshot and share it to a social media network when a button is clicked, however, I cannot quite figure out how to do so. I will appreciate any help
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
/* Called when a touch begins */
UITouch *touch = [touches anyObject];
CGPoint location = [touch locationInNode:self];
SKNode *node = [self nodeAtPoint:location];
if ([node.name isEqualToString:#"twitter"]){
[self.button play];
twitter = [[SLComposeViewController alloc] init];
twitter = [SLComposeViewController composeViewControllerForServiceType:SLServiceTypeTwitter];
[twitter setInitialText:#""];
UIViewController *twit = self.view.window.rootViewController;
[twit presentViewController: twitter animated: YES completion:NULL];
}
}
I am using sprite-kit and targeted iOS 7. I want to show leaderboard with button in my MenuScene.
my helper method codes.
#import "GameKitHelper.h"
NSString *const PresentAuthenticationViewController =
#"present_authentication_view_controller";
#interface GameKitHelper()<GKGameCenterControllerDelegate>
#end
#implementation GameKitHelper {
BOOL _enableGameCenter;
}
+ (instancetype)sharedGameKitHelper
{
static GameKitHelper *sharedGameKitHelper;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedGameKitHelper = [[GameKitHelper alloc] init];
});
return sharedGameKitHelper;
}
- (id)init
{
self = [super init];
if (self) {
_enableGameCenter = YES;
}
return self;
}
- (void)showGKGameCenterViewController:
(UIViewController *)viewController
{
if (!_enableGameCenter) {
NSLog(#"Local play is not authenticated");
}
GKGameCenterViewController *gameCenterViewController =
[[GKGameCenterViewController alloc] init];
gameCenterViewController.gameCenterDelegate = self;
gameCenterViewController.viewState =
GKGameCenterViewControllerStateAchievements;
[viewController presentViewController:gameCenterViewController
animated:YES
completion:nil];
}
I want to Leaderboard Button in this class.
-(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *touch = [touches anyObject];
CGPoint location = [touch locationInNode:self];
SKNode *node = [self nodeAtPoint:location];
if ([node.name isEqualToString:#"start"]) {
MyScene *myScene = [MyScene sceneWithSize:self.size];
[self.view presentScene:myScene transition:[SKTransition pushWithDirection:SKTransitionDirectionLeft duration:0.5]];
}
if ([node.name isEqualToString:#"gameCenter"]) {
//HERE MY LEADERBOARD BUTTON ACTION
//I don't know what i write here...
{
}
I tried so much methods but these working in iOS 6, I targeted iOS 7.
I tried this:
[[GameKitHelper sharedGameKitHelper] showGKGameCenterViewController:self]; Xcode says for self
Incompatible pointer types sending 'GameMenuScene *' to parameter of type 'UIViewController *'
Andrey is right. gameKitHelper means [gameKitHelper sharedGameKitHelper]. like this example
if ([node.name isEqualToString:#"gameCenter"]) {
UIViewController *vc = self.view.window.rootViewController;
[[GameKitHelper sharedGameKitHelper] showGKGameCenterViewController:vc];
}
Keep coding :)
if ([node.name isEqualToString:#"gameCenter"]) {
UIViewController *vc = self.view.window.rootViewController;
[[GameKitHelper sharedGameKitHelper] showGKGameCenterViewController:vc];
}
But actually you should present another ViewController from your ViewController, not from SKScene
Try this, it's easy to implement and works well:
https://github.com/nihalahmed/GameCenterManager
inside viewDidLoad:
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(openLeaderboard)
name:#"TestNotification"
object:nil];
Inside VC:
- (void) openLeaderboard
{
// Open Leaderboards here
}
In your Scene:
[[NSNotificationCenter defaultCenter]
postNotificationName:#"TestNotification"
object:self];
I want to call a method whenever a specific UIViewController is touched.
-touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event is a method that does what I'm looking for, exept it doesn't detect a touch on neither the statur bar, navigation bar or toolbar. How can I make a method that runs everytime the UIViewController is touched? Or in other words, the whole screen?
try adding a gesture recognition. to your window object, since it's a subclass of a uiview.
or like #Bamsworld said. "For full screen detection (including status bar) I think you'll need to sub class UIWindow and make it becomeFirstResponder: Override touches and handle from window sub class."
Subclass UIApplication say MyApplication and implement the method
- (void)sendEvent:(UIEvent *)event {
[super sendEvent:event];
// Do whatever you want
}
Then in main.m change the default implementation to
int main(int argc, char *argv[])
{
#autoreleasepool {
return UIApplicationMain(argc, argv, NSStringFromClass([MyApplication class]), NSStringFromClass([YourAppdelegate class]));
}
}
You will get each and every action in method
- (void)sendEvent:(UIEvent *)event
#import <QuartzCore/QuartzCore.h>
- (void)viewDidLoad
{
[super viewDidLoad];
[self.view setMultipleTouchEnabled:YES];
}
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
// Remove old red circles on screen
NSArray *subviews = [self.view subviews];
for (UIView *view in subviews) {
[view removeFromSuperview];
}
// Enumerate over all the touches and draw a red dot on the screen where the touches were
[touches enumerateObjectsUsingBlock:^(id obj, BOOL *stop) {
// Get a single touch and it's location
UITouch *touch = obj;
CGPoint touchPoint = [touch locationInView:self.view];
// Draw a red circle where the touch occurred
UIView *touchView = [[UIView alloc] init];
[touchView setBackgroundColor:[UIColor redColor]];
touchView.frame = CGRectMake(touchPoint.x, touchPoint.y, 30, 30);
touchView.layer.cornerRadius = 15;
[self.view addSubview:touchView];
[touchView release];
}];
}
I'm entering iOS via Sprite Kit, which I recognize is unwise.
My goal is to display a "Share" button upon Game Over. Tapping the share button should present a SLComposeViewController (Twitter Share). The contents of the scene should not change.
The game logic that dictates "Game Over" lives in SpriteMyScene.m, a subclass of SKScene.
I'm able to display a Share button on Game Over this way:
-(void)update:(CFTimeInterval)currentTime {
if (gameOver){
UIButton *button = [UIButton buttonWithType:UIButtonTypeRoundedRect];
[button addTarget:self
action:#selector(sendToController)
forControlEvents:UIControlEventTouchDown];
[button setTitle:#"Show View" forState:UIControlStateNormal];
button.frame = CGRectMake(80.0, 210.0, 160.0, 40.0);
[self.view addSubview:button];
}
}
- (void)sendToController
{
NSLog(#"ok");
SpriteViewController *viewController = [SpriteViewController alloc];
[viewController openTweetSheet];
}
Where I get stuck is trying to get the showTweetButton method to work. My SpriteViewController.m looks like this:
- (void)openTweetSheet
{
SLComposeViewController *tweetSheet = [SLComposeViewController
composeViewControllerForServiceType:
SLServiceTypeTwitter];
// Sets the completion handler. Note that we don't know which thread the
// block will be called on, so we need to ensure that any required UI
// updates occur on the main queue
tweetSheet.completionHandler = ^(SLComposeViewControllerResult result) {
switch(result) {
// This means the user cancelled without sending the Tweet
case SLComposeViewControllerResultCancelled:
break;
// This means the user hit 'Send'
case SLComposeViewControllerResultDone:
break;
}
};
// Set the initial body of the Tweet
[tweetSheet setInitialText:#"just setting up my twttr"];
// Adds an image to the Tweet. For demo purposes, assume we have an
// image named 'larry.png' that we wish to attach
if (![tweetSheet addImage:[UIImage imageNamed:#"larry.png"]]) {
NSLog(#"Unable to add the image!");
}
// Add an URL to the Tweet. You can add multiple URLs.
if (![tweetSheet addURL:[NSURL URLWithString:#"http://twitter.com/"]]){
NSLog(#"Unable to add the URL!");
}
// Presents the Tweet Sheet to the user
[self presentViewController:tweetSheet animated:NO completion:^{
NSLog(#"Tweet sheet has been presented.");
}];
}
I always get something like this in the logs:
-[UIView presentScene:]: unrecognized selector sent to instance 0x13e63d00 2013-10-17 18:40:01.611 Fix[33409:a0b] * Terminating app
due to uncaught exception 'NSInvalidArgumentException', reason:
'-[UIView presentScene:]: unrecognized selector sent to instance
0x13e63d00'
You're creating a new view controller but never presenting it:
SpriteViewController *viewController = [SpriteViewController alloc];
I'm assuming that SpriteViewController is what presents your SpriteMyScene, and you'd like to hand control back to the presenting SpriteViewController.
You need to keep a reference to SpriteViewController in your SpriteMyScene subclass, and then access that reference when you call openTweetSheet.
in SpriteMyScene.h
#class SpriteViewController;
#interface SpriteMyScene : SKScene
#property (nonatomic, weak) SpriteViewController *spriteViewController;
#end
in SpriteViewController.m
// somewhere you initialize your SpriteMyScene object, I'm going to call it myScene
myScene.spriteViewController = self;
in SpriteMyScene.m
#import "SpriteViewController.h"
- (void)sendToController
{
NSLog(#"ok");
// use the already-created spriteViewController
[_spriteViewController openTweetSheet];
}
You can use
UIViewController *vc = self.view.window.rootViewController;
This code will give you the access to your root View controller so you can do anything you do will your view controller like normal.
However, do you need to add a button? Use a sprite and add an event to it is better for you in this case. Just call:
UIViewController *vc = self.view.window.rootViewController;
[vc openTweetSheet];
And
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *touch = [touches anyObject];
NSArray *nodes = [self nodesAtPoint:[touch locationInNode:self]];
for (SKNode *node in nodes) {
if ([node.name isEqualToString:#"OpenTweet"]) {
UIViewController *vc = self.view.window.rootViewController;
[vc openTweetSheet];
}
}
}
If you want to open another UIViewController from inside your scene, you have to first create a delegate in the primary View Controller that originally created this scene so your scene can notify its ViewController of an open tweet action. You will need following steps:
Define a delegate in the primary View Controller - the view controller of our scene, to handle the open tweet action.
Implement the delegate method in the primary View Controller
Add a delegate property in your scene so it can keep a handle to its ViewController's delegate method implementation. Set this delegate as the primary View Controller during the creation of the scene
Detect an event on the scene to call the delegate method of the primary ViewController
In the delegate method implementation pass the control to the TweetSheetViewController
Here's the example:
#protocol ViewControllerDelegate <NSObject>
-(void) openTweetSheet;
#end
Extend this ViewController to support this protocol in its .h file
#interface ViewController : UIViewController<ViewControllerDelegate>
#end
Then in the .m file implement the method from the protocol
-(void) openTweetSheet{
TweetSheetViewController *ctrl = [[TweetSheetViewController alloc] initWithNibName:#"TweetSheetViewController" bundle:nil];
[self presentViewController:ctrl animated:YES completion:nil];
}
In your Scene header class, add a delegate property
#interface MyScene : SKScene {
}
#property (nonatomic, weak) id <ViewControllerDelegate> delegate;
#end
In the ViewController, before presenting the scene set its delegate in viewDidLoad method:
// Create and configure the scene.
MyScene * scene = [MyScene sceneWithSize:skView.bounds.size];
scene.scaleMode = SKSceneScaleModeAspectFill;
[scene setDelegate:self];
// Present the scene.
[skView presentScene:scene];
Now your Scene can pass the message back to its ViewController and the ViewController can open another ViewController. In your scene class, determine the action which will trigger the opening up of TweetSheetViewController
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
/* Called when a touch begins */
for (UITouch *touch in touches) {
CGPoint location = [touch locationInNode:self];
SKAction *fadeOut = [SKAction fadeOutWithDuration:0.5];
SKAction *fadeIn = [SKAction fadeInWithDuration:1.0];
SKAction *sequence = [SKAction sequence:#[fadeOut,fadeIn]];
SKNode *node = [self nodeAtPoint:location];
if ([[node name] isEqual: #"openTweet"]) {
NSLog(#"help");
[node runAction:sequence];
[delegate openTweetSheet];
}
}
Hope that helps.
Write the SlComposeViewController Method in the scene you want it to take place. For example:
#interface GameOverScene: SKScene
...initwithsize bla bla bla
...
Add these methods:
-(void)OpenTweetShet{
if ([SLComposeViewController composeViewControllerForServiceType:SLServiceTypeTwitter]) {
_composeTwitter = [SLComposeViewController composeViewControllerForServiceType:SLServiceTypeTwitter];
[_composeTwitter setInitialText:#"TWEET"];
Then call:
self.view.window.rootViewController **to present the SLComposeViewController**
[self.view.window.rootViewController presentViewController:_composeTwitter animated:YES completion:nil];
}
[_composeTwitter setCompletionHandler:^(SLComposeViewControllerResult result){
NSString *output =[[NSString alloc]init];
switch (result) {
case SLComposeViewControllerResultCancelled:
output = #"Post cancelled";
break;
case SLComposeViewControllerResultDone:
output = #"Post Succesfull";
break;
default:
break;
}
Here is the option for presenting UIAlert after the send/cancel post:
UIAlertView *alert = [[UIAlertView alloc]initWithTitle:#"Twitter" message:output delegate:nil cancelButtonTitle:#"Ok" otherButtonTitles: nil];
[alert show];
}];
}
#end
This worked for me: self.view.window.rootViewController
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *touch = [touches anyObject];
NSArray *nodes = [self nodesAtPoint:[touch locationInNode:self]];
for (SKNode *node in nodes) {
if ([node.name isEqualToString:#"OpenTweet"]) {
UIViewController *vc = self.view.window.rootViewController;
[self.view.window.rootViewController openTweetSheet];
}
}
}