It requires a little mental gymnastics at first but once you get used to the logic it comes easier. ChadH did the coding on the PIG 2 so he can answer more specific questions but I think I can relay some of the concepts.
Everything being processed is serial, one step at a time. Everything is based on a loop and it's the speed of the processor that give the illusion of several things happening at the same time.
Do Loop
Does Input 1 = High?
Yes
Set Output 1 High
No
Set Output 1 Low
Does Input 2 = High?
Yes
Set Output 2 High
No
Set Output 2 Low
Loop
Everything starts here. If there is a button on each input pin and an LED on each output pin. It would seem like the chip is doing two things at once. If you have one button pressed, one led is on, if you have them both pressed, it has both on. But you can see here, they are happening serially. It's that the chip is handling these operations in thousandths of a second. You can't see it happening.
To get more pinball functions, you need to keep track of a lot of stuff, like what is the clock time right now? What is the state of all of the inputs right now -- is that different than they were the last time I checked?
Lets say you want to make an LED blink, 1 second on and 1 second off while you're holding down the button connected to Input 1. (I'm assuming the button is a 5v source, on and off)
Boolean Input1State = False
Int Output1BlinkTime = 0
Do Loop
Does Input 1 = High?
Is Input1Sate = False?
Yes
Set Input1State = True
Output1BlinkTime = Millis()
No
If Millis() - Output1Blinktime () > 2000
Set Output1Blinktime = Millis()
If Millis() - Output1BlinkTime < 1000
Set Output 1 High
Else
Set Output 1 Low
Else
Does Input1State = True?
Set Input1State = False
Set Output1 Low
Loop
That's Pseudo Code so don't plug that into the IDE. And I apologize if there are bugs in that thinking I'm just streaming this out of my head.
The idea here is that you have to keep track of the timer, the state of the input, and what the state of the input was before in order to get the "Blink while I'm pressing the button" effect. You could add extra LED's and Buttons by recycling the above code and adding "Input2State", etc. You'd get two LEDS blinking at the same rate, but at different times based on when you pressed which button.
For more inputs and outputs, you can't put logic in like, "While I'm pressing the button" because then it will loop on that single output and ignore all the rest.
You may be thinking, "Holy crap, that's a lot to keep track of!" The more complex it gets, you start needing more powerful processors - or better code.
You can change how it performs based on how you structure the decision tree. The idea is to try to eliminate as many decisions as is practical. Also, say it takes 1/50th of a second to do a Serial.Write. If you do a single one, it's hard to notice. If you do 10 of them, suddenly you've got a .2 second pause which doesn't seem like much, but is an ETERNITY! You can demonstrate this by playing with the "BLINK" example in the arduino IDE.
A 1 second ON and 1 Second OFF blink is REALLY slow. You begin to realize that in pinball time, lamps go on and off several times a second when they are blinking. If you hold something up with a serial.write it becomes really noticeable.
OK, sorry, chew on that and we can build from there.