用c 语言实现贪吃蛇小游戏

1.1.贪吃蛇的属性

本程序使用单链表连接组成贪吃蛇身,所以,在创建贪吃蛇属性时也要创建单个贪吃蛇节点,以及蛇的当前状态、前进方向等等,如下:

enum DIRECTION
{
	UP = 1,
	DOWN,
	LEFT,
	RIGHT
};//蛇当前方向
enum Game_Status{
	OK,//正常运行
	END_NORMAL,//按ESC退出
	KILL_BY_WALL,
	KILL_BY_SELF
};//蛇的状态,为OK时正常运行,其他情况结束游戏
typedef strct SnakeNode{
	int x;
	int y;
	//x、y为节点当前所处的坐标位置
	struct SnakeNode*next;
}SnakeNode,*pSnakeNode;//贪吃蛇节点
struct Snake{
	struct SnakeNode*_pSnake;//蛇头节点
	struct SnakeNode*_pFood;//食物节点
	int _Score;//贪吃蛇累计得分
	int _FoodWeight;//一个食物的分数
	int _SleepTime;//每走一步的休息时间
	enum DIRECTION _Dir;//描述蛇的方向
	enum Status _Status;//游戏的状态:正常、退出、撞墙、吃到自己
}Snake,*pSnake;//贪吃蛇整体属性

1.2.窗口界面以及贪吃蛇身、食物的初始化和打印(了解win32 API有关服务的使用,调用这些服务需要包含“<windows.h>”头文件)

做以上事情需要调用win32 API的一些服务(相当于调用函数),先了解一些服务的使用:

1.2.1.获取终端(控制台窗口)的句柄

首先要想在窗口中随意构图,便要先获取终端设备的句柄(⽤来标识不同设备的数值,使⽤它可以操作设备)。调用GetStdHandle.

1.2.2.获取光标信息

光标结构体类型定义为CONSOLE_CURSOR_INFO,如下:

typedef struct _CONSOLE_CURSOR_INFO
 {
	 DWORD dwSize;//光标填充的字符单元格的百分⽐,从1到100
 	BOOL bVisible;//光标可视度,非0为可视,0为不可视
}  CONSOLE_CURSOR_INFO, *PCONSOLE_CURSOR_INFO

然后调用服务GetConsloeCursorInfo获取光标信息,在调用服务SetConsoleCursorInfo设置修改光标信息,如:

HANDLE handle=GetStdConsloe(STD_OUTPUT_HANDLE);
CONSOLE_CURSOR_INFO cursor_info;
GetConsoleCursorInfo(handle,&cursor_info);
cursor_info.dwSize=50;
cursor_info.bVisible=0;
SetConsoleCursorInfo(handle,&cursor_info);

这就把光标的填充百分比改成50%,且不可视了。

1.2.3.修改光标位置

typedef struct _COORD {
 SHORT X;
 SHORT Y;
} COORD, *PCOORD;
//COORD表示⼀个字符在控制台屏幕上的坐标
  • 注意:这里的坐标系不同于普通直角坐标系,如下:
    在这里插入图片描述

接着调用服务SetConsoleCursorPosition。例如:

 COORD pos = { 10, 5};
 HANDLE hOutput = NULL;
 //获取标准输出的句柄(⽤来标识不同设备的数值)
 hOutput = GetStdHandle(STD_OUTPUT_HANDLE);
 //设置标准输出上光标的位置为pos
 SetConsoleCursorPosition(hOutput, pos);

这就是把光标改到坐标为(10,5)的位置上。

  • 下面实现一个能改变光标位置的函数:
void Setpos(int x,int y)
{
	HANDLE handle=GetStdHandle(STD_OUTPUT_HANDLE);
	COORD pos={x,y};
	SetConsoleCursorPosition(handle,pos);
}

1.2.4.创建游戏界面窗口

  • 使用宽字符‘□’代表墙,‘★’代表食物,‘●’代表蛇,需要调用setlocal服务才能打印特殊符,打印一个‘▲’如下:
	setlocale(LC_ALL, "");
	wchar_t ch = L'▲';
	wprintf(L“%lc”,ch);
  • 制作一个高28,宽28的游戏界面,如下:
