Już od bardzo dawna nic tutaj nie pisałem… Niestety, miałem bardzo mało czasu, a teraz nie mam go wiele więcej, więc częstotliwość zamieszczania postów raczej się u mnie nie zwiększy.
Jeśli kogoś to interesuje, to udało mi się jakimś cudem dostać w tym roku do finału Olimpiady Informatycznej (do której przygotowania kosztowały mnie mnóstwo czasu i wysiłku).
Aby ten post nie zawierał jedynie chwalenia się i narzekania na brak czasu, postanowiłem zamieścić kod pewnej gry, którą tworzyłem w wakacje około 2 godzin. Cechą charakterystyczną tej gry jest to, że cała jej oprawa graficzna składa się ze znaków wyświetlanych w standardowej konsoli Windows’a.
Celem rozgrywki jest dotarcie jak najniżej i zdobycie jak największej ilości punktów. Trzeba unikać przeszkód („kolców”), które pojawiają się na drodze i zabierają cenne HP.
Kod pliku conoleRenderer.h
//Author: lukaszw #pragma once #include <Windows.h> class consoleRenderer { private: struct elementData { char c; int color; bool operator==(const elementData &el) { return c==el.c&&color==el.color; } bool operator!=(const elementData &el) { return !((*this)==el); } elementData():c(0),color(24) { } elementData &operator=(const elementData &el) { c=el.c; color=el.color; return *this; } }; HANDLE conOut; elementData scr[2][1024][80]; int w; int h; int currBuff; public: class sprite { friend class consoleRenderer; private: elementData *data; int w; int h; public: sprite(int w,int h):data(new elementData[w*h]),w(w),h(h) { } ~sprite() { delete[] data; } void setCharAt(int x,int y,char c,int color=24) { data[y*w+x].c=c; data[y*w+x].color=color; } }; consoleRenderer(int h):conOut(GetStdHandle(STD_OUTPUT_HANDLE)),w(80),h(h),currBuff(0) { CONSOLE_CURSOR_INFO ci; ci.bVisible=false; ci.dwSize=sizeof(ci); SetConsoleCursorInfo(conOut,&ci); } ~consoleRenderer() { } void drawSprite(int x,int y,const sprite &spr) { const elementData *ptr=spr.data; for(int myY=0;myY<min(spr.h,h-y);++myY) { for(int myX=0;myX<min(spr.w,w-x);++myX) { if(myY+y<0||myX+x<0)continue; scr[currBuff&1][myY+y][myX+x]=*(ptr++); } } } void clear(int color=FOREGROUND_INTENSITY) { for(int y=0;y<h;++y) for(int x=0;x<w;++x) { scr[currBuff&1][y][x].c=' '; scr[currBuff&1][y][x].color=color; } } void drawChar(int x,int y,char c,int color=FOREGROUND_INTENSITY) { if(x<0||y<0)return; if(y>=h)return; if(x>=w)return; scr[currBuff&1][y][x].c=c; scr[currBuff&1][y][x].color=color; } void drawString(int x,int y,const char *str,int color=24) { while(*str!=0) { drawChar(x++,y,*str,color); ++str; } } void flush() { for(int y=0;y<h;++y) { for(int x=0;x<w;++x) { if(scr[currBuff&1][y][x]!=scr[(currBuff+1)&1][y][x]) { COORD crd={x,y}; SetConsoleCursorPosition(conOut,crd); SetConsoleTextAttribute(conOut,scr[currBuff&1][y][x].color); char buff[2]={(scr[currBuff&1][y][x].c),0}; DWORD ret; WriteConsoleA(conOut,buff,1,&ret,0); } } } ++currBuff; COORD crd={0,0}; SetConsoleCursorPosition(conOut,crd); } };
Kod gry:
//Author: lukaszw #include "stdafx.h" //#include <stdio.h> //#include <tchar.h> // //#include <Windows.h> //#include <cstdio> //#include <algorithm> //#include <vector> //#include <string> //#include <fstream> //#include <ctime> //#include <conio.h> //#include <list> //using namespace std; #include "consoleRenderer.h" float g=0.0010f; consoleRenderer *rndr; int random(int a,int b) { return rand()%(b-a)+a; } static const char platformImg[]={219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219}; static const char platformImg2[]={30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30}; consoleRenderer::sprite platformSprite(18,1),platformSprite2(18,1); void initPlatformSprite() { for(int i=0;i<18;++i) { platformSprite.setCharAt(i,0,platformImg[i],FOREGROUND_BLUE|BACKGROUND_BLUE); platformSprite2.setCharAt(i,0,platformImg2[i],FOREGROUND_RED); } } struct platform { int x,y; int w; bool dangerous; platform(){} platform(int x,int y,int w,bool d):x(x),y(y),w(w),dangerous(d) { } }; vector<platform> platforms; struct player { float hp; float x,y; float vx,vy; int lvl; float timeToNextLvl; float bulletTimeTime; int prevY; int points; player(int x,int y):hp(100),x(x),y(y),lvl(1),timeToNextLvl(100),bulletTimeTime(100),prevY(0),points(0) { for(int i=platforms.size();i<y+50;++i) { platforms.push_back(platform(random(-10,80),i,(i%3!=0)?0:18,random(0,10)%4==0)); } } void update(float dt) { if(prevY!=(int)y) { prevY=(int)y; points+=lvl; } if(platforms.size()<y+40) { for(int i=platforms.size();i<y+50;++i) { platforms.push_back(platform(random(-10,80),i,(i%3!=0)?0:18,random(0,10)%4==0)); } } if(x>=platforms[y].x&&x<=platforms[y].x+platforms[y].w) { vy=0; if(platforms[y].dangerous)hp-=0.05*dt; else if(hp<100)hp+=0.001*dt; } else { vy=lvl*0.25*0.0125f; if(hp<100)hp+=0.001*dt; } if(GetAsyncKeyState(VK_RIGHT)) { vx=0.025; } else if(GetAsyncKeyState(VK_LEFT)) { vx=-0.05; } else { vx=0; } if(GetAsyncKeyState(VK_DOWN))vy*=4; else if(GetAsyncKeyState(VK_UP)&&bulletTimeTime>0) { vy*=0.25; bulletTimeTime-=4*0.01f*dt; } if(hp>100)hp=100; x+=vx*dt; y+=vy*dt; if(x<0)x=0; if(x>79-3)x=79-3; bulletTimeTime+=0.01f*dt; if(bulletTimeTime>100)bulletTimeTime=100; timeToNextLvl-=0.01*dt; if(timeToNextLvl<0) { timeToNextLvl=100; ++lvl; } } void draw() { rndr->drawChar(x,8,148,FOREGROUND_GREEN); for(int i=max(0,y-8);i<y+20;++i) { if(platforms[i].w>0) { if(platforms[i].dangerous)rndr->drawSprite(platforms[i].x,i-(int)y+9,platformSprite2); else rndr->drawSprite(platforms[i].x,i-(int)y+9,platformSprite); } } char buff[81]; sprintf_s(buff,"HP: %3d Points: %6d Level: %3d (%d) Bullet time: %3d",max((int)hp,0),points,lvl,(int)(timeToNextLvl*0.1f),(int)(bulletTimeTime)); for(int i=strlen(buff);i<80;++i)buff[i]=' '; buff[80]=0; rndr->drawString(0,0,buff,FOREGROUND_INTENSITY); } }; bool g_tryAgain; void gameOver(int pts) { while(!GetAsyncKeyState(VK_ESCAPE)) { rndr->clear(0); rndr->drawString(30,10,"GAME OVER",FOREGROUND_RED); rndr->drawString(30,11,"Your result: ",FOREGROUND_INTENSITY); char buff[32]; sprintf_s(buff,"%6d",pts); rndr->drawString(46,11,buff,FOREGROUND_GREEN); rndr->drawString(30,13,"Try again? [Y/N]",FOREGROUND_INTENSITY); rndr->flush(); if(GetAsyncKeyState('Y')) { g_tryAgain=true; break; } else if(GetAsyncKeyState('N')) { g_tryAgain=false; break; } } } int _tmain(int argc, _TCHAR* argv[]) { SetConsoleTitleA("Falling down by lukaszw"); srand(time(0)); rndr=new consoleRenderer(25); do { g_tryAgain=false; platforms.clear(); platforms.push_back(platform(0,0,18,false)); initPlatformSprite(); float accumulator=0.f; float dt; float timeStep=0.5f; float lastUpdateTime=GetTickCount(); player myPlayer(0,0); while(!GetAsyncKeyState(VK_ESCAPE)&&myPlayer.hp>0) { float currentTime=GetTickCount(); dt=currentTime-lastUpdateTime; accumulator+=dt; lastUpdateTime=currentTime; while(accumulator>timeStep) { accumulator-=timeStep; myPlayer.update(timeStep); } rndr->clear(); myPlayer.draw(); rndr->flush(); } if(myPlayer.hp<=0)gameOver(myPlayer.points); } while(g_tryAgain); delete rndr; return 0; }
Mam nadzieję, że komuś ten kod się przyda.