【木棉花】基于JAVA UI开发的小游戏——推箱子(上) 原创 精华

木棉花BlueStar
发布于 2022-12-25 19:52
浏览
3收藏

前言

上期文章中,分享了关于项目的效果预览图,从这一期开始,将逐步分享这个项目的构建流程。实际上,笔者在进行开发的过程中,并不是写完一个界面的内部逻辑,就开始对界面进行美化,而是先让所有的东西可以正常地跑起来,再谈美化。因此本系列文章前半部分会重点讨论游戏以及界面之间的核心逻辑,后半部分则会分享美化界面的部分。

项目创建

打开DevEco Studio,创建一个新项目,选择JAVA作为开发语言,将项目保存至合适的位置。
【木棉花】基于JAVA UI开发的小游戏——推箱子(上)-鸿蒙开发者社区
根据上期分享的开发思路,先完成UI交互部分的框架。
【木棉花】基于JAVA UI开发的小游戏——推箱子(上)-鸿蒙开发者社区
可以看到,这里需要新建三个Slice(原本自带一个MainAbilitySlice):
【木棉花】基于JAVA UI开发的小游戏——推箱子(上)-鸿蒙开发者社区
下面对四个
MainAbilitySlice:打开应用时,首先显示的界面,也就是用户主界面。
【木棉花】基于JAVA UI开发的小游戏——推箱子(上)-鸿蒙开发者社区
SelectSlice:关卡选择界面,用户可以在这个界面选择将要跳转的关卡。
【木棉花】基于JAVA UI开发的小游戏——推箱子(上)-鸿蒙开发者社区
InitSlice:加载界面。当用户选择关卡之后,会进入加载界面,仿照游戏加载资源。(实际上啥都没干)
【木棉花】基于JAVA UI开发的小游戏——推箱子(上)-鸿蒙开发者社区
GameSlice:最后一个界面,也就是这个游戏的核心界面,所有的游戏逻辑都将在这个页面中进行,因此它将是本篇文章的核心讲解部分。
【木棉花】基于JAVA UI开发的小游戏——推箱子(上)-鸿蒙开发者社区
至此,我们可以简单地梳理一下四个界面以及他们包含的组件之间的关系:用户进入MainAbilitySlice之后,通过“开始游戏”按键进入SelectSlice,在SelectSlice中有三个按键,会对应跳转到三个不同的关卡,但是进入关卡之前会先进入InitSlice,加载过后在进入最后的GameSlice,从而开始游戏。以上就是开发的时候要理清楚的页面跳转关系。

核心代码分析

MainAbilitySlice
里面有四个按钮,那可以简单的给他们分个类,例如:开始游戏的按钮要实现的功能是页面跳转,直接与其他界面关联,分为一类;历史记录关于游戏可以用弹出窗口来实现,不需要额外界面,归为一类;退出游戏按钮直接结束应用进程,也是单独一类。明确之后,就可以给各个按钮添加点击事件了:

	//开始游戏按钮
        startBtn.setClickedListener(new Component.ClickedListener() {
            @Override
            public void onClick(Component component) {
		//页面跳转
                present(new SelectSlice(),new Intent());
            }
        });
        //历史记录按钮
        recordBtn.setClickedListener(new Component.ClickedListener() {
            @Override
            public void onClick(Component component) {		
                //历史记录弹窗
            }
        });
        //关于游戏按钮
        aboutBtn.setClickedListener(new Component.ClickedListener() {
            @Override
            public void onClick(Component component) {
                //关于游戏弹窗
            }
        });
        //退出游戏按钮
        exitBtn.setClickedListener(new Component.ClickedListener() {
            @Override
            public void onClick(Component component) {
		//退出游戏提示
                CommonDialog commonDialog = new CommonDialog(getContext());
                commonDialog.setTitleText("提示");
                commonDialog.setContentText("是否退出游戏");
                commonDialog.setButton(1, "确定", new IDialog.ClickedListener() {
                    @Override
                    public void onClick(IDialog iDialog, int i) {
                        terminateAbility();
                    }
                });
                commonDialog.setButton(2, "取消", new IDialog.ClickedListener() {
                    @Override
                    public void onClick(IDialog iDialog, int i) {
                        commonDialog.destroy();
                    }
                });
                commonDialog.show();
            }
        });
  • 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.

