說明:
一、本程序是一個斜視角地圖的滾屏演示。本程序在實現的時候並沒有考慮屏幕渲染效率和內存空間的節省問題。所以地圖繪制函數並沒有對不可視的圖塊部分進行排除。本程序的實現完全采用了win32匯編語言,因此采用gdi接口也能獲得較好的幀速。
二、本程序反映了2d游戲地圖的控制思路。即,核心問題是幾個坐標變換問題,解決了坐標變換就可以了。
1、保存地圖的一維數據索引。需要把這個一維數組索引轉變成地圖坐標,即(列號,行號)。完成這一步以後,繪圖程序才能遍歷整個一維數組,就象遍歷
一個二維的地圖塊數組一樣。即通過數組索引確定它是在地圖上的坐標。
2、地圖坐標----圖塊列號、行號。地圖坐標轉變成屏幕貼圖坐標。因為地圖坐標是(列號、行號),所以必須要通過地圖坐標求解出地圖塊左上角的像素坐標,即貼圖坐標。
3、進行視變換。即,地圖很大的時候,把視口舉行在地圖上進行平移就可以實現地圖的滾動,看到不同的部分。所以,一旦視口的左上角在地圖上的絕對坐標確定下來,那麼一個地圖塊在視口內部的相對坐標------最終的窗口客戶區貼圖坐標就可以求出。
4、經過上面幾步變換,一個地圖塊就真正的可以被繪制到窗口裡面。
三、幀速控制:
a、用變量timeOld記錄上次計算幀速結束的時間。
b、變量timeNew記錄當前時間。
c、用變量frameCount記錄從timeOld到timeNew的間隔裡一共播放的幀數。
d、每次獲取當前時間timeNew以後,求自從
上次計算幀速結束到現在一共有多少時間(ms):timeNew - timeOld
當這個時間間隔大於1秒,就進行一次幀速計算,並且令timeOld = timeNew,frameCount也歸零,准備從現在重新記錄幀播放,以備在下一秒進行計算。
e、用timeCur進行時間跟蹤,以便幀速控制。
timeCur記錄上次播放一幀結束的時間。timeNew - timeCur表示自從上次播放一幀到現在經過了多少時間。
所以如果每次當 timeNew - timeCur > 10的時候才進行一幀的播放,然後令timeCur = timeNew,以便進行下一幀播放時間間隔的控制。這樣我們就可以控制在每個10ms內最多播放一幀,即對幀速進行了控制。
代碼說明:
本例子主要的代碼是地圖繪制函數,地圖繪制函數實現了幾個坐標變換。
DrawMap proc hdc1:HDC
LOCAL i:DWORD
LOCAL row:DWORD
LOCAL col:DWORD
LOCAL xAbs:DWORD
LOCAL yAbs:DWORD
LOCAL vx:DWORD
LOCAL vy:DWORD
LOCAL vp:POINT
invoke BitBlt,buffer,0,0,640,480,bgDC,0,0,SRCCOPY
mov i,0
.repeat
;把數組索引轉變成地圖坐標
xor edx,edx
mov eax,i
mov ebx,20
div ebx
mov row,edx
mov col,eax
;把地圖坐標轉變成貼圖坐標(絕對坐標)
mov eax,row
mov ebx,64/2
mul ebx
mov xAbs,eax
mov eax,col
mul ebx
sub xAbs,eax
mov eax,xstart
add xAbs,eax
mov eax,col
mov ebx,32/2
mul ebx
mov yAbs,eax
mov eax,row
mul ebx
add yAbs,eax
mov eax,ystart
add yAbs,eax
;根據視口坐標,把貼圖坐標轉變成窗口(視口)坐標
mov eax,xAbs
sub eax,viewRect.left
mov vx,eax
mov eax,yAbs
sub eax,viewRect.top
mov vy,eax
;進行屏幕貼圖
mov eax,i
.if mapInfo[eax]==0
invoke BitBlt,buffer,vx,vy,64,32,tile0,64,0,SRCAND
invoke BitBlt,buffer,vx,vy,64,32,tile0,0,0,SRCPAINT
.elseif mapInfo[eax]==1
invoke BitBlt,buffer,vx,vy,64,32,tile1,64,0,SRCAND
invoke BitBlt,buffer,vx,vy,64,32,tile1,0,0,SRCPAINT
.elseif mapInfo[eax]==2
invoke BitBlt,buffer,vx,vy,64,32,tile2,64,0,SRCAND
invoke BitBlt,buffer,vx,vy,64,32,tile2,0,0,SRCPAINT
.else
invoke BitBlt,buffer,vx,vy,64,32,tile3,64,0,SRCAND
invoke BitBlt,buffer,vx,vy,64,32,tile3,0,0,SRCPAINT
.endif
;
add i,1
.until i==400
;處理景物
mov i,0
.repeat
;把數組索引轉變成地圖坐標
xor edx,edx
mov eax,i
mov ebx,20
div ebx
mov row,edx
mov col,eax
;把地圖坐標轉變成貼圖坐標(絕對坐標)
mov eax,row
mov ebx,64/2
mul ebx
mov xAbs,eax
mov eax,col
mul ebx
sub xAbs,eax
mov eax,xstart
add xAbs,eax
mov eax,col
mov ebx,32/2
mul ebx
mov yAbs,eax
mov eax,row
mul ebx
add yAbs,eax
mov eax,ystart
add yAbs,eax
;根據視口坐標,把貼圖坐標轉變成窗口(視口)坐標
mov eax,xAbs
sub eax,viewRect.left
mov vx,eax
mov eax,yAbs
sub eax,viewRect.top
mov vy,eax
;進行屏幕貼圖
mov eax,i
.if sceneInfo[eax]==1
add vx,7
sub vy,44
invoke BitBlt,buffer,vx,vy,50,60,scene1,50,0,SRCAND
invoke BitBlt,buffer,vx,vy,50,60,scene1,0,0,SRCPAINT
.elseif sceneInfo[eax]==2
add vx,7
sub vy,30
invoke BitBlt,buffer,vx,vy,50,60,scene2,50,0,SRCAND
invoke BitBlt,buffer,vx,vy,50,60,scene2,0,0,SRCPAINT
.endif
;
add i,1
.until i==400
;<<<<<<<<<<<<<<<<<<處理精靈<<<<<<<<<<<<<<<<<<<<<<<<<<<<
mov eax,viewRect.left
mov vp.x,eax
mov eax,viewRect.top
mov vp.y,eax
invoke GetStatus
.if eax==0
invoke SetDir
.endif
invoke DrawSprite,buffer,vp
;打印程序信息
invoke SetBkMode,buffer,TRANSPARENT
invoke TextOut,buffer,50,300,addr frameInfo,28
invoke TextOut,buffer, 50,350,addr appInfo,sizeof appInfo - 1
invoke TextOut,buffer,55, 400,addr authInfo,sizeof authInfo - 1
invoke SetBkMode,buffer,OPAQUE
invoke BitBlt,hdc1,0,0,640,480,buffer,0,0,SRCCOPY
ret
DrawMap endp