鸿蒙DevEco Studio HarmonyOS 5跑酷小游戏实现指南

1. 项目概述

本跑酷小游戏基于鸿蒙HarmonyOS 5开发,使用DevEco Studio作为开发工具,采用Java语言实现,包含角色控制、障碍物生成和分数计算系统。

2. 项目结构

/src/main/java/com/example/runner/
    ├── MainAbilitySlice.java    // 主界面
    ├── GameView.java          // 游戏核心逻辑
    ├── Player.java           // 玩家角色类
    ├── Obstacle.java         // 障碍物类
    └── resources/
        ├── base/
        │   ├── layout/
        │   │   └── ability_main.xml  // 布局文件
        │   └── media/
        │       ├── player.png    // 角色图片
        │       ├── obstacle.png  // 障碍物图片
        │       ├── background.png // 背景图片
        │       └── ground.png    // 地面图片

3. 核心代码实现

3.1 玩家角色类(Player.java)

package com.example.runner;

import ohos.agp.utils.RectFloat;

public class Player {
    private RectFloat rect;      // 角色矩形区域
    private float velocityY;      // Y轴速度
    private boolean isJumping;   // 是否在跳跃
    private boolean isDucking;   // 是否在蹲下
    
    public Player(float left, float top, float right, float bottom) {
        this.rect = new RectFloat(left, top, right, bottom);
        this.velocityY = 0;
        this.isJumping = false;
        this.isDucking = false;
    }
    
    // 跳跃
    public void jump() {
        if (!isJumping) {
            velocityY = -25; // 向上的初速度
            isJumping = true;
        }
    }
    
    // 蹲下
    public void duck() {
        if (!isJumping) {
            isDucking = true;
            rect.modify(rect.left, rect.top + 20, 
                       rect.right, rect.bottom);
        }
    }
    
    // 站起
    public void stand() {
        isDucking = false;
        rect.modify(rect.left, rect.top - 20, 
                   rect.right, rect.bottom);
    }
    
    // 更新位置
    public void update() {
        if (isJumping) {
            // 更新Y轴位置
            rect.modify(rect.left, rect.top + velocityY, 
                       rect.right, rect.bottom + velocityY);
            
            // 应用重力
            velocityY += 1.5f;
            
            // 检查是否落地
            if (rect.top >= 0) {
                rect.modify(rect.left, 0, 
                           rect.right, rect.bottom - rect.top);
                isJumping = false;
                velocityY = 0;
            }
        }
    }
    
    // 检查碰撞
    public boolean checkCollision(RectFloat obstacle) {
        return rect.left < obstacle.right && 
               rect.right > obstacle.left && 
               rect.top < obstacle.bottom && 
               rect.bottom > obstacle.top;
    }
    
    // getter方法
    public RectFloat getRect() { return rect; }
    public boolean isJumping() { return isJumping; }
    public boolean isDucking() { return isDucking; }
}

3.2 障碍物类(Obstacle.java)

package com.example.runner;

import ohos.agp.utils.RectFloat;
import java.util.Random;

public class Obstacle {
    private RectFloat rect;      // 障碍物矩形区域
    private int speed;          // 移动速度
    private boolean isActive;   // 是否活动
    private int type;          // 障碍物类型(0:低障碍,1:高障碍)
    
    public Obstacle(float left, float top, float right, float bottom, int speed, int type) {
        this.rect = new RectFloat(left, top, right, bottom);
        this.speed = speed;
        this.isActive = true;
        this.type = type;
    }
    
    // 更新位置
    public void update() {
        rect.modify(rect.left - speed, rect.top, 
                   rect.right - speed, rect.bottom);
        
        // 检查是否超出屏幕
        if (rect.right < 0) {
            isActive = false;
        }
    }
    
    // getter方法
    public RectFloat getRect() { return rect; }
    public boolean isActive() { return isActive; }
    public int getType() { return type; }
    
    // 随机生成障碍物
    public static Obstacle generateRandom(int screenWidth, int screenHeight, int speed) {
        Random random = new Random();
        int type = random.nextInt(2); // 0或1
        float width = 50;
        float height = type == 0 ? 30 : 60;
        float top = screenHeight - height;
        
        return new Obstacle(screenWidth, top, 
                          screenWidth + width, screenHeight, 
                          speed, type);
    }
}

3.3 游戏视图(GameView.java)

package com.example.runner;

import ohos.agp.components.Component;
import ohos.agp.render.Canvas;
import ohos.agp.render.Paint;
import ohos.agp.utils.Color;
import ohos.app.Context;
import ohos.media.image.PixelMap;
import java.util.ArrayList;
import java.util.Random;

public class GameView extends Component implements Component.DrawTask {
    private Player player;
    private ArrayList obstacles = new ArrayList<>();
    private int score = 0;
    private int speed = 10;
    private boolean isGameOver = false;
    
    private Paint scorePaint;
    private Paint gameOverPaint;
    
