Unity平台模拟自动挡驾驶汽车

自动挡汽车功能分析:

(1)刹车数值用连续量0-255表示,连续量根据键盘按键按下时长进行递增,1秒后达到峰值,无论车辆处于前进挡还是倒挡,踩下刹车后车辆逐渐减速至0
(2)汽车分为四个挡位,停车挡P,倒挡R,空挡N,前进挡D
(3)汽车启动后,松开刹车,车辆进入怠速模式,速度从0逐步提升至12KM/H
(4)刹车数值用连续量0-255表示。车速对应1档0-10,2档11-20,3档21-40,4档41-60,5档61-80,6档81-最大值,对应峰值车速150KM/H
(5)挂住P档,拉起手刹车辆停止。
(6)挂住R档,车辆可进行倒车操作。
(7)通过键盘A和D可以控制车辆左右转向

运行结果图:

启动车辆,拉起手刹,挂前进挡,车辆进入怠速模式,缓慢进行加速。

速度提升到12km/h后匀速行驶,继续加速需要踩下油门。

踩下油门后车辆快速加速,自行切换挡位:

前进时踩下刹车后车子逐渐减速至0:

切换至倒挡,踩下油门,车辆后退,踩下刹车,车子逐渐减速至0:

前进时左右转向:

倒挡时左右转型:

源代码:

采用manager of manager的方式,使用了单例模式。

1.Car_Mng类负责管理车辆的物理仿真
2.Input_Mng类负责接受用户的键盘输入信息
3.UI_Mng类负责更新UI界面的显示

Car_Mng

using System.Collections;
using System.Collections.Generic;
using System.Diagnostics.Tracing;
using UnityEngine;

public class Car_Mng : MonoBehaviour
{
 static public Car_Mng Instance;
 public SpeedGear speedGear;

 public float maxMotorTorque; //最大的前进力矩
 public float maxSpeed; //车辆最大前进速度

 public float maxReversMotorTorque; //最大的倒车力矩

 public float maxBrakeToeque; //最大的刹车阻力

 public float maxSteeringAngle; //主动轮最大的旋转角度

 public Rigidbody car; //车辆的刚体
 public WheelCollider[] coliders; //车轮碰撞器
 public GameObject[] wheelMesh; //车轮模型

 public CarState carState=CarState.Off; //车辆启动状态
 public GearState gearState = GearState.ParkingGear; //车辆的挡位
 public bool isHandBrakeON; //是否拉起手刹的标志位

 public float currentSpeed=0; //计算当前车辆的速度

 private bool currentHandBrakeState=true;

 private void Awake()
 {
 Instance = this;
 }
 void Start()
 {
 /* coliders[0].steerAngle = 30;
 coliders[1].steerAngle = 30;
 for (int i = 0; i < 4; i++)
 {
  Quaternion quat;
  Vector3 position;
  coliders[i].GetWorldPose(out position, out quat);
  Debug.Log(position);
  Debug.Log(quat.eulerAngles);
  wheelMesh[i].transform.position = position;
  wheelMesh[i].transform.rotation =
  coliders[i].transform.rotation * Quaternion.Euler(0, coliders[i].steerAngle, 0); 

 }*/
 }

 private void Update()
 {
 UpdateHandBrokeState(); //更新手刹状态
 }
 private void FixedUpdate()
 {
 if (gearState == GearState.ForwardGear || gearState == GearState.ReversGear)
 {
  BrakeCalculate(); //刹车计算 阻力
  AccCalculate(); //油门计算 动力
 }
 SteerCalculate();
 UpdateCarSpeed(); //更新车子的速度
 AutoChangeGear(); //自动换挡 自动挡的车子
 SynchronousWheelMesh(); //将车轮的状态同步给车的模型

 }
 void SynchronousWheelMesh()
 {
 for (int i = 0; i < 6; i++)
 {
  Quaternion quat;
  Vector3 position;
  coliders[i].GetWorldPose(out position, out quat);

  wheelMesh[i].transform.position = position;
  wheelMesh[i].transform.rotation = quat;
 }
 }

 void UpdateHandBrokeState()
 {
 if (currentHandBrakeState != isHandBrakeON)
 {
  currentHandBrakeState = isHandBrakeON;
  if (currentHandBrakeState)
  {
  PullupHandbrake();
  }
  else
  {
  PullDownHandbrake();
  }
 }
 } //更新手刹状态

