Creating a scrollview - ios

Here's my current situation:
I created a CCScene named StoreScene.
Within that scene, I've initialized a CCLayer and just named it Store layer.
Now, I want a scrollable layer that contains content which the user can touch.
To do this, I created another CCLayer named Store Container.
I create an instance of this layer and add it as a child to StoreScene.
In StoreContainer, I've added multiple sprites, each with a unique tag.
The scrolling is done within the StoreScene and touches will move the entire Storecontainer layer up or down.
I have added 4 sprites to my scrolling layer (store container)
Initially,
sprite 1 is located at 0,10
sprite 2 is located at 0,20
sprite 3 is located at 0,30
sprite 4 is located at 0,40
Obviously, as the entire storecontainer layer shifts, the sprite positions shift as well.
However,
when I do this in the TouchesEnded method:
if (CGRectContainsPoint(sprite1.boundingBox, touchpoint)){
NSLog(#"TouchedSprite1");
}
... and so on for each sprite
The touch locations of each sprite remain in the same place!!!
Visually, the sprites are moving up and down nicely.
but their locations when receiving touches stay constant..
is there a reason for this?
Any other way for approaching a scrolling layer?
I've already looked at the UIKit's scrollview and I've looked at CCScrollLayer and both aren't good enough for me.
My way may be simpler but it doesn't work as planned.
Thanks in advance! ^_^

I'm guessing you've implemented touchesEnded in your StoreContainer. In that case the touches' coordinates will be relative to that layer, which explains why their coordinate system is following the layer around the screen. You could implement touchesEnded in the scene instead, or put the StoreContainer instance inside a new and immobile layer whose purpose is only to handle touches.
Alternatively you could keep your current setup and use your answer to this question to get the touch coordinates in the world... :)

Check out CCKit, there is a nice CCScrollLayer implementation included.

Related

Using SpriteKit inside UIKit

I am contemplating a simple app that has four characters that you can drag around on the screen. While dragging they "wiggle" — that's the animation. And they snap to a position if they get close enough to it... like in a puzzle. Without the animation, this is all simple in UIKit.
My first thought is to render each character in its own SKView inside a plain old UIView. I could attach UIGestureRecognizers to each SKView to track tapping and dragging. But I think this implies individual GameScenes for each character/SKView. That seems go go against the grain of SpriteKit.
The alternative is a single GameScene with the four sprites. But I would still need to track & drag them and I don't see how to do that within an all-SpriteKit app.
Is either approach better practice than the other?
You should implement the one that has a single scene and separate sprites for each character. The sprites will be SKSpriteNode instances which are SKNode instances, which descend from UIResponder and can, therefore, respond to touch events.
Look at the documentation for SKNode. It is a wealth of information that applies to sprites as well as to any other kind of node. In particular it says:
All nodes are responder objects that can respond directly to user interaction with the node onscreen…
And then later has a section on "The Hit-Test Order is the Reverse of Drawing Order" etc.

Adding child SKNode to existing SKNode changes the touch area

I'm create a SKNode to the scene and logging touch events on each individual SKNode. I can add as many as I want and the touches work as expected, if I touch the node and only the visible node do I see the log messages. Now, if I add another SKShapeNode to any of the previous SKNode's the touch area expands to be more of a rectangle and now I see the log message even if I touch outside the origin SKNode.
The first picture shows the original touch area of the SKNode and the second is the new touch area after adding a child SKShapeNode to that SKNode. The SKShapeNode being added is 20x20 so it fits within the 20x100 bar.
The problem is I now get multiple touch events when touching the other bars since they overlap. Is there any way around this?
You appear to be using separate graphics for each angle of your line. Instead try using the same graphic with your line at 0 degrees and then using the zRotation to angle it. I have not tried this myself but I think it will fix your issue.
Alternately try using containsPoint for your touch recognition in the touchesBegan method. You can check if the touch is within any of the nodes and process accordingly.

Building a tower defense game. How do I add a circular menu with tower choices on tile Node in SpriteKit?

