鸿蒙HarmonyOS 5跳棋小游戏实现指南

1. 项目概述

本跳棋小游戏基于鸿蒙HarmonyOS 5开发,包含完整的游戏逻辑和UI界面,支持六人跳棋对战。

2. 项目结构

/src/main/java/com/example/chinesecheckers/
    ├── MainAbilitySlice.java    // 主界面
    ├── GameView.java          // 游戏核心逻辑
    ├── Piece.java             // 棋子类
    ├── Player.java            // 玩家类
    └── resources/
        ├── base/
        │   ├── layout/
        │   │   └── ability_main.xml  // 布局文件
        │   └── graphic/
        │       ├── piece_red.xml      // 红方棋子样式
        │       ├── piece_blue.xml     // 蓝方棋子样式
        │       └── board_bg.xml      // 棋盘背景

3. 核心代码实现

3.1 棋子类(Piece.java)

package com.example.chinesecheckers;

public class Piece {
    public static final int RED = 0;
    public static final int BLUE = 1;
    public static final int GREEN = 2;
    public static final int YELLOW = 3;
    public static final int PURPLE = 4;
    public static final int ORANGE = 5;
    
    private int color;   // 棋子颜色
    private int row;     // 行坐标
    private int col;     // 列坐标
    private boolean selected = false; // 是否选中
    
    public Piece(int color, int row, int col) {
        this.color = color;
        this.row = row;
        this.col = col;
    }
    
    // getter和setter方法
    public int getColor() { return color; }
    public int getRow() { return row; }
    public int getCol() { return col; }
    public boolean isSelected() { return selected; }
    public void setSelected(boolean selected) { this.selected = selected; }
    public void setPosition(int row, int col) { this.row = row; this.col = col; }
    
    // 获取棋子颜色值
    public int getColorValue() {
        switch(color) {
            case RED: return 0xFFFF0000;
            case BLUE: return 0xFF0000FF;
            case GREEN: return 0xFF00FF00;
            case YELLOW: return 0xFFFFFF00;
            case PURPLE: return 0xFF800080;
            case ORANGE: return 0xFFFFA500;
            default: return 0xFF000000;
        }
    }
}

3.2 游戏视图(GameView.java)

package com.example.chinesecheckers;

import ohos.agp.components.Component;
import ohos.agp.render.Canvas;
import ohos.agp.render.Paint;
import ohos.agp.utils.Color;
import ohos.agp.utils.Point;
import ohos.app.Context;
import java.util.ArrayList;
import java.util.List;

public class GameView extends Component implements Component.DrawTask {
    private static final int BOARD_SIZE = 17; // 棋盘大小(六角形边长)
    private Paint boardPaint;
    private Paint piecePaint;
    private Paint selectedPaint;
    private Paint hintPaint;
    
    private List<Piece> pieces = new ArrayList<>();
    private Piece selectedPiece = null;
    private List<Point> possibleMoves = new ArrayList<>();
    private int currentPlayer = Piece.RED;
    
    public GameView(Context context) {
        super(context);
        init();
    }
    
    private void init() {
        boardPaint = new Paint();
        boardPaint.setColor(new Color(0xFF8B4513)); // 棕色棋盘
        
        piecePaint = new Paint();
        piecePaint.setStyle(Paint.Style.FILL_STYLE);
        
        selectedPaint = new Paint();
        selectedPaint.setColor(new Color(0x66FFFF00)); // 半透明黄色
        
        hintPaint = new Paint();
        hintPaint.setColor(new Color(0x6600FF00)); // 半透明绿色
        
        initPieces();
        addDrawTask(this);
        setTouchEventListener(this::onTouchEvent);
    }
    
    private void initPieces() {
        // 初始化六方棋子(每个玩家10颗棋子)
        // 红方
        initPlayerPieces(Piece.RED, 0, 0);
        // 蓝方
        initPlayerPieces(Piece.BLUE, 0, BOARD_SIZE-1);
        // 其他颜色类似...
    }
    
    private void initPlayerPieces(int color, int startRow, int startCol) {
        // 根据起始位置初始化玩家棋子
        // 实际实现需要考虑六角形棋盘的布局
    }
    