int i;
for (i = 0; i <= 54; i += 2)
{
	wprintf(L"%lc", WALL);
}
SetPos(0, 27);
for (i = 0; i <= 54; i += 2)
{
	wprintf(L"%lc", WALL);
}
for (i = 1; i <= 26; i++)
{
	SetPos(0, i);
	wprintf(L"%lc", WALL);
	SetPos(54, i);
	wprintf(L"%lc", WALL);
}

在这里插入图片描述

1.2.5.初始化贪吃蛇

接着初始化贪吃蛇,令其行进方向变量一开始为“RIGHT”’,状态为“OK”,休眠时间(即运动速度,休眠时间越长,速度越慢,反之)为200ms,一个食物的得分为10,初始累计得分为0,再创建5个蛇身节点,代码如下:

	int i;
	pSnakeNode pcur=NULL;
	for (i = 0; i < 5; i++)
	{
		pcur = (pSnakeNode)malloc(sizeof(SnakeNode));
		pcur->x = 20 + 2 * i;
		pcur->y = 14;
		pcur->next = NULL;
		//采用头插法,从左往右构建蛇身
		if (ps->_pSnake == NULL)
		{
			ps->_pSnake= pcur;
		}
		else
		{
			pcur->next = ps->_pSnake;
			ps->_pSnake = pcur;
		}
	}
	pSnakeNode cur = ps->_pSnake;
	//打印蛇身
	while (cur)
	{
		SetPos(cur->x, cur->y);//改变光标位置,实现从右往左打印蛇身
		wprintf(L"%lc", BODY);
		cur = cur->next;
	}
	//初始化贪吃蛇属性
	ps->_Status = OK;
	ps->_Score = 0;
	ps->_pFood = NULL;
	ps->_SleepTime = 200;
	ps->_FoodWeight = 10;
	ps->_Dir = RIGHT;
  • 打印图如下:
    在这里插入图片描述

1.2.6.食物的随机生成

食物不能生成在蛇身的位置,并且只能在方框内生成,代码如下:

#define FOOD L'★'
 void CreateFood(pSnakeNode pSnake->_pSnake)
{
	srand((unsigned int)time(NULL));
	again:
		while(1)
		{
			int x=rand()%51+2;//因为一个宽字符占两个普通字符大小,所以横坐标只能是2的倍数
			int y=rand()%26+1;
			if(x%2==0)
			{
				break;
			}
		}
		pSnakeNode pcur=pSnake->_pSnake;
		while(pcur)
		{
			if(x==pcur->x&&y==pcur->y)
			{
				goto again;//如果食物坐标等于蛇身坐标,返回“again”位置重新生成食物坐标
			}
			pcur=pcur->next;
		}	
		pSnakeNode pFood = (pSnakeNode)malloc(sizeof(SnakeNode));
		if (pFood == NULL)
		{
			perror("CreatFood()::malloc()");
			return;
		}
		pFood->x = x;
		pFood->y = y;
		ps->_pFood = pFood;//把当前地图上仅有的一个食物节点信息保存在贪吃蛇食物属性中
		SetPos(x, y);
		wprintf(L"%lc",FOOD);
}

生成图如下:
在这里插入图片描述

1.3.贪吃蛇的行动

贪吃蛇每行动一格就要考虑当前方向、下一步的方向、下一步是否吃到食物(如果吃到食物则下一步变成蛇的头其他不变;如果没吃到食物则下一步变成头,原蛇身最后一个节点销毁)。

  • 在讲以上东西之前先了解win32API的GetAsyncKeyState服务。GetAsyncKeyState 的返回值是short类型,在上⼀次调⽤GetAsyncKeyState 函数后,如果返回的16位的short数据中,最位是1,说明按键的状态是按下,如果最⾼是0,说明按键的状态是抬起;如果最低位被置为1则说明,该按键被按过,否则为0。如果我们要判断⼀个键是否被按过,可以检测GetAsyncKeyState返回值的最低值是否为1,所以可以定义:
#define KEY_PRESS(vs)  (GetAsyncKeyState(vs)&1)?1:0

1.3.1.根据指定按键改变贪吃蛇运动方向

当按下的按键方向与原运动方向相反时,贪吃蛇方向不改变;只有当按下的按键方向与原运动方向不相反时,贪吃蛇方向变成按键方向。代码如下:

//pSnake->_Dir是贪吃蛇原运动方向
if(KEEY_PRESS(VK_UP)&&pSnake->_Dir!=DOWN)
{
   pSnake->_Dir=UP;
}
if(KEEY_PRESS(VK_DOWN)&&pSnake->_Dir!=UP)
{
   pSnake->_Dir=DOWN;
}
if(KEEY_PRESS(VK_LEFT)&&pSnake->_Dir!=RIGHT)
{
   pSnake->_Dir=LEFT;
}
if(KEEY_PRESS(VK_RIGHT)&&pSnake->_Dir!=LEFT)
{
   pSnake->_Dir=RIGHT;
}

1.3.2.根据贪吃蛇的当前方向来确定蛇头移动一格后的位置,从而推导至整条蛇的位置。

  • 如果蛇方向向上,蛇头移动后的位置是当前蛇头上方一格。同理左、右、下都是如此。代码如下:
//pSnake->_Dir是贪吃蛇方向
PSnakeNode pNext=(pSnakeNode)malloc(sizeof(SnakeNode));//开辟下一格位置的空间
if(pSnake->_Dir==UP)
{
	pNext->x=pSnake->_pSnake->x;
	pNext->y=pSnake->_pSnake->y-1;
}
if(pSnake->_Dir==DOWN)
{
	pNext->x=pSnake->_pSnake->x;
	pNext->y=pSnake->_pSnake->y+1;
}
if(pSnake->_Dir==LEFT)
{
	pNext->x=pSnake->_pSnake->x-1;
	pNext->y=pSnake->_pSnake->y;
}
if(pSnake->_Dir==RIGHT)
{
	pNext->x=pSnake->_pSnake->x+1;
	pNext->y=pSnake->_pSnake->y;
}

1.3.3.考虑下一格位置是否是食物

  • 如果下一格是食物,那么食物位置就变成了蛇头位置,其余不变,再重新打印一遍贪吃蛇;如果下一格不是食物,把蛇头移到下一格,销毁原蛇身尾节点,重新打印一遍贪吃蛇。
  • 如果下一格是食物。
if(pNext->x==pSnake->_pFood->x&&pNext->y==pSnake->_pFood->y)//判断下一格是否是食物
{
	pNext->next=pSnake->_pSnake;
	pSnake->_pSnake=pNext;
	pSnakeNode pcur=pSnake->_pSnake;
	while(pcur)//打印移动后的蛇身
	{
		Setpos(pcur->x,pcur->y);//把光标定位到相应位置依次打印节点
		wprintf(L"%lc",BODY);//打印宽字符
		pcur=pcur->next;
	}
	free(pSnake->_pSnake);
	pSnake->_pFood=NULL;
	CreateFood(pSnake->_pSnake);//调用食物生成函数重新生成食物
	pSnake->_Score+=pSnake->_FoodWeight;//累计分数等于当前分数加上单个食物的分数
}
  • 如果下一格不是食物。
if(pNext->x!=pSnake->_pFood->x||pNext->y!=pSnake->_pFood->y)//判断下一格是否是食物
{
	pNext->next=pSnake->_pSnake;
	pSnake->_pSnake=pNext;
	pSnakeNode pcur=pSnake->_pSnake;
	while(pcur->next->next)//当遍历到倒数第二个节点时停下来,从而可以释放掉最后一个节点
	{
		Setpos(pcur->x,pcur->y);
		wprintf(L"%lc",BODY);
		pcur=pcur->next;
	}
	Setpos(pcur->x,pcur->y);
	printf("  ");//把原来占两个字符大小的尾节点图形'●'换成同为两个字符大小的'  '。
	free(pcur->next);//释放掉最后一个节点
	pcur->next=NULL;
}

1.4.游戏结束的几种情况

当蛇头碰到了墙、蛇头碰到了蛇身、按下“ESCAPE”正常退出、按下空格

1.4.1.蛇撞墙死完导致游戏结束

  • 如果蛇头位置等于周围墙的位置,则游戏结束
pSnakeNode pcur=pSnake->_pSnake;
if(pcur->x==0||
	pcur->x==54||
	pcur->y==0||
	pcur->y==27)
	{
		pSnake->_Status=KILL_BY_WALL;
	}