在开发中,由于历史记录跟关于游戏这两个功能并不是核心,因此,最开始也只是做个壳子放在这,以便自己能专注于游戏主逻辑的开发,这也是我想分享的一种思路:先搭壳子再填东西。因此,阅读本系列时,如果碰到代码中只有注释,没有实现内容时,那是因为当时做到这一步的时候,并不会去关注具体如何实现,只会想个大概,先放着。
到这里之后,实际上已经完成了游戏的退出以及从MainAbilitySlice页面到SelectSlice页面的导航,便可进行到我们的下一步。
SelectSlice
这一个界面主要有三个按钮,如何实现按下不同的按钮,跳转到同一个加载界面,但是加载完后又跳转到不同的游戏界面?这里使用Intent对跳转时的数据进行打包传输,具体实现如下:

        firstBtn.setClickedListener(new Component.ClickedListener() {
            @Override
            public void onClick(Component component) {
                Intent i = new Intent();
                i.setParam("关卡",1);
                present(new InitSlice(),i);
            }
        });
        secondBtn.setClickedListener(new Component.ClickedListener() {
            @Override
            public void onClick(Component component) {
                Intent i = new Intent();
                i.setParam("关卡",2);
                present(new InitSlice(),i);
            }
        });
        thirdBtn.setClickedListener(new Component.ClickedListener() {
            @Override
            public void onClick(Component component) {
                Intent i = new Intent();
                i.setParam("关卡",3);
                present(new InitSlice(),i);
            }
        });

  • 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.

这里Intent的key都是“关卡”,但是有不同的value,对应不同的关卡。实际上,到这里SelectSlice已经完成了它的功能了。接下来进入InitSlice。
InitSlice
在加载界面中,我预想的是一个动态的画面,然后加上一个进度条,因此我可能需要用到能够播放gif的组件,以及进度条组件。那要怎么实现加载的时候进度条跟进?我的实现方式是使用两个定时器(其实用一个也完全能搞定)

//onStart外定义
    Timer t1 = new Timer();
    Timer t2 = new Timer();
//onStart内
        TimerTask task1 = new TimerTask() {
            @Override
            public void run() {
		//页面跳转
                present(new GameSlice(),intent);
            }
        };
        TimerTask task2 = new TimerTask() {
            @Override
            public void run() {
		//进度条更新
                int value = progressBar.getProgress();
                progressBar.setProgressValue(value+20);
            }
        };
        t1.schedule(task1, 5000);
        t2.schedule(task2,0,1000);

  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.

关于如何播放gif,本不应该在此讲解,因为与主线任务无关,但是这里用到的第三方组件,后面游戏界面频繁使用,因此在这进行介绍。
这里用到了第三方组件Glide,关于组件如何使用,可具体看这篇文章,只需几行代码即可完成gif的播放,十分方便。

        int imageResourceId = ResourceTable.Media_gifimg;
        Glide.with(this)
                .asGif()
                .load(imageResourceId)
                .into(draweeView);

  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.

至此,从InitSlice跳转到GameSlice的逻辑也写好了,并且携带着从SelectSlice打包过来的数据,接下来重点讲解游戏界面的实现。
GameSlice
制作一个可以玩的游戏界面最首要的任务就是绘制地图,因此定义了一个JAVA类GameMap用于地图的绘制。
在说明如何实现GameMap之前,我想先简单阐述一下推箱子游戏的实现逻辑:实际上每一次操作的都是图片,逻辑判断依赖的是图片所绑定的属性值(只涉及加减运算),举个例子:我在程序中将路设置为0,将墙体设置为1,将宝可梦设置为2和3,将空球设置为4,那收服之后的球应该设置为:2+4=6、3+4=7,这样就实现了你把空球推向宝可梦时,显示的是已经收复的球的状态;而如果将人设置为8,那8+2=10、8+3=11也必须是人,这样才能实现你移动到宝可梦上面时,是以原人物的方式呈现。这是在设置属性值需要注意的,其他方面,例如怎么判断墙体之类的,只需要if语句判断即可。
还有一点,如果我们要实现回退功能,就需要用到的一些相关操作。
核心代码如下:

//GameMap继承于PositionLayout布局,方便对图片进行渲染
public class GameMap extends PositionLayout{

    private final static int size = 110;

