Вы забыли использовать new
для растрового изображения в конструкторе, поэтому вы загружаете файл bmp
в растровые объекты, которые еще не созданы, следовательно, нарушение прав доступа.Вы можете использовать прозрачность для растровых изображений tetrominos ... вам просто нужно активировать их на целевом холсте (например, Form1
... в его свойствах).Однако я хотел бы визуализировать мои tetrominos непосредственно в растровое изображение вместо использования файлов ... Вы можете использовать растровое изображение в качестве экранного буфера ...
Здесь простой BDS2006 C ++ / VCL Tetris пример, который я кодировал смои студенты во время одной лекции несколько лет назад, когда они хотели написать код игры и проголосовали за тетрис ... (уродливо, но работает ...)
//---------------------------------------------------------------------------
#include <vcl.h>
#pragma hdrstop
#include "win_main.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
// window
TForm1 *Form1;
// keyboard map
enum{
_key_left =0,
_key_right,
_key_rot ,
_key_drop ,
_keys
};
int keys [_keys]; // is key pressed ?
WORD keys_code[_keys]; // scan code
// back/double buffer
Graphics::TBitmap *bmp = new Graphics::TBitmap;
// scoore, position of falling tetromino,next shape
int score=0,px=0,py=0,novy_dielik=0;
// actual tetromino map
BYTE pm[4][4]=
{
0,0,1,0,
0,1,1,0,
0,0,1,0,
0,0,1,0
};
// game board size
const int map_xs=10;
const int map_ys=20;
BYTE map[map_xs][map_ys];
// tetrominos
BYTE shp[7*16]=
{
0,1,0,0,
0,1,0,0,
0,1,0,0,
0,1,0,0,
0,1,0,0,
0,1,0,0,
0,1,1,0,
0,0,0,0,
0,0,1,0,
0,0,1,0,
0,1,1,0,
0,0,0,0,
0,1,0,0,
0,1,1,0,
0,0,1,0,
0,0,0,0,
0,0,1,0,
0,1,1,0,
0,1,0,0,
0,0,0,0,
0,0,0,0,
0,0,1,0,
0,1,1,1,
0,0,0,0,
0,0,0,0,
0,1,1,0,
0,1,1,0,
0,0,0,0
};
//---------------------------------------------------------------------------
// tetromino colision test
//---------------------------------------------------------------------------
int step()
{
int i,j,x,y;
for (i=0;i<4;i++)
for (j=0;j<4;j++)
if (pm[i][j]!=0)
{
x=px+j;
y=py+i;
if (x<0) return 1;
if (x>=map_xs) return 1;
if (y<0) return 1;
if (y>=map_ys) return 1;
if (map[x][y]!=0) return 1;
}
return 0;
}
//---------------------------------------------------------------------------
// render game
//---------------------------------------------------------------------------
void draw()
{
// clear screen
bmp->Canvas->Brush->Color=clBlack;
bmp->Canvas->FillRect(TRect(0,0,bmp->Width,bmp->Height));
// [game board]
int x,y,a,i,j,adr;
x=bmp->Width/(map_xs+4+3);
y=bmp->Height/(map_ys+2);
if (x<y) a=x; else a=y;
// border
x=a; y=a;
bmp->Canvas->Pen->Color=clBlue;
bmp->Canvas->Pen->Width=a>>1;
bmp->Canvas->Rectangle(x,y,x+(map_xs*a),y+(map_ys*a));
bmp->Canvas->Pen->Width=1;
// game board
for (j=0;j<map_ys;j++)
{
for (i=0;i<map_xs;i++)
{
// set color from map
if (map[i][j]==0) bmp->Canvas->Brush->Color=clBlack;
else bmp->Canvas->Brush->Color=clAqua;
// grid cell
bmp->Canvas->FillRect(TRect(x,y,x+a,y+a));
x+=a; // posun sa o policko vpravo
}
x-=map_xs*a; // vrat sa vlavo
y+=a; // posun sa o policko dole
}
y-=map_ys*a; // vrat sa hore
// falling tetromino
x+=px*a;
y+=py*a;
for (j=0;j<4;j++)
{
for (i=0;i<4;i++)
{
// cell
if (pm[j][i]!=0)
{
bmp->Canvas->Brush->Color=clGreen;
bmp->Canvas->FillRect(TRect(x,y,x+a,y+a));
}
x+=a; // posun sa o policko vpravo
}
x-=4*a; // vrat sa vlavo
y+=a; // posun sa o policko dole
}
y-=4*a; // vrat sa hore
x-=px*a;
y-=py*a;
x+=(map_xs+1)*a; // posun sa na pravy stlpec
// score:
bmp->Canvas->Font->Color=clWhite;
bmp->Canvas->Brush->Color=clBlack;
bmp->Canvas->TextOutA(x,y,AnsiString().sprintf("Score: %i",score));
y+=a+a;
// border
bmp->Canvas->Pen->Color=clBlue;
bmp->Canvas->Pen->Width=a>>1;
bmp->Canvas->Rectangle(x,y,x+(4*a),y+(4*a));
bmp->Canvas->Pen->Width=1;
adr=16*novy_dielik;
for (j=0;j<4;j++)
{
for (i=0;i<4;i++)
{
// set color from map
if (shp[adr]==0) bmp->Canvas->Brush->Color=clBlack;
else bmp->Canvas->Brush->Color=clAqua;
// nakresli stvorcek
bmp->Canvas->FillRect(TRect(x,y,x+a,y+a));
x+=a; // go right
adr++;
}
x-=4*a; // return left
y+=a; // go down
}
y-=4*a; // return up
Form1->Canvas->Draw(0,0,bmp);
}
//--- konstruktor okna ------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
: TForm(Owner)
{
keys_code[_key_left ]='O';
keys_code[_key_right]='P';
keys_code[_key_rot ]='Q';
keys_code[_key_drop ]='A';
// new game
novy_dielik=rand()%7; // new tetromino
px=(map_xs>>1)-2; // position top/middle
py=0;
int adr=16*novy_dielik;
for (int j=0;j<4;j++) // copy it to pm
for (int i=0;i<4;i++)
{
pm[j][i]=shp[adr];
adr++;
}
for (int j=0;j<map_ys;j++) // clear map
for (int i=0;i<map_xs;i++)
map[i][j]=0;
novy_dielik=rand()%7;
}
//--- resize event ----------------------------------------------------------
void __fastcall TForm1::FormResize(TObject *Sender)
{
bmp->Width=ClientWidth;
bmp->Height=ClientHeight;
draw(); // force redraw
}
//--- redraw event ----------------------------------------------------------
void __fastcall TForm1::FormPaint(TObject *Sender)
{
draw();
}
//--- falling timer ---------------------------------------------------------
void __fastcall TForm1::Timer1Timer(TObject *Sender)
{
py++;
if (step()) // tetromino hit the ground?
{
py--;
int i,j,x,y,adr,e; // copy it to map
for (j=0;j<4;j++)
for (i=0;i<4;i++)
if (pm[j][i])
{
x=px+i;
y=py+j;
map[x][y]=1;
}
px=(map_xs>>1)-2; // new tetromino top/middle position
py=0;
adr=16*novy_dielik;
for (j=0;j<4;j++) // copy it to pm
for (i=0;i<4;i++)
{
pm[j][i]=shp[adr];
adr++;
}
// map full line test
int dscore=0;
for (j=map_ys-1;j>=0;j--)
{
e=1;
for (i=0;i<map_xs;i++)
if (map[i][j]==0)
{
e=0;
break;
}
if (e)
{
dscore<<=1;
dscore+=100;
e=j;
for (j=e-1;j>=0;j--)
for (i=0;i<map_xs;i++)
map[i][j+1]=map[i][j];
j=e+1;
draw();
Sleep(200);
}
}
score+=dscore;
if (step()) // end game? (no new tetromino)
{
int q;
q=bmp->Canvas->Font->Height;
bmp->Canvas->Font->Height=40;
bmp->Canvas->Font->Color=clRed;
bmp->Canvas->Brush->Style=bsClear;
AnsiString s="Game over";
bmp->Canvas->TextOutA(
(bmp->Width-bmp->Canvas->TextWidth(s))>>1,
(bmp->Height-bmp->Canvas->TextHeight(s))>>1,s);
bmp->Canvas->Brush->Style=bsSolid;
bmp->Canvas->Font->Height=q;
Form1->Canvas->Draw(0,0,bmp);
Sleep(1000);
// new game
novy_dielik=rand()%7; // new tetromino
px=(map_xs>>1)-2; // top/middle
py=0;
int adr=16*novy_dielik;
for (int j=0;j<4;j++) // copy it to pm
for (int i=0;i<4;i++)
{
pm[j][i]=shp[adr];
adr++;
}
for (int j=0;j<map_ys;j++) // clear board
for (int i=0;i<map_xs;i++)
map[i][j]=0;
novy_dielik=rand()%7;
}
novy_dielik=rand()%7; // random next tetromino 0-6
}
draw();
}
//--- keyboard timer --------------------------------------------------------
void __fastcall TForm1::Timer2Timer(TObject *Sender)
{
int e=0;
if (keys[_key_left ]!=0)
{
px--; if (step()) px++; else e=1;
}
if (keys[_key_right]!=0)
{
px++; if (step()) px--; else e=1;
}
if (keys[_key_rot ]!=0)
{
int i,j;
BYTE ori[4][4];
for (j=0;j<4;j++) for (i=0;i<4;i++) ori[i][j]=pm[i][j];
for (j=0;j<4;j++) for (i=0;i<4;i++) pm[3-j][i]=ori[i][j];
if (step()) for (j=0;j<4;j++) for (i=0;i<4;i++) pm[i][j]=ori[i][j];
else e=1;
}
if (keys[_key_drop ]!=0)
{
py++; if (step()) py--; else e=1;
}
if (e) draw();
}
//---------------------------------------------------------------------------
void __fastcall TForm1::FormKeyDown(TObject *Sender, WORD &Key,
TShiftState Shift)
{
Caption=Key;
for (int i=0;i<_keys;i++) // test all keys
if (Key==keys_code[i]) // if match
keys[i]=1; // set it as pressed
}
//---------------------------------------------------------------------------
void __fastcall TForm1::FormKeyUp(TObject *Sender, WORD &Key, TShiftState Shift)
{
for (int i=0;i<_keys;i++) // test all keys
if (Key==keys_code[i]) // if match
keys[i]=0; // set it as released
}
//---------------------------------------------------------------------------
void __fastcall TForm1::FormActivate(TObject *Sender)
{
for (int i=0;i<_keys;i++) // set all keys
keys[i]=0; // as released
}
//---------------------------------------------------------------------------
---------------------------------------
Это одно приложение формы с 2 таймерами на нем
Timer1
равно 250 мс
Timer2
- это80ms
Если вы хотите использовать мой, вы должны:
- создать пустую форму приложения
- установить 2 таймера и установить интервалы
- создавать все события, которые использует мой код
- копировать коды событий и игр в правильные места
Но вы должны использовать это скорее как подсказку, как может выглядеть архитектура игры.Я знаю, что это безобразно и без уроков (те ученики, у которых еще нет возможности ООП , и мы вместе закодировали игру, так что был достигнут некоторый консенсус по всем частям, чтобы сделать это простым ...)
Таким образом, bmp
походит на экранный буфер (чтобы избежать мерцания), управление осуществляется клавишами O P Q A
.Один таймер управляет падающей анимацией / симуляцией, а другой управляет клавиатурой.Рендеринг выполняется с использованием VCL инкапсулированных GDI и bmp
...
для получения дополнительной информации см .: