UE游戏开发(自用)

多米诺的数据结构(DominoPiece.lua)

基本数据:

function DominoPiece:Initialize(id, topValue, bottomValue)
    --self.ID = id                     这个可能不需要,因为每个关卡都是要手动设计的,以后需要的话就加上
    self.TopValue = topValue         -- 上半部分的点数(1-6)
    self.BottomValue = bottomValue   -- 下半部分的点数(1-6)
    self.TopUsed = false             -- 上半部分是否已使用
    self.BottomUsed = false          -- 下半部分是否已使用
    self.Position = UE.FVector2D()   -- 在UI中的位置,解释一下这个UE.FVector2D是创建一个(0,0)的向量
    self.IsFlipped = false           -- 是否翻开(可见)
end

匹配方法:

function DominoPiece:CanMatch(value)
    -- 检查是否可以与给定值匹配
    if not self.TopUsed and self.TopValue == value then
        return true, "Top"
    elseif not self.BottomUsed and self.BottomValue == value then
        return true, "Bottom"
    end
    return false, nil
end

使用函数

UseHalf("Top")来标记半边已经用完

function DominoPiece:UseHalf(half)
    -- 标记牌的一半为已使用
    if half == "Top" then
        self.TopUsed = true
    elseif half == "Bottom" then
        self.BottomUsed = true
    end
end

检测函数

function DominoPiece:IsFullyUsed()
    -- 检查牌是否完全使用(两半都已用)
    return self.TopUsed and self.BottomUsed
end

游戏核心图结构(DominoGraph.lua)

基本数据

对于DominoDream我的想法是,如果一张牌压在一张牌的下面,就说明从下面到上面存在一条有向边,所以需要有边的数据,所有点的数据,所有点的入度

function DominoGraph:Initialize()
    self.Pieces = {}     -- 存储所有牌的引用
    self.Edges = {}      -- 存储有向边:Edges[fromID] = {toID1, toID2, ...}
    self.InDegree = {}   -- 存储每张牌的入度:InDegree[id] = count
end

添加一个Domino到游戏中

在右上角可能有完成某个指标就能够增加一张牌

function DominoGraph:AddPiece(piece)
    -- 添加一张牌到图中
    self.Pieces[piece.ID] = piece
    self.Edges[piece.ID] = {}
    self.InDegree[piece.ID] = 0
end

添加一条边

function DominoGraph:AddEdge(fromID, toID)
    -- 添加一条从fromID到toID的有向边(表示toID压在fromID上面)
    table.insert(self.Edges[fromID], toID)
    self.InDegree[toID] = (self.InDegree[toID] or 0) + 1
end

删除一条边
 

这里解释一下ipairs的意思是遍历table中的所有数据

下面的主要作用是将所有被它压住的Domino的入度减一,并且修改总边计数器与其相关的边

function DominoGraph:RemovePiece(pieceID)
    -- 从图中移除一张牌及其关联的边
    -- 更新受影响的牌的入度
    for _, toID in ipairs(self.Edges[pieceID] or {}) do
        self.InDegree[toID] = self.InDegree[toID] - 1
    end
    
    -- 移除该牌
    self.Pieces[pieceID] = nil
    self.Edges[pieceID] = nil
    
    -- 从其他牌的边列表中移除
    for fromID, toList in pairs(self.Edges) do
        for i = #toList, 1, -1 do
            if toList[i] == pieceID then
                table.remove(toList, i)
            end
        end
    end
    
    return self:GetFlippablePieces()
end

返回所有可以翻开的牌(入度为0)

返回当前可以翻开的牌,实际上就是查询所有的边的入度,并且进行标记,这个后面可能要加入动画

function DominoGraph:GetFlippablePieces()
    -- 返回所有出度为0的牌(可以翻开的牌)
    local flippable = {}
    for id, piece in pairs(self.Pieces) do
        if #(self.Edges[id] or {}) == 0 and not piece.IsFlipped then
            piece.IsFlipped = true
            table.insert(flippable, piece)
        end
    end
    return flippable
end

返回所有已经翻开的牌

function DominoGraph:GetVisiblePieces()
    -- 返回所有已翻开的牌
    local visible = {}
    for _, piece in pairs(self.Pieces) do
        if piece.IsFlipped then
            table.insert(visible, piece)
        end
    end
    return visible