 public void StartCar() //启动车辆
 {
 carState = CarState.On;
 }
 public void StopCar() //停车
 {
 carState = CarState.Off; //停止接收油门、方向盘、刹车信号
 gearState = GearState.ParkingGear; //挂上停车挡
 PullupHandbrake(); //拉起手刹
 }
 void PullupHandbrake() //拉起手刹,相当于阻力矩最大,直接Freeze车辆刚体的运动
 {
 isHandBrakeON = true; //设置标志位
 //仅保留y轴向的运动
 car.constraints = RigidbodyConstraints.FreezeRotation
  | RigidbodyConstraints.FreezePositionX | RigidbodyConstraints.FreezePositionZ;
 }

 void PullDownHandbrake() //放下手刹,解锁运动
 {
 isHandBrakeON = false;
 //解锁所有运动
 car.constraints = RigidbodyConstraints.None;
 }

 void BrakeCalculate() //计算刹车的阻力
 {

 var value = Input_Mng.Instance.GetBrakeValue(); //读取刹车阻力
 var brakeToequePerWheel = maxBrakeToeque / 2 * value / 255; //计算一个车轮的阻力
 coliders[0].motorTorque = 0;
 coliders[1].motorTorque = 0;
 for (int i = 0; i < 6; i++)
 {
  coliders[i].brakeTorque = brakeToequePerWheel;
 }

 // Debug.Log("刹车阻力:"+ brakeToequePerWheel);
 }

 void AccCalculate() //油门动力计算
 {
 if (gearState == GearState.ForwardGear) //前进
 {
  var value = Input_Mng.Instance.GetAcceleratorValue();
  if (value != 0) //加速行驶
  {

  if(MeterPerSeconds2KmPerHour(currentSpeed) <= 150)
  {
   var accToequePerWheel = maxMotorTorque * value / 255; //计算一个车轮的动力
   coliders[0].motorTorque = accToequePerWheel;
   coliders[1].motorTorque = accToequePerWheel;
  }
  else //不能超过速度上限
  {
   coliders[0].motorTorque = 0;
   coliders[1].motorTorque = 0;
  }
  }
  else //怠速驾驶
  {
  if (MeterPerSeconds2KmPerHour(currentSpeed) < 12)
  {
   coliders[0].motorTorque = 100;
   coliders[1].motorTorque = 100;
  }
  else
  {
   Debug.Log("无动力");
   for (int i = 0; i < 6; i++)
   {
   coliders[i].motorTorque = 0;
   }
  }

  }

 }
 else //倒车
 {
  var value = Input_Mng.Instance.GetAcceleratorValue();
  var accToequePerWheel = maxReversMotorTorque / 2 * value / 255; //计算一个车轮的动力
  coliders[0].motorTorque = -accToequePerWheel;
  coliders[1].motorTorque = -accToequePerWheel;
 }

 }

 void SteerCalculate() //计算转向
 {
 var value= Input_Mng.Instance.GetSteerValue();
 var steerAngle = (value - 128) / 128 * maxSteeringAngle; //计算旋转角度
 coliders[0].steerAngle = steerAngle;
 coliders[1].steerAngle = steerAngle;

 }

 void AutoChangeGear() //自动挡,前进时根据车辆的速度自动切换挡位
 {
 if (gearState == GearState.ForwardGear)
 {
  var speed = MeterPerSeconds2KmPerHour(currentSpeed);
  if (speed <= 10 && speed > 0)
  {
  speedGear = SpeedGear.Speed01;
  }
  if (speed <= 20 && speed > 10)
  {
  speedGear = SpeedGear.Speed02;
  }
  if (speed <= 40 && speed > 20)
  {
  speedGear = SpeedGear.Speed03;
  }
  if (speed <= 60 && speed > 40)
  {
  speedGear = SpeedGear.Speed04;
  }
  if (speed <= 80 && speed > 60)
  {
  speedGear = SpeedGear.Speed05;
  }
  if (speed <= 155 && speed > 80)
  {
  speedGear = SpeedGear.Speed06;
  }
 }
 else
 {
  speedGear = SpeedGear.none;
 }

 }