	//用二维数组来存储地图
    private Integer[][] gameMap;
	//定义x,y坐标
    private Pair<Integer,Integer> map_position;
	//标识是否绘制过地图(画过一次后,后面所有的操作都只能是进行刷新,防止重复生成对象)
    private Boolean isDrew = Boolean.FALSE;
	//定义移动方式枚举,方便外部调用进行选择
    public enum MOVE_WAY{
        MOVE_UP,
        MOVE_DOWN,
        MOVE_LEFT,
        MOVE_RIGHT
    }

    //设置每种物体的属性值
    private final static int ROAD = 0;
    private final static int WALL = 1;

    private final static int LABA = 2;
    private final static int YIBU = 3;
    private final static int BOBO = 4;
    private final static int MINI = 5;
    private final static int MIAO = 6;

    private final static int BALL_EMPTY = 7;
    private final static int BALL_FULL1 = 9;
    private final static int BALL_FULL2 = 10;
    private final static int BALL_FULL3 = 11;
    private final static int BALL_FULL4 = 12;
    private final static int BALL_FULL5 = 13;
    private final static int PEOPLE1 = 14;
    private final static int PEOPLE2 = 16;
    private final static int PEOPLE3 = 17;
    private final static int PEOPLE4 = 18;
    private final static int PEOPLE5 = 19;
    private final static int PEOPLE6 = 20;
	//定义存储地图用的栈
    private Stack<Integer[][]> stack;
	//可使用此构造函数绘制不同大小的地图,这个是预留的接口,项目中使用的是直接在xml文件中加入这个组件(因为继承了PositionLayout所以可以在xml文件中使用),当然也可以直接用构造函数创建,留给读者自己发挥。
    public GameMap(Context context,Integer[][] map,int x,int y) {
        super(context);
        gameMap = map;
        map_position = new Pair<>(x,y);
    }
	//外部设置地图接口
    public void setMap(Integer[][] map) {
        gameMap = map;
        map_position = new Pair<>(map.length,map[0].length);
        stack = new Stack<>();
    }
	//绘制地图接口
    public void drawMap() {
        setHeight(size * map_position.s);
        setWidth(size * map_position.f);
        for (int i = 0; i < map_position.f; i++) {
            for (int j = 0; j < map_position.s; j++) {
                DraweeView draweeView = new DraweeView(getContext());
                draweeView.setComponentSize(size,size);
                draweeView.setContentPosition(size * j, size * i);
                int index = gameMap[i][j];
                switch (index) {
                    case ROAD:
                        Glide.with(getContext())
                                .load(ResourceTable.Media_road)
                                .diskCacheStrategy(DiskCacheStrategy.NONE)
                                .skipMemoryCache(true)
                                .into(draweeView);
                        break;
                    case WALL:
                        Glide.with(getContext())
                                .load(ResourceTable.Media_wall)
                                .diskCacheStrategy(DiskCacheStrategy.NONE)
                                .skipMemoryCache(true)
                                .into(draweeView);
                        break;
                    case LABA:
                        Glide.with(getContext())
                                .load(ResourceTable.Media_laba)
                                .diskCacheStrategy(DiskCacheStrategy.NONE)
                                .skipMemoryCache(true)
                                .into(draweeView);
                        break;
                    case YIBU:
                        Glide.with(getContext())
                                .load(ResourceTable.Media_yibu)
                                .diskCacheStrategy(DiskCacheStrategy.NONE)
                                .skipMemoryCache(true)
                                .into(draweeView);
                        break;
                    case BOBO:
                        Glide.with(getContext())
                                .load(ResourceTable.Media_bobo)
                                .diskCacheStrategy(DiskCacheStrategy.NONE)
                                .skipMemoryCache(true)
                                .into(draweeView);
                        break;
                    case MINI:
                        Glide.with(getContext())
                                .load(ResourceTable.Media_mini)
                                .diskCacheStrategy(DiskCacheStrategy.NONE)
                                .skipMemoryCache(true)
                                .into(draweeView);
                        break;
                    case MIAO:
                        Glide.with(getContext())
                                .load(ResourceTable.Media_miao)
                                .diskCacheStrategy(DiskCacheStrategy.NONE)
                                .skipMemoryCache(true)
                                .into(draweeView);
                        break;
                    case BALL_EMPTY:
                        Glide.with(getContext())
                                .load(ResourceTable.Media_ballEmpty)
                                .diskCacheStrategy(DiskCacheStrategy.NONE)
                                .skipMemoryCache(true)
                                .into(draweeView);
                        break;
                    case BALL_FULL1:
                    case BALL_FULL2:
                    case BALL_FULL3:
                    case BALL_FULL4:
                    case BALL_FULL5:
                        Glide.with(getContext())
                                .load(ResourceTable.Media_ballFull)
                                .diskCacheStrategy(DiskCacheStrategy.NONE)
                                .skipMemoryCache(true)
                                .into(draweeView);
                        break;
                    case PEOPLE1:
                    case PEOPLE2:
                    case PEOPLE3:
                    case PEOPLE4:
                    case PEOPLE5:
                    case PEOPLE6:
                        Glide.with(getContext())
                                .load(ResourceTable.Media_people)
                                .diskCacheStrategy(DiskCacheStrategy.NONE)
                                .skipMemoryCache(true)
                                .into(draweeView);
                        break;
                }

                this.addComponent(draweeView);
            }
        }
        isDrew = Boolean.TRUE;
    }
	//外部刷新地图接口
    public void flushMap(){
        for (int i = 0; i < map_position.f; i++) {
            for (int j = 0; j < map_position.s; j++) {
                DraweeView draweeView = (DraweeView) getComponentAt(i * map_position.s + j);
                draweeView.setComponentSize(size,size);
                draweeView.setContentPosition(size * j, size * i);
                int index = gameMap[i][j];
                switch (index) {
                    case ROAD:
                        Glide.with(getContext())
                                .load(ResourceTable.Media_road)
                                .diskCacheStrategy(DiskCacheStrategy.NONE)
                                .skipMemoryCache(true)
                                .into(draweeView);
                        break;
                    case WALL:
                        Glide.with(getContext())
                                .load(ResourceTable.Media_wall)
                                .diskCacheStrategy(DiskCacheStrategy.NONE)
                                .skipMemoryCache(true)
                                .into(draweeView);
                        break;
                    case LABA:
                        Glide.with(getContext())
                                .load(ResourceTable.Media_laba)
                                .diskCacheStrategy(DiskCacheStrategy.NONE)
                                .skipMemoryCache(true)
                                .into(draweeView);
                        break;
                    case YIBU:
                        Glide.with(getContext())
                                .load(ResourceTable.Media_yibu)
                                .diskCacheStrategy(DiskCacheStrategy.NONE)
                                .skipMemoryCache(true)
                                .into(draweeView);
                        break;
                    case BOBO:
                        Glide.with(getContext())
                                .load(ResourceTable.Media_bobo)
                                .diskCacheStrategy(DiskCacheStrategy.NONE)
                                .skipMemoryCache(true)
                                .into(draweeView);
                        break;
                    case MINI:
                        Glide.with(getContext())
                                .load(ResourceTable.Media_mini)
                                .diskCacheStrategy(DiskCacheStrategy.NONE)
                                .skipMemoryCache(true)
                                .into(draweeView);
                        break;
                    case MIAO:
                        Glide.with(getContext())
                                .load(ResourceTable.Media_miao)
                                .diskCacheStrategy(DiskCacheStrategy.NONE)
                                .skipMemoryCache(true)
                                .into(draweeView);
                        break;
                    case BALL_EMPTY:
                        Glide.with(getContext())
                                .load(ResourceTable.Media_ballEmpty)
                                .diskCacheStrategy(DiskCacheStrategy.NONE)
                                .skipMemoryCache(true)
                                .into(draweeView);
                        break;
                    case BALL_FULL1:
                    case BALL_FULL2:
                    case BALL_FULL3:
                    case BALL_FULL4:
                    case BALL_FULL5:
                        Glide.with(getContext())
                                .load(ResourceTable.Media_ballFull)
                                .diskCacheStrategy(DiskCacheStrategy.NONE)
                                .skipMemoryCache(true)
                                .into(draweeView);
                        break;
                    case PEOPLE1:
                    case PEOPLE2:
                    case PEOPLE3:
                    case PEOPLE4:
                    case PEOPLE5:
                    case PEOPLE6:
                        Glide.with(getContext())
                                .load(ResourceTable.Media_people)
                                .diskCacheStrategy(DiskCacheStrategy.NONE)
                                .skipMemoryCache(true)
                                .into(draweeView);
                        break;
                }

            }
        }
    }
	//获取当前操作的人物坐标
    public Pair<Integer,Integer> getMyPosition(){
        for (int i = 0; i < map_position.f; i++)
        {
            for (int j = 0; j < map_position.s; j++)
            {
                if (gameMap[i][j] == PEOPLE1 || gameMap[i][j] == PEOPLE2 ||
                        gameMap[i][j] == PEOPLE3 || gameMap[i][j] == PEOPLE4 ||
                        gameMap[i][j] == PEOPLE5 || gameMap[i][j] == PEOPLE6)
                {
                    return new Pair<>(i,j);
                }

            }
        }
        return new Pair<>(-1,-1);
    }
	//给地图里任意一张图设置对应的值,移动的时候需要此接口
    protected void setValue(int x,int y,int value){
        gameMap[x][y] += value;
    }
	//判断是否能够移动
    protected Boolean isMove(int i,int j){
        if (gameMap[i][j] == ROAD || gameMap[i][j] == LABA ||
                gameMap[i][j] == YIBU || gameMap[i][j] == BOBO ||
                gameMap[i][j] == MINI || gameMap[i][j] == MIAO)
            return Boolean.TRUE;
        return Boolean.FALSE;
    }
	//判断是不是球
    protected Boolean isBall(int i,int j){
        if (gameMap[i][j] == BALL_EMPTY || gameMap[i][j] == BALL_FULL1 ||
                gameMap[i][j] == BALL_FULL2 || gameMap[i][j] == BALL_FULL3 ||
                gameMap[i][j] == BALL_FULL4 || gameMap[i][j] == BALL_FULL5)
        {
            return true;
        }
        return Boolean.FALSE;
    }
	//外部接口,每一次移动完判断游戏是否结束
    public Boolean isWin(){
        for (int i = 0; i < map_position.f; i++)
        {
            for (int j = 0; j < map_position.s; j++)
            {
                if (gameMap[i][j] == LABA || gameMap[i][j] == YIBU ||
                        gameMap[i][j] == BOBO || gameMap[i][j] == MINI ||
                        gameMap[i][j] == MIAO) return Boolean.FALSE;
            }
        }
        return Boolean.TRUE;
    }
	//外部移动接口
    public void move(@NotNull MOVE_WAY move_way){
        Pair<Integer,Integer> position = getMyPosition();
        Integer[][] oldMap = new Integer[map_position.f][map_position.s];
        for (int i = 0; i < map_position.f; i++) {
            if (map_position.s >= 0) System.arraycopy(gameMap[i], 0, oldMap[i], 0, map_position.s);
        }

        stack.push(oldMap);
        switch (move_way){
            case MOVE_UP:
                if (this.isMove(position.f - 1, position.s))
                {
                    this.setValue(position.f, position.s, -PEOPLE1);
                    this.setValue(position.f - 1, position.s, PEOPLE1);
                }
                if (this.isBall(position.f - 1, position.s))
                {
                    if (this.isMove(position.f - 2, position.s))
                    {
                        this.setValue(position.f, position.s, -PEOPLE1);
                        this.setValue(position.f - 1, position.s, BALL_EMPTY);
                        this.setValue(position.f - 2, position.s, BALL_EMPTY);
                    }
                }
                break;
            case MOVE_DOWN:
                if (this.isMove(position.f + 1, position.s))
                {
                    this.setValue(position.f, position.s, -PEOPLE1);
                    this.setValue(position.f + 1, position.s, PEOPLE1);
                }
                if (this.isBall(position.f + 1, position.s))
                {
                    if (this.isMove(position.f + 2, position.s))
                    {
                        this.setValue(position.f, position.s, -PEOPLE1);
                        this.setValue(position.f + 1, position.s, BALL_EMPTY);
                        this.setValue(position.f + 2, position.s, BALL_EMPTY);
                    }
                }
                break;
            case MOVE_LEFT:
                if (this.isMove(position.f, position.s - 1))
                {
                    this.setValue(position.f, position.s, -PEOPLE1);
                    this.setValue(position.f, position.s - 1, PEOPLE1);
                }
                if (this.isBall(position.f, position.s - 1))
                {
                    if (this.isMove(position.f, position.s - 2))
                    {
                        this.setValue(position.f, position.s, -PEOPLE1);
                        this.setValue(position.f, position.s - 1, BALL_EMPTY);
                        this.setValue(position.f, position.s - 2, BALL_EMPTY);
                    }
                }
                break;
            case MOVE_RIGHT:
                if (this.isMove(position.f, position.s + 1))
                {
                    this.setValue(position.f, position.s, -PEOPLE1);
                    this.setValue(position.f, position.s + 1, PEOPLE1);
                }
                if (this.isBall(position.f, position.s + 1))
                {
                    if (this.isMove(position.f, position.s + 2))
                    {
                        this.setValue(position.f, position.s, -PEOPLE1);
                        this.setValue(position.f, position.s + 1, BALL_EMPTY);
                        this.setValue(position.f, position.s + 2, BALL_EMPTY);
                    }
                }
                break;
        }
        flushMap();
    }
	//外部回退原先地图接口
    public void back(){
        if(stack.empty()) return;
        Integer[][] temp = stack.peek();
        for (int i = 0; i < map_position.f; i++) {
            if (map_position.s >= 0) System.arraycopy(temp[i], 0, gameMap[i], 0, map_position.s);
        }
        flushMap();
        stack.pop();
    }

