Just another "PicPong" project ! Why ?
-------------------------------------
Considering the already existing PIC based pong games, the main goals of this little project were:
- Keeping a very common and easily programmable PIC16F84 (featuring no A/D input)
(However, in case of obsolescence the P16F628 can be used instead)
- Using two potentiometers for controls, as in the original pong games (+ 2 pushbuttons)
(Yes, this is possible without A/D input!)
- Generating a B/W composite video with a moderated contrast (background luminance) and a grey scale
(to save the CRTs and give a better visual feeling).
- Having some simple sounds (beeps) available
- Providing a modular and re-usable SW kit useable for developping other simple games. And this should
be possible without taking care on how the video signal generation works, how potentiometer
positions are coded via digital data, and how pushbuttons are debounced
- Allowing a REALLY easy development of other games without taking care of real-time constraints, because
the video and peripheral handling processes are preemptive and behave as an OS.
- Leaving the unused I/O ports free for any specific use if needed (LED, additional switch...)
- Addressing pixel lines/columns in a way which simplifies the handling of objects moving just
vertically. (Price to pay: reduced game field width and bigger pixels, compare to "competitors")
A lot of these requirements are met in already existing projects but not at the same time.
I have to admit that the video memory handler in existing "competitors" is often more optimized than in
my system(*) but it is also less flexible. It is quite difficult to start developping a new game based on
these existing source codes without getting deeply into the complete stuff.
(*) E.g: Game field over zone the full screen width, smaller pixels, lower system clock and even character
generation that my SW kit doesn't support
About the characteristics of the pong game itself, the goal was to implement:
- Progressive ball acceleration while the game is played
- Selectable starting speed before launching the game
- Ball bouncing direction (up/down) which can be impacted when the ball is hit by a pad extremity
- Player lives displayed as dots under the game field zone (directly handled by video process)
General characteristics:
-----------------------
* Video standard: European 625 lines black and white composite video (abusively called "PAL")
* Potentiometer position estimation method (for game controls):
Periodical discharging time measurement of an RC network where R is the potentiometer
* Visible game field: array of 14 columns x 15 lines, written at 1/0 to set/clear pixels
How to play
-----------
Pushbutton 1 is used to:
- Launch a new game
- Launch a new ball for the next run after one player has lost
Pushbutton 2 is used to increase ball speed on start-up (one press before PB1 is pressed)
Potentiometers are naturally used to control the left and right paddles.
Remaining lives are displayed with dots at the bottom of the screen.
Development howto's for reusing this design:
-------------------------------------------
The only part of code that you need to edit starts at the following notice:
;**************************************************************************
;*************************** Game Setup ******************************
;**************************************************************************
Then it ends at:
;************************************************************************************
; Wait for timer value (sent in TTARGET) with no jitter
;************************************************************************************
Therefore, except for your own information you don't have to take care about the rest
of the code which is related to video and peripheral handling. Note that you must not
change the interrupt settings or even use interrupts or write to TMR0 in your game
applicative code. This would flaw the video handler. Other reference time bases are
available (see further).
Naming conventions:
------------------
In this explanation document:
The term "game field" describes the screen area where pixels can be set and cleared by
the game application code.
Any visible object (made from a single pixel or from multiple pixels) moving over the game
field will be called "sprite" (old-fashioned video game terminology).
The single word "line" will not mean "video line" but a pixel line of the game field
(pixels have an actual height of 32 interlaced video lines).
INTERFACING YOUR CODE WITH THE VIDEO HANDLER AND PERIPHERALS:
------------------------------------------------------------
Your program will have the following inputs:
- bit PB1: Debounced pushbutton 1 (true = pressed)
- bit PB2: Debounced pushbutton 2 (true = pressed)
- byte Pt1Lev: Potentiometer 1 position (from 0 to 14)
- byte Pt2Lev: Potentiometer 2 position (from 0 to 14)
- bit Tick: Set by the video handler at each new video half-frame. To be reset by your
code after reading. To be used as a 20ms time base for game related counters/events.
(Example in the PicPong game: byte "Frcnt" runs as a time base for ball related timings)
- bit Ssig: Set and reset by the video handler only. To improve quality of sprite moves,
it is better to wait that this bit is set before moving multi-pixel complex sprites.
(Example in the PicPong game: this is used to move paddles, but is not needed for the
simple ball). In case of slow moves (less than 1 move / 8 frames), this procedure is
not needed at all because visual perception will be more tolerant to artefacts.
- Any eventual unused I/O port that you would decide to use (and eventually to debounce
by yourself).
Your program will have the following outputs:
- byte Llives: Number of displayed dots on screen, under the game field, on the left side
- byte Rlives: Number of displayed dots on screen, under the game field, on the right side
- byte Audpt: Cleared to stop any audio signal. Filled with a square wave pattern to play
the corresponding signal.
Examples: B'11110000" = lowest frequency, B'10101010' = highest frequency.
In case of long audio signals (longer than a 1-frame beep), the tone will be hacked by
short gaps with a 20ms periodicity (causing some kind of "ringing" effect).
- byte array HIPTAB: Ranging from address HIPTAB to (HIPTAB+13), this array contains the
pixel states of the game field upper 8 lines. (See "handling video memory")
- byte array LOPTAB: Ranging from address LOPTAB to (LOPTAB+13), this array contains the
pixel states of the game field lowest 7 lines. (See "handling video memory")
- Any eventual unused I/O port that you would decide to use
Handling the video memory
-------------------------
The upper and bottom pixel arrays defining the game field are handled in the same way:
- The byte address defines the column (BaseAddr+0 = left border, BaseAddr+13 = right border)
- The bit 0 of the addressed byte defines the upper line, and bit 7 the lowest line
- Example in the upper game field part: To set a pixel on at column 3, line 4:
BSF (HIPTAB+3),4 (for column and line numbers starting at zero)
- Example in the lowest game field part: To set a pixel on at column 6, line 11:
BSF (LOPTAB+6),3 (because we have to substract 8: then 11 - 8 = 3)
- Of course it is strongly recommended to use the FSR for column selection and to use
two temporary bytes as cascaded shift registers to fill the column, so that game controlled
moves are made easily possible. See the "PicPong" game as example (paddle handling).
- When moving a sprite, it is simpler to first erase full columns (simple indexed CLRF
instructions) and then "redraw" the sprite by setting the corresponding pixels at their
new locations. This is also done like this in the PicPong game application.
List of bytes only related to game application, and which can be re-assigned:
----------------------------------------------------------------------------
Flags/bits defining game status:
Mvflag EQU 024H ; Move/status flags (depending on your game)
Bytes used as variables:
Xball EQU 020H ; Ball column index (game task only)
Yball EQU 021H ; Ball line index (game task only)
Lpady EQU 022H ; Left pad line index (game task only)
Rpady EQU 023H ; Right pad line index (game task only)
Frcnt EQU 025H ; Video frame counter used for game timings
Glpcnt EQU 026H ; Loop cunter used by game task only
Balspe EQU 027H ; Ball speed (high value = low speed)
Tmpvar EQU 028H ; Temporary variable (game task only)
Tmpv2 EQU 029H ; Temporary variable (game task only)
Accelc EQU 02AH ; Ball acceleration counter
All other byte addresses are reserved for the video handler and/or as
interface beetween it and your code.
New addresses can be used after "Audpt" and before "HIPTAB". If more
addresses are needed, then move HIPTAB and LOPTAB further while keeping the
same offset beetween them.
Have fun!
**************************************************************************************
OTHER EXISTING PROJECTS dealing with PIC based video pong games:
----------------------------------------------------------------
(Almost all named "PicPong")
http://www.rickard.gunee.com/projects/video/pic/pong.php
http://www.dos4ever.com/upong/upong.html
http://www.xxdave.wz.cz/?ContentPage=http://www.xxdave.wz.cz/www/elektro/color_pic_pong_PIC16F628A_PAL/
http://www.brouhaha.com/~eric/pic/picpong.html
http://dt.prohosting.com/pic/pong.html