1.4.2.蛇头撞到蛇身导致游戏结束

  • 如果蛇头位置与其蛇身任意位置相同,则游戏结束。
pSnakeNode pcur=pSnake->_pSnake;
while(pcur)
{
	if(pcur->x==(pSnake->_pSnake->x)&&pcur->y==(pSnake->_pSnake->y))
	{
		pSnake->_Status=KILL_BY_SELF;
	}
	pcur=pcur->next;
}

1.4.3.按“ESCAPE”键直接结束游戏

if(KEEY_PRESS(VK_ESCAPE))
{
	pSnake->_Status=END_NORMAL;
}

1.5整体代码的实现

说了这么多,还是那句话——“Talk is cheap,show me the code”。直接上代码吧

  • Snake.h
#define KEEY_PRESS(vk) ((GetAsyncKeyState(vk)&0x1)?1:0)
#include <stdlib.h>
#include <stdio.h>
#include <windows.h>
#include <stdbool.h>
#include <locale.h>
#include <time.h>
#define WALL L'□'
#define FOOD L'★'
#define BODY L'●'
enum DIRECTION
{
	UP = 1,
	DOWN,
	LEFT,
	RIGHT
};
enum Game_Status
{
	OK,//正常运行
	END_NORMAL,//按ESC退出
	KILL_BY_WALL,
	KILL_BY_SELF
};
typedef struct SnakeNode
{
	int x;
	int y;
	struct SnakeNode* next;
}SnakeNode, * pSnakeNode;
typedef struct Snake
{
	pSnakeNode _pSnake;//指向贪吃蛇头的指针
	pSnakeNode _pFood;//指向食物的指针
	int _Score;//贪吃蛇累计得分
	int _FoodWeight;//一个食物的分数
	int _SleepTime;//每走一步的休息时间
	enum DIRECTION _Dir;//描述蛇的方向
	enum Status _Status;//游戏的状态:正常、退出、撞墙、吃到自己
}Snake, * pSnake;
void GameStart(pSnake ps);
void GameRun(pSnake ps);
void GameEnd(pSnake ps);
  • Snake.c
#include "Snake.h"
void SetPos(int x, int y)
{
	HANDLE handle = GetStdHandle(STD_OUTPUT_HANDLE);
	COORD pos = { x,y };
	SetConsoleCursorPosition(handle, pos);
}
void PrintHelpInfo()
{
	SetPos(64, 15);
	printf("1.不能撞墙,不能咬到自己");
	SetPos(64, 16);
	printf("2.使用  'W''S''A''D'分别控制蛇移动");
	SetPos(64, 17);
	printf("3.F3加速,F4减速");
	SetPos(64, 18);
	printf("4.ESC-退出, 空格-暂停游戏");

	SetPos(64, 20);
	printf("胡桃的苟@版权");
}
void WelComeToGame()
{
	//定位光标
	SetPos(40, 14);
	printf("欢迎来到胡桃的苟制作的贪吃蛇小游戏");
	SetPos(40, 25);
	system("pause");//pause是暂停
	system("cls");
	SetPos(20, 14);
	printf("使用 'W''S''A''D'分别控制蛇的移动, F3是加速,F4是减速");
	SetPos(40, 25);
	system("pause");
	system("cls");
}
void CreateMap()
{
	int i;
	for (i = 0; i <= 54; i += 2)
	{
		wprintf(L"%lc", WALL);
	}
	SetPos(0, 27);
	for (i = 0; i <= 54; i += 2)
	{
		wprintf(L"%lc", WALL);
	}
	for (i = 1; i <= 26; i++)
	{
		SetPos(0, i);
		wprintf(L"%lc", WALL);
		SetPos(54, i);
		wprintf(L"%lc", WALL);
	}
}
void InitSnake(pSnake ps)
{
	int i;
	pSnakeNode pcur=NULL;
	for (i = 0; i < 5; i++)
	{
		pcur = (pSnakeNode)malloc(sizeof(SnakeNode));
		pcur->x = 20 + 2 * i;
		pcur->y = 14;
		pcur->next = NULL;
		if (ps->_pSnake == NULL)
		{
			ps->_pSnake= pcur;
		}
		else
		{
			pcur->next = ps->_pSnake;
			ps->_pSnake = pcur;
		}
	}
	pSnakeNode cur = ps->_pSnake;
	while (cur)
	{
		SetPos(cur->x, cur->y);
		wprintf(L"%lc", BODY);
		cur = cur->next;
	}
	ps->_Status = OK;
	ps->_Score = 0;
	ps->_pFood = NULL;
	ps->_SleepTime = 200;
	ps->_FoodWeight = 10;
	ps->_Dir = RIGHT;
}
void CreateFood(pSnake ps)
{
	int x;
	int y;
again:
	do
	{
		x = rand() % 51 + 2;
		y = rand() % 26 + 1;
	} while (x % 2 != 0);
	pSnakeNode pcur = ps->_pSnake;
	while (pcur)
	{
		if (x == pcur->x && y == pcur->y)
		{
			goto again;
		}
		pcur = pcur->next;
	}
	pSnakeNode pFood = (pSnakeNode)malloc(sizeof(SnakeNode));
	if (pFood == NULL)
	{
		perror("CreatFood()::malloc()");
		return;
	}
	pFood->x = x;
	pFood->y = y;
	ps->_pFood = pFood;
	SetPos(x, y);
	wprintf(L"%lc", FOOD);
}