    public Boolean getIsDrew(){
        return isDrew;
    }

    public GameMap(Context context) {
        super(context);
    }

    public GameMap(Context context, AttrSet attrSet) {
        super(context, attrSet);
    }

    public GameMap(Context context, AttrSet attrSet, String styleName) {
        super(context, attrSet, styleName);
    }
}
  • 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.
  • 62.
  • 63.
  • 64.
  • 65.
  • 66.
  • 67.
  • 68.
  • 69.
  • 70.
  • 71.
  • 72.
  • 73.
  • 74.
  • 75.
  • 76.
  • 77.
  • 78.
  • 79.
  • 80.
  • 81.
  • 82.
  • 83.
  • 84.
  • 85.
  • 86.
  • 87.
  • 88.
  • 89.
  • 90.
  • 91.
  • 92.
  • 93.
  • 94.
  • 95.
  • 96.
  • 97.
  • 98.
  • 99.
  • 100.
  • 101.
  • 102.
  • 103.
  • 104.
  • 105.
  • 106.
  • 107.
  • 108.
  • 109.
  • 110.
  • 111.
  • 112.
  • 113.
  • 114.
  • 115.
  • 116.
  • 117.
  • 118.
  • 119.
  • 120.
  • 121.
  • 122.
  • 123.
  • 124.
  • 125.
  • 126.
  • 127.
  • 128.
  • 129.
  • 130.
  • 131.
  • 132.
  • 133.
  • 134.
  • 135.
  • 136.
  • 137.
  • 138.
  • 139.
  • 140.
  • 141.
  • 142.
  • 143.
  • 144.
  • 145.
  • 146.
  • 147.
  • 148.
  • 149.
  • 150.
  • 151.
  • 152.
  • 153.
  • 154.
  • 155.
  • 156.
  • 157.
  • 158.
  • 159.
  • 160.
  • 161.
  • 162.
  • 163.
  • 164.
  • 165.
  • 166.
  • 167.
  • 168.
  • 169.
  • 170.
  • 171.
  • 172.
  • 173.
  • 174.
  • 175.
  • 176.
  • 177.
  • 178.
  • 179.
  • 180.
  • 181.
  • 182.
  • 183.
  • 184.
  • 185.
  • 186.
  • 187.
  • 188.
  • 189.
  • 190.
  • 191.
  • 192.
  • 193.
  • 194.
  • 195.
  • 196.
  • 197.
  • 198.
  • 199.
  • 200.
  • 201.
  • 202.
  • 203.
  • 204.
  • 205.
  • 206.
  • 207.
  • 208.
  • 209.
  • 210.
  • 211.
  • 212.
  • 213.
  • 214.
  • 215.
  • 216.
  • 217.
  • 218.
  • 219.
  • 220.
  • 221.
  • 222.
  • 223.
  • 224.
  • 225.
  • 226.
  • 227.
  • 228.
  • 229.
  • 230.
  • 231.
  • 232.
  • 233.
  • 234.
  • 235.
  • 236.
  • 237.
  • 238.
  • 239.
  • 240.
  • 241.
  • 242.
  • 243.
  • 244.
  • 245.
  • 246.
  • 247.
  • 248.
  • 249.
  • 250.
  • 251.
  • 252.
  • 253.
  • 254.
  • 255.
  • 256.
  • 257.
  • 258.
  • 259.
  • 260.
  • 261.
  • 262.
  • 263.
  • 264.
  • 265.
  • 266.
  • 267.
  • 268.
  • 269.
  • 270.
  • 271.
  • 272.
  • 273.
  • 274.
  • 275.
  • 276.
  • 277.
  • 278.
  • 279.
  • 280.
  • 281.
  • 282.
  • 283.
  • 284.
  • 285.
  • 286.
  • 287.
  • 288.
  • 289.
  • 290.
  • 291.
  • 292.
  • 293.
  • 294.
  • 295.
  • 296.
  • 297.
  • 298.
  • 299.
  • 300.
  • 301.
  • 302.
  • 303.
  • 304.
  • 305.
  • 306.
  • 307.
  • 308.
  • 309.
  • 310.
  • 311.
  • 312.
  • 313.
  • 314.
  • 315.
  • 316.
  • 317.
  • 318.
  • 319.
  • 320.
  • 321.
  • 322.
  • 323.
  • 324.
  • 325.
  • 326.
  • 327.
  • 328.
  • 329.
  • 330.
  • 331.
  • 332.
  • 333.
  • 334.
  • 335.
  • 336.
  • 337.
  • 338.
  • 339.
  • 340.
  • 341.
  • 342.
  • 343.
  • 344.
  • 345.
  • 346.
  • 347.
  • 348.
  • 349.
  • 350.
  • 351.
  • 352.
  • 353.
  • 354.
  • 355.
  • 356.
  • 357.
  • 358.
  • 359.
  • 360.
  • 361.
  • 362.
  • 363.
  • 364.
  • 365.
  • 366.
  • 367.
  • 368.
  • 369.
  • 370.
  • 371.
  • 372.
  • 373.
  • 374.
  • 375.
  • 376.
  • 377.
  • 378.
  • 379.
  • 380.
  • 381.
  • 382.
  • 383.
  • 384.
  • 385.
  • 386.
  • 387.
  • 388.
  • 389.
  • 390.
  • 391.
  • 392.
  • 393.
  • 394.
  • 395.
  • 396.
  • 397.
  • 398.
  • 399.
  • 400.
  • 401.

