From Apple to Raspberry Pi: Windows Buttons and Widgets — on Pi!

appleberryI’ve explored much of the basic coding in Python, but I’ll need a good user interface for the projects I’m doing. When it comes to the graphical user interface (GUI), Xcode and Python are on  two different planets. With storyboards and interface builder, Xcode arguably spoils developers. There are times one does need to add buttons and text programmatically to UIView, but it is mandatory to do so in Python, using a module called tkinter.

Making  a Tkinter Window and Frame

A bare bones version of a tkinter window look like this:

#tkinter_playbox_01
#regular import
from tkinter import *

#make the  window
root = Tk()
root.title('tkinter Playbox')

#start the mainloop
root.mainloop()

This is actually pretty boring.

tkinter01

The code makes a window by creating an instance of Tk and set the window’s title. We the start the main loop to get everything going:

Next we will need to add a frame to the code:

#tkinter_playbox_01
#regular import
from tkinter import *

#make the  window
root = Tk()
root.title('tkinter Playbox')

#make a frame
rootFrame = Frame(root)
rootFrame.grid(row=0,column=0)

#start the mainloop
root.mainloop()

This time when we run, our window seems to disappear. If you look around, you might find a tiny  black sliver like this one:

tkinter02

We created a frame, and the frame is an auto-sizing frame. We have no content in the frame , so it is the smallest it can possibly be.

Adding Labels in Tkinter

Now under the frame code add this:

#make labels
label1 = Label(rootFrame,text= 'Hello')
label1.grid(row=0,column=0)

Now run this code:

tkinter03

Here, we add a label called label1. This prints the always familiar message Hello. Let’s make another label. In our code, under the first label add this:

label2 = Label(rootFrame,text= 'Python')
label2.grid(row=0,column=1)

And that works as expected:

tkinter04

Notice the use of .grid(). This method places the widget in the row and column in the frame specified. We can swap the labels by changing our code to this:

#make labels
label1 = Label(rootFrame,text= 'Hello')
label1.grid(row=0,column=1)

label2 = Label(rootFrame,text= 'Python')
label2.grid(row=0,column=0)

tkinter05

or stack them like this:

#make labels
label1 = Label(rootFrame,text= 'Hello')
label1.grid(row=0,column=0)

label2 = Label(rootFrame,text= 'Python')
label2.grid(row=1,column=0)

tkinter06

Adding Buttons to the Tkinter Window

Now let’s add two buttons. Change the code as shown below. Make sure to change the grid positions on the labels:

#make buttons
button1 = Button(rootFrame, text = 'Press Me')
button1.grid(row =1, column = 0)
quit_button = Button(rootFrame,text='quit)
quit_button.grid(row = 1,column = 1)
#make labels
label1 = Label(rootFrame,text= 'Hello')
label1.grid(row=0,column=0)

label2 = Label(rootFrame,text= 'Python')
label2.grid(row=0,column=1)

We added the buttons the same way we added the labels, except using the Button constructor instead. When we run this time we get:

tkinter07

We can even click the buttons but they do nothing. Add the following to the quit button:

quit_button = Button(rootFrame,text='quit', command = quit)

Now when we click the quit button our program ends. adding in the command option allows us to call a method or function where the work gets done. Let’s try another example, but before we do we need to introduce variables in Tkinter. Add the following to the code, Just under the root.title assignment:

#define some variables
my_label_text = StringVar()
my_label_text.set('Python')

Now change label2 as follows:

label2 = Label(rootFrame,textvariable= my_label_text)

Run and you should see no difference.

tkinter07
Tkinter has its own set of variables. Unlike Python, they are strongly typed. These can be assigned to the textvariable or variable option of widgets to allow for dynamic changes to the widget, in this case a label. The variables have two methods associated with them, set and get. In the above code, we create a Stringvar, and then set its value to Python.

We can use the getter for the variable in a function for our button. Just underneath the from..import, add

def pressMe():
    print ('GO!')
    if my_label_text.get() == 'Python':
        my_label_text.set('Monty')
    else:
        my_label_text.set('Python')

Now change button 1 to this

button1 = Button(rootFrame, text = 'Press Me', command = pressMe)

Your code should now look like this:

#tkinter_playbox_01
#regular import
from tkinter import *

def pressMe():
    print ('GO!')
    if my_label_text.get() == 'Python':
        my_label_text.set('Monty')
        print ('Monty')
    else:
        my_label_text.set('Python')
        print ('Python')
#make the  window
root = Tk()
root.title('tkinter Playbox 01')

#define some variables
my_label_text = StringVar()
my_label_text.set('Python')

#make a frame
rootFrame = Frame(root)
rootFrame.grid(row=0,column=0)

#make buttons
button1 = Button(rootFrame, text = 'Press Me', command = pressMe)
button1.grid(row =1, column = 0)
quit_button = Button(rootFrame,text='quit', command = quit)
quit_button.grid(row = 1,column = 1)

#make labels
label1 = Label(rootFrame,text= 'Hello')
label1.grid(row=0,column=0)

label2 = Label(rootFrame,textvariable = my_label_text)
label2.grid(row=0,column=1)

#start the mainloop
root.mainloop()

Now when you click the button, the label will toggle between Monty and Python. This gives us buttons and labels, two of the most important of the widgets/controls in a UI. In our next installment, we will do a bit of customization to the buttons and labels.

SlippyFlippy 1.1: How to make a Countdown Timer in Sprite Kit.

icon2_120
SlippyFlippyPenguin

The next item on the update project list is making a countdown timer.  For those who haven’t read earlier episodes of this blog, there is a bug I cannot find. For a very small number of users, the game ends immediately when starting in hard mode. This might just be a user problem not moving the penguin fast enough, which I did get some reports from users. To solve that, we’ll add a three-second delay between pressing the button to start the game and running the game. For feedback during that time,  I am building a countdown timer.  I tried to do this in a method to drop directly into what we already have, but found nothing worked.  The problem is update:  and the frame cycle.

As you can find in Apple’s Sprite Kit Programming Guide there is a cycle of methods every frame. As developers, we can override three methods that update the frame in different ways.  The first is update:, where a lot of the actions take place. Actions are then evaluated by the system. Next, didEvaluateActions: allows us to handle the scene after the action for that frame.  The physics engine then kicks in. The evaluations of the physics engine can then be handled just before Sprite Kit renders the scene in the view.

I tried making a few methods that would run the countdown timer using SKAction. The above cycling caused them not to work: They dumped all the timing labels in a few frames, piled on top of each other.  In order to have both a timer and changes to the label with the countdown, we have to put our code in update:  and not out of it. Essentially, we will update the label with the current time, which conveniently is update: ‘s parameter.

I made a playbox to look at this without distractions. Starting with a new Sprite Kit template, I cleaned out the spaceship, and “Hello World” label.

I’ll add three instance variables:

  •  SKLabelNode,for the timer display
  •  BOOL flag, to let us know to start the countdown
  •  NSTimeInterval ,to let us have a start time.

Add this to the code:

@implementation SLMyScene{
SKLabelNode *countDown;
BOOL startGamePlay;
NSTimeInterval startTime;
}

Add to initWithSize: the following to make the label:

countDown = [SKLabelNode labelNodeWithFontNamed:"Futura-Medium"];
countDown.fontSize = 70;
countDown.position = CGPointMake(CGRectGetMidX(self.frame),
CGRectGetMaxY(self.frame)*0.85);
countDown.verticalAlignment =SKVerticalAlignmentCenter;
countDown.fontColor = [SKColor whiteColor ];
countDown.name = @"countDown";
countDown.zPosition = 100;
[self addChild:countDown];

Add the following to update:

countDown.text = [NSString stringWithFormat:@"%i", (int)currentTime];

This casts current time as an integer, and then prints it as one. Now when we run, we get the system time and date in seconds.

Let’s expand on this. For the playbox, we will set reset the timer to 0 when the user touches the label. This is a simple way to make a label into a button BTW.

Set up touchesBegan: to toggle the flag

-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
/* Called when a touch begins */
     for (UITouch *touch in touches) {
          CGPoint location = [touch locationInNode:self];
          if (CGRectContainsPoint(countDown.frame, location)){
               startGamePlay = YES;
          }
     }
}

