I am trying to add Vungle video ads in my sprite kit skscene. I have a sprite node which is when clicked, should load the ad. The guide provided by Vungle https://github.com/Vungle/vungle-resources/blob/master/iOS-resources/iOS-dev-guide.md shows how to place an ad through a view controller.
VungleSDK* sdk = [VungleSDK sharedSDK];
[sdk playAd:self];
I have different SKScene and i want to play ad in the scene rather than i the view controller. How can i achieve it.
Following is my SKScene code where the user is clicking an SKSpriteNode and i want the ad to load.
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
for (UITouch *touch in touches) {
SKNode *n = [self nodeAtPoint:[touch locationInNode:self]];
if ( [n.name isEqual: #"play"]) {
[self levelSelect];
}
else if( [n.name isEqual: #"coins"]){
VungleSDK* sdk = [VungleSDK sharedSDK];
[sdk playAd:self.view]; //TODO
}
}
This gives error as i am not passing a view controller to the method playAd. Can someone guide me?
Sovled this so if anyone else gets the same problem, here is the solution:-
In your view controller , Do this inside viewDidLoad method
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(handleNotification:) name:#"playVungle" object:nil];
also create a method
-(void)playVungleAd{
VungleSDK* sdk = [VungleSDK sharedSDK];
[sdk playAd:self];
}
Don't forget to import VungleSDK/VungleSDK.h
Now in your skscene, inside your touches began method do this
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
for (UITouch *touch in touches) {
SKNode *n = [self nodeAtPoint:[touch locationInNode:self]];
if ( [n.name isEqual: #"play"]) {
[self levelSelect];
}
else if( [n.name isEqual: #"coins"]){
[[NSNotificationCenter defaultCenter] postNotificationName:#"playVungle" object:nil]; //Sends message to viewcontroller to show ad.
}
}
Here we are sending a message to view controller to play the vungle ad. Now when you touch your "coins" skspritenode in your scene, it should play the video ad.
Related
I have a custom view which is not being deallocated. I dismiss controller on close button pressed. Now if I only press the button the view is deallocated alright. But If press button with one finger with other finger touching the view its not deallocated on dismiss but on the next touch event.
Its UITouch which is keeping the reference of my view and not releasing it. How can I fix this?
Here is my code for my close action:
- (IBAction)closePressed:(UIButton *)sender {
NSLog(#"Close pressed");
if (self.loader)
[self.loader cancelJsonLoading];
[self.plView quit];
[self dismissViewControllerAnimated:YES completion:nil];
}
Did you try to call:
[self.view resignFirstResponder];
That should cancel all pending UITouches.
If this doesn't work, you can keep trace of your touches:
define a NSMutableSet where you store current touches:
NSMutableSet *_currentTouches;
in your init():
_currentTouches = [[NSMutableSet alloc] init];
And implement:
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
[super.touchesBegan:touches withEvent:event];
[_currentTouches unionSet:touches]; // record new touches
}
- (void)touchesEnded:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
[super.touchesEnded:touches withEvent:event];
[_currentTouches minusSet:touches]; // remove ended touches
}
- (void)touchesCancelled:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
[super.touchesEnded:touches withEvent:event];
[_currentTouches minusSet:touches]; // remove cancelled touches
}
Then, when you need to clean your touches (when you release your view for instance):
- (void)cleanCurrentTouches {
self touchesCancelled:_currentTouches withEvent:nil];
_currentTouchesremoveAllObjects];
}
It is, I think, a bit hacky, but the doc says:
When an object receives a touchesCancelled:withEvent: message it
should clean up any state information that was established in its
touchesBegan:withEvent: implementation.
Okay so I have to Scenes: TitleScene and GameScene. Obviously there is a lot of stuff in GameScene and that resulted in something very annoying. I have a play-button in the TitleScene and whenever that gets pressed I present the GameScene.
I do that like this:
In TitleScene.m :
-(void)didMoveToView: (SKView *)view {
if(!self.contentCreated) {
self.createSceneContents;
self.contentCreated = YES;
}
}
-(void)createSceneContents {
//among other TitleScene stuff
self.gameScene = [GameScene sceneWithSize:self.frame.size];
self.gameScene.scaleMode = SKScaleModeResizeFill;
}
-(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *touch = [touches anyObject];
CGPoint location = [touch locationInNode:self];
if ([self.playButton containsPoint:location]) {
[self.view presentScene:self.gameScene];
}
}
The Problem is that whenever I press the play-button it causes like a second to two seconds of lag before transitioning to the next scene.
I create the GameScene just like the TitleScene with a lot of stuff in the createSceneContents method. I know it is not the simulators fault, because I tested it on my iPhone 6.
Can I pre-load all the GameScene's stuff when the app is first opened, or is there another way to stop this lag?
I'd really like to get to the bottom of why this code causes intermittent response to touch input... Even with NSLog as the first instruction...
I've just made a new project in cocos2d with Box2d for a game that at this stage needs to just a few simple things...
A basket that appears in the centre of the screen. It must be a b2Fixture and fall onto a surface. Then if the user touched the screen, I want the basket to zoom to the touch point, and from there the user can drag it around the screen.
When the user lets go, the basket drops... I have this working right now...
However the BUG is that touching the screen doesn't always work... It intermittently responds to touches, and therefore intermittently calls the methods.
As you will see below, I have used NSLog to check when each methods are being called. The result is that sometimes you have to lift your finger off the screen and then back on several times, and then "seemingly at random", it will decide to run the code....
Heres what I got...
My touch methods....
-(void)ccTouchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
NSLog(#"Multi Touch Moved...");
if (_mouseJoint == NULL) return;
UITouch *myTouch = [touches anyObject];
CGPoint location = [myTouch locationInView:[myTouch view]];
location = [[CCDirector sharedDirector] convertToGL:location];
b2Vec2 locationWorld = b2Vec2(location.x/PTM_RATIO, location.y/PTM_RATIO);
_mouseJoint->SetTarget(locationWorld);
}
-(void)ccTouchCancelled:(UITouch *)touch withEvent:(UIEvent *)event
{
NSLog(#"\nThe touch was CANCELED...");
}
-(void) ccTouchMoved:(UITouch *)touch withEvent:(UIEvent *)event
{
NSLog(#"Single Touch Moved...");
}
- (void)ccTouchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *myTouch = [touches anyObject];
CGPoint location = [myTouch locationInView:[myTouch view]];
location = [[CCDirector sharedDirector] convertToGL:location];
b2Vec2 locationWorld = b2Vec2(location.x/PTM_RATIO, location.y/PTM_RATIO);
NSLog(#"\n\nTouch did begin...");
if (_mouseJoint != NULL)
{
_mouseJoint->SetTarget(locationWorld);
NSLog(#"The IF statment was met...");
return;
}
NSLog(#"The IF statment was NOT met...Running _mouseJoint setup...");
b2MouseJointDef md;
md.bodyA = _groundBody;
md.bodyB = _body;
md.target = _body->GetPosition();
md.collideConnected = true;
md.maxForce = 100000000.0f * _body->GetMass();
_mouseJoint = (b2MouseJoint *)_world->CreateJoint(&md);
_body->SetAwake(true);
_mouseJoint->SetTarget(locationWorld);
}
-(void)ccTouchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
if (_mouseJoint != nil) {
_world->DestroyJoint(_mouseJoint);
_mouseJoint = nil;
}
}
And this is the interface that some of the code refers to...
#interface HelloWorldLayer : CCLayerColor
{
b2World *_world;
b2Body *_body;
b2Fixture *_bodyFix;
b2MouseJoint *_mouseJoint;
b2Body *_groundBody;
}
The only idea another member helped me determine is, that because I'm working within a single scene, and I have/had a CCMenu and a CCLabelTTF on the screen, is it possible that the CCMenu is still intercepting touches, and if so, how can I destroy the CCMenu after my animation has finished?
Pressing the only button item simply CCmoves the title and label(CCMenuItem) off the screen vertically... But the object still exists...
The problem here was that my CCMenu was still receiving touches (I assume in parts of the screen where the CCMenuItems where formed).
The solution was to declare my CCMenu in my #implementation rather than in my init scene setup.
#implementation HelloWorldLayer
{
CCLabelTTF *label;
CCLabelTTF *startTheGameLabel;
CCSprite *theCattery;
CCMenu *_menu;
}
Then in my init, rather than declaring it there, i simply assign to the one in the #implementation.
-(id) init { if( (self=[super initWithColor:ccc4(50, 180, 220, 255)]) )
{
//.. Other "irrelevant to question" scene setup stuff here...//
// Start the game button
startTheGameLabel = [CCLabelTTF labelWithString:#"Save Some Kitties!" fontName:#"Zapfino" fontSize:20];
CCMenuItemLabel *startTheGameLabelItem = [CCMenuItemLabel itemWithLabel:startTheGameLabel target:self selector:#selector(startGameStub:)];
// Push the menu
_menu = [CCMenu menuWithItems: startTheGameLabelItem, nil];
[self addChild:_menu];
//.. Other "irrelevant to question" scene setup stuff here...//
}
This gives me access to the CCMenu throughout my class, so I can later disable touch input once the user has made a selection.
-(void) startGameStub:(id)sender
{
CGSize size = [[CCDirector sharedDirector] winSize];
// Clear the labels off the screen
CMoveTo *moveTheTitleLabelAction = [CCMoveTo actionWithDuration:1.0 position:ccp(label.position.x, size.height + label.boundingBox.size.height)];
CCMoveTo *moveTheStartLabelAction = [CCMoveTo actionWithDuration:1.0 position:ccp(startTheGameLabel.position.x, size.height + startTheGameLabel.boundingBox.size.height)];
// Commit actions
[label runAction:moveTheTitleLabelAction];
[startTheGameLabel runAction:moveTheStartLabelAction];
// LIFE SAVING MESSAGE!!!
[_menu setTouchEnabled:NO]; // This is what fixes the problem
}
I am following through the Stanford iOS class and have a bit of a design question. In the class we are making a card matching game that has some 20 cards on screen or so. I recently made the cards UIViews so I could draw them properly.
I gave them each a method tap that will swap faceUp to YES/NO, thus flipping the cards. I add the gesture recognizer to each in my ViewController and it works. The individual cards know when they're touched and flip.
However, I need to know in my ViewController that a cardView has been touched... and which one.
How/what ways do I have to do this? Can I broadcast something in my View that the ViewController will listen for? Can I have my viewController handle that taps (but is there a way to get the sending view if I do this?) I apologize if this is really base, but I'm new to iOS and would like to not learn by patching and implementing a broken MVC pattern.
EDIT: Just for information, this is my final implementation.
Each CardView has a tap recognizer on it. When a tap is recognized it calls:
- (void)cardTapped:(UIGestureRecognizer *)gesture
{
UIView *view = [gesture view]; // This method is what I was looking for.
if ([view isKindOfClass:[PlayingCardView class]]) {
PlayingCardView *playingCardView = (PlayingCardView *)view;
[playingCardView flip]; // flips card
// Game code
if (!self.game.hasStarted) {
[self startGame];
}
int cardIndex = [self.cardViews indexOfObject:playingCardView];
[self.game chooseCardAtIndex:cardIndex];
[self updateUI];
}
}
The tag property will tell you which view has been tapped. Set the proper tag when you create your view and in your action method that's been triggered on tap you can call a delegate method that will notify your delegate about which view has been tapped. Make your viewcontroller has the delegate and it will received the notification.
// your target method will look like this:
- (void) didTap:(id)sender {
//... your code that handle flipping the card
[self.delegate didTapOnCard:self]; // where delegate is your view controller
}
You can use touchesBegan method to detect which view was tapped.
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *touch = [touches anyObject];
NSLog(#"%d", [touch view].tag); // Considering you have set tags for your UIViews..
if([touch view] == cardView1) // Considering you have a view as cardView1
{
NSLog(#"cardView1 is tapped");
}
}
In your UIView card class add
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)e {
UITouch *touch = [touches anyObject];
if ([self pointInside:[touch locationInView:self] withEvent:nil]) {
[self touchesCancelled:touches withEvent:e];
// Add your card flipping code here
}
}
The broadcast approach: in your UIView's tap method, send a notification:
[[NSNotificationCenter defaultCenter] postNotificationName:#"cardTapped" object:self userInfo:#{ #"card": #(self.cardId), #"faceUp": #(self.faceup) }];
and in your ViewController subscribe to that notification:
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(cardTapped:) name:#"cardTapped" object:nil];
and implement
-(void)cardTapped:(NSNotification*)notification
{
int card = [[notification.userInfo objectForKey:#"card"] intValue];
BOOL faceUp = [[notification.userInfo objectForKey:#"faceUp"] boolValue];
}
I have subclassed a UIView that already handles single touches and drags. I want to enhance the interaction of this view so that, while dragging, if the user touches with a second finger (anywhere else in the view), then the system prints a message. I've made a stab at the code:
In my header file I've declared:
NSString *key; // This unique key identifies the first touch
My .m file I have:
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
for (UITouch *t in touches) {
if (key == NULL)
{
key = [[[NSValue valueWithPointer:t] description] copy];
}
if ([key isEqualToString:[[NSValue valueWithPointer:t] description]])
{
NSLog(#"calling parent to handle single touch");
[super touchesBegan:[NSSet setWithObject:t] withEvent:event];
}
else
{
[self twoTouchDetected];
}
}
}
-(void) touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
for (UITouch *t in touches) {
if ([key isEqualToString:[[NSValue valueWithPointer:t] description]])
{
[super touchesMoved:[NSSet setWithObject:t] withEvent:event];
}
}
}
-(void) touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
for (UITouch *t in touches) {
if ([key isEqualToString:[[NSValue valueWithPointer:t] description]])
{
[super touchesEnded:[NSSet setWithObject:t] withEvent:event];
key = NULL;
}
}
}
Unfortunately there are issues with this implementation. The first time (while dragging with one finger) if I touch with the second figer, the system will register it immediately. However, the second time I touch with a second finger (while still continuing to drag with the first finger), the second finger touch does not register until the first finger is lifted up. The events from the second finger are backed up...
What is also strange is that sometimes, the parent gets called with touch data from the 2nd finger and not the 1st.
It turns out my code worked, but the problem was that I subclassed an object belonging to the Core Plot framework. This framework does weird things to their objects and therefore the touches were coming back in the wrong order.
I created an empty project to receive touches and everything came out great.