在android中,要实现动画效果,要么通过循环调用canvas.draw系统方法,要么通过调用opengl es中的GLSurfaceView.Renderer实现方法onDrawFrame方法。
canvas画图确实要简单得多,但要实现更好的性能最好还是调用opengl方法,因为它的性能相对来说要好一些。
实现动画的关键就是实现GLSurfaceView.Renderer接口内的方法,最重要的一个就是onDrawFrame,这个方法大体的原理是开起一个线程,在此线程内不断的调用onDrawFrame,以实现动画效果。因此onDrawFrame的主要作用就是将不同的图片显示出来就可以了。
在此先谈一个额外的话题,那就是怎么去控制onDrawFrame调用的频率,比如1秒钟执行几次?从本人找到的资料看,还没有谁这么做过,细节情况则取决于GLSurfaceView这个类的实现,但这类相当复杂,看了一下没有看懂,最后就放弃了。但我可以知道每秒执行了多少次吧?这个功能可以自己实现,而且还比较简单,先写一个实现类:
public class FPSCounter {
long startTime = System.nanoTime();
int frames = 0;
/**
* 计算每秒执行了多少次
*/
public void logFrame() {
frames++;
if(System.nanoTime() - startTime >= 1000000000) {
Log.d("FPSCounter", "fps: " + frames);
frames = 0;
startTime = System.nanoTime();
}
}
}
然后在onDrawFrame中调用即可。
经过上述操作后就可以在日志文件中查看到每秒钟会执行多少次onDrawFrame方法了。
至于怎么在onDrawFrame方法中实现动画效果这个可能相对来说要麻烦一点,比如拿上一篇博客中的jumper为例,作者自已实现了一个动画类:
public class Animation {
public static final int ANIMATION_LOOPING = 0;
public static final int ANIMATION_NONLOOPING = 1;
final TextureRegion[] keyFrames;
final float frameDuration;
public Animation(float frameDuration, TextureRegion ... keyFrames) {
this.frameDuration = frameDuration;
this.keyFrames = keyFrames;
}
public TextureRegion getKeyFrame(float stateTime, int mode) {
int frameNumber = (int)(stateTime / frameDuration);
if(mode == ANIMATION_NONLOOPING) {
frameNumber = Math.min(keyFrames.length-1, frameNumber);
} else {
frameNumber = frameNumber % keyFrames.length;
}
return keyFrames[frameNumber];
}
}
这个类中有两个主要的参数,keyFrames用于存储动画播放的连续图片,而frameDuration则用于图片更新的时间间隔。而getKeyFrame则根据不同的时间取出不同的图片,然后onDrawFrame调用getKeyFrame方法获得图片将其画出,这样就实现了游戏的单个角色的动画效果。具体实现可见上一篇博客中的jumper代码。
游戏确实是一张一张图画上去的,但要通过opengl来画,却还有些规则,这也是opengl难用的主要原因-----规则太多。举个简单点的例子,如高分排行榜,除了先画个游戏背景外,还得在背景下画些数字出来,则就会用到两种不同的显示设置:
public void present(float deltaTime) {
GL10 gl = glGraphics.getGL();
gl.glClear(GL10.GL_COLOR_BUFFER_BIT);
guiCam.setViewportAndMatrices();
gl.glEnable(GL10.GL_TEXTURE_2D);
batcher.beginBatch(Assets.background);
batcher.drawSprite(160, 240, 320, 480, Assets.backgroundRegion);
batcher.endBatch();
gl.glEnable(GL10.GL_BLEND);
gl.glBlendFunc(GL10.GL_SRC_ALPHA, GL10.GL_ONE_MINUS_SRC_ALPHA);
batcher.beginBatch(Assets.items);
batcher.drawSprite(160, 360, 300, 33, Assets.highScoresRegion);
float y = 240;
for(int i = 4; i >= 0; i--) {
Assets.font.drawText(batcher, highScores[i], xOffset, y);
y += Assets.font.glyphHeight;
}
batcher.drawSprite(32, 32, 64, 64, Assets.arrow);
batcher.endBatch();
gl.glDisable(GL10.GL_BLEND);
}
可以看到,画背景时使用的是GL10.GL_TEXTURE_2D模式,而在背景上画文字或角色时使用融合模式GL10.GL_BLEND。
关于游戏画面及动画的主要部分就是这些了,opengl 里面的需要注意的东西还很多,以后有时间的话再讲讲其它方面的。
分享到:
相关推荐
【作品名称】:泰迪杯 : 基于 python 实现 运输车辆安全驾驶行为的分析 【适用人群】:适用于希望学习不同技术领域的小白或进阶学习者。可作为毕设项目、课程设计、大作业、工程实训或初期项目立项。 【项目介绍】: 在车辆运输过程中,不良驾驶行为主要包括疲劳驾驶、急加速、急减速、怠速预热、 超长怠速、熄火滑行、超速、急变道等。 针对以上运输车辆的不良驾驶行为,给出不同不良驾驶行为的判别标准,行车安全评价模型如下: 疲劳驾驶:连续行车时间超过4小时。 提取数据思路:若某一行acc_state列值为1并且gps_speed列数值大于0,则认为汽车开始启动,继续扫描数据表,直到寻找到一行gps_speed列的数值为0,则认为汽车已经处于停止状态,再根据location_time列由两个数据获取时间间隔,判断是否属于疲劳驾驶。 急加速、急减速:每两个经纬度间汽车的加速度达到或者超过20km/s^2。两个经纬度间汽车的加速 【资源声明】:本资源作为“参考资料”而不是“定制需求”,代码只能作为参考,不能完全复制照搬。需要有一定的基础看懂代码,自行调试代码并解决报错,能自行添加功能修改代码。
基于springboot的校园社交平台源码数据库文档.zip
scipy-1.7.1-cp37-cp37m-linux_armv7l.whl
java源码资源EJB 模拟银行ATM流程及操作源代码提取方式是百度网盘分享地址
pillow-11.0.0-cp39-cp39-linux_armv7l.whl
java面试视频资源微服务架构之Spring Cloud Eureka 场景分析与实战提取方式是百度网盘分享地址
基于springboot+vue的音乐播放系统源码数据库文档.zip
matplotlib-3.5.0-cp37-cp37m-linux_armv7l.whl
onnxruntime-1.16.2-cp311-cp311-win_amd64.whl
基于springboot复兴村医疗管理系统源码数据库文档.zip
环境说明: 开发软件:VS 2017 (版本2017以上即可,不能低于2017) 数据库:SqlServer2008r2(数据库版本无限制,都可以导入) 开发模式:mvc
onnxruntime-win-x64-gpu-1.19.2.zip
bimdata_api_client-4.0.7-py3-none-any.whl
基于springboot的实验室开放管理系统源码数据库文档.zip
Pillow-9.2.0-cp39-cp39-linux_armv7l.whl
STM32神舟III号例程源码STM32芯片按键点灯-无防抖(STM32神舟III号-寄存器版)提取方式是百度网盘分享地址
基于springboot医疗废物管理系统源码数据库文档.zip
基于springboot的车辆保险理赔平台源码数据库文档.zip