Pick Your Own Adventure iPhone Edition

Pick Your Own Adventure iPhone Edition

A few days ago I came across this cool Pick Your Own Adventure game on Twitter from user Peretti. I decided to make a quick renewable application that used UIAlertViews and UIActionSheets to tell the story. We are going to implement the UIAlertView and UIActionSheet protocol methods in order to get the functionality we are looking for. This will be a short project but will show the important methods associated with these views.

Step 1

Start a new view based project called CYOA. If you want to add a background image you can add a UIImageView to your CYOAViewController.xib. You can get the one I used here. But that is not necessary.

Step 2

In your project we are going to create a new object to hold the pieces that compose and given “frame” of a pick your own adventure. A frame of a pick your own adventure game is composed of 6 things as far as I am concerned.

  1. Prompt/Title
  2. Choice 1 Text
  3. Choice 2 Text
  4. Choice 1 Tile
  5. Choice 2 Tile
  6. isEnd

Through the use of these 6 objects we will be able to create a network of what I have called “AdventurePieces”. Create a new file. Make a subclass of NSObject and call it AdventurePiece.

Open AdventurePiece.h and input the following.

#import 
 
@interface AdventurePiece : NSObject {
	NSString *message;
	NSString *choice1;
	NSString *choice2;
 
	AdventurePiece *choice1Piece;
	AdventurePiece *choice2Piece;
 
	BOOL isEnd;
}
 
@property (nonatomic, retain) NSString *message;
@property (nonatomic, retain) NSString *choice1;
@property (nonatomic, retain) NSString *choice2;
 
@property (nonatomic, retain) AdventurePiece *choice1Piece;
@property (nonatomic, retain) AdventurePiece *choice2Piece;
 
@property (assign) BOOL isEnd;
 
-initWithMessage:(NSString*)_message
	 firstChoice:(NSString*)_choice1
	secondChoice:(NSString*)_choice2
	  firstPiece:(AdventurePiece*)_choice1Piece
	 secondPiece:(AdventurePiece*)_choice2Piece
		   isEnd:(BOOL)_isEnd;
 
@end

Step 3

We are now going to implement the initialization method that we defined in our header. Open up AdventurePiece.m and input the following.

#import "AdventurePiece.h"
 
@implementation AdventurePiece
 
@synthesize message;
@synthesize choice1;
@synthesize choice2;
 
@synthesize choice1Piece;
@synthesize choice2Piece;
 
@synthesize isEnd;
 
-initWithMessage:(NSString*)_message
	 firstChoice:(NSString*)_choice1
	secondChoice:(NSString*)_choice2
	  firstPiece:(AdventurePiece*)_choice1Piece
	 secondPiece:(AdventurePiece*)_choice2Piece
		   isEnd:(BOOL)_isEnd
{
	if(self = [super init])
	{
		message = _message;
		choice1 = _choice1;
		choice2 = _choice2;
		choice1Piece = _choice1Piece;
		choice2Piece = _choice2Piece;
		isEnd = _isEnd;
	}
 
	return self;
}
@end

All we need to do in this initialization method is fill in our object parameters appropriately.

Step 4

Now that we have made the object that will facilitate our story we need to go about making the logic to automate bringing up the adventure pieces in the right order. First we are going to define one object in our view controller header. Go to CYOAViewController.h and input the following.

#import
#import "AdventurePiece.h"
 
@interface MakeMyOwnAdventureViewController : UIViewController <UIActionSheetDelegate, UIAlertViewDelegate>  {
 
	AdventurePiece *currentPiece;
}
 
@end

Step 5

With that done we need to do the following final steps.

  1. When the app launches a method should be called that creates a bunch of connected adventure pieces and sets the currentPiece instance variable to the one we desire to start on.
  2. Tell the app to show the currentPiece adventure tile.
  3. Respond to users pushing buttons on the adventure tile by resetting the current piece instance variable.
  4. Pull up a different view when the end of the chain is reached.

For our purposes we will be have UIAlertViews show the parts of the story before the end. And the final piece of our story will be shown in a UIActionSheet. Lets look at each of the code pieces required to finish off our last four steps.

1. When the app launches a method should be called that creates a bunch of connected adventure pieces and sets the currentPiece instance variable to the one we desire to start on.

