前言

贪吃蛇是一款经典的游戏,它简单易懂却又充满趣味性。在本篇博客中,我将带你使用DevEco Studio开发一个运行在HarmonyOS上的贪吃蛇游戏。通过这个项目,你将学习到HarmonyOS应用开发的基本概念和UI实现技巧。

环境准备

首先确保你已经安装了以下工具:

  • DevEco Studio 3.0或更高版本

  • HarmonyOS SDK

  • Java JDK

创建新项目

  1. 打开DevEco Studio,选择"Create HarmonyOS Project"

  2. 选择"Empty Ability"模板

  3. 配置项目信息:

    • Project Name: SnakeGame

    • Package Name: 根据你的需求设置

    • Language: Java

  4. 点击"Finish"完成创建

游戏设计

我们的贪吃蛇游戏将包含以下核心组件:

  • 游戏主界面(绘制网格、蛇和食物)

  • 游戏逻辑控制(移动、碰撞检测、得分)

  • 方向控制(通过触摸屏幕或按键)

代码实现

1. 定义游戏常量

Slice类中添加以下常量:

public class GameSlice extends AbilitySlice {
    // 游戏区域大小
    private static final int GRID_SIZE = 20;
    private static final int GRID_WIDTH = 30;
    private static final int GRID_HEIGHT = 30;
    
    // 方向常量
    private static final int DIRECTION_UP = 0;
    private static final int DIRECTION_RIGHT = 1;
    private static final int DIRECTION_DOWN = 2;
    private static final int DIRECTION_LEFT = 3;
    
    private int currentDirection = DIRECTION_RIGHT;
    // 其他变量声明...
}

2. 初始化游戏界面

@Override
public void onStart(Intent intent) {
    super.onStart(intent);
    initGame();
    setupUI();
    startGame();
}

private void initGame() {
    // 初始化蛇身
    snake = new ArrayList<>();
    snake.add(new Point(5, 5));
    snake.add(new Point(4, 5));
    snake.add(new Point(3, 5));
    
    // 生成第一个食物
    generateFood();
    
    score = 0;
    gameOver = false;
}

private void setupUI() {
    DirectionLayout layout = new DirectionLayout(this);
    layout.setOrientation(Component.VERTICAL);
    
    // 分数显示
    scoreText = new Text(this);
    scoreText.setText("得分: 0");
    layout.addComponent(scoreText);
    
    // 游戏区域
    gameView = new Component(this) {
        @Override
        public void onDraw(Canvas canvas) {
            super.onDraw(canvas);
            drawGame(canvas);
        }
    };
    gameView.setWidth(GRID_SIZE * GRID_WIDTH);
    gameView.setHeight(GRID_SIZE * GRID_HEIGHT);
    layout.addComponent(gameView);
    
    super.setUIContent(layout);
    
    // 添加触摸事件监听
    gameView.setTouchEventListener(new Component.TouchEventListener() {
        @Override
        public boolean onTouchEvent(Component component, TouchEvent touchEvent) {
            handleTouchEvent(touchEvent);
            return true;
        }
    });
}

3. 绘制游戏元素

private void drawGame(Canvas canvas) {
    // 绘制背景
    Paint paint = new Paint();
    paint.setColor(new Color(255, 255, 255));
    canvas.drawRect(new Rect(0, 0, GRID_SIZE * GRID_WIDTH, GRID_SIZE * GRID_HEIGHT), paint);
    
    // 绘制食物
    paint.setColor(new Color(255, 0, 0));
    canvas.drawRect(new Rect(
        food.x * GRID_SIZE, 
        food.y * GRID_SIZE, 
        (food.x + 1) * GRID_SIZE, 
        (food.y + 1) * GRID_SIZE
    ), paint);
    
    // 绘制蛇
    paint.setColor(new Color(0, 128, 0));
    for (Point point : snake) {
        canvas.drawRect(new Rect(
            point.x * GRID_SIZE, 
            point.y * GRID_SIZE, 
            (point.x + 1) * GRID_SIZE, 
            (point.y + 1) * GRID_SIZE
        ), paint);
    }
    
    // 游戏结束提示
    if (gameOver) {
        paint.setColor(new Color(0, 0, 0));
        paint.setTextSize(50);
        canvas.drawText(paint, "游戏结束!", GRID_SIZE * GRID_WIDTH / 4, GRID_SIZE * GRID_HEIGHT / 2);
    }
}