    @Override
    public void onDraw(Component component, Canvas canvas) {
        int width = getWidth();
        int height = getHeight();
        float hexSize = Math.min(width, height) / (BOARD_SIZE * 1.5f);
        float centerX = width / 2f;
        float centerY = height / 2f;
        
        // 绘制棋盘
        drawBoard(canvas, centerX, centerY, hexSize);
        
        // 绘制可移动位置提示
        drawMoveHints(canvas, hexSize);
        
        // 绘制棋子
        drawPieces(canvas, hexSize);
    }
    
    private void drawBoard(Canvas canvas, float centerX, float centerY, float hexSize) {
        // 绘制六角形棋盘
        // 实际实现需要绘制多个六边形组成棋盘
    }
    
    private void drawMoveHints(Canvas canvas, float hexSize) {
        for (Point move : possibleMoves) {
            float centerX = getHexCenterX(move.x, move.y, hexSize);
            float centerY = getHexCenterY(move.x, move.y, hexSize);
            canvas.drawCircle(centerX, centerY, hexSize * 0.3f, hintPaint);
        }
    }
    
    private void drawPieces(Canvas canvas, float hexSize) {
        for (Piece piece : pieces) {
            float centerX = getHexCenterX(piece.getRow(), piece.getCol(), hexSize);
            float centerY = getHexCenterY(piece.getRow(), piece.getCol(), hexSize);
            
            // 绘制棋子
            piecePaint.setColor(new Color(piece.getColorValue()));
            canvas.drawCircle(centerX, centerY, hexSize * 0.4f, piecePaint);
            
            // 绘制选中状态
            if (piece.isSelected()) {
                canvas.drawCircle(centerX, centerY, hexSize * 0.45f, selectedPaint);
            }
        }
    }
    
    private float getHexCenterX(int row, int col, float hexSize) {
        // 计算六角形格子的中心X坐标
        return hexSize * 1.5f * col + (row % 2) * hexSize * 0.75f;
    }
    
    private float getHexCenterY(int row, int col, float hexSize) {
        // 计算六角形格子的中心Y坐标
        return hexSize * (float)(Math.sqrt(3) / 2) * row;
    }
    
    private boolean onTouchEvent(Component component, TouchEvent event) {
        if (event.getAction() == TouchEvent.PRIMARY_POINT_DOWN) {
            int width = getWidth();
            int height = getHeight();
            float hexSize = Math.min(width, height) / (BOARD_SIZE * 1.5f);
            
            // 获取点击位置
            float x = event.getPointerPosition(0).getX();
            float y = event.getPointerPosition(0).getY();
            
            // 转换为六角形格子坐标
            int[] hexCoord = getHexCoordinate(x, y, hexSize);
            if (hexCoord != null) {
                handleClick(hexCoord[0], hexCoord[1]);
            }
        }
        return true;
    }
    
    private int[] getHexCoordinate(float x, float y, float hexSize) {
        // 将屏幕坐标转换为六角形格子坐标
        // 实现略...
        return new int[]{row, col};
    }
    
    private void handleClick(int row, int col) {
        // 查找点击的棋子
        Piece clickedPiece = getPieceAt(row, col);
        
        if (selectedPiece == null) {
            // 选中棋子
            if (clickedPiece != null && clickedPiece.getColor() == currentPlayer) {
                selectedPiece = clickedPiece;
                selectedPiece.setSelected(true);
                calculatePossibleMoves();
                invalidate();
            }
        } else {
            // 尝试移动棋子
            if (clickedPiece != null && clickedPiece.getColor() == currentPlayer) {
                // 切换选中
                selectedPiece.setSelected(false);
                selectedPiece = clickedPiece;
                selectedPiece.setSelected(true);
                calculatePossibleMoves();
                invalidate();
            } else {
                // 检查是否是合法移动
                for (Point move : possibleMoves) {
                    if (move.x == row && move.y == col) {
                        movePiece(selectedPiece, row, col);
                        return;
                    }
                }
            }
        }
    }
    
    private Piece getPieceAt(int row, int col) {
        for (Piece piece : pieces) {
            if (piece.getRow() == row && piece.getCol() == col) {
                return piece;
            }
        }
        return null;
    }
    
    private void calculatePossibleMoves() {
        possibleMoves.clear();
        if (selectedPiece == null) return;
        
        // 实现跳棋移动规则
        // 1. 相邻移动
        addAdjacentMoves(selectedPiece.getRow(), selectedPiece.getCol());
        
        // 2. 跳跃移动(递归查找所有可能的跳跃路径)
        findJumpMoves(selectedPiece.getRow(), selectedPiece.getCol(), new boolean[BOARD_SIZE][BOARD_SIZE]);
    }
    