-(void)makeTheStory {
 
	AdventurePiece *successPiece = [[AdventurePiece alloc] initWithMessage:@"Sparks fly from the red wire but no explosion! Kim Jong Il’s evil plot is foiled!" firstChoice:@"YAY" secondChoice:nil firstPiece:nil secondPiece:nil isEnd:YES];
	AdventurePiece *failPiece = [[AdventurePiece alloc] initWithMessage:@"Cutting the blue wire begins a chain reaction - omg that is bad. Like really bad..Kaboom! What went wrong!?!" firstChoice:@"Too Bad" secondChoice:nil firstPiece:nil secondPiece:nil isEnd:YES];
	AdventurePiece *failPiece1 = [[AdventurePiece alloc] initWithMessage:@"Bad Choice. You Die" firstChoice:@"Too Bad" secondChoice:nil firstPiece:nil secondPiece:nil isEnd:YES];
	AdventurePiece *middlePieceA = [[AdventurePiece alloc] initWithMessage:@"You parachute to North Korea, sneak past guards to a live nuclear bomb. Do you" firstChoice:@"Cut Red" secondChoice:@"Cut Blue" firstPiece:successPiece secondPiece:failPiece isEnd:NO];
	AdventurePiece *middlePieceB = [[AdventurePiece alloc] initWithMessage:@"As you are leaving you notice trained assassins behind you" firstChoice:@"Run" secondChoice:@"Fight" firstPiece:failPiece1 secondPiece:failPiece1	isEnd:NO];
	currentPiece = [[AdventurePiece alloc] initWithMessage:@"You are assigned to a dangerous mission." firstChoice:@"Accept" secondChoice:@"Vacation" firstPiece:middlePieceA secondPiece:middlePieceB isEnd:NO];
}

In this method we make 5 total adventure pieces. This specific pick your own adventure is quite short. It as 3 prompts, 2 choices each with a total of 4 end points. You can see what I mean in this diagram here. The white square are the prompts, the green squares are the choices and the red squares are the final results. We fill in the current piece instance variable as the top most piece and we are done here.

2. Tell the app to show the currentPiece adventure tile.

- (void)viewDidLoad {
 
    [super viewDidLoad];
	[self makeTheStory];
	[self showStoryForCurrentPiece];
}
-(void)showStoryForCurrentPiece {
 
	if([currentPiece isEnd]) {
		UIActionSheet *actionSheet = [[UIActionSheet alloc] initWithTitle:[currentPiece message] delegate:self cancelButtonTitle:nil destructiveButtonTitle:nil otherButtonTitles:[currentPiece choice1],@"Retry",nil];
		[actionSheet showInView:self.view];
	}
 
	else {
 
		UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Your Message" message:[currentPiece message] delegate:self cancelButtonTitle:nil otherButtonTitles:[currentPiece choice1],[currentPiece choice2],nil];
		[alert show];
	}
}

This method should be called every time a new current piece is set. If checks to see if the adventure piece is an ending piece, if it is then an action sheet it created. If it is not an alert view is created. The button titles, and prompts are filled in appropriately.

Respond to users pushing buttons on the adventure tile by resetting the current piece instance variable.

- (void)alertView:(UIAlertView *)alertView willDismissWithButtonIndex:(NSInteger)buttonIndex {
 
	if(buttonIndex == 0)
	{
		currentPiece = [currentPiece choice1Piece];
		[self showStoryForCurrentPiece];
	}
 
	else
	{
		currentPiece = [currentPiece choice2Piece];
		[self showStoryForCurrentPiece];
	}
}

When an alert view button is pressed this method will be called. An adventure piece that brings up an alert view should always have connected adventure pieces for both of the possible answers it as. This resets the currentPiece adventure piece and show the current piece again.

Pull up a different view when the end of the chain is reached

- (void)actionSheet:(UIActionSheet *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex {
 
	if(buttonIndex == 1)
	{
		[self makeTheStory];
		[self showStoryForCurrentPiece];
	}
}

If this method is called that means that a action piece that was at the end of a chain was brought up. If the users hits the second button (button id == 1) that means they want to reset the story. This can be performed by building our story again showing the current piece again.

You can change the makeTheStory method to be whatever type of story you want. You can download the project here.

Leave a Reply

Your email address will not be published. Required fields are marked *