I'm building a tower defence game using SpriteKit and I'm relatively new to this.
My map basically consists of tile Nodes that are touchable. Once a user touches the node, I can place a tower on that node (I have this part working so far). What I want to do moving forward, is instead of directly placing a tower, I'd like a circular menu to pop up around the tile Node to let the user pick the tower that they wish to place in this tile node.If the user clicks anywhere other than the circular menu, the menu should disappear.
So something like this:
http://imgur.com/QvCsM8Q
I'm wondering what the best way to do this is. I have two possible solutions but they seem hacky:
1) Creating a custom UIView consisting of the menu and 4 buttons and then adding it to my scene (but then how do I detect button presses in this menu from the scence?)
2) Extending a SKShapeNode to create a circle and adding in 4 SpriteNodes around the circle, then verifying if a touch location corresponds to one of the 4 SpriteNode locations.
Any suggestions/code examples of how best to approach this?
I would suggest you create a separate class for your tile nodes (which inherit SKSpriteNode) and add the functionality within that.
For the approach for the menu, I think something along the lines of point (2) would be better. By subclassing the tile node, you can make the tile detect the selection by itself.
Expand the tile using SKShapeNode or a SKSpriteNode with a circular image using animation.
Place the four buttons on the expanded part.
Implement the touch for the selection within the tile node class.
For closing the menu, a tap on the scene can trigger a NSNotification for which the tileNode could become a listener on expansion.

Drag and Drop objects from one CCLayer to another

I have three layers in my CCScene. MainLayer which contains GameLayer and HUDLayer. This is what it looks like now:
[ z-Order ] | [ Layer ]
==============================
3 ( Top Most ) | HUDLayer
2 ( Middle ) | GameLayer
1 ( Bottom ) | MainLayer
I have added touch listeners (ccTouchBegan, ccTouchMoved, and ccTouchEnded) on my MainLayer which calls GameLayer's method getTouchedObject( CCPoint p_Loc ) which returns the touched object in that layer.
I am now able to successfully 'touch' a specific object in the MainLayer. Now, what I want to do is to drag the object touched and put it into the HUDLayer. When I was working with just one layer, I was able to drag and drop different objects with no problem but the need to implement CCLayers came so I divided the main layer into three different layers.
Answers doesn't need to be cocos2d-x. I understand a bit of Obj-C and can translate Obj-C into C++ so cocos2d answers are welcome. Thanks in advance.
The easiest way to do it, is probably:
Add a new CCLayer on the very top called HoverLayer or something. This is for modularity.
As soon as a sprite is touched on any layer, remove it from that layer, and add it as a child of HoverLayer at the same position. The user will not "see" anything changed.
On touch up, after dragging the sprite, detect if the sprite is within the HUDLayer or not.
Remove the sprite from the HoverLayer and add it to the appropriate layer.
NOTES:
You can use the HUDLayer instead of the HoverLayer, but your class will be messy.
Of course, if you keep the touched sprite at the GameLayer while dragging, it will end up behind the HUDLayer at some point, so moving the sprite to a top layer is a must.
The code to implement the given solution is trivial. Nothing special to do, really.
I will provide an implementation here:
CCSprite* tmpSprite = getTouchedObject();
tmpSprite->retain();
tmpSprite->removeFromParentAndCleanup(false);
//do something here to get a pointer to you HUDLayer
//for example myHud = GameLayer->getChildByTag(HUD_TAG);
myHud->addChild(tmpSprite);
tmpSprite->release();

hacking ios ui responder chain

I'm facing a delicated problem handling touch events. This is problably not a usual stuff to make but i think it is possible. I just don't know how...
I have a Main View (A) and Main View (B) with a lot of subviews 1,2,3,4,5,...
MainView
SubView(A)
1
2
3
SubView(B)
1
2
3
Some of these sub sub views (1,2,4) are scrollviews.
It happens that I want to change between A and B with a two finger pan.
I have tried to attach a UIPanGestureRecognizer to MainView but the scrollviews cancel the touches and it only works sometimes.
I need a consistent method to first capture the touches, detect if it is a two finger pan, and only then decide if it will pass the touches downwards (or upwards... i'm not sure) the responder chain.
I tried to create a top level view to handle that, but I cant make to have the touches being passed through that view.
I have found a lot of people with similar problems but couldn't find a solution to this problem from their solutions.
If any one could give me a light, that would be great as i'm already desperate with this.
You can create a top level view to capture the touches and the coordinates of touches then you can check if the coordinates of touch is inside of the sub views. You can do that using
BOOL CGRectContainsPoint(CGRect rect, CGPoint point)
Method. Rect is a frame of the view, and point is point of touch.
Please not that the frames and touch locations are relative to their super views, therefore you need to convert them to coordinate system of app window.
Or maybe it can be more helpful
Receiving touch events on more then one UIView simultaneously

Resources