如何以恒定速度使鼠标单击方向移动?

时间:2016-10-26 14:56:03

标签: delphi

我正在尝试使鼠标单击一定距离的形状移动。我尝试为鼠标点击事件的x和y创建变量,并在x和y中创建到达鼠标点击位置的距离,并使用计时器划分+截断值以使形状在该方向上移动,虽然我的问题是我需要移动特定距离的形状,无论光标在哪里,只需使用鼠标单击方向,以及使用此方法不会以恒定速度移动的形状。

当前代码: 鼠标按下:

mx := x;
my := y;

计时器:

shape1.left := shape1.Left + (mx - shape1.left + 8) div 32;
shape1.top := shape1.top + (my - shape1.top + 8) div 32;

3 个答案:

答案 0 :(得分:5)

您的方法存在的问题是,您每单位时间移动的数量与形状和鼠标点击位置之间的距离成正比。从鼠标位置获得的所有方法都是一个方向,获得方向的标准方法是规范化感兴趣点之间形成的向量。

除以感兴趣点之间形成的线段的大小,在您想要的方向上产生长度为1px的单位矢量。然后必须通过速度缩放以产生运动增量。

这与整数一样笨拙,因为你的增量必须在每一步舍入,但可以按如下方式完成:

procedure TForm1.Timer1Timer(Sender: TObject);
const
  SPEED = 5;
var
  dx, dy : integer;
  mag : double;
begin
  dx := mx - Shape1.Left;                           {vector x}
  dy := my - Shape1.Top;                            {vector y}
  mag := Sqrt(dx*dx + dy*dy);                       {vector magnitude}  
  if (Abs(dx) > SPEED) or (Abs(dy) > SPEED) then 
  begin
    { use Ceil to move at least 1px. }
    Shape1.Left := Shape1.Left 
                   + Sign(dx)*Ceil(SPEED*Abs(dx)/mag);  {divide by mag}
    Shape1.Top := Shape1.Top                            {to give a unit}
                   + Sign(dy)*Ceil(SPEED*Abs(dy)/mag);  {vector in the}   
  end else begin                                        {required direction}
    Shape1.Left := mx;        {snap to mx/my if close enough}
    Shape1.Top := my;         {deals with rounding issues...}  
  end;
end;

否则,更优雅的是,您可以将形状的位置存储在浮点对中,并仅在设置控件的位置时舍入为整数。这避免了整个过程中每个步骤的整数精度问题。

答案 1 :(得分:1)

以下内容考虑了距离和恒定速度,并使用浮点数进行计算以获得更高的精度。

以下列形式声明:

private
  mx, my: integer; // mouse down
  Steps: integer;
  StepCount: integer;
  OrgPos: TPoint;  // original position
  TrgPos: TPoint;  // target position at angle and distance from orig. pos.
  DeltaX: single;  // x movement per step
  DeltaY: single;  // y movement per step

表格OnMouseDown:

var
  angle: single;
  dx, dy: single;
  dist: single;
begin
  mx := X;
  my := Y;
  Steps := 32;
  StepCount := 0;
  dist := 100.0;
  // shape origin
  OrgPos.X := Shape1.Left;
  OrgPos.Y := Shape1.Top;
  // get the angle
  dx := Abs(mx - OrgPos.X);
  if dx = 0 then dx := 0.00000001;
  dy := Abs(my - OrgPos.Y);
  if dy = 0 then dy := 0.00000001;
  angle := arctan(dy/dx);
  // correction for quadrant
  if (OrgPos.X>mx) and (OrgPos.Y<my) then angle := Pi-angle;
  if (OrgPos.X>mx) and (OrgPos.Y>my) then angle := Pi+angle;
  if (OrgPos.X<mx) and (OrgPos.Y>my) then angle := 2*Pi-angle;
  // endpoint based on angle and distance
  TrgPos.X := round(OrgPos.X + dist*cos(angle));
  TrgPos.Y := round(OrgPos.Y + dist*sin(angle));
  // x and y changes per step
  DeltaX := (TrgPos.X - OrgPos.X) / Steps;
  DeltaY := (TrgPos.Y - OrgPos.Y) / Steps;
  Timer1.Enabled := True;
