作者VVll (J.)
看板C_Sharp
标题Re: [问题] 按键延迟的解决方法?
时间Fri Jun 20 12:53:07 2014
进阶篇
Q: 为什麽切换移动方向会卡卡的?
A: 因为Form1_KeyDown的事件处理,一次只能处理一个按键,
所以要解决这个问题,必须自己监听按键。
以最基本的画面更新速度FPS 30.0来说,这代表的是
每秒有30张祯数在跑(Frame Per Second),
也就是每秒处理30次画面动作。
所以需要产一个Thread,每秒工作30次。
(可以试试把 FPS_PAGE 改成10看看)
而在C#中,若产生控制项的Thread与进行操作的Thread不同,会发生错误。
所以自订一个控制项的委派方法去进行控制项操作(InvokeIfRequired)
另外在这个程式中,会用到两个数学式
1. 求两点距离
2. 单位移动位置
http://i.imgur.com/uYlbWHW.png
--------------------------------------------------
public partial class Form1 : Form
{
int MAX_W; //画面宽度上限
int MAX_H; //画面高度上限
int UNIT_W; //单位宽度
int UNIT_H; //单位高度
int UNIT_MOVE; //每次单位移动量
int FPS_TIME; //每次工作等待延迟
float FPS_PAGE = 30.0f;//每秒祯数
Point TARGET; //单位移动目标位置
Point UnitPos//单位位置
{
get
{
return this.Unit.Location;
}
set
{
this.Unit.Location = value;
}
}
public Form1()
{
InitializeComponent();
Point defaultPos = new Point() { X = 100, Y = 100 };//预设起始点
this.Unit.Location = defaultPos;//设定单位预设位置
TARGET = defaultPos;//设定单位移动目标位置
MAX_W = this.ClientSize.Width;
MAX_H = this.ClientSize.Height;
UNIT_W = this.Unit.Width;
UNIT_H = this.Unit.Height;
UNIT_MOVE = 2;
FPS_TIME = (int)(1000.0 / FPS_PAGE);
Task.Run(() => UnitWork());//产生一个Thread进行 单位工作
}
//单位移动处理
private void UnitWork()
{
while (true)
{
Thread.Sleep(FPS_TIME);
this.InvokeIfRequired(() =>
{
ProcessKeyDwon();//处理键盘事件
});
double dis = GetDistance();
if (dis == 0)
continue;
else if (dis <= UNIT_MOVE)
SetPostion(TARGET);
else
{
double m = UNIT_MOVE / dis;
Point movePos = TARGET;
movePos.X += (int)((UnitPos.X - TARGET.X) * m);//向量移动位置
movePos.Y += (int)((UnitPos.Y - TARGET.Y) * m);//向量移动位置
SetPostion(movePos);
}
}
}
//处理键盘事件
private void ProcessKeyDwon()
{
if (Keyboard.IsKeyDown(Key.Right))
TARGET.X += UNIT_MOVE;
if (Keyboard.IsKeyDown(Key.Left))
TARGET.X -= UNIT_MOVE;
if (Keyboard.IsKeyDown(Key.Up))
TARGET.Y -= UNIT_MOVE;
if (Keyboard.IsKeyDown(Key.Down))
TARGET.Y += UNIT_MOVE;
if (TARGET.X + UNIT_W > MAX_W)
TARGET.X = MAX_W - UNIT_W;
else if (TARGET.X < 0)
TARGET.X = 0;
if (TARGET.Y + UNIT_H > MAX_H)
TARGET.Y = MAX_H - UNIT_H;
else if (TARGET.Y < 0)
TARGET.Y = 0;
}
private double GetDistance()//求两点距离
{
double powX = Math.Pow(UnitPos.X - TARGET.X, 2);
double powY = Math.Pow(UnitPos.Y - TARGET.Y, 2);
return Math.Sqrt(powX + powY);
}
private void SetPostion(Point p)
{
this.InvokeIfRequired(() =>
{
UnitPos = p;
});
}
}
//扩充方法
public static class Extension
{
//非同步委派更新UI
public static void InvokeIfRequired(
this Control control, MethodInvoker action)
{
if (control.InvokeRequired)//在非当前执行绪内 使用委派
{
control.Invoke(action);
}
else
{
action();
}
}
}
--------------------------------------------------
注:
Keyboard.IsKeyDown 需要增加参考
1. PresentationCore.dll
2. WindowsBase.dll
并 using namesapce
System.Windows.Input
完成档(仅exe)
http://ppt.cc/YuOr
使用 .NET Framework 4.5
http://www.microsoft.com/zh-tw/download/details.aspx?id=30653
--
※ 发信站: 批踢踢实业坊(ptt.cc), 来自: 123.240.239.100
※ 文章网址: http://webptt.com/cn.aspx?n=bbs/C_Sharp/M.1403239991.A.74B.html
※ 编辑: VVll (123.240.239.100), 06/20/2014 14:35:46
1F:推 Abbee:受教了 06/20 15:00
2F:推 neo5277:推推~~ 06/21 02:04