代码改变世界

团队项目代码分析

2019-05-19 17:40  20189203梓航  阅读(177)  评论(0编辑  收藏  举报

代码组成部分

本项目代码共有17个类,主要可以分为活动类、视图类、游戏处理类、辅助功能类4种

  • 活动类
    活动类包含一个类:MagicTower,类此类继承了Activity类,是本项目的主活动。
  • 视图类
    视图类实现了游戏的界面显示,包含了八个类:GameView类、GameScreen类、MainMenu类、SplashScreen类、HelpScreen类、AboutScreen类、FightScreen类、ThreadCanvas类
    其中GameView类继承了View类,是概念层类;GameScreen类继承了GameView类,是游戏的游戏运行视图;MainMenu类继承了GameView类,是游戏的主菜单视图;SplashScreen类继承了GameView类,是游戏的音效选择视图;HelpScreen类继承了GameView类,是游戏的帮助视图;AboutScreen类继承了GameView类,是游戏的关于信息视图;FightScreen类是游戏的战斗视图,由于该视图显示与游戏运行视图之上,调用该类需要传入GameScreen类;ThreadCanvas类是游戏的操作控制类,作为独立线程独立与其他视图之外,用于接收用户的触屏或按键等操作。
  • 游戏处理类
    游戏处理类实现了游戏的后台处理,包括六个类:MainGame类、GameMap类、HeroSprite类、FightCalc类、Task类、MySet类
    其中MainGame类是游戏的运行本体,负责在各个视图间的调度;GameMap类负责处理游戏的地图信息;HeroSprite类负责游戏的主角(即用户操作的角色)数据以及对主角的操作处理;FightCalc类责游戏的战斗处理;Task类负责处理游戏的npc事件以及游戏关键道具;MySet类负责处理游戏的基本数据信息设定,如界面长宽、字体大小、基本文字图像显示等。
  • 辅助功能类
    辅助功能类添加了一些游戏的辅助功能,包括了两个类:CMIDIPlayer类和TextUtil类
    其中CMIDIPlayer类是游戏的音乐播放器,负责播放游戏背景音乐;TextUtil类负责对游戏的一些文本文字进行处理和显示输出。

代码调用关系

各个类之间的代码调用关系如下图所示:

代码分析

游戏运行会首先打开MagicTower,随后会调用SplashScreen进行音效设置,设置完成调用MainMenu进入主界面,主界面有多个选项,点击相应的选项按“确定”会调用相应的程序,进入相应界面。点击新游戏会调用GameScreen,在GameScreen实例化过程中会调用Gamemap、HeroSprite、task,显示在界面上。
我在该项目中主要负责 SplashScreen类、HelpScreen类、AboutScreen类、MainMenu类、CMIDIPlayer类和TextUtil类的功能实现。
SplashScreen类主要代码如下:

    protected void onDraw(Canvas canvas)
    {
        tick++;
        paint.setColor(Color.BLACK);
        MySet.fillRect(canvas, 0, 0, MySet.SCREENW, MySet.SCREENH, paint);

        paint.setColor(Color.WHITE);
        String string = "是否开启音效?";
        MySet.drawString(canvas, string, (MySet.SCREENW - paint.measureText(string)) / 2, (MySet.SCREENH - paint.getTextSize()) / 2, paint);
        string = "是";
        MySet.drawString(canvas, string, 350, MySet.SCREENH - paint.getTextSize() - 550, paint);
        string = "否";
        MySet.drawString(canvas, string, MySet.SCREENW - paint.measureText(string) - 350, MySet.SCREENH - paint.getTextSize() - 550, paint);
    }


    public boolean onTouchEvent(MotionEvent event)
    {
        int x = (int) event.getX();
        int y = (int) event.getY();
        int type = 0;
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                // 记录触摸点坐标
                if (MySet.touchYes(x,y) )
                {
                    mMainGame.mbMusic = 1;;
                }

                else if (MySet.touchNo(x,y))
                {
                    mMainGame.mbMusic = 0;
                }
                mMainGame.controlView(MySet.GAME_MENU);
                if (mMainGame.mbMusic == 1)
                {
                    mMainGame.mCMIDIPlayer.PlayMusic(1);
                }
                break;
            case MotionEvent.ACTION_UP:
                break;
        }
        return true;
    }
    public void refurbish()
    {
        // if (tick > 10)
        // {
        // mMainGame.controlView(MySet.GAME_MENU);
        // }
    }


    public void reCycle()
    {
        paint = null;
        System.gc();
    }
}

这部分代码主要实现了音效的开启和关闭选择。