Then change update: to the following:

//reset counter if starting
if (startGamePlay){
     startTime = currentTime;
     startGamePlay = NO;
}
countDown.text = [NSString stringWithFormat:"%i", (int)(currentTime-startTime)];

Build and run. Now when we tap the timer, it resets to 0.Screenshot 2014-04-10 06.17.03

We are still counting up. Let’s count down from 5. Modify update this way:

int countDownInt = 5.0 -(int)(currentTime-startTime);
countDown.text = [NSString stringWithFormat:@"%i", countDownInt];

Build and run. That will give us negative numbers, which we don’t want. Modify update: again to only show positive numbers. When we get a negative, stop counting.

int countDownInt = 5.0 -(int)(currentTime-startTime);
if(countDownInt>0){ //if counting down to 0 show counter
     countDown.text = [NSString stringWithFormat:@"%i", countDownInt];
}else { //if not show message, dismiss, whatever you need to do.
     countDown.text=@"GO!";
}

Screenshot 2014-04-10 06.20.04And that works!! I then place this code into SlippyFlippy penguin. I made a few adjustments to fit into SlippyFlippy. I  set the timer to three seconds, and aligned the timer and flash labels a bit better.  It works great — with two exceptions.

The flash labels are slightly annoying and clunky looking when they show up. I Need to set timing better on when to show them, and I need a method to remove them from the screen if we get a game over status while they are still showing.Screenshot 2014-04-10 06.20.36

Then I try to test the hard mode. The bug which I couldn’t find is now very front and center. If a user taps the screen after hitting the hard mode but before the penguin appears, the game ends. Next time, we begin our search and destroy mission for The Bug.

The playbox code for the countdown timer:

//
//  SLMyScene.m
//  CountdownTimer
//
//  Created by Steven Lipton on 4/8/14.
//  Copyright (c) 2014 Steven Lipton. All rights reserved.
//

#import "SLMyScene.h"

@implementation SLMyScene{
    SKLabelNode *countDown;
    BOOL startGamePlay;
    NSTimeInterval startTime;
}

-(id)initWithSize:(CGSize)size {    
    if (self = [super initWithSize:size]) {
        /* Setup your scene here */
        
        //Make a label for the timer
        self.backgroundColor = [SKColor colorWithRed:0.15 green:0.15 blue:0.3 alpha:1.0];
        countDown = [SKLabelNode labelNodeWithFontNamed:@"Futura-Medium"];
        countDown.fontSize = 50;
        countDown.position = CGPointMake(CGRectGetMidX(self.frame),
                                             CGRectGetMaxY(self.frame)*0.85);
        countDown.verticalAlignmentMode = SKLabelVerticalAlignmentModeCenter; //good for positioning with other sprites
        countDown.fontColor = [SKColor whiteColor ];
        countDown.name = @"countDown";
        countDown.zPosition = 100;
        [self addChild:countDown];
    }
    return self;
}

-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
    /* Called when a touch begins */
    
    for (UITouch *touch in touches) {
        CGPoint location = [touch locationInNode:self];
        if (CGRectContainsPoint(countDown.frame, location)){
            startGamePlay = YES;
        }
    }
}

-(void)update:(CFTimeInterval)currentTime {
    /* Called before each frame is rendered */
    /*code for beginning animation before game play ,and the start game */
    
    //reset counter if starting
    if (startGamePlay){
        startTime = currentTime;
        startGamePlay = NO;
    }
    
    int countDownInt = (int)(currentTime-startTime);
    if(countDownInt>0){  //if counting down to 0 show counter
        countDown.text = [NSString stringWithFormat:@"%i", countDownInt];
    }else { //if not show message, dismiss, whatever you need to do.
        countDown.text=@"GO!";
        /* code here runs every frame -- 
         Try not to put animations here, unless
         you can fire them once only or fire them through good timing.
         */
    }
}

@end

From Apple to Raspberry Pi: Using Strings

appleberryThere are several ordered types in Python, one of the most common is the string. In Xcode, we defined a NSString this way:

NSString *myString = @"and now for SOMEthing completely different"

Objective-C has the @"...” indicators for a string. Python on the other hand can use the much easier "..." or '...'

my_string = "and Now for something completely different"

The use of double or single quotes allows for the use of double or single quotes within the string. Python also supports Triple quotes """...""" which  allows for any white space, including new lines.

print (
""" ANd now
   for
something
           completely
    different""")
 ANd now
   for 
something 
           completely 
    different

Concatenation of strings are a  plus sign:

my_string ="and now for SOMEthing completely different"
my_silly_string ="silly walks"
print (my_string + ' -- The Ministry of ' + my_silly_string )
and now for SOMEthing completely different -- The Ministry of silly walks

There are a few functions that work on strings, such as:

string_length = len (my_string)

Methods of the str class perform string manipulations. For example there are several to deal with differing forms of capitalization:

