问候!
我是C#的新手,我一直在关注YouTube的教程播放列表来创建相关应用程序。然而,现在我只是完成系列赛的一段视频,我决定尝试给我的游戏一点点我自己的扭曲。游戏非常基本,有一个 playerUnit (主要玩家),一个 enemyUnit (敌人)和 allyUnit (第二个玩家) 。我在教程系列的开头简单地创建了 allyUnit ,甚至没有想过将它变成第二个玩家。然而,凭借从其他剧集中获得的知识,我决定将其变成第二个玩家。在它自己的脚本中,我只使用相同的代码进行运动,我用于 playerUnit ,只更改运动键。但是,当按下键并且立即移动时, playerUnit 响应正确,而第二个玩家则滞后。它需要一段时间才能开始移动,有时会以不同的间隔移动。
在 Game.cs 脚本中,在第43和44行中,在 public void Run()中,我注意到如果我使用 allyUnit.Update 切换 playerUnit.Update , allyUnit 将不再滞后,但 playerUnit 将会延迟。因此,代码中首先出现的不会滞后,另一个会出现。这让我觉得它可能与Update有些冲突?既然它同时更新键输入,在同一个循环中还是什么?鉴于我还在学习,我可能会说最大的亵渎,但这也是我创建这个主题的原因。
以下是相关脚本:
Game.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 ("\n\nWould 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;
}
}
}
}
}
AllyUnit.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);
}
}
}
}
PlayerUnit.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);
}
}
}
Unit.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()函数,但它不起作用。我还尝试了其他一些小事,但没有人做过这件事。我该怎么做才能解决这个问题?
提前谢谢你,
Nervly
答案 0 :(得分:-1)
我怀疑您的PlayerUnit和AllyUnit Update()方法都调用了ReadKey()。当首先调用任何Update()方法时,将抓住按下的键,不再为第二个方法调用留下按键事件。
无论如何,将任何类型的I / O直接包含在逻辑类中都是不好的形式,所以我要做的是在Game.cs中创建一个单独的Update函数来读取密钥,然后将密钥读取传递给PlayerUnit。 Update()和AllyUnit.Update()调用。
编辑: 在Game.cs中有类似的东西:
Update(mSecs) {
ConsoleKeyInfo cki = Console.ReadKey();
playerUnit.Update(cki, mSecs);
allyUnit.Update(cki, mSecs);
enemyUnit.Update(mSecs);
}
然后相应地更改* Unit类中的方法。 您还必须更改Run()方法,以通过调用此方法来替换Update调用。