文档章节

游戏开发基础 (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);

 

© 著作权归作者所有

共有 人打赏支持
上一篇: Drools语法
下一篇: Android学习笔记
玄影镜心
粉丝 9
博文 90
码字总数 49460
作品 0
西安
高级程序员
私信 提问
【上海】招聘手机游戏开发工程师,多个职位【猎头诚聘】

iOS开发工程师 【15-20K】 职位描述: 1、 参与移动终端产品技术架构的设计; 2、 完成移动终端产品Iphone版的开发、测试、发布; 基本要求: 1、 大学本科及以上学历; 2、 至少2年以上移动...

二师兄
2011/11/09
230
0
【上海】【大型网游公司】急招3D图形研发工程师,更多职位内详

招聘职位详情: 3D图形研发工程师(12-18K) 1. MMO游戏图形引擎的功能研发和性能优化工作 1. 国家正规院校计算机软件或相关专业本科以上学历; 2. 熟练C++编程,有丰富的VC项目经验; 3. 三...

二师兄
2012/02/01
396
2
北京知名网游公司招聘网游客户端程序员、引擎程序员【猎头】

网游客户端程序员 薪资8K——13K 岗位职责: 1. 客户端框架设计和代码架构开发。 2. 标准化代码的规范。 3. 与策划进行项目上的沟通。 4. 游戏的客户端开发。 岗位要求: 1. 大学本科以上学历...

安德Tyler
2012/05/07
422
10
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

没有更多内容

加载失败,请刷新页面

加载更多

《资治通鉴》读书笔记及阅读感悟2200字

《资治通鉴》读书笔记及阅读感悟2200字: 1.用夏桀,商纣暴虐昏君和商汤,周武王仁德明君做比较,因为人民归心,上天赐名要不然就永远要恪守臣节至死不渝。 又用商朝的微子取代纣王,商朝可以...

原创小博客
21分钟前
1
0
十万个为什么之为什么大家都说dubbo

Dubbo是什么? 使用背景 dubbo为什么这么流行, 为什么大家都这么喜欢用dubbo; 通过了解分布式开发了解到, 为适应访问量暴增,业务拆分后, 子应用部署在多台服务器上,而多台服务器通过可以通过d...

尾生
59分钟前
2
0
Docker搭建代码质量检测平台-SonarQube(中文版)

Sonar是一个用于代码质量管理的开源平台,用于管理源代码的质量,可以从七个维度检测代码质量。通过插件形式,可以支持包括java,C#,C/C++,PL/SQL,Cobol,JavaScrip,Groovy等等二十几种编程语言...

Jacktanger
今天
2
0
Windows / Linux / MacOS 设置代理上网的方法汇总

本文汇总了 Windows / Linux / MacOS 设置代理上网的各种方法,总结如下: 1、设置系统代理(Windows、Linux、MacOS) 2、设置代理插件(Chrome、Chromium、Firefox、Opera、QQ等浏览器) 3、...

sunboy2050
昨天
4
0
自定义 Maven 的 repositories

有时,应用中需要一些比较新的依赖,而这些依赖并没有正式发布,还是处于milestone或者是snapshot阶段,并不能从中央仓库或者镜像站上下载到。此时,就需要 自定义Maven的<repositories>。 ...

waylau
昨天
3
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部