文档章节

游戏开发基础 (1)

玄影镜心
 玄影镜心
发布于 2017/03/17 15:16
字数 1784
阅读 18
收藏 0

对游戏开发者而言,游戏是静态的,只是在不停的播放不同的画面,让玩家看到动态效果。

三个重要的类:

View视图、 Canvas画布、Paint画笔

 

绘制在画布中的图像是静态的,只有通过不断的展现不同的画布,才能实现动态效果,手机上画布永远只有一张,所以不可能不断的播放不同画布来实现动态效果,这时就需要进行刷新来实现动态效果。

    刷屏:如果橡皮擦,不断的清除画布上之前的内容,重新绘制新内容。如此反复形成动态效果,二这个过程称为。

常用的三种视图:

View:显示视图,内置画布、提供图形绘制函数、刷屏事件、按键事件等函数;

SurfaceView: 基于View进行扩展,更适合2D游戏开发。

GLSurfaceView:基于SurfaceView进行扩展,专用于3D游戏开发的视图。(支持GPU加速)

 

一:创建View

public class MyView extends View {

    //需要重写父类构造器
    public MyView(Context context) {
        super(context);
    }

    //重写绘图函数
    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
    }

    //重写按键按下事件函数
    @Override
    public boolean onKeyDown(int keyCode, KeyEvent event) {
        return super.onKeyDown(keyCode, event);
    }

    //重写按键抬起事件函数
    @Override
    public boolean onKeyUp(int keyCode, KeyEvent event) {
        return super.onKeyUp(keyCode, event);
    }

    //重写触屏事件函数
    @Override
    public boolean onTouchEvent(MotionEvent event) {
        return super.onTouchEvent(event);
    }
}

画布的实例存在于View的绘制函数onDraw中。

    //重写绘图函数
    @Override
    protected void onDraw(Canvas canvas) {
        //创建一个画笔实例
        Paint paint = new Paint();
        //设置画笔颜色
        paint.setColor(Color.RED); //颜色可以使用16进制来表示
        //绘制文本
        canvas.drawText("GAME OVER", 50, 50, paint);
        super.onDraw(canvas);
    }




//隐藏手机固定元素
public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        //隐去标题栏
        this.requestWindowFeature(Window.FEATURE_NO_TITLE);
        //隐去状态栏
        this.getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
                WindowManager.LayoutParams.FLAG_FULLSCREEN);
        //设置显示实例
        setContentView(new MyView(this));
    }
}

 

隐去标题
android:theme="@android:style/Theme.Black.NoTitleBar"
全屏
android:theme="@android:style/Theme.Black.NoTitleBar.Fullscreen"

无论是横屏还是竖屏,当时的左上角永远是0,0点。

view获取焦点:就是告诉系统,视图需要与用户交互,让系统来监听此视图。因为一个界面可以显示多个视图,为了避免出现多个View简单混乱,View类有了焦点属性,以及设置焦点的方法

    public MyView(Context context) {
        super(context);
        setFocusable(true); //设置焦点,只需要设置一遍
    }

 

onDraw函数值会在View开始创建运行时候执行一遍,如果想看到更改后的画布状态,需要重新绘制画布、

view提供了两个函数,这两个函数都会再次调用onDraw()

invalidate() : 不能再当前线程中循环调用执行(自己创建的线程)。

postInvalidate():可以在子线程中循环调用。

如果不在当前View中创建线程循环重绘画布的话,这两个函数没有区别,都可以使用。

   //重写触屏事件函数
    @Override
    public boolean onTouchEvent(MotionEvent event) {
        int x = (int) event.getX();
        int y = (int) event.getY();

        if(event.getAction() == MotionEvent.ACTION_DOWN){
            textX = x;
            textY = y;
        }else if(event.getAction() == MotionEvent.ACTION_MOVE){
            textX = x;
            textY = y;
        }else if(event.getAction() == MotionEvent.ACTION_UP){
            textX = x;
            textY = y;
        }
        invalidate();
        return true;  //不再使用父类返回值,因为父类中有可能什么也没有反回了false
    }

触屏监听函数只有一个参数MotionEvent event,它保存了玩家触屏的动作:常用的有按下、抬起、移动、触屏压力、多点触屏等。