void GameStart(pSnake ps)
{
	//打印欢迎界面
	WelComeToGame();
	//创建地图
	CreateMap();
	//初始化贪食蛇
	InitSnake(ps);
	//创建食物
	CreateFood(ps);
}
void pause()
{
	while (1)
	{
		Sleep(1000);
		if(KEEY_PRESS(VK_SPACE))
		{
			break;
		}
	}
}
void EatFood(pSnake ps,pSnakeNode pNext)
{
	pNext->next = ps->_pSnake;
	ps->_pSnake = pNext;
	pSnakeNode pcur = ps->_pSnake;
	while (pcur)
	{
		SetPos(pcur->x, pcur->y);
		wprintf(L"%lc", BODY);
		pcur = pcur->next;
	}
	free(ps->_pFood);
	CreateFood(ps);
	ps->_Score += ps->_FoodWeight;

}
void EatNoFood(pSnake ps,pSnakeNode pNext)
{
	pNext->next = ps->_pSnake;
	ps->_pSnake = pNext;
	pSnakeNode pcur  = ps->_pSnake;
	while (pcur->next->next)
	{
		SetPos(pcur->x, pcur->y);
		wprintf(L"%lc", BODY);
		pcur = pcur->next;
	}
	SetPos(pcur->next->x, pcur->next->y);
	printf("  ");
	SetPos(pcur->x, pcur->y);
	wprintf(L"%lc", BODY);
	free(pcur->next);
	pcur->next = NULL;
}
void KILLBYSELF(pSnake ps)
{
	pSnakeNode pcur = ps->_pSnake->next;
	while (pcur)
	{	

		if (ps->_pSnake->x == pcur->x && ps->_pSnake->y == pcur->y)
		{
			ps->_Status = KILL_BY_SELF;
		}	
		pcur = pcur->next;
	}
}
void KILLBYWALL(pSnake ps)
{
	if (ps->_pSnake->y == 0 ||
		ps->_pSnake->x == 54 ||
		ps->_pSnake->x == 0 ||
		ps->_pSnake->y == 27)
		ps->_Status = KILL_BY_WALL;
}