AboutScreen类主要代码:


    public AboutScreen(Context context, MainGame mainGame)
    {
        super(context);
        mMainGame = mainGame;
        paint = new Paint();
        tu = new TextUtil();
        title = new TextUtil();
        Resources r = this.getContext().getResources();
        title.InitText((r.getString(R.string.t_about)), (int)(MySet.SCREENW - paint.measureText((r.getString(R.string.t_about)))) / 2, 0, MySet.SCREENW, MySet.SCREENH, 0x0, 0xff0000, 255, MySet.TextSize);
        tu.InitText(((String) r.getString(R.string.about)), 0, 0, MySet.SCREENW, MySet.SCREENH, 0x0, 0xff0000, 255, MySet.TextSize);
    }


    protected void onDraw(Canvas canvas)
    {
        paint.setColor(Color.BLACK);
        MySet.fillRect(canvas, 0, 0, MySet.SCREENW, MySet.SCREENH, paint);
        drawCont(canvas);
        title.SetTextColor(0xffff00);
        title.DrawText(canvas);
        tu.SetTextColor(0xffff00);
        tu.DrawText(canvas);
    }

    private void drawCont(Canvas canvas) //操作栏
    {
        MySet.drawImage(canvas, getImage(GameScreen.IMAGE_WHEEL), 160, 1350, 400, 400, 0, 0);
        MySet.drawImage(canvas, getImage(GameScreen.IMAGE_BTNA), 600, 1380, 240, 240, 0, 0);
        MySet.drawImage(canvas, getImage(GameScreen.IMAGE_BTNB), 800, 1520, 240, 240, 0, 0);
    }

    public Bitmap getImage(int type)
    {
        Bitmap result = null;
        switch (type)
        {
            case  GameScreen.IMAGE_WHEEL:
                result = BitmapFactory.decodeResource(this.getResources(), R.mipmap.wheel_1);
                break;
            case  GameScreen.IMAGE_BTNA:
                result = BitmapFactory.decodeResource(this.getResources(), R.mipmap.btna_1);
                break;
            case  GameScreen.IMAGE_BTNB:
                result = BitmapFactory.decodeResource(this.getResources(), R.mipmap.btnb_1);
                break;
        }
        return result;
    }

    public boolean onTouchEvent(MotionEvent event)
    {
        int x = (int) event.getX();
        int y = (int) event.getY();
        int type = 0;
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                // 记录触摸点坐标
                if (MySet.touchUp(x,y) )
                {
                    tu.Key(MySet.KEY_DPAD_UP);
                }
                else if (MySet.touchDown(x,y))
                {
                    tu.Key(MySet.KEY_DPAD_DOWN);
                }
                else
                {
                    mMainGame.controlView(MySet.GAME_MENU);
                }
                break;
            case MotionEvent.ACTION_UP:
                break;
        }
        return true;
    }


    public void refurbish()
    {

    }


    public void reCycle()
    {
        paint = null;
        title = null;
        tu = null;
        System.gc();
    }
}

主要实现了关于界面的绘制,点击任意位置返回主界面。

