Android遊戲Graphics繪圖之影象畫素操作
阿新 • • 發佈:2019-02-20
我們在玩遊戲時經常會看到一些影象的特效,比如半透明等效果。要實現這些效果並不難,只需要對影象本身的畫素執行操作。Android中的 Bitmap同樣提供了操作畫素的方法,可以通過getPixels方法來獲得該影象的畫素並放到一個數組中,我們處理這個畫素陣列就可以了,最後通過 setPixels設定這個畫素陣列到Bitmap中。
在Android中,每一個影象畫素通過一個4位元組整數來展現:最高位位元組用作Alpha通道,即用來實現透明與不透明控制,255代表完全不透明,0則代表完全透明;接下來的一個位元組是Red紅色通道,255代表完全是紅色。依次類推,接下來的兩個位元組相應地實現綠色和藍色通道。
下面的示例通過對影象畫素的操作來模擬水紋效果,如圖5-11所示。
實現程式碼如下所示:
001 |
package
com.yarin.android.Examples_05_10; |
002 |
003 |
import
android.content.Context; |
004 |
import
android.graphics.Bitmap; |
005 |
import
android.graphics.BitmapFactory; |
006 |
import
android.graphics.Canvas; |
007 |
import
android.view.KeyEvent; |
008 |
import
android.view.MotionEvent; |
009 |
import
android.view.View; |
010 |
011 |
public
class GameView extends
View implements
Runnable |
012 |
{ |
013 |
int
BACKWIDTH; |
014 |
015 |
int
BACKHEIGHT; |
016 |
017 |
short [] buf2;
|
018 |
019 |
short [] buf1;
|
020 |
021 |
int [] Bitmap2;
|
022 |
023 |
int [] Bitmap1;
|
024 |
025 |
public
GameView(Context context) |
026 |
{
|
027 |
super (context);
|
028 |
029 |
/** 裝載圖片 */ |
030 |
Bitmap image = BitmapFactory.decodeResource( this .getResources(),R.drawable.qq);
|
031 |
BACKWIDTH = image.getWidth();
|
032 |
BACKHEIGHT = image.getHeight();
|
033 |
034 |
buf2 =
new short [BACKWIDTH * BACKHEIGHT];
|
035 |
buf1 =
new short [BACKWIDTH * BACKHEIGHT];
|
036 |
Bitmap2 =
new int [BACKWIDTH * BACKHEIGHT];
|
037 |
Bitmap1 =
new int [BACKWIDTH * BACKHEIGHT];
|
038 |
039 |
/** 載入圖片的畫素到陣列中 */ |
040 |
image.getPixels(Bitmap1,
0 , BACKWIDTH,
0 , 0 , BACKWIDTH, BACKHEIGHT);
|
041 |
042 |
new
Thread( this ).start();
|
043 |
}
|
044 |
045 |
046 |
void
DropStone( int
x, // x座標 |
047 |
int
y, // y座標 |
048 |
int
stonesize, // 波源半徑
|
049 |
int
stoneweight) // 波源能量
|
050 |
{
|
051 |
for
( int
posx = x - stonesize; posx < x + stonesize; posx++) |
052 |
for
( int
posy = y - stonesize; posy < y + stonesize; posy++) |
053 |
if
((posx - x) * (posx - x) + (posy - y) * (posy - y) < stonesize * stonesize)
|
054 |
buf1[BACKWIDTH * posy + posx] = ( short ) -stoneweight;
|
055 |
}
|
056 |
057 |
058 |
void
RippleSpread() |
059 |
{
|
060 |
for
( int
i = BACKWIDTH; i < BACKWIDTH * BACKHEIGHT - BACKWIDTH; i++) |
061 |
{
|
062 |
// 波能擴散
|
063 |
buf2[i] = ( short ) (((buf1[i -
1 ] + buf1[i +
1 ] + buf1[i - BACKWIDTH] + buf1[i + BACKWIDTH]) >>
1 ) - buf2[i]);
|
064 |
// 波能衰減
|
065 |
buf2[i] -= buf2[i] >>
5 ; |
066 |
}
|
067 |
068 |
// 交換波能資料緩衝區
|
069 |
short [] ptmp = buf1;
|
070 |
buf1 = buf2;
|
071 |
buf2 = ptmp;
|
072 |
}
|
073 |
074 |
/** 渲染你水紋效果 */ |
075 |
void
render() |
076 |
{
|
077 |
int
xoff, yoff; |
078 |
int
k = BACKWIDTH; |
079 |
for
( int
i = 1 ; i < BACKHEIGHT -
1 ; i++) |
080 |
{
|
081 |
for
( int
j = 0 ; j < BACKWIDTH; j++)
|
082 |
{
|
083 |
// 計算偏移量
|
084 |
xoff = buf1[k -
1 ] - buf1[k +
1 ]; |
085 |
yoff = buf1[k - BACKWIDTH] - buf1[k + BACKWIDTH];
|
086 |
087 |
// 判斷座標是否在視窗範圍內
|
088 |
if
((i + yoff) < 0 )
|
089 |
{
|
090 |
k++;
|
091 |
continue ;
|
092 |
}
|
093 |
if
((i + yoff) > BACKHEIGHT) |
094 |
{
|
095 |
k++;
|
096 |
continue ;
|
097 |
}
|
098 |
if
((j + xoff) < 0 )
|
099 |
{
|
100 |
k++;
|
101 |
continue ;
|
102 |
}
|
103 |
if
((j + xoff) > BACKWIDTH) |
104 |
{
|
105 |
k++;
|
106 |
continue ;
|
107 |
}
|
108 |
109 |
// 計算出偏移象素和原始象素的記憶體地址偏移量
|
110 |
int
pos1, pos2; |
111 |
pos1 = BACKWIDTH * (i + yoff) + (j + xoff);
|
112 |
pos2 = BACKWIDTH * i + j;
|
113 |
Bitmap2[pos2++] = Bitmap1[pos1++];
|
114 |
k++;
|
115 |
}
|
116 |
}
|
117 |
}
|
118 |
119 |
public
void onDraw(Canvas canvas)
|
120 |
{
|
121 |
super .onDraw(canvas);
|
122 |
123 |
/** 繪製經過處理的圖片效果 */ |
124 |
canvas.drawBitmap(Bitmap2,
0 , BACKWIDTH,
0 , 0 , BACKWIDTH, BACKHEIGHT,
false , null );
|
125 |
}
|
126 |
127 |
// 觸筆事件
|
128 |
public
boolean onTouchEvent(MotionEvent event)
|
129 |
{
|
130 |
131 |
return
true ; |
132 |
}
|
133 |
134 |
135 |
// 按鍵按下事件
|
136 |
public
boolean onKeyDown( int
keyCode, KeyEvent event) |
137 |
{
|
138 |
return
true ; |
139 |
}
|
140 |
141 |
142 |
// 按鍵彈起事件
|
143 |
public
boolean onKeyUp( int
keyCode, KeyEvent event) |
144 |
{
|
145 |
DropStone(BACKWIDTH/ 2 , BACKHEIGHT/ 2 ,
10 , 30 );
|
146 |
return
false ; |
147 |
}
|
148 |
149 |
150 |
public
boolean onKeyMultiple( int
keyCode, int
repeatCount, KeyEvent event) |
151 |
{
|
152 |
return
true ; |
153 |
}
|
154 |
155 |
/**
|
156 |
* 執行緒處理
|
157 |
*/ |
158 |
public
void run() |
159 |
{
|
160 |
while
(!Thread.currentThread().isInterrupted()) |
161 |
{
|
162 |
try |
163 |
{
|
164 |
Thread.sleep( 50 );
|
165 |
}
|
166 |
catch
(InterruptedException e) |
167 |
{
|
168 |
Thread.currentThread().interrupt();
|
169 |
}
|
170 |
RippleSpread();
|
171 |
render();
|
172 |
//使用postInvalidate可以直接線上程中更新介面
|
173 |
postInvalidate();
|
174 |
}
|
175 |
}
|
176 |
} |