c# - 播放器没有响应 Unity 中的 arduino 代码
问题描述
所以我正在开发这个游戏(作为更大游戏的一部分),玩家必须在进入下一个级别之前收集所有硬币。我希望播放器在收到来自 arduino 的一定数量的按钮点击时。每个级别都需要不同数量的压力机。例如,级别 1 需要点击 1 次,级别 2 需要点击 2 次等。这里的问题是玩家没有响应输入,我不知道为什么。当我使用空格键测试这段代码时,播放器移动了,所以问题肯定在播放器和 arduino 之间的某个地方。此外,有时我按下按钮两次,Arduino 输出 3 而不是 2,有时我按下按钮一次,Arduino 输出 2 而不是 1。任何关于如何解决这些问题的提示将不胜感激。
这是 Arduino 脚本:
#include <Bounce2.h>
#include<SoftwareSerial.h>
#include <Wire.h>
// Connect each button with one connection
// to GND and the other to a digital pin.
const byte buttonPin = 2;
const byte buttonPin2 = 3;
class Button{
private:
byte m_buttonPin;
byte m_counter = 0;
unsigned long m_buttonPressTimeout;
unsigned long m_previousMillis;
public:
Button(byte buttonPin):
m_buttonPin(buttonPin),
m_counter(0),
m_buttonPressTimeout(2000), // Button press timeout in ms.
m_previousMillis(0){}
void Update(){
if(m_counter > 0 && millis() - m_previousMillis >= m_buttonPressTimeout)
{
//Serial.print("Count from Update() just before it's reset to 0 = ");
Serial.println(GetCounter());
m_counter = 0;
}
}
void IncrementCounter(){
m_counter++;
if(m_counter > 4){m_counter = 4;}
if(m_counter == 1)
{
m_previousMillis = millis();
}
}
friend void IncrementCounter(Button&);
void IncrementCounter(Button&){
IncrementCounter();
}
byte GetCounter(){
return m_counter;
}
};
Bounce buttonOneDebouncer = Bounce();
Bounce buttonTwoDebouncer = Bounce();
Button ButtonOne(buttonPin);
Button ButtonTwo(buttonPin2);
void setup(){
Serial.begin(9600);
pinMode(buttonPin, INPUT_PULLUP);
pinMode(buttonPin2, INPUT_PULLUP);
buttonOneDebouncer.attach(buttonPin);
buttonTwoDebouncer.attach(buttonPin2);
buttonOneDebouncer.interval(25);
buttonTwoDebouncer.interval(25);
}
void loop(){
// Call the Update function as fast as possible.
ButtonOne.Update();
ButtonTwo.Update();
// Button one pressed.
if(buttonOneDebouncer.update()){
if(buttonOneDebouncer.fell()){
if(digitalRead(buttonPin2) == 0){
ButtonOne.IncrementCounter();
}
}
}
// Button two pressed.
if(buttonTwoDebouncer.update()){
if(buttonTwoDebouncer.fell()){
if(digitalRead(buttonPin) == 0){
ButtonOne.IncrementCounter(ButtonTwo);
}
}
}
/*if(digitalRead(buttonPin) == 0 && (digitalRead(buttonPin2) == 0))
{
Serial.println("9");
}*/
}
这是播放器脚本:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.SceneManagement;
using System.IO.Ports;
public class PlayerControllerb : MonoBehaviour
{
public static int level;
[Header("Debug")]
[SerializeField] private PlatformProvider platformProvider;
SerialPort sp = new SerialPort("\\\\.\\COM4", 9600);
//player = GameObject.FindWithTag("Player").GetComponent<Renderer>().material;
private void Awake()
{
OnSceneLoaded();
SceneManager.sceneLoaded -= OnSceneLoaded;
SceneManager.sceneLoaded += OnSceneLoaded;
print(level);
}
public void OnSceneLoaded()
{
}
public void OnSceneLoaded(Scene scene, LoadSceneMode mode)
{
platformProvider = FindObjectOfType<PlatformProvider>();
}
public float Speed = 1;
private int currentPlatformIndex;
public Vector2 height;
public float xMin, xMax, yMin, yMax;
string value;
int amount;
void Start()
{
if (!sp.IsOpen)
{ // If the erial port is not open
sp.Open(); // Open
}
sp.ReadTimeout = 1; // Timeout for reading
print(level);
}
void Update()
{
// if (Input.GetKeyDown(KeyCode.Space) && level == 1)
// GoToNextPlatform();
if (sp.IsOpen)
{ // Check to see if the serial port is open
try
{
value = sp.ReadLine(); //Read the information
amount = int.Parse(value);
print(amount);
//transform.Translate(Speed * Time.deltaTime, 0f, 0f); //walk
//if (/*amount > 25f)*/Input.GetKeyDown(KeyCode.Space)) //jump
if (amount == 1 && level == 1)
{
//if (Input.GetKeyDown(KeyCode.Space))
//{
GoToNextPlatform();
// GetComponent<Rigidbody2D>().AddForce(2* height, ForceMode2D.Impulse);
}
if (amount == 2 && level == 2)
{
//if (Input.GetKeyDown(KeyCode.Space))
//{
GoToNextPlatform();
// GetComponent<Rigidbody2D>().AddForce(2* height, ForceMode2D.Impulse);
}
if (amount == 3 && level == 3)
{
//if (Input.GetKeyDown(KeyCode.Space))
//{
GoToNextPlatform();
// GetComponent<Rigidbody2D>().AddForce(2* height, ForceMode2D.Impulse);
}
if (amount == 4 && level == 4)
{
//if (Input.GetKeyDown(KeyCode.Space))
//{
GoToNextPlatform();
// GetComponent<Rigidbody2D>().AddForce(2* height, ForceMode2D.Impulse);
}
}
catch (System.Exception)
{
}
/*GetComponent<Rigidbody2D>().position = new Vector3
(
Mathf.Clamp(GetComponent<Rigidbody2D>().position.x, xMin, xMax),
Mathf.Clamp(GetComponent<Rigidbody2D>().position.y, yMin, yMax)
);*/
}
}
[ContextMenu(nameof(GoToNextPlatform))]
public void GoToNextPlatform()
{
currentPlatformIndex++;
currentPlatformIndex = Mathf.Min(currentPlatformIndex, platformProvider.platforms.Length);
GoToPlatform(currentPlatformIndex);
}
[ContextMenu(nameof(GoToPreviousPlatform))]
public void GoToPreviousPlatform()
{
currentPlatformIndex--;
currentPlatformIndex = Mathf.Max(currentPlatformIndex, 0);
GoToPlatform(currentPlatformIndex);
}
private void GoToPlatform(int index)
{
//StopAllCoroutines();
//StartCoroutine(MoveTo(platformProvider.platforms[index].transform.position));
gameObject.transform.position = platformProvider.platforms[index].transform.position;
}
IEnumerator MoveRoutine(Vector3 target)
{
while (!Mathf.Approximately(0, Vector3.Distance(transform.position, target)))
{
yield return new WaitForFixedUpdate();
GetComponent<Rigidbody>().MovePosition(Vector3.MoveTowards(GetComponent<Rigidbody>().position, target, Time.deltaTime * Speed));
}
}
private void FixedUpdate()
{
GetComponent<Rigidbody2D>().position = new Vector3
(
Mathf.Clamp(GetComponent<Rigidbody2D>().position.x, xMin, xMax),
Mathf.Clamp(GetComponent<Rigidbody2D>().position.y, yMin, yMax)
);
}
void ApplicationQuit()
{
if (sp != null)
{
{
sp.Close();
}
}
}
}
解决方案
那么在某个地方,您需要从 yes 获得这些平台的位置。
我会PlatformProvider
在每个场景中都有一个专门的
public class PlatformProvider : MonoBehaviour
{
// Here reference your platforms via drag&drop in the order you need
public Platform[] platforms;
}
并将其放在所有平台上
public class Platform : MonoBehaviour { }
它不必做任何事情,但用于引用它们。
然后在您的控制器中找到平台,例如每次加载新场景时。
我只是在这里假设您的控制器永远不会被破坏而是保持活动状态,否则您只需要PlatformProvider
在 Awake 或通过 Inspector 设置一次,而根本不需要在运行时设置它。
public class PlayerControllerb : MonoBehaviour
{
[Header("Debug")]
[SerializeField] private PlatformProvider platformProvider;
private void Awake ()
{
OnSceneLoaded();
SceneManager.sceneLoaded -= OnSceneLoaded;
SceneManager.sceneLoaded += OnSceneLoaded;
}
private void OnSceneLoaded(Scene scene, LoadSceneMode mode)
{
// If anyway there is a new PlayerControllerb on each scene
// remove Awake and OnSceneLoaded and simply set the reference in the Inspector.
platformProvider = FindObjectOfType<PlatformProvider>();
}
那么您可以简单地从平台获取下一个位置,例如
// Set in the Inspector in Units per second
public float Speed = 1;
private int currentPlatformIndex;
private void Update()
{
if(ARDUINO_MAGIC)
{
GoToNextPlatform ();
}
}
// Using this you can debug it in the context menu of the component without Arduino ;)
[ContextMenu(nameof(GoToNextPlatform)>]
public void GoToNextPlatform()
{
currentPlatformIndex++;
currentPlatformIndex = Mathf.Min(currentPlatformIndex, platformProvider.platforms.Length - 1);
GoToPlatform (currentPlatformIndex);
}
[ContextMenu (nameof(GoToPreviousPlatform))]
public void GoToPreviousPlatform()
{
currentPlatformIndex--;
currentPlatformIndex = Mathf.Max(currentPlatformIndex, 0);
GoToPlatform (currentPlatformIndex);
}
然后对于运动,我会使用 aCoroutine
而不是在Update
. 无论如何,只要Rigdbody(2D)
涉及 a ,您不应该通过组件分配任何转换,Transform
而是通过Rigidbody(2D)
and分配FixedUpdate
,以免破坏物理。在协程中,这可以通过使用来实现WaitForFixedUpdate
private void GoToPlatform(int index)
{
// Depends on your needs
// You can either use a bool and ignore concurrent routines
// or simply stop any running one
StopAllCoroutines();
StartCoroutine(MoveTo(platformProvider.platforms [index].transform.position));
}
private IEnumerator MoveRoutine (Vector3 target)
{
while(!Mathf.Approximately(0, Vector3.Distance(transform.position, target)))
{
yield return new WaitForFixedUpdate();
rigidbody.MovePositio (Vector3.MoveTowards(rigidbody.position, target, Time.deltaTime * moveSpeed);
}
}
}
推荐阅读
- c# - 在 Xamarin 中的 listview 和另一个页面之间传递参数
- amazon-web-services - 将 CNAME 和 CNAME 值输入 DNS 以进行 AWS 证书批准
- laravel - 如何对 json 数据使用 Symfony 验证
- c++ - Visual Studio Code 在终端中运行程序以进行输入
- php - 如何加入2选择?
- python - 在 Pandas 中跨多种电影类型的 Groupby
- java - 是否可以在类的方法中将@InjectMocks 注入到临时对象实例中?
- sql - POSTGRES - 超级用户无法访问 pg_authid 表
- c# - UI Automation using Selenium c# for Windows App 使用带有 CEF 框架的 WPF 应用程序开发
- django - 工人不运行时执行芹菜任务