Delphi 经典游戏程序设计40例 的学习例4 大型图像4个方向的滚动
unit rei40_04; interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls, ExtCtrls; type TRein40_04 = class(TForm) Button1: TButton; Button2: TButton; Button3: TButton; Button4: TButton; Button5: TButton; tmr1: TTimer; procedure FormCreate(Sender: TObject); procedure tmr1Timer(Sender: TObject); procedure Button1MouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); procedure Button2MouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); procedure Button3MouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); procedure Button4MouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); procedure Button5MouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); procedure FormClose(Sender: TObject; var Action: TCloseAction); private { Private declarations } public { Public declarations } end; const Yoko = 39; //图案数 Tate = 29; GmenX = (Yoko-2)*16; //显示点数,像素点数? 592,464 GmenY = (tate-2)*16; Mdot =2 ; //滚动点数 var Rein40_04: TRein40_04; LoadBmap :TBitmap; //图案库BMP MakeBmap :TBitmap; //预览BMP BigMap : array[0..255,0..255] of Byte; //图案数组,构成图片 P,PX,PY :Byte; // p 图案代码,PX,PY 在图案库里的坐标 MapX,MapY,DX,DY :Byte; // 显示图像X,Y格数,位移点数 Dir,NextD : Byte; // NEXTD 方向, RectL,RectG,RectM,RectC :TRect; implementation {$R *.dfm} procedure TRein40_04.FormCreate(Sender: TObject); var x,y :Byte; begin LoadBmap := TBitmap.Create; LoadBmap.LoadFromFile(GetCurrentDir+'\Pat_sample.bmp'); for y:=0 to 255 do for x:=0 to 255 do begin if (x=0)or (x=255)or (y=0)or (y=255) then p:=2 else if (x=128)and (y=128) then p:=2 else if (x<5)or (x>250)or (y<5)or (y>250) then P:=12 else if (x<15)or (x>235)or (y<15)or (y>235) then P:=15 else if (x<138) and (x>118) and (y<138) and (y>128) then P:=15 else if (x<148)and (x>108)and (y<148)and (y>108)then P:=14 else if (x*y<25000)and (x*y > 23000)then P:=13 else if (x*y<28000)and (x*y>20000) then P:=12 else if (x*y<31000)and (x*y>17000) then P:=15 else if (x*y<34000)and (x*y > 14000)then P:=13 else if (x*y<37000)and (x*y>11000) then P:=14 else if (x*y<40000)and (x*y>8000) then P:=12 else if (x*y<43000)and (x*y > 6000)then P:=15 else if (x*y<47000)and (x*y>4000) then P:=14 else if (x*y<50000)and (x*y>2000) then P:=13 else if (x*y<53000)and (x*y>1000) then P:=12 else P:=2; BigMap[x,y] := P; //大地图数据 end; MakeBmap := TBitmap.Create; MakeBmap.Height :=Tate * 16; //预览 MakeBmap.Width :=Yoko *16; MapX := 109; //初始显示图像开始位置 MapY :=114; DX :=16; // 位移初始设置 DY :=16; Dir :=0; //滚动方向,现在,下次 NextD :=0; MakeBmap.Canvas.CopyMode :=cmSrcCopy; for y:=0 to (Tate-1)do for x:=0 to (Yoko-1) do begin P := Bigmap[MapX+x,MapY+y] ; //格子数不会溢出吗? PX := (p mod 16) *16; PY := (p div 16) *16; RectL :=Rect(PX,PY,PX+16,PY+16); RectM :=Rect(x*16,y*16,x*16+16,y*16+16); MakeBmap.Canvas.CopyRect(RectM,LoadBmap.Canvas,RectL); end; end; procedure TRein40_04.tmr1Timer(Sender: TObject); var x,y :Byte; begin case Dir of //滚动方向 1: DY := DY - Mdot; // 上 2: DY := DY + Mdot; // 下 3: DX := DX - Mdot; // 左 4: DX := DX + Mdot; // 右, end; Rein40_04.Canvas.CopyMode :=cmSrcCopy; RectM :=Rect(DX,DY,DX + GmenX,DY + GmenY); RectG :=Rect(0,0,GmenX,GmenY); Rein40_04.Canvas.CopyRect(RectG,MakeBmap.Canvas,RectM); if ((DX and 31)= 0) or ((DY and 31)=0) then //超边界 // if (dx = 31) or (dy = 31) then begin MakeBmap.Canvas.CopyMode := cmSrcCopy; case Dir of 1: begin //图像上限 RectM := Rect(0,0, GmenX+ 32, GmenY+16); RectC := Rect(0,16,GmenX+32,GmenY+32); MakeBmap.Canvas.CopyRect(RectC,MakeBmap.Canvas,RectM); MapY :=MapY -1; for x :=0 to (Yoko -1 ) do begin p:= BigMap[(MapX +x )and $FF,MapY]; PX := (p mod 16) *16; PY := (p div 16) *16; RectL := Rect(PX,PY,PX+16,PY+16); RectM := Rect(x*16,0,x*16+16,16); MakeBmap.Canvas.CopyRect(RectM,LoadBmap.Canvas,RectL); end; end; 2:begin //图像下限 RectM :=Rect(0,16,GmenX+32,GmenY +32); RectC :=Rect(0,0,GmenX+32,GmenY +16); MakeBmap.Canvas.CopyRect(RectC,MakeBmap.Canvas,RectM); MapY :=MapY +1; for x:=0 to (Yoko -1) do begin p:= BigMap[MapX+x,MapY]; PX := (p mod 16) *16; PY := (p div 16) *16; RectL :=Rect(PX,PY,PX+16,PY+16); RectM :=Rect(x*16,GmenY+16,x*16+16,GmenY+32); MakeBmap.Canvas.CopyRect(RectM,LoadBmap.Canvas,RectL); end; end; 3:begin //图像左限 RectM :=Rect(0,0,GmenX+16,GmenY +32); RectC :=Rect(16,0,GmenX+32,GmenY +32); MakeBmap.Canvas.CopyRect(RectC,MakeBmap.Canvas,RectM); MapX :=MapX -1; for y:=0 to (Tate -1) do begin p:= BigMap[MapX,MapY+y]; PX := (p mod 16) *16; PY := (p div 16) *16; RectL :=Rect(PX,PY,PX+16,PY+16); RectM :=Rect(0,y*16,16,y*16+16); MakeBmap.Canvas.CopyRect(RectM,LoadBmap.Canvas,RectL); end; end; 4:begin //图像右限 RectM :=Rect(16,0,GmenX+32,GmenY +32); RectC :=Rect(0,0,GmenX+16,GmenY +32); MakeBmap.Canvas.CopyRect(RectC,MakeBmap.Canvas,RectM); Mapx :=MapX +1; for y:=0 to (Tate -1) do begin p:= BigMap[MapX,MapY+y]; PX := (p mod 16) *16; PY := (p div 16) *16; RectL :=Rect(PX,PY,PX+16,PY+16); RectM :=Rect(GmenX+16,y*16,GmenX+32,y*16+16); MakeBmap.Canvas.CopyRect(RectM,LoadBmap.Canvas,RectL); end; end; end; Dir :=NextD; //重新设置滚动方向 DX :=16; DY :=16; end; end; procedure TRein40_04.Button1MouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); begin NextD :=1; if Dir =0 then Dir :=1; end; procedure TRein40_04.Button2MouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); begin NextD :=2; if Dir =0 then Dir :=2; end; procedure TRein40_04.Button3MouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); begin NextD :=3; if Dir =0 then Dir :=3; end; procedure TRein40_04.Button4MouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); begin NextD := 4; if Dir =0 then Dir :=4; end; procedure TRein40_04.Button5MouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); begin NextD :=0; end; procedure TRein40_04.FormClose(Sender: TObject; var Action: TCloseAction); begin LoadBmap.Free; MakeBmap.Free; end; end.
原理理解了,
在makebmap 里面做一个 比显示 大 2格的 图像
显示可以移动,当 超过 这个2格 边界的时候 就重新 做 makebmap 补上。
大部分的 变量 设置可以理解,
问题1 为什么要将方向 设为一个现在DIR ,一个下次 NEXTD ?
还要在DIR=0 停止的情况下改变 DIR 的方向?
答案:改了下程序,直接 DIR 等于 NEXTD ,程序正常。
问题 2,这个比较难了,关于 用 逻辑运算代替算术运算, 的问题。应该是可以节省 计算机的算力吧,
但是有点难以理解。
if ((DX and 31)= 0) or ((DY and 31)=0) then
功能和这个一样
if (dx >31) or (dy >31) or (dx < 1 )or (DY <1) then