通过event.getAction()获取玩家的动作和所需动作常量。

 

 

二:SurfaceView

public class MySurfaceView extends SurfaceView implements SurfaceHolder.Callback {
    private SurfaceHolder sfh; //用于控制SurfaceView
    private Paint paint;

    public MySurfaceView(Context context) {
        super(context);
        sfh = this.getHolder();
        //为surfaceView添加状态监听
        sfh.addCallback(this);
        //实例化画笔
        paint = new Paint();
        paint.setColor(Color.WHITE);
    }
    
    //当SurfaceView创建完成后响应
    @Override
    public void surfaceCreated(SurfaceHolder holder) {
        myDraw();
    }

    //当SurfaceView状态发生改变时响应
    @Override
    public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {

    }

    //当SurfaceView状态销毁时响应
    @Override
    public void surfaceDestroyed(SurfaceHolder holder) {

    }

    public void myDraw(){
        Canvas canvas = sfh.lockCanvas();  //获取当前视图的画布,同时对画布进行加锁
        canvas.drawText("hello world", 20, 20, paint);
        sfh.unlockCanvasAndPost(canvas); //解锁画布并提交
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        textX = (int) event.getX();
        textY = (int) event.getY();
        myDraw();
        return true;
    }
}

SurfaceHolder类提供了控制SurfaceView的大小、格式等,并且主要用于监听SurfaceView的状态。

SurfaceView只是保存当前视图的像素数据,我们通过SurfaceHolder来控制SurfaceView.

刷屏原理:每次在画布绘制之前,都对画布进行一次整体性的覆盖。可以是颜色,可以是背景图

 

三:SurfaceView视图添加线程

在游戏中,基本不会等用户每次触发才去重绘画布,而是固定一个世界去刷新画布;比如游戏中的倒计时,动态的花草、流水灯,这些元素并不会跟玩家交互,但是都需要动态显示,所以必须有一个线程不停的去重绘画布,实时的更新游戏元素的状态。

注意:

    按back键后重回游戏顺序: surfaceDestroyed-->构造器-->surfaceCreated-->surfaceChanged

    按home后重回游戏的顺序:surfaceDestroyed-->surfaceCreated-->surfaceChanged

    所以:应该将线程的初始化和启动都写在视图的SurfaceCreated函数中,并将线程标识位在视图摧毁时将其改变为false。从而避免线程启动异常。

//获取视图的宽、高
 this.getWidth(); 
 this.getHeight();

    在SurfaceView中获取视图宽高,一定要在视图创建后才能获取到,在SurfaceCreated执行之前取永远是0,因为视图尚未创建。

    注意点:

    1:为了避免lockCanvas()返回值为null报错,需要对绘图函数捕获异常。

    2:提交画布必须放在finally中,避免不可预知的问题。

    3:刷帧时间尽可能保证一致。

线程休眠时间:一般为50~100毫秒之间

    public void run() {
        while (flag){
            long start = System.currentTimeMillis();
            myDraw();
            long end = System.currentTimeMillis();
            try {
                //设置休眠时间的方法
                if((end - start) < 50){
                    Thread.sleep(50 - (end - start));
                }
            }catch (Exception e){

            }
        }
    }

 

四:Bitmap位图的渲染与操作

//加载图片
Bitmap bmp = BitmapFactory.decodeResource(this.getResources(), android.R.mipmap.sym_def_app_icon);
//旋转图片,第一个参数:画布旋转角度, 第2、3个参数,画布的旋转点。
//如果旋转较大大于0,顺时针,小于0则逆时针旋转
thCanvas.rotate(30, bmp.getWidth()/2, bmp.getHeight()/2);
//绘制图片
thCanvas.drawBitmap(bmp, textX,textY,paint);

save():保存当前画布状态。

restore() :恢复上次保存的画布状态。

这两个函数总是成对出现。

当对画布进行缩放、旋转和位移操作时,为了保证其他绘制的元素不受影响,应该对画布进行适当的保存和恢复操作。

利用矩阵Matrix操作图位:

Matrix mx = new Matrix();
mx.postRotate(30, bmp.getWidth()/2, bmp.getHeight()/2);
thCanvas.drawBitmap(bmp, mx, paint);

