Shop Learn
a (try) version of pong — Parallax Forums

a (try) version of pong

I have never read an implementation of Pong and have wanted to work on it for a long time.
In principle, it works the way I thought it would. At times strange effects occur, but on the whole it is stable.
After the weekend, I can continue to take care of it.
At this version of pong the propeller plays against itself. The paddle position is calculated to hit the ball.
An expansion to several cogs is planned.

nice weekend
Reinhard

Comments

  • I believe the strange effect are gone with this workaround,
    but I have not a long time observed.
    LINE175		if(ym < 20 || ym > 470)
    
  • roglohrogloh Posts: 2,953
    edited 2020-07-17 11:28
    Hi Reinhard,

    I've modified your pong code to speed it up and it runs smoother now. Not so much flicker.
    You can use the fillCircle routine I included to draw circles of any colour and size, as well as
    syncing up to the blanking period to avoid tearing etc. Clearing the entire screen
    is slow, so you can erase just the ball and paddle. Take a look at what I changed.

    By the way, no need to distribute the entire video folder, just p2videodrv.spin2 is enough.

    Cheers,
    Roger.
    *
    +--------------------------------------------------------------------
    | TERMS OF USE: MIT License
    +--------------------------------------------------------------------
    Permission is hereby granted, free of charge, to any person obtaining
    a copy of this software and associated documentation files
    (the "Software"), to deal in the Software without restriction,
    including without limitation the rights to use, copy, modify, merge,
    publish, distribute, sublicense, and/or sell copies of the Software,
    and to permit persons to whom the Software is furnished to do so,
    subject to the following conditions:
    
    The above copyright notice and this permission notice shall be
    included in all copies or substantial portions of the Software.
    
    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
    EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
    MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
    IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
    CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
    TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
    SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
    +--------------------------------------------------------------------
    */
    
    
    #include <stdio.h>
    #include <string.h>
    #include <stdlib.h>
    #include <unistd.h>
    #include <math.h>
    
    #include <propeller2.h>
    #define P2_TARGET_MHZ 160
    #include "sys/p2es_clock.h"
    
    #define BAUD 230400
    
    // screen size
    #define SCRN_WIDTH 640
    #define SCRN_HEIGHT 480
    
    // VGA definitions
    #define VGA_BASE_PIN 48
    #define VGA_VSYNC_PIN (VGA_BASE_PIN + 4)
    
    // enough room for a scanline at full colour bit depth
    #define LINEBUFSIZE (1920*4)
    
    // RGBI8 colortable with full luminance
    #define ORANGE	0b000_11111
    #define BLUE	0b001_11111
    #define	GREEN	0b010_11111
    #define	CYAN	0b011_11111
    #define RED		0b100_11111
    #define	MAGENTA	0b101_11111
    #define	YELLOW	0b110_11111
    #define	WHITE	0b111_11111
    #define	BLACK	0
    
    // the video object
    struct __using("video/p2videodrv.spin2") vid;
    
    // space for video driver display and region info
    int display1[14];
    int first[14];
    
    // the actual frame and line buffer
    char frameBuffer[SCRN_WIDTH*SCRN_HEIGHT];
    int lineBuffer[LINEBUFSIZE];
    
    
    void Setup_Video()
    {
        vid.initDisplay(@display1, vid.VGA, VGA_BASE_PIN, VGA_VSYNC_PIN, vid.RGBHV, @lineBuffer, LINEBUFSIZE, 0);
    
        vid.initRegion(@first, vid.RGBI, 480, 0, 0, 0, 8, &frameBuffer[0], 0);
      
        // enable display list
        vid.setDisplayRegions(display1, first);
    }
    
    void line( int x0, int y0, int x1, int y1,int color)
    {
      int dx =  abs(x1-x0), sx = x0<x1 ? 1 : -1;
      int dy = -abs(y1-y0), sy = y0<y1 ? 1 : -1;
      int err = dx+dy, e2; /* error value e_xy */
    
      for(;;){  /* loop */
        plot(x0,y0,color);
        if (x0==x1 && y0==y1) break;
        e2 = 2*err;
        if (e2 > dy) { err += dy; x0 += sx; } /* e_xy+e_x > 0 */
        if (e2 < dx) { err += dx; y0 += sy; } /* e_xy+e_y < 0 */
      }
    }
    
    // routine to plot a point at screen coordinate (x,y) and color "color"
    void plot(int x, int y, int color)
    {
        frameBuffer[y*SCRN_WIDTH+x] = color;
    }
    
    void clearscreen (int color)
    {
    	// clear the screen
        memset(frameBuffer, color , SCRN_WIDTH*SCRN_HEIGHT);	
    }
    
    // Function for circle-generation
    // using Bresenham's algorithm
    void fillCircle(void *screen, int width, int xc, int yc, int r, int colour, int bpp)
    { 
        int x, y, d;
        x = 0;
        y = r;
        d = 3 - 2 * r;
        horizLine(screen, width, xc+x, yc+y, xc-x, yc+y, colour, bpp);
        horizLine(screen, width, xc+x, yc-y, xc-x, yc-y, colour, bpp);
        horizLine(screen, width, xc+y, yc+x, xc-y, yc+x, colour, bpp);
        horizLine(screen, width, xc+y, yc-x, xc-y, yc-x, colour, bpp);
        while (x <= y)
        {
            horizLine(screen, width, xc+x, yc+y, xc-x, yc+y, colour, bpp);
            horizLine(screen, width, xc+x, yc-y, xc-x, yc-y, colour, bpp);
            horizLine(screen, width, xc+y, yc+x, xc-y, yc+x, colour, bpp);
            horizLine(screen, width, xc+y, yc-x, xc-y, yc-x, colour, bpp);
            if (d > 0)
            {
                d = d + 4 * (x - y) + 10;
                y--;
            }
            else
                d = d + 4 * x + 6;
            x++;
        }
    }
    
    
    void horizLine(void *buf, int width, int x1, int y1, int x2,int y2, int c, int bpp)
    { 
        int  len = x1-x2 + 1;
        switch(bpp)
        {
        case 8:
          bytefill(buf + x2+y1*width, c, len);
          break;
        case 16:
          wordfill(buf + 2*(x2+y1*width), c, len);
          break;
        case 32:
          longfill(buf + 4*(x2+y1*width), c, len);
          break;
         default: return; // unhandled for now
       }
    }
              
    void ball(int x0,int y0, int radius, int color)
    {
    /*
    	int x,y,t;
    	unsigned int phi = 0;
    	for(t = 0; t < 2048; t++ )
    	{
    		__asm {
    			qrotate	#5, phi
    			getqx	x
    			getqy	y
    		};	
    		line(x0,y0,x0+x,y0+y,WHITE);
    		//plot(x0+x,y0+y,WHITE);
    		phi += 0x200000}
    */
    	fillCircle(&frameBuffer, SCRN_WIDTH*8/8, x0, y0, radius, color, 8); // 8bpp
    }
    
    void paddle (int ym, int colour)
    {
    	int yo = ym - 10;
    	int yu = ym + 10;
    	line(610,yu,610,yo,colour);
    }
    
    void main()
    {
         int i;
    	
        _clkset(_SETFREQ, _CLOCKFREQ);
        Setup_Video();
        _setbaud(BAUD);
        
        int xx = 20;
        int yy = 20;
        int dx = 5;
        int dy = 5;
        int ym = 230;
        float r;
        clearscreen(BLUE);
        for (;;)
        {
    //		clearscreen(BLUE);
    		ball(xx, yy, 5, WHITE);
    		paddle(ym, WHITE);
                    vid.waitforblanking(&display1);
                    ball(xx,yy, 5, BLUE);
    		paddle(ym, BLUE);
    		
    		//usleep(10000);
    		xx += dx;
    		yy += dy;
    		// check limits
    		if(xx < 20) dx = -dx;
    		if(xx > 620) dx = -dx;
    		if(yy < 20) dy = -dy;
    		if(yy > 460) dy = -dy;
    		
    		// check relation from ball to paddle
    		if ( ((xx+5) == 610) && 
    		     (((yy) < (ym-10)) || ((yy) < (ym+10)))  
    		   )
    			dx = -dx;
    			
    		if(dx > 0)
    		{
    			r = (float)((610 - xx) / dx);
    			ym = yy + (int)r * dy;
    		}
    		else
    			ym = ym;
    		
    		if(ym < 20 || ym > 460)
    		  ym = 230;
    	}
    
    
        	
    }
    
  • @rogloh
    Thanks for the many tips. I am currently out of my home and will only have my hardware again on Monday. I can't wait to try your version!
  • @rogloh
    Your improvements are great. I now have 2 players. Is it an advantage if I split that over 2 cogs (?).
    A sound output during ping would also be interesting.

    cheers
    Reinhard
  • Cool. You could split into two Cogs but it might be harder to write the overall logic that way. As long as both Cogs don't write to the same frame buffer address it could be done. There's so much power in a single Cog for this application its not really going to be worth doing. A separate Cog like what Ahle2 has written (or the P2 port of SIDCOG) would be good for your sound effects.

    You might like to figure out a way to slide your paddles up and down on each side more smoothly too (interpolate) when they figure out the final position instead of jumping, although the jumping effect still looks okay.

    This sort of makes a good screensaver.
Sign In or Register to comment.