My first One-Page Game is complete, and I completed the most restrictive challenge – a game in one 80×60 page! And here it is!
#include <windows.h>
#include <vector>
using namespace std;HANDLE wh;HANDLE rh;CHAR_INFO bb[4000];COORD cBS={80,50};
COORD cPos = {0,0};SMALL_RECT wA = {0,0,79,49};bool running=true;int fc = 0;
struct u{int x;int y;int dx;int dy;int state;};vector<u> c;vector<u> mush;
vector<u> bullets;u s = {20, 49, 0, 0, 1};int score,lives,i,j;SetChar(int x,
int y,char c,int a){bb[(y*80)+x].Char.AsciiChar=c;bb[(y*80)+x].Attributes=a;}
void ResetC(){c.clear();u head={19,0,1,1,1};c.push_back(head);for(i=18;i>=0;--i)
{u b={i,0,0,0,0};c.push_back(b);}}SetPos(int x,int y){COORD c1={x,y};
SetConsoleCursorPosition(wh,c1);}MoveCP(){if(fc%2){for(i=19;i>-1;--i){int headx,
heady;if(c[i].state==1){int tx=c[i].x+c[i].dx;bool hm=false;for(j=0;j<
mush.size();++j){if(c[i].x+c[i].dx==mush[j].x&&c[i].y==mush[j].y&&mush[j].state)
hm=true;}if(tx>40||tx<0||hm){c[i].dx=-c[i].dx;int ty=c[i].y+c[i].dy;if(ty>49||
ty<0||(ty<39&&c[i].dy==-1)){c[i].dy=-c[i].dy;}c[i].y+=c[i].dy;}else{c[i].x+=
c[i].dx;}}else{c[i].x=c[i-1].x;c[i].y=c[i-1].y;}}}}MoveS(){bool ok=true;for(i=0;
i<mush.size();++i){if(s.dx==mush[i].x&&s.dy==mush[i].y)ok=false;}if(ok){s.x=
s.dx;s.y = s.dy;}}MoveB(){for(j=0;j<2;++j){for(i=0;i<20;++i){int mrx,mry;
if(c[i].state==1){mrx=c[i].dx;mry=c[i].dy;}if(bullets[j].x==c[i].x&&bullets[j].y
==c[i].y&&bullets[j].state!=0&&c[i].state!=-1){if(c[i].state==0)score+=10;else
score+=50;u m={c[i].x,c[i].y,0,0,1};mush.push_back(m);bullets[j].state=0;
c[i].state=-1;if(i!= 19){if(c[i+1].state!=-1){c[i+1].state=1;c[i+1].dx=mrx;
c[i+1].dy = mry;}}int lc=0;for(int z=0;z<20;++z){if(c[z].state!=-1)++lc;}
if(lc==0)ResetC();}}for(i=0;i<mush.size();++i){if(bullets[j].x==mush[i].x&&
bullets[j].y==mush[i].y&&bullets[j].state!=0&&mush[i].state==1){bullets[j].state
=0;mush[i].state=0;score+=3;}}if(bullets[j].state==1){--bullets[j].y;
if(bullets[j].y < 0)bullets[j].state=0;}}}Init(){wh=GetStdHandle(
STD_OUTPUT_HANDLE);rh=GetStdHandle(STD_INPUT_HANDLE);SMALL_RECT w={0,0,79,49};
SetConsoleWindowInfo(wh,TRUE,&w);COORD b={80,50};SetConsoleScreenBufferSize(wh,
b);}Input(){DWORD nE=0;DWORD nER=0;GetNumberOfConsoleInputEvents(rh,&nE);if(nE!=
0){INPUT_RECORD *eB=new INPUT_RECORD[nE];ReadConsoleInput(rh,eB,nE,&nER);for(i=
0;i<nER;++i){if (eB[i].EventType==KEY_EVENT){if(eB[i].Event.KeyEvent.
wVirtualKeyCode==VK_ESCAPE){running=false;}}else if(eB[i].EventType==
MOUSE_EVENT){s.dx=eB[i].Event.MouseEvent.dwMousePosition.X;if(s.dx>40)s.dx=40;
s.dy=eB[i].Event.MouseEvent.dwMousePosition.Y;if(s.dy<40)s.dy=40;if(eB[i].Event.
MouseEvent.dwButtonState&FROM_LEFT_1ST_BUTTON_PRESSED){for(int z=0;z<2;++z){
if(bullets[z].state == 0){bullets[z].x=s.x;bullets[z].y=s.y-1;bullets[z].state
=1;break;}}}}}delete eB;}}ResetM(){mush.clear();for(i=0;i<100;++i){u m={rand()
%40,(rand()%46)+1,0,0,1};mush.push_back(m);}}int main(int argc,char* argv[])
{Init();ResetC();ResetM();u b1={ -1, -1, 0, 0, 0};bullets.push_back(b1);bullets.
push_back(b1);score=0;lives=3;while(running){ZeroMemory(bb,4000*sizeof(
CHAR_INFO));Input();MoveCP();MoveS();MoveB();for(i=0;i<50;++i)SetChar(41,i,219,
15);SetChar(s.x,s.y,127,15);for(i=0;i<20;++i){if(c[i].state==1){SetChar(c[i].x,
c[i].y,1,2);}else if(c[i].state==0){SetChar(c[i].x,c[i].y,15,2);}}for(i=0;i<
mush.size();++i){if(mush[i].state){SetChar(mush[i].x,mush[i].y,6,14);}}for(i=0;
i<2;++i){if(bullets[i].state)SetChar(bullets[i].x,bullets[i].y,24,15);}
WriteConsoleOutput(wh,bb,cBS,cPos,&wA);bool ll=false;for(i=0;i<c.size();++i){
if(c[i].state!=-1&&c[i].x==s.x&&c[i].y==s.y){--lives;ll=true;ResetC();}}int mc
=0;for(i=0;i<mush.size();++i)if(mush[i].state)++mc;if(mc<50){int nm=0;do{nm=
rand()%mush.size();}while(mush[nm].state);mush[nm].state=1;}SetPos(45,0);printf(
"SANDWORM!");SetPos(45,1);printf("Score: %d",score);SetPos(45,2);printf(
"Lives: %d",lives);if(!lives){SetPos(16,20);printf("GAME OVER");Sleep(5000);
score=0;lives=3;ResetM();}else if(ll)Sleep(1000);else Sleep(17);++fc;}return 0;}
Create a new console application project in Visual Studio, paste that into the source file, and compile it. If you have trouble compiling the file, it might be easier to debug if you had a cleaner version – so here’s one.
Or, if that’s too much trouble, you can just download the executable.
The game is a simplified version of the classic arcade game Centipede. You control your shooter with the mouse and fire with the left mouse button. Shooting the sandworm creates a new rock and splits the sandworm into two separate parts. Breaking a rock gets you three points, hitting a sandworm segment gets you ten points, and hitting a sandworm head gets you fifty points. You can have up to two shots on the screen at the same time. If you manage to kill the entire sandworm, a new one respawns. If any part of the sandworm hits you, you lose a life. Lose all your lives and it’s game over, but a new game will start in a few seconds automatically. Press ESC on your keyboard to exit the game. Press ALT + ENTER to play in fullscreen mode.
Here I’ve chopped the sandworm up into sushi…I’m probably going to regret that in a few minutes.
I was quite nervous about coming in under the limit because of the incredibly long function and constant names Windows insists on using. I was surprised when I did the final compress to see that I had a full eight lines free, more than enough space to put in another feature like the spider or the flea! But this will do for a first version.
Needless to say, the code is filthy. You may have problems on other platforms with the fact that I don’t declare return values for a lot of my functions (VS 2003 supplies int automatically) and use variables without initializing them first. And if you’re not on Windows…well, good luck 🙂
So, challenge successfully accomplished! I just wish Tom would get off his duff and complete his two-page 3D RPG…you will NOT believe your eyes when you see it.
For my next challenge, I will almost certainly attempt an RPG in one page of source. But it’s not like I’m obsessed with RPGs or anything…
Oh come on, can you really claim to have written a program in C++ without declaring your variables? 😛
Hey, I typed something into the compiler and a working program came out. That’s the only criteria I recognize 🙂
That’s impressive and all, but really more impressed at the speed you complete a game. Like you did for your 40 hour games. Try one hour or two hour games 🙂
Keith
Dude, that is the awesomest thing ever.
Spider! I demand spider!
This is very impressive :). May I ask how long it took you to complete this challenge time-wise? It would be interesting to see something like this for other languages as well – perhaps see how much gameplay a page of C++ can pack in versus a page of Java? 🙂
Ryan: I don’t want to put in the spider. I always hated the spider – it comes in at an unpredictale angle while you’re trying to focus on the centipede. The whole point of the spider was to kill the player quickly so he’d have to put in another quarter.
Chuch: I’d say it probably took me about five hours total to write once I figured out the proper way to write a Windows console application.
Keith: That would be an interesting challenge, which I may take on at some point 🙂
[…] I wrote a little arcade game. […]
[…] a one-page game called Collector. Collector is based on a famous arcade game just like my game Sandworm was. Which one? I’ll let you find out yourself Casey said that he likes the one-page game […]