当前位置:   article > 正文

OrangePi PC 玩Linux主线内核踩坑之旅(五)之简易版的贪吃蛇_orange pi make应用

orange pi make应用

可不可以用香橙派来玩游戏呢?当然可以,今天用它来玩贪吃蛇!

一、终端版的贪吃蛇

在踩坑之旅(四)中,我们介绍了设置声卡的两款工具alsamixer和amixer,很显然alsamixer这种图形化的界面更加人性化,更适合人机互动,那这个界面是如何实现的呢?亲自动手完成变身MP3播放器的同学会发现,alsamixer用到了一个依赖包ncurses。Ncurses是一个能提供功能键定义(快捷键),屏幕绘制以及基于文本终端的图形互动功能的动态库[1]。Ncurses可以:

  • 只要您喜欢,您可以使用整个屏幕
  • 创建和管理一个窗口
  • 使用8种不同的彩色
  • 为您的程序提供鼠标支持
  • 使用键盘上的功能键

有心的同学可能会记得,在踩坑之旅(一)中make menuconfig也用到了ncurses库,没错,就是我们看到的那个配置界面。事实上,make menuconfig最终修改了buildroot-2020.11目录下的.config文件,这个文件就是个文本文档,可以手工修改,但还是用make menuconfig更直观。

由此看来,Ncurses可以实现终端界面下的图形互动,虽然略显简陋。本文介绍的贪吃蛇就是Ncurses的一个典型应用。当然,这里不是要讲贪吃蛇的具体算法实现,我们直接使用他人开源的代码。下载地址:

https://codeload.github.com/CoinsJack/my_snake_game/zip/master

将代码下载到桌面上。对源代码感兴趣的同学可以访问作者的博客:

https://www.cnblogs.com/litran/p/10640893.html

将代码包解压到桌面,此时可以看到目录中有个可执行文件hungry_snake,这个文件是电脑端运行的文件,你可以双击运行体验一下。我们需要重新编译可在香橙派运行的可执行文件,也就是传说中的交叉编译。在终端进入该目录,输入如下命令对代码进行编译

dpmicro@dpmicro-PC:~/Desktop/my_snake_game-master$ arm-linux-gnueabihf-gcc -o snake main.c snake.c -L ../buildroot-2020.11/output/target/usr/lib -lncurses -I ../buildroot-2020.11/output/host/arm-buildroot-linux-gnueabihf/sysroot/usr/include/

将生成的snake文件传送到香橙派上

  1. dpmicro@dpmicro-PC:~/Desktop/my_snake_game-master$ scp snake root@192.168.1.10:/root
  2. root@192.168.1.10's password:
  3. snake 100% 23KB 681.9KB/s 00:00

在香橙派的SSH命令中输入

  1. # ls
  2. snake
  3. # ./snake

按下字母e键开始游戏吧。

画面颜色不好看?我们来改代码,很简单。打开main.c,将第25行至32行修改如下

  1. init_pair(1,COLOR_GREEN,COLOR_BLACK);//前景色,背景色
  2. init_pair(2,COLOR_BLACK,COLOR_WHITE);
  3. attron(COLOR_PAIR(1));//增加一行,其余不变
  4. print_snake_logo(stdscr);
  5. mvprintw(LINES-1,COLS-20,"Producted by Jack");

看看效果