HelpScreen类主要代码如下:



    public HelpScreen(Context context, MainGame mainGame)
    {
        super(context);
        mMainGame = mainGame;
        paint = new Paint();
        title = new TextUtil();
        tu = new TextUtil();
        Resources r = this.getContext().getResources();
        title.InitText((r.getString(R.string.t_help)), (int)(MySet.SCREENW - paint.measureText((r.getString(R.string.t_about)))) / 2, 0, MySet.SCREENW, MySet.SCREENH, 0x0, 0xff0000, 255, MySet.TextSize);
        tu.InitText(((String) r.getString(R.string.help)), 0, 0, MySet.SCREENW, MySet.SCREENH, 0x0, 0xff0000, 255, MySet.TextSize);
    }


    protected void onDraw(Canvas canvas)
    {
        paint.setColor(Color.BLACK);
        MySet.fillRect(canvas, 0, 0, MySet.SCREENW, MySet.SCREENH, paint);
        drawCont(canvas);
        title.SetTextColor(0xffff00);
        tu.SetTextColor(0xffff00);
        title.DrawText(canvas);
        tu.DrawText(canvas);
    }

    private void drawCont(Canvas canvas) //操作栏
    {
        MySet.drawImage(canvas, getImage(GameScreen.IMAGE_WHEEL), 160, 1350, 400, 400, 0, 0);
        MySet.drawImage(canvas, getImage(GameScreen.IMAGE_BTNA), 600, 1380, 240, 240, 0, 0);
        MySet.drawImage(canvas, getImage(GameScreen.IMAGE_BTNB), 800, 1520, 240, 240, 0, 0);
    }

    public Bitmap getImage(int type)
    {
        Bitmap result = null;
        switch (type)
        {
            case  GameScreen.IMAGE_WHEEL:
                result = BitmapFactory.decodeResource(this.getResources(), R.mipmap.wheel_1);
                break;
            case  GameScreen.IMAGE_BTNA:
                result = BitmapFactory.decodeResource(this.getResources(), R.mipmap.btna_1);
                break;
            case  GameScreen.IMAGE_BTNB:
                result = BitmapFactory.decodeResource(this.getResources(), R.mipmap.btnb_1);
                break;
        }
        return result;
    }

    public boolean onTouchEvent(MotionEvent event)
    {
        int x = (int) event.getX();
        int y = (int) event.getY();
        int type = 0;
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                // 记录触摸点坐标
                if (MySet.touchUp(x,y) )
                {
                    tu.Key(MySet.KEY_DPAD_UP);
                }
                else if (MySet.touchDown(x,y))
                {
                    tu.Key(MySet.KEY_DPAD_DOWN);
                }
                else
                {
                    mMainGame.controlView(MySet.GAME_MENU);
                }
                break;
            case MotionEvent.ACTION_UP:
                break;
        }
        return true;
    }

    public void refurbish()
    {

    }


    public void reCycle()
    {
        paint = null;
        title = null;
        tu = null;
        System.gc();
    }
}

实现了帮助界面的绘制,点击任意位置返回主界面。

MainMenu类主要代码如下:

public class MainMenu extends GameView
{
    private String[]	menu		= { "新游戏", "读取上次游戏", "帮助", "关于", "退出" };
    private int			itemNum		= menu.length;
    private int			curItem;
    private boolean		isFirstPlay	= false;
    public int			borderX, borderY;
    private Bitmap		mImgMenuBG	= null;

    private MainGame	mMainGame	= null;

    private int			split		= MySet.TextSize + 5;

    private int			y;
    private Paint		paint		= null;


    public MainMenu(Context context, MainGame mainGame)
    {
        super(context);
        borderX = 0;
        borderY = 0;

        paint = new Paint();
        paint.setTextSize(MySet.TextSize);
        paint.setFlags(Paint.ANTI_ALIAS_FLAG);
        mMainGame = mainGame;

        mImgMenuBG = BitmapFactory.decodeResource(this.getResources(), R.mipmap.menu_1);
    }


    private void next()
    {
        if ((curItem + 1) < itemNum)
            curItem++;
        else
            curItem = 0;
        if ((curItem == 1) && (isFirstPlay))
        {
            curItem++;
        }
    }


    private void pre()
    {
        if ((curItem - 1) >= 0)
            curItem--;
        else
            curItem = itemNum - 1;
        if ((curItem == 1) && (isFirstPlay))
        {
            curItem--;
        }
    }


    protected void onDraw(Canvas canvas)
    {
        paint.setColor(Color.BLACK);
        MySet.fillRect(canvas, 0, 0, MySet.SCREENW, MySet.SCREENH, paint);
        drawCont(canvas);
        MySet.drawImage(canvas, mImgMenuBG, (MySet.SCREENW - mImgMenuBG.getWidth()) / 2, 60);
        drawItem(canvas);
        y = (curItem + 1) * split + borderY + 600;

        paint.setARGB(255, 255, 0, 0);

        MySet.drawString(canvas, menu[curItem], borderX + (MySet.BORDERW - paint.measureText(menu[curItem])) / 2, y, paint);
    }

    private void drawCont(Canvas canvas) //操作栏
    {
        MySet.drawImage(canvas, getImage(GameScreen.IMAGE_WHEEL), 160, 1350, 400, 400, 0, 0);
        MySet.drawImage(canvas, getImage(GameScreen.IMAGE_BTNA), 600, 1380, 240, 240, 0, 0);
        MySet.drawImage(canvas, getImage(GameScreen.IMAGE_BTNB), 800, 1520, 240, 240, 0, 0);
    }

    public Bitmap getImage(int type)
    {
        Bitmap result = null;
        switch (type)
        {
            case  GameScreen.IMAGE_WHEEL:
                result = BitmapFactory.decodeResource(this.getResources(), R.mipmap.wheel_1);
                break;
            case  GameScreen.IMAGE_BTNA:
                result = BitmapFactory.decodeResource(this.getResources(), R.mipmap.btna_1);
                break;
            case  GameScreen.IMAGE_BTNB:
                result = BitmapFactory.decodeResource(this.getResources(), R.mipmap.btnb_1);
                break;
        }
        return result;
    }

