本人自小玩魔塔游戏长大的,当时学习机上的50层魔塔玩了不知道多少遍了,现在做了码农一枚,非常希望可以制作一款自己的魔塔,于是花费了一点时间,断断续续的完成了一款运行于Android上的魔塔小游戏。本人不是专门编写Android程序的,所以肯定很多方面考虑的不完善,欢迎大家指教。
游戏运行的效果就是这个样子的了,当作这么不专业的界面是我自己设计的,也并没有美工不是,地图都是自己制作的,详情请参见https://blog.csdn.net/dongze2/article/details/90769387
实现了怪物掉血查看,快速上下楼,以及保存和加载游戏
没有实现的便是打斗界面,由于在我看来这个不太实用,强行延长我打游戏的时间,影响我打游戏的心情,所以我就没有加上
全部文章将会分为以下几部分
一、界面的制作以及方向键设计
二、地图的加载
三、怪物的生成和运动
四、主人公移动的判断
五、怪物查看和上下楼的实现
六、保存和加载的实现
界面是分为左中右三段,中间的是游戏界面,在我的设计里,游戏界面是运行时加载的,所以xml文件里只有左和右两部分。左面一个LinearLayout,内部竖直八等分,即所有height设置为0,weight设置为1。右面放一些必要的按钮,下面放上方向键。代码如下:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/layout1"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.lidongze.mota.MainActivity"
android:orientation="horizontal">
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_marginLeft="10dp"
android:layout_marginRight="10dp"
android:orientation="vertical" >
<LinearLayout
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:orientation="horizontal" >
<TextView
android:id="@+id/stair"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:gravity="start|center_vertical"
android:drawableLeft="@drawable/up_floor"
android:drawableStart="@drawable/up_floor"
android:drawablePadding="10dp"
android:paddingStart="10dp"
android:paddingLeft="10dp"
android:paddingRight="10dp"
android:textColor="#ffffffff"
android:text="1"
android:textSize="14sp" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:orientation="horizontal" >
<TextView
android:id="@+id/life"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:gravity="start|center_vertical"
android:drawableLeft="@drawable/icon_6"
android:drawableStart="@drawable/icon_6"
android:drawablePadding="10dp"
android:paddingStart="10dp"
android:paddingLeft="10dp"
android:paddingRight="10dp"
android:textColor="#ffffffff"
android:textSize="14sp" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:orientation="horizontal" >
<TextView
android:id="@+id/attack_power"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:gravity="start|center_vertical"
android:drawableLeft="@drawable/icon_7"
android:drawableStart="@drawable/icon_7"
android:drawablePadding="10dp"
android:paddingStart="10dp"
android:paddingLeft="10dp"
android:paddingRight="10dp"
android:textColor="#ffffffff"
android:textSize="14sp" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:orientation="horizontal" >
<TextView
android:id="@+id/defensive_power"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:gravity="start|center_vertical"
android:drawableLeft="@drawable/icon_5"
android:drawableStart="@drawable/icon_5"
android:drawablePadding="10dp"
android:paddingStart="10dp"
android:paddingLeft="10dp"
android:paddingRight="10dp"
android:textColor="#ffffffff"
android:textSize="14sp" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:orientation="horizontal" >
<TextView
android:id="@+id/money"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:gravity="start|center_vertical"
android:drawableLeft="@drawable/icon_4"
android:drawableStart="@drawable/icon_4"
android:drawablePadding="10dp"
android:paddingStart="10dp"
android:paddingLeft="10dp"
android:paddingRight="10dp"
android:textColor="#ffffffff"
android:textSize="14sp" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:orientation="horizontal" >
<TextView
android:id="@+id/yellow_key"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:gravity="start|center_vertical"
android:drawableLeft="@drawable/icon_1"
android:drawableStart="@drawable/icon_1"
android:drawablePadding="10dp"
android:paddingStart="10dp"
android:paddingLeft="10dp"
android:paddingRight="10dp"
android:textColor="#ffffffff"
android:textSize="14sp" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:orientation="horizontal" >
<TextView
android:id="@+id/blue_key"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:gravity="start|center_vertical"
android:drawableLeft="@drawable/icon_2"
android:drawableStart="@drawable/icon_2"
android:drawablePadding="10dp"
android:paddingStart="10dp"
android:paddingLeft="10dp"
android:paddingRight="10dp"
android:textColor="#ffffffff"
android:textSize="14sp" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:orientation="horizontal" >
<TextView
android:id="@+id/red_key"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:gravity="start|center_vertical"
android:drawableLeft="@drawable/icon_3"
android:drawableStart="@drawable/icon_3"
android:drawablePadding="10dp"
android:paddingStart="10dp"
android:paddingLeft="10dp"
android:paddingRight="10dp"
android:textColor="#ffffffff"
android:textSize="14sp" />
</LinearLayout>
</LinearLayout>
<LinearLayout
android:id="@+id/layout2"
android:orientation="horizontal"
android:layout_width="wrap_content"
android:layout_height="match_parent" />
<RelativeLayout
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:id="@+id/direction_layout">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/imageButton_layout"
android:orientation="horizontal">
<ImageButton android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/s41_b"
android:id="@+id/lookButton"/>
<ImageButton android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/up_down_label"
android:layout_toRightOf="@id/lookButton"
android:id="@+id/up_downButton"/>
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_below="@id/imageButton_layout"
android:orientation="vertical">
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/save_button"
android:text="保存游戏"
android:layout_below="@id/lookButton"/>
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/load_button"
android:text="加载游戏"
android:layout_below="@id/save_button"/>
<LinearLayout
android:layout_height="wrap_content"
android:layout_width="match_parent"
android:layout_weight="1">
</LinearLayout>
<com.lidongze.mota.DirectionButton
android:id="@+id/direction"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="0"
android:layout_gravity="center_horizontal"
android:alpha="0.7"
android:padding="20dp" />
<LinearLayout
android:layout_height="wrap_content"
android:layout_width="match_parent"
android:layout_weight="1">
</LinearLayout>
</LinearLayout>
</RelativeLayout>
</LinearLayout>
其中那个丑陋的方向键是我自己画的,原谅我不具有艺术细胞。我给方向键起名为DirectionButton,继承的是View类。当然,为了区分上下左右四个方向被按下,这里需要五张图片。我给方向键在四个方向上分别给上光照效果,便生成了四张图片
在不同的手机上,该按钮大小肯定是不一样的,在更新的时候,需要对它进行缩放
private void init() {
picture_width=direction.getWidth();
picture_height=direction.getHeight();
float scaleWidth = ((float) radius) / picture_width;
float scaleHeight = ((float) radius) / picture_height;
// 取得想要缩放的matrix参数
Matrix matrix = new Matrix();
matrix.postScale(scaleWidth, scaleHeight);
// 得到新的图片
direction = Bitmap.createBitmap(direction, 0, 0, picture_width, picture_height, matrix,
true);
right_direction = Bitmap.createBitmap(right_direction, 0, 0, picture_width, picture_height, matrix,
true);
up_direction = Bitmap.createBitmap(up_direction, 0, 0, picture_width, picture_height, matrix,
true);
left_direction = Bitmap.createBitmap(left_direction, 0, 0, picture_width, picture_height, matrix,
true);
down_direction = Bitmap.createBitmap(down_direction, 0, 0, picture_width, picture_height, matrix,
true);
bitmap=direction;
}
按键的时候,需要检测其按下的是哪个方向,首先,图片的中间以及两个方向的边界肯定是不予判断的,这里选取了绝对值50,然后调用接口函数,回调函数longCheck是用于检测一个按钮是否被长时间按下,如果长时间按下一个方向,主角便会变为跑步,节约时间。setBitmap函数会判断具体哪个按键被按下,从而更新图片和调用接口函数
@Override
public boolean onTouchEvent(MotionEvent event) {
final float x=event.getX();
final float y=event.getY();
switch (event.getAction()){
case MotionEvent.ACTION_DOWN:
//中间值不予判定
if(Math.abs(x-y)<50||Math.abs(x+y-bound)<50) return true;
//根据y和x大小,及y与x的和进行判定,四块四个按钮
setBitmap(x,y);
break;
case MotionEvent.ACTION_MOVE:
if(Math.abs(x-y)<50||Math.abs(x+y-bound)<50)
{
if(directionlistener!=null)
{
directionlistener.cancel();
}
bitmap=direction;
removeCallbacks(longCheck);
isTouch=false;
i=0;
}
else
{
if (!isTouch)
{
setBitmap(x,y);
}
}
break;
case MotionEvent.ACTION_UP:
if(directionlistener!=null)
{
directionlistener.cancel();
}
removeCallbacks(longCheck);
i=0;
bitmap=direction;
isTouch=false;
break;
}
invalidate();
return true;
}
private void setBitmap(float x,float y)
{
//查看哪个方向被按下
if(x>y)
{
if(x+y<bound)
{
flag=DirectionListener.DIRECTION_UP;
if (directionlistener!=null)
directionlistener.direction_go(false,flag);
bitmap=up_direction;
}else
{
flag=DirectionListener.DIRECTION_RIGHT;
if (directionlistener!=null)
directionlistener.direction_go(false,flag);
bitmap=right_direction;
}
}else
{
if(x+y<bound)
{
flag=DirectionListener.DIRECTION_LEFT;
if (directionlistener!=null)
directionlistener.direction_go(false,flag);
bitmap=left_direction;
}else
{
flag=DirectionListener.DIRECTION_DOWN;
if (directionlistener!=null)
directionlistener.direction_go(false,flag);
bitmap=down_direction;
}
}
isTouch=true;
//检测长时间按下
postDelayed(longCheck,250);}
长按方法的实现,线程反复调用自己去持续检测按钮是否被按下,从而调用接口函数,一旦松开,线程也就不再调用自己了
class LongCheck implements Runnable
{
@Override
public void run() {
if(isTouch)
{
if(i==1) {
if (directionlistener!=null)
directionlistener.direction_go(DirectionListener.LONG_DIRECTION,flag);
return;
}
postDelayed(longCheck,250);
i++;
}
else {
i = 0;
if (directionlistener != null)
directionlistener.cancel();
}
}
}
当然,该类中具体的实现方法全都是调用接口,实现还需结合游戏本身,接口如下所示,规定了上下左右,和两个方法,direction_go不但传递方向,还传递长时间按下这个信息。
interface DirectionListener
{
final static int DIRECTION_UP=0;
final static int DIRECTION_LEFT=1;
final static int DIRECTION_DOWN=2;
final static int DIRECTION_RIGHT=3;
final static boolean LONG_DIRECTION=true;
void direction_go(boolean isLong,int direction);
void cancel();
}
制此,界面便设计完毕了。