使用矩阵操作图位,可以免去对画布状态的保存和恢复,因为矩阵就是针对单独图文进行的操作,不影响画布上其他元素的绘制;

平移画布

 thCanvas.translate(10,10);  //x,y

利用矩阵平移图位旋转和缩放图位时,无法移动图的位置。因为矩阵本身没有设置初始位置的函数,因此可以利用矩阵的平移函数来弥补这个问题。

 Matrix mx = new Matrix();
 mx.setScale(0.2f,0.2f);
 mx.postTranslate(textX,textY);
 thCanvas.drawBitmap(bmp, mx,paint);

 

© 著作权归作者所有

共有 人打赏支持
玄影镜心
粉丝 9
博文 90
码字总数 49460
作品 0
西安
高级程序员
iOS游戏框架Sprite Kit基础教程第1章编写第一个Sprite Kit程序

iOS游戏框架Sprite Kit基础教程第1章编写第一个Sprite Kit程序 程序是为了实现特定目标或解决特定问题而用计算机语言编写的命令序列的集合。本章将以编写第一个Sprite Kit程序为主线,为开发...

大学霸
2014/12/23
0
0
Unity资源Assetmport New Asset对话框

Unity资源Assetmport New Asset对话框 1.2.2 资源 开发游戏一定会使用很多东西,如网格、纹理、电影、动画、声音、音乐、文本等等。这些文件都被Unity称为资源(Asset)。只有导入到Unity中的...

大学霸
2015/01/20
0
0
VC++实战《星际传奇》网游课程第一部分网络游戏开发基础篇(游戏引擎设计)

本系列课程基于最新的DirectX11接口进行深入细致的讲解,内容涉及D3D11原理与应用、DirectInput、DirectSound等; 教程中专门针对新兴的D3D11接口展开深入的讲解,详细讲解了D3D11渲染管线、...

hatred2124
2014/05/12
0
0
刘国柱- Unity游戏开发深度学习 系列课程福利大放送

刘国柱--Unity游戏开发深度学习 系列课程福利大发送!不单优惠, 还送Unity最新版本必备实战书籍! HI, 各位热心的Unity爱好者与学员,《Unity3D/2D 游戏开发从0到1(第二版)》书籍已经正式发...

Liu_guozhu
05/23
0
0
LibGDX 跨平台游戏开发基础教程(总目录)

本文链接: http://blog.csdn.net/xietansheng/article/details/50185655 前言 本套教程讲解了 LibGDX 的基础开发,从环境搭建,到基础 API 的使用,最后再到 2048 和 Flappy Bird 两个游戏的...

xietansheng
2015/12/09
0
0

没有更多内容

加载失败,请刷新页面

加载更多

SQL count(*) 和count(1)的区别

开发中经常会使用这两个聚合函数,作用都是用来统计记录行,今天查找资料发现,其实这两个函数并没有区别, 实践才是检验的标准,首先看执行计划(表是我自己建立的): 可以看到,两个执行计...

一曲图森破
20分钟前
1
0
ppwjs之bootstrap文字排版:字体设置

<!DOCTYPT html><html><head><meta http-equiv="content-type" content="text/html; charset=utf-8" /><title>ppwjs欢迎您</title><link rel="icon" href="/favicon.ico" ......

ppwjs
23分钟前
1
0
区块链100讲:详解区块链之P2P网络

1 P2P网络 如果我们简单来看 P2P 技术,它的应用领域已经非常广泛了,从流媒体到点对点通讯、从文件共享到协同处理,多种领域都有它的身影出现。 同样的,P2P 的网络协议也有很多,比较常见的...

HiBlock
38分钟前
0
0
74.expect脚本同步文件以及指定host同步文件 构建分发系统文件和命令

20.31 expect脚本同步文件: 在expect脚本中去实现在一台机器上把文件同步到另外一台机器上去。核心命令用的是rsync ~1.自动同步文件 #!/usr/bin/expect set passwd "123456" spawn rsync -a...

王鑫linux
今天
1
0
TypeScript项目引用(project references)

转发 TypeScript项目引用(project references) TypeScript新特性之项目引用(project references) 项目引用是TypeScript 3.0中的一项新功能,允许您将TypeScript程序构建为更小的部分。 通过这...

durban
今天
1
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部