画面颜色太单调?继续改main.c

  1. #include <unistd.h>
  2. #include <stdlib.h>
  3. #include "snake.h"
  4. #include <ncurses.h>
  5. #include "wellcome.h"
  6. #include <pthread.h>
  7. int ch;
  8. int GAMEOVER;
  9. int main()
  10. {
  11. initscr();
  12. start_color();
  13. keypad(stdscr,TRUE);
  14. curs_set(0);
  15. noecho();
  16. halfdelay(4);
  17. init_pair(1, COLOR_GREEN,COLOR_BLACK);
  18. init_pair(2, COLOR_BLACK,COLOR_WHITE);
  19. //增加7种前景色,加上背景色黑色,一共支持8种颜色
  20. init_pair(4, COLOR_RED, COLOR_BLACK);
  21. init_pair(5, COLOR_GREEN, COLOR_BLACK);
  22. init_pair(6, COLOR_YELLOW,COLOR_BLACK);
  23. init_pair(7, COLOR_BLUE, COLOR_BLACK);
  24. init_pair(8, COLOR_MAGENTA,COLOR_BLACK);
  25. init_pair(9, COLOR_CYAN, COLOR_BLACK);
  26. init_pair(10, COLOR_WHITE, COLOR_BLACK);
  27. attron(COLOR_PAIR(1));
  28. print_snake_logo(stdscr);
  29. mvprintw(LINES-1,COLS-20,"Producted by Jack");
  30. mvprintw(LINES-4,(COLS-21)/2,"|-> START");
  31. printw(" (? for help)");
  32. refresh();
  33. int choice;
  34. char goout = 0;
  35. while (!goout)
  36. {
  37. switch (choice = getch() )
  38. {
  39. case 'q':
  40. endwin();
  41. return 0;
  42. case 'e':
  43. goout = 1;
  44. break;
  45. }
  46. }
  47. Psnake jack = init_snake();
  48. init_show_snake(jack);
  49. ch = mvgetch(LINES-1,0);
  50. srand((unsigned)time(0));
  51. for (int i = 0; i<10; i++)
  52. putfood(jack);
  53. refresh();
  54. int noout = 1;
  55. int c = 0;
  56. int i=4;//颜色循环
  57. while(noout)
  58. {
  59. attron(COLOR_PAIR(i));//使用i指向的颜色
  60. ch = getch();
  61. switch (ch)
  62. {
  63. case KEY_RIGHT:
  64. c = snake_go_right(jack);
  65. if ( c == -1)
  66. {
  67. noout = 0;
  68. GAMEOVER = 1;
  69. break;
  70. }
  71. continue;
  72. case KEY_DOWN :
  73. c = snake_go_down(jack);
  74. if ( c == -1)
  75. {
  76. noout = 0;
  77. GAMEOVER = 1;
  78. break;
  79. }
  80. continue;
  81. case KEY_LEFT:
  82. c = snake_go_left(jack);
  83. if ( c == -1)
  84. {
  85. noout = 0;
  86. GAMEOVER = 1;
  87. break;
  88. }
  89. continue;
  90. case KEY_UP:
  91. c = snake_go_up(jack);
  92. if ( c == -1)
  93. {
  94. noout = 0;
  95. GAMEOVER = 1;
  96. break;
  97. }
  98. continue;
  99. case 'q':
  100. game_over(jack);
  101. endwin();
  102. return 0;
  103. }
  104. if (jack->righting)
  105. {
  106. c = snake_go_right(jack);
  107. if (c == -1)
  108. {
  109. GAMEOVER = 1;
  110. break;
  111. }
  112. }
  113. else if (jack->lefting)
  114. {
  115. c = snake_go_left(jack);
  116. if (c == -1)
  117. {
  118. GAMEOVER = 1;
  119. break;
  120. }
  121. }
  122. else if(jack->uping)
  123. {
  124. c = snake_go_up(jack);
  125. if (c == -1)
  126. {
  127. GAMEOVER = 1;
  128. break;
  129. }
  130. }
  131. else if(jack->downing)
  132. {
  133. c = snake_go_down(jack);
  134. if (c == -1)
  135. {
  136. GAMEOVER = 1;
  137. break;
  138. }
  139. }
  140. if (food_num < 30)
  141. putfood(jack);
  142. mvprintw(LINES-1,2,"-- socre %d --",jack->length);
  143. attroff(COLOR_PAIR(i));
  144. refresh();
  145. i++;
  146. if(i==11)i=4;//颜色循环结束
  147. }
  148. if(GAMEOVER)
  149. game_over(jack);
  150. refresh();
  151. endwin();
  152. return 0;
  153. }

漂亮多了吧?好似满天繁星

二、接个显示器玩贪吃蛇

如此好玩的游戏只能借助SSH才能使用实在是不舒服,我们来给香橙派接个显示器。香橙派自带HDMI和AV模拟输出,而我只有VGA接口的显示器,所以使用HDMI转VGA再连接显示器。开机上电,uboot启动内核后好像没有画面了,只剩一个光标在左上角闪烁,这是怎么回事?刚通电的时候,可以看到显示器上有uboot的启动信息,说明是可以通过HDMI输出画面的,问题出在哪里呢?回到SSH,查看uboot传递给内核的启动参数

  1. # cat /proc/cmdline
  2. console=ttyS0,115200 earlyprintk root=/dev/mmcblk0p2 rootwait

可以看到,console参数只配置了串口,也就是说内核启动、初始化的信息只会输出到串口。这个配置在哪里修改呢?打开buildroot-2020.11/board/orangepi/orangepi-pc目录下的boot.cmd文件可以看到,这些参数均属于环境变量bootargs

  1. setenv fdt_high ffffffff
  2. setenv bootargs console=ttyS0,115200 earlyprintk root=/dev/mmcblk0p2 rootwait
  3. fatload mmc 0 $kernel_addr_r zImage
  4. fatload mmc 0 $fdt_addr_r sun8i-h3-orangepi-pc.dtb
  5. bootz $kernel_addr_r - $fdt_addr_r

如果我们将第三行修改为

setenv bootargs console=ttyS0,115200 console=tty0 earlyprintk root=/dev/mmcblk0p2 rootwait