 void UpdateCarSpeed()
 {
 currentSpeed = car.velocity.magnitude;
 }
 static public float MeterPerSeconds2KmPerHour(float speed) //切换单位 m/s换算成 km/h
 {
 return speed*3.6f;
 }
 static float KmPerHour2MeterPerSeconds(float speed) //切换单位 km/h换算成m/s
 {
 return speed/3.6f;
 }

}
public enum CarState
{
 Off = 0, //关机状态
 On = 1, //运行状态

}
public enum GearState
{
 ParkingGear = 1, //停车挡
 ReversGear = 2, //倒挡
 NeutralGear = 3, //空挡
 ForwardGear = 4,  //前进挡
}

public enum SpeedGear
{
 none,
 Speed01,
 Speed02,
 Speed03,
 Speed04,
 Speed05,
 Speed06
}

Input_Mng

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Input_Mng : MonoBehaviour
{
 static public Input_Mng Instance; //单例模式

 private KeyCode braKeyCode=KeyCode.M; //刹车对应的键盘按键
 public float brakeValue = 0; //刹车值
 public bool isBra = false;

 private KeyCode accKeyCode=KeyCode.W; //油门对应的键盘按键
 public float acceleratorValue = 0; //油门值
 public bool isAcc = false;

 private KeyCode leftSteerKeyCode = KeyCode.A;
 private KeyCode rightSteerKeyCode = KeyCode.D;
 public float steerValue = 128;

 private KeyCode parkingKeyCode = KeyCode.Alpha1; //停车对应的按键
 private KeyCode reversKeyCode = KeyCode.Alpha2; //倒车对应的按键
 private KeyCode neutralKeyCode = KeyCode.Alpha3; //空挡对应的按键
 private KeyCode forwardKeyCode = KeyCode.Alpha4; //前进挡对应的按键

 private KeyCode handBrakeKeyCode = KeyCode.H; //手刹对应的按键

 public float GetBrakeValue() //获取刹车值
 {
 return brakeValue;
 }
 public float GetAcceleratorValue() //获取油门值
 {
 return acceleratorValue;
 }
 public float GetSteerValue()
 {
 return steerValue;
 } //获取转弯值

 private void Awake()
 {
 Instance = this;
 }

 private void Update()
 {
 if (Car_Mng.Instance.carState == CarState.On) //当车辆启动后,检测油门刹车和挡位变换
 {

  UpdateGeerState();

 }
 UpdateSteerValue();
 UpdateHandBrakeState();
 UpdateAcceleratorValue(accKeyCode);
 UpdateBrakeValue(braKeyCode);
 }
 void UpdateHandBrakeState()
 {
 if (Input.GetKeyDown(handBrakeKeyCode))
 {
  if (Car_Mng.Instance.isHandBrakeON)
  {
  Car_Mng.Instance.isHandBrakeON = false;
  }
  else
  {
  Car_Mng.Instance.isHandBrakeON = true;
  }
 }
 }

 void UpdateAcceleratorValue(KeyCode AccCode)
 {
 if (Input.GetKey(AccCode))
 {
  acceleratorValue += 255 * Time.deltaTime;
  acceleratorValue = Mathf.Clamp(acceleratorValue, 0, 255);
  isAcc = true;
 }
 else
 {
  acceleratorValue = 0;
  isAcc = false;
 }
 } //更新油门状态

 void UpdateBrakeValue(KeyCode BraCode) //更新刹车状态
 {
 if (Input.GetKey(BraCode))
 {
  brakeValue += 255 * Time.deltaTime;
  brakeValue = Mathf.Clamp(brakeValue, 0, 255);
  isBra = true;
 }
 else
 {
  brakeValue = 0;
  isBra = false;
 }
 }

 void UpdateSteerValue() //更新方向盘状态
 {
 if (Input.GetKey(leftSteerKeyCode))
 {
  steerValue -= 255 * Time.deltaTime; //0.5秒左侧打死
  steerValue = Mathf.Clamp(steerValue, 0, 255);
 }else if(Input.GetKey(rightSteerKeyCode))
 {
  steerValue += 255 * Time.deltaTime; //0.5秒右侧打死
  steerValue = Mathf.Clamp(steerValue, 0, 255);
 }
 else
 {
  steerValue = 128;
 }
 }
 void UpdateGeerState() //更新挡位状态
 {
 if (Input.GetKeyDown(parkingKeyCode)) //设置为停车档
 {
  Car_Mng.Instance.gearState = GearState.ParkingGear;
 }
 if (Input.GetKeyDown(reversKeyCode)) //倒车档
 {
  Car_Mng.Instance.gearState = GearState.ReversGear;
 }
 if (Input.GetKeyDown(neutralKeyCode)) //空挡
 {
  Car_Mng.Instance.gearState = GearState.NeutralGear;
 }
 if (Input.GetKeyDown(forwardKeyCode)) //前进挡
 {
  Car_Mng.Instance.gearState = GearState.ForwardGear;
 }

 }
}

