Here is a pong game I made for the NXT. It uses the NXTChuck to read a Wii Nunchuk, and uses the values as the user input to the game.
In the video I was using two NXTChucks and Nunchuks, in two-player game mode. If you want to play single-player, you can change just one line of the program so that it compiles for single-player mode.
You need to have the NXC NXTChuck library, available from Dexter Industries’ downloads page.
Lines 3 through 16 are constants that determine the characteristics of the game. Most of them are fairly self-explanatory. Try changing them, and don’t worry, I have listed all the original values in the program, so you can always change it back really easily. Line 16 tells the compiler to compile for 1 or for 2 controllers.
#include "NXTChuck lib.nxc"
#define SpeedUpAmount 5 // 5
#define InitialSpeed 50 // 50
#define InitialBallSize 4 // 4
#define InitialPaddleWidth 10 // 10
#define MinX 1 // 1
#define MaxX 98 // 98
#define MinY 1 // 0
#define MaxY 55 // 55
#define NXTChuck_1_PORT S1 // S1
#define NXTChuck_2_PORT S2 // S2
#define Controllers 2 // 2
byte N1_SX, N1_SY;
int N1_AX, N1_AY, N1_AZ;
byte N1_B;
#if Controllers == 2
byte N2_SX, N2_SY;
int N2_AX, N2_AY, N2_AZ;
byte N2_B;
#endif
long LeftScore, RightScore, TotalScore; // scores
float TotalSpeed; // ball speed
byte BallRadius; // ball size
byte PaddleHalfWidth; // paddle size
int PaddleL, PaddleR; // paddle positions
int BallXspeedBase, BallYspeedBase; // base speed, expenced to be in the range of 0-100
char BallXdir, BallYdir; // ball travle direction
float BallXPos, BallYPos; // current position
int BallXlast, BallYlast; // was a byte, and should be fine as such // last position, for erasing the last frame
unsigned long LastTick, ThisTick;
#define Clip(in,min,max) (in<min?min:(in>max?max:in))
inline long Round(float Value){
long Result = Value > 0 ? Value + 0.5 : Value - 0.5 ;
return Result;
}
float ScaleRange(float Value, float ValueMin, float ValueMax, float DesiredMin, float DesiredMax)
{
return (DesiredMax - DesiredMin) * (Value - ValueMin) / (ValueMax - ValueMin) + DesiredMin;
}
int ScaleRangeInt(float Value, float ValueMin, float ValueMax, float DesiredMin, float DesiredMax)
{
return (DesiredMax - DesiredMin) * (Value - ValueMin) / (ValueMax - ValueMin) + DesiredMin;
}
void InitializeValues(bool First){
LeftScore = 0;
RightScore = 0;
TotalScore = 0;
TotalSpeed = InitialSpeed;
BallRadius = InitialBallSize;
PaddleHalfWidth = InitialPaddleWidth;
BallXspeedBase = ScaleRange(Random(), -32768, 32767, 45, 55);
BallYspeedBase = 100 - BallXspeedBase;
BallXdir = Random()&1?1:-1;
Wait(Random(25));
BallYdir = Random()&1?1:-1;
BallXPos = (MaxX - MinX) / 2;
BallYPos = (MaxY - MinY) / 2;
if(First){
ClearScreen();
TextOut(12, LCD_LINE1, "Initializing");
until(NXTChuckInit(NXTChuck_1_PORT, false) == NXTChuck_COM_SUCCESS);
until(NXTChuckIdent(NXTChuck_1_PORT) == NXTChuck_DEVICE_NUNCHUK);
#if Controllers == 2
until(NXTChuckInit(NXTChuck_2_PORT, false) == NXTChuck_COM_SUCCESS);
until(NXTChuckIdent(NXTChuck_2_PORT) == NXTChuck_DEVICE_NUNCHUK);
#endif
ClearScreen();
TextOut(23, LCD_LINE1, "Press z");
TextOut(23, LCD_LINE2, "to start.");
}
else{
TextOut(17, LCD_LINE7, "Press z to");
TextOut(23, LCD_LINE8, "restart.");
}
#if Controllers == 2
while(!(N1_B&N2_B&NXTChuck_N_BTN_Z)){
NXTChuckReadNunchuk(NXTChuck_2_PORT, N2_SX, N2_SY, N2_AX, N2_AY, N2_AZ, N2_B);
#else
while(!(N1_B&NXTChuck_N_BTN_Z)){
#endif
NXTChuckReadNunchuk(NXTChuck_1_PORT, N1_SX, N1_SY, N1_AX, N1_AY, N1_AZ, N1_B);
Wait(10);
}
ClearScreen();
LastTick = CurrentTick();
}
void UpdateDisplay(){
CircleOut(BallXlast, BallYlast, BallRadius, 0x36);
BallXlast = Round(BallXPos);
BallYlast = Round(BallYPos);
CircleOut(BallXlast, BallYlast, BallRadius, 0x32);
LineOut(MinX - 1, PaddleL-PaddleHalfWidth, MinX - 1, PaddleL + PaddleHalfWidth);
LineOut(MaxX + 1, PaddleR-PaddleHalfWidth, MaxX + 1, PaddleR + PaddleHalfWidth);
LineOut(0, 55, 99, 55);
LineOut(0, 0, 99, 0);
ClearLine(LCD_LINE1);
NumOut(37, LCD_LINE1, TotalScore);
NumOut(0, LCD_LINE1, LeftScore);
NumOut(75, LCD_LINE1, RightScore);
}
void ChangeBaseSpeeds(){
char OffsetFromEven = BallXspeedBase - 50;
BallXspeedBase += Round(ScaleRange(Random(), -32768, 32767, OffsetFromEven>0?-5:-4, OffsetFromEven<0?5:4));
BallYspeedBase = 100 - BallXspeedBase;
if(BallXspeedBase > 90){
BallXspeedBase = 90;
BallYspeedBase = 10;
}
else if(BallXspeedBase < 10){
BallXspeedBase = 10;
BallYspeedBase = 90;
}
}
char CheckEdge(){
if(BallYPos < (MinY + BallRadius)){
BallYdir = -BallYdir;
BallYPos = MinY + BallRadius;
ChangeBaseSpeeds();
}
if(BallYPos > (MaxY - BallRadius)){
BallYdir = -BallYdir;
BallYPos = MaxY - BallRadius;
ChangeBaseSpeeds();
}
char result = 0;
if(BallXPos < (MinX + BallRadius)){
if(Round(BallYPos) > (PaddleL + PaddleHalfWidth) || Round(BallYPos) < (PaddleL - PaddleHalfWidth)){
result = -1;
}
else{
result = 1;
}
BallXdir = -BallXdir;
BallXPos = MinX + BallRadius;
ChangeBaseSpeeds();
}
if(BallXPos > (MaxX - BallRadius)){
if(Round(BallYPos) > (PaddleR + PaddleHalfWidth) || Round(BallYPos) < (PaddleR - PaddleHalfWidth)){
result = -2;
}
else{
result = 2;
}
BallXdir = -BallXdir;
BallXPos = MaxX - BallRadius;
ChangeBaseSpeeds();
}
return result;
}
char Edge;
task Game(){
InitializeValues(true);
while(true){
NXTChuckReadNunchuk(NXTChuck_1_PORT, N1_SX, N1_SY, N1_AX, N1_AY, N1_AZ, N1_B);
PaddleL = Clip(ScaleRangeInt(N1_SY, 0, 255, MinY + PaddleHalfWidth, MaxY - PaddleHalfWidth), MinY + PaddleHalfWidth, MaxY - PaddleHalfWidth);
#if Controllers == 2
NXTChuckReadNunchuk(NXTChuck_2_PORT, N2_SX, N2_SY, N2_AX, N2_AY, N2_AZ, N1_B);
PaddleR = Clip(ScaleRangeInt(N2_SY, 0, 255, MinY + PaddleHalfWidth, MaxY - PaddleHalfWidth), MinY + PaddleHalfWidth, MaxY - PaddleHalfWidth);
#else
PaddleR = PaddleL;
#endif
ThisTick = CurrentTick();
BallXPos += (ScaleRange((BallXspeedBase * BallXdir), -100, 100, -TotalSpeed, TotalSpeed) * (ThisTick - LastTick) / 1000 );
BallYPos += (ScaleRange((BallYspeedBase * BallYdir), -100, 100, -TotalSpeed, TotalSpeed) * (ThisTick - LastTick) / 1000 );
LastTick = ThisTick;
Edge = CheckEdge();
if(Edge == 0){
}
else if(Edge == 1){
LeftScore++;
TotalScore++;
TotalSpeed += SpeedUpAmount;
}
else if(Edge == 2){
RightScore++;
TotalScore++;
TotalSpeed += SpeedUpAmount;
}
else if(Edge == -1 || Edge == -2){
ClearScreen();
NumOut(37, LCD_LINE1, TotalScore);
NumOut(0, LCD_LINE1, LeftScore);
NumOut(75, LCD_LINE1, RightScore);
TextOut(18, LCD_LINE2, "Game Over,");
if(Edge == -1){
TextOut(18, LCD_LINE3, "Left Lost.");
}
if(Edge == -2){
TextOut(15, LCD_LINE3, "Right Lost.");
}
TextOut(0, LCD_LINE5, "Speed Was =");
NumOut(72, LCD_LINE5, TotalSpeed);
InitializeValues(false);
}
UpdateDisplay();
Wait(10);
}
}
task main(){
start Game;
}
Pingback: Pong for the LEGO MINDSTORMSDexter Industries Blog
Pingback: LEGO MINDSTORMS NXT Pong Game using Wii Nunchucks - Hacked Gadgets – DIY Tech Blog
Pingback: LEGO MINDSTORMS NXT Pong Game using Wii Nunchucks | Price Gadget Reviews