鱼C论坛

 找回密码
 立即注册
楼主: crymin

[技术交流] C语言贪吃蛇代码

  [复制链接]
发表于 2021-9-30 20:04:44 From FishC Mobile | 显示全部楼层
学习了,看了,,
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2021-10-1 18:18:27 | 显示全部楼层
本帖最后由 王义忠 于 2021-10-1 18:22 编辑

照猫画虎打了一遍,但是还是不成功,抄都抄不对 加油
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2021-10-1 19:40:12 | 显示全部楼层
资瓷
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2021-10-1 23:00:42 | 显示全部楼层
看下
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2021-10-5 20:56:26 | 显示全部楼层
学习
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2021-10-6 11:52:39 | 显示全部楼层
1
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2021-10-6 12:06:11 | 显示全部楼层
看看
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2021-10-6 12:21:53 | 显示全部楼层
666
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2021-10-6 12:24:08 | 显示全部楼层
看看,学习中
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2021-10-6 13:56:53 | 显示全部楼层
受益很多,在我的编译环境下面,做了一点修改(我的编译环境可能与作者的不同)可以运行。不错。
#include <stdio.h>
#include <time.h>
#include <windows.h>
#include <stdlib.h>
#include <conio.h>
#pragma warning(disable:4996)

#define INFO_X 100  //提示信息区横坐标
#define WIDE 50     //游戏界面宽度
#define HIGH 36     //游戏界面高度
#define LEVELUP 5   //升级所需的食物个数

/* 定义全局变量 */
unsigned char key;
int i, j, k, end[2];                //i,j,k为循环变量,end数组用来做蛇尾坐标的中间变量


/* 蛇身结构 */
struct Snakes
{
    int X[100];     //蛇身的横坐标
    int Y[100];     //蛇身的纵坐标
    int length;     //蛇的长度
    int speed;      //蛇移动速度
    int count;      //蛇吃到食物个数
};
/* 食物结构 */
struct Food
{
    int X;          //食物横坐标
    int Y;          //食物纵坐标
};