print (my_string.capitalize())
print (my_string.upper())
print (my_string.lower())
print (my_string.title())
print (my_string.swapcase())
And now for something completely different
AND NOW FOR SOMETHING COMPLETELY DIFFERENT
and now for something completely different
And Now For Something Completely Different
AND NOW FOR someTHING COMPLETELY DIFFERENT
and now for SOMEthing completely different

and several for alignment:

my_string = "silly walks"
print (my_string.center(30))
print (my_string.center(30,'*'))
print (my_string.rjust(30,'-'))
print (my_string.ljust(30,'^'))
         silly walks          
*********silly walks**********
-------------------silly walks
silly walks^^^^^^^^^^^^^^^^^^^

and several for editing the string:

print (my_string.replace('different','penguin'))
print (my_string.partition('SOME'))
print (my_string.count('e'), " e's in our string")
print (my_string.find('e'))
and now for SOMEthing completely penguin
('and now for ', 'SOME', 'thing completely different')
4  e's in our string
27

The most used Xcode string function is for formatting numbers:

NSString *myString = [NSString stringwithFormat:@"now for a integer %i and float %6.2f",3,3.14];

In later versions of Python they replaced the % with braces and colons. The above format would be done like this:

my_string = "now for a integer {0:d} and float{1:6.2f}".format(3,3.141)

The braces tell Python to substitute something there. At the simplest  in the latest versions, you can do this:

my_string = "now for a integer {} and float{} and string {}".format(3,3.141, "oh my!")

You can also do this, which marks the position in the parameters:

my_string = "now for a integer {0} and float{1} and string {2}".format(3,3.141, "oh my!")
 

This explicitly grabs from the first, second or third parameters. like stringWithFormat:, the list of all the possibilities is quite long. I suggest looking up the documentation for all the possibilities.

I was going to do some more sequential structure next, but I wanted to do something a bit more practical. Python does not have a UI Foundation, but it does have a module which does many of the same things: tkinter. I will begin to explore that next.

From Apple to Raspberry Pi: Using Inheritance and Overrides

appleberry

Object oriented languages have a  concept called inhertance. A class can give its methods and properties to another class, which then replaces or expands the inherited class. We call the new class a subclass. When we replace a function or method we override the method or function. This allows the method or function of the same name to work in many circumstances. Let’s look at some Objective C- code.

#import "PDPythonStuff.h"

@implementation PDPythonStuff

-(int)montyFunction:(int)a b:(int)b{
     return a+b*b;
}
-(int)montyFunction{
     return self.a+self.b*self.b;
}

@end

We  have a different number of parameters in each method for this to work. We cannot, however add this method with different types to the implementation above:

-(float)montyFunction:(float)a b:(float)b{
     return a+b*b;
}

To use this code, I need  a subclass. I  define a subclass  in my header file:

@interface PDPythonFloatStuff :<strong> PDPythonStuff</strong>
     -(float)montyFunction:(float)a b:(float)b;
     -(float)montyFunction;
@end

I then override the methods above by re-writing them for floating point numbers.

@implementation PDPythonFloatStuff
-(float)montyFunction:(float)a b:(float)b{
    return a+b*b;
}
-(float)montyFunction{
    return self.a+self.b*self.b;
}
@end

Now let’s look at Python and inheritance. Look at this code.

#PSPythonStuff.py
class PSPythonStuff:
    def __init__(self,a,b):
        self.a = a
        self.b = b
    def montyPythonFunction(self,a,b):
        return a+b*b
    def montyPythonFunction(self):
        return self.a + self.b * self.b

We have two functions with the same name but a different number of parameters. Run the code, it runs successfully, though nothing seems to  happen. Now at the Shell, type the following:

>>> from PSPythonStuff import *
>>> my_instance = PSPythonStuff(5,25)
>>> print(my_instance.montyPythonFunction())

The shell responds with

630

One function works. Now try the other function:

>>> print(my_instance.montyPythonFunction(5,25))

We get an error:

Traceback (most recent call last):
File "<pyshell#3>", line 1, in;
print(my_instance.montyPythonFunction(5,25))
TypeError: montyPythonFunction() takes 1 positional argument but 3 were given

The message tells us that only the montyPython() function exists. Unlike Objective-C, we cannot have two functions with the same name but different parameters. The last one defined is the only function that works.

Using inheritance, We can define subclasses from the parent class or the super class. The subclass has everything that the super class does, but we  customize the subclass. We override same function or method from one class in a subclass as we did in Objective-C. Now if we want to use our function, we can.
Let’s define a class PSMorePythonStuff in Python which is a subclass of PSPythonStuff.

#PSPythonStuff.py
class PSPythonStuff:
    def __init__(self,a,b):
        self.a = a
        self.b = b
    def montyPythonFunction(self,a,b):
        return a+b*b

class PSMorePythonStuff(PSPythonStuff):
    def __init__(self,a,b):
        PSPythonStuff.__init__(self,a,b)
    def montyPythonFunction(self):
        return self.a+self.b*self.b

We tell Python this is a subclass by placing in parentheses the superclass PSPythonStuff.  In __init__ we add

PSPythonStuff.__init__(self,a,b)

This initializes and further connects the attributes of the super class to the subclass. Note here we use all three parameters for __init__ so that self connects the subclass and super class. Now open a new window and type the following module:

#class_demo_3
from PSPythonStuff import *
my_instance = PSPythonStuff(5,25)
print(my_instance.montyPythonFunction(5,25))
my_other_instance = PSMorePythonStuff(5,25)
print (my_other_instance.montyPythonFunction())

Save both modules and run class_demo_3. Because they are different classes, the montyPythonFunction works with different parameters.

We can also add attributes. Let’s make another subclass of PSPythonStuff. At the bottom of PSPythonStuff.py add

class PSStillMorePythonStuff(PSPythonStuff):
    def __init__(self,a,b,c):
        PSPythonStuff.__init__(self ,a,b)
        self.c=c
    def montyPythonFunction(self):
        return self.a+self.b*self.c
    def printMontyPythonFunction(self,myString):
        print(myString,self.a,self.b,self.c, self.montyPythonFunction())

add to class_demo_3

another_instance = PSStillMorePythonStuff(1,2,3)
print(another_instance.montyPythonFunction())
another_instance.printMontyPythonFunction('hello')

Save and run. Our code works. Most of object-oriented programming is subclassing and overriding what already exists. There is a special case of inheritance, known as an abstract class. Next time, we’ll talk about the abstract class pattern.

The Slippy Flippy Dare: Making a Basic Obstacle

icon2_120To make a game fun there must be a challenge. One of those challenges is some obstacle in your path or headed towards you.  In both Flappy Bird and SlippyFlippyPenguin that  obstacle is a large rectangle with a gap in it. Your job is to get through the gap. If you do, you  score a  point.

