代码组成部分
本项目代码共有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 m_String;
Paint m_paint;
int m_iTextSize;
public TextUtil()
{
m_paint = new Paint();
m_String = new Vector();
}
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();
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;
}
}
该部分实现了文本的处理和显示。