    private void addAdjacentMoves(int row, int col) {
        // 六角形六个方向的相邻格子
        int[][] directions = {
            {0, -1}, {0, 1},    // 左右
            {-1, 0}, {1, 0},     // 上下
            {row % 2 == 0 ? -1 : 1, -1}, {row % 2 == 0 ? -1 : 1, 1} // 斜向
        };
        
        for (int[] dir : directions) {
            int newRow = row + dir[0];
            int newCol = col + dir[1];
            
            if (isValidPosition(newRow, newCol) && getPieceAt(newRow, newCol) == null) {
                possibleMoves.add(new Point(newRow, newCol));
            }
        }
    }
    
    private void findJumpMoves(int row, int col, boolean[][] visited) {
        if (visited[row][col]) return;
        visited[row][col] = true;
        
        // 六角形六个方向的跳跃
        int[][] directions = {
            {0, -2}, {0, 2},    // 左右跳跃
            {-2, 0}, {2, 0},     // 上下跳跃
            {row % 2 == 0 ? -2 : 2, -2}, {row % 2 == 0 ? -2 : 2, 2} // 斜向跳跃
        };
        
        for (int[] dir : directions) {
            int newRow = row + dir[0];
            int newCol = col + dir[1];
            
            if (isValidPosition(newRow, newCol) && getPieceAt(newRow, newCol) == null) {
                // 检查中间是否有棋子
                int midRow = (row + newRow) / 2;
                int midCol = (col + newCol) / 2;
                
                if (getPieceAt(midRow, midCol) != null) {
                    possibleMoves.add(new Point(newRow, newCol));
                    findJumpMoves(newRow, newCol, visited); // 递归查找连续跳跃
                }
            }
        }
    }
    
    private boolean isValidPosition(int row, int col) {
        return row >= 0 && row < BOARD_SIZE && col >= 0 && col < BOARD_SIZE;
    }
    
    private void movePiece(Piece piece, int toRow, int toCol) {
        piece.setPosition(toRow, toCol);
        piece.setSelected(false);
        selectedPiece = null;
        possibleMoves.clear();
        
        // 检查游戏是否结束
        if (checkWin(piece.getColor())) {
            gameOver(piece.getColor());
            return;
        }
        
        // 切换到下一个玩家
        switchToNextPlayer();
        invalidate();
    }
    
    private boolean checkWin(int color) {
        // 检查玩家是否将所有棋子移动到对面区域
        // 实现略...
        return false;
    }
    
    private void switchToNextPlayer() {
        // 六玩家轮流顺序
        currentPlayer = (currentPlayer + 1) % 6;
    }
    
    private void gameOver(int winner) {
        String[] colors = {"红方", "蓝方", "绿方", "黄方", "紫方", "橙方"};
        String message = colors[winner] + "获胜!";
        
        if (getContext() instanceof MainAbilitySlice) {
            ((MainAbilitySlice) getContext()).showGameOverDialog(message);
        }
        
        // 重置游戏
        resetGame();
    }
    
    public void resetGame() {
        pieces.clear();
        initPieces();
        currentPlayer = Piece.RED;
        selectedPiece = null;
        possibleMoves.clear();
        invalidate();
    }
}

3.3 主界面(MainAbilitySlice.java)

package com.example.chinesecheckers;

import ohos.aafwk.ability.AbilitySlice;
import ohos.aafwk.content.Intent;
import ohos.agp.components.*;
import ohos.agp.window.dialog.ToastDialog;

public class MainAbilitySlice extends AbilitySlice {
    private GameView gameView;
    private Text statusText;
    
    @Override
    public void onStart(Intent intent) {
        super.onStart(intent);
        
        DirectionalLayout layout = new DirectionalLayout(this);
        layout.setOrientation(DirectionalLayout.VERTICAL);
        
        // 状态文本
        statusText = new Text(this);
        statusText.setText("当前回合: 红方");
        statusText.setTextSize(50);
        statusText.setPadding(10, 10, 10, 10);
        
        // 游戏视图
        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 ruleButton = new Button(this);
        ruleButton.setText("游戏规则");
        ruleButton.setClickedListener(component -> showRules());
        
        buttonLayout.addComponent(resetButton);
        buttonLayout.addComponent(ruleButton);
        
        layout.addComponent(statusText);
        layout.addComponent(gameView);
        layout.addComponent(buttonLayout);
        
        super.setUIContent(layout);
    }
    
