Arcade Machine
Posted: 19 Sep 2013, 19:16
by haydenstudios
Hey guys. My LEGO MINDSTORMS building career is about to come to an end. I've been getting older, getting busier, gaining other hobbies, and simply haven't been able to set aside as much time for LEGO MINDSTORMS as I used to. It is for this reason that the project you see here will likely be my last one. It is my Arcade Machine.
This machine consists of:
Here is a bundle of all the files you'll need to download the programs:
The source code to the programs are posted below if you'd like to view it here instead of download the attachment:
Here are some step-by-step building instructions for the model:
http://www.mediafire.com/view/3re3aoiec ... achine.pdf
The virtual model was built using the LDraw system of tools.
Here is a full video demonstration:
I began building this in August 2011. It took me about 2 weeks to build it, with minor revisions being made as time went on. Unfortunately, the programming part got severely delayed due to high school beginning for me when the 2011-2012 school year began. I got very busy, and blew my opportunity to get this project done during Summer 2012. The delay continued once again when the 2012-2013 year began, but I finally finished the programming in May 2013 after Summer began, just recently finished the documentation, and got the Youtube video published last night. This is a large part of the reason I haven't been super active these past 2 years. The fact that this project took me 2 years when it should have taken me little more than 4 months speaks volumes for the fact that it's nearing the time for me to start phasing out of MINDSTORMS. I also find this to be a fitting time to retire due to all these people of the new generation coming now that the EV3 is coming out. With this being my last project, I'm not sure how much longer you'll be seeing me here, or on any other MINDSTORMS websites, so I guess this thread could be considered my farewell to this community. I may drop in every once in a while, but for the most part I'm done. These three years with you guys have been awesome.
- 2 NXTs
- 1 RCX
- 2 NXT motors
- 1 RCX motor
- 2 NXT touch sensors
- 3 RCX touch sensors
- 2 RCX rotation sensors
- 1 NXT light sensor
- 1 LEGO NXT color sensor
- 1 lamp
Here is a bundle of all the files you'll need to download the programs:
- Programs.zip
- The programs, as well as the necessary images files, and a text file that should be downloaded onto the master NXT.
- (10.66 KiB) Downloaded 761 times
The Master NXT program:
The slave NXT program:
The RCX program:
Code: Select all
byte Rx_Buffer[], fileHandle, ASCIIPos, coin = 4;
short bytesWritten;
string detectedCoin = " ", cent;
string SBallX, SBallY, SPosition1, Sp1score, Sp2score, sBallTime, sTotalTime, scores, scoresp1, scoresp2, current = "", name, currentCharacter;
string ln1, ptime, pscore1, pscore2, pscore3, pscore4, pscore5, begin, open, end, tempName, tempScore;
bool check = 0;
bool Determined = 0, Players = 0, survival = 0, setball = 0, gameover = 0;
bool ballhor, ballvert, capsLock = 1;
int defaultLight, degrees = 0, timer3, centsToPay = 25;
int fSize, totalTime, p1score, p2score, p3score = 0, p4score = 0, p5score = 0, BallX, BallY, activateball = 0, Position1 = 0;
int strLen_score, strLen_name, strLen_ptime, plyrScore;
int difficultyLevel, ballspeed, rside1, rside2, lside1, lside2, number, number2, survpos, timer1, scoreSpot;
int characterPos = 0, character, allowedCharacters;
long offset1 = 0, offset2 = 0, offset3 = 0, ballTime, timer2;
float Position2 = 37, Difficulty = 1;
inline void WaitForMessageToBeSent()
{
while(RS485SendingData())
Wait(3);
}
sub Deposit() //The subroutine for depositing coins in the container
{
OnFwd(OUT_B, 30);
Wait(1750);
Off(OUT_B);
Wait(100);
RotateMotorEx(OUT_B, 30, -28, 0, false, true);
Wait(1000);
}
int CalcPosition(int SensorNew) //Make some calculations necessary for using the rotation sensor value to its fullest
{
int SensorOld;
SensorOld = SensorNew;
SensorNew = SENSOR_2;
SensorNew -= SensorOld;
return SensorNew;
}
string ParseScoreText(string scores, string beginning, string bracketOpen, string bracketClose, string pname, string pscore, string ptime, int strLen_name, int strLen_score, int strLen_ptime, int plyrScore)
{ //Assemble the necessary text for displaying the high scores
if(beginning == "null")
pname = SubStr(scores, 0, Pos(bracketOpen, scores));
else
pname = SubStr(scores, Pos(beginning, scores) + 1, Pos(bracketOpen, scores) - Pos(beginning, scores) - 1);
strLen_name = StrLen(pname);
strLen_score = StrLen(SubStr(scores, Pos(bracketOpen, scores) + 1, Pos(bracketClose, scores) - (Pos(bracketOpen, scores) + 1)));
pscore = SubStr(scores, Pos(bracketOpen, scores) + 1, Pos(bracketClose, scores) - Pos(bracketOpen, scores) - 1);
plyrScore = StrToNum(pscore);
if(plyrScore % 60 >= 10)
ptime = StrCat(NumToStr(plyrScore / 60), ":", NumToStr(plyrScore % 60));
else
ptime = StrCat(NumToStr(plyrScore / 60), ":0", NumToStr(plyrScore % 60));
strLen_ptime = StrLen(ptime);
repeat(14 - (strLen_name + strLen_ptime))
pname += " ";
pname += ptime;
return pname;
}
sub Victory() //Play the tune "Victory!" from Cave Story
{
PlayToneEx(262, 96, 4, false);
Wait(96);
PlayToneEx(330, 96, 4, false);
Wait(96);
PlayToneEx(392, 96, 4, false);
Wait(96);
PlayToneEx(494, 96, 4, false);
Wait(96);
PlayToneEx(523, 96, 4, false);
Wait(96);
PlayToneEx(659, 96, 4, false);
Wait(96);
PlayToneEx(784, 96, 4, false);
Wait(96);
PlayToneEx(988, 96, 4, false);
Wait(96);
PlayToneEx(1046, 192, 4, false);
Wait(192);
PlayToneEx(1046, 96, 2, false);
Wait(96);
PlayToneEx(1046, 90, 4, false);
Wait(96);
PlayToneEx(1046, 96, 4, false);
Wait(96);
PlayToneEx(1046, 96, 2, false);
Wait(96);
repeat (3)
{
PlayToneEx(880, 96, 4, false);
Wait(96);
PlayToneEx(880, 96, 2, false);
Wait(96);
}
PlayToneEx(988, 864, 4, false);
Wait(864);
PlayToneEx(988, 96, 2, false);
Wait(92);
}
sub GetHeartTank() //Play the tune "Get Heart Tank!" from Cave Story
{
PlayToneEx(220, 120, 3, false);
Wait(120);
PlayToneEx(220, 120, 2, false);
Wait(120);
PlayToneEx(277, 120, 3, false);
Wait(120);
PlayToneEx(277, 120, 2, false);
Wait(120);
PlayToneEx(330, 120, 4, false);
Wait(120);
PlayToneEx(330, 120, 2, false);
Wait(120);
PlayToneEx(277, 120, 3, false);
Wait(120);
PlayToneEx(277, 120, 2, false);
Wait(120);
PlayToneEx(330, 120, 3, false);
Wait(120);
PlayToneEx(330, 120, 2, false);
Wait(120);
PlayToneEx(415, 120, 4, false);
Wait(120);
PlayToneEx(415, 120, 2, false);
Wait(120);
PlayToneEx(370, 120, 3, false);
Wait(120);
PlayToneEx(370, 120, 2, false);
Wait(120);
PlayToneEx(311, 120, 3, false);
Wait(120);
PlayToneEx(311, 120, 2, false);
Wait(120);
PlayToneEx(247, 120, 3, false);
Wait(120);
PlayToneEx(247, 120, 2, false);
Wait(120);
PlayToneEx(210, 120, 3, false);
Wait(120);
PlayToneEx(210, 120, 2, false);
Wait(120);
PlayToneEx(247, 120, 4, false);
Wait(120);
PlayToneEx(247, 120, 2, false);
Wait(120);
PlayToneEx(311, 120, 4, false);
Wait(120);
PlayToneEx(311, 120, 2, false);
Wait(120);
PlayToneEx(277, 1440, 2, false);
Wait(1440);
}
sub ShowPongStats() //Display the current stats of the game
{
if(!survival) //If this is a two player game or if it's not in survival mode,
{
NumOut(49, LCD_LINE7, p1score); //then display the scores
NumOut(49, LCD_LINE2, p2score);
}
else //If it's in survival mode,
{
if(StrLen(NumToStr(ballTime % 60)) == 1)
sBallTime = NumToStr(ballTime / 60) + ":0" + NumToStr(ballTime % 60);
else //Calculate how long the previous bout lasted,
sBallTime = NumToStr(ballTime / 60) + ":" + NumToStr(ballTime % 60);
if(StrLen(NumToStr(totalTime % 60)) == 1)
sTotalTime = NumToStr(totalTime / 60) + ":0" + NumToStr(totalTime % 60);
else //and the sum of the bouts so far,
sTotalTime = NumToStr(totalTime / 60) + ":" + NumToStr(totalTime % 60);
TextOut(14, LCD_LINE6, "Bout" + NumToStr(p2score) + ": " + sBallTime); //and display them
TextOut(14, LCD_LINE7, "Total: " + sTotalTime);
}
}
sub BouncePaddle(int lside, int rside) //This subroutine is triggered if the ball reaches the area of a paddle along the y axis
{
if((BallX >= lside) && (BallX <= rside)) //If a paddle is above or beneath the ball, then do the following:
{
if(((BallX == lside || BallX == lside + 1) && ballhor) || ((BallX == rside || BallX == rside - 1) && !ballhor))
ballhor = !ballhor; //If it bounces on a corner, then change the ball's horizontal direction,
ballvert = !ballvert; //in addition to the changing of the vertical direction,
PlayTone(550, 100); //and playing a beep to indicate a collision and bounce
}
}
sub playpong()
{
totalTime = 0;
BallX = 49;
BallY = 29;
p1score = 0;
p2score = 0;
Position1 = 38; //Set variables to their default positions at the beginning of the game
Determined = 1;
int SensorNew, Middle;
if(Players == 0) //If this is a 1-player game,
{
Position2 = 30; //then make some calculations
difficultyLevel = Difficulty; //that will help the opponent behave based on
Difficulty /= 10; //the difficulty setting chosen by the player
}
else //If this is a 2-player game,
{
Difficulty = 2;
SendRS485Number(1); //then establish communication with the other player
WaitForMessageToBeSent();
}
while (gameover == 0) //Mantain this loop until the game is over
{
while(SENSOR_1 == 0) //Maintain this loop until the ball has been activated
{
if(difficultyLevel == 2)
ballspeed = 70;
else
{ //Begin the ball at different speeds based on the difficulaty level
if(difficultyLevel == 3)
ballspeed = 65;
else
{
ballspeed = 75;
if(difficultyLevel == 4)
survival = true;
}
}
SensorNew = SENSOR_2;
if(Players == 1) //If this is a 2-player game,
{
SPosition1 = "p" + NumToStr(Position1); //Then send the position of your paddle,
SendRS485String(SPosition1);
WaitForMessageToBeSent();
SBallX = "x" + NumToStr(BallX); //the x position of the ball,
SendRS485String(SBallX);
WaitForMessageToBeSent();
SBallY = "y" + NumToStr(BallY); //and the y position of the ball,
SendRS485String(SBallY);
WaitForMessageToBeSent();
until(RS485DataAvailable());
RS485Read(Rx_Buffer);
Position2 = Rx_Buffer[0]; //in addition to receiving the position of the player's paddle
}
ClearScreen();
GraphicOut(Position1, 0, "Tray.ric");
GraphicOut(Position2, 60, "Tray.ric"); //Display the ball and paddles at their appropriate position,
GraphicOut(BallX, BallY, "Ball.ric");
ShowPongStats(); //and show their stats
Position1 += CalcPosition(SensorNew); //see if the rotation sensor value has changed, and make necessary calculations
if(Position1 < 0)
Position1 = 0; //Keep the paddle from going off the screen
if(Position1 > 76)
Position1 = 76;
} //End this loop now that the ball has been activated
activateball = 1; //Notify the ball task to start calculating the ball's position
offset2 = CurrentTick(); //Reset timer 2
while(activateball == 1) //Mantain this loop until the ball gets past one of the paddles
{
SensorNew = SENSOR_2;
if(Players == 1)
{
SPosition1 = "p" + NumToStr(Position1); //Then send the position of your paddle,
SendRS485String(SPosition1);
WaitForMessageToBeSent();
SBallX = "x" + NumToStr(BallX); //the x position of the ball,
SendRS485String(SBallX);
WaitForMessageToBeSent();
SBallY = "y" + NumToStr(BallY); //and the y position of the ball,
SendRS485String(SBallY);
WaitForMessageToBeSent();
until(RS485DataAvailable());
RS485Read(Rx_Buffer);
Position2 = Rx_Buffer[0]; //in addition to receiving the position of the player's paddle
}
ClearScreen();
GraphicOut(Position1, 0, "Tray.ric");
GraphicOut(Position2, 60, "Tray.ric"); //Display the ball and paddles at their appropriate position,
GraphicOut(BallX, BallY, "Ball.ric");
ShowPongStats(); //and show their stats
Position1 += CalcPosition(SensorNew); //see if the rotation sensor value has changed, and make necessary calculations
if(Position1 < 0)
Position1 = 0; //Keep the paddle from going off the screen
if(Position1 > 76)
Position1 = 76;
rside1 = Position1 + 24;
lside1 = Position1 - 3; //Calculate the positions of the corners of the paddles
rside2 = Position2 + 24;
lside2 = Position2 - 3;
if(Players == 0) //If this is a 1-player game,
{
Middle = Position2 + 12;
survpos = BallX - 12;
if(BallX < Middle) //and if the ball is to the left of the center of the cpu's paddle along the x axis,
{
if(!survival) //if this isn't survival mode,
Position2 -= Difficulty; //then make the computer player respond at different speeds based on the difficulty set by the player
else //if this is survival mode,
Position2 = survpos; //then set the computer player's paddle's position such that the ball is in the center along the x axis
}
if(BallX > Middle) //and if the ball is to the right of the center of the cpu's paddle along the x axis,
{
if(!survival)
Position2 += Difficulty; //then make the computer player respond at different speeds based on the difficulty set by the player
else
Position2 = survpos; //then set the computer player's paddle's position such that the ball is in the center along the x axis
}
if(Position2 < 0)
Position2 = 0; //Keep the paddle from going off the screen
if(Position2 > 76)
Position2 = 76;
}
} //End the loop, as the ball has gotten past one of the paddles
ballTime = timer2 / 1000;
totalTime += ballTime; //Get the value for the amount of time that ball took
GraphicOut(Position1, 0, "Tray.ric");
GraphicOut(BallX, BallY, "Ball.ric");
GraphicOut(Position2, 60, "Tray.ric");
ShowPongStats();
PlayTone(349, 500);
if(BallY <= 0)
{
SendRS485String("t");
WaitForMessageToBeSent();
}
if(BallY >= 60) //Send the message of who scored to the other NXT
{
SendRS485String("o");
WaitForMessageToBeSent();
}
Wait(500);
if(p1score >= 5 || p2score >= 5) //Break out of the loop if one of the players has reached 5 points
break;
BallX = 49;
BallY = 29; //If the game's not over yet, set the ball to its default position for the next round
} //End the loop if one of the players has reached five points
ClearScreen();
Wait(1250);
if(!survival) //If this wasn't a survival game,
{
if(p1score > p2score)
{
TextOut(25, LCD_LINE2, "You win!");
Victory();
}
else //tell the player whether he or she won or lost
{
TextOut(25, LCD_LINE2, "You lose");
Wait(2880);
}
TextOut(30, LCD_LINE5, "SCORES:"); //Then show the scores
TextOut(20, LCD_LINE7, "Player 1: " + NumToStr(p1score));
if(Players == 0)
TextOut(20, LCD_LINE8, "Computer: " + NumToStr(p2score));
else
TextOut(20, LCD_LINE8, "Player 2: " + NumToStr(p2score));
Wait(1250);
}
else //If this was a survival game,
{
TextOut(24, LCD_LINE2, "Game over"); //tell the player the game has ended,
Wait(2880);
TextOut(12, LCD_LINE5, "You survived:");
if(StrLen(NumToStr(totalTime % 60)) == 1) //then tell him or her how long he or she survived
sTotalTime = NumToStr(totalTime / 60) + ":0" + NumToStr(totalTime % 60);
else
sTotalTime = NumToStr(totalTime / 60) + ":" + NumToStr(totalTime % 60);
TextOut(36, LCD_LINE7, sTotalTime);
Wait(1250);
}
until(SENSOR_1 == 1);
until(SENSOR_1 == 0); //Wait for the player to press and release the touch sensor
if(survival) //If this was a survival game,
{
scoreSpot = 0;
OpenFileRead("HighScores.txt", fSize, fileHandle);
ReadLnString(fileHandle, scores); //Then read the high scores text file,
CloseFile(fileHandle);
p1score = StrToNum(SubStr(scores, Pos("/", scores) + 1, Pos("\\", scores) - Pos("/", scores) - 1));
if(totalTime > p1score) //see if the player made the high score list,
{
scoreSpot = 5; //and sort it into the right spot
p2score = StrToNum(SubStr(scores, Pos("<", scores) + 1, Pos(">", scores) - Pos("<", scores) - 1));
if(totalTime > p2score)
scoreSpot--;
p3score = StrToNum(SubStr(scores, Pos("{", scores) + 1, Pos("}", scores) - Pos("{", scores) - 1));
if(totalTime > p3score)
scoreSpot--;
p4score = StrToNum(SubStr(scores, Pos("[", scores) + 1, Pos("]", scores) - Pos("[", scores) - 1));
if(totalTime > p4score)
scoreSpot--;
p5score = StrToNum(SubStr(scores, Pos("(", scores) + 1, Pos(")", scores) - Pos("(", scores) - 1));
if(totalTime > p5score)
scoreSpot--;
ClearScreen();
if(totalTime >= 600)
allowedCharacters = 9;
else
allowedCharacters = 10;
TextOut(3, LCD_LINE1, "Enter your name:");
TextOut(0, LCD_LINE3, "Caps Lock is ON");
TextOut(0, LCD_LINE4, "Next: A");
TextOut(0, LCD_LINE6, "_");
TextOut(9, LCD_LINE8, "Chars left: " + NumToStr(allowedCharacters));
PlayTone(610,140);
Wait(220);
PlayTone(511,100);
Wait(180);
PlayTone(610,140);
Wait(140);
ClearSensor(IN_2);
while(true) //Allow the player to enter his or her name if he or she got a decent score
{
while(true)
{
if(characterPos >= 0 && characterPos <= 25) //If the option the user is about to select is a letter of the alphabet...
{
if(capsLock) //If Caps Lock is on...
ASCIIPos = characterPos + 65; //Make the letter uppercase
else
ASCIIPos = characterPos + 97; //Make the letter lowercase
currentCharacter = FlattenVar(ASCIIPos); //Make the current character the flattened raw ASCII value of teh character pos
}
if(characterPos == 26) //If we want to press space...
currentCharacter = " "; //Make the next character a space
TextOut(3, LCD_LINE1, "Enter your name:");
if(capsLock) //If Caps Lock is on...
TextOut(0, LCD_LINE3, "Caps Lock is ON"); //Say that Caps Lock is on
else //If Caps Lock is NOT on...
TextOut(0, LCD_LINE3, "Caps Lock is OFF");//Say that Caps Lock is off
if(characterPos >= 0 && characterPos <= 25) //If the character position is between 0 and 25...
TextOut(0, LCD_LINE4, "Next: " + currentCharacter); //Then make the next character a letter of the alphabet
if(characterPos == 26) //If the character position is 26...
TextOut(0, LCD_LINE4, "Next: SPACE"); //Then make the next character a space
if(characterPos == 27) //If the character position is 27...
TextOut(0, LCD_LINE4, "Next: BACKSPACE"); //Then make the next character a backspace
if(characterPos == 28) //If the character position is 28...
TextOut(0, LCD_LINE4, "Next: CAPS LOCK"); //Then toggle Caps Lock
if(characterPos == 29) //If the character position is 29...
TextOut(0, LCD_LINE4, "Next: DONE"); //Then submit
if((allowedCharacters - StrLen(current)) > 0)
TextOut(0, LCD_LINE6, current + "_"); //*Show what has been typed so far
else
TextOut(0, LCD_LINE6, current);
TextOut(9, LCD_LINE8, "Chars left: " + NumToStr(allowedCharacters - StrLen(current))); //Show how many characters are left (not finished with this line of code yet; what is displayed is only temporary)
Wait(30); ClearScreen();
if((allowedCharacters - StrLen(current)) > 0)
{
if(SENSOR_2 < -8) //If the rotation sensor gets moved to the left...
{
ClearSensor(IN_2); //Reset the rotation sensor,
if(characterPos == 0)
characterPos = 29; //and set the character position to 29 if it's 0,
else
characterPos--; //and decrement the character position if it's not equal to 0
}
if(SENSOR_2 > 8) //If the rotation sensor gets moved to the right...
{
ClearSensor(IN_2); //Reset the rotation sensor,
if(characterPos == 29)
characterPos = 0; //and set the character position to 0 if it's 29,
else
characterPos++; //and increment the character position if it's not equal to 29
} //Essentially, the above 15 lines of code keep the character position between 0 and 29
}
else //If there are no remaining characters left,
{
if(SENSOR_2 < -8 || SENSOR_2 > 8) //then allow the only options to be
{
if(characterPos == 27) //"DONE", and
characterPos = 29;
else //"BACKSPACE"
characterPos = 27;
ClearSensor(IN_2);
}
}
if(SENSOR_1 == 1)
{
until(SENSOR_1 == 0);
break; //End the loop when the touch sensor has been pressed and released
}
} //Once the loop has ended...
if(characterPos == 29)
break; //End the more outer loop when the player has selected "DONE"
if(characterPos >= 0 && characterPos <= 26) //If the user's selection is a letter of the alphabet, or a space, then...
{
current = StrCat(current, currentCharacter); //Adds the selected character onto what you're typing
if((allowedCharacters - StrLen(current)) < 1)
characterPos = 29;
}
if(characterPos == 27)
current = SubStr(current, 0, StrLen(current)-1);
if(characterPos == 28) //If the user has selected the Caps Lock option...
capsLock = !capsLock; //Then toggle Caps Lock
}
name = current;
if(scoreSpot < 5) //Sort rhe player's score onto the list based on how high it is
{
tempName = SubStr(scores, Pos("}", scores) + 1, Pos("<", scores) - Pos("}", scores) - 1);
tempScore = SubStr(scores, Pos("<", scores) + 1, Pos(">", scores) - Pos("<", scores) - 1);
scores = StrCat(SubStr(scores, 0, Pos(">", scores) + 1), tempName, "/", tempScore, "\\");
if(scoreSpot < 4)
{
tempName = SubStr(scores, Pos("]", scores) + 1, Pos("{", scores) - Pos("]", scores) - 1);
tempScore = SubStr(scores, Pos("{", scores) + 1, Pos("}", scores) - Pos("{", scores) - 1);
scores = StrCat(SubStr(scores, 0, Pos("}", scores) + 1), tempName, "<", tempScore, ">", SubStr(scores, Pos(">", scores) + 1, StrLen(scores)));
if(scoreSpot < 3)
{
tempName = SubStr(scores, Pos(")", scores) + 1, Pos("[", scores) - Pos(")", scores) - 1);
tempScore = SubStr(scores, Pos("[", scores) + 1, Pos("]", scores) - Pos("[", scores) - 1);
scores = StrCat(SubStr(scores, 0, Pos("]", scores) + 1), tempName, "{", tempScore, "}", SubStr(scores, Pos("}", scores) + 1, StrLen(scores)));
if(scoreSpot < 2)
{
tempName = SubStr(scores, 0, Pos("(", scores));
tempScore = SubStr(scores, Pos("(", scores) + 1, Pos(")", scores) - Pos("(", scores) - 1);
scores = StrCat(SubStr(scores, 0, Pos(")", scores) + 1), tempName, "[", tempScore, "]", SubStr(scores, Pos("]", scores) + 1, StrLen(scores)));
}
}
}
}
if(scoreSpot == 1)
{
begin = "null";
open = "(";
end = ")";
scoresp2 = SubStr(scores, Pos(")", scores) + 1, StrLen(scores));
scores = StrCat(name, open, NumToStr(totalTime), end, scoresp2);
}
else
{
if(scoreSpot == 5)
{
scoresp1 = SubStr(scores, 0, Pos(">", scores) + 1);
scores = StrCat(scoresp1, name, "/", NumToStr(totalTime), "\\");
}
else
{
if(scoreSpot == 2)
{
begin = ")";
open = "[";
end = "]";
}
if(scoreSpot == 3)
{
begin = "]";
open = "{";
end = "}";
}
if(scoreSpot == 4)
{
begin = "}";
open = "<";
end = ">";
}
scoresp1 = SubStr(scores, 0, Pos(begin, scores) + 1);
scoresp2 = SubStr(scores, Pos(end, scores) + 1, StrLen(scores));
scores = StrCat(scoresp1, name, open, NumToStr(totalTime), end, scoresp2);
}
}
DeleteFile("HighScores.txt");
CreateFile("HighScores.txt", 512, fileHandle);
WriteLnString(fileHandle, scores, bytesWritten);
CloseFile(fileHandle);
}
pscore1 = ParseScoreText(scores, "null", "(", ")", " ", " ", " ", 0, 0, 0, 0);
pscore2 = ParseScoreText(scores, ")", "[", "]", " ", " ", " ", 0, 0, 0, 0);
pscore3 = ParseScoreText(scores, "]", "{", "}", " ", " ", " ", 0, 0, 0, 0); //Parse the text fot the scores
pscore4 = ParseScoreText(scores, "}", "<", ">", " ", " ", " ", 0, 0, 0, 0);
pscore5 = ParseScoreText(scores, ">", "/", "\\", " ", " ", " ", 0, 0, 0, 0);
TextOut(32, LCD_LINE1, "-PONG-");
TextOut(14, LCD_LINE2, "High Scores:");
TextOut(0, LCD_LINE4, "1." + pscore1);
TextOut(0, LCD_LINE5, "2." + pscore2);
TextOut(0, LCD_LINE6, "3." + pscore3); //Display the scores
TextOut(0, LCD_LINE7, "4." + pscore4);
TextOut(0, LCD_LINE8, "5." + pscore5);
if(scoreSpot == 1) //If the player got the top score, then play a victory jingle
Victory();
if(scoreSpot > 1) //If the player didn't get the top score, then play a moderately happy jingle
GetHeartTank();
until(SENSOR_1);
until(!SENSOR_1); //Wait for the user to press and release the touch sensor
}
}
task calctimer()
{
while(true)
{
timer1 = CurrentTick() - offset1;
timer2 = CurrentTick() - offset2;
timer3 = CurrentTick() - offset3;
}
}
task checkCoins()
{
while(true)
{
until(check); //Proceed if the machine is expecting coins
until(SENSOR_3 < defaultLight-2 || SENSOR_3 > defaultLight+2); //Wait until a coin has been detected
degrees = MotorTachoCount(OUT_A); //See how long it took for the coin to get through
PlayTone(3000, 250);
ClearScreen();
TextOut(9, LCD_LINE3, "Please insert");
TextOut(34, LCD_LINE4, "coins");
if(centsToPay == 1)
cent = "cent";
else
cent = "cents";
TextOut(6, LCD_LINE7, NumToStr(centsToPay) + " " + cent + " to pay");
Off(OUT_A);
if(degrees < 520) //If it took less than 520 degrees,
{
centsToPay -= 10;
coin = 0; //the coin is a dime
}
else
{
if(degrees < 588) //If it took more than 520 degrees but less than 588,
{
centsToPay--;
coin = 1; //the coin is a penny
}
else
{
if(degrees < 780) //If it took more than 588 degrees but less than 780,
{
centsToPay -= 5;
coin = 2; //the coin is a nickel
}
else //If it took more than 780 degrees,
{
centsToPay -= 25;
coin = 3; //the coin is a quarter
}
}
}
Wait(300);
}
}
task secondary()
{
int Arrowpos = 22, SensorNew;
UseRS485(); // make sure the RS485 system is turned on
RS485Enable();
RS485Uart(HS_BAUD_DEFAULT, HS_MODE_DEFAULT);
Wait(1);
SendRS485Number(1); //Establish connection with the other NXT
WaitForMessageToBeSent();
defaultLight = SENSOR_3;
while(true)
{
while(true)
{
SensorNew = SENSOR_2;
TextOut(32, LCD_LINE1, "-PONG-");
TextOut(0, LCD_LINE2, "Select number of");
TextOut(28, LCD_LINE3, "players");
TextOut(25, LCD_LINE5, "1 Player");
TextOut(25, LCD_LINE6, "2 Players");
TextOut(18, Arrowpos, ">");
Wait(30); ClearScreen();
Position1 += CalcPosition(SensorNew);
if(Position1 < 0)
Position1 = 0; //Let the user select how many players he or she wants
if(Position1 > 21)
Position1 = 21;
if((Position1 >= 0) && (Position1 <= 10))
{
Players = 0;
Arrowpos = 29;
}
if((Position1 >= 11) && (Position1 <= 21))
{
Players = 1;
Arrowpos = 22;
}
if(SENSOR_1 == 1)
{
until(SENSOR_1 == 0);
break;
}
}
if(Players == 0) //If it's one player,
centsToPay = 25; //make the user pay 25 cents
else //If it's two players,
centsToPay = 50; //make the user pay 50 cents
check = true; //Start checking for coins
while(centsToPay > 0) //Mantain this loop as long as the user has not payed fully
{
ClearScreen();
TextOut(9, LCD_LINE3, "Please insert");
TextOut(34, LCD_LINE4, "coins");
if(centsToPay == 1)
cent = "cent";
else
cent = "cents";
TextOut(6, LCD_LINE7, NumToStr(centsToPay) + " " + cent + " to pay");
until(SENSOR_1 || RS485DataAvailable()); //Wait for the other NXT to register a coin first
RS485Read(Rx_Buffer);
if(!SENSOR_1)
{
offset3 = CurrentTick();
RotateMotorEx(OUT_A, 30, 1050, 0, false, true);
Wait(250);
if(coin == 0)
RotateMotorEx(OUT_A, 60, -677, 0, false, true);
if(coin == 1)
RotateMotorEx(OUT_A, 60, -750, 0, false, true);
if(coin == 2)
RotateMotorEx(OUT_A, 60, -965, 0, false, true);
if(coin == 3)
RotateMotorEx(OUT_A, 60, -1034, 0, false, true);
if(coin == 4)
RotateMotorEx(OUT_A, 60, -1200, 0, false, true);
ResetTachoCount(OUT_A);
coin = 4;
}
else //If the user wants a refund,
{
OnRev(OUT_B, 30);
OnFwd(OUT_C, 100);
Wait(1750);
Off(OUT_B); //Then send the money back,
Wait(100);
RotateMotorEx(OUT_B, 30, 28, 0, false, true);
Wait(1000);
Off(OUT_C);
if(Players == 0)
centsToPay = 25; //and reset the amount of money to be paid
else
centsToPay = 50;
}
} //End this loop when the game has been payed for
Deposit(); //Permanently deposit the money
check = false; //Stop checking for coins now that it's been paid
if(Players == 1) //If this is a 2-player game, then get the other NXT ready
{
SendRS485String("br");
WaitForMessageToBeSent();
}
else
{
Arrowpos = 15; Position1 = 0; SensorNew = 0;
while(true)
{
SensorNew = SENSOR_2;
TextOut(32, LCD_LINE1, "-PONG-");
TextOut(32, LCD_LINE2, "Select");
TextOut(0, LCD_LINE3, "difficulty level");
TextOut(25, LCD_LINE5, "Easy");
TextOut(25, LCD_LINE6, "Medium");
TextOut(25, LCD_LINE7, "Hard");
TextOut(25, LCD_LINE8, "Survival"); //If this is a 1-player game, then let the user select the difficulty
TextOut(18, Arrowpos, ">");
Wait(30); ClearScreen();
Position1 += CalcPosition(SensorNew);
if(Position1 < 0)
Position1 = 0;
if(Position1 > 43)
Position1 = 31;
if((Position1 >= 0) && (Position1 <= 10))
{
Difficulty = 1;
Arrowpos = 30;
}
if((Position1 >= 11) && (Position1 <= 21))
{
Difficulty = 2;
Arrowpos = 22;
}
if((Position1 >= 22) && (Position1 <= 32))
{
Difficulty = 3;
Arrowpos = 15;
}
if((Position1 >= 33) && (Position1 <= 43))
{
Difficulty = 4;
Arrowpos = 0;
}
if(SENSOR_1 == 1)
{
until(SENSOR_1 == 0);
break;
}
}
}
playpong();
}
}
task ball()
{
while(gameover == 0) //Proceed only if a game is going
{
until(activateball == 1); //Wait until the ball has been set loose,
ballhor = 1;
ballvert = 0; //then set the initial directions
while(activateball == 1) //Maintain this loop while a round is still going
{
if(ballvert)
BallY += 1; //If the ball's vertical direction is up, then move up
else
BallY -= 1; //If the ball's vertical direction is down, then move down
if(ballhor)
BallX += 1; //If the ball's horizontal direction is right, then move right
else
BallX -= 1; //If the ball's horizontal direction is left, then move left
if(BallY <= 4) //If the ball is entering player 1's territory,
BouncePaddle(lside1, rside1); //Then check if it's ready to bounce it, and act accordingly
if(BallY >= 56)//If the ball is entering player 2's territory,
BouncePaddle(lside2, rside2); //Then check if it's ready to bounce it, and act accordingly
if(BallY <= 0) //If the ball got past player 1,
{
activateball = 0; //then end the round,
p2score += 1; //and give player 2 a point
}
if(BallY >= 60) //If the ball got past player 2,
{
activateball = 0; //then end the round,
p1score += 1; //and give player 1 a point
}
if((BallX < 0) || (BallX > 96))
{
ballhor = !ballhor; //Keep the ball within the boundaries along the x axis
PlayTone(587, 100);
}
Wait(ballspeed); //Make the delay for this loop equal to the value of variable "ballspeed"
if(timer1 >= 10000)
{
ballspeed -= 5; //Every 10 seconds, decrease the delay by 5 miliseconds
offset1 = CurrentTick();
}
}
}
}
task main()
{
Precedes(secondary, checkCoins, ball, calctimer);
SetSensor(IN_1, SENSOR_TOUCH);
SetSensor(IN_2, SENSOR_ROTATION); //Initialize the sensors
SetSensorLight(IN_3);
ResetTachoCount(OUT_A);
Wait(1);
Deposit(); //Calibrate the holding area motor's position
}
Code: Select all
int cval;
inline void WaitForMessageToBeSent()
{
while(RS485SendingData())
Wait(1);
}
task main()
{
string buffer, debug;
bool gameover = 0, gamestart = 0;
int BallX, BallY, Position1, Position2, SensorOld, SensorNew, stringlength, Number;
int p1score, p2score;
SetSensor(IN_1, SENSOR_TOUCH);
SetSensor(IN_2, SENSOR_ROTATION);
SetSensorColorFull(S3);
ColorSensorReadType csr;
csr.Port = S3;
SetSensorColorFull(S3); //Initialize sensors
UseRS485(); // make sure the RS485 system is turned on
RS485Enable();
RS485Uart(HS_BAUD_DEFAULT, HS_MODE_DEFAULT);
Wait(1);
TextOut(0, LCD_LINE4, "Standing by...");
PlayTone(3000, 500);
while(true)
{
BallX = 49;
BallY = 29;
p1score = 0;
p2score = 0;
Position2 = 38; //Initialize some variables
while(true)
{
SysColorSensorRead(csr); //Read the color sensor
if(csr.ColorValue != 6 && csr.ColorValue != 1) //If a coin has been detected,
{
SendRS485Number(1);
WaitForMessageToBeSent(); //send a message to the master,
PlayTone(100, 100); //and play a beep
Wait(3000);
}
if(RS485DataAvailable())
{
RS485Read(buffer);
if(buffer == "br") //break if the slave receives the message: "br"
break;
}
}
while(true) //Begin pong
{
SensorNew = SENSOR_2;
repeat(3)
{
until(RS485DataAvailable());
RS485Read(buffer);
stringlength = StrLen(buffer);
stringlength--;
if("p" == LeftStr(buffer, 1)) //Read the opponent's paddle position,
Position1 = StrToNum(SubStr(buffer, 1, stringlength));
if("x" == LeftStr(buffer, 1)) //the ball's x position,
BallX = StrToNum(SubStr(buffer, 1, stringlength));
if("y" == LeftStr(buffer, 1)) //and the ball's y position
BallY = StrToNum(SubStr(buffer, 1, stringlength));
if(buffer == "t")
{
p2score++;
break;
} //Change the scores if a message telling it to has been received
if(buffer == "o")
{
p1score++;
break;
}
}
SendRS485Number(Position2); //Send the position of the player's paddle to the master
WaitForMessageToBeSent();
ClearScreen();
GraphicOut(Position2, 60, "Tray.ric");
GraphicOut(Position1, 0, "Tray.ric"); //Display the paddles and ball
GraphicOut(BallX, BallY, "Ball.ric");
if ((BallX == 49 && BallY == 29) || (BallY <= 1 || BallY >= 59))
{ //Show the scores if the time is appropriate
NumOut(49, LCD_LINE7, p1score);
NumOut(49, LCD_LINE2, p2score);
}
SensorOld = SensorNew;
SensorNew = SENSOR_2; //Make a few calculations for the paddle's position
SensorNew -= SensorOld;
Position2 += SensorNew;
if(Position2 < 0)
Position2 = 0;
if(Position2 > 76) //Keep the paddle within the boundaries
Position2 = 76;
if(p1score >= 5 || p2score >= 5)
break; //Break when someone has scored 5 points
}
Wait(500);
ClearScreen();
Wait(1250);
if(p2score > p1score) //If the player has won, let him or her know that
{
TextOut(25, LCD_LINE2, "You win!");
PlayToneEx(262, 96, 4, false);
Wait(96);
PlayToneEx(330, 96, 4, false);
Wait(96);
PlayToneEx(392, 96, 4, false);
Wait(96);
PlayToneEx(494, 96, 4, false);
Wait(96);
PlayToneEx(523, 96, 4, false);
Wait(96);
PlayToneEx(659, 96, 4, false);
Wait(96);
PlayToneEx(784, 96, 4, false);
Wait(96);
PlayToneEx(988, 96, 4, false);
Wait(96);
PlayToneEx(1046, 192, 4, false);
Wait(192);
PlayToneEx(1046, 96, 2, false);
Wait(96);
PlayToneEx(1046, 90, 4, false);
Wait(96);
PlayToneEx(1046, 96, 4, false);
Wait(96);
PlayToneEx(1046, 96, 2, false);
Wait(96);
repeat (3)
{
PlayToneEx(880, 96, 4, false);
Wait(96);
PlayToneEx(880, 96, 2, false);
Wait(96);
}
PlayToneEx(988, 864, 4, false);
Wait(864);
PlayToneEx(988, 96, 2, false);
Wait(92);
}
else //If the player has lost, let him or her know that
{
TextOut(25, LCD_LINE2, "You lose");
Wait(2880);
}
TextOut(30, LCD_LINE5, "SCORES:"); //Show the scores
TextOut(20, LCD_LINE7, "Player 1: " + NumToStr(p1score));
TextOut(20, LCD_LINE8, "Player 2: " + NumToStr(p2score));
Wait(1250);
until((SENSOR_1 == 1) || RS485DataAvailable()); //Start back at the beginning of the loop when either the player
until((SENSOR_1 == 0) || RS485DataAvailable()); //presses the touch sensor, or when it's needed for more coin receiving
ClearScreen();
}
}
Code: Select all
program test {
#include <RCX2.h>
#include <RCX2MLT.h>
#include <RCX2Sounds.h>
#include <RCX2Def.h>
sensor touch1 on 1
touch1 is switch as boolean
event tPress_touch1EventPress when touch1.pressed
event tRelease_touch1EventRelease when touch1.released
sensor touch2 on 2
touch2 is switch as boolean
event tPress_touch2EventPress when touch2.pressed
event tRelease_touch2EventRelease when touch2.released
sensor touch3 on 3
touch3 is switch as boolean
event tPress_touch3EventPress when touch3.pressed
event tRelease_touch3EventRelease when touch3.released
event greater_counter1EventHigh when counter1 > 100
event equal_counter1EventEqual when counter1 = 10
main {
ext InterfaceType "kFreestyle"
rcx_ClearTimers
bbs_GlobalReset([A B C])
trigger greater_counter1EventHigh
trigger equal_counter1EventEqual
start TouchWatcher0
start TouchWatcher1
start TouchWatcher2
trigger tRelease_touch1EventRelease
rcx_Priority( 8)
trigger tPress_touch1EventPress
trigger tPress_touch2EventPress
trigger tPress_touch3EventPress
try {
counter1 = 10
} retry on fail
try {
forever {
wait until greater_counter1EventHigh
sound 4
wait 200
bb_MotorControl ( [ ] , [ B ] , [ B ] , 170 )
wait until equal_counter1EventEqual
}
} retry on fail
}
watcher TouchWatcher0 monitor tPress_touch1EventPress
{
rcx_Priority( 3 )
try {
if counter1 = 40{
wait until tRelease_touch1EventRelease
counter1 += 10
}
else
{
if counter1 = 60{
wait until tRelease_touch1EventRelease
counter1 += 10
}
else
{
if counter1 = 100{
wait until tRelease_touch1EventRelease
counter1 += 10
}
else
{
if counter1 = 110{
wait until tRelease_touch1EventRelease
counter1 = 10
bb_MotorControl ( [B ] , [ ] , [ B ] , 330 )
}
else
{
counter1 = 10
sound 5
}
}
}
}
} restart on fail
} restart on event
watcher TouchWatcher1 monitor tPress_touch2EventPress
{
rcx_Priority( 3 )
try {
if counter1 < 40{
wait until tRelease_touch2EventRelease
counter1 += 10
}
else
{
if counter1 = 80{
wait until tRelease_touch2EventRelease
counter1 += 10
}
else
{
if counter1 = 110{
wait until tRelease_touch2EventRelease
counter1 = 10
bb_MotorControl ( [B ] , [ ] , [ B ] , 330 )
}
else
{
counter1 = 10
sound 5
}
}
}
} restart on fail
} restart on event
watcher TouchWatcher2 monitor tPress_touch3EventPress
{
rcx_Priority( 3 )
try {
if counter1 = 50{
wait until tRelease_touch3EventRelease
counter1 += 10
}
else
{
if counter1 = 70{
wait until tRelease_touch3EventRelease
counter1 += 10
}
else
{
if counter1 = 90{
wait until tRelease_touch3EventRelease
counter1 += 10
}
else
{
if counter1 = 110{
wait until tRelease_touch3EventRelease
counter1 = 10
bb_MotorControl ( [B ] , [ ] , [ B ] , 330 )
}
else
{
counter1 = 10
sound 5
}
}
}
}
} restart on fail
} restart on event
}
http://www.mediafire.com/view/3re3aoiec ... achine.pdf
The virtual model was built using the LDraw system of tools.
Here is a full video demonstration:
I began building this in August 2011. It took me about 2 weeks to build it, with minor revisions being made as time went on. Unfortunately, the programming part got severely delayed due to high school beginning for me when the 2011-2012 school year began. I got very busy, and blew my opportunity to get this project done during Summer 2012. The delay continued once again when the 2012-2013 year began, but I finally finished the programming in May 2013 after Summer began, just recently finished the documentation, and got the Youtube video published last night. This is a large part of the reason I haven't been super active these past 2 years. The fact that this project took me 2 years when it should have taken me little more than 4 months speaks volumes for the fact that it's nearing the time for me to start phasing out of MINDSTORMS. I also find this to be a fitting time to retire due to all these people of the new generation coming now that the EV3 is coming out. With this being my last project, I'm not sure how much longer you'll be seeing me here, or on any other MINDSTORMS websites, so I guess this thread could be considered my farewell to this community. I may drop in every once in a while, but for the most part I'm done. These three years with you guys have been awesome.