至此,完成了地图类的代码,可以开始绘制GameSlice了。在预览图中看到,核心部分有很多:一个退出界面按钮,一个设置按钮,一个倒计时器,还有一张地图,一个后退地图操作的按钮,按照我自己的想法先进行分类。后退地图操作的按钮地图是刚需,优先实现,代码如下:

//在外部定义变量
    float start_x;
    float start_y;

    Integer[][] map;
    Integer[][] map1 = {
            {1, 1, 1, 1, 1, 1, 1, 1, 1},
            {1, 0, 0, 0, 1, 0, 0, 1, 1},
            {1, 0, 1, 0, 1, 7, 2, 1, 1},
            {1, 0, 0, 0, 0, 7, 3, 1, 1},
            {1, 0, 1, 0, 1, 7, 4, 1, 1},
            {1, 0, 0, 0, 1, 0, 0, 1, 1},
            {1, 1, 1, 1, 1, 0, 14, 1, 1},
            {1, 1, 1, 1, 1, 1, 1, 1, 1},
            {1, 1, 1, 1, 1, 1, 1, 1, 1}
    };
    Integer[][] map2 = {
            {1, 1, 1, 1, 1, 1, 1, 1, 1},
            {1, 1, 1, 1, 1, 1, 1, 1, 1},
            {1, 1, 0, 0, 0, 3, 0, 1, 1},
            {1, 1, 0, 1, 0, 1, 0, 1, 1},
            {1, 1, 0, 7, 14, 7, 0, 1, 1},
            {1, 1, 0, 1, 0, 1, 5, 1, 1},
            {1, 1, 0, 7, 6, 0, 0, 1, 1},
            {1, 1, 1, 1, 1, 1, 1, 1, 1},
            {1, 1, 1, 1, 1, 1, 1, 1, 1}
    };
    Integer[][] map3 = {
            {1, 1, 1, 1, 1, 1, 1, 1, 1},
            {1, 1, 1, 1, 1, 1, 1, 1, 1},
            {1, 0, 2, 0, 7, 0, 1, 1, 1},
            {1, 1, 0, 7, 6, 7, 0, 1, 1},
            {1, 3, 4, 5, 1, 0, 5, 1, 1},
            {1, 0, 1, 7, 0, 7, 0, 1, 1},
            {1, 0, 7, 0, 1, 2, 7, 1, 1},
            {1, 0, 14, 0, 0, 0, 0, 1, 1},
            {1, 1, 1, 1, 1, 1, 1, 1, 1}
    };

