2016-10-26 2 views
1

특정 거리에서 마우스 클릭 방향으로 모양을 이동하려고합니다. x 및 y 마우스 클릭 이벤트 및 거리를 x 및 y 마우스 클릭 위치를 얻고 나누기 위해 trunc 필요에 대한 변수를 만드는 시도했다 + 모양을 타이머를 사용하여 그 방향으로 이동하려면 trunc, 내 문제는 커서가 어디에 있든 상관없이 특정한 거리를 이동하는 셰이프가 필요하지만 방향을 마우스로 클릭하는 것만으로 셰이프는이 메서드를 사용하여 일정한 속도로 이동하지 않습니다. 아래로 마우스 :일정한 속도로 마우스 클릭 방향으로 도형을 움직이게하려면 어떻게해야합니까?

현재 코드

mx := x; 
my := y; 

타이머 :

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

내가 가지고있는 코드를 포함하도록 질문을 편집 해보십시오. –

+0

수정 해 주셔서 감사합니다. 하나의 질문이 더 많습니다. 특정 거리는 얼마입니까? –

+0

그러면 마우스 클릭으로 정의 된 일정한 속도로이 모양을 이동해야합니까? 그런 다음 마우스를 클릭하면 속도, vx 및 vy (x 및 y 구성 요소)를 계산하여 저장합니다. 각 타이머 이벤트에서 do do1.lft : = shape1.left + vx; shape1.top : = shape1.top + vy; –

답변

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; 

타이머 번호 : OrgPos.X + Round(StepCount * DeltaX); 계단식 에러 방지로 새로운 위치를 계산

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

한다.

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; 

그렇지 않으면, 더 우아하게, 당신은 부동에서 도형의 위치를 ​​저장할 수 있습니다 point 쌍을 지정하고 컨트롤의 위치를 ​​설정할 때만 정수로 반올림합니다. 이렇게하면 각 단계마다 정수 정밀도 문제가 발생하지 않습니다.

+0

고마워, 이건 내가 원하는 바로 그 것이다. 마우스를 클릭 한 곳이 아닌 셰이프를 설정된 거리만큼 이동시킬 수 있습니까? 예를 들어, 양식의 어딘가를 클릭하고 싶습니다. 모양이 마우스 클릭이 더 많거나 적 든간에 그 방향으로 100을 이동합니다. – User049

+0

@ User049 무엇이든 가능합니다. 이 대답이 무엇을하는지 이해한다면 어떻게해야하는지 분명해야합니다. –

+0

MX와 MY 값을 필요한 위치로 변환해야합니까? – User049

관련 문제