圖片分割,亂數排列,排圖小遊戲 |
|
dllee
站務副站長 發表:321 回覆:2519 積分:1711 註冊:2002-04-15 發送簡訊給我 |
本遊戲靈感來自
■【BCB】【發表】圖片分割,亂數排列
http://delphi.ktop.com.tw/topic.php?TOPIC_ID=50139 我不會美工,不然我想畫一些小朋友喜歡的圖應該是不錯玩 < >
附上幾張圖,所以有點大...
不想下的,可以直接看看以下的原始碼 < >
//--------------------------------------------------------------------------- #ifndef PartPictureUnitH #define PartPictureUnitH //--------------------------------------------------------------------------- #include //--------------------------------------------------------------------------- // 圖片分割,亂數排列,排圖小遊戲 by dllee http://dllee.ktop.com.tw // 本範例使用了以下技巧: // 1. 使用 Canvas->CopyRect() 分割圖片 // 2. 動態產生物件,及指定事件 // 3. 使用 TStringList 儲存元件 // 4. srand, random 產生亂數的方法 // 5. 以交換方式亂排 // 6. 移動元件 // 7. 使用 Canvas->StretchDraw() 自動縮放 //--------------------------------------------------------------------------- #includehttp://www.ViewMove.com 視動自動化科技股份有限公司 ViewMove Technologies, Inc. 發表人 - dllee 於 2004/05/30 23:07:08
------
http://www.ViewMove.com | |||
dllee
站務副站長 發表:321 回覆:2519 積分:1711 註冊:2002-04-15 發送簡訊給我 |
重貼程式碼:
■ PartPictureUnit.dfm [code cpp] object Form1: TForm1 Left = 194 Top = 115 BorderIcons = [biSystemMenu, biMinimize] BorderStyle = bsSingle Caption = '圖片分割,亂數排列,排圖小遊戲 by dllee http://dllee.ktop.com.tw' ClientHeight = 591 ClientWidth = 776 Color = clBtnFace Font.Charset = DEFAULT_CHARSET Font.Color = clWindowText Font.Height = -11 Font.Name = 'MS Sans Serif' Font.Style = [] Icon.Data = { 0000010001001010000000000000680500001600000028000000100000002000 0000010008000000000040010000000000000000000000000000000000000000 00000E0E0E00FFD4E300FFD0E000FFCCDD00FFCCDC00FFC8D900FFB2C700F2F2 F200EFEFEF00EDEDED00FFC3D500FFBACE00FF9FB800CECECE00C9C9C900B1B1 B100FFC6D700FFBDD000C2C2C200B6B6B6009E9E9E00FFB8CC00FFA3BC00E8E8 E800BABABA00DEDEDE00A2A2A200FFFFFF000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000001010101010101010101010101000000011A 1B151515011A1B15151501000000011819141415011819141415010000000108 0E13141501080E1314150100000001080E0E0F1001080E0E0F10010000000108 0808090A01080808090A0100000001010101010101010101010101000000011A 1B15151501000000000000000000011819141415010001010101010101000108 0E13141501000116170D0D0D010001080E0E0F1001000111120C0C0D01000108 0808090A01000102050B0C0D0100010101010101010001020505060701000000 000000000000010202020304010000000000000000000101010101010100FFFF 00000007000000070000000700000007000000070000000700000007000001FF 00000101000001010000010100000101000001010000FF010000FF010000} OldCreateOrder = False Position = poScreenCenter OnMouseMove = FormMouseMove PixelsPerInch = 96 TextHeight = 13 object Label1: TLabel Left = 16 Top = 18 Width = 53 Height = 15 AutoSize = False Caption = '切割數:' OnMouseMove = FormMouseMove end object Label3: TLabel Left = 534 Top = 72 Width = 235 Height = 197 AutoSize = False Caption = 'DEBUG' Font.Charset = ANSI_CHARSET Font.Color = clWindowText Font.Height = -12 Font.Name = 'Courier New' Font.Style = [] ParentFont = False WordWrap = True OnMouseMove = FormMouseMove end object Label2: TLabel Left = 406 Top = 18 Width = 48 Height = 13 Caption = '花費時間' OnMouseMove = FormMouseMove end object Image1: TImage Left = 36 Top = 66 Width = 105 Height = 105 end object Image2: TImage Left = 532 Top = 284 Width = 200 Height = 200 OnMouseMove = FormMouseMove end object ComboBox1: TComboBox Left = 66 Top = 14 Width = 133 Height = 21 Style = csDropDownList ItemHeight = 13 TabOrder = 0 OnChange = ComboBox1Change Items.Strings = ( '3 - Easy' '4 - Medium' '5 - Hard' '9 - OOXX') end object CheckBox1: TCheckBox Left = 536 Top = 8 Width = 97 Height = 17 Caption = '提示 ' Checked = True State = cbChecked TabOrder = 1 OnClick = CheckBox1Click OnMouseMove = FormMouseMove end object CheckBox2: TCheckBox Left = 536 Top = 34 Width = 97 Height = 17 Caption = '預覽全圖 ' Checked = True State = cbChecked TabOrder = 2 OnClick = CheckBox2Click OnMouseMove = FormMouseMove end object CheckBox3: TCheckBox Left = 646 Top = 8 Width = 97 Height = 17 Caption = '自由移動 ' TabOrder = 3 OnClick = CheckBox3Click OnMouseMove = FormMouseMove end object CheckBox4: TCheckBox Left = 646 Top = 34 Width = 119 Height = 17 Caption = '自動縮放原圖 ' Checked = True State = cbChecked TabOrder = 4 end object ComboBox2: TComboBox Left = 220 Top = 14 Width = 175 Height = 21 Style = csDropDownList ItemHeight = 13 TabOrder = 5 OnChange = ComboBox2Change Items.Strings = ( 'Level1 -- 牽牛花' 'Level2 -- 未成熟梨' 'Level3 -- 野菜' '[自行選檔]') end object OpenPictureDialog1: TOpenPictureDialog Filter = 'Bitmaps (*.bmp)|*.bmp' Left = 254 Top = 74 end object Timer1: TTimer Enabled = False Interval = 333 OnTimer = Timer1Timer Left = 354 Top = 74 end end [/code] ■ PartPictureUnit.h [code cpp] //--------------------------------------------------------------------------- #ifndef PartPictureUnitH #define PartPictureUnitH //--------------------------------------------------------------------------- #include #include #include #include <Forms.hpp><br />#include #include #include #include //--------------------------------------------------------------------------- class TForm1 : public TForm { __published: // IDE-managed Components TOpenPictureDialog *OpenPictureDialog1; TLabel *Label1; TComboBox *ComboBox1; TLabel *Label3; TLabel *Label2; TTimer *Timer1; TImage *Image1; TImage *Image2; TCheckBox *CheckBox1; TCheckBox *CheckBox2; TCheckBox *CheckBox3; TCheckBox *CheckBox4; TComboBox *ComboBox2; void __fastcall ComboBox1Change(TObject *Sender); void __fastcall ComboBox2Change(TObject *Sender); void __fastcall MyImageClick(TObject *Sender); void __fastcall Timer1Timer(TObject *Sender); void __fastcall CheckBox1Click(TObject *Sender); void __fastcall CheckBox2Click(TObject *Sender); void __fastcall ImageMouseDown(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y); void __fastcall ImageMouseMove(TObject *Sender, TShiftState Shift, int X, int Y); void __fastcall ImageMouseUp(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y); void __fastcall FormMouseMove(TObject *Sender, TShiftState Shift, int X, int Y); void __fastcall CheckBox3Click(TObject *Sender); private: // User declarations TStringList *MyImageList; int InVisibleIndex; int Part; int ChangeableIndex[4]; TDateTime StartTime; AnsiString LastSelectBmpFile; int LastSelectIndex; bool bMouseDown; int iDownIndex; int iDownX; int iDownY; int iImageX; int iImageY; bool bNeedExchange; bool bAlreadyDone; void __fastcall UpdateChangeableIndex(void); void __fastcall ChangeImage(int Index1,int Index2); void __fastcall UpdateDebugInformation(void); void __fastcall CheckIfAlreadyDone(void); void __fastcall RePartImage(AnsiString BmpFileName); public: // User declarations __fastcall TForm1(TComponent* Owner); }; //--------------------------------------------------------------------------- extern PACKAGE TForm1 *Form1; //--------------------------------------------------------------------------- #endif [/code] ■ PartPictureUnit.cpp [code cpp] //--------------------------------------------------------------------------- // 圖片分割,亂數排列,排圖小遊戲 by dllee http://dllee.ktop.com.tw // 本範例使用了以下技巧: // 1. 使用 Canvas->CopyRect() 分割圖片 // 2. 動態產生物件,及指定事件 // 3. 使用 TStringList 儲存元件 // 4. srand, random 產生亂數的方法 // 5. 以交換方式亂排 // 6. 移動元件 // 7. 使用 Canvas->StretchDraw() 自動縮放 //--------------------------------------------------------------------------- #include #pragma hdrstop #include "PartPictureUnit.h" //--------------------------------------------------------------------------- #pragma package(smart_init) #pragma resource "*.dfm" TForm1 *Form1; //--------------------------------------------------------------------------- __fastcall TForm1::TForm1(TComponent* Owner) : TForm(Owner) { MyImageList=new TStringList; Image1->Width=512; Image1->Height=512; Image1->Top=50; Image1->Left=0; Image1->Visible=false; ComboBox1->ItemIndex=0; ComboBox2->ItemIndex=0; CheckBox1Click(NULL); CheckBox2Click(NULL); ComboBox2Change(NULL); this->DoubleBuffered=true; } //--------------------------------------------------------------------------- void __fastcall TForm1::UpdateChangeableIndex(void) { // 左邊 if(InVisibleIndex%Part==0) // 已在最左邊 ChangeableIndex[0]=-1; else ChangeableIndex[0]=InVisibleIndex-1; // 右邊 if((InVisibleIndex 1)%Part==0) // 已在最右邊 ChangeableIndex[1]=-1; else ChangeableIndex[1]=InVisibleIndex 1; // 上面 if(InVisibleIndex/Part==0) // 已在最上面 ChangeableIndex[2]=-1; else ChangeableIndex[2]=InVisibleIndex-Part; // 下面 if(InVisibleIndex/Part==Part-1) // 已在最下面 ChangeableIndex[3]=-1; else ChangeableIndex[3]=InVisibleIndex Part; } //--------------------------------------------------------------------------- void __fastcall TForm1::ChangeImage(int Index1,int Index2) { AnsiString tempS=MyImageList->Strings[Index1]; TObject *tempO=MyImageList->Objects[Index1]; int temp1X=((TImage*)MyImageList->Objects[Index1])->Left; int temp1Y=((TImage*)MyImageList->Objects[Index1])->Top; int temp2X=((TImage*)MyImageList->Objects[Index2])->Left; int temp2Y=((TImage*)MyImageList->Objects[Index2])->Top; MyImageList->Strings[Index1]=MyImageList->Strings[Index2]; MyImageList->Objects[Index1]=MyImageList->Objects[Index2]; MyImageList->Strings[Index2]=tempS; MyImageList->Objects[Index2]=tempO; ((TImage*)MyImageList->Objects[Index1])->Left=temp1X; ((TImage*)MyImageList->Objects[Index1])->Top= temp1Y; ((TImage*)MyImageList->Objects[Index2])->Left=temp2X; ((TImage*)MyImageList->Objects[Index2])->Top= temp2Y; } //--------------------------------------------------------------------------- void __fastcall TForm1::UpdateDebugInformation(void) { AnsiString as=EmptyStr; for(int i=0;i as=as ((MyImageList->Strings[i].Length()==1)?" ":"") MyImageList->Strings[i] (((i 1)%Part==0)?"\n":" "); Label3->Caption=as; } //--------------------------------------------------------------------------- void __fastcall TForm1::CheckIfAlreadyDone(void) { // 判斷是否已經排好 for(int i=0;i { if(MyImageList->Strings[i]!=String(i 1)) return; } // 如果已排好,則把隱藏的那一塊顯示出來,同時禁止再移動了 ((TImage*)MyImageList->Objects[InVisibleIndex])->Visible=true; for(int i=0;i<4;i ) ChangeableIndex[i]=-1; Timer1->Enabled=false; // 不必再更新花費時間 bAlreadyDone=true; ShowMessage("恭喜您! 完成了!"); } //--------------------------------------------------------------------------- void __fastcall TForm1::RePartImage(AnsiString BmpFileName) { Part=ComboBox1->Text.SubString(1,1).ToIntDef(3); // 決定分割數 srand(GetTickCount()); // 決定亂數種子 for(int i=0;i delete ((TImage*)MyImageList->Objects[i]); MyImageList->Clear(); // 清除上次的圖案 Image1->Canvas->FillRect(Rect(0,0,512,512)); // 載入原始圖 Graphics::TBitmap *Bitmap = new Graphics::TBitmap(); Bitmap->LoadFromFile(BmpFileName); if(CheckBox4->Checked) // 自動縮放 Image1->Canvas->StretchDraw(Rect(0,0,512,512),Bitmap); else // 原圖切割 Image1->Canvas->CopyRect(Rect(0,0,512,512),Bitmap->Canvas, Rect(0,0,512,512)); Image2->Canvas->StretchDraw(Rect(0,0,200,200),Image1->Picture->Graphic); // 原圖參考 delete Bitmap; for(int i=0;i for(int j=0;j TImage *img=new TImage(this); // 建立圖片 img->Parent=this; img->Width=Image1->Width/Part; // 決定大小 img->Height=Image1->Height/Part; img->Canvas->CopyRect(Rect(0,0,img->Width,img->Height), Image1->Canvas, // 由原圖按順序切割成小圖 Rect(j*img->Width,i*img->Height,(j 1)*img->Width,(i 1)*img->Height)); img->Canvas->Brush->Color=clSilver; // 加灰色邊框 img->Canvas->FrameRect(Rect(0,0,img->Width,img->Height)); img->Left=(j)*(img->Width); img->Top =(i)*(img->Height) 50; // 保留上面 50 點給按鈕 img->MyImageClick; img->ImageMouseDown; img->ImageMouseMove; img->ImageMouseUp; img->Tag=i*Part j; MyImageList->AddObject(String(i*Part j 1),img); // 加入 ImageList 以便管理 } } InVisibleIndex=Part*Part-1; ((TImage*)MyImageList->Objects[InVisibleIndex])->Visible=false; for(int i=0;i { int ChangeIndex=random(MyImageList->Count); // 以亂數決定交換位置 (交換法) ChangeImage(InVisibleIndex,ChangeIndex); // 與不可見的交換 InVisibleIndex=ChangeIndex; } UpdateChangeableIndex(); UpdateDebugInformation(); CheckBox3Click(NULL); bAlreadyDone=false; StartTime=Now(); // 計時開始 Timer1->Enabled=true; // 開始顯示花費時間 LastSelectBmpFile=BmpFileName; } //--------------------------------------------------------------------------- void __fastcall TForm1::ComboBox1Change(TObject *Sender) { RePartImage(LastSelectBmpFile); } //--------------------------------------------------------------------------- void __fastcall TForm1::ComboBox2Change(TObject *Sender) { switch(ComboBox2->ItemIndex) { case 0: RePartImage(ExtractFilePath(Application->ExeName) "牽牛花.bmp"); LastSelectIndex=0; break; case 1: RePartImage(ExtractFilePath(Application->ExeName) "未成熟梨.bmp"); LastSelectIndex=1; break; case 2: RePartImage(ExtractFilePath(Application->ExeName) "野菜.bmp"); LastSelectIndex=2; break; default: if(OpenPictureDialog1->Execute()) // 選檔 RePartImage(OpenPictureDialog1->FileName); else { ComboBox2->ItemIndex=LastSelectIndex; ComboBox2Change(Sender); } break; } } //--------------------------------------------------------------------------- void __fastcall TForm1::MyImageClick(TObject *Sender) { if(bAlreadyDone // 如果已完成 || CheckBox3->Checked) // 在自由移動模式,不啟動以下程式 return; int ThisIndex=MyImageList->IndexOfObject(Sender); if(ThisIndex<0) return; // 判斷是否可以交換 bool Changeable=false; for(int i=0;i<4;i ) { if(ThisIndex==ChangeableIndex[i]) { Changeable=true; break; } } if(Changeable==false) return; // 與看不見的換位置 ChangeImage(InVisibleIndex,ThisIndex); InVisibleIndex=ThisIndex; UpdateChangeableIndex(); UpdateDebugInformation(); CheckIfAlreadyDone(); } //--------------------------------------------------------------------------- void __fastcall TForm1::Timer1Timer(TObject *Sender) { // 顯示花費時間 Label2->Caption=(Now()-StartTime).FormatString("hh:nn:ss"); } //--------------------------------------------------------------------------- void __fastcall TForm1::CheckBox1Click(TObject *Sender) { Label3->Visible=CheckBox1->Checked; } //--------------------------------------------------------------------------- void __fastcall TForm1::CheckBox2Click(TObject *Sender) { Image2->Visible=CheckBox2->Checked; } //--------------------------------------------------------------------------- void __fastcall TForm1::ImageMouseDown(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y) { if(bAlreadyDone // 如果已完成 || !CheckBox3->Checked) // 不在自由移動模式,不啟動以下程式 return; TImage *img=(TImage*)Sender; if(Button==mbLeft) { bMouseDown=true; iDownX=img->Width/2; iDownY=img->Height/2; iDownIndex=MyImageList->IndexOfObject(Sender); iImageX=img->Left; iImageY=img->Top; img->BringToFront(); ImageMouseMove(Sender,Shift,X,Y); } } //--------------------------------------------------------------------------- void __fastcall TForm1::ImageMouseMove(TObject *Sender, TShiftState Shift, int X, int Y) { if(bAlreadyDone // 如果已完成 || !CheckBox3->Checked) // 不在自由移動模式,不啟動以下程式 return; if(bMouseDown) { ((TImage*)Sender)->Left =X-iDownX; ((TImage*)Sender)->Top =Y-iDownY; } if(bNeedExchange) { ChangeImage(iDownIndex,MyImageList->IndexOfObject(Sender)); bNeedExchange=false; UpdateDebugInformation(); CheckIfAlreadyDone(); } } //--------------------------------------------------------------------------- void __fastcall TForm1::ImageMouseUp(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y) { if(bAlreadyDone // 如果已完成 || !CheckBox3->Checked) // 不在自由移動模式,不啟動以下程式 return; TImage *img=(TImage*)Sender; img->Left=iImageX; img->Top=iImageY; bMouseDown=false; bNeedExchange=true; } //--------------------------------------------------------------------------- void __fastcall TForm1::FormMouseMove(TObject *Sender, TShiftState Shift, int X, int Y) { bNeedExchange=false; } //--------------------------------------------------------------------------- void __fastcall TForm1::CheckBox3Click(TObject *Sender) { // 在自由移動模式,所有的圖都顯示,在非自動移動模式,有一個圖是隱藏的 ((TImage*)MyImageList->Objects[InVisibleIndex])->Visible=CheckBox3->Checked; } //--------------------------------------------------------------------------- [/code] ■ VMASK ■ VMIO-Server / HMI / SECS/GEM ■ blog.yam.com/dllee ■ dllee's StatPlus ■
------
http://www.ViewMove.com |
|||
dllee
站務副站長 發表:321 回覆:2519 積分:1711 註冊:2002-04-15 發送簡訊給我 |
RR7788, 您好, 不好意思,因為程式都在 Delphi.Ktop,有問題還是在此問會比較好,我也選擇在此回覆。 在我程式中 PartPictureUnit.cpp 第 146-149 img->On Click=MyImageClick; img->On MouseDown=ImageMouseDown; img->On MouseMove=ImageMouseMove; img->On MouseUp=ImageMouseUp; 主要設定 Image 的事件, MouseDown/Move/Up 主要用在自由移動(應該不是您想問的內容) Click 主要作的就是點圖移到附近的空位上,也就是您想問的部分。 MyImageClick() 在 第 211 行先找出是那個 Image 被點到, 因為 Sender 就是被點到的 Image 元件指標,在事前已將 所有 Image 都放在 MyImageList 內,所以用 IndexOfObject(Sender) 就可以取得是分割出來的第幾個小圖。 第 215-223 就是判斷點到的圖可不可以移, 我的作法是, 因為空位只有一個,所以,最多只有 4 個位置可以移到此空位,因此, 在確定好空位後,就把可以移入的 4 個位置放在 ChangeableIndex[ ] 內, 就作位置的比對,確認所點的圖是否在這 4 個位置, 如果不是,就不理會此次的圖檔 Click 如果是,就移動圖檔 ChangeImage(InVisibleIndex,ThisIndex); 更新看空位的位置 InVisibleIndex=ThisIndex; 更新可移位空位的位置 UpdateChangeableIndex(); 更新 DEBUG 資訊(顯示目前小圖的編號) UpdateDebugInformation(); 檢查是否已排好 CheckIfAlreadyDone(); 我想,應該不難,在 IDE 好好的單步 Trace,查看/記錄變數變化的狀況,就會更明白。 ■ VMASK ■ VMIO-Server / HMI / SECS/GEM ■ blog.yam.com/dllee ■ dllee's StatPlus ■
------
http://www.ViewMove.com |
|||
rr7788
一般會員 發表:2 回覆:6 積分:1 註冊:2008-05-13 發送簡訊給我 |
||||
dllee
站務副站長 發表:321 回覆:2519 積分:1711 註冊:2002-04-15 發送簡訊給我 |
UpdateChangeableIndex() 就是更新可移到空位的位置
以目前空位的位置,其上下左右為可移到空位的位置, 如果已在最上,當然,就無法由其上面移下圖。 同理己在最下,也無法由其下面移上圖, 同樣左右也是,就是作這些判斷而已。 此函式原有的註解應該夠清楚了。 ChangeImage() 就是把兩個影像位置互換 所以記錄了兩張圖的位置,並互換, 其中,因為我把圖的編號放在一個 StringList 內,並把圖放在它的 ObjectList 內, 所以,多了這個部分的處理。 在發表過的文提問或回覆,我會收到 EMail 通知,就會知道有人回覆了。 Blog 提問... 我 Blog 設的 EMail 是 Yahoo,我並不會去 Check Yahoo 的 EMail,因為垃圾信太多了。 ■ VMASK ■ VMIO-Server / HMI / SECS/GEM ■ blog.yam.com/dllee ■ dllee's StatPlus ■
------
http://www.ViewMove.com |
本站聲明 |
1. 本論壇為無營利行為之開放平台,所有文章都是由網友自行張貼,如牽涉到法律糾紛一切與本站無關。 2. 假如網友發表之內容涉及侵權,而損及您的利益,請立即通知版主刪除。 3. 請勿批評中華民國元首及政府或批評各政黨,是藍是綠本站無權干涉,但這裡不是政治性論壇! |