struct Snakes s, * snake = &s;       //定义蛇的结构体指针并指向蛇的结构体
struct Food f, * food = &f;          //定义食物结构体指针并指向食物结构体
/* 设置控制台标题和大小 */
void SetTitle()
{
    //设置控制台窗口大小
    system("mode con cols=150 lines=40");
    //设置控制台标题
    SetConsoleTitle("贪吃蛇");
}
/* 设置光标位置 */
void SetPos(int x, int y)
{
    HANDLE winhandle;
    COORD pos = { x,y };
    winhandle = GetStdHandle(STD_OUTPUT_HANDLE);
    SetConsoleCursorPosition(winhandle, pos);
}
/* 设置控制台颜色 */
void Setcolor(int forcolor, int bakcolor)
{
    /*
    0=黑色,   8=灰色,
    1=蓝色,   9=淡蓝色,
    2=绿色,   A=淡绿色,
    3=湖蓝色, B=淡浅绿色,
    4=红色,   C=淡红色,
    5=紫色,   D=淡紫色,
    6=黄色,   E=淡黄色,
    7=白色,   F=亮白色
    */
    HANDLE winhandle;
    winhandle = GetStdHandle(STD_OUTPUT_HANDLE);
    SetConsoleTextAttribute(winhandle, forcolor + bakcolor * 0x10);
}
/* 清楚单行显示 */
void Cleanlin(int x, int y)
{
    SetPos(x, y);
    for (i = 0; i < 50; i++)
    {
        printf(" ");
    }
}
/* 设置游戏界面 */
void Table()
{
    for (i = 0; i < HIGH; i++)
    {
        if (i == 0 || i == HIGH - 1)
        {
            for (k = 0; k < WIDE * 2 - 1; k += 2)
            {
                SetPos(k, i);
                printf("■");
            }
            continue;
        }
        else
        {
            for (j = 0; j < WIDE * 2 - 1; j += 2)
            {
                if (j == 0 || j == WIDE * 2 - 2)
                {
                    SetPos(j, i);
                    printf("■");
                }
            }
        }
    }
}
/* 显示提示和菜单 */
void ShowMenu()
{
    SetPos(INFO_X + 17, 1);
    Setcolor(9, 0);
    printf("欢迎来到贪吃蛇!");
    SetPos(INFO_X + 17, 5);
    printf("Esc  退出游戏");
    SetPos(INFO_X + 17, 7);
    printf("空格 暂停游戏");
    SetPos(INFO_X + 17, 9);
    printf("↑↓←→ 控制蛇头方向");
    SetPos(INFO_X + 17, 11);
    printf("长按方向键加速");
    SetPos(INFO_X + 17, 15);
    printf("游戏得分:%d", snake->count * 100);
    SetPos(INFO_X + 17, 17);
    printf("当前级别:%d", snake->count / LEVELUP + 1);
    SetPos(INFO_X + 17, 19);
    printf("当前速度:%d", snake->speed);
    SetPos(INFO_X + 17, 21);
    printf("吃到食物:%d", snake->count);
    SetPos(INFO_X + 17, 23);
    printf("食物坐标:%-2d,%-2d", food->X, food->Y);
}
/* 初始化蛇身 */
void init_snake()
{
    snake->X[0] = WIDE;                   //初始化蛇的横坐标
    snake->Y[0] = HIGH / 2;                 //初始化蛇的竖坐标
    end[0] = snake->X;                    //记住蛇尾横坐标
    end[1] = snake->Y;                    //记住蛇尾纵坐标
    snake->speed = 300;                 //初始化蛇的速度为300ms
    snake->length = 3;                    //初始化蛇的长度为3节
    snake->count = 0;                     //初始化蛇吃的个数为0
    for (i = 1; i < snake->length; i++)
    {
        /* 依次得到蛇身、蛇头的坐标 */
        snake->X[i] = snake->X[i - 1] + 2;
        snake->Y[i] = snake->Y[i - 1];
    }
}
/* 移动蛇身 */
void move_snake()
{
    SetPos(snake->X[0], snake->Y[0]);
    printf("  ");               /* 清除蛇尾*/
    for (i = 1; i < snake->length; i++)
    {/* 后一节的坐标依次取代前一节的坐标 */
        snake->X[i - 1] = snake->X[i];
        snake->Y[i - 1] = snake->Y[i];
    }
}
/* 显示蛇身 */
void print_snake()
{
    for (i = 0; i < snake->length; i++)
    {
        SetPos(snake->X[i], snake->Y[i]);
        if (i == 0)
        {
            printf("○");    //打印蛇尾
        }
        else if (i == snake->length - 1)
        {
            printf("¤");    //打印蛇头
        }
        else
        {
            printf("⊙");    //打印蛇身
        }
    }
}
/* 产生食物 */
void get_food()
{
    srand((unsigned)time(NULL));
    while (1)
    {
        food->X = ((rand() % (WIDE - 3)) + 1) * 2;
        food->Y = (rand() % (HIGH - 2)) + 1;
        for (i = 0; i < snake->length; i++)
        {
            if (food->X == snake->X[i] && food->Y == snake->Y[i])
            {
                break;
            }
        }
        if (i == snake->length)
        {
            SetPos(food->X, food->Y);
            Setcolor(10, 0);
            printf("⊙");
            Setcolor(9, 0);
            break;
        }
    }
}
/* 吃食物 */
void eat_food()
{
    if (snake->X[snake->length - 1] == food->X && snake->Y[snake->length - 1] == food->Y)
    {/*如果蛇头坐标和食物坐标相同,吃掉食物,身长加1。*/
        snake->length++;
        for (i = snake->length - 1; i > 0; i--)
        {/* 蛇后节坐标依次赋值给蛇前一节的坐标,依次得到蛇身及蛇头的坐标 */

            snake->X[i] = snake->X[i - 1];
            snake->Y[i] = snake->Y[i - 1];
        }
        snake->X[0] = end[0];
        snake->Y[0] = end[1];
        get_food();
        snake->count++;
        if (snake->count % LEVELUP == 0)
        {/* 当蛇吃LEVELUP个食物时,速度加快20毫秒并且升一级 */
            snake->speed -= 20;
        }
    }
}
/* 穿墙 */
void through_wall()
{   /* 当蛇碰到移动方向的边界时,蛇身穿过边界从相对的另一边出现。*/
    if (key == 72 && snake->Y[snake->length - 1] == 0)//上键
    {
        snake->Y[snake->length - 1] = HIGH - 2;
    }
    if (key == 77 && snake->X[snake->length - 1] == WIDE * 2 - 2)//右键
    {
        snake->X[snake->length - 1] = 2;
    }
    if (key == 80 && snake->Y[snake->length - 1] == HIGH - 1)//下键
    {
        snake->Y[snake->length - 1] = 1;
    }
    if (key == 75 && snake->X[snake->length - 1] == 0)//左键
    {
        snake->X[snake->length - 1] = (WIDE - 2) * 2;
    }
}