    public boolean onTouchEvent(MotionEvent event)
    {
        int x = (int) event.getX();
        int y = (int) event.getY();
        int type = 0;
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                // 记录触摸点坐标
                if (MySet.touchUp(x,y) )
                {
                    pre();
                }
                else if (MySet.touchDown(x,y))
                {
                    next();
                }
                else if (MySet.touchOK(x,y))
                {
                    dealItem();
                }
                break;
            case MotionEvent.ACTION_UP:
                break;
        }
        return true;
    }


    private void drawItem(Canvas canvas)
    {
        paint.setColor(Color.WHITE);
        for (int i = 0; i < itemNum; i++)
        {
            y = (i + 1) * split + borderY + 600;

            MySet.drawString(canvas, menu[i], borderX + (MySet.BORDERW - paint.measureText(menu[i])) / 2, y, paint);
        }
    }


    private void dealItem()
    {
        switch (curItem)
        {
            case 0:
                mMainGame.controlView(MySet.GAME_RUN);
                if (mMainGame.mbMusic == 1)
                {
                    mMainGame.mCMIDIPlayer.PlayMusic(2);
                }
                break;
            case 1:
                mMainGame.controlView(MySet.GAME_CONTINUE);
                if (mMainGame.mbMusic == 1)
                {
                    mMainGame.mCMIDIPlayer.PlayMusic(2);
                }
                break;
            case 2:
                mMainGame.controlView(MySet.GAME_HELP);
                break;
            case 3:
                mMainGame.controlView(MySet.GAME_ABOUT);
                break;
            case 4:
                if (mMainGame.mCMIDIPlayer != null)
                {
                    mMainGame.mCMIDIPlayer.FreeMusic();
                    mMainGame.mCMIDIPlayer = null;
                }
                System.gc();
                mMainGame.getMagicTower().finish();
                break;
        }
    }


    public void refurbish()
    {

    }


    public void reCycle()
    {
        mImgMenuBG = null;
        paint = null;
        System.gc();
    }
}

该部分实现了主界面的功能,可以选择查看关于、帮助界面,可以选择进入新游戏、退出、继续游戏。

CMIDIPlayer类主要代码如下:

public class CMIDIPlayer
{
    public MediaPlayer	playerMusic;

    public MagicTower	magicTower	= null;


    public CMIDIPlayer(MagicTower magicTower)
    {
        this.magicTower = magicTower;

    }


    // 播放音乐
    public void PlayMusic(int ID)
    {
        FreeMusic();
        switch (ID)
        {
            case 1:
                //装载音乐
                playerMusic = MediaPlayer.create(magicTower, R.raw.menu);
                //设置循环
                playerMusic.setLooping(true);
                try
                {
                    //准备
                    playerMusic.prepare();
                }
                catch (IllegalStateException e)
                {
                    e.printStackTrace();
                }
                catch (IOException e)
                {
                    e.printStackTrace();
                }
                //开始
                playerMusic.start();
                break;
            case 2:
                playerMusic = MediaPlayer.create(magicTower, R.raw.run);
                playerMusic.setLooping(true);
                try
                {
                    playerMusic.prepare();
                }
                catch (IllegalStateException e)
                {
                    e.printStackTrace();
                }
                catch (IOException e)
                {
                    e.printStackTrace();
                }
                playerMusic.start();
                break;
        }
    }


    // 退出释放资源
    public void FreeMusic()
    {
        if (playerMusic != null)
        {
            playerMusic.stop();
            playerMusic.release();
        }
    }


    // 停止播放
    public void StopMusic()
    {
        if (playerMusic != null)
        {
            playerMusic.stop();
        }
    }
}

该部分主要实现了音乐的播放和关闭功能。
TextUtil类主要代码如下:

public class TextUtil
{
    int				m_iTextPosX;
    int				m_iTextPosY;
    int				m_iTextWidth;
    int				m_iTextHeight;

    int				m_iFontHeight;

    int				m_ipageLineNum;

    int				m_iTextBGColor; // 背景颜色
    int				m_iTextColor;	// 字体颜色
    int				m_iAlpha;

    int				m_iRealLine;	// 字符串真实的行数
    int				m_iCurLine;

    String			m_strText;

    Vector<String>	m_String;

    Paint			m_paint;

    int				m_iTextSize;


    public TextUtil()
    {
        m_paint = new Paint();
        m_String = new Vector<String>();
    }


