Icarousel in Sprite Kit

iCarousel in Sprite Kit

You can use NSNotifications to show your character picker. You just need to observe the notifications posted by your SKScene. Your viewDidLoad should look something like:

override func viewDidLoad(){
super.viewDidLoad()

carousel.type = .CoverFlow
carousel.reloadData()

let spriteKitView = SKView()
spriteKitView.frame = self.view.bounds
self.view.insertSubview(spriteKitView, belowSubview: self.carousel)

spriteKitView.showsFPS = true
spriteKitView.showsNodeCount = true
spriteKitView.ignoresSiblingOrder = true

self.gameScene = GameScene(size:self.view.bounds.size)
self.gameScene.scaleMode = .AspectFill
self.gameScene.imageName = self.images[0] as! String

self.carousel.hidden = true
spriteKitView.presentScene(self.gameScene)

NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(self.showCarousel), name: gameScene.kShowNotification, object: nil)
}

You'll want to implementing carousel(carousel:iCarousel, didSelectItemAtIndex index:NSInteger) so you know what is selected, and so you can return to game play. For example:

func carousel(carousel:iCarousel, didSelectItemAtIndex index:NSInteger)
{
self.gameScene.imageName = self.images[index] as! String
self.hideCarousel()
}

You also need to remove observing before your view controller is deallocated.

deinit
{
NSNotificationCenter.defaultCenter().removeObserver(self)
}

Your SKScene can then post a notifications:

import SpriteKit

class GameScene: SKScene {
var imageName = "square1"{
didSet{
self.hidden = false
self.childNode.texture = SKTexture(imageNamed: imageName)
}
}

let kShowNotification = "showPicker"

var childNode = SKSpriteNode()
override func didMoveToView(view: SKView) {
/* Setup your scene here */

self.childNode = SKSpriteNode(imageNamed: imageName)
self.childNode.anchorPoint = CGPointZero
self.childNode.position = CGPointZero
self.addChild(self.childNode)
}

override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
self.showCharPicker()
}

func showCharPicker()
{
self.hidden = true
NSNotificationCenter.defaultCenter().postNotificationName(kShowNotification, object: nil)
}

}

If you want to change hit detection, you need to subclass the view for which you need it to change. This case your iCarousel view.

You can then either override hitTest or pointInside. I've created an iCarousel subclass and overrode pointInside to only return true when the point is inside one of the carousel's contentView's subviews.

class CarouselSubclass: iCarousel {

override func pointInside(point: CGPoint, withEvent event: UIEvent?) -> Bool {
var inside = false
for view in self.contentView.subviews
{
inside = CGRectContainsPoint(view.frame, point)
if inside
{
return inside
}
}
return inside
}
}

You need to remember to change the class of your carousel in interface builder and update your outlet as well.

iCarousel on Game Swift+SpriteKit not working properly

You're not setting the frame of the carousel or setting constraints on it.

Try changing your setupCarousel method to:

func setupCarousel() {
carousel = iCarousel()
carousel.dataSource = self
carousel.delegate = self
carousel.type = .Linear
carousel.reloadData()
// turn off autoresizing mask
carousel.translatesAutoresizingMaskIntoConstraints = false
self.view.addSubview(self.carousel)
// Add constraints
carousel.topAnchor.constraintEqualToAnchor(self.topLayoutGuide.bottomAnchor).active = true
carousel.leadingAnchor.constraintEqualToAnchor(self.view.leadingAnchor).active = true
carousel.trailingAnchor.constraintEqualToAnchor(self.view.trailingAnchor).active = true
carousel.bottomAnchor.constraintEqualToAnchor(self.view.bottomAnchor).active = true

NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(self.showCarousel), name: "showBallPicker", object: nil)
NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(self.hideCarousel), name: "hideBallPicker", object: nil)
}

Update

These constraints will pin the carousel to the edges of your view controller's view. If you want to position it differently, you could, for example, replace those constraints with something like:

carousel.centerXAnchor.constraintEqualToAnchor(self.view.centerXAnchor).active = true
carousel.centerYAnchor.constraintEqualToAnchor(self.view.centerYAnchor, constant: -100).active = true
carousel.widthAnchor.constraintEqualToAnchor(self.view.widthAnchor).active = true
carousel.heightAnchor.constraintEqualToConstant(200.0).active = true