end

检查图是否为空

这个next有两个参数和返回值,输入的第一个值是table表,第二个值是index,表示从这里开始next,如果在遍历的过程中有值,就返回其index和value,如果没有就返回nil

function DominoGraph:IsEmpty()
    -- 检查图是否为空(所有牌都被移除)
    return next(self.Pieces) == nil
end

玩家的手牌管理(PlayerHand.lua)

玩家可使用的Domino

function PlayerHand:Initialize(initialPieces)
    self.Pieces = initialPieces or {}  -- 手中的牌列表
end

返回手牌中最右边的牌
 

function PlayerHand:GetRightmostPiece()
    -- 获取最右边的牌
    if #self.Pieces > 0 then
        return self.Pieces[#self.Pieces]
    end
    return nil
end

移除最右边的牌并且记录

function PlayerHand:RemoveRightmostPiece()
    -- 移除并返回最右边的牌
    if #self.Pieces > 0 then
        return table.remove(self.Pieces)
    end
    return nil
end

添加一张手牌

function PlayerHand:AddPiece(piece)
    -- 添加一张牌到手中
    table.insert(self.Pieces, piece)
end

获得最右边的牌的可用值

function PlayerHand:GetMatchValue()
    -- 获取最右边牌的可用值
    local piece = self:GetRightmostPiece()
    if piece then
        if not piece.TopUsed then
            return piece.TopValue
        elseif not piece.BottomUsed then
            return piece.BottomValue
        end
    end
    return nil
end

return PlayerHand

GameManager(DominoGameManager.lua)

初始化数据

这个我有点疑问

function DominoGameManager:Initialize()
    self.Graph = require "DominoGraph".New()
    self.PlayerHand = require "PlayerHand".New()
    self.AvailablePieces = {}  -- 可以匹配的牌
end

初始化所有数据

function DominoGameManager:SetupGame(tableSetup, handPieces)
    -- 设置游戏初始状态
    -- tableSetup: {pieces={piece1, piece2, ...}, edges={{from1, to1}, {from2, to2}, ...}}
    
    -- 添加桌面上的牌
    for _, piece in ipairs(tableSetup.pieces) do
        self.Graph:AddPiece(piece)
    end
    
    -- 添加覆盖关系
    for _, edge in ipairs(tableSetup.edges) do
        self.Graph:AddEdge(edge[1], edge[2])
    end
    
    -- 初始化可翻开的牌
    local flippablePieces = self.Graph:GetFlippablePieces()
    self.AvailablePieces = flippablePieces
    
    -- 设置玩家手牌
    self.PlayerHand = require "PlayerHand".New(handPieces)
    
    return self
end

查找可以匹配的牌

function DominoGameManager:FindMatchingPieces(value)
    -- 查找可以与给定值匹配的牌
    local matches = {}
    for _, piece in ipairs(self.AvailablePieces) do
        local canMatch, half = piece:CanMatch(value)
        if canMatch then
            table.insert(matches, {piece=piece, half=half})
        end
    end
    return matches
end

获取当前玩家状态

function DominoGameManager:GetGameState()
    -- 获取当前游戏状态
    local matchValue = self.PlayerHand:GetMatchValue()
    local matchingPieces = {}
    
    if matchValue then
        matchingPieces = self:FindMatchingPieces(matchValue)
    end
    
    return {
        handPieces = self.PlayerHand.Pieces,
        availablePieces = self.AvailablePieces,
        matchValue = matchValue,
        matchingPieces = matchingPieces,
        hasMatches = #matchingPieces > 0
    }
end

这一步以后要换成射线检测之类的

function DominoGameManager:PlayMove(tablePieceID, tablePieceHalf)
    -- 执行一步移动
    -- 1. 找到要拿起的桌面牌
    local tablePiece = nil
    for _, piece in ipairs(self.AvailablePieces) do
        if piece.ID == tablePieceID then
            tablePiece = piece
            break
        end
    end
    
    if not tablePiece then
        return false, "无法找到选择的牌"
    end
    
    -- 2. 验证匹配
    local value = self.PlayerHand:GetMatchValue()
    local canMatch, half = tablePiece:CanMatch(value)
    
    if not canMatch or half ~= tablePieceHalf then
        return false, "选择的牌不匹配"
    end
    
    -- 3. 从桌面移除牌
    self.Graph:RemovePiece(tablePieceID)
    
    -- 4. 更新可用牌列表
    local newFlippable = self.Graph:GetFlippablePieces()
    for _, piece in ipairs(newFlippable) do
        table.insert(self.AvailablePieces, piece)
    end
    
    -- 从可用列表中移除已用牌
    for i = #self.AvailablePieces, 1, -1 do
        if self.AvailablePieces[i].ID == tablePieceID then
            table.remove(self.AvailablePieces, i)
            break
        end
    end
    
    -- 5. 更新手牌
    local handPiece = self.PlayerHand:GetRightmostPiece()
    if not handPiece.TopUsed and handPiece.TopValue == value then
        handPiece:UseHalf("Top")
    elseif not handPiece.BottomUsed and handPiece.BottomValue == value then
        handPiece:UseHalf("Bottom")
    end
    
    -- 6. 如果手牌已完全使用,舍弃它
    if handPiece:IsFullyUsed() then
        self.PlayerHand:RemoveRightmostPiece()
    end
    
    -- 标记桌面牌的已用半部分
    tablePiece:UseHalf(tablePieceHalf)
    
    -- 7. 检查胜利条件
    local isWin = self.Graph:IsEmpty()
    
    return true, {
        isWin = isWin,
        newFlippable = newFlippable
    }
end

游戏模式参考

-- DominoGameMode.lua
-- 游戏模式,负责管理游戏全局逻辑
local DominoGameMode = Class()
local DominoGameManager = require "DominoGameManager"

function DominoGameMode:Initialize(Initializer)
    -- 调用BP_DominoGameMode的父类构造函数
    self.Super:Initialize(Initializer)
    
    -- 初始化游戏管理器
    self.GameManager = DominoGameManager.New()
    
    -- 游戏配置参数
    self.NumHandPieces = 7  -- 初始手牌数量
    self.NumTablePieces = 28 -- 桌面牌数量
    
    -- 游戏状态
    self.IsGameStarted = false
    self.IsGameOver = false
    self.Winner = nil
end

function DominoGameMode:BeginPlay()
    self.Super:BeginPlay()
    UE.UGameplayStatics.SetGamePaused(self:GetWorld(), true)
end

function DominoGameMode:StartNewGame()
    self.IsGameStarted = true
    self.IsGameOver = false
    self.Winner = nil
    
    -- 重置游戏状态并创建新的游戏
    self:SetupNewGame()
    
    -- 取消游戏暂停
    UE.UGameplayStatics.SetGamePaused(self:GetWorld(), false)
    
    -- 广播游戏开始事件
    self:OnGameStarted()
end

function DominoGameMode:SetupNewGame()
    -- 创建所有牌
    local allPieces = self:CreateAllDominoPieces()
    
    -- 随机选择手牌和桌面牌
    local handPieces, tablePieces = self:DistributePieces(allPieces)
    
    -- 创建桌面布局(牌的位置和覆盖关系)
    local tableSetup = self:CreateTableSetup(tablePieces)
    
    -- 初始化游戏管理器
    self.GameManager:SetupGame(tableSetup, handPieces)
    
    -- 刷新UI
    self:UpdateGameUI()
end

function DominoGameMode:CreateAllDominoPieces()
    -- 创建一副完整的多米诺牌
    local DominoPiece = require "DominoPiece"
    local pieces = {}
    local id = 1
    
    for i = 1, 6 do
        for j = 1, 6 do
            local piece = DominoPiece.New(id, i, j)
            table.insert(pieces, piece)
            id = id + 1
        end
    end
    
    -- 随机打乱牌的顺序
    for i = #pieces, 2, -1 do
        local j = math.random(i)
        pieces[i], pieces[j] = pieces[j], pieces[i]
    end
    
    return pieces
end

function DominoGameMode:DistributePieces(allPieces)
    -- 分配手牌和桌面牌
    local handPieces = {}
    local tablePieces = {}
    
    -- 分配手牌
    for i = 1, math.min(self.NumHandPieces, #allPieces) do
        table.insert(handPieces, table.remove(allPieces, 1))
    end
    
    -- 分配桌面牌
    for i = 1, math.min(self.NumTablePieces, #allPieces) do
        table.insert(tablePieces, table.remove(allPieces, 1))
    end
    
    return handPieces, tablePieces
end

function DominoGameMode:CreateTableSetup(tablePieces)
    -- 创建桌面牌的布局
    -- 这里使用简单的随机覆盖关系
    local tableSetup = {
        pieces = tablePieces,
        edges = {}
    }
    
    -- 创建一些随机的覆盖关系(边)
    local numEdges = math.floor(#tablePieces * 0.3)  -- 约30%的牌会覆盖其他牌
    
    for i = 1, numEdges do
        local fromIndex = math.random(#tablePieces)
        local toIndex = math.random(#tablePieces)
        
        -- 避免自环和重复边
        if fromIndex ~= toIndex then
            local fromID = tablePieces[fromIndex].ID
            local toID = tablePieces[toIndex].ID
            
            -- 检查是否会导致循环依赖
            local willCreateCycle = false
            -- 简单检测:如果已经存在从toID到fromID的路径,则会形成循环
            for _, edge in ipairs(tableSetup.edges) do
                if edge[1] == toID and edge[2] == fromID then
                    willCreateCycle = true
                    break
                end
            end
            
            if not willCreateCycle then
                table.insert(tableSetup.edges, {fromID, toID})
            end
        end
    end
    
    return tableSetup
end

function DominoGameMode:UpdateGameUI()
    -- 获取当前游戏状态
    local gameState = self.GameManager:GetGameState()
    
    -- 更新UI(通过调用蓝图实现的函数)
    self:UpdateHandPiecesUI(gameState.handPieces)
    self:UpdateTablePiecesUI(gameState.availablePieces)
    self:UpdateMatchIndicator(gameState.matchValue, gameState.hasMatches)
    
    -- 高亮可匹配的牌
    if gameState.hasMatches then
        local matchingIDs = {}
        for _, match in ipairs(gameState.matchingPieces) do
            table.insert(matchingIDs, match.piece.ID)
        end
        self:HighlightMatchingPieces(matchingIDs)
    end
end

-- 这些函数将在蓝图中实现
function DominoGameMode:UpdateHandPiecesUI(handPieces)
    -- 在蓝图中实现
end

function DominoGameMode:UpdateTablePiecesUI(tablePieces)
    -- 在蓝图中实现
end

function DominoGameMode:UpdateMatchIndicator(matchValue, hasMatches)
    -- 在蓝图中实现
end

function DominoGameMode:HighlightMatchingPieces(pieceIDs)
    -- 在蓝图中实现
end

function DominoGameMode:OnGameStarted()
    -- 在蓝图中实现
end

function DominoGameMode:OnGameOver(isWin)
    -- 在蓝图中实现
end

-- 游戏操作API,可以从UI调用
function DominoGameMode:PlayPiece(tablePieceID, half)
    if self.IsGameOver then return false end
    
    local success, result = self.GameManager:PlayMove(tablePieceID, half)
    
    if success then
        -- 更新UI
        self:UpdateGameUI()
        
        -- 检查胜利条件
        if result.isWin then
            self.IsGameOver = true
            self.Winner = "Player"
            self:OnGameOver(true)
        end
    end
    
    return success
end

function DominoGameMode:DiscardHandPiece()
    if self.IsGameOver then return false end
    
    local success = self.GameManager:DiscardHandPiece()
    
    if success then
        -- 更新UI
        self:UpdateGameUI()
        
        -- 检查是否还有手牌
        local gameState = self.GameManager:GetGameState()
        if #gameState.handPieces == 0 then
            self.IsGameOver = true
            self.Winner = nil  -- 平局
            self:OnGameOver(false)
        end
    end
    
    return success
end

return DominoGameMode

-- DominoPieceWidget.lua
-- 多米诺牌的UI组件
local DominoPieceWidget = Class()

function DominoPieceWidget:Construct()
    self.Super:Construct()
    self.PieceData = nil
    self.IsHighlighted = false
    self.IsHandPiece = false
    
    -- 绑定点击事件
    self.Button_Top.OnClicked:Add(self, self.OnTopClicked)
    self.Button_Bottom.OnClicked:Add(self, self.OnBottomClicked)
end

function DominoPieceWidget:SetPieceData(pieceData, isHandPiece)
    self.PieceData = pieceData
    self.IsHandPiece = isHandPiece or false
    
    -- 更新UI显示
    self:UpdateVisuals()
end

function DominoPieceWidget:UpdateVisuals()
    if not self.PieceData then return end
    
    -- 设置点数显示
    self.Text_TopValue:SetText(tostring(self.PieceData.TopValue))
    self.Text_BottomValue:SetText(tostring(self.PieceData.BottomValue))
    
    -- 设置已使用状态
    local topOpacity = self.PieceData.TopUsed and 0.3 or 1.0
    local bottomOpacity = self.PieceData.BottomUsed and 0.3 or 1.0
    
    self.Panel_Top:SetRenderOpacity(topOpacity)
    self.Panel_Bottom:SetRenderOpacity(bottomOpacity)
    
    -- 设置可见性
    local visibility = self.PieceData.IsFlipped and UE.ESlateVisibility.Visible or UE.ESlateVisibility.Hidden
    self:SetVisibility(visibility)
    
    -- 设置按钮可交互性
    self.Button_Top:SetIsEnabled(not self.PieceData.TopUsed and not self.IsHandPiece)
    self.Button_Bottom:SetIsEnabled(not self.PieceData.BottomUsed and not self.IsHandPiece)
    
    -- 更新高亮状态
    self:SetHighlighted(self.IsHighlighted)
end

function DominoPieceWidget:SetHighlighted(highlight)
    self.IsHighlighted = highlight
    
    local borderColor = highlight and UE.FLinearColor(1.0, 0.8, 0.0, 1.0) or UE.FLinearColor(0.0, 0.0, 0.0, 1.0)
    local borderThickness = highlight and 3.0 or 1.0
    
    self.Border_Main:SetBrushColor(borderColor)
    self.Border_Main:SetDesiredSizeScale(UE.FVector2D(1.0, borderThickness))
end

function DominoPieceWidget:OnTopClicked()
    if self.OnPieceHalfClicked and self.PieceData then
        self.OnPieceHalfClicked(self.PieceData.ID, "Top")
    end
end

function DominoPieceWidget:OnBottomClicked()
    if self.OnPieceHalfClicked and self.PieceData then
        self.OnPieceHalfClicked(self.PieceData.ID, "Bottom")
    end
end

return DominoPieceWidget

-- DominoGameHUD.lua
-- 主游戏UI
local DominoGameHUD = Class()

function DominoGameHUD:Construct()
    self.Super:Construct()
    
    -- 获取游戏模式引用
    self.GameMode = UE.UGameplayStatics.GetGameMode(self)
    
    -- 绑定按钮事件
    self.Button_StartGame.OnClicked:Add(self, self.OnStartGameClicked)
    self.Button_DiscardPiece.OnClicked:Add(self, self.OnDiscardPieceClicked)
    
    -- 初始化UI状态
    self:UpdateUIState(false)
end

function DominoGameHUD:UpdateUIState(gameStarted)
    self.Panel_MainMenu:SetVisibility(gameStarted and UE.ESlateVisibility.Hidden or UE.ESlateVisibility.Visible)
    self.Panel_GameUI:SetVisibility(gameStarted and UE.ESlateVisibility.Visible or UE.ESlateVisibility.Hidden)
end

function DominoGameHUD:SetupPieceWidgets(container, pieces, isHandPieces)
    -- 清空容器
    container:ClearChildren()
    
    -- 创建并添加牌组件
    for _, piece in ipairs(pieces) do
        local widget = self:CreatePieceWidget()
        widget:SetPieceData(piece, isHandPieces)
        
        -- 如果是桌面牌,绑定点击事件
        if not isHandPieces then
            widget.OnPieceHalfClicked = function(pieceID, half)
                self:OnTablePieceClicked(pieceID, half)
            end
        end
        
        container:AddChild(widget)
    end
end

function DominoGameHUD:CreatePieceWidget()
    -- 创建一个多米诺牌组件实例
    return UE.UWidgetBlueprintLibrary.Create(self, self.DominoPieceWidgetClass)
end

function DominoGameHUD:HighlightMatchingPieces(matchingIDs)
    -- 高亮所有可匹配的牌
    for i = 0, self.Container_TablePieces:GetChildrenCount() - 1 do
        local widget = self.Container_TablePieces:GetChildAt(i)
        
        local isMatching = false
        for _, id in ipairs(matchingIDs) do
            if widget.PieceData and widget.PieceData.ID == id then
                isMatching = true
                break
            end
        end
        
        widget:SetHighlighted(isMatching)
    end
end

function DominoGameHUD:UpdateMatchIndicator(matchValue, hasMatches)
    -- 更新匹配指示器
    local text = "当前匹配值: " .. (matchValue or "无")
    self.Text_MatchValue:SetText(text)
    
    local color = hasMatches and UE.FLinearColor(0.0, 1.0, 0.0, 1.0) or UE.FLinearColor(1.0, 0.0, 0.0, 1.0)
    self.Text_MatchValue:SetColorAndOpacity(color)
    
    -- 更新舍弃按钮状态
    self.Button_DiscardPiece:SetIsEnabled(true) -- 通常始终允许舍弃
end

function DominoGameHUD:OnStartGameClicked()
    if self.GameMode then
        self.GameMode:StartNewGame()
        self:UpdateUIState(true)
    end
end

function DominoGameHUD:OnDiscardPieceClicked()
    if self.GameMode then
        self.GameMode:DiscardHandPiece()
    end
end

function DominoGameHUD:OnTablePieceClicked(pieceID, half)
    if self.GameMode then
        self.GameMode:PlayPiece(pieceID, half)
    end
end

function DominoGameHUD:ShowGameOverScreen(isWin)
    -- 显示游戏结束界面
    self.Panel_GameOver:SetVisibility(UE.ESlateVisibility.Visible)
    
    local resultText = isWin and "胜利!" or "游戏结束"
    self.Text_GameResult:SetText(resultText)
end

return DominoGameHUD

unlua的单例模式

-- singleton.lua
local Singleton = {}

local instance = nil

function Singleton.getInstance()
    if not instance then
        instance = {
            -- 单例的属性和方法
            value = 0,
            
            setValue = function(self, val)
                self.value = val
            end,
            
            getValue = function(self)
                return self.value
            end
        }
    end
    return instance
end

return Singleton

-- 在其他地方使用
local SingletonModule = require "singleton"
local instance = SingletonModule.getInstance()
instance:setValue(10)

基于PYNQ-Z2实现手写数字识别卷积神经网络硬件加速器源代码(CNN硬件加速器入门级项目),该项目是个人毕设项目,答辩评审分达到98分,代码都经过调试测试,确保可以运行!欢迎下载使用,可用于小白学习、进阶。该资源主要针对计算机、通信、人工智能、自动化等相关专业的学生、老师或从业者下载使用,亦可作为期末课程设计、课程大作业、毕业设计等。项目整体具有较高的学习借鉴价值!基础能力强的可以在此基础上修改调整,以实现不同的功能。 基于PYNQ-Z2实现手写数字识别卷积神经网络硬件加速器源代码(CNN硬件加速器入门级项目)基于PYNQ-Z2实现手写数字识别卷积神经网络硬件加速器源代码(CNN硬件加速器入门级项目)基于PYNQ-Z2实现手写数字识别卷积神经网络硬件加速器源代码(CNN硬件加速器入门级项目)基于PYNQ-Z2实现手写数字识别卷积神经网络硬件加速器源代码(CNN硬件加速器入门级项目)基于PYNQ-Z2实现手写数字识别卷积神经网络硬件加速器源代码(CNN硬件加速器入门级项目)基于PYNQ-Z2实现手写数字识别卷积神经网络硬件加速器源代码(CNN硬件加速器入门级项目)基于PYNQ-Z2实现手写数字识别卷积神经网络硬件加速器源代码(CNN硬件加速器入门级项目)基于PYNQ-Z2实现手写数字识别卷积神经网络硬件加速器源代码(CNN硬件加速器入门级项目)基于PYNQ-Z2实现手写数字识别卷积神经网络硬件加速器源代码(CNN硬件加速器入门级项目)基于PYNQ-Z2实现手写数字识别卷积神经网络硬件加速器源代码(CNN硬件加速器入门级项目)基于PYNQ-Z2实现手写数字识别卷积神经网络硬件加速器源代码(CNN硬件加速器入门级项目)基于PYNQ-Z2实现手写数字识别卷积神经网络硬件加速器源代码(CNN硬件加速器入门级项目)基于PYNQ-Z2实现手写数字识别卷积神经网络硬件加速器源代码(CN
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值