第二个玩家移动输入滞后



问候!

我对 C# 很陌生,我一直在关注 YouTube 上的教程播放列表来创建有问题的应用程序。然而,现在我离完成这个系列还差一个视频,我决定尝试给游戏一点我自己的改变。游戏是非常基本的,有一个玩家单位(主要玩家(,一个敌人单位(敌人(和盟友单位(第二个玩家(。我在教程系列的开头简单地创建了盟友单位作为练习,甚至没有想过把它变成第二个玩家。然而,凭借从其他剧集中获得的知识,我决定成为第二个玩家。在它自己的脚本中,我只是简单地使用了与播放器相同的移动代码,只是更改了移动键。但是,当您按下按键并立即移动时,玩家单位会立即响应,但第二个玩家会滞后。它需要一段时间才能开始移动,有时会以不同的间隔移动。

Game.cs脚本的第43 行和第 44 行中,在公共无效 Run((中,我注意到如果我使用 allyUnit.Update 切换playerUnit.Update盟友单位将不再滞后,但玩家单位会。因此,代码中首先出现的哪个都不会滞后,另一个会滞后。这让我觉得它可能与更新有些冲突?因为它在同一时间、同一周期内更新关键输入或其他什么?鉴于我还在学习,我可能会说有史以来最大的亵渎,但这也是我创建这个线程的原因。

以下是相关脚本:

游戏.cs

using System;
using System.Threading;
using System.Diagnostics;
namespace DodgeGame
{
public class Game
{
public Game () //This function runs when the player starts a New Game, thus creating the characters
{
//Creates a player unit and sets its position/graphic
playerUnit = new PlayerUnit(30, 10, "@");
//Creates an enemy unit and sets its position/graphic
enemyUnit = new EnemyUnit(Console.WindowWidth - 1, 10, "X");
//Creates an ally unit and sets its position/graphic
allyUnit = new AllyUnit(12, 5, "O");
stopwatch = new Stopwatch();
}
private Stopwatch stopwatch;
private Unit playerUnit;
private Unit enemyUnit;
private Unit allyUnit;
public void Run() //This function is called once the New Game has begun, thus drawing the characters
{
stopwatch.Start ();
int timeAtPreviousFrame = (int)stopwatch.ElapsedMilliseconds; //timeAtPreviousFrame -- milliseconds the stopwatch reported last frame

while (true) 
{
//Time since last frame
int deltaTimeMS = (int)(stopwatch.ElapsedMilliseconds - timeAtPreviousFrame); //1000 / desiredFPS;
timeAtPreviousFrame = (int)stopwatch.ElapsedMilliseconds;
//Update units
playerUnit.Update (deltaTimeMS);
allyUnit.Update (deltaTimeMS);
enemyUnit.Update (deltaTimeMS);
//Detect collide (True = Game Over)
if (playerUnit.IsCollidingWith (enemyUnit) || allyUnit.IsCollidingWith(enemyUnit))
{
GameOver ();    
}
//Draws all units
playerUnit.Draw ();
allyUnit.Draw ();
enemyUnit.Draw ();
//Tiny sleep to avoid running at too high FPS
Thread.Sleep (5);   
}
}
void GameOver()
{
Console.Clear ();
Console.WriteLine ("Game Over!");
Console.WriteLine ("nnWould you like to try again? (Y/N)");
while(true)
{
ConsoleKeyInfo cki = Console.ReadKey (true);
switch(cki.Key)
{
case ConsoleKey.Y:
Console.Clear ();
Game game = new Game ();
game.Run ();
break;
case ConsoleKey.N:
Environment.Exit(0);
break;
}
}
}
}
}

盟友单位.cs

using System;
namespace DodgeGame
{
public class AllyUnit : Unit
{
public AllyUnit (int x, int y, string unitGraphic) : base(x, y, unitGraphic)    {       }
override public void Update(int deltaTimeMS)
{
//Ally Actions
//Has the second player pressed a key?
if (Console.KeyAvailable == true)       // Yes
{ 
//This will make the second player move
ConsoleKeyInfo cki = Console.ReadKey (true);
switch (cki.Key) 
{
//Move Up
case ConsoleKey.UpArrow:    case ConsoleKey.NumPad8:
if (Y > 0)
Y = Y - 1;
break;
//Move Down
case ConsoleKey.DownArrow:  case ConsoleKey.NumPad2:
if (Y < Console.WindowHeight - 1)
Y = Y + 1;
break;
//Move Left
case ConsoleKey.LeftArrow:  case ConsoleKey.NumPad4:
if (X > 0)
X = X - 1;
break;
//Move Right
case ConsoleKey.RightArrow: case ConsoleKey.NumPad6:
if (X < Console.WindowWidth - 1)
X = X + 1;
break;
}
//With Ally Actions calculated, we want to call Unit's Update in case it has important work to do
base.Update (deltaTimeMS);
}
}
}
}

玩家单位.cs

using System;
namespace DodgeGame
{
public class PlayerUnit : Unit
{
public PlayerUnit (int x, int y, string unitGraphic) : base(x, y, unitGraphic)
{
}
override public void Update(int deltaTimeMS)
{
//====================================================================\
//                           PLAYER ACTIONS                           \
//====================================================================\
//Has the user pressed a key?
if (Console.KeyAvailable == true) // Yes
{
//This will make the player move
ConsoleKeyInfo cki = Console.ReadKey (true);
switch(cki.Key)
{
//Move Up
case ConsoleKey.W: case ConsoleKey.NumPad8:
if(Y > 0)
Y = Y - 1;
break;
//Move Down
case ConsoleKey.S: case ConsoleKey.NumPad2:
if(Y < Console.WindowHeight - 1)
Y = Y + 1;
break;
//Move Left
case ConsoleKey.A: case ConsoleKey.NumPad4:
if(X > 0)   
X = X - 1;
break;
//Move Right
case ConsoleKey.D: case ConsoleKey.NumPad6:
if(X < Console.WindowWidth - 1)
X = X + 1;
break;
}
}
//With keyboard input received, we want to call Unit's Update in case it has important work to do
base.Update (deltaTimeMS);
}
}
}

单位.cs

using System;
namespace DodgeGame
{
abstract public class Unit
{
public Unit(int x, int y, string unitGraphic)
{
this.X = x;
this.Y = y;
this.UnitGraphic = unitGraphic;
}
//Unit's Position
public int X //The way the rest of the program interacts with X
{
get
{
return _x;
}
set
{
if(value < 0 || value >= Console.WindowWidth)
{
throw new Exception ("Invalid X Coordinate."); 
}
Clean ();
_x = value;
}
}
private int _x; //Where the value of X is actually stored
//Unit's Position
public int Y //The way the rest of the program interacts with X
{
get
{
return _y;
}
set
{
if(value < 0 || value >= Console.WindowHeight)
{
throw new Exception ("Invalid Y Coordinate."); 
}
Clean ();
_y = value;
}
}
private int _y; //Where the value of X is actually stored
//====================================================================\
//Unit's Graphics
public string UnitGraphic {get; set;}
//Update Unit's Position
virtual public void Update(int deltaTimeMS)
{
}
//This draws the units on the screen
public void Draw()
{
Console.SetCursorPosition (X, Y);
Console.Write (UnitGraphic);
}
public void Clean()
{
Console.SetCursorPosition (X, Y);
Console.Write(' ');
}
public bool IsCollidingWith(Unit other)
{
if (this.X == other.X && this.Y == other.Y)
{
return true;
}
return false;
}    
}
}

我尝试专门为allyUnit创建一个不同的单独Update((函数,但它不起作用。我还尝试了其他一些小事情,但没有一件能完成这项工作。我该怎么做才能解决这个问题?

提前谢谢你,

神经质

我怀疑你的 PlayerUnit 和 AllyUnit Update(( 方法都调用 ReadKey((。当第一个调用 Update(( 方法时,将抓住按下的键,没有为第二个方法调用留下任何按键事件。

无论如何,将任何类型的I/O直接包含在逻辑类中都是糟糕的形式,所以我要做的是在游戏中创建一个单独的更新函数.cs该函数读取密钥,然后将读取的密钥传递给PlayerUnit.Update((和AllyUnit.Update((调用。

编辑: 所以在游戏中是这样的.cs:

Update(mSecs) {
ConsoleKeyInfo cki = Console.ReadKey();
playerUnit.Update(cki, mSecs);
allyUnit.Update(cki, mSecs);
enemyUnit.Update(mSecs);
}

然后相应地更改 *Unit 类中的方法。 您还必须更改 Run(( 方法,以将 Update 调用替换为对此方法的调用。