void GameOver()
{
    system("cls");
    SetPos(WIDE, HIGH / 2);
    printf("游戏结束!");
    ShowMenu();
    SetPos(0, HIGH);
    exit(0);
    getch();
}
/* 判断蛇的死亡 */
void die()
{
    for (i = 0; i < snake->length - 1; i++)
    {   /* 当蛇头碰到蛇身,蛇死亡。 */
        if (snake->X[snake->length - 1] == snake->X[i] && snake->Y[snake->length - 1] == snake->Y[i])
        {
            GameOver();
        }
    }
}
/* 得到用户输入 */
void GetKey()
{
    switch (key)
    {
    case 27://Esc键--结束游戏
    {
        GameOver();
        break;
    }
    case 32://空格键--暂停游戏
    {
        SetPos(INFO_X + 13, HIGH - 5);
        Setcolor(5, 0);
        Sleep(500);
        printf("游戏暂停,按方向键继续!");
        Setcolor(9, 0);
        SetPos(0, HIGH);
        break;
    }
    case 72://上键
    {
        move_snake();
        snake->Y[snake->length - 1] -= 1;
        break;
    }
    case 77://右键
    {
        move_snake();
        snake->X[snake->length - 1] += 2;
        break;
    }
    case 80://下键
    {
        move_snake();
        snake->Y[snake->length - 1] += 1;
        break;
    }
    case 75://左键
    {
        move_snake();
        snake->X[snake->length - 1] -= 2;
        break;
    }
    }
}
/* 开始游戏 */
void GameStar()
{
    key = 77;                 //初始化蛇向右移动
    SetTitle();             //设置控制台标题和大小
    Setcolor(4, 0);
    Table();                //初始化游戏界面
    init_snake();           //初始化蛇身
    get_food();             //初始化第一个食物
    while (1)
    {
        Cleanlin(INFO_X, HIGH - 5);
        ShowMenu();
        end[0] = snake->X[0];
        end[1] = snake->Y[0];
        j = 0;
        if (kbhit())
        {/* 判断是否按下键盘,如果按下,ch接收键盘输入 */
            key = getch();
            if (kbhit())
            {/* 如果长按键盘,则加速 */
                Sleep(20);
                j = 1;
            }
        }
        GetKey();
        through_wall();
        eat_food();
        print_snake();
        die();
        if (j == 0)
        {
            Sleep(snake->speed);        //延迟时间
        }
        else
        {
            Sleep(10);
        }
    }
}
/* 游戏结束 */

int main()
{
    GameStar();
    return 0;
}
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2021-10-6 14:01:33 | 显示全部楼层

