Re: [問題] 按鍵延遲的解決方法?
進階篇
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://www.ptt.cc/bbs/C_Sharp/M.1403239991.A.74B.html
※ 編輯: VVll (123.240.239.100), 06/20/2014 14:35:46
推
06/20 15:00, , 1F
06/20 15:00, 1F
推
06/21 02:04, , 2F
06/21 02:04, 2F
討論串 (同標題文章)
完整討論串 (本文為第 3 之 3 篇):
0
2
C_Sharp 近期熱門文章
PTT數位生活區 即時熱門文章