UI_Mng

using System.Collections;
using System.Collections.Generic;
using System.Drawing;
using UnityEngine;
using UnityEngine.UI;

public class UI_Mng : MonoBehaviour
{
 static public UI_Mng Instance;

 public Image ParkingBg; //停车档
 public Image ForwardBg; //前进挡
 public Image NeutralBg; //空挡
 public Image ReversBg; //倒车档
 public Image HandBrakeBg; //手刹
 public Text speedText; //速度显示
 public Text speedGearText; //挡位显示

 public Image SwitchBg; //开关背景
 public Text Switchtext; //开关显示文字

 public Image AccBg; //油门
 public Image BraBg; //刹车

 private GearState currentGearState;
 private bool currentBrakeState;

 private void Awake()
 {
 Instance = this;
 }
 private void Update()
 {
 UpdateGearUI();
 UpdateHandBrakeUI();
 UpdateAccBra();
 UpdateSpeed();
 }

 void UpdateSpeed()
 {
 speedText.text = Car_Mng.MeterPerSeconds2KmPerHour(Car_Mng.Instance.currentSpeed).ToString("F2")
  + " Km/h";
 SpeedGear speedGear = Car_Mng.Instance.speedGear;
 switch (speedGear)
 {
  case SpeedGear.none:
  speedGearText.text = "自动挡";
  break;
  case SpeedGear.Speed01:
  speedGearText.text = "1挡";
  break;
  case SpeedGear.Speed02:
  speedGearText.text = "2挡";
  break;
  case SpeedGear.Speed03:
  speedGearText.text = "3挡";
  break;
  case SpeedGear.Speed04:
  speedGearText.text = "4挡";
  break;
  case SpeedGear.Speed05:
  speedGearText.text = "5挡";
  break;
  case SpeedGear.Speed06:
  speedGearText.text = "6挡";
  break;
  default:
  break;
 }
 }
 void UpdateAccBra()
 {
 if (Input_Mng.Instance.isAcc)
 {
  AccBg.color = UnityEngine.Color.green;
 }
 else
 {
  AccBg.color = UnityEngine.Color.white;
 }
 if (Input_Mng.Instance.isBra)
 {
  BraBg.color = UnityEngine.Color.green;
 }
 else
 {
  BraBg.color = UnityEngine.Color.white;
 }
 }

 void UpdateHandBrakeUI()
 {
 if (currentBrakeState != Car_Mng.Instance.isHandBrakeON)
 {
  currentBrakeState = Car_Mng.Instance.isHandBrakeON;
  if (currentBrakeState)
  {
  HandBrakeBg.color = UnityEngine.Color.red;
  }
  else
  {
  HandBrakeBg.color = UnityEngine.Color.white;

  }
 }
 }

 private void Start()
 {
 Car_Mng.Instance.StopCar(); //关闭车辆
 OnCarShutDown();//更新UI
 }

 void UpdateGearUI()
 {
 if (currentGearState != Car_Mng.Instance.gearState)
 {
  currentGearState = Car_Mng.Instance.gearState;
  ClearGearUI();
  SetGearUI(currentGearState);
 }
 }
 void ClearGearUI()
 {
 ParkingBg.color = UnityEngine.Color.white;
 ForwardBg.color = UnityEngine.Color.white;
 NeutralBg.color = UnityEngine.Color.white;
 ReversBg.color = UnityEngine.Color.white;
 }
 void SetGearUI(GearState state)
 {
 switch (state)
 {
  case GearState.ForwardGear:
  ForwardBg.color = UnityEngine.Color.red;
  break;
  case GearState.ReversGear:
  ReversBg.color = UnityEngine.Color.red;
  break;
  case GearState.NeutralGear:
  NeutralBg.color = UnityEngine.Color.red;
  break;
  case GearState.ParkingGear:
  ParkingBg.color = UnityEngine.Color.red;
  break;

 }
 }