    public void showGameOverDialog(String message) {
        new ToastDialog(this)
            .setText(message)
            .show();
    }
    
    private void showRules() {
        new ToastDialog(this)
            .setText("跳棋规则:\n1. 每次可以移动一步或连续跳跃\n2. 先将所有棋子移动到对面为胜\n3. 点击棋子显示可移动位置")
            .show();
    }
}

4. 布局文件(ability_main.xml)

<?xml version="1.0" encoding="utf-8"?>
<DirectionalLayout
    xmlns:ohos="http://schemas.huawei.com/res/ohos"
    ohos:width="match_parent"
    ohos:height="match_parent"
    ohos:orientation="vertical"
    ohos:background_element="#F5F5F5">
    
    <Text
        ohos:id="$+id:status_text"
        ohos:width="match_parent"
        ohos:height="50vp"
        ohos:text="当前回合: 红方"
        ohos:text_size="20fp"
        ohos:text_color="#FF0000"
        ohos:padding="10vp"
        ohos:margin="5vp"
        ohos:background_element="#FFFFFF"/>
        
    <com.example.chinesecheckers.GameView
        ohos:id="$+id:game_view"
        ohos:width="match_parent"
        ohos:height="0vp"
        ohos:weight="1"
        ohos:margin="5vp"
        ohos:background_element="#FFFFFF"/>
        
    <DirectionalLayout
        ohos:id="$+id:button_layout"
        ohos:width="match_parent"
        ohos:height="wrap_content"
        ohos:orientation="horizontal"
        ohos:padding="10vp"
        ohos:margin="5vp"
        ohos:background_element="#FFFFFF">
        
        <Button
            ohos:id="$+id:reset_button"
            ohos:width="0vp"
            ohos:height="50vp"
            ohos:weight="1"
            ohos:text="重新开始"
            ohos:text_size="16fp"
            ohos:margin="5vp"/>
            
        <Button
            ohos:id="$+id:rule_button"
            ohos:width="0vp"
            ohos:height="50vp"
            ohos:weight="1"
            ohos:text="游戏规则"
            ohos:text_size="16fp"
            ohos:margin="5vp"/>
    </DirectionalLayout>
</DirectionalLayout>

5. 游戏规则实现要点

5.1 六角形棋盘坐标系统

// 六角形格子坐标转换为屏幕坐标
private float getHexCenterX(int row, int col, float hexSize) {
    return hexSize * 1.5f * col + (row % 2) * hexSize * 0.75f;
}

private float getHexCenterY(int row, int col, float hexSize) {
    return hexSize * (float)(Math.sqrt(3) / 2) * row;
}

// 屏幕坐标转换为六角形格子坐标
private int[] getHexCoordinate(float x, float y, float hexSize) {
    float hexHeight = (float)(Math.sqrt(3) / 2) * hexSize;
    int row = Math.round(y / hexHeight);
    
    float hexWidth = hexSize * 1.5f;
    int col = Math.round((x - (row % 2) * hexSize * 0.75f) / hexWidth);
    
    // 检查是否在有效范围内
    if (row >= 0 && row < BOARD_SIZE && col >= 0 && col < BOARD_SIZE) {
        return new int[]{row, col};
    }
    return null;
}

5.2 跳跃移动算法

private void findJumpMoves(int row, int col, boolean[][] visited) {
    if (visited[row][col]) return;
    visited[row][col] = true;
    
    int[][] directions = {
        {0, -2}, {0, 2},    // 左右跳跃
        {-2, 0}, {2, 0},     // 上下跳跃
        {row % 2 == 0 ? -2 : 2, -2}, {row % 2 == 0 ? -2 : 2, 2} // 斜向跳跃
    };
    
    for (int[] dir : directions) {
        int newRow = row + dir[0];
        int newCol = col + dir[1];
        
        if (isValidPosition(newRow, newCol) && getPieceAt(newRow, newCol) == null) {
            // 检查中间是否有棋子
            int midRow = (row + newRow) / 2;
            int midCol = (col + newCol) / 2;
            
            if (getPieceAt(midRow, midCol) != null) {
                possibleMoves.add(new Point(newRow, newCol));
                findJumpMoves(newRow, newCol, visited); // 递归查找连续跳跃
            }
        }
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值