编辑代码

import sys,os
#调用数学库和时间库
import math,time
#调用多线程库
import threading

#定义全局变量
program_running_flag = False
accel = 0

#标准getch部分,不重复说明
def getch():
    # tty = teletypewriter, termios = terminal io interface
    import tty, termios
    # stdin = standard input, fileno = filestream number 
    fd = sys.stdin.fileno()
    # tcgetattr = termios configuration get attribute
    old_settings = termios.tcgetattr(fd)
    # 尝试
    try:
        # 通过tty模块获取stdin的file stream,然后用read(1)读取1个字节
        tty.setraw(sys.stdin.fileno())
        ch = sys.stdin.read(1)
    # 尝试部分执行完成后执行的“善后”代码
    finally:
        # termios configuration set attribute
        # TCSADRAIN,在termios传输完成后生效,具体参照Unix termios模块的说明
        # 不确定通过tty模块读取输入会对配置造成什么影响,这段代码是用来消除这个影响的
        termios.tcsetattr(fd, termios.TCSADRAIN, old_settings)
    # 返回并输出读取到的ch
    return ch

#定义输入任务
def input_task():
    #设定获取全局变量
    #全局变量可被跨线程访问
    global accel, program_running_flag
    #设置本地变量
    #可以调整sleep时间来看下实际影响
    input_task_sleep_time=0.1
    #用flag控制主程序循环,这样在需要的时候可以更好的控制退出的时机和行为
    while program_running_flag:
        #获取输入
        input_key = getch()
        #如果输入是ESC按键
        if ord(input_key) == 27:
            #通过改变flag状态控制所有线程退出
            program_running_flag = False
        #如果输入是w则加速
        elif ord(input_key) == ord("w"):
            accel+=1
        #如果输入是s则加速
        elif ord(input_key) == ord("s"):
            accel-=1
        #如果输入是空格则加速度清零
        elif ord(input_key) == ord(" "):
            accel = 0
        #通过inline if来控制accel的范围
        #math.copysign(x,y)返回y的符号和x的值
        accel = accel if abs(accel)<=10 else math.copysign(10,accel)
        #通过控制线程睡眠时间避免跑得过快抢占系统资源
        time.sleep(input_task_sleep_time)
    

#定义输出任务
def output_task():
    #设定获取全局变量
    #全局变量可被跨线程访问
    global accel, program_running_flag
    #删除整行文字的控制符,具体可以参考下面链接(仅适用linux):
    # https://tldp.org/HOWTO/Bash-Prompt-HOWTO/x361.html
    erase_str = "\r\033[k"
    # 设置本地变量
    speed = 0
    #可以调整sleep时间来看下实际影响
    output_task_sleep_time = 0.1
    #用flag控制主程序循环,这样在需要的时候可以更好的控制退出的时机和行为
    while program_running_flag:
        #更新速度
        speed += accel*output_task_sleep_time
        #通过inline if来控制speed的范围
        speed = speed if abs(speed)<=100 else math.copysign(100,speed)
        #组合显示信息
        display_str = "Speed:\t {0:.2f}m/s Accel:\t{1:.0f}m/s^2".format(speed,accel)
        #通过write写入stdout
        sys.stdout.write(erase_str+display_str)
        #通过控制线程睡眠时间避免跑得过快抢占系统资源
        time.sleep(output_task_sleep_time)

#定义主函数
def main():
    #设定获取全局变量
    #全局变量可被跨线程访问
    global program_running_flag
    #通过改变flag状态确保所有线程能运行
    program_running_flag = True
    #设置输入线程任务目标
    input_thread = threading.Thread(target=input_task)
    #启动输入线程
    input_thread.start()
    #设置输出线程任务目标
    output_thread = threading.Thread(target=output_task)
    #启动输出线程
    output_thread.start()
    
    #等待输入输出线程正常退出
    input_thread.join()
    output_thread.join()

#启动main函数
main()