受益很多,在我的编译环境下面,做了一点修改(我的编译环境可能与作者的不同)可以运行。不错。
#include <stdio.h>
#include <time.h>
#include <windows.h>
#include <stdlib.h>
#include <conio.h>
#pragma warning(disable:4996)//在某些编译环境中,以下用到的一些函数可能会报不安全,比如:getch,kbhit 所以这里要加上这个定义可以
/*某一些函数的先后执行顺序做了调整*/
#define INFO_X 100  //提示信息区横坐标
#define WIDE 50     //游戏界面宽度
#define HIGH 36     //游戏界面高度
#define LEVELUP 5   //升级所需的食物个数

/* 定义全局变量 */
unsigned char key;
int i, j, k, end[2];                //i,j,k为循环变量,end数组用来做蛇尾坐标的中间变量


/* 蛇身结构 */
struct Snakes
{
    int X[100];     //蛇身的横坐标
    int Y[100];     //蛇身的纵坐标
    int length;     //蛇的长度
    int speed;      //蛇移动速度
    int count;      //蛇吃到食物个数
};
/* 食物结构 */
struct Food
{
    int X;          //食物横坐标
    int Y;          //食物纵坐标
};

struct Snakes s, * snake = &s;       //定义蛇的结构体指针并指向蛇的结构体
struct Food f, * food = &f;          //定义食物结构体指针并指向食物结构体
/* 设置控制台标题和大小 */
void SetTitle()
{
    //设置控制台窗口大小
    system("mode con cols=150 lines=40");
    //设置控制台标题
    SetConsoleTitle("贪吃蛇");
}
/* 设置光标位置 */
void SetPos(int x, int y)
{
    HANDLE winhandle;
    COORD pos = { x,y };
    winhandle = GetStdHandle(STD_OUTPUT_HANDLE);
    SetConsoleCursorPosition(winhandle, pos);
}
/* 设置控制台颜色 */
void Setcolor(int forcolor, int bakcolor)
{
    /*
    0=黑色,   8=灰色,
    1=蓝色,   9=淡蓝色,
    2=绿色,   A=淡绿色,
    3=湖蓝色, B=淡浅绿色,
    4=红色,   C=淡红色,
    5=紫色,   D=淡紫色,
    6=黄色,   E=淡黄色,
    7=白色,   F=亮白色
    */
    HANDLE winhandle;
    winhandle = GetStdHandle(STD_OUTPUT_HANDLE);
    SetConsoleTextAttribute(winhandle, forcolor + bakcolor * 0x10);
}
/* 清楚单行显示 */
void Cleanlin(int x, int y)
{
    SetPos(x, y);
    for (i = 0; i < 50; i++)
    {
        printf(" ");
    }
}
/* 设置游戏界面 */
void Table()
{
    for (i = 0; i < HIGH; i++)
    {
        if (i == 0 || i == HIGH - 1)
        {
            for (k = 0; k < WIDE * 2 - 1; k += 2)
            {
                SetPos(k, i);
                printf("■");
            }
            continue;
        }
        else
        {
            for (j = 0; j < WIDE * 2 - 1; j += 2)
            {
                if (j == 0 || j == WIDE * 2 - 2)
                {
                    SetPos(j, i);
                    printf("■");
                }
            }
        }
    }
}
/* 显示提示和菜单 */
void ShowMenu()
{
    SetPos(INFO_X + 17, 1);
    Setcolor(9, 0);
    printf("欢迎来到贪吃蛇!");
    SetPos(INFO_X + 17, 5);
    printf("Esc  退出游戏");
    SetPos(INFO_X + 17, 7);
    printf("空格 暂停游戏");
    SetPos(INFO_X + 17, 9);
    printf("↑↓←→ 控制蛇头方向");
    SetPos(INFO_X + 17, 11);
    printf("长按方向键加速");
    SetPos(INFO_X + 17, 15);
    printf("游戏得分:%d", snake->count * 100);
    SetPos(INFO_X + 17, 17);
    printf("当前级别:%d", snake->count / LEVELUP + 1);
    SetPos(INFO_X + 17, 19);
    printf("当前速度:%d", snake->speed);
    SetPos(INFO_X + 17, 21);
    printf("吃到食物:%d", snake->count);
    SetPos(INFO_X + 17, 23);
    printf("食物坐标:%-2d,%-2d", food->X, food->Y);
}
/* 初始化蛇身 */
void init_snake()
{
    snake->X[0] = WIDE;                   //初始化蛇的横坐标
    snake->Y[0] = HIGH / 2;                 //初始化蛇的竖坐标
    end[0] = snake->X;                    //记住蛇尾横坐标
    end[1] = snake->Y;                    //记住蛇尾纵坐标
    snake->speed = 300;                 //初始化蛇的速度为300ms
    snake->length = 3;                    //初始化蛇的长度为3节
    snake->count = 0;                     //初始化蛇吃的个数为0
    for (i = 1; i < snake->length; i++)
    {
        /* 依次得到蛇身、蛇头的坐标 */
        snake->X[i] = snake->X[i - 1] + 2;
        snake->Y[i] = snake->Y[i - 1];
    }
}
/* 移动蛇身 */
void move_snake()
{
    SetPos(snake->X[0], snake->Y[0]);
    printf("  ");               /* 清除蛇尾*/
    for (i = 1; i < snake->length; i++)
    {/* 后一节的坐标依次取代前一节的坐标 */
        snake->X[i - 1] = snake->X[i];
        snake->Y[i - 1] = snake->Y[i];
    }
}
/* 显示蛇身 */
void print_snake()
{
    for (i = 0; i < snake->length; i++)
    {
        SetPos(snake->X[i], snake->Y[i]);
        if (i == 0)
        {
            printf("○");    //打印蛇尾
        }
        else if (i == snake->length - 1)
        {
            printf("¤");    //打印蛇头
        }
        else
        {
            printf("⊙");    //打印蛇身
        }
    }
}
/* 产生食物 */
void get_food()
{
    srand((unsigned)time(NULL));
    while (1)
    {
        food->X = ((rand() % (WIDE - 3)) + 1) * 2;
        food->Y = (rand() % (HIGH - 2)) + 1;
        for (i = 0; i < snake->length; i++)
        {
            if (food->X == snake->X[i] && food->Y == snake->Y[i])
            {
                break;
            }
        }
        if (i == snake->length)
        {
            SetPos(food->X, food->Y);
            Setcolor(10, 0);
            printf("⊙");
            Setcolor(9, 0);
            break;
        }
    }
}
/* 吃食物 */
void eat_food()
{
    if (snake->X[snake->length - 1] == food->X && snake->Y[snake->length - 1] == food->Y)
    {/*如果蛇头坐标和食物坐标相同,吃掉食物,身长加1。*/
        snake->length++;
        for (i = snake->length - 1; i > 0; i--)
        {/* 蛇后节坐标依次赋值给蛇前一节的坐标,依次得到蛇身及蛇头的坐标 */

            snake->X[i] = snake->X[i - 1];
            snake->Y[i] = snake->Y[i - 1];
        }
        snake->X[0] = end[0];
        snake->Y[0] = end[1];
        get_food();
        snake->count++;
        if (snake->count % LEVELUP == 0)
        {/* 当蛇吃LEVELUP个食物时,速度加快20毫秒并且升一级 */
            snake->speed -= 20;
        }
    }
}
/* 穿墙 */
void through_wall()
{   /* 当蛇碰到移动方向的边界时,蛇身穿过边界从相对的另一边出现。*/
    if (key == 72 && snake->Y[snake->length - 1] == 0)//上键
    {
        snake->Y[snake->length - 1] = HIGH - 2;
    }
    if (key == 77 && snake->X[snake->length - 1] == WIDE * 2 - 2)//右键
    {
        snake->X[snake->length - 1] = 2;
    }
    if (key == 80 && snake->Y[snake->length - 1] == HIGH - 1)//下键
    {
        snake->Y[snake->length - 1] = 1;
    }
    if (key == 75 && snake->X[snake->length - 1] == 0)//左键
    {
        snake->X[snake->length - 1] = (WIDE - 2) * 2;
    }
}

