我对使用C#编程相当新,可能需要一些帮助来解决我遇到的这个问题。 我的观点是,由于按住键时发生的延迟,球员位置的运动非常不稳定。像这样:e ... e e e e e;)
如何让它更顺畅地移动(摆脱延迟?)
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Drawing;
using System.Windows.Forms;
namespace kek
{
class player
{
Image Player;
Point Playerposition = new Point(600, 200);
Form1 game;
public void playerinitialize(Form game)
{
this.game = (Form1)game;
Player = Bitmap.FromFile("player.png");
game.KeyDown += Game_KeyDown;
game.KeyPress += Game_KeyPress;
}
private void Game_KeyPress(object sender, KeyPressEventArgs e)
{
if (e.KeyChar < 50)
{
Playerposition.Y -= 10;
}
}
private void Game_KeyDown(object sender, KeyEventArgs e)
{
//Player move on keypress
if (e.KeyCode == Keys.W)
{
Playerposition.Y -= 10;
}
if (e.KeyCode == Keys.S)
{
Playerposition.Y += 10;
}
if (e.KeyCode == Keys.A)
{
Playerposition.X -= 10;
}
if (e.KeyCode == Keys.D)
{
Playerposition.X += 10;
}
//Playerposition.Y -= GamePad.GetState(PLayerIndex.One).ThumbSticks.Left.Y;
//Playerposition.Y += GamePad.GetState(PLayerIndex.One).ThumbSticks.Right.Y;
//Playerposition.X -= GamePad.GetState(PLayerIndex.One).ThumbSticks.Left.X;
//Playerposition.X += GamePad.GetState(PLayerIndex.One).ThumbSticks.Right.X;
}
public void Draw(Graphics graphics)
{
//on update
graphics.DrawImage(Player, Playerposition);
}
}
}
答案 0 :(得分:0)
首先,最好不要将WinForms用于游戏开发。然而,做出你想要的东西并非不可能。
您的要求的关键是不更新关键事件中的位置。基本游戏循环持续执行以下操作。首先它会更新职位&#39;其次,它在屏幕上绘制了新的位置。
首先我们要更新位置,但要做到这一点,我们必须知道是否按下了某个键。一种方法是捕获按键和按键事件,并在键盘图中标记这些事件。在更新中,我们现在只检查键是否关闭,并相应地更新“播放器”的位置。
前段时间我刚刚创建了一个有趣的小型演示项目。我会和你分享。希望它有所帮助。
更新:此外,在更新动作时,请考虑两次绘制之间的时间每次都可能不同。因此,您应该在更新中确定应添加的移动量。请参阅Snake.UpdatePositions方法?我声明玩家应该在1秒后移动100个单位(像素)。所以我根据现在和最后一帧之间的时间计算出的位移量。
创建一个名为SmoothAnimationDemo的Winform项目,并使用以下代码替换Form1.cs的代码。
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Windows.Forms;
namespace SmoothAnimationDemo
{
public partial class Form1 : Form
{
// check every x frames, calculate fps, adjust x
private readonly FrameInfo _frameInfo = new FrameInfo(DateTime.Now);
private readonly List<Animation> _animations = new List<Animation>();
public Form1()
{
InitializeComponent();
this.DoubleBuffered = true;
FrameInfoVisible = false; // Set to true if needed.
RegisterAnimation(new Snake(this));
}
public bool FrameInfoVisible { get; set; }
public void RegisterAnimation(Animation animation)
{
_animations.Add(animation);
}
private int _skipframes = 1;
protected override void OnPaint(PaintEventArgs e)
{
base.OnPaint(e);
// Skip updating if needed.
if (_skipframes > 0)
{
_skipframes--;
}
else
{
_frameInfo.Update();
foreach (var animation in _animations)
animation.UpdatePositions(_frameInfo);
_skipframes = 0; // adjust to skip frames or leave at 0 to not skip frames.
}
// init drawing
var gfx = e.Graphics;
gfx.Clear(Color.Black);
// draw each frame.
foreach (var animation in _animations)
{
animation.Draw(gfx);
gfx.ResetTransform(); // in case the animation used transform methods.
}
// draw timer info on top
if (FrameInfoVisible)
_frameInfo.Draw(gfx);
// wait till a certain time has passed before drawing again.
//Thread.Sleep(10);
Invalidate(); // ensure new paint soon
}
}
/// <summary>
/// abstract base class for animations.
/// An animation contains two methods. First one used for updating animation data, eg positions.
/// Second one used for drawing the data onto a graphics object.
/// </summary>
public abstract class Animation : IDrawable, IAnimatable
{
public abstract void Draw(Graphics gfx);
public abstract void UpdatePositions(FrameInfo frameInfo);
}
/// <summary>
/// Contains info about our frames
/// </summary>
public class FrameInfo
{
public DateTime FirstFrameTime { get; set; }
public DateTime PrevFrameTime { get; set; }
public DateTime FrameTime { get; set; }
public int FrameCount { get; set; }
public double FramesPerSecond { get; set; }
public FrameInfo(DateTime now)
{
FirstFrameTime = now;
}
public void Update()
{
PrevFrameTime = FrameTime;
FrameTime = DateTime.Now;
FrameCount++;
FramesPerSecond = 1000.0 / (FrameTime - PrevFrameTime).TotalMilliseconds;
}
public void Draw(Graphics gfx)
{
gfx.DrawString("Frame time", SystemFonts.DefaultFont, Brushes.Black, 0, 0);
gfx.DrawString(String.Format(": {0:hh:mm:ss.zzzz}", FrameTime - FirstFrameTime), SystemFonts.DefaultFont, Brushes.Black, 70, 0);
gfx.DrawString("Frame", SystemFonts.DefaultFont, Brushes.Black, 0, 16);
gfx.DrawString(": " + FrameCount, SystemFonts.DefaultFont, Brushes.Black, 70, 16);
gfx.DrawString("FPS", SystemFonts.DefaultFont, Brushes.Black, 0, 32);
gfx.DrawString(": " + FramesPerSecond, SystemFonts.DefaultFont, Brushes.Black, 70, 32);
}
}
internal interface IAnimatable
{
void UpdatePositions(FrameInfo frameInfo);
}
internal interface IDrawable
{
void Draw(Graphics gfx);
}
/// <summary>
/// Animation module
/// </summary>
internal class Snake : Animation
{
public Snake(Control form)
{
form.KeyDown += form_KeyDown;
form.KeyUp += form_KeyUp;
}
readonly Dictionary<Keys, bool> _keyMap = new Dictionary<Keys, bool>
{
{ Keys.Up, false },
{ Keys.Down, false },
{ Keys.Left, false },
{ Keys.Right, false }
};
void form_KeyUp(object sender, KeyEventArgs e)
{
if (_keyMap.ContainsKey(e.KeyCode))
_keyMap[e.KeyCode] = false;
}
void form_KeyDown(object sender, KeyEventArgs e)
{
if (_keyMap.ContainsKey(e.KeyCode))
_keyMap[e.KeyCode] = true;
}
private PointF _headPos = new PointF(100.0f, 100.0f);
public override void UpdatePositions(FrameInfo info)
{
// Ensure that the motion is moving at a
var speed = 100; // 100 units within 1 second
var perc = (double)(info.FrameTime - info.PrevFrameTime).TotalMilliseconds / 1000;
var displaceAmount = (float)(speed * perc);
if (_keyMap[Keys.Up])
_headPos.Y -= displaceAmount;
if (_keyMap[Keys.Down])
_headPos.Y += displaceAmount;
if (_keyMap[Keys.Right])
_headPos.X += displaceAmount;
if (_keyMap[Keys.Left])
_headPos.X -= displaceAmount;
}
public override void Draw(Graphics gfx)
{
gfx.SmoothingMode = SmoothingMode.AntiAlias;
gfx.DrawString(String.Format("[{0},{1}]", _headPos.X, _headPos.Y), SystemFonts.DefaultFont, Brushes.Black, 0.0f, 48.0f);
gfx.DrawEllipse(Pens.White, _headPos.X, _headPos.Y, 10.0f, 10.0f);
}
}
}