由于Android开发 横竖屏的切换会给游戏开发造成非常麻烦的事情 所以在游戏的制作当中会强制手机屏幕横屏或者竖屏避免横竖屏切换造成的数据重置 即使让程序不在切换屏幕后调用onCreat()方法 也会带来屏幕自适应的麻烦 所以Android的游戏一般都会强制横屏或者强制竖屏。
强制横屏的方法
1 2 3 4 |
//强制为横屏 setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE); |
强制竖屏的方法
1 2 3 4 |
//强制竖屏 setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT); |
游戏中的菜单在游戏开发中虽然在程序员的眼力不是最难的开发难点但是它在玩家眼力确实很重要的一部分,因为任何一款游戏第一个进入玩家眼帘的就是游戏的主菜单,制作一个漂亮的界面对于游戏品质来说会提高很多。现在主流的游戏主菜单都是使用漂亮的背景加上一些动画效果而构成,今天雨松MOMO用自己写的一个Demo向大家介绍如何制作一个漂亮的游戏菜单。
1.游戏背景图
2. 图片按钮 教学 与 设置, 在程序中须要对点击图片按钮进行事件的处理
3.动画效果 红框中的小鱼是一组游戏动画 ,从一进游戏菜单界面开始小鱼就从屏幕的右边向左边游让界面动了起来, 游戏菜单中可以多加一些这样的动画效果会使游戏界面活灵活现起来,给玩家一种视觉的冲击,游戏动画绘制的方法我已经在前几篇博客详细的说明 如果看到这里你还是不太清楚动画如何来绘制请阅读我前几篇博客。
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 |
public class ImageButton { /**按钮图片**/ private Bitmap mBitButton = null; /**图片绘制的XY坐标**/ private int mPosX =0; private int mPosY =0; /**图片绘制的宽高**/ private int mWidth =0; private int mHeight =0; public ImageButton(Context context, int frameBitmapID, int x, int y) { mBitButton = ReadBitMap(context,frameBitmapID); mPosX = x; mPosY = y; mWidth = mBitButton.getWidth(); mHeight = mBitButton.getHeight(); } /** * 绘制图片按钮 * @param canvas * @param paint */ public void DrawImageButton(Canvas canvas, Paint paint) { canvas.drawBitmap(mBitButton, mPosX, mPosY, paint); } /** * 判断是否点中图片按钮 * @param x * @param y */ public boolean IsClick(int x, int y) { boolean isClick = false; if (x >= mPosX && x <= mPosX + mWidth && y >= mPosY && y <= mPosY + mHeight) { isClick = true; } return isClick; } /** * 读取图片资源 * @param context * @param resId * @return */ public Bitmap ReadBitMap(Context context, int resId) { BitmapFactory.Options opt = new BitmapFactory.Options(); opt.inPreferredConfig = Bitmap.Config.RGB_565; opt.inPurgeable = true; opt.inInputShareable = true; // 获取资源图片 InputStream is = context.getResources().openRawResource(resId); return BitmapFactory.decodeStream(is, null, opt); } } |
2.游戏进度条的实现
我相信读我博文的朋友 应该都玩过游戏吧, 进度条机制基本上是个游戏都有,要想做一个完全百分百以按读取进度比例的进度条就需要使用线程检测文件的读取进度来确定当前的进度信息,我觉得这么做完全没必要,纯属多余,而且基本上没有游戏公司这么做,为什么呢?我相信大家玩游戏的时候都会发现有时候进度条读取的很不均匀 比如说进度条从左边给右边走 在中间某一个点卡住了一小会儿,这就表明游戏的进度是通过读取文件结束以后才计算出来的,卡住的时候刚好是在读较多文件的时候。下面我向大家分享一下我在游戏开发中如何来计算进度信息。
在读取进度的界面我会调用Loading()这个方法,每次调用mProgress 就会++ ,在switch 中就可以分布式读取资源,每个case中会加载 不同的资源 所以读取的时间是不一样的,读取的总数 和 当前读取mProgress的值 就 可以计算出进度的百分比值,最后根据计算出来的百分比在屏幕中显示进度信息。
我在强调一下下面代码中的sleep(200)须要替换成真正需要加载的资源,由于本例中没有大量的资源 所以我临时写成Sleep去等待 将进度显示在UI中。
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 |
public void Loading() { // 这里应该是去读取资源, 由于没有大量的资源 这里我暂时只用线程去等待 try { switch (mProgress) { case 0: Thread.sleep(200); break; case 1: Thread.sleep(200); break; case 2: Thread.sleep(200); break; case 3: Thread.sleep(200); break; case 4: Thread.sleep(200); break; case 5: Thread.sleep(200); break; case 6: Thread.sleep(200); break; case 7: Thread.sleep(200); break; case 8: Thread.sleep(200); break; case 9: Thread.sleep(200); break; case 10: Thread.sleep(200); break; case 11: Thread.sleep(200); break; } mProgressBar = (100 / 12) * mProgress; mProgress++; } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } |
在Loading状态中实时监测mProgress的值, 未读取到100在UI中绘制进度信息,读取到100则修改游戏状态机状态 转跳读取成功界面。
1 2 3 4 5 6 |
/** 这里表示进度加载完成 **/ if (mProgressBar >= 100) { setGameState(GAME_TEACH); } |
3.游戏状态机
游戏状态机的实现方式的是通过变量来控制当前游戏状态,在游戏主线程中只更新绘制当前游戏状态下的内容,这就是游戏状态机的原理。
下面的代码中一共有4个游戏状态 分别是 游戏菜单状态,读取进度状态,读取成功教学状态 ,游戏设置状态。在程序执行的过程中根据须要的时候去更改游戏状态。
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 |
protected void Draw() { switch (mState) { case GAME_MENU: /**计算鱼动画的X坐标向左超出屏幕后在还原保持一直在屏幕上游动**/ mMenuAnimPosX-= 5; if(mMenuAnimPosX + MENU_ANIM_WIDTH <= 0) { mMenuAnimPosX = mScreenWidth; } /**绘制背景**/ mCanvas.drawBitmap(mBitMenuBG, 0, 0, mPaint); mCanvas.drawBitmap(mBitMenuTitle, (mScreenWidth - mBitMenuTitle.getWidth()) >> 1,0, mPaint); mMenuAnim.DrawAnimation(mCanvas, mPaint, mMenuAnimPosX , 100); /**绘制按钮**/ mButtonTeach.DrawImageButton(mCanvas, mPaint); mButtonOption.DrawImageButton(mCanvas, mPaint); break; case GAME_LOAD: mCanvas.drawBitmap(mBitMenuBG, 0, 0, mPaint); mCanvas.drawBitmap(mBitMenuTitle, (mScreenWidth - mBitMenuTitle.getWidth()) >> 1,0, mPaint); mButtonTeach.DrawImageButton(mCanvas, mPaint); mButtonOption.DrawImageButton(mCanvas, mPaint); mCanvas.drawBitmap(mLoadBack, (mScreenWidth - mLoadBack.getWidth()) >> 1, mScreenHeight >> 1, mPaint); //这里计算进度条进度 Loading(); break; case GAME_TEACH: mCanvas.drawBitmap(mBitTeach, 0, 0, mPaint); mCanvas.drawBitmap(mMomo, (mScreenWidth >> 1) - (mMomo.getWidth()>> 1), 20, mPaint); String str1 = "欢迎光临雨松MOMO的博客 资源已经全部加载完成"; drawRimString(mCanvas,str1,Color.BLACK,(mScreenWidth >> 1) - (((int)mPaint.measureText(str1)) >> 1), mScreenHeight >> 1); break; case GAME_OPTION: mCanvas.drawBitmap(mBitTeach, 0, 0, mPaint); mCanvas.drawBitmap(mMomo, (mScreenWidth >> 1) - (mMomo.getWidth()>> 1), 20, mPaint); String str2 = "设置界面暂未 开放 雨松MOMO:xuanyusong@gmail.com"; drawRimString(mCanvas,str2,Color.BLACK,(mScreenWidth >> 1) - (((int)mPaint.measureText(str2)) >> 1), mScreenHeight >> 1); break; } } |
如图:我们实现点击设置按钮 游戏状态机跳转到 游戏状态页面
在拿到玩家触摸屏幕后的的X Y坐标 判断是否在游戏主菜单界面 点击设置按钮 状态机切换到GAME_OPTION 游戏设置界面。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
public void UpdateTouchEvent(int x, int y) { switch(mState) { case GAME_MENU: if(mButtonTeach.IsClick(x, y)) { //教学图片按钮被按下 setGameState(GAME_LOAD); }else if(mButtonOption.IsClick(x, y)) { //设置图片按钮被按下 setGameState(GAME_OPTION); } break; } } |
后期我还会详细介绍游戏状态机,今天只是先简单给大家介绍一下,希望孩童们快速跟进雨松MOMO的博客。
最后由于代码较多我就不贴在博客中了 , 老规矩每一篇博文都会附带我写的源代码,下面给出Demo源码的下载地址欢迎大家下载阅读互相学习,互相研究,互相讨论 雨松MOMO希望可以和大家一起进步。
- 本文固定链接: https://www.xuanyusong.com/archives/271
- 转载请注明: 雨松MOMO 于 雨松MOMO程序研究院 发表
松哥:首先,很感谢你能将这么精彩博文分享.但是这篇文章里面好像有点不太合理,如果我说错了,请您也别见怪.我刚转游戏,所以有些不是很明白.不合理之处:Loading方法中你模拟了12段Thread.sleep(200);用于加载游戏资源文件,而我们第一次进入进行循环,这个时候也就是说我们已经把第一段的资源读取完毕,我们要绘制进度条应该是8%.而这个时候你绘制的进度条为0%,其实主要因为mProgress ;在算取进度的后面,我想你这样做是不是为了:我们第一次进入的时候首先把进度条展示给用户(进度为0%。)然后在进行读取资源文件进行相应的进度,是么,我觉得这样确实挺合理的.(解决办法:case的值从1-12.)o(∩_∩)o .说来这个也不没什么.再次说一句:松哥你辛苦了,你的文章确实相当的赞!!!
松哥:首先,很感谢你能将这么精彩博文分享.但是这篇文章里面好像有点不太合理,如果我说错了,请您也别见怪.我刚转游戏,所以有些不是很明白.不合理之处:Loading方法中你模拟了12段Thread.sleep(200);用于加载游戏资源文件,而我们第一次进入进行循环,这个时候也就是说我们已经把第一段的资源读取完毕,我们要绘制进度条应该是8%.而这个时候你绘制的进度条为0%,其实主要因为mProgress++;在算取进度的后面,我想你这样做是不是为了:我们第一次进入的时候首先把进度条展示给用户(进度为0%。)然后在进行读取资源文件进行相应的进度,是么,我觉得这样确实挺合理的.(解决办法:case的值从1-12.)o(∩_∩)o .说来这个也不没什么.再次说一句:松哥你辛苦了,你的文章确实相当的赞!!!