    private PixelMap playerImage;
    private PixelMap obstacleImage;
    private PixelMap backgroundImage;
    private PixelMap groundImage;
    
    private Random random = new Random();
    private long lastObstacleTime = 0;
    private float groundPosition = 0;
    
    public GameView(Context context) {
        super(context);
        init();
    }
    
    private void init() {
        // 初始化画笔
        scorePaint = new Paint();
        scorePaint.setColor(Color.BLACK);
        scorePaint.setTextSize(50);
        
        gameOverPaint = new Paint();
        gameOverPaint.setColor(Color.RED);
        gameOverPaint.setTextSize(100);
        
        // 初始化玩家
        int screenHeight = getHeight();
        player = new Player(100, screenHeight - 100, 200, screenHeight);
        
        // 加载图片资源
        playerImage = loadPixelMap("entry/resources/base/media/player.png");
        obstacleImage = loadPixelMap("entry/resources/base/media/obstacle.png");
        backgroundImage = loadPixelMap("entry/resources/base/media/background.png");
        groundImage = loadPixelMap("entry/resources/base/media/ground.png");
        
        addDrawTask(this);
        setTouchEventListener(this::onTouchEvent);
        
        // 启动游戏循环
        startGameLoop();
    }
    
    @Override
    public void onDraw(Component component, Canvas canvas) {
        // 绘制背景
        if (backgroundImage != null) {
            canvas.drawPixelMapHolder(backgroundImage.createPixelMapHolder(), 0, 0);
        } else {
            canvas.drawColor(Color.WHITE);
        }
        
        // 绘制地面
        if (groundImage != null) {
            for (int i = 0; i < 3; i++) {
                canvas.drawPixelMapHolder(groundImage.createPixelMapHolder(), 
                                        groundPosition + i * getWidth(), getHeight() - 50);
            }
        }
        
        // 绘制玩家
        RectFloat playerRect = player.getRect();
        if (playerImage != null) {
            canvas.drawPixelMapHolder(playerImage.createPixelMapHolder(), 
                                    playerRect.left, playerRect.top);
        } else {
            Paint playerPaint = new Paint();
            playerPaint.setColor(Color.BLUE);
            canvas.drawRect(playerRect, playerPaint);
        }
        
        // 绘制障碍物
        for (Obstacle obstacle : obstacles) {
            if (obstacle.isActive()) {
                RectFloat rect = obstacle.getRect();
                if (obstacleImage != null) {
                    canvas.drawPixelMapHolder(obstacleImage.createPixelMapHolder(), 
                                           rect.left, rect.top);
                } else {
                    Paint obstaclePaint = new Paint();
                    obstaclePaint.setColor(Color.RED);
                    canvas.drawRect(rect, obstaclePaint);
                }
            }
        }
        
        // 绘制分数
        canvas.drawText("分数: " + score, 50, 50, scorePaint);
        
        // 绘制游戏结束
        if (isGameOver) {
            canvas.drawText("游戏结束!", getWidth() / 2 - 150, getHeight() / 2, gameOverPaint);
        }
    }
    
    private boolean onTouchEvent(Component component, TouchEvent event) {
        if (isGameOver) {
            if (event.getAction() == TouchEvent.PRIMARY_POINT_DOWN) {
                resetGame();
            }
            return true;
        }
        
        switch (event.getAction()) {
            case TouchEvent.PRIMARY_POINT_DOWN:
                player.jump();
                break;
                
            case TouchEvent.POINT_MOVE:
                // 长按蹲下
                player.duck();
                break;
                
            case TouchEvent.PRIMARY_POINT_UP:
                player.stand();
                break;
        }
        return true;
    }
    
    private void startGameLoop() {
        // 使用定时器更新游戏状态
        getContext().getUITaskDispatcher().delayDispatch(() -> {
            if (!isGameOver) {
                long currentTime = System.currentTimeMillis();
                
                // 更新玩家
                player.update();
                
                // 生成新障碍物
                if (currentTime - lastObstacleTime > 1500 - speed * 10) {
                    obstacles.add(Obstacle.generateRandom(getWidth(), getHeight(), speed));
                    lastObstacleTime = currentTime;
                }
                
                // 更新障碍物
                for (Obstacle obstacle : obstacles) {
                    obstacle.update();
                    
                    // 检查碰撞
                    if (player.checkCollision(obstacle.getRect())) {
                        isGameOver = true;
                    }
                }
                
                // 更新地面位置
                groundPosition -= speed / 2;
                if (groundPosition <= -getWidth()) {
                    groundPosition = 0;
                }
                
                // 增加分数
                score++;
                
                // 增加难度
                if (score % 100 == 0) {
                    speed++;
                }
                
                // 清理不活动的障碍物
                cleanupObstacles();
            }
            
            invalidate();
            
            // 继续游戏循环
            startGameLoop();
        }, 16); // 约60帧/秒
    }
    