    public TextUtil(String strText, int x, int y, int w, int h, int bgcolor, int txetcolor, int a, int iTextSize)
    {
        m_paint = new Paint();
        m_String = new Vector<String>();

        m_strText = strText;

        m_iTextPosX = x;
        m_iTextPosY = y;
        m_iTextWidth = w;
        m_iTextHeight = h;

        m_iTextBGColor = bgcolor;
        m_iTextColor = txetcolor;

        m_iTextSize = iTextSize;

        m_iAlpha = a;

    }


    public void  InitText(String strText, int x, int y, int w, int h, int bgcolor, int txetcolor, int a, int iTextSize) //设置文本
    {
        m_iCurLine = 0;
        m_ipageLineNum = 0;
        m_iRealLine = 0;
        m_strText = "";
        m_iTextPosX = 0;
        m_iTextPosY = 0;
        m_iTextWidth = 0;
        m_iTextHeight = 0;
        m_iTextBGColor = 0;
        m_iTextColor = 0;
        m_iTextSize = 0;
        m_iAlpha = 0;

        m_String.clear();

        SetText(strText);
        SetRect(x, y, w, h);
        SetBGColor(bgcolor);
        SetTextColor(txetcolor);
        SetFontSize(iTextSize);
        SetAlpha(a);

        SetPaint();

        GetTextIfon();
    }


    public void SetAlpha(int a)
    {
        m_iAlpha = a;
    }


    public void SetPaint()
    {
        m_paint.setARGB(m_iAlpha, Color.red(m_iTextColor), Color.green(m_iTextColor), Color.blue(m_iTextColor));
        m_paint.setTextSize(m_iTextSize);
    }


    public void SetFontSize(int iTextSize)
    {
        m_iTextSize = iTextSize;
    }


    public void SetRect(int x, int y, int w, int h)
    {
        m_iTextPosX = x;
        m_iTextPosY = y;
        m_iTextWidth = w;
        m_iTextHeight = h;
    }


    public void SetBGColor(int bgcolor)
    {
        m_iTextBGColor = bgcolor;
    }


    public void SetTextColor(int txetcolor)
    {
        m_iTextColor = txetcolor;
    }


    public void SetText(String strText)
    {
        m_strText = strText;
    }


    public void GetTextIfon()
    {
        char ch;
        int w = 0;
        int istart = 0;
        FontMetrics fm = m_paint.getFontMetrics();

        m_iFontHeight = (int) Math.ceil(fm.descent - fm.top) + 2;

        m_ipageLineNum = (m_iTextHeight-m_iTextSize) / m_iFontHeight;

        for (int i = 0; i < m_strText.length(); i++)
        {
            ch = m_strText.charAt(i);
            float[] widths = new float[1];
            String srt = String.valueOf(ch);
            m_paint.getTextWidths(srt, widths);

            if (ch == '\n')
            {
                m_iRealLine++;
                m_String.addElement(m_strText.substring(istart, i));
                istart = i + 1;
                w = 0;
            }
            else
            {
                w += (int) (Math.ceil(widths[0]));
                if (w > m_iTextWidth)
                {
                    m_iRealLine++;
                    m_String.addElement(m_strText.substring(istart, i));
                    istart = i;
                    i--;
                    w = 0;
                }
                else
                {
                    if (i == (m_strText.length() - 1))
                    {
                        m_iRealLine++;
                        m_String.addElement(m_strText.substring(istart, m_strText.length()));
                    }
                }
            }
        }
    }


    public void DrawText(Canvas canvas)
    {
        m_paint.setFlags(Paint.ANTI_ALIAS_FLAG);
        for (int i = m_iCurLine, j = 0; i < m_iRealLine; i++, j++)
        {
            if (j > m_ipageLineNum)
            {
                break;
            }
            canvas.drawText((String) (m_String.elementAt(i)), m_iTextPosX, m_iTextPosY + m_iFontHeight * j + m_paint.getTextSize() + 3, m_paint);
        }
    }


    public boolean Key(int keyCode)
    {
        if (keyCode == KeyEvent.KEYCODE_DPAD_UP)
        {
            if (m_iCurLine > 0)
            {
                m_iCurLine--;
                return true;
            }
        }
        else if (keyCode == KeyEvent.KEYCODE_DPAD_DOWN)
        {
            if ((m_iCurLine + m_ipageLineNum) < (m_iRealLine - 1))
            {
                m_iCurLine++;
                return true;
            }
        }
        return false;
    }
}

该部分实现了文本的处理和显示。