文档章节

游戏开发基础 (1)

玄影镜心
 玄影镜心
发布于 2017/03/17 15:16
字数 1784
阅读 15
收藏 0
点赞 0
评论 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);

 

© 著作权归作者所有

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

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

大学霸 ⋅ 2014/12/23 ⋅ 0

Unity资源Assetmport New Asset对话框

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

大学霸 ⋅ 2015/01/20 ⋅ 0

VC++实战《星际传奇》网游课程第一部分网络游戏开发基础篇(游戏引擎设计)

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

hatred2124 ⋅ 2014/05/12 ⋅ 0

刘国柱- Unity游戏开发深度学习 系列课程福利大放送

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

Liu_guozhu ⋅ 05/23 ⋅ 0

Windows Phone 7 智能型手机应用程序开发总览(转载)

摘要 Windows Phone 7 是 Microsoft 推出的全新智能型手机操作系统,不但具有新颖的用户接口,也支持整合当红的社交网站与微网志,内建搜寻功能,LBS (Location-Based Service) 适地性服务,...

junwong ⋅ 2012/02/17 ⋅ 0

LibGDX 跨平台游戏开发基础教程(总目录)

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

xietansheng ⋅ 2015/12/09 ⋅ 0

【Visual C++】游戏开发笔记之一——API函数、DirectX的关键系统

本系列文章由zhmxy555(毛星云)编写,转载请注明出处。 http://blog.csdn.net/zhmxy555/article/details/7318264 作者:毛星云 邮箱: happylifemxy@qq.com 大家别叫我楼主可以吗- -.请叫我...

长平狐 ⋅ 2012/11/12 ⋅ 0

【Visual C++】游戏开发笔记之一——API函数、DirectX的关键系统

本系列文章由zhmxy555(毛星云)编写,转载请注明出处。 http://blog.csdn.net/zhmxy555/article/details/7318264 作者:毛星云 邮箱: happylifemxy@qq.com 大家别叫我楼主可以吗- -.请叫我...

长平狐 ⋅ 2012/11/12 ⋅ 0

HTML5游戏开发凭什么这么火?看了你就知道了...

很多人都会问H5游戏有前途吗?其实我个人是比较看好H5的前景,尤其是在这个移动互联网的时代,Web技术的触角必然会深入到各个领域. 当然H5目前仍然存在着不少缺点,包括大家所提到的性能较弱...

让往事随风 ⋅ 2016/04/21 ⋅ 1

Windows Phone 7 智能型手机应用程序开发总览

摘要 Windows Phone 7 是 Microsoft 推出的全新智能型手机操作系统,不但具有新颖的用户接口,也支持整合当红的社交网站与微网志,内建搜寻功能,LBS (Location-Based Service) 适地性服务,...

junwong ⋅ 2012/02/27 ⋅ 0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

Greys Java在线问题诊断工具

Greys是一个JVM进程执行过程中的异常诊断工具。 在不中断程序执行的情况下轻松完成JVM相关问题排查工作 目标群体 有时候突然一个问题反馈上来,需要入参才能完成定位,但恰恰没有任何日志。回...

素雷 ⋅ 25分钟前 ⋅ 0

git从远程仓库拉取代码的常用指令

一种(比较麻烦的)拉代码的方法 git clone //克隆代码库,与远程代码库的主干建立连接,如果主干已经在就不用再clone啦,克隆路径为当前路径下的新创建的文件夹 git checkout -b //本地建立...

Helios51 ⋅ 40分钟前 ⋅ 0

005. 深入JVM学习—Java堆内存参数调整

1. JVM整体内存调整图解(调优关键) 实际上每一块子内存区域都会存在一部分可变伸缩区域,其基本流程:如果内存空间不足,则在可变的范围之内扩大内存空间,当一段时间之后,内存空间不紧张...

影狼 ⋅ 45分钟前 ⋅ 0

内存障碍: 软件黑客的硬件视图

此文为笔者近日有幸看到的一则关于计算机底层内存障碍的学术论文,并翻译(机译)而来[自认为翻译的还行],若读者想要英文原版的论文话,给我留言,我发给你。 内存障碍: 软件黑客的硬件视图...

Romane ⋅ 今天 ⋅ 0

SpringCloud 微服务 (七) 服务通信 Feign

壹 继续第(六)篇RestTemplate篇 做到现在,本机上已经有注册中心: eureka, 服务:client、order、product 继续在order中实现通信向product服务,使用Feign方式 下面记录学习和遇到的问题 贰 or...

___大侠 ⋅ 今天 ⋅ 0

gitee、github上issue标签方案

目录 [TOC] issue生命周期 st=>start: 开始e=>end: 结束op0=>operation: 新建issueop1=>operation: 评审issueop2=>operation: 任务负责人执行任务cond1=>condition: 是否通过?op3=>o......

lovewinner ⋅ 今天 ⋅ 0

浅谈mysql的索引设计原则以及常见索引的区别

索引定义:是一个单独的,存储在磁盘上的数据库结构,其包含着对数据表里所有记录的引用指针. 数据库索引的设计原则: 为了使索引的使用效率更高,在创建索引时,必须考虑在哪些字段上创建索...

屌丝男神 ⋅ 今天 ⋅ 0

String,StringBuilder,StringBuffer三者的区别

这三个类之间的区别主要是在两个方面,即运行速度和线程安全这两方面。 首先说运行速度,或者说是, 1.执行速度 在这方面运行速度快慢为:StringBuilder(线程不安全,可变) > StringBuffer...

时刻在奔跑 ⋅ 今天 ⋅ 0

java以太坊开发 - web3j使用钱包进行转账

首先载入钱包,然后利用账户凭证操作受控交易Transfer进行转账: Web3j web3 = Web3j.build(new HttpService()); // defaults to http://localhost:8545/Credentials credentials = Wallet......

以太坊教程 ⋅ 今天 ⋅ 0

Oracle全文检索配置与实践

Oracle全文检索配置与实践

微小宝 ⋅ 今天 ⋅ 0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部