//onStart方法内

	switch (intent.getIntParam("关卡",0))
        {
            case 1:
                map = map1;
                break;
            case 2:
                map = map2;
                break;
            case 3:
                map = map3;
                break;
        }
        gameMap.setMap(map);
        if(!gameMap.getIsDrew()) gameMap.drawMap();
        else gameMap.flushMap();

	//滑动屏幕移动角色
        gameMap.setTouchEventListener(new Component.TouchEventListener() {
            @Override
            public boolean onTouchEvent(Component component, TouchEvent touchEvent) {
                int action = touchEvent.getAction();
                switch (action) {
                    case TouchEvent.PRIMARY_POINT_DOWN:
                        MmiPoint startPoint = touchEvent.getPointerPosition(0);
                        start_x = startPoint.getX();
                        start_y = startPoint.getY();
                        break;
                    case TouchEvent.PRIMARY_POINT_UP:
                        MmiPoint endPoint = touchEvent.getPointerPosition(0);
                        if(endPoint.getX() > start_x && Math.abs(endPoint.getY() - start_y) < 100){//right
                            gameMap.move(GameMap.MOVE_WAY.MOVE_RIGHT);
                        }
                        else if(endPoint.getX() < start_x && Math.abs(endPoint.getY() - start_y) < 100){//left
                            gameMap.move(GameMap.MOVE_WAY.MOVE_LEFT);
                        }
                        else if(endPoint.getY() < start_y && Math.abs(endPoint.getX() - start_x) < 100){//up
                            gameMap.move(GameMap.MOVE_WAY.MOVE_UP);
                        }
                        else if(endPoint.getY() > start_y && Math.abs(endPoint.getX() - start_x) < 100){//down
                            gameMap.move(GameMap.MOVE_WAY.MOVE_DOWN);
                        }
                        if(gameMap.isWin()){
                            //赢了之后该干嘛

                        }
                        break;
                }
                return true;
            }

        });
        stackBtn.setClickedListener(new Component.ClickedListener() {
            @Override
            public void onClick(Component component) {
                gameMap.back();
            }
        });
  • 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.
  • 62.
  • 63.
  • 64.
  • 65.
  • 66.
  • 67.
  • 68.
  • 69.
  • 70.
  • 71.
  • 72.
  • 73.
  • 74.
  • 75.
  • 76.
  • 77.
  • 78.
  • 79.
  • 80.
  • 81.
  • 82.
  • 83.
  • 84.
  • 85.
  • 86.
  • 87.
  • 88.
  • 89.
  • 90.
  • 91.
  • 92.
  • 93.
  • 94.
  • 95.
  • 96.
  • 97.
  • 98.