This will center the carousel horizontally and place the carousel 100 points up from the center vertically. The carousel will be the same width as it's superview but will always be 200 points tall. You can look at Apple's documentation for more options for using anchors to create constraints.

If you want to add labels to your carousel items you should do that in viewForItemAtIndex. You can create a simple UIView subclass that will hold a UIImageView and UILabel and return that instead of just a UIImageView. For example:

class CarouselItem: UIView {
let imageView:UIImageView =
{
let imageView = UIImageView()
imageView.translatesAutoresizingMaskIntoConstraints = false
imageView.contentMode = .ScaleAspectFill
return imageView
}()

let label:UILabel =
{
let label = UILabel()
label.adjustsFontSizeToFitWidth = true
label.minimumScaleFactor = 0.5
label.translatesAutoresizingMaskIntoConstraints = false
label.textAlignment = .Center
label.numberOfLines = 0
return label
}()

override init(frame: CGRect)
{
super.init(frame: frame)
self.commonInit()
}

required init?(coder aDecoder: NSCoder)
{
super.init(coder: aDecoder)
self.commonInit()
}

func commonInit()
{
self.addSubview(self.imageView)
self.addSubview(self.label)

self.imageView.topAnchor.constraintEqualToAnchor(self.topAnchor).active = true
self.imageView.centerXAnchor.constraintEqualToAnchor(self.centerXAnchor).active = true
self.imageView.widthAnchor.constraintEqualToAnchor(self.widthAnchor).active = true
self.imageView.heightAnchor.constraintEqualToAnchor(self.heightAnchor, multiplier: 0.9).active = true

self.label.topAnchor.constraintEqualToAnchor(self.imageView.bottomAnchor, constant: 8.0).active = true
self.label.centerXAnchor.constraintEqualToAnchor(self.centerXAnchor).active = true
}
}

Now in viewForItemAtIndex

func carousel(carousel: iCarousel, viewForItemAtIndex index: Int, reusingView view: UIView?) -> UIView {
var carouselItem: CarouselItem!

if view == nil {
carouselItem = CarouselItem(frame: CGRectMake(0, 0, 250, 250))
carouselItem.backgroundColor = UIColor.redColor()
}else{
carouselItem = view as! CarouselItem
}

carouselItem.imageView.image = UIImage(named: "\(imageArray.objectAtIndex(index))")
carouselItem.label.text = "Some Text"

return carouselItem
}

carouselCurrentItemIndexDidChange on iCarousel only being called when I swipe

You should set up your carousel views in viewForItemAtIndex: reusingView:. The view returned by this method should represent the current state of that carousel item; so locked or "Select" as appropriate.

If the state of an item changes then you can call reloadItemAtIndex: to have iCarousel request an updated view for that item by calling viewForItemAtIndex: reusingView:.

You can scroll the carousel to a particular item by calling scrollToItemAtIndex:animated:

is it possible to implement iCarousel with SKScene array?

It's a little expensive in term of storage capacity, but it works perfectly.
Here's what you'll get:

The calling view of carousel

When you click load arena, you'll get the following view to select your arena:

carousel view

You have to select the arena and the click on the green button to return back to the calling view with the chosen arena loaded.

