Well...the tutorial from this site that im following on building a tetris clone is outdated and i cant seem to get my blocks to appear on the screen. I do understand what im doing for the most part but up until this tutorial i never really worked much with Device Context, i normally used libraries and such for sprites and transformation... Anyways my problem is that i cant seem to get any blocks to display. I might have made a mistake somewhere but its compiling fine. Or maybe im just misunderstanding the tutorial because i dont see anywhere where actual block graphics are loaded in. So uh...thanks :D
Heres the code:
Actually...Heres the link to the tut im following first: http://www.gamedev.net/topic/192483-tetris-clone-in-an-hour-with-c/
bitmap.h
#ifndef BIMAPOBJECT_H
#define BIMAPOBJECT_H
#pragma once
#include <windows.h>
class bimapobject
{
public:
bimapobject();
virtual ~bimapobject();
void Load(HDC hdccompatable, LPCTSTR lpszFileName);
void Create(HDC hdccompatable, int height, int width);
void Destroy();
int GetHeight();
int GetWidth();
operator HDC();
protected:
private:
HDC hdcMemory;
HBITMAP hbitnewmap;
HBITMAP hbitoldmap;
int iWidth;
int iHeight;
};
#endif // BIMAPOBJECT_H
bimap.cpp
#include "bimapobject.h"
#include <windows.h>
bimapobject::bimapobject()
{
hdcMemory = NULL;
hbitnewmap = NULL;
hbitoldmap = NULL;
iWidth = 0;
iHeight = 0;
}
bimapobject::~bimapobject()
{
if(hdcMemory)
Destroy();
}
void bimapobject::Load(HDC hdcCompatable, LPCTSTR lpcFileName)
{
if(hdcMemory)
Destroy();
hdcCompatable = CreateCompatibleDC(hdcCompatable); //Creates Device Context Handler
hbitnewmap = (HBITMAP)LoadImage(NULL, lpcFileName, IMAGE_BITMAP,0,0,LR_LOADFROMFILE); // hbitnew holds this image
hbitoldmap = (HBITMAP)SelectObject(hdcMemory, hbitnewmap); // hbitoldmap takes the newmap and shoves it into hdcMemory
BITMAP bmp;
GetObject(hbitnewmap, sizeof(BITMAP),(LPVOID) &bmp); //bmp is the buffer to be filled by newmap, the size of the buffer is sizeofBITMAP
iWidth = bmp.bmWidth; //Sets the Private vars to their corrosponding Values
iHeight = bmp.bmHeight; // Sets the Private vars to their corrosponding Values ie. whatever the loaded bmp was
}
void bimapobject::Create(HDC hdcompatable, int height, int width)
{
if(hdcMemory)
Destroy();
hdcMemory = CreateCompatibleDC(hdcompatable); //Creates Device Context instance
hbitnewmap = CreateCompatibleBitmap(hdcompatable, height, width); //Creates the Bitmap
hbitoldmap =(HBITMAP)SelectObject(hdcMemory, hbitnewmap);
iWidth = width;
iHeight = height;
}
void bimapobject::Destroy()
{
SelectObject(hdcMemory,hbitoldmap);
DeleteObject(hbitnewmap);
DeleteDC(hdcMemory);
hdcMemory = NULL;
hbitnewmap = NULL;
hbitoldmap = NULL;
iWidth = 0;
iHeight = 0;
}
bimapobject::operator HDC()
{
return(hdcMemory);
}
int bimapobject::GetHeight(){
return iHeight;
}
int bimapobject::GetWidth(){
return iWidth;
}
main.cpp
#include <windows.h>
#include <stdlib.h>
#include "bimapobject.h"
//Create Variables
#define Windowclassname "Tetris"
#define WindowTitle "TetrisGame"
const int TILESIZE = 16;
const int MAP_WIDTH = 10;
const int MAP_HEIGHT = 30;
const int GREY = 8;
const int TILENODRAW = -1;
const int TILEBLACK = 0;
const int TILEGREY = 1;
const int TILEBLUE = 2;
const int TILERED = 3;
const int TILEGREEN = 4;
const int TILEYELLOW = 5;
const int TILEWHITE = 6;
const int TILESTEEL = 7;
const int TILEPURPLE = 8;
//functions
bool Gameint();
void GameLoop();
void GameDone();
void DrawTile(int x, int y, int tile);
void DrawMap();
void NewBlock();
void RotateBlock();
void move(int x, int y);
int CollisionDetect(int nx, int ny);
void RemoveRow(int x);
void NewGame();
HINSTANCE hInstmain = NULL;
HWND hwndMain;
int map[MAP_WIDTH][MAP_HEIGHT+1];
//PieceMaxSize = 16(4x4).
struct Piece
{
int size [4][4];
int x;
int y;
};
//Creates 2 objects;
Piece sPrePiece;
Piece sPiece;
//More Variables
DWORD start_time;
bool gamestarted=false;
//Creates two bitmap objects for the tiles and for the map
bimapobject bmoMap;
bimapobject bmoTiles;
//Predefined WindowProcFunction
LRESULT CALLBACK TheWindowProc(HWND hwnd, UINT uMsg,WPARAM wParam, LPARAM lParam)
{
switch(uMsg)
{
case WM_KEYDOWN:
{
if (wParam ==VK_ESCAPE)
{
DestroyWindow(hwnd);
return 0;
}
if(wParam == VK_DOWN)
{
move(0, 1);
return(0);
}
if(wParam == VK_UP)
{
RotateBlock();
return(0);
}
if(wParam == VK_LEFT)
{
move(-1,0);
}
if(wParam == VK_RIGHT)
{
move(1,0);
}
}
break;
case WM_DESTROY:
{
PostQuitMessage(0);
return(0);
}
break;
case WM_PAINT: //Called to Pain The Window
{
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hwnd, &ps);
BitBlt(hdc,0,0,TILESIZE*MAP_WIDTH+TILESIZE*GREY,TILESIZE*MAP_HEIGHT,bmoMap,0,0,SRCCOPY); //Pushes window paint info into the hdc
EndPaint(hwnd, &ps); //endPain Standard.
return(0);
}
break;
}
return (DefWindowProc(hwnd,uMsg,wParam,lParam));
}
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE Irrelevent, LPSTR lpcmdline, int nCmdShow)
{
hInstmain = hInstance;
WNDCLASSEX wclass;
wclass.cbClsExtra = 0;
wclass.cbSize = sizeof(WNDCLASSEX);
wclass.cbWndExtra = 0;
wclass.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
wclass.hCursor = LoadCursor(NULL, IDC_ARROW);
wclass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wclass.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
wclass.hInstance = hInstmain;
wclass.lpfnWndProc = TheWindowProc;
wclass.lpszClassName = Windowclassname;
wclass.lpszMenuName = NULL;
wclass.style = CS_OWNDC | CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS;
if(!RegisterClassEx(&wclass))
return (0);
hwndMain = CreateWindowEx(
0,
Windowclassname,
WindowTitle,
WS_BORDER | WS_SYSMENU | WS_CAPTION | WS_VISIBLE,
0,
0,
320,
240,
NULL,
NULL,
hInstmain,
NULL);
if(!hwndMain) return (0);
if(!Gameint()) return(0);
MSG msg;
for( ; ;)
{
if(PeekMessage(&msg,NULL,0,0,PM_REMOVE))
{
if(msg.message == WM_QUIT) break;
TranslateMessage(&msg);
DispatchMessage(&msg);
}
GameLoop();
}
GameDone();
return(msg.wParam);
}
bool Gameint()
{
RECT rcTemp;
SetRect(&rcTemp,0,0,MAP_WIDTH*TILESIZE+TILESIZE*TILEGREY, MAP_HEIGHT*TILESIZE); //160X480 Client Area
AdjustWindowRect(&rcTemp,WS_BORDER | WS_SYSMENU | WS_CAPTION | WS_VISIBLE, FALSE); //Stores adjustions in rcTemp
SetWindowPos(hwndMain,NULL,0,0,rcTemp.right-rcTemp.left,rcTemp.bottom-rcTemp.top,SWP_NOMOVE); //Sets Client Window Position
HDC hdc = GetDC(hwndMain); // Gets Device Context from window
bmoMap.Create(hdc, MAP_WIDTH*TILESIZE+TILEGREY*TILESIZE, MAP_HEIGHT*TILESIZE); //Creates map 10 tiles wide+grey tiles wide
FillRect(bmoMap,&rcTemp, (HBRUSH)GetStockObject(BLACK_BRUSH)); //Fills Client Area
ReleaseDC(hwndMain, hdc); // Release
bmoTiles.Load(hdc, "bitmap.bmp"); //Load
NewGame(); //Calls NewGame()
return(true);
}
void GameDone()
{
}
void GameLoop()
{
if((GetTickCount()-start_time) > 1000)
{
move(0,1); //Every one second move down
start_time = GetTickCount();
}
}
void NewGame()
{
start_time = GetTickCount();
gamestarted = false;
for (int x=0; x<MAP_WIDTH+1; x++) //Not Sure come back to this
{
for( int y=0; y<MAP_HEIGHT+1; y++) //Not sure, come back to this
{
if(y == MAP_HEIGHT)
map[x][y] = TILEGREY; //if y == the bottom of the mat its on a tile grey
else
map[x][y] = TILEBLACK; //If not y is in the black area
}
}
NewBlock();
DrawMap();
}
void DrawTile(int x, int y, int tile)
{
//mask than paint
BitBlt(bmoMap, x*TILESIZE, y*TILESIZE, TILESIZE, TILESIZE, bmoTiles, tile*TILESIZE, TILESIZE, SRCAND);
BitBlt(bmoMap, x*TILESIZE, y*TILESIZE, TILESIZE, TILESIZE, bmoTiles, tile*TILESIZE, TILESIZE, SRCPAINT);
}
void DrawMap()
{
//Draw Holder for Next Block
int xmy, ymx;
for(xmy = MAP_WIDTH; xmy < 4; xmy++ )
for(ymx = MAP_HEIGHT; ymx < 4; xmy++)
DrawTile(xmy, ymx, TILEGREY);
//Draw Previous Block
for(xmy = 0; xmy < 4; xmy++)
for(ymx = 0; ymx <4; ymx++ )
if(sPrePiece.size[xmy][ymx] != TILENODRAW)
DrawTile(sPrePiece.x+xmy, sPrePiece.y+ymx, sPrePiece.size[xmy][ymx]);
//Draw map
for(xmy = 0; xmy < MAP_WIDTH; xmy++)
for(ymx = 0; ymx <MAP_HEIGHT; ymx++)
DrawTile(xmy, ymx, map[xmy][ymx]);
//draw moving block
for(xmy = 0; xmy < 4; xmy++)
for(ymx = 0; ymx <4; ymx++)
if(sPiece.size[xmy][ymx] != TILENODRAW)
DrawTile(sPiece.x=xmy, sPiece.y+ymx, sPiece.size[xmy][ymx]);
InvalidateRect(hwndMain,NULL, FALSE);
}
void NewBlock()
{
int newblock;
int i, j;
// 0 1 2 3 4 5 6
// X These
// X XX X XX XX XX XX are
// X XX XXX XX XX X X block
// X X X types
srand(GetTickCount());
for(i = 0; i < 4; i++)
for(j = 0; j < 4; j++)
sPiece.size[j] = TILENODRAW;
sPiece.x = MAP_WIDTH/2-2;
sPiece.y = -1;
if(gamestarted == false)
{
gamestarted = true;
newblock = rand()%7;
switch(newblock)
{
case 0: //Tower
{
sPiece.size[1][0]=TILERED;
sPiece.size[1][1]=TILERED;
sPiece.size[1][2]=TILERED;
sPiece.size[1][3]=TILERED;
sPiece.y = 0;
}
break;
case 1: //Cube
{
sPiece.size[1][1]=TILEBLUE;
sPiece.size[1][2]=TILEBLUE;
sPiece.size[2][1]=TILEBLUE;
sPiece.size[2][2]=TILEBLUE;
}
break;
case 2: //Pyramid
{
sPiece.size[1][1] = TILESTEEL;
sPiece.size[0][2]=TILESTEEL;
sPiece.size[1][2]=TILESTEEL;
sPiece.size[2][2]=TILESTEEL;
}
break;
case 3: //Left Leaner
{
sPiece.size[0][1]=TILEYELLOW;
sPiece.size[1][1]=TILEYELLOW;
sPiece.size[1][2]=TILEYELLOW;
sPiece.size[0][2]=TILEYELLOW;
}
break;
case 4: //Right Leaner
{
sPiece.size[2][1]=TILEGREEN;
sPiece.size[1][1]=TILEGREEN;
sPiece.size[1][2]=TILEGREEN;
sPiece.size[0][2]=TILEGREEN;
}
break;
case 5: //Left Knight
{
sPiece.size[1][1]=TILEWHITE;
sPiece.size[2][1]=TILEWHITE;
sPiece.size[2][2]=TILEWHITE;
sPiece.size[2][3]=TILEWHITE;
}
break;
case 6: //Right Knight
{
sPiece.size[2][1]=TILEPURPLE;
sPiece.size[1][1]=TILEPURPLE;
sPiece.size[1][2]=TILEPURPLE;
sPiece.size[1][3]=TILEPURPLE;
}
break;
}
}
else
{
for(i = 0; i < 4; i++)
for(j=0; j< 4; j++)
sPiece.size[j] = sPrePiece.size[j];
newblock = rand()%7;
for(i = 0; i < 4; i++)
for(j=0; j< 4; j++)
sPrePiece.size[j] = TILENODRAW;
sPrePiece.x = MAP_WIDTH+GREY/4;
sPrePiece.x = GREY/4;
switch(newblock)
{
case 0: //Tower
{
sPiece.size[1][0]=TILERED;
sPiece.size[1][1]=TILERED;
sPiece.size[1][2]=TILERED;
sPiece.size[1][3]=TILERED;
sPiece.y = 0;
}
break;
case 1: //Cube
{
sPiece.size[1][1]=TILEBLUE;
sPiece.size[1][2]=TILEBLUE;
sPiece.size[2][1]=TILEBLUE;
sPiece.size[2][2]=TILEBLUE;
}
break;
case 2: //Pyramid
{
sPiece.size[1][1] = TILESTEEL;
sPiece.size[0][2]=TILESTEEL;
sPiece.size[1][2]=TILESTEEL;
sPiece.size[2][2]=TILESTEEL;
}
break;
case 3: //Left Leaner
{
sPiece.size[0][1]=TILEYELLOW;
sPiece.size[1][1]=TILEYELLOW;
sPiece.size[1][2]=TILEYELLOW;
sPiece.size[0][2]=TILEYELLOW;
}
break;
case 4: //Right Leaner
{
sPiece.size[2][1]=TILEGREEN;
sPiece.size[1][1]=TILEGREEN;
sPiece.size[1][2]=TILEGREEN;
sPiece.size[0][2]=TILEGREEN;
}
break;
case 5: //Left Knight
{
sPiece.size[1][1]=TILEWHITE;
sPiece.size[2][1]=TILEWHITE;
sPiece.size[2][2]=TILEWHITE;
sPiece.size[2][3]=TILEWHITE;
}
break;
case 6: //Right Knight
{
sPiece.size[2][1]=TILEPURPLE;
sPiece.size[1][1]=TILEPURPLE;
sPiece.size[1][2]=TILEPURPLE;
sPiece.size[1][3]=TILEPURPLE;
}
break;
}
}
DrawMap();
}
void RotateBlock() //Come Back To this
{
int i,j,temp[4][4];
for(i=0; i<4; i++)
for(j = 0; j<4; j++)//
temp[3-j]=sPiece.size[j];
//Collision Detection with border
for(i = 0; i <4 ; i++)
for(j=0; j<4; j++)
if(temp[j] != TILENODRAW)
if(sPiece.x + i <0 || sPiece.x + i > MAP_WIDTH-1 ||
sPiece.y + j < 0 || sPiece.y +j > MAP_HEIGHT-1 )
return; //If piece is on top or bottom or either side dont allow rotate. Return the function before rotate
//Come Back To This
for(int x=0; x< MAP_WIDTH; x++)
for(int y=0; y< MAP_HEIGHT; y++)
if(x >= sPiece.x && x < sPiece.x + 4)
if(y >= sPiece.y && y < sPiece.y +4)
if(map[x][y] != TILEBLACK)
if(temp[x - sPiece.x][y - sPiece.y] != TILENODRAW)
return;
for(i=0; i<4; i++)
for(j=0; j<4; j++)
sPiece.size[ i ][j]=temp[ i ][j];
DrawMap();
return;
}
void move(int x , int y)
{
if(CollisionDetect(x,y))
{
if(y == 1)
{
if(sPiece.y < 1)
{
NewGame();
}//You Lost
else
{
bool killblock = false;
int i, j;
//Come Back
for(i = 0; i<4; i++ )
for(j = 0; j<4; j++)
if(sPiece.size[j] != TILENODRAW) //If it can be drawn
map[sPiece.x+1][sPiece.y+1] =sPiece.size[j]; //sPiece.size says where to move on the map
for(j =0; j<MAP_HEIGHT; j++)
{
bool filled =true;
for(i=0; i<MAP_WIDTH; i++)
if(map[j] == TILEBLACK) //if there are any black tiles
filled = false; //Filled isnt true
if(filled)
{
RemoveRow(j);
killblock = true;
}
if(killblock)
{
for(i=0; i<4; i++)
for(j=0; j<4; j++)
sPiece.size[ i ][j]=TILENODRAW;
}
NewBlock();
}
}
}
else
{
sPiece.x +=x;
sPiece.y +=y;
}
DrawMap();
}
}
int CollisionDetect(int nx, int ny)
{
int newx=sPiece.x+nx;
int newy=sPiece.y+ny;
int i,j,x,y;
for(i=0; i<4; i++)
for(j=0; j<4; j++)
if(sPiece.size[j] != TILENODRAW)
if(newx +i < 0 || newx+i > MAP_WIDTH - 1 ||
newy + j <0 || newy + j > MAP_HEIGHT -1 )
return 1;
for(x= 0; x < MAP_WIDTH; x++)
for(y=0; y<MAP_HEIGHT; y++)
if(x>=newx && x < newx+4)
if(y >=newy && y < newy+4)
if(map[x][y] !=TILEBLACK)
if(sPiece.size[x-newx][y-newy] !=TILENODRAW)
return 1;
return 0;
}
void RemoveRow(int row)
{
int x,y;
int counter=0;
for(x=0; x< MAP_WIDTH; x++)
for(y=row; y>0; y--)
map[x][y]=map[x][y-1];
}