<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>codetorment &#187; pong</title>
	<atom:link href="http://www.codetorment.com/tag/pong/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.codetorment.com</link>
	<description>code, tech, random stuff</description>
	<lastBuildDate>Tue, 07 Sep 2010 08:47:12 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>Arduino Pong using S65 Shield</title>
		<link>http://www.codetorment.com/2009/11/11/arduino-pong-using-s65-shield/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=arduino-pong-using-s65-shield</link>
		<comments>http://www.codetorment.com/2009/11/11/arduino-pong-using-s65-shield/#comments</comments>
		<pubDate>Wed, 11 Nov 2009 21:03:01 +0000</pubDate>
		<dc:creator>tom</dc:creator>
				<category><![CDATA[Arduino]]></category>
		<category><![CDATA[Code]]></category>
		<category><![CDATA[display]]></category>
		<category><![CDATA[game]]></category>
		<category><![CDATA[pong]]></category>
		<category><![CDATA[s65]]></category>
		<category><![CDATA[screen]]></category>
		<category><![CDATA[shield]]></category>

		<guid isPermaLink="false">http://www.codetorment.com/?p=695</guid>
		<description><![CDATA[Since today was a holiday (here in Belgium) I had a few moments to spare so I wrote a quick and dirty version of pong for the arduino using the S65 shield. Check the video after the break&#8230; EDIT: Added sound using a buzzer EDIT: Didn&#8217;t get time to rewrite some things, just added some [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://www.codetorment.com/wp-content/uploads/pong_moving.JPG"><img class="size-full wp-image-696  alignnone" title="pong_moving" src="http://www.codetorment.com/wp-content/uploads/pong_moving.JPG" alt=" Arduino Pong using S65 Shield" width="430" height="323" /></a></p>
<p>Since today was a holiday (here in Belgium) I had a few moments to spare so I wrote a quick and dirty version of pong for the arduino using the S65 shield.</p>
<p>Check the video after the break&#8230;<span id="more-695"></span></p>
<p><object classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000" width="400" height="300" codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,40,0"><param name="allowfullscreen" value="true" /><param name="allowscriptaccess" value="always" /><param name="src" value="http://vimeo.com/moogaloop.swf?clip_id=7558097&amp;server=vimeo.com&amp;show_title=1&amp;show_byline=1&amp;show_portrait=0&amp;color=&amp;fullscreen=1" /><embed type="application/x-shockwave-flash" width="400" height="300" src="http://vimeo.com/moogaloop.swf?clip_id=7558097&amp;server=vimeo.com&amp;show_title=1&amp;show_byline=1&amp;show_portrait=0&amp;color=&amp;fullscreen=1" allowscriptaccess="always" allowfullscreen="true"></embed></object></p>
<p>EDIT: Added sound using a buzzer</p>
<p><object width="400" height="300"><param name="allowfullscreen" value="true" /><param name="allowscriptaccess" value="always" /><param name="movie" value="http://vimeo.com/moogaloop.swf?clip_id=7596054&amp;server=vimeo.com&amp;show_title=1&amp;show_byline=1&amp;show_portrait=0&amp;color=&amp;fullscreen=1" /><embed src="http://vimeo.com/moogaloop.swf?clip_id=7596054&amp;server=vimeo.com&amp;show_title=1&amp;show_byline=1&amp;show_portrait=0&amp;color=&amp;fullscreen=1" type="application/x-shockwave-flash" allowfullscreen="true" allowscriptaccess="always" width="400" height="300"></embed></object></p>
<p>EDIT: Didn&#8217;t get time to rewrite some things, just added some comments</p>
<pre class="brush: cpp; title: ; notranslate">

#include &lt;S65Display.h&gt;
#include &lt;RotaryEncoder.h&gt;
#include &lt;string.h&gt;

#define WIDTH 176
#define HEIGHT 132
#define BAT_WIDTH 5
#define BAT_HEIGHT 30
#define BAT_INIT_X 5
#define BAT_INIT_Y 56
#define BALL 5
#define BAT_STEP 5
#define AI_STEP 2
#define MAX_TURNS 5

float ball_x = WIDTH / 2;
float ball_x_prev = ball_x;
float ball_y = HEIGHT / 2;
float ball_y_prev = ball_y;
float ball_dir = 0;
float bat_1_dir = 0;
int bat1_x = BAT_INIT_X;
int bat1_y = BAT_INIT_Y;
int bat1_y_prev = bat1_y;
int bat2_x = WIDTH - BAT_INIT_X - BAT_WIDTH;
int bat2_y = BAT_INIT_Y;
int bat2_y_prev = bat2_y;
int bat2_step = AI_STEP;
int p1_score = 0;
int p2_score = 0;
int ball_angle = 0;          // angle between ball path and horizontal axis
int ball_angle_sign = 0;   // sign of ball_angle : up = +1, down = -1, horizontal = 0
boolean score = false;
boolean gameover = false;
char buffer[256];           // string buffer

S65Display lcd;
RotaryEncoder encoder;

// Encoder must be serviced regularly.
ISR(TIMER2_OVF_vect)
{
  TCNT2 -= 250;        //1000 Hz
  encoder.service();
}

void setup()
{
  lcd.init(2);
  encoder.init();
  // More encoder stuff
  //init Timer2
  TCCR2B  = (1&amp;lt;&amp;lt;CS22);           //clk=F_CPU/64
  TCNT2   = 0x00;
  TIMSK2 |= (1&amp;lt;&amp;lt;TOIE2);         //enable overflow interupt
  score = false;
  gameover = false;
  lcd.clear(0);
  initTurn();
  startGame();
}

void loop(){

  while(!score &amp;amp;&amp;amp; !gameover){
    checkControls();
    updateAI();
    updateFields();
    drawScreen();
    delay(10);
  }

  if(checkPress() &amp;amp;&amp;amp; !gameover){	// if a player scored wait for rotary press
    initTurn();
  }
  delay(10);
}

// initialize fields for the beginning of game/round
void initTurn(void){
  lcd.clear(0);
  ball_x = WIDTH / 2;
  ball_x_prev = ball_x;
  ball_y = HEIGHT / 2;
  ball_y_prev = ball_y;
  ball_dir = 0;
  bat1_x = BAT_INIT_X;
  bat1_y = BAT_INIT_Y;
  bat1_y_prev = bat1_y;
  bat2_x = WIDTH - BAT_INIT_X - BAT_WIDTH;
  bat2_y = BAT_INIT_Y;
  bat2_y_prev = bat2_y;
  ball_angle = 0;           // angle between ball path and horizontal axis
  ball_angle_sign = 0;    // up = +1, down = -1, horizontal = 0
  score = false;
  ball_dir = 1;
  ball_angle = 45;
}

// start the game and wait for press on rotary encoder
void startGame(void){
  lcd.drawText(35, 60, &quot;Click to start&quot;, RGB(255,255,255), RGB(0,0,0));
  while(!checkPress()){
    delay(10);
  };
  lcd.clear(0);
}

// checks if rotary encoder was pressed
boolean checkPress(void){
  int8_t press;
  press = encoder.sw();
  if (SW_PRESSED == press || SW_PRESSEDLONG == press) {
    return true;
  }
  else{
    return false;
  }
}

void checkRotation(void){
  moveBat(encoder.step());
}

void checkControls(void){
  if(checkPress()){    // pause
    lcd.drawText(45, 60, &quot;Game paused&quot;, RGB(255,255,255), RGB(0,0,0));
    while(!checkPress()){ // wait until pressed
    }
    lcd.clear(0);
  }
  checkRotation();
}

void moveBat(int rot){
  if(!score &amp;amp;&amp;amp; !gameover){
    if(rot == 1){                                  // clockwise rotation, move bat up
	if(bat1_y - BAT_STEP &amp;gt;= 0){   // only move up when there is enough space left
	  bat1_y -= BAT_STEP;
	}
    }
    else if(rot == -1){                         // anti-clockwise rotation, move bat down
        // only move down when there is enough space left
	if((bat1_y + BAT_HEIGHT + BAT_STEP) &amp;lt; HEIGHT){
	  bat1_y += BAT_STEP;
	}
    }
  }
}

void updateFields(void){
 // top or bottom of screen reached, bounce ball back
  if(ball_y &amp;lt;= 0 || ball_y + BALL &amp;gt;= HEIGHT){
    if(ball_angle_sign == -1){ // ball was going down
	ball_angle_sign = 1;    // ball is now going up
    }
    else{                            // ball was going up
	ball_angle_sign = -1;   // ball is now going down
    }
  }
  // check if ball has is in reach of bat1 (horizontal), for some reason checking for equality doens't seem to work here ?
  if((ball_x &amp;lt;= 12 &amp;amp;&amp;amp; ball_x &amp;gt;= 11) &amp;amp;&amp;amp; (ball_dir == 1)){
    // ball is in reach of bat1(vertical)
    if((ball_y + BALL) &amp;gt;= bat1_y &amp;amp;&amp;amp; ball_y &amp;lt;= (bat1_y + BAT_HEIGHT)){
	ball_dir = 0;     // ball hits bat1, change direction
    }
  }
   // check if ball has is in reach of bat2 (horizontal)
  if((ball_x &amp;gt;= 160 &amp;amp;&amp;amp; ball_x &amp;lt;= 162) &amp;amp;&amp;amp; (ball_dir == 0)){
     // ball is in reach of bat2 (vertical)
    if((ball_y + BALL) &amp;gt;= bat2_y &amp;amp;&amp;amp; ball_y &amp;lt;= (bat2_y + BAT_HEIGHT)){
	ball_dir = 1;	      // ball hits bat2, change direction
    }
  }

  if( ball_x &amp;gt; 0 &amp;amp;&amp;amp; ball_x + BALL &amp;lt; WIDTH){           // ball is not near left or right edge
    if(ball_dir == 0){								// ball is moving to the right
	ball_x += cos(ball_angle);						// cosine is always positive in 1st and 4th quadrant
	if(ball_angle_sign == -1){						// check sign of angle
	  ball_y  -= sin(ball_angle);						// negative if angle in 4th quadrant
	}
	else{
	  ball_y  += sin(ball_angle);						// positive if angle in 1th quadrant
	}
    }
    else{									        // ball is moving to the left
	ball_x -= cos(ball_angle);						// cosine is always negative in 2nd and 3rd quadrant
	if(ball_angle_sign == -1){
	  ball_y  -= sin(ball_angle);						// sine is always negative in 3rd quadrant
	}
	else{
	  ball_y  += sin(ball_angle);						// sine is always positive in 2nd quadrant
	}
    }

  }
  else{										// ball hits left or right edge
    if(!score &amp;amp;&amp;amp; !gameover){
	if(ball_dir == 0){							        // ball was going to the right
	  if(p1_score++ &amp;lt; MAX_TURNS){
	    p1_score++;								// player 1 scores
	  }
	  else{
	    gameover = true;
	  }
	}
	else{									        // ball was going to the left
	  if(p2_score &amp;lt; MAX_TURNS){
	    p2_score++;								// player 2 scores
	  }
	  else{
	    gameover = true;
	  }
	}
	score = true;
    }
  }
}

void updateAI(void){
  // bat2 follows vertical position of ball, TODO : implement difficulty levels
  if(ball_y &amp;gt; (bat2_y + (BAT_HEIGHT / 2))){
    // TODO : make function moveBat() that does the bound checking
    if((bat2_y + BAT_HEIGHT + bat2_step) &amp;lt; HEIGHT){
	bat2_y += bat2_step;
    }

  }
  else{
    if((bat2_y - bat2_step) &amp;gt;= 0){
	bat2_y -= bat2_step;
    }
  }
}

void drawScreen(void){
  // draw ball
  lcd.drawRect( ball_x_prev, ball_y_prev, ball_x_prev + BALL, ball_y_prev + BALL, RGB(0,0,0));
  lcd.drawRect( ball_x, ball_y, ball_x + BALL, ball_y + BALL, RGB(255,255,255));
  ball_x_prev = ball_x;
  ball_y_prev = ball_y;
  // draw left bat
  lcd.drawRect( bat1_x, bat1_y_prev, bat1_x + BAT_WIDTH, bat1_y_prev + BAT_HEIGHT, RGB(0,0,0));
  lcd.drawRect( bat1_x, bat1_y, bat1_x + BAT_WIDTH, bat1_y + BAT_HEIGHT, RGB(255,255,255));
  bat1_y_prev = bat1_y;
  // draw right bat
  lcd.drawRect( bat2_x, bat2_y_prev, bat2_x + BAT_WIDTH, bat2_y_prev + BAT_HEIGHT, RGB(0,0,0));
  lcd.drawRect( bat2_x, bat2_y, bat2_x + BAT_WIDTH, bat2_y + BAT_HEIGHT, RGB(255,255,255));
  bat2_y_prev = bat2_y;
  drawScore();
}

void drawScore(void){
  sprintf(buffer, &quot;%d - %d&quot;, p1_score, p2_score);
  lcd.drawText(72, 5, buffer, RGB(255,255,255), RGB(0,0,0));
}
</pre>
<p><a class="a2a_dd a2a_target addtoany_share_save" href="http://www.addtoany.com/share_save#url=http%3A%2F%2Fwww.codetorment.com%2F2009%2F11%2F11%2Farduino-pong-using-s65-shield%2F&amp;title=Arduino%20Pong%20using%20S65%20Shield" id="wpa2a_2"><img src="http://www.codetorment.com/wp-content/plugins/add-to-any/share_save_171_16.png" width="171" height="16" alt="share save 171 16 Arduino Pong using S65 Shield"  title="Arduino Pong using S65 Shield" /></a></p>]]></content:encoded>
			<wfw:commentRss>http://www.codetorment.com/2009/11/11/arduino-pong-using-s65-shield/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
	</channel>
</rss>