 public void ChangeCarState()
 {
 if (Car_Mng.Instance.carState == CarState.On) //如果处于开机状态,则停机
 {
  Car_Mng.Instance.StopCar(); //关闭车辆
  OnCarShutDown();//更新UI  

 }else
 {
  Car_Mng.Instance.StartCar(); //启动车子
  OnCarStart();//更新UI
 }
 }
 private void OnCarStart() //车辆启动时更新ui
 {
 SwitchBg.color = UnityEngine.Color.red;
 Switchtext.text = "关闭车辆";

 }
 private void OnCarShutDown() //车辆关闭时执行的逻辑
 {

 SwitchBg.color = UnityEngine.Color.green;
 Switchtext.text = "启动车辆";
 }

}

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。

(0)

相关推荐

  • unity实现手机端摇杆控制人物移动

    前言 玩过王者荣耀或者荒野行动的人,都知道,手机左下方或右下方都会有一个摇杆,滑动摇杆可以让人物向360度方向移动.没有玩过的可以看看下方图片(荒野行动手机端为例).本篇就来讲解如何使用unity制作摇杆控制人物移动. 2种方法: 1.GUITexture制作,是unity自带的一个joystick组件,主要由GUITexture和一个JS脚本构成.优点:unity自带,使用简单方便.缺点是无法适应屏幕大小. 2.EasyTouch插件,可以实现1的功能并且克服了1的缺陷,可以适应屏幕大小.本篇

  • Unity3D实现虚拟按钮控制人物移动效果

    本文为大家分享了Unity3D实现虚拟按钮控制人物移动的具体代码,供大家参考,具体内容如下 创建Image的UI组件,在Image下新建一个Button按钮.在Image 和Button上拖进Sprite图片 在Button按钮上挂载该脚本 using System.Collections; using UnityEngine; using UnityEngine.EventSystems; using UnityEngine.UI; public class MyJoystick : Mono

  • Unity UGUI通过摇杆控制角色移动

    本文实例为大家分享了Unity UGUI通过摇杆控制角色移动的具体代码,供大家参考,具体内容如下 简单版:控制方块的移动. 进阶版:控制人物的移动 知识铺垫: 首先我们必须要知道,在Unity的UGUI中,对UI的操作有八个回调,分别需要实现八个接口.分别是: 鼠标进入,鼠标离开,鼠标点下,鼠标抬起,鼠标开始拖拽,鼠标拖拽中,拖拽结束 如下所示: 我们可以先对这几个接口方法进行一下测试: 测试结束后,大家就会对这些接口方法有一些初步的了解. using UnityEngine; using Un

  • Unity平台模拟自动挡驾驶汽车

    自动挡汽车功能分析: (1)刹车数值用连续量0-255表示,连续量根据键盘按键按下时长进行递增,1秒后达到峰值,无论车辆处于前进挡还是倒挡,踩下刹车后车辆逐渐减速至0 (2)汽车分为四个挡位,停车挡P,倒挡R,空挡N,前进挡D (3)汽车启动后,松开刹车,车辆进入怠速模式,速度从0逐步提升至12KM/H (4)刹车数值用连续量0-255表示.车速对应1档0-10,2档11-20,3档21-40,4档41-60,5档61-80,6档81-最大值,对应峰值车速150KM/H (5)挂住P档,拉起手刹

  • C#实现的三种模拟自动登录和提交POST信息的方法

    本文实例讲述了C#实现的三种模拟自动登录和提交POST信息的方法.分享给大家供大家参考,具体如下: 网页自动登录(提交Post内容)的用途很多,如验证身份.程序升级.网络投票等,以下是用C#实现的方法. 网页自动登录和提交POST信息的核心就是分析网页的源代码(HTML),在C#中,可以用来提取网页HTML的组件比较多,常用的用WebBrowser.WebClient.HttpWebRequest这三个.以下就分别用这三种方法来实现: 1.WebBrowser是个"迷你"浏览器,其特点

  • Unity ScrollView实现自动吸附效果

    本文实例为大家分享了Unity ScrollView实现自动吸附效果的具体代码,供大家参考,具体内容如下 一.效果演示 二.实现思路 通过使用UGUI的拖拽接口,在拖拽结束时比较当前滑动框的NormalizedPositon与每一页的NormalizedPositon值,找到距离当前拖拽结束位置最近的页并缓慢滑动过去 三.使用说明 --此功能脚本是对ScrollView的扩展,所以必须添加UGUI提供的基础Scroll View --Content上必须添加GridLayoutGroup组件并添

  • JS模拟自动点击的简单实例

    复制代码 代码如下: <html xmlns="http://www.w3.org/1999/xhtml"><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8" /><title>javascript模拟鼠标自动点击链接</title><script type="text/java

  • Unity Shader模拟玻璃效果

    本文实例为大家分享了Unity Shader实现玻璃效果的具体代码,供大家参考,具体内容如下 Shader "Glass Refraction" { Properties { _MainTex ("Main Tex", 2D) = "white" {} _BumpMap ("Normal Map", 2D) = "bump" {} _Cubemap ("Environment Cubemap&qu

  • Java基础之教你如何正确运用依赖注入

    一.C++的诟病 C++最遭人诟病的地方就是定义一个类需要写两个文件,一个.h文件和一个.cpp文件.例如定义一个CMainFrame类,mainframe.h内容如下: class CMainFrame : public CFrameWndEx { protected: CMainFrame(); public: virtual ~CMainFrame(); }; mainframe.cpp内容如下: CMainFrame::CMainFrame() { } CMainFrame::~CMai

  • 自动驾驶网络到底是什么

    1 .从宏观上理解自动驾驶网络 自动驾驶网络名字是从自动驾驶汽车的概念借用来的,这是业界的习惯叫法.虽然中文叫自动驾驶网络,但对应的英文却是Autonomous Driving Network,也有部分人使用Self-driving Network,而TMF用了Autonomous Network名字.Autonomous这个词是自治的意思,强调网络的自主决策能力.不过自治这个词仔细琢磨其实有点不合适,因为网络为人服务的,一定要按人的想法执行,哪来的自治?在自动驾驶汽车怎么称呼上,也有类似争议,

  • 自动档汽车如何省油的小技巧

    1.先说自动档车的起步:不少朋友起步给油太少,这样没必要,其实也不好.自动档的换挡设计在2500转(热车时在2200左右换挡),给油太少,达不到2500转时,换挡很慢,不但发动机声音大,而且容易使发动机产生积炭,还会影响发动机的寿命,故多给一些油,让转速迅速到达2500转.这样做的目的不但起步快,对发动机也有利,虽然瞬时油耗可以到达40L,但平均油耗降低. 2.自动档车的带挡滑行最省油!加油到适当时候,松掉油门,这时候的瞬时油耗:0 !!,而且根据行驶状况可以保持很长时间.在市内特别有用:看到远

  • 模拟HTTP请求实现网页自动操作及数据采集的方法

    前言 网页可分为信息提供和业务操作类,信息提供如新闻.股票行情之类的网站.业务操作如网上营业厅.OA之类的.当然,也有很多网站同时具有这两种性质,像微博.豆瓣.淘宝这类网站,既提供信息,也实现某些业务. 普通上网方式一般都是手动操作(这个不需要解释:D).但有时候人工手动操作的方式可能就无法胜任了,如爬取网络上大量数据,实时监测某个页面的变化,批量操作业务(如批量发微博,批量淘宝购物).刷单等.由于操作量大,而且都是重复的操作,人工操作效率低下,且易出错.这时候就可以使用软件来自动操作了. 本人

  • Java模拟新浪和腾讯自动登录并发送微博

    Java模拟新浪和腾讯自动登录并发送微博功能分享给大家,供大家参考,具体内容如下 1.准备工作 只是登录无需申请新浪和腾迅的开发者账号,如果需要发送微博功能,需要申请一个新浪和腾迅的开发者账号,并添加一个测试应用. 过程请参考官方帮助文档,申请地址:新浪:http://open.weibo.com    腾迅:http://dev.t.qq.com/ 我们需要的是App Key和App Secre及redirect_URI,源代码中已经包含了我申请的测试key,但由于限制直接用我的key你们的账

随机推荐