`
至尊Louis
  • 浏览: 3579 次
  • 性别: Icon_minigender_1
  • 来自: 填写香港或选择
最近访客 更多访客>>
社区版块
存档分类
最新评论

OGEngine开发2048游戏及完整源代码揭秘和下载 (一)

阅读更多
使用OGEngine开发2048游戏机源码解析
        最近有一款2048的游戏非常火,本文将来介绍一下使用OGEngine游戏引擎开发游戏2048
OGEngine引擎是开源的,我们很容易找到,搭建起来也很方便,我们只需在Android工程下添加OGEnginejar包或者直接引用源码就可以了。


OGEngine引擎官网

2048游戏源码下载

1.创建游戏的主Activity 
创建的游戏主Activity入口类继承于GameActivity类,需要重写相关方法。
(1) 重写onCreatePixelPerfectEngineOptions(). 此类主要是设置引擎相关参数。
@Override
        protected PixelPerfectEngineOptions onCreatePixelPerfectEngineOptions() {
                PixelPerfectEngineOptions pixelPerfectEngineOptions = new PixelPerfectEngineOptions(
                                this, ZoomCamera.class);
                // 设置竖屏
                pixelPerfectEngineOptions
                                .setScreenOrientation(ScreenOrientation.PORTRAIT_FIXED); 
                // 适配模式,这里设置为“保持宽度不变,改变高”
                pixelPerfectEngineOptions
                                .setPixelPerfectMode(PixelPerfectMode.CHANGE_HEIGHT);
                // 参考尺寸
                pixelPerfectEngineOptions.setDesiredSize(ConstantUtil.DESIRED_SIZE);
                return pixelPerfectEngineOptions;
        }
解析:
① 根据游戏本身的需要设置竖屏或者横屏;ScreenOrientation.PORTRAIT_FIXED 这个参数表示竖屏,ScreenOrientation.LANDSCAPE_FIXED 这参数表上横屏,我这里设置成了竖屏。
② 设置适配模式,PixelPerfectMode.CHANGE_HEIGHT 表上“保持宽度不变,改变高”。
③ 屏幕参考尺寸,我这里是竖屏上面又设置了“保持宽度不变,改变高”,所以我这里的参考尺寸设为480,表示保持镜头的宽为480不变,根据实际手机屏幕分辨率的宽高比改变镜头的高。
 
(2) 重写 onLoadResources(). 此类主要用于在此加载相关资源。
 
@Override
        protected void onLoadResources() {
                // 加载图片资源
                RegionRes.loadTexturesFromAssets(Res.ALL_XML);
                
                // 加载字体资源
                FontRes.loadFont(128, 128, Typeface.create(Typeface.DEFAULT, Typeface.BOLD), 32, true, Color.BLACK, ConstantUtil.FONT_CARD_NUM);
                FontRes.loadFont(128, 128, Typeface.create(Typeface.DEFAULT, Typeface.NORMAL), 25, true, Color.WHITE, ConstantUtil.FONT_SCORE_NUM);

                // 加载音效资源
                SoundFactory.setAssetBasePath("mfx/");
                SoundRes.loadSoundFromAssets(ConstantUtil.SOUND_SELECT, "select.mp3");
                SoundRes.loadSoundFromAssets(ConstantUtil.SOUND_SETPOS, "setpos.mp3");
                SoundRes.loadSoundFromAssets(ConstantUtil.SOUND_MERGE, "merge.mp3");
        }
(3) 重写 onLoadComplete(). 此类在上面onLoadComplete()方法中加载资源完成后执行,通常此时可以跳转到相关游戏场景。
@Override
        protected void onLoadComplete() {
                // 加载资源完成后
                this.startScene(GameScene.class);
        }
2.创建游戏场景 GameScene 
创建场景的类可以继承于Scene 类,场景SceneEntity的子类,该类用来创建游戏中的场景。Scene是屏幕上所有对象的根容器。
onSceneCreate(SceneBundle bundle)方法里面创建各种实体,比如 EntityGroupSpriteTextLayer
@Override
        public void onSceneCreate(SceneBundle bundle) {
                super.onSceneCreate(bundle);
                initView();
        }
        private void initView() {
                // 游戏背景
                AnimatedSprite game_bg = new AnimatedSprite(0, 0, Res.GAME_BG,
                                getVertexBufferObjectManager());
                this.attachChild(game_bg);
                // 中间游戏主体部分
                mGameGroup = new GameGroup(this);
                // 设置改Group的中心位置在镜头的中心点上
                mGameGroup.setCentrePosition(this.getCameraCenterX(),
                                this.getCameraCenterY());
                this.attachChild(mGameGroup);

                // 2048 LOGO
                AnimatedSprite game_logo = new AnimatedSprite(20, 20, Res.GAME_LOGO,
                                getVertexBufferObjectManager());
                this.attachChild(game_logo);

                // 最佳得分背景
                bestScoreBg = new AnimatedSprite(0, 20, Res.GAME_SCORE_BG_BEST,
                                getVertexBufferObjectManager());
                // 设置bestScoreBg右边x坐标的位置在镜头的右边减20的位置
                bestScoreBg.setRightPositionX(this.getCameraRightX() - 20);
                this.attachChild(bestScoreBg);

                tBestScore = new Text(0, bestScoreBg.getY() + 50,
                                FontRes.getFont(ConstantUtil.FONT_SCORE_NUM),
                                SharedUtil.getBestScore(getActivity()) + "", 4,
                                getVertexBufferObjectManager());
                // 设置 tBestScore 的X坐标上的中点在bestScoreBg的X坐标中点上
                tBestScore.setCentrePositionX(bestScoreBg.getCentreX());
                this.attachChild(tBestScore);

                // 当前得分背景
                currScoreBg = new AnimatedSprite(0, bestScoreBg.getY(),
                                Res.GAME_SCORE_BG_NOW, getVertexBufferObjectManager());
                // 设置currScoreBg的右边X坐标点在bestScoreBg左边的X坐标减20的位置上
                currScoreBg.setRightPositionX(bestScoreBg.getLeftX() - 20);
                this.attachChild(currScoreBg);
.....
        }
(1) Scene 类是游戏中非常重要的一个类,在Scene场景中,利用attachChild(IEntity)来添加实体。

(2) GameActivity 类跳转到Scene 或者Scene 于 Scene 之间的跳转使用
public Scene startScene(Class<? extends Scene> pSceneCls)
public Scene startScene(Class<? extends Scene> pSceneCls, SceneBundle bundle)
pSceneCls:需要跳转的场景的Class
bundle用于传递场景之间的数据

(3) Scene中包含生命周期,在Scene被添加到引擎渲染后、Activity执行对应生命周期时、Scene会重新显示时执行
public void onSceneCreate(SceneBundle bundle)
public void onSceneResume()
public void onScenePause()
public void onSceneDestroy()

(4) 要关闭一个Scene 使用 finish() 方法即可。

(5) 需要灵活运用实体中有关设置坐标位置和获取坐标位置的方法来设定实体Entity的位置。下面是部分相关方法。
 
        //获取左X坐标
        public float getLeftX() ;
//获取右X坐标
        public float getRightX();
        //设置右上X位置
        public void setRightPositionX(float pX);
//获取底部Y位置
        public float getBottomY();
//设置底部Y位置
        public void setBottomPositionY(float pY) ;
        // 获取中心X坐标
        public float getCentreX() ;
        // 获取中心Y坐标
        public float getCentreY() ;
        // 设置中心X位置
        public void setCentrePositionX(float pCentreX) ;
        // 设置中心Y位置
        public void setCentrePositionY(float pCentreY);
        // 设置中心位置
        public void setCentrePosition(float pCentreX, float pCentreY) ;
(6) 显示、更新分数。这里显示分数使用到了Text 文本类 tBestScore、tBestScore均为Text
/**
         * 更新最高纪录
         * 
         * @param pBestScore
         */
        private void updateBestScore(int pBestScore) {
                tBestScore.setText(pBestScore + "");
// 设置居中
                tBestScore.setCentrePositionX(bestScoreBg.getCentreX());
        }

        /**
         * 增加当前分数
         * 
         * @param pAddScore
         *            所增加的分数
         */
        public void addCurrScore(int pAddScore) {
                if (pAddScore != 0) {
                        // 播放音效
                        SoundRes.playSound(ConstantUtil.SOUND_MERGE);
                }
                currScore += pAddScore;
                tCurrScore.setText(currScore + "");
                tCurrScore.setCentrePositionX(currScoreBg.getCentreX());

                // 当前分数大于所保存的最佳分数时,更新最佳分数
                if (currScore > SharedUtil.getBestScore(getActivity())) {
                        SharedUtil.setBestScore(getActivity(), currScore);
                        updateBestScore(currScore);
                }
        }
() 按钮及按钮点击事件监听,btnHelp 和 btnExit 均为ButtonSprite,通过
setOnClickListener(onClickListener); 设置点击事件监听。
/**
         * 按钮点击监听
         */
        private OnClickListener onClickListener = new OnClickListener() {

                @Override
                public void onClick(ButtonSprite pButtonSprite, float pTouchAreaLocalX,
                                float pTouchAreaLocalY) {
                        if (pButtonSprite == btnHelp) {
                                // 点击了帮助按钮
                                attachChild(helpLayer);
                        } else if (pButtonSprite == btnExit) {
                                // 点击了退出游戏按钮
                                showDialog();
                        }

                }
        };
3.创建卡片类
手游2048中,卡片是一个重要的单元体,移动的其实是卡片,下面我们来介绍一下卡片类的实现。

(1) 稍微扩展一下卡片精灵
我们知道,在2048游戏中,每种数字所对应的卡片颜色不一样,这里我们使用卡片的原图是一白色的方块图,通过相关设置颜色的方法可以改变卡片的颜色。观察OGEngine引擎源码可以发现Entity 类里有个 setColor 的方法,它可以使设定的RGB颜色值叠加在原图上形成新的颜色,我们这里的原图使用的是白色的方块图,所以我们可以找到想要变成的颜色的图,拿到它的RGB值就好办了。
我们可以看一下Entity 中的 setColor
/**
         * @param pRed
         *            from <code>0.0f</code> to <code>1.0f</code>
         * @param pGreen
         *            from <code>0.0f</code> to <code>1.0f</code>
         * @param pBlue
         *            from <code>0.0f</code> to <code>1.0f</code>
         */
        @Override
        public void setColor(final float pRed, final float pGreen, final float pBlue) {
                if (this.mColor.setChecking(pRed, pGreen, pBlue)) { 
                    this.onUpdateColor();
                }
        }
由上面的源码可以看到,RGB各个颜色值的范围是0~1(如下面的源码注释),而我们用取色器获取得到的RGB0~255的,不太方便使用,所以我们扩展一下。这里我们在卡片精灵CardSprite 类中扩展一下。
public class CardSprite extends AnimatedSprite {

        public CardSprite(VertexBufferObjectManager pVertexBufferObjectManager) {
                super(0, 0, Res.GAME_ROUNDRECT, pVertexBufferObjectManager);
        }

        /**
         * 设置RGB 0 到 255
        /**
        public void setRGB(float pRed, float pGreen, float pBlue) {
                this.setColor(pRed / 255, pGreen / 255, pBlue / 255);
        }

        /**
         * 设置数组形式的 RGB 0 到 255
         * @param pRGBs 数组形式的RGB
         */
        public void setRGB(float[] pRGBs) {
                this.setColor(pRGBs[0] / 255, pRGBs[1] / 255, pRGBs[2] / 255);
        }
}
(2) 创建卡片精灵和卡片上面显示的数字的组合类
OGEngine中要把精灵、文本实体等组合成一个整体我们通常使用到EntityGroup 类。
public class CardGroup extends EntityGroup {

        private CardSprite cardSprite;// 卡片背景
        private int number = 0;// 数字
        private Text tNum; // 数字文本

        // ============get&set===================
        // 获取数字
        public int getNumber() {
                return number;
        }
        // 设置数字
        public void setNumber(int number) {
                this.number = number;
                onDrawNum(number);
        }
        // ======================================
        public CardGroup(float pX, float pY, Scene pScene) {
// 卡片资源原图的大小为90*90,所以这个组合的宽高可以设置为90*90
                super(pX, pY, 90, 90, pScene);
                // 初始化View
                initView();
                // 自动计算成自适应宽高
                this.setWrapSize();
        }

private void initView() {
                // 创建卡片精灵
                cardSprite = new CardSprite(this.getVertexBufferObjectManager());
                this.attachChild(cardSprite);
                // 创建文本实体用于显示卡片上的数字,文本是可变的,这里设置文本的默认值为空字符串,最大的显示位数为4
                tNum = new Text(0, 0, FontRes.getFont(ConstantUtil.FONT_CARD_NUM), "",
                                4, this.getVertexBufferObjectManager());
                // 设置文本的中心Y坐标在cardSprite的Y坐标中点上
                tNum.setCentrePositionY(cardSprite.getCentreY());
                this.attachChild(tNum);
                // 画卡片上的数字并根据数字显示颜色,默认值为0
                onDrawNum(0);
        }







        // 画卡片上的数字,并根据数字设置卡片的颜色
        private void onDrawNum(int number) {
                float[] mRGBs;
                switch (number) {
                case 0:
                        mRGBs = ConstantUtil.RGBS_0;
                        break;
                case 2:
                        mRGBs = ConstantUtil.RGBS_2;
                        break;
                case 4:
                        mRGBs = ConstantUtil.RGBS_4;
                        break;
                case 8:
                        mRGBs = ConstantUtil.RGBS_8;
                        break;

                // 此次省略了16、32、64、128、256、512 的设置

                case 1024:
                        mRGBs = ConstantUtil.RGBS_1024;
                        break;
                case 2048:
                        mRGBs = ConstantUtil.RGBS_2048;
                        break;
                default:
                        mRGBs = ConstantUtil.RGBS_0;
                        break;
                }
                // 设置精灵颜色,传入的是RGB的数组形式
                cardSprite.setRGB(mRGBs);
                // 设置文本显示,设置数字相对于卡片精灵X坐标居中
                if (number == 0) {
                        tNum.setText("");
                } else {
                        tNum.setText(number + "");
                        tNum.setCentrePositionX(cardSprite.getCentreX());
                }
        }
// 对比当前卡片与传进来的卡片上的数字是否相等
        public boolean equals(CardGroup pCardGroup) {
                return getNumber() == pCardGroup.getNumber();
        }
这样整个卡片类就创建好了,代码注释得比较详细,就不再多解析了。

4.把卡片添加到游戏主体界面部分(GameGroup
上面我们已经创建了卡片类 CardGroup,下面我们再把它组合成一个整体。
(1) 建立GameGroup类,声明一些常量,构造器。
public class GameGroup extends EntityGroup {
        private GameScene mGameScene;
        /**手指滑动的最小响应距离**/
        private final static int FLING_MIN_DISTANCE =10;
        /**卡片之间的间隔**/
        private static final float INTERVAL = 15;
        /**卡片行列数量**/
        private final static int mCount = 4;
        /**卡片尺寸**/
        private final static float CARD_SIZE = 90;
        /**卡片数组**/
        private CardGroup[][] cardArrays = new CardGroup[4][4];
        /**用于标记还有哪些空的位置**/
        private List<Point> emptyPoints = new ArrayList<Point>();
/**随机生成的数字2**/
        private final static int mSamllNum = 2;
/**随机生成的数字4**/
        private final static int mBignum = 4;
        public GameGroup(GameScene pGameScene) {
                super(0, 0, 435, 435, pGameScene);
                // 设置可以监听触碰事件
                this.setIgnoreTouch(false);
                this.mGameScene = pGameScene;
                initView();
        }
(2)具体实现创建卡片函数,代码如下:
        private void initView() {
                // 创建背景
                AnimatedSprite rectBg = new AnimatedSprite(0, 0, Res.GAME_RECT_BG, this.getVertexBufferObjectManager());
                this.attachChild(rectBg);
                // 创建 4*4 单元格 卡片
                for (int row = 0; row < mCount; row++) {
                        for (int column = 0; column < mCount; column++) {
                                cardArrays[row][column]=new CardGroup((column+1)*INTERVAL+column*CARD_SIZE, (row+1)*INTERVAL+row*CARD_SIZE, getScene());
                                this.attachChild(cardArrays[row][column]);
                                
                        }
                }
                // 在随机一处剩余的空白单元随机生成数字,2或者4
                addRandomNum();
                addRandomNum();
        }
(3)游戏生成随机卡片数字addRandomNum()
/**
         * 在随机一处剩余的空白单元随机生成数字,2或者4
         */
        private void addRandomNum() {
                // 播放音效
                SoundRes.playSound(ConstantUtil.SOUND_SETPOS);
                emptyPoints.clear();
                for (int x = 0; x < mCount; x++) { 
                        for (int y = 0; y < mCount; y++) {
                                if (cardArrays[x][y].getNumber() <= 0) {
                                        emptyPoints.add(new Point(x, y));
                                }
                        }
                }
                Point p = emptyPoints
                                .remove((int) (Math.random() * emptyPoints.size()));
                cardArrays[p.x][p.y].setNumber(Math.random() > 0.1f ? mSamllNum
                                : mBignum);
// 生成卡片的一些动作效果,就是一个由0到1倍的缩放过程
                cardArrays[p.x][p.y].registerEntityModifier(new ScaleModifier(0.2f, 0.0f, 1.0f));
        }
(4)在游戏场景GameScene 类中创建GameGroup
// 中间游戏主体部分
                mGameGroup = new GameGroup(this);
                // 设置改Group的中心位置在镜头的中心点上
                mGameGroup.setCentrePosition(this.getCameraCenterX(),
                                this.getCameraCenterY());
                this.attachChild(mGameGroup);
(5)运行效果
运行效果如下,中间部分则为GameGroup 中展示的界面

 

分享到:
评论

相关推荐

    OGEngine源代码

    OGEngine是一款开源的游戏引擎,它的源代码提供了丰富的学习资源,对于希望深入理解游戏开发技术的开发者来说,这是一个不可多得的宝藏。本文将详细探讨OGEngine的核心概念、架构设计以及源代码中的关键模块,帮助...

    java使用OGEngine开发2048

    OGEngine是一款基于Java的国产游戏开发引擎,它是在AndEngine的基础上进行改进和优化的产物。AndEngine作为一款轻量级的2D游戏引擎,虽然不支持3D游戏的开发,但在2D游戏领域具有较高的性能和灵活性。而OGEngine则...

    OGEngine开发者文档和api文档

    OGEngine是一款基于Java语言开发的游戏引擎,专为Android平台的手游开发设计。它提供了一整套工具和技术,帮助开发者高效地构建游戏,包括图形渲染、物理模拟、音频处理、资源管理等多个方面。开发者文档和API文档是...

    2048游戏源码+开发教程

    《2048游戏源码+开发教程》是一份针对编程爱好者和初学者的宝贵资源,它涵盖了2048这款游戏的源代码分析以及开发过程的详细指导。2048是一款深受玩家喜爱的数字拼接游戏,通过简单的滑动操作,合并相同数字直至达到...

    一个基于OG引擎开发的躲避游戏

    自己做的一个用基于OGENGINE开发的直线躲避游戏,仅供学习使用~

    OGEngine引擎的消灭星星源码

    OGEngine是一款高效、灵活的游戏开发框架,尤其适合于2D游戏的开发。在本篇中,我们将深入探讨如何使用OGEngine来构建“消灭星星”游戏,并解析提供的源码。 首先,我们需要了解OGEngine的核心特性。OGEngine以C++...

    OGEngine_v2.1

    遵循LGPL(GNU Lesser General Public License)开源协议,OGEngine允许开发者在自己的项目中自由地使用、修改和分发源代码,同时保留了对商业应用的友好性。 **OpenGL ES** 是一种针对嵌入式设备和移动平台的图形...

    使用AndroidStudio搭建OGengine工程 - 知乎.rar

    在Android开发领域,OGengine是一个常用的图形引擎,它为开发者提供了高效、易用的2D和3D游戏开发工具。本文将详细介绍如何使用Android Studio搭建OGengine工程,并解决在这个过程中可能遇到的问题。 首先,让我们...

    OGEngineJava程序员也能开发iOS游戏共2页.p

    总结,这份压缩包中的PDF文档可能是一个快速引导Java程序员进入iOS游戏开发世界的入门教程,虽然篇幅不长,但涵盖了OGEngine的关键使用方法和游戏开发的基本概念,同时可能还涉及了盈利项目的初步指导。

    Android游戏源码经典游戏别踩白块钢琴块源码.zip

    本项目是一个基于安卓OGEngine引擎的别踩白块(也叫黑白块或者钢琴块)的游戏源码,别踩白块是一款非常耐玩的休闲益智游戏,别踩白块儿,这就是这个游戏唯一的一个规则,代码有大量详细的中文注释,游戏试玩了一下很...

    Android游戏源码别踩白块钢琴块.zip

    本项目是一个基于安卓OGEngine引擎的别踩白块(也叫黑白块或者钢琴块)的游戏源码,别踩白块是一款非常耐玩的休闲益智游戏,别踩白块儿,这就是这个游戏唯一的一个规则,代码有大量详细的中文注释,游戏试玩了一下很...

    Java可以同时开发安卓和iOS_.docx

    由于Java的普及性,很多开发者对其熟悉并热衷于使用,因此OGEngine为这些开发者提供了在iOS和Android上开发游戏的可能。通过Java,开发者可以编写一次代码,然后在多个平台上运行,大大降低了开发成本和时间。 另一...

    Android游戏源码经典游戏别踩白块钢琴块源码

    本项目是一个基于安卓OGEngine引擎的别踩白块(也叫黑白块或者钢琴块)的游戏源码,别踩白块是一款非常耐玩的休闲益智游戏,别踩白块儿,这就是这个游戏唯一的一个规则,代码有大量详细的中文注释,游戏试玩了一下很...

    别踩白块游戏源码

    在"OGEngineDemo_block"这个文件中,我们可以推测"OGEngine"可能是一个自定义的游戏引擎,用于处理游戏的基础功能和物理模拟。"Demo"则表明这是该引擎的一个演示或示例,而"block"很可能是指游戏中的方块元素。 ...

    OGEngineDeom_block源码

    游戏引擎是游戏开发的基石,它负责处理图形渲染、物理模拟、音频处理、输入响应等基础功能,使得开发者可以专注于游戏逻辑和内容创作,而非底层技术细节。 首先,我们需要了解Android游戏开发的基础知识。Android...

    OGEngine 引擎jar包(2.1版)

    目前OGEngine最新的引擎包 OGEngine是基于Java语言开发的课跨平台(Android、iOS)游戏引擎

    ogengine chm

    ogengine看了下说明好像是手游方面的。我就做了一份chm格式以供学习参考。

Global site tag (gtag.js) - Google Analytics