and here's the way to achieve it:

 -(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
//UITableViewCell *cell=[tableView cellForRowAtIndexPath:indexPath];
selectedItem=[_Title objectAtIndex:indexPath.row];
[singleton setChoice:selectedItem];

tableSelectedItemIndexPath=indexPath; //Here we strore the selected item index so later when returninng to normal mode we can deselect the item

TableViewRef=tableView;

if([selectedItem isEqualToString:@"load arena])
{
if ([[SpriteMyScene getMapsVector] count] == 0){

UIAlertView * alert =[[UIAlertView alloc ] initWithTitle:@"Absence de carte à visualiser" message:@"Il n'y a pas de carte disponible" delegate:self cancelButtonTitle:@"Ok" otherButtonTitles: nil];
[alert show];
}

else{

[[[[self.tabBarController tabBar]items]objectAtIndex:2]setEnabled:TRUE];

[self.tabBarController setSelectedIndex:2 ];
}
}

if([selectedItem isEqualToString:@"save arena"])
{
UIAlertView * alert =[[UIAlertView alloc ] initWithTitle:@"XML Save" message:@"Enter the name of the file you wish to save." delegate:self cancelButtonTitle:@"Cancel" otherButtonTitles: nil];
alert.alertViewStyle = UIAlertViewStylePlainTextInput;
[alert addButtonWithTitle:@"OK"];
[alert show];

//We programmarically remove the selection
[TableViewRef deselectRowAtIndexPath:tableSelectedItemIndexPath animated:YES];

}

if([selectedItem isEqualToString:@"delete arena"])
{
int yCoordinate=40;
//This is the scroll pan ein which the xml file list is displayed
_polygonView = [[UIScrollView alloc] initWithFrame: CGRectMake ( 0, 0, 500, 300)];
_polygonView.backgroundColor=[UIColor clearColor];
[_polygonView setScrollEnabled:YES]; //we activated the scroll function

NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); //here we all directory paths on ios
NSString *docDir;

docDir=[paths objectAtIndex:0]; //this is the path to Document directory

//we get an array containing all files in a given directory. This is same as File class in java
NSArray *directoryContent = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:docDir error:NULL];
for (int i = 0; i < (int)[directoryContent count]; i++)
{
NSRange range;
range=[[directoryContent objectAtIndex:i] rangeOfString:@".xml"];
if(range.location != NSNotFound)
{

//this index is used ot exlude the .xml part when displaying teh name sof the files to the user
int ToIndex=[[directoryContent objectAtIndex:i] length];
ToIndex-=4;

NSString *btnTitle=[[directoryContent objectAtIndex:i] substringToIndex:ToIndex];
if(![btnTitle isEqualToString:@"imageData"])
{
UIButton *FileButton = [[UIButton alloc] initWithFrame:CGRectMake(165, yCoordinate, 200, 40)];
[FileButton setTitle:btnTitle forState:UIControlStateNormal];
[FileButton setTitleColor:[UIColor whiteColor]forState:UIControlStateNormal];
[FileButton setEnabled:YES];
[FileButton setUserInteractionEnabled:YES];
[FileButton addTarget: self action: @selector(buttonIsPressed:) forControlEvents: UIControlEventTouchDown];
[FileButton setBackgroundColor:[UIColor blueColor]];
[_polygonView addSubview:FileButton];
yCoordinate+=45;
}
}

}

_polygonView.contentSize = CGSizeMake(self.view.frame.size.width, self.view.frame.size.height *2.5);

//This is the licensed class that is used to create a window pane
CustomIOS7AlertView* alertView=[[CustomIOS7AlertView alloc]init];
alertView.tag=1;
[alertView setFrame:CGRectMake(500, 0, 500, 500)];

[alertView setContainerView:_polygonView];
[alertView setButtonTitles:[NSMutableArray arrayWithObjects:@"Delete File", @"Cancel", nil]];
[alertView setDelegate:self];
[alertView show];
}

....
/*
* This method is used ot read the user input text value when user enters the name of the xml file
* This is used when saving a xml file
*/

- (void)alertView:(UIAlertView *)alertView didDismissWithButtonIndex:(NSInteger)buttonIndex
{ if (buttonIndex == 1) {

UITextField* fileName = [alertView textFieldAtIndex:0];

XMLHandler* xml=[[XMLHandler alloc] init];

[xml setXmlFileName:fileName.text];

[[SpriteViewController getSceneRef] snapShotScene:fileName.text];

//we save the image file
[xml generateImageFile:[SpriteMyScene getImageData]:[SpriteMyScene getImageFileName]];

//this function gets the _nodeDictionnary as argument
NSMutableDictionary* tmp = [singleton getSceneNodeDictionnary];

[xml generateXML:tmp];

}}

and the picture are taken each time the user save an arena using this method:

- (void) snapShotScene: (NSString*) imageName{

UIGraphicsBeginImageContextWithOptions(self.view.bounds.size, NO, 0.50);
[self.view drawViewHierarchyInRect:self.view.bounds afterScreenUpdates:YES];
UIImage * image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();

@autoreleasepool
{

//convert image into .png format.
imageData = UIImagePNGRepresentation(image);

imageFileName= imageName;

[mapsVector addObject: imageData];
[fileNamesVector addObject: imageFileName];

}

}

For the iCarousel class, use this link: The iCarousel repository
I hope this will help.



Related Topics



Leave a reply



Submit