end;

计时器代码:

  Inc(StepCount);
  Shape1.Left := OrgPos.X + Round(StepCount * DeltaX);
  Shape1.Top := OrgPos.Y + Round(StepCount * DeltaY);
  if StepCount >= Steps then
    Timer1.Enabled := False;

将新位置计算为OrgPos.X + Round(StepCount * DeltaX);可防止出现级联错误。

答案 2 :(得分:0)

无需使用计时器。如果按下鼠标左键,则可以移动形状。

Running experiment with config {
  "training": {
    "env": "Asteroids-v0",
    "run": "DQN",
    "stop": {
      "training_iteration": 1
    },
    "local_dir": "/opt/ml/output/intermediate",
    "checkpoint_freq": 10,
    "config": {
      "double_q": false,
      "dueling": false,
      "num_atoms": 1,
      "noisy": false,
      "prioritized_replay": false,
      "n_step": 1,
      "target_network_update_freq": 8000,
      "lr": 6.25e-05,
      "adam_epsilon": 0.00015,
      "hiddens": [
        512
      ],
      "learning_starts": 20000,
      "buffer_size": 1000000,
      "sample_batch_size": 4,
      "train_batch_size": 32,
      "schedule_max_timesteps": 2000000,
      "exploration_final_eps": 0.01,
      "exploration_fraction": 0.1,
      "prioritized_replay_alpha": 0.5,
      "beta_annealing_fraction": 1.0,
      "final_prioritized_replay_beta": 1.0,
      "num_gpus": 0.2,
      "timesteps_per_iteration": 10000
    },
    "checkpoint_at_end": true
  },
  "trial_resources": {
    "cpu": 1,
    "extra_cpu": 3
  }
}
Important! Ray with version <=7.2 may report "Did not find checkpoint file" even if the experiment is actually restored successfully. If restoration is expected, please check "training_iteration" in the experiment info to confirm.
Traceback (most recent call last):
  File "train-ray.py", line 83, in <module>
    MyLauncher().train_main()
  File "/opt/ml/code/sagemaker_rl/ray_launcher.py", line 332, in train_main
    launcher.launch()
  File "/opt/ml/code/sagemaker_rl/ray_launcher.py", line 313, in launch
    run_experiments(experiment_config)
  File "/usr/local/lib/python3.6/dist-packages/ray/tune/tune.py", line 296, in run_experiments
    experiments = convert_to_experiment_list(experiments)
  File "/usr/local/lib/python3.6/dist-packages/ray/tune/experiment.py", line 199, in convert_to_experiment_list
    for name, spec in experiments.items()
  File "/usr/local/lib/python3.6/dist-packages/ray/tune/experiment.py", line 199, in <listcomp>
    for name, spec in experiments.items()
  File "/usr/local/lib/python3.6/dist-packages/ray/tune/experiment.py", line 122, in from_json
    raise TuneError("No trainable specified!")
ray.tune.error.TuneError: No trainable specified!
2020-04-22 13:21:15,784 sagemaker-containers ERROR    ExecuteUserScriptError:
Command "/usr/bin/python train-ray.py --rl.training.checkpoint_freq 1 --rl.training.stop.training_iteration 1 --s3_bucket XXXXX

创建表单时。

var
 LeftMousePressed2 : Boolean ;
 X_original,Y_original : cardinal ;

在这里您可以获得鼠标的原始坐标

procedure TForm1.FormCreate(Sender: TObject);
begin
 LeftMousePressed2 := false ;
end;

移动(按下鼠标+左键)时,形状也会移动:

procedure TForm1.Shape1MouseDown(Sender: TObject; Button: TMouseButton;
   Shift: TShiftState; X, Y: Integer);
begin
if Button = mbLeft then
begin
   X_original:=x;
   Y_original:=y;
   LeftMousePressed2 := true ;
end;

从鼠标上抬起手指时

procedure TForm1.Shape1MouseMove(Sender: TObject; Shift: TShiftState; X,
  Y : Integer);
begin
if LeftMousePressed2 then
begin
  shape1.Left := Shape1.Left +(x-X_original);
  shape1.Top := shape1.Top + (y-Y_original);
end;
end;