void GameOver()
{
    system("cls");
    SetPos(WIDE, HIGH / 2);
    printf("游戏结束!");
    ShowMenu();
    SetPos(0, HIGH);
    exit(0);
    getch();
}
/* 判断蛇的死亡 */
void die()
{
    for (i = 0; i < snake->length - 1; i++)
    {   /* 当蛇头碰到蛇身,蛇死亡。 */
        if (snake->X[snake->length - 1] == snake->X[i] && snake->Y[snake->length - 1] == snake->Y[i])
        {
            GameOver();
        }
    }
}
/* 得到用户输入 */
void GetKey()
{
    switch (key)
    {
    case 27://Esc键--结束游戏
    {
        GameOver();
        break;
    }
    case 32://空格键--暂停游戏
    {
        SetPos(INFO_X + 13, HIGH - 5);
        Setcolor(5, 0);
        Sleep(500);
        printf("游戏暂停,按方向键继续!");
        Setcolor(9, 0);
        SetPos(0, HIGH);
        break;
    }
    case 72://上键
    {
        move_snake();
        snake->Y[snake->length - 1] -= 1;
        break;
    }
    case 77://右键
    {
        move_snake();
        snake->X[snake->length - 1] += 2;
        break;
    }
    case 80://下键
    {
        move_snake();
        snake->Y[snake->length - 1] += 1;
        break;
    }
    case 75://左键
    {
        move_snake();
        snake->X[snake->length - 1] -= 2;
        break;
    }
    }
}
/* 开始游戏 */
void GameStar()
{
    key = 77;                 //初始化蛇向右移动
    SetTitle();             //设置控制台标题和大小
    Setcolor(4, 0);
    Table();                //初始化游戏界面
    init_snake();           //初始化蛇身
    get_food();             //初始化第一个食物
    while (1)
    {
        Cleanlin(INFO_X, HIGH - 5);
        ShowMenu();
        end[0] = snake->X[0];
        end[1] = snake->Y[0];
        j = 0;
        if (kbhit())
        {/* 判断是否按下键盘,如果按下,ch接收键盘输入 */
            key = getch();
            if (kbhit())
            {/* 如果长按键盘,则加速 */
                Sleep(20);
                j = 1;
            }
        }
        GetKey();
        through_wall();
        eat_food();
        print_snake();
        die();
        if (j == 0)
        {
            Sleep(snake->speed);        //延迟时间
        }
        else
        {
            Sleep(10);
        }
    }
}
/* 游戏结束 */

int main()
{
    GameStar();
    return 0;
}
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2021-10-6 16:34:01 | 显示全部楼层
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2021-10-6 18:13:43 | 显示全部楼层
6666
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2021-10-6 18:38:47 | 显示全部楼层
6
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2021-10-6 21:27:05 | 显示全部楼层

想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2021-10-7 19:20:38 From FishC Mobile | 显示全部楼层
真想知道
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2021-10-7 19:44:37 | 显示全部楼层
谢谢大佬
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2021-10-13 15:41:18 | 显示全部楼层
666
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2021-10-13 16:20:27 | 显示全部楼层
6666
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2021-10-13 19:15:54 | 显示全部楼层
666
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|鱼C工作室 ( 粤ICP备18085999号-1 | 粤公网安备 44051102000585号)

GMT+8, 2024-7-13 06:38

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表