In this post, we’ll make a basic obstacle. In the next part of this series, we’ll turn that obstacle in to the pipes of Flappy Bird or the ice caves of SlippyFlippyPenguin

Make a Simple Obstacle

To start making  an obstacle, we will start with a new method,

-(void)makeObstacle{
     UIColor *obstacleColor = [UIColor blueColor];
     CGSize obstacleSize = CGSizeMake(64, 128);
     SKSpriteNode *obstacle = [SKSpriteNode spriteNodeWithColor:obstacleColor size:obstacleSize];
     obstacle.name = @"obstacle";
     [self addChild:obstacle];
}

Next we need to call this method. To start, place the method  towards the end of initWithSize:, just under the [self addChild:penguin] line in the code from the last installment.

[self addChild:penguin];
//make and add an obstacle to the scene
[self makeObstacle];

we now have a small rectangle in the bottom left corner.

iOS Simulator Screen shot Apr 3, 2014, 8.44.49 AM

By default our position is (0,0).  We are seeing a quarter of the rectangle, since our anchor point is the center of the sprite by default.   We need to move the obstacle to the right edge, and center it.

I realized in the last installment, I used but neglected to mention a set of very useful functions that we will use extensively. Repeatedly, I will mention the problem of screen fragmentation.  My iPhone4 has a different size than my iPhone 5. The phones have a different screen size than an iPad.  It becomes very difficult to position anything to an absolute point. Instead we work from a relative value. To help, we have the following functions, which you can read about in Apple’s CGGeometry Reference Guide

Getting Min, Mid, and Max Values
CGRectGetMinX
CGRectGetMinY
CGRectGetMidX
CGRectGetMidY
CGRectGetMaxX
CGRectGetMaxY
Getting Height and Width
CGRectGetHeight
CGRectGetWidth

We can use these functions with the frame of our scene and identify points relative to the top, bottom, left and right side of the visible scene.

To move our obstacle to the center of the scene we would add to our makeObstacle: method

obstacle.position = CGPointMake(CGRectGetMidX(self.frame ),CGRectGetMidY(self.frame));

Run and build. We have an obstacle in the center, obscuring the penguin.  Change the position property to CGRectMaxX(self.frame) instead:

obstacle.position = CGPointMake(<strong>CGRectGetMaxX(self.frame)</strong>, CGRectGetMidY(self.frame));

This creates a blue rectangle that is sitting halfway off the scene on the right edge of the scene. For illustration and debugging purposes, we will keep the obstacle visible for the moment.

iOS Simulator Screen shot Apr 3, 2014, 9.22.50 AM

Move an Obstacle

Next we need to move the obstacle.  Add the SKAction lines in bold below:

-(void)makeObstacle{
     UIColor *obstacleColor = [UIColor blueColor];
     CGSize obstacleSize = CGSizeMake(64, 128);
     SKSpriteNode *obstacle = [SKSpriteNode spriteNodeWithColor:obstacleColor size:obstacleSize];
     obstacle.position = CGPointMake(CGRectGetMaxX(self.frame), CGRectGetMidY(self.frame));
     obstacle.name = @"obstacle";
     <strong>SKAction *obstacleAction = [SKAction moveToX:0.0 duration:4];</strong>
     <strong>[obstacle runAction:obstacleAction];</strong>
     [self addChild:obstacle];
}

Build and run. The obstacle moves from one edge to the other in four seconds, passing over the penguin in the process.

It’s important for memory and performance reasons to get rid of an obstacle after we finish using it.  Change this line

[obstacle runAction:obstacleAction];

to this:

[obstacle runAction:obstacleAction <strong>completion:^{[obstacle removeFromParent];}</strong>];

After we run the action, we remove the obstacle from the node tree.   Build and run.

Set Game Play for the Obstacle

Change the update: method to match this

-(void)update:(CFTimeInterval)currentTime {
/* Called before each frame is rendered */
     SKNode *penguin =[self childNodeWithName:@"penguin"];
     CGPoint position = penguin.position;
     if (++position.y <= CGRectGetMidY(self.frame)){
          [[self childNodeWithName:@"penguin"] setPosition:CGPointMake(++position.x, ++position.y) ];
     }
<strong>
//Code to make an obstacle appear if we do not have one.
     if (![self childNodeWithName:@"obstacle"] ){
          [self makeObstacle];
     }</strong>

}

Build and run. Now our obstacle crosses the screen, disappears, and re-appears at the beginning again.  Note the display on the bottom telling us we only have two nodes.  We used the childNodeWithName: method every frame to find if there were any obstacles in the node tree. If there isn’t, we can make an obstacle. The obstacle will eventually destroy itself and then the next frame will make a new obstacle.

However we don’t want the obstacle to start before the game does. We start the game with a touch, and the penguin becomes subject to gravity as we see here:

-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
 /* Called when a touch begins */

     if ([touches count]>0) {
          SKNode *penguin =[self childNodeWithName:@"penguin"];
          if (penguin.physicsBody.affectedByGravity){ // game play on
               [penguin.physicsBody applyImpulse:CGVectorMake(0, 0)];
               [penguin.physicsBody applyImpulse:CGVectorMake(0, 7)];
          } else{ //game play off -- begin game
               penguin.physicsBody.affectedByGravity = YES;
               penguin.physicsBody.density = 0.1;
          }
     }
}

We can  make a flag to say we are playing the game or not playing the game. However the penguin’s isAffectedByGravity  property is the same value as a playing/not playing BOOL value, so I just used that.

Change the if statement in update: to read

if (![self childNodeWithName:@"obstacle"] && penguin.physicsBody.affectedByGravity ){
[self makeObstacle];
}

Remove the [self makeObstacle] from initWithsize: Now build and run. When we tap the screen, the obstacle begins its  movement pattern.

Make the Obstacle Slide In and Out

We don’t want to see the obstacle appear or disappear.  Instead, we want the obstacle to slide onto the screen. We are now sure our animation works right. We can change its initial and ending position to be greater  and less than the frame’s MaxX and MinX. It will exist, but not be visible when it appears and disappears.  First in makeObstacle: change

obstacle.position = CGPointMake(CGRectGetMaxX(self.frame)<strong>+ 2.0* obstacle.size.width</strong>, CGRectGetMidY(self.frame));

We start two times the width of the obstacle off the screen. Run and build.  Now the obstacle slides into the scene.

Now change our SKAction the same way, so it move to a point two times the width of the obstacle before disappearing.

SKAction *obstacleAction = [SKAction moveToX:0.0 <strong>- 2.0 * obstacle.size.width</strong> duration:4];

Build and run. Our obstacle is now sliding in and out of the scene.