    private void cleanupObstacles() {
        for (int i = obstacles.size() - 1; i >= 0; i--) {
            if (!obstacles.get(i).isActive()) {
                obstacles.remove(i);
            }
        }
    }
    
    private PixelMap loadPixelMap(String path) {
        // 实现图片加载逻辑
        // 实际项目中应该使用ResourceManager加载资源
        return null;
    }
    
    public void resetGame() {
        obstacles.clear();
        player = new Player(100, getHeight() - 100, 200, getHeight());
        score = 0;
        speed = 10;
        isGameOver = false;
        lastObstacleTime = System.currentTimeMillis();
        groundPosition = 0;
    }
}

3.4 主界面(MainAbilitySlice.java)

package com.example.runner;

import ohos.aafwk.ability.AbilitySlice;
import ohos.aafwk.content.Intent;
import ohos.agp.components.Button;
import ohos.agp.components.DirectionalLayout;
import ohos.agp.components.Text;
import ohos.agp.window.dialog.ToastDialog;

public class MainAbilitySlice extends AbilitySlice {
    private GameView gameView;
    
    @Override
    public void onStart(Intent intent) {
        super.onStart(intent);
        
        DirectionalLayout layout = new DirectionalLayout(this);
        layout.setOrientation(DirectionalLayout.VERTICAL);
        
        // 游戏视图
        gameView = new GameView(this);
        
        // 按钮布局
        DirectionalLayout buttonLayout = new DirectionalLayout(this);
        buttonLayout.setOrientation(DirectionalLayout.HORIZONTAL);
        buttonLayout.setPadding(10, 10, 10, 10);
        
        // 重新开始按钮
        Button resetButton = new Button(this);
        resetButton.setText("重新开始");
        resetButton.setClickedListener(component -> gameView.resetGame());
        
        // 帮助按钮
        Button helpButton = new Button(this);
        helpButton.setText("帮助");
        helpButton.setClickedListener(component -> showHelp());
        
        buttonLayout.addComponent(resetButton);
        buttonLayout.addComponent(helpButton);
        
        layout.addComponent(gameView);
        layout.addComponent(buttonLayout);
        
        super.setUIContent(layout);
    }
    
    private void showHelp() {
        new ToastDialog(this)
            .setText("游戏玩法:\n1. 点击屏幕跳跃\n2. 长按屏幕蹲下\n3. 避开障碍物\n4. 坚持越久分数越高")
            .show();
    }
}

4. 布局文件(ability_main.xml)



    
    
        
    
        
        

5. 游戏核心机制实现

5.1 玩家控制逻辑

// 跳跃
public void jump() {
    if (!isJumping) {
        velocityY = -25; // 向上的初速度
        isJumping = true;
    }
}

// 蹲下
public void duck() {
    if (!isJumping) {
        isDucking = true;
        rect.modify(rect.left, rect.top + 20, 
                   rect.right, rect.bottom);
    }
}

// 更新位置
public void update() {
    if (isJumping) {
        // 更新Y轴位置
        rect.modify(rect.left, rect.top + velocityY, 
                   rect.right, rect.bottom + velocityY);
        
        // 应用重力
        velocityY += 1.5f;
        
        // 检查是否落地
        if (rect.top >= 0) {
            rect.modify(rect.left, 0, 
                       rect.right, rect.bottom - rect.top);
            isJumping = false;
            velocityY = 0;
        }
    }
}

5.2 障碍物生成逻辑

// 随机生成障碍物
public static Obstacle generateRandom(int screenWidth, int screenHeight, int speed) {
    Random random = new Random();
    int type = random.nextInt(2); // 0或1
    float width = 50;
    float height = type == 0 ? 30 : 60;
    float top = screenHeight - height;
    
    return new Obstacle(screenWidth, top, 
                      screenWidth + width, screenHeight, 
                      speed, type);
}

// 在游戏循环中生成障碍物
if (currentTime - lastObstacleTime > 1500 - speed * 10) {
    obstacles.add(Obstacle.generateRandom(getWidth(), getHeight(), speed));
    lastObstacleTime = currentTime;
}

5.3 游戏循环与难度递增

private void startGameLoop() {
    getContext().getUITaskDispatcher().delayDispatch(() -> {
        if (!isGameOver) {
            // 更新游戏状态...
            
            // 增加分数
            score++;
            
            // 增加难度
            if (score % 100 == 0) {
                speed++;
            }
        }
        
        invalidate();
        startGameLoop();
    }, 16); // 约60帧/秒
}

6. 扩展功能建议

  1. ​多种角色选择​​:解锁不同外观的角色
  2. ​道具系统​​:无敌、加速、磁铁等道具
  3. ​场景变化​​:日夜交替或季节变化
  4. ​音效系统​​:跳跃音效、碰撞音效等
  5. ​特效系统​​:粒子效果、动画效果
  6. ​成就系统​​:记录玩家成就
  7. ​在线排行榜​​:与全球玩家比拼分数

你可能感兴趣的:(harmonyos,华为)