然后回到buildroot-2020.11目录下,先make再烧录镜像,你会发现,完全没有效果,哈哈。这是因为uboot实际读取的是boot.scr,然而make命令并没有生成新的文件。我们来手工生成一下,终端打开buildroot-2020.11/board/orangepi/orangepi-pc目录

  1. dpmicro@dpmicro-PC:~/Desktop/buildroot-2020.11/board/orangepi/orangepi-pc$ ../../../output/build/uboot-2020.07/tools/mkimage -A arm -O linux -T script -C none -a 0 -e 0 -n "OrangePi Boot Script" -d boot.cmd boot.scr
  2. Image Name: OrangePi Boot Script
  3. Created: Fri Jan 1 18:00:47 2021
  4. Image Type: ARM Linux Script (uncompressed)
  5. Data Size: 249 Bytes = 0.24 KiB = 0.00 MiB
  6. Load Address: 00000000
  7. Entry Point: 00000000
  8. Contents:
  9. Image 0: 241 Bytes = 0.24 KiB = 0.00 MiB
  10. dpmicro@dpmicro-PC:~/Desktop/buildroot-2020.11/board/orangepi/orangepi-pc$ ls
  11. boot.cmd boot.scr genimage.cfg linux.fragment readme.txt

将刚刚生成的boot.scr传送到香橙派TF卡的第一分区,也就是那个FAT32格式的分区。我们先将该分区进行挂载,然后用scp传过去

  1. # mount /dev/mmcblk0p1 /mnt/
  2. # ls /mnt/
  3. boot.scr sun8i-h3-orangepi-pc.dtb zImage
  1. dpmicro@dpmicro-PC:~/Desktop/buildroot-2020.11/board/orangepi/orangepi-pc$ scp boot.scr root@192.168.1.10:/mnt
  2. root@192.168.1.10's password:
  3. boot.scr 100% 313 55.3KB/s 00:00

好,现在重启香橙派。可以看到,在屏幕上也显示了内核启动的各项信息。但是,启动完并不能登陆啊,纯粹只是显示内核打印的信息而已。。。

突然回想起踩坑之旅(一)当中的一个配置

这个配置项用于配置系统启动后终端模式的启动方式,当然啦,这里配置的是串口,那这个配置实际修改了哪个文件呢?是/etc/inittab,我们来查看一下

  1. # /etc/inittab
  2. #
  3. # Copyright (C) 2001 Erik Andersen <andersen@codepoet.org>
  4. #
  5. # Note: BusyBox init doesn't support runlevels. The runlevels field is
  6. # completely ignored by BusyBox init. If you want runlevels, use
  7. # sysvinit.
  8. #
  9. # Format for each entry: <id>:<runlevels>:<action>:<process>
  10. #
  11. # id == tty to run on, or empty for /dev/console
  12. # runlevels == ignored
  13. # action == one of sysinit, respawn, askfirst, wait, and once
  14. # process == program to run
  15. # Startup the system
  16. ::sysinit:/bin/mount -t proc proc /proc
  17. ::sysinit:/bin/mount -o remount,rw /
  18. ::sysinit:/bin/mkdir -p /dev/pts /dev/shm
  19. ::sysinit:/bin/mount -a
  20. ::sysinit:/sbin/swapon -a
  21. null::sysinit:/bin/ln -sf /proc/self/fd /dev/fd
  22. null::sysinit:/bin/ln -sf /proc/self/fd/0 /dev/stdin
  23. null::sysinit:/bin/ln -sf /proc/self/fd/1 /dev/stdout
  24. null::sysinit:/bin/ln -sf /proc/self/fd/2 /dev/stderr
  25. ::sysinit:/bin/hostname -F /etc/hostname
  26. # now run any rc scripts
  27. ::sysinit:/etc/init.d/rcS
  28. # Put a getty on the serial port
  29. ttyS0::respawn:/sbin/getty -L ttyS0 115200 vt100 # GENERIC_SERIAL
  30. # Stuff to do for the 3-finger salute
  31. #::ctrlaltdel:/sbin/reboot
  32. # Stuff to do before rebooting
  33. ::shutdown:/etc/init.d/rcK
  34. ::shutdown:/sbin/swapoff -a
  35. ::shutdown:/bin/umount -a -r

# Put a getty on the serial port这一句已经很明显了,我们来增加一句,修改如下

  1. # Put a getty on the serial port
  2. ttyS0::respawn:/sbin/getty -L ttyS0 115200 vt100 # GENERIC_SERIAL
  3. tty0::respawn:/sbin/getty tty0 0

大体格式上照抄,但tty0实际上是虚拟的设备,不是串口,也就没有波特率,这里写0,其实任何值都无所谓。这样就将终端同时在串口和屏幕上启动。保存文件然后重启。

这样就达到了在屏幕上显示终端的目的。事实上,上文的boot.cmd可以不修改,不过踩坑嘛,没坑还踩啥。没错,不用揉眼睛,这个SNAKE不是彩色的,我也很奇怪,明明是可以显示颜色的呀,有知道的小伙伴请留言哦。

参考文献

[1]https://www.oschina.net/p/ncurses

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/我家小花儿/article/detail/840920?site
推荐阅读
相关标签
  

闽ICP备14008679号