Add Physics

This looks good but the obstacle needs to collide with the penguin. Right now they pass through each other.  We need to active physics on the obstacle.

obstacle.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:obstacle.size];
obstacle.physicsBody.affectedByGravity = NO;
obstacle.physicsBody.allowsRotation = NO;

We made a physicsBody like the penguin’s, then changed a few flags. Gravity should not affect the obstacle. We also turn off rotation since we want to keep the obstacle vertical. Some collisions will send it spinning, a lot like Slippy now will as you play with him.

Build and Run. You can now bounce the penguin all over the screen, and against the obstacle. You can also get the penguin crushed, which I made my game over state.

iOS Simulator Screen shot Apr 3, 2014, 9.25.06 AM

allowsRotation is the first major difference between SlippyFlippyPenguin and Flappy Bird. When I had allowsRotation off by mistake and watched Slippy spinning out, I saw my penguin as a different game than Flappy Bird. Both games however score by getting through a gap in the obstacle, and our next installment I will change our current obstacle and make that gap.

</pre>
<h1>Completed code</h1>
<pre>
//
//  SFMyScene.m
//  slippyflippyPenguinDemo
//
//  Created by Steven Lipton on 3/20/14.
//  Copyright (c) 2014 Steven Lipton. All rights reserved.
//

#import "SFMyScene.h"

@implementation SFMyScene{

}

-(void)makeObstacle{
    UIColor *obstacleColor = [UIColor blueColor];
    CGSize obstacleSize = CGSizeMake(64, 128);
    SKSpriteNode *obstacle = [SKSpriteNode spriteNodeWithColor:obstacleColor size:obstacleSize];

    obstacle.position = CGPointMake(CGRectGetMaxX(self.frame)+ 2.0 * obstacle.size.width, CGRectGetMidY(self.frame));
    obstacle.name = @"obstacle";

    obstacle.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:obstacle.size];
    obstacle.physicsBody.affectedByGravity = NO;
    obstacle.physicsBody.allowsRotation = NO;

    SKAction *obstacleAction = [SKAction moveToX:0.0 - 2.0 * obstacle.size.width duration:4];
    [obstacle runAction:obstacleAction completion:^{[obstacle removeFromParent];}];
    [self addChild:obstacle];
}

-(id)initWithSize:(CGSize)size {
    if (self = [super initWithSize:size]) {
        /* Setup your scene here */

        self.backgroundColor = [SKColor colorWithRed:0.85 green:0.85 blue:1.0 alpha:1.0];
        //set up world physics
        self.physicsWorld.gravity = CGVectorMake(0.0, -3.5); //set to -5 to -9
        //a physics body to prevent the penguin from going off the screen.
        self.physicsBody = [SKPhysicsBody bodyWithEdgeLoopFromRect:self.frame];

        /* Make a penguin */

        //Initialize a sprite with a texture from a file.
        SKSpriteNode *penguin = [SKSpriteNode spriteNodeWithImageNamed:@"gray penguin"];
        penguin.position = CGPointMake(0, 0);
        penguin.name = @"penguin";
        penguin.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:penguin.frame.size];
        penguin.physicsBody.affectedByGravity = NO;
        //set mass
        penguin.physicsBody.density = 0.1;

        SKAction *movePenguin = [SKAction moveTo:CGPointMake(CGRectGetMidX(self.frame), CGRectGetMidY(self.frame)) duration:2.0];
        [penguin runAction:movePenguin];

        [self addChild:penguin];
        //make and add an obstacle to the scene
       //[self makeObstacle];
    }
    return self;
}

-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
    /* Called when a touch begins */

    if ([touches count]>0) {
        SKNode *penguin =[self childNodeWithName:@"penguin"];
        if (penguin.physicsBody.affectedByGravity){ // game play on
            [penguin.physicsBody applyImpulse:CGVectorMake(0, 0)];
            [penguin.physicsBody applyImpulse:CGVectorMake(0, 7)];
        } else{ //game play off -- begin game
            penguin.physicsBody.affectedByGravity = YES;
            penguin.physicsBody.density = 0.1;
        }
    }
}

-(void)update:(CFTimeInterval)currentTime {
    /* Called before each frame is rendered */
    SKNode *penguin =[self childNodeWithName:@"penguin"];
    CGPoint position = penguin.position;
    if (++position.y <= CGRectGetMidY(self.frame)){
        [[self childNodeWithName:@"penguin"] setPosition:CGPointMake(++position.x, ++position.y) ];
    }
    if (![self childNodeWithName:@"obstacle"] && penguin.physicsBody.affectedByGravity ){
        [self makeObstacle];
    }

}

@end

From Apple to Raspberry Pi: Importing Classes and Disturbing Attributes.

appleberryI didn’t do as much As I thought I would today, as I was installing tightvnc on the Raspberry Pi. I then tried out acessing my RasPi on my Mac, Pc, and even my iPad mini. I wasn’t nuts enough t try it on my iPhone — yet. I did download the app though.

pi on ipad
A view of my Raspberry Pi from my iPad Mini.

 

This should speed up the programming development side of things. Now, we are exploring classes.

Importing a Class

In our last installment, we learned how to make classes in Python. So we have something fresh to work with, open a new window and add this class:

#PSPythonStuff.py
class PSPythonStuff:
    def __init__(self,a,b):
        self.a = a
        self.b = b
        self.penguin = 0

    def myPythonFunction(self,a,b):
        return a+b*b
    def montyPythonFunction(self):
        return self.a+self.b*self.b
    def montyPenguinFunction(self):
        return self.a + self.penguin * self.penguin

Save it as PSPythonStuff.py. We  created four functions in the class:

  • A constructor for the class
  • A function which computes a value all from parameters
  • A function which computes a value all from attributes
  • Another function which computes a value from attributes

In XCode, I am used to getting a custom class into another implementation file by using something like this:

#import "PSPythonStuff.h"

In Python we obviously don’t have a header declaring types for everything. Instead we open the implementation file, which needs to be in the same directory as the file loading it. If the class file, called a module contains multiple classes we can select the classes we want to load, and skip the ones we don’t. We can load all classes in the module like this:

from PSPythonStuff import *

Now open a new window and let’s test this. Type in the following code:

#class_demo_2

from PSPythonStuff import *

my_instance = PSPythonStuff(5,25)

print(my_instance.myPythonFunction(5,25))

print(my_instance.montyPythonFunction())

my_instance.a = 4
print(my_instance.montyPythonFunction())

print(my_instance.montyPenguinFunction())

Save this as class_demo_2.py and run this code. If all goes correctly you should get the numbers

630
630
629
4

