转载自【黑米GameDev街区】 原文链接: http://www.himigame.com/android-game/298.html
———————————————————————
『很多童鞋说我的代码运行后,点击home或者back后会程序异常,如果你也这样遇到过,那么你肯定没有仔细读完Himi的博文,第十九篇Himi专门写了关于这些错误的原因和解决方法,这里我在博客都补充说明下,省的童鞋们总疑惑这一块;请点击下面联系进入阅读:
【Android游戏开发十九】(必看篇)SurfaceView运行机制详解—剖析Back与Home按键及切入后台等异常处理! 』
——————————————————————-
其实上一篇分析surfaceview的文章就是一个简单的游戏框架了,当然这里再强调一下,简单的游戏框架,以不要高手们不要乱喷哦 :kl: ~
这个Demo是给群里一童鞋写的一个对图片操作以及按键处理,游戏简单框架的一个demo,这里放出给大家分享~
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
|
package
com
.
himi
;
import
android
.
content
.
Context
;
import
android
.
content
.
res
.
Resources
;
import
android
.
graphics
.
Bitmap
;
import
android
.
graphics
.
BitmapFactory
;
import
android
.
graphics
.
Canvas
;
import
android
.
graphics
.
Color
;
import
android
.
graphics
.
Paint
;
import
android
.
util
.
Log
;
import
android
.
view
.
KeyEvent
;
import
android
.
view
.
SurfaceHolder
;
import
android
.
view
.
SurfaceView
;
import
android
.
view
.
SurfaceHolder
.
Callback
;
public
class
MySurfaceView
extends
SurfaceView
implements
Callback
,
Runnable
{
private
Thread
th
=
new
Thread
(
this
)
;
private
SurfaceHolder
sfh
;
private
int
SH
,
SW
;
private
Canvas
canvas
;
private
Paint
p
;
private
Paint
p2
;
private
Resources
res
;
private
Bitmap
bmp
;
private
int
bmp_x
=
100
,
bmp_y
=
100
;
private
boolean
UP
,
DOWN
,
LEFT
,
RIGHT
;
private
int
animation_up
[
]
=
{
3
,
4
,
5
}
;
private
int
animation_down
[
]
=
{
0
,
1
,
2
}
;
private
int
animation_left
[
]
=
{
6
,
7
,
8
}
;
private
int
animation_right
[
]
=
{
9
,
10
,
11
}
;
private
int
animation_init
[
]
=
animation_down
;
private
int
frame_count
;
public
MySurfaceView
(
Context
context
)
{
super
(
context
)
;
this
.
setKeepScreenOn
(
true
)
;
res
=
this
.
getResources
(
)
;
bmp
=
BitmapFactory
.
decodeResource
(
res
,
R
.
drawable
.
enemy1
)
;
sfh
=
this
.
getHolder
(
)
;
sfh
.
addCallback
(
this
)
;
p
=
new
Paint
(
)
;
p
.
setColor
(
Color
.
YELLOW
)
;
p2
=
new
Paint
(
)
;
p2
.
setColor
(
Color
.
RED
)
;
p
.
setAntiAlias
(
true
)
;
setFocusable
(
true
)
;
//备注1
}
public
void
surfaceCreated
(
SurfaceHolder
holder
)
{
SH
=
this
.
getHeight
(
)
;
SW
=
this
.
getWidth
(
)
;
th
.
start
(
)
;
}
public
void
draw
(
)
{
canvas
=
sfh
.
lockCanvas
(
)
;
canvas
.
drawRect
(
0
,
0
,
SW
,
SH
,
p
)
;
//备注2
canvas
.
save
(
)
;
//备注3
canvas
.
drawText
(
"Himi"
,
bmp_x
-
2
,
bmp_y
-
10
,
p2
)
;
canvas
.
clipRect
(
bmp_x
,
bmp_y
,
bmp_x
+
bmp
.
getWidth
(
)
/
13
,
bmp_y
+
bmp
.
getHeight
(
)
)
;
if
(
animation_init
==
animation_up
)
{
canvas
.
drawBitmap
(
bmp
,
bmp_x
-
animation_up
[
frame_count
]
*
(
bmp
.
getWidth
(
)
/
13
)
,
bmp_y
,
p
)
;
}
else
if
(
animation_init
==
animation_down
)
{
canvas
.
drawBitmap
(
bmp
,
bmp_x
-
animation_down
[
frame_count
]
*
(
bmp
.
getWidth
(
)
/
13
)
,
bmp_y
,
p
)
;
}
else
if
(
animation_init
==
animation_left
)
{
canvas
.
drawBitmap
(
bmp
,
bmp_x
-
animation_left
[
frame_count
]
*
(
bmp
.
getWidth
(
)
/
13
)
,
bmp_y
,
p
)
;
}
else
if
(
animation_init
==
animation_right
)
{
canvas
.
drawBitmap
(
bmp
,
bmp_x
-
animation_right
[
frame_count
]
*
(
bmp
.
getWidth
(
)
/
13
)
,
bmp_y
,
p
)
;
}
canvas
.
restore
(
)
;
//备注3
sfh
.
unlockCanvasAndPost
(
canvas
)
;
}
public
void
cycle
(
)
{
if
(
DOWN
)
{
bmp_y
+=
5
;
}
else
if
(
UP
)
{
bmp_y
-=
5
;
}
else
if
(
LEFT
)
{
bmp_x
-=
5
;
}
else
if
(
RIGHT
)
{
bmp_x
+=
5
;
}
if
(
DOWN
||
UP
||
LEFT
||
RIGHT
)
{
if
(
frame_count
&
lt
;
2
)
{
frame_count
++
;
}
else
{
frame_count
=
0
;
}
}
if
(
DOWN
==
false
&
amp
;
&
amp
;
UP
==
false
&
amp
;
&
amp
;
LEFT
==
false
&
amp
;
&
amp
;
RIGHT
==
false
)
{
frame_count
=
0
;
}
}
@
Override
public
boolean
onKeyDown
(
int
key
,
KeyEvent
event
)
{
if
(
key
==
KeyEvent
.
KEYCODE_DPAD_UP
)
{
if
(
UP
==
false
)
{
animation_init
=
animation_up
;
}
UP
=
true
;
}
else
if
(
key
==
KeyEvent
.
KEYCODE_DPAD_DOWN
)
{
if
(
DOWN
==
false
)
{
animation_init
=
animation_down
;
}
DOWN
=
true
;
}
else
if
(
key
==
KeyEvent
.
KEYCODE_DPAD_LEFT
)
{
if
(
LEFT
==
false
)
{
animation_init
=
animation_left
;
}
LEFT
=
true
;
}
else
if
(
key
==
KeyEvent
.
KEYCODE_DPAD_RIGHT
)
{
if
(
RIGHT
==
false
)
{
animation_init
=
animation_right
;
}
RIGHT
=
true
;
}
return
super
.
onKeyDown
(
key
,
event
)
;
}
/* (non-Javadoc)
* @see android.view.View#onKeyUp(int, android.view.KeyEvent)
*/
@
Override
public
boolean
onKeyUp
(
int
keyCode
,
KeyEvent
event
)
{
if
(
DOWN
)
{
DOWN
=
false
;
}
else
if
(
UP
)
{
UP
=
false
;
}
else
if
(
LEFT
)
{
LEFT
=
false
;
}
else
if
(
RIGHT
)
{
RIGHT
=
false
;
}
return
super
.
onKeyUp
(
keyCode
,
event
)
;
}
@
Override
public
void
run
(
)
{
// TODO Auto-generated method stub
while
(
true
)
{
draw
(
)
;
cycle
(
)
;
try
{
Thread
.
sleep
(
100
)
;
}
catch
(
Exception
ex
)
{
}
}
}
@
Override
public
void
surfaceChanged
(
SurfaceHolder
holder
,
int
format
,
int
width
,
int
height
)
{
// TODO Auto-generated method stub
}
@
Override
public
void
surfaceDestroyed
(
SurfaceHolder
holder
)
{
// TODO Auto-generated method stub
}
}
|
备注1
此方法是用来响应按键!如果是自己定义一个继承自View的类,重新实现onKeyDown方法后,只有当该View获得焦点时才会调用onKeyDown方法,Actvity中的onKeyDown方法是当所有控件均没有处理该按键事件时,才会调用.
备注2
这里也是对屏幕进行刷屏操作,其实这也只是一种,之前文章里我也用到drawRGB的方法同样实现,当然也可以用fillRect等来刷屏。
那么这里我想说下,在继承view中,因为onDraw方法是系统自动调用的,不像在surfaceview这里这样去在run里面自己去不断调用,在view中我们可以抵用 invalidate()/postInvalidate() 这两种方法实现让系统调用onDraw方法,这里也是和surfaceview中的不同之一!
备注3
这里canvas.save();和canvas.restore();是两个相互匹配出现的,作用是用来保存画布的状态和取出保存的状态的。这里稍微解释一下,
当我们对画布进行旋转,缩放,平移等操作的时候其实我们是想对特定的元素进行操作,比如图片,一个矩形等,但是当你用canvas的方法来进行这些操作的时候,其实是对整个画布进行了操作,那么之后在画布上的元素都会受到影响,所以我们在操作之前调用canvas.save()来保存画布当前的状态,当操作之后取出之前保存过的状态,这样就不会对其他的元素进行影响
对于 canvas.save();和canvas.restore(); 还有不少童鞋不懂,OK、我再补充点:
代码段1:
1
2
3
4
5
6
7
8
9
10
|
public
void
draw
(
)
{
Canvas
canvas
=
sfh
.
lockCanvas
(
)
;
canvas
.
drawColor
(
Color
.
BLACK
)
;
canvas
.
drawBitmap
(
bmp1
,
0
,
0
,
paint
)
;
canvas
.
save
(
)
;
canvas
.
scale
(
1.5f
,
1.5f
)
;
canvas
.
restore
(
)
;
canvas
.
drawBitmap
(
bmp2
,
0
,
0
,
paint
)
;
sfh
.
unlockCanvasAndPost
(
canvas
)
;
}
|
代码段2:
1
2
3
4
5
6
7
8
|
public
void
draw
(
)
{
Canvas
canvas
=
sfh
.
lockCanvas
(
)
;
canvas
.
drawColor
(
Color
.
BLACK
)
;
canvas
.
drawBitmap
(
bmp1
,
0
,
0
,
paint
)
;
canvas
.
scale
(
1.5f
,
1.5f
)
;
canvas
.
drawBitmap
(
bmp2
,
0
,
0
,
paint
)
;
sfh
.
unlockCanvasAndPost
(
canvas
)
;
}
|
上面这两个代码片段中我们都假设有两张图片 bmp1和bmp2,并且都画在画布上!
那么代码段1和代码段2的不同:
代码段1中我们进行画布缩放的之前保存了画布状态,做了缩放操作之后又取出之前保存的状态,这样做是为了保证bmp2正常画出来不受到缩放的影响!
代码段2里,画了bmp1后就执行了缩放操作,并且没有保存状态!紧接着画了bmp2,那么bmp2也会一样受到缩放的影响!!
所以我们如果单独处理一张图片的时候,而且不想影响其他部分的绘制,那么应该如下来做:
1
2
3
4
5
6
7
8
9
10
|
public
void
draw
(
)
{
Canvas
canvas
=
sfh
.
lockCanvas
(
)
;
canvas
.
drawColor
(
Color
.
BLACK
)
;
canvas
.
drawBitmap
(
bmp1
,
0
,
0
,
paint
)
;
canvas
.
save
(
)
;
canvas
.
scale
(
1.5f
,
1.5f
)
;
canvas
.
drawBitmap
(
bmp2
,
0
,
0
,
paint
)
;
canvas
.
restore
(
)
;
sfh
.
unlockCanvasAndPost
(
canvas
)
;
}
|
本章源码下载: “Himi-Android游戏框架源码.rar” 下载地址: http://vdisk.weibo.com/s/hq1dQ