2015-09-18 4 views
0

Я довольно новичок в программировании на C#, и мне может понадобиться помощь в решении этой проблемы, с которой я столкнулся. Моя точка, положение игрока имеет очень рывкое движение из-за задержки, вызванной нажатием клавиши. Как это: е ... EEEEEEEE;)Плавное движение точки в C#?

Как сделать это двигаться более плавно, (чтобы избавиться от задержки)

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); 

     } 
    } 
} 
+5

Первый шаг - не использовать WinForms для игр ... Или, по крайней мере, изменить всю концепцию обработки логики игры в обработчике событий KeyDown. Вам нужен игровой цикл, который работает все время, и переменные, в которых хранятся ключи (de). Прочтите о двойной буферизации и блинии, если вы хотите гладкую анимацию. – CodeCaster

+2

Ну, вы перемещаете его на 10 пикселей каждый раз, поэтому, очевидно, он не будет гладким. – Rotem

+1

Не обновляйте состояние игры в событиях, запускайте операцию, которая запускает анимацию, например, изменяя позицию элемента каждые X миллисекунд. Это выполняется даже для бизнес-приложений - не обновляйте банковский счет в событии OnClick, вызывайте метод в классе, задача которого заключается в обновлении банковского счета –

ответ

0

Прежде всего, это лучше не использовать WinForms для игры? девиация Однако делать что-то вроде того, что вы хотите, невозможно.

Ключом к вашему требованию является не обновление позиции в ключевом событии. Основной игровой цикл непрерывно выполняет следующее. Сначала это будет «Обновить позиции», а во-вторых, он отображает новые позиции на экране.

Итак, сначала мы хотим обновить позиции, но для этого мы должны знать, нажата ли клавиша или нет. Один из способов сделать это - захватить клавиши вниз и активировать события и пометить их на карте клавиатуры. В рамках обновления мы теперь проверяем только, закрыт ли ключ и соответственно обновляет положение «Player».

Некоторое время назад я только что создал небольшой демонстрационный проект для развлечения. Я поделюсь им с вами. Надеюсь, поможет.

Обновление: Также при обновлении движения учитывайте, что время между двумя ничьями может различаться каждый раз. Таким образом, вы должны в рамках обновления определить количество движения должно быть добавлено. См. Метод Snake.UpdatePositions? Я заявляю, что через 1 секунду игрок должен переместить 100 единиц (пикселей). Поэтому я рассчитываю, что объем перемещения будет соответствовать времени между настоящим и последним кадрами.

Создайте проект Winform под названием SmoothAnimationDemo и замените код для 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); 
     } 
    } 

} 
Смежные вопросы