在c#中平滑移动一个点

本文关键字:一个 平滑 移动 | 更新日期: 2023-09-27 18:13:22

我对c#编程相当陌生,可能需要一些帮助来解决我遇到的这个问题。我的观点是,玩家的位置有一个非常不稳定的移动,这是由于按住一个键造成的延迟。像这样: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);
        }
    }
}

在c#中平滑移动一个点

首先,最好不要在游戏开发中使用WinForms,但这并非不可能实现你想要的东西。

Key对于您的要求是不更新键事件中的位置。一个基本的游戏循环会持续做以下事情。首先,它会"更新位置",其次,它会在屏幕上绘制新的位置。

首先我们想要更新位置,但要做到这一点,我们必须知道一个键是否被按下。一种方法是捕获按下键和按上键事件,并在键盘图中标记它们。在更新中,我们现在只检查一个键是否按下,并相应地更新"播放器"的位置。

前段时间我刚刚创建了一个有趣的小演示项目。我会和你分享的。希望能有所帮助。

Update:在更新移动时也要考虑到每次两次抽取之间的时间可能不同。所以你应该在更新中决定应该添加的移动量。看蛇。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);
        }
    }
}