游戏整体框架(不包括数据存储)大概就是这些,至此,已经实现了这个游戏最基础的功能了,从开始界面到游戏界面,以及各种游戏操作,接下来的事情就是对这些零零散散的组件,用一个漂亮的布局整合起来,再根据自己的兴趣添加一些其他功能,下篇将重点给出美化UI交互界面的代码,敬请期待!

©著作权归作者所有,如需转载,请注明出处,否则将追究法律责任
已于2022-12-25 19:52:34修改
5
收藏 3
回复
举报
5
4
3
4条回复
按时间正序
/
按时间倒序
红叶亦知秋
红叶亦知秋

先搭壳子再填东西的思路很好,编程不能走一步看一步。

1
回复
2022-12-26 09:57:32
喝一大口可乐
喝一大口可乐

是因为游戏界面加载太快所以只能象征的加个加载界面了么

回复
2022-12-26 13:59:56
木棉花BlueStar
木棉花BlueStar 回复了 喝一大口可乐
是因为游戏界面加载太快所以只能象征的加个加载界面了么

加载界面可以用于一些请求,比如游戏要联网,可以在加载界面配置好,因为这个游戏比较简单,所以只是象征性写了这个界面😂

回复
2022-12-27 09:41:37
木棉花_小蓝
木棉花_小蓝

Excellent!

回复
2022-12-28 11:23:43


回复
    相关推荐