4. 游戏逻辑实现

private void startGame() {
    timer = new Timer();
    timer.schedule(new TimerTask() {
        @Override
        public void run() {
            if (!gameOver) {
                moveSnake();
                checkCollision();
                getContext().getUITaskDispatcher().asyncDispatch(new Runnable() {
                    @Override
                    public void run() {
                        gameView.invalidate();
                        scoreText.setText("得分: " + score);
                    }
                });
            }
        }
    }, 0, 200); // 每200毫秒更新一次
}

private void moveSnake() {
    Point head = snake.get(0);
    Point newHead = new Point(head.x, head.y);
    
    switch (currentDirection) {
        case DIRECTION_UP:
            newHead.y--;
            break;
        case DIRECTION_RIGHT:
            newHead.x++;
            break;
        case DIRECTION_DOWN:
            newHead.y++;
            break;
        case DIRECTION_LEFT:
            newHead.x--;
            break;
    }
    
    snake.add(0, newHead);
    
    // 如果吃到食物,不删除尾部,否则删除
    if (newHead.x == food.x && newHead.y == food.y) {
        score++;
        generateFood();
    } else {
        snake.remove(snake.size() - 1);
    }
}

private void checkCollision() {
    Point head = snake.get(0);
    
    // 检查是否撞墙
    if (head.x < 0 || head.x >= GRID_WIDTH || head.y < 0 || head.y >= GRID_HEIGHT) {
        gameOver = true;
        return;
    }
    
    // 检查是否撞到自己
    for (int i = 1; i < snake.size(); i++) {
        if (head.x == snake.get(i).x && head.y == snake.get(i).y) {
            gameOver = true;
            return;
        }
    }
}

private void generateFood() {
    Random random = new Random();
    int x, y;
    boolean onSnake;
    
    do {
        onSnake = false;
        x = random.nextInt(GRID_WIDTH);
        y = random.nextInt(GRID_HEIGHT);
        
        for (Point point : snake) {
            if (point.x == x && point.y == y) {
                onSnake = true;
                break;
            }
        }
    } while (onSnake);
    
    food = new Point(x, y);
}

5. 处理控制输入

private void handleTouchEvent(TouchEvent touchEvent) {
    if (touchEvent.getAction() == TouchEvent.PRIMARY_POINT_DOWN) {
        float x = touchEvent.getPointerPosition(0).getX();
        float y = touchEvent.getPointerPosition(0).getY();
        
        float centerX = gameView.getWidth() / 2;
        float centerY = gameView.getHeight() / 2;
        
        // 根据点击位置判断方向
        if (Math.abs(x - centerX) > Math.abs(y - centerY)) {
            // 水平方向
            if (x > centerX && currentDirection != DIRECTION_LEFT) {
                currentDirection = DIRECTION_RIGHT;
            } else if (x < centerX && currentDirection != DIRECTION_RIGHT) {
                currentDirection = DIRECTION_LEFT;
            }
        } else {
            // 垂直方向
            if (y > centerY && currentDirection != DIRECTION_UP) {
                currentDirection = DIRECTION_DOWN;
            } else if (y < centerY && currentDirection != DIRECTION_DOWN) {
                currentDirection = DIRECTION_UP;
            }
        }
    }
}

运行和测试

完成代码编写后,你可以通过以下步骤运行游戏:

  1. 连接HarmonyOS设备或启动模拟器

  2. 点击DevEco Studio中的运行按钮

  3. 在设备上测试游戏功能

总结

通过这个简单的贪吃蛇游戏项目,我们学习了:

  • HarmonyOS应用的基本结构

  • 使用Canvas绘制图形

  • 处理用户输入事件

  • 实现游戏逻辑和状态管理

你可以在此基础上进一步扩展功能,比如添加音效、设计更精美的UI、实现游戏暂停和重新开始功能等。

希望这篇博客对你学习HarmonyOS开发有所帮助!如果有任何问题,欢迎在评论区留言讨论。

班级链接:https://developer.huawei.com/consumer/cn/training/classDetail/0e5a7e7a9a324608848b1475d5c8ee1a?type=1?ha_source=hmosclass&ha_sourceId=89000248

Logo

讨论HarmonyOS开发技术,专注于API与组件、DevEco Studio、测试、元服务和应用上架分发等。

更多推荐