void snakemove(pSnake ps)
{
	pSnakeNode pNext = (pSnakeNode)malloc(sizeof(SnakeNode));
	if (pNext == NULL)
	{
		perror("snakemove()::malloc()");
		return;
	}
	switch (ps->_Dir)
	{
	case UP:
		pNext->x = ps->_pSnake->x;
		pNext->y = ps->_pSnake->y -1;
		break;
	case DOWN:
		pNext->x = ps->_pSnake->x;
		pNext->y = ps->_pSnake->y +1;
		break;
	case LEFT:
		pNext->x = ps->_pSnake->x-2;
		pNext->y = ps->_pSnake->y;
		break; 
	case RIGHT:
		pNext->x = ps->_pSnake->x+2;
		pNext->y = ps->_pSnake->y;
		break;
	}
	pSnake pcur = ps;
	if (pNext->x==(pcur->_pFood)->x&&pNext->y==(pcur->_pFood)->y)
	{
		//下一步吃到食物
		EatFood(ps,pNext);
	}
	else if (pNext->x != (pcur->_pFood)->x || pNext->y != (pcur->_pFood)->y)
	{
		//下一步没吃到食物
		EatNoFood(ps,pNext);
	}
	KILLBYWALL(ps);
	KILLBYSELF(ps);

}
void Destroy(pSnake ps)
{
	pSnakeNode pcur = ps->_pSnake;
	while (pcur)
	{
		pSnakeNode next = pcur->next;
		free(pcur);
		pcur = NULL;
		pcur = next;
	}
	ps->_pSnake = NULL;
}
void GameRun(pSnake ps)
{
	PrintHelpInfo();
	do
	{
		SetPos(64, 9);
		printf("得分:%5d", ps->_Score);
		SetPos(64, 10);
		printf("当前每个食物的分数:%2d", ps->_FoodWeight);
		if (KEEY_PRESS(0x57) && ps->_Dir != DOWN)
		{
			ps->_Dir = UP;
		}
		if (KEEY_PRESS(0x53) && ps->_Dir != UP)
		{
			ps->_Dir = DOWN;
		}
		if (KEEY_PRESS(0x41) && ps->_Dir != RIGHT)
		{
			ps->_Dir = LEFT;
		}
		if (KEEY_PRESS(0x44) && ps->_Dir != LEFT)
		{
			ps->_Dir = RIGHT;
		}
		if (KEEY_PRESS(VK_SPACE))
		{
			//暂停
			pause();
		}
		if (KEEY_PRESS(VK_ESCAPE))
		{
			ps->_Status = END_NORMAL;
			break;
		}
		if (KEEY_PRESS(VK_F3))
		{
			if (ps->_SleepTime > 80)
			{
				ps->_SleepTime -=30;
				ps->_FoodWeight += 2;
			}
		}
		if (KEEY_PRESS(VK_F4))
		{
			if (ps->_SleepTime<320)
			{
				ps->_SleepTime += 30;
				ps->_FoodWeight -= 2;
			 }
		}
		Sleep(ps->_SleepTime);
		snakemove(ps);
	} while (ps->_Status == OK);
}
void GameEnd(pSnake ps)
{
	SetPos(25, 14);
	switch(ps->_Status)
	{
	case END_NORMAL:
		printf("你已退出游戏...\n");
		break;
	case KILL_BY_SELF:
		printf("你已自杀...\n");
		break;
	case KILL_BY_WALL:
		printf("你撞墙死了...\n");
		break;
	}
	Destroy(ps);
}
  • test.c
#include "Snake.h"
void test()
{
	int ch = 0;
	do
	{
		Snake snake = { 0 };//创建了贪吃蛇
		//1. 游戏开始 - 初始化游戏
		GameStart(&snake);
		//2. 游戏运行 - 游戏的正常运行过程
		GameRun(&snake);
		//3. 游戏结束 - 游戏善后(释放资源)
		GameEnd(&snake);
		SetPos(25,13);
		printf("再来一局吗?(Y/N):");
		ch = getchar();
		system("cls");
		getchar();//消除\n
	} while (ch == 'Y' || ch == 'y');
	SetPos(0, 27);
}
int main()
{
	//控制台窗口的设置
	//其中贪吃蛇游戏界面宽28,高28
	system("title 贪吃蛇");
	system("mode con cols=100 lines=40");
	//本地初始化
	setlocale(LC_ALL, "");
	//设置随机数种子
	srand((unsigned int)time(NULL));
	//获取终端设备句柄
	HANDLE handle = GetStdHandle(STD_OUTPUT_HANDLE);
	//获取光标信号,并隐藏光标
	CONSOLE_CURSOR_INFO cursor_info;
	GetConsoleCursorInfo(handle, &cursor_info);
	cursor_info.bVisible = false;
	SetConsoleCursorInfo(handle, &cursor_info);
	//开始测试
	test();
}

好了以上就是我对于”c语言实现贪吃蛇小游戏”的一些理解了,喜欢的话可以点点赞哦。

  • 37
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值