printed on your console. Besides using functions of the class, we also re-assigned an attribute with a new value.

The Disturbing Attribute

Go back to the PSPythonStuff.py module. Remove the following line of code:

self.penguin = 0

Now go back to class_Demo_2 module, and run it again. It should be no big surprise what happens:

   return self.a + self.penguin * self.penguin
AttributeError: 'PSPythonStuff' object has no attribute 'penguin'

We used penguin as an attribute and it is not defined anywhere. Add the following to just above the last print line in the module

my_instance.penguin = 25

your code should now look like this:

#class_demo_2

from PSPythonStuff import *

my_instance = PSPythonStuff(5,25)
print(my_instance.myPythonFunction(5,25))
print(my_instance.montyPythonFunction())
my_instance.a = 4
print(my_instance.montyPythonFunction())
my_instance.penguin = 25
print(my_instance.montyPenguinFunction())

Save and run your code. The console gives the following

630
 630
 629
 629

That this works disturbs me. It is as disturbing as someone grafting a third arm on, then playing the guitar with it minutes later. It should not run and the Python interpreter should have a hissy fit about adding an attribute to a class outside of the class definition. But that would be Xcode freaking out, not Python. Python apparently doesn’t care if you pull this. It puts a lot of responsibility on the programmer. Here’s where it gets us into trouble. There might be an attribute in one instance of a class that isn’t in another. Trying to reference that attribute could cause a fatal error.

I’m sure Python has its reasons for this, but coming from a much more structured environment it scares the willies out of me what bugs will lie in the code I’ll write.

SlippyFlippy 1.1: Adding a Fading-in and out Label with Background in SpriteKit

icon2_120Today we have a bug to deal with in SlippyFlippyPenguin. There are a two reports of when a user selects the hard skill level  the game  immediately goes to game over. I cannot find anything that is different in the code to account for this except user error. I think the user error is users not realizing how fast they have to take controls in the hard mode. The penguin drops to the bottom, and ends the game before they can react. I’ve had more reports from a lot other users that is a user problem.  It is the speed that flippy drops after pressing the button that gets them. The  game is not clear about Slippy touching the sides or about what you are to do — and all of that  happens fast.

So here is what I’m going to do.

  • Add directions as messages that appear and disappear.
  • Add a countdown timer before starting

I’ll  implement this in two stages. Lets’ start with placing a message on the screen. What we need to do is flash a string on the screen, then make it disappear.

-(void)flashMessage:(NSString *)message atPosition:(CGPoint)position duration:(NSTimeInterval)duration{
//a method to make a sprite for a flash message at a certain position on the screen
//to be used for instructions

//make a label that is invisible
     SKLabelNode *flashLabel = [SKLabelNode labelNodeWithFontNamed:@"MarkerFelt-Wide"];
     flashLabel.position = position;
     flashLabel.fontSize = 17;
     flashLabel.fontColor = [SKColor blackColor];
     flashLabel.text = message;
     flashLabel.alpha =0;
     flashLabel.zPosition = 100;
     [self addChild:flashLabel];
//make an animation sequence to flash in and out the label
     SKAction *flashAction = [SKAction sequence:@[
           [SKAction fadeInWithDuration:duration/3.0],
           [SKAction waitForDuration:duration],
           [SKAction fadeOutWithDuration:duration/3.0]
]];
// run the sequence then delete the label
[flashLabel runAction:flashAction completion:^{[flashLabel removeFromParent];}];

}

Pretty straightforward code, and the comments make clear each of our steps:

  • Make a label node
  • Set its properties, and make it invisible
  • Make an action that fades in the label, shows it, then fades it out
  • Run the action, then remove the sprite.

Couple of items to note here: it’s important to set the z-height to 100, so the messages are not obscured by anything in the game. A new method for me  was runAction:completion: which here immediately removes the node when the animation is done. I think this will be a good practice, and will be a modification to what I actually did in the SlippyFlippy challenge when I write about it shortly.

We implement that method in the touchesBegan: code when we select our difficulty level;

else if (CGRectContainsPoint(hardRect, location)){
                //   NSLog(@" Hard TOUCH!!");
                [self flashMessage:@"Avoid the sides" atPosition:CGPointMake(CGRectGetMidX(self.frame), CGRectGetMaxY(self.frame)*0.1) duration:3];
                [self flashMessage:@"Avoid the sides" atPosition:CGPointMake(CGRectGetMidX(self.frame), CGRectGetMaxY(self.frame)*0.8) duration:3];
                [self flashMessage:@"Tap the screen to move Penguin" atPosition:CGPointMake(CGRectGetMidX(self.frame), CGRectGetMaxY(self.frame)*0.65) duration:1];
                [myLabel removeFromParent];
                [[self childNodeWithName:@"easy button"] removeFromParent];
                [[self childNodeWithName:@"hard button"] removeFromParent];
               
Notice I keep everything a relative position, a percentage of the full screen. This helps with the screen size fragmentation problem, and keeps everything proportional. 

We end up with this: iOS Simulator Screen shot Apr 1, 2014, 7.39.46 PM

This is good, but it needs a background to stand out more. So I made two more nodes: a SKNode as a container, and a SKSpriteNode as a background. I’ll put the label and the Sprite into the node and then animate the node. Note I had to set the label’s verticalAlignmentMode to center from its default baseline alignment. Otherwise our positioning is on the baseline of the text, and fails to align with the background.

 
-(void)flashMessage:(NSString *)message atPosition:(CGPoint)position duration:(NSTimeInterval)duration{
//a method to make a sprite for a flash message at a certain position on the screen
//to be used for instructions

//make a label
     SKLabelNode *flashLabel = [SKLabelNode labelNodeWithFontNamed:@"MarkerFelt-Wide"];
     flashLabel.verticalAlignmentMode = SKLabelVerticalAlignmentModeCenter;
     flashLabel.fontSize = 17;
     flashLabel.fontColor = [SKColor whiteColor];
     flashLabel.text = message;


//make a background based on the size of the label
     CGSize mySize = flashLabel.frame.size;
     mySize.height *=1.5;
     mySize.width *= 1.2;
     SKSpriteNode *background = [SKSpriteNode spriteNodeWithColor:[UIColor redColor] size:mySize];

//make a container node
     SKNode *flashLabelNode = [SKNode node];
     flashLabelNode.position = position;
     flashLabelNode.zPosition = 100;
     flashLabelNode.alpha = 0;
     flashLabelNode.name = @"flashLabelNode";
//add the node tree together
     [flashLabelNode addChild:background];
     [flashLabelNode addChild:flashLabel];
     [self addChild:flashLabelNode];

//make an animation sequence to flash in and out the label
     SKAction *flashAction = [SKAction sequence:@[
          [SKAction fadeInWithDuration:duration/3.0],
          [SKAction waitForDuration:duration],
          [SKAction fadeOutWithDuration:duration/3.0]

     ]];
// run the sequence then delete the label
     [flashLabelNode runAction:flashAction completion:^{[flashLabelNode removeFromParent];}];

}

So our steps here are:

  • Make the SKLabelNode
  •  Make a background slightly bigger than the label’s size with a SKSpriteNode.
  • Make a SKNode as a container, then add the label and sprite to the node.
  • Make the action, though this time directed at the SKNode instead of the SKLabelNode
  • Perform the action, then remove the node.

iOS Simulator Screen shot Apr 1, 2014, 7.38.04 PMThis works but it leaves a bit of a problem. I don’t get rid of the labels when I need to. In a game over situation, the labels are still there, but I don’t want them there. I need to remove the labels completely at a game over state.

Lets remove all flash labels in one purge using the enumerateChildNodesWIthname:usingBlock: method

-(void)removeAllFlashMessages{

     [self enumerateChildNodesWithName:@"flashLabelNode" usingBlock:^(SKNode *node, BOOL *stop) {
          [node removeAllActions];
          [node removeFromParent];
     }];
}

iOS Simulator Screen shot Apr 1, 2014, 7.38.13 PMThat works great. I might want to identify the labels so I can get rid of them at events, but I’ll do that later.

Next time,  we will do the countdown timer.

SlippyFlippy 1.1: Making a High and Low Score Indicator

icon2_120This is the first of my improvements to the SlippyFlippy penguin game.  While this may not make sense since I have not posted all the game code yet, it might help those trying to come up with some of these solutions for their own games. While playing against  some of my friends on our different devices, we found we need a different score for the hard mode and easy mode. In the hard mode, the game ends if the penguin contacts the top or bottom walls.  In the easy mode the penguin bounces off the top and bottom walls.

There is a bit of a real estate problem about putting two scores on the screen.  The solution is to fade in one high score, then fade it out, then fade the other one in, then fade that one out. This repeats forever.

My current code for changing the label looks like this:

highScoreLabel.text = [NSString stringWithFormat:@"High Score: %li",(long)highScore];

It’s just setting the labels text.  This shows up at setup and game over. Since it shows up in two places, I’ll make a method for the animation. Before I do, I need to find and store the high score. I look at the game over code in update:

if (highScore < score ){
highScore = score;
highScoreLabel.text = [NSString stringWithFormat:@"High Score: %li",(long)highScore];
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
[defaults setInteger:highScore forKey:@"highScore"];
[defaults synchronize];

}

If we have a high score, we do two things. We first display the new high score, and secondly we save the new high score to NSUserDefaults.  I introduced an new NSInteger called highScoreHard. With this addition, there are two situations instead of one where we need to process a high score, so the if has to reflect both:

if ((highScore < score && isEasyMode) || (highScoreHard < score && !isEasyMode)){

The BOOL isEasyMode is set when we select the mode we want to use. If we are in easy mode and there is a new high score, or if we are in hard mode and we have a new high score,  we need to post a new high score. We can now use isEasyMode to post the score to the right place:

if (isEasyMode)
highScore = score;
else
highScoreHard = score;

Our last change to the game over code is to add another key entry to the NSUserDefaults entries under defaults.

[defaults setInteger:highScoreHard forKey:@"highScoreHard"];

If we stub our animation method in makeHighScoreAnimate  for the moment, this snippet of code changes to:

if ((highScore < score && isEasyMode) || (highScoreHard < score && !isEasyMode)){
if (isEasyMode)
highScore = score;
else
highScoreHard = score;

[self makeHighScoreAnimate];
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
[defaults setInteger:highScore forKey:@"highScore"];
[defaults setInteger:highScoreHard forKey:@"highScoreHard"];
[defaults synchronize];

}

We now need to read the high scores when we start the app in initwithSize:.  We have another entry in defaults with a new key. That segment of code in initwithSize: looks like this now:

//grab the last high score from persistent memory
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
highScore = [defaults integerForKey:@"highScore"];
highScoreHard = [defaults integerForKey:@"highScoreHard"];
[self makeHighScoreAnimate];

We have one more thing to do and that is make the animation code.

-(void)makeHighScoreAnimate{
//remove the old high score animation, if there
[highScoreLabel removeActionForKey:@"highScoreAnimate"];

//makes strings for the two scores
NSString *highScoreLabelText = [NSString stringWithFormat:@"Easy High: %li",(long)highScore];
NSString *highScoreLabelHardText = [NSString stringWithFormat:@"Hard High: %li",(long)highScoreHard];
//Create the animation sequence and run it forever.
SKAction *highScoreAnimateSequence = [SKAction sequence:@[
[SKAction runBlock:^{highScoreLabel.text = highScoreLabelText;}],
[SKAction fadeInWithDuration:1.00],
[SKAction waitForDuration:3.0],
[SKAction fadeOutWithDuration:1.0],
[SKAction runBlock:^{highScoreLabel.text = highScoreLabelHardText;}],
[SKAction fadeInWithDuration:1.00],
[SKAction waitForDuration:3.0],
[SKAction fadeOutWithDuration:1.0],
]];
SKAction *highScoreAnimate = [SKAction repeatActionForever:highScoreAnimateSequence];

//put the action in the label
[highScoreLabel runAction:highScoreAnimate withKey:@"highScoreAnimate"];
}

We remove the old high score first. If there is no SKaction there, it will do nothing.  To make the coding easier to read,  we make two strings highScoreLabelText and highScoreLabelHardText to hold the two high scores and titles.  We make an SKAction sequence, which is an array of SKActions. If you have something other than an SKAction that you want to do, you can add it in a runBlock: method, as we did with changing the titles.  I then take the sequence and repeat it forever.

I run the SKAction to the highScoreLabel and give it a key so I can remove it when I need to change it.  Now when I build and run, the two high scores fade in and out.

from Apple to Raspberry Pi: Making Classes in Python

appleberryObjective-C and Python are similar when it comes to defining new classes, but be careful with their differences. In Objective-C we would define a class with two files: a header and an implementation file. In the header we would declare properties like this

@interface PDPythonStuff : NSObject
     @property int a;
     @property int b;
@end

And possibly public methods

@interface PDPythonStuff : NSObject

     @property int a;
     @property int b;

     +(int)myFunction:(int)a b:(int)b;
     -(int)montyFunction:(int)a b:(int)b;
     -(int)montyFunction;
@end

In the implementation file we would have the code for the methods

@implementation PDPythonStuff

+(int)myFunction:(int)a b:(int)b{
    return a+b*b;
}

-(int)montyFunction:(int)a b:(int)b{
    return a+b*b;
}
-(int)montyFunction{
    return self.a+self.b*self.b;
}

@end

Finally we import the class into another class we are working with, such as a ViewController subclass

#import "PDMontyPython.h"

We would set up a property of the subclass for our instance

@interface PDViewController ()

    @property PDPythonStuff *montyPython;

@end

Allocate space and initialize the instance

    PDPythonStuff *montyPython = [[PDPythonStuff alloc]init];

We are now free to use it. A very simple example would be this which executes with the press of a button:

@implementation PDViewController{

}
- (IBAction)myButtonPressed:(UIButton *)sender {
    //calling the class method
    NSLog(@"myFunction PDPythonStuff = %i",[PDPythonStuff myFunction:5 b:25]);

    //initialize an instance
    PDPythonStuff *montyPython = [[PDPythonStuff alloc]init];
    //the method with parameters
    NSLog(@"myFunction montyPython = %i",[montyPython montyFunction:5 b:25]);

    //set the properties
    montyPython.a=5;
    montyPython.b=25;

    //the method using properties
    NSLog(@"myFunction montyFunction = %i",[montyPython montyFunction]);

}

@end

Xcode does a lot to make the class without our working for it. There are no constructors, setters or getters that need implementation, like Java or C++. Prior to XCode 4.4, you did need the @synthesize, but even that isn’t necessary anymore. It’s all automatic or not needed. Granted, you can make you own setters and getters, but it isn’t mandatory.

Python’s class definitions are quite interesting in that context:

#Objects_01
class PDPythonStuff:
    def __init__(self,a,b):
        self.a=a;
        self.b=b;
    def myFunction(self,a,b):
        return a + b*b

    def montyFunction(self):
        return self.a + self.b * self.b

# test implementation of the class
c=PDPythonStuff(5,25)
print('my Function =',c.myFunction(5,25))
print('my Function =',c.myFunction(4,25))
print('my Function =',c.montyFunction())
c.a = 4
print('my Function =',c.montyFunction())

Like defining functions, Python is super simple in defining classes. We don’t need to define what is public or private, or what is a class or instance method. With all those definitions missing, our code is a lot smaller. We start with a class operator name, then have a series of functions in the class. The first function among them __init__ is very important. As we saw above, Objective-C does have an init method, and can set beginning values for the instance. In Python __init__ is the constructor for the class. We do not have a header .h file in Python like Objective-C to declare what our properties are. Therefore we must declare their existence somewhere and the best place is in __init__.

Add the following function to the class:

    def montyFunctionToo(self):
        return self.a + self.d *self.d

Now add under the other print functions

print('my Function =',c.montyFunctionToo())

Save and run. You will get a error:
AttributeError: 'PDPythonStuff' object has no attribute 'd'

Nowhere did we define a what I would call a property in XCode, or attribute in Pythonspeak, called d. Python is angry at us for that. In the __init__ add:

self.d = 10

Save and run again, and things will work fine again. You do not have to put the initial value in the parameter list.

Note the first parameter in each def here is self. It is mandatory for methods of a class to have self as the first parameter in the definition. So we have

def myFunction(self,a,b):
        return a + b*b

We do not need self when we call the method:

print('my Function =',c.myFunction(4,25))

Note the def for a  function that has no parameters still has self.

  def montyFunction(self):
        return self.a + self.b * self.b
...
print('my Function =',c.montyFunction())

Now that we can make some classes, we can start to use them in Python. We’ll discuss more about classes and some cautions about them in our next entry.

From Apple to Raspberry Pi: Transitioning into Functions.

appleberryWhen I started Making App Pie, one of my big frustrations was wrapping my head around defining methods. I was used to C++ and Java functions. Objective-C and its Smalltalk roots just threw me. Now going into Python is difficult too — but for another reason. Once again dynamic typing in Python rears up to make things different in defining functions.

Simple functions are not that difficult to define though. Just use the def keyword.

def my_function(a,b):
    c=a+b*b
    return c

This looks simple enough. def works great in this situation. Dynamic typing means there is no specifying the return type or the types of the parameters. For the  same reason it’s simple,  def can cause some big run time errors. If somewhere in your program there was:

my_function(5,'cute')

There would be a fatal TypeError exception. Even Python can’t multiply strings together. With a few notable exceptions, in Objective-C as a static typed, compiled language, this generally cannot occur. In an interpreted language with dynamic type like Python this isn’t caught until run time, when it is too late. So when working in Python, ether type checking or good error handling are a good idea.Exception handling uses the try:...except: clause. For our function above, this would look like:

def my_fun(a,b):
    try:
        c=a+b*b
        return c
    except TypeError:
        return 'TypeError' 

print(my_fun(5,'cute'))

We place the code where the error may occur after the try:. In the case of an exception, one or more except: handlers do something other than crash the program.

What I return in the case of a TypeError could be a problem too.  In the case above, what I return is a string TypreError. If I always check for type errors wherever this function gets called, this will be okay. If I just use the function in some other mathematical expression, the TypeError will then happen there. I could also return 0 in the case of a type error, though it might mess up the math I was trying to do, or make a bug very difficult to trace.

Besides exception handling, I could type check. Python’s  function isinstance() returns a boolean value of an object given a target type or class.

def my_fun_too(a,b):
    if isinstance(a,int) and isinstance(b,int):
        c=a+b*b
        return c
    else:
        return 0

This works, sort of. I can now use the function, but only for two integers. If I want one of the two, or both of the numbers to be float values, I would get zero for a result. Python has a form of NSArray which makes a unmutable ordered collection called a tuple. We can put a tuple in the isinstance() function of all the types we will accept for calculations.

def my_fun_too(a,b):
    if isinstance(a,(int,float)) and isinstance(b,(int,float)):
        c=a+b*b
        return c
    else:
        return 0

An alternative to this code would be this snippet, using a second function to let numbers only into the calculation before we do the calculation in the my_fun function.

def cast_number(a):
#returns floats and int, makes everything else 0
    if isinstance(a,(int,float)):
        return a
    else:
        return 0

def my_fun_three(a,b):
    b = cast_number(b)
    c= cast_number(a) + b*b
    return c

The big change between Python and any of the compiled languages like C, C++, Java, or Objective-C is that the compiler demanding static typing handles much, if not all of this for us. In Python we need to be very careful about what types end up in a function’s parameter, and for every function deal with the eventuality that something that doesn’t belong there will end up in a place it could break our program. Of course the upside of Python is we do not, as in Objective-C have both an int and an float method to write code for — its just one function.