|
Drag line with mouse on a fixed angle |
chelneru
Member #15,378
November 2013
|
Hi I know this is not Allegro related but I hope that maybe someone will explain me some things about analitical geometry. I have a line that has a point fixed on certain coordinates and the other one follows the mouse. The next thing that I want to do is when I press the left mouse button , the line is fixed on a certain angle pointing to my mouse and I can move it on the axis formed by the mouse and the fixed point. The mouse event is not a problem , the only thins is I don't know how to write it. Can you give me some hints or ideas how to do this ? |
LennyLen
Member #5,313
December 2004
|
I just want to paraphrase what you are saying so that we're on the same page. So basically what you want is when you have the mouse button pressed, and you move the muse towards the fixed point, the line will get shorter and if you move the mouse away from the fixed point the line will get longer. But so long as the mouse button is held down, the angle the line is on will remain the same. Is that correct? If so. The first thing I would do is calculate the x/y ratio. eg: float ratio = (mouse_x - initial_x) / (mouse_y - initial_y); and store either the x or y component at this time: float x_length = mouse_x - initial_x; Then I would calculate the length (actually, I'd calculate its square to save calculation on times) of the line as it stands right now: float initial_line_length = (mouse_x - initial_x) * (mouse_x - initial_x) + (mouse_y - initial_y) * (mouse_y - initial_y); Then do your loop that checks if the mouse is held down, and while it is, keep rechecking the new squared distance from the current position to the initial position: <code>float current_line_length = (mouse_x - initial_x) * (mouse_x - initial_x) + (mouse_y - initial_y) * (mouse_y - initial_y); The new x position for the end of the line is now: float new_x = initial_x + x_length * initial_line_length / current_line_length; The new y position is now: float new_y = initial_y + x_length * initial_line_length / current_line_length * ratio; If that causes the line to shrink and grow too quickly, just multiply the current_line_length value to some number between 0 and 1 until the speed is good for you.
|
chelneru
Member #15,378
November 2013
|
The initial_x and initial_y are the fixed point's coordinates ? What I want is when I press the mouse button the line won't get shorter it will be moved .Anyway I think your code gave me some help because I think the difference between getting shorter and be moved will be that for the move I also have to modify the fixed point coordinates. |
LennyLen
Member #5,313
December 2004
|
chelneru said: The initial_x and initial_y are the fixed point's coordinates ? Yes. I probably should have named them fixed_x and fixed_y. Quote: Anyway I think your code gave me some help because I think the difference between getting shorter and be moved will be that for the move I also have to modify the fixed point coordinates. That's even easier. First calculate the difference in position from the fixed point to the end of the line when you detect the mouse button is pressed, and store the mouse location: Now while the mouse is held down, just loop through the following, which determines how far the mouse has moved since you pressed the button and moves the line by that amount: The new line is drawn form x1, y1 to x2, y2.
|
chelneru
Member #15,378
November 2013
|
So , here's what I did : 1//Some code before....
2
3else if (events.type== ALLEGRO_EVENT_TIMER)
4{
5
6 al_get_mouse_state(&MouseState);
7 if (MouseState.buttons & 1)
8 {
9
10float mouse_clicked_x = mx; //When I press the mouse button
11 //I store the coordinates
12float mouse_clicked_y = my;
13
14
15
16}
17 else {
18
19
20//Now in the Timer event
21
22float x1 = mx - mouse_clicked_x; //If I add "+fixed_x" the line
23 //will be at a 'fixed_x' distance from the mouse
24float y1 = my - mouse_clicked_y;
25
26// I put at the third and forth parameter +200 because my line will always have
27
28//the same distance so I will not need the x_diff and y_diff
29al_draw_line(x1,y1,x1+200,y1+200,al_map_rgb(200,100,155),2);
30 }
But this will make a line (that has an angle of 90+ degrees I don't know why..???) that follows the mouse. I am sorry if I misunderstood what you were trying to explain but I want the line to move on a certain angle even if the mouse is not on the same angle. I want to make a pool game . This will help me with the cue. When I press the mouse button i want to drag the cue to set the force that will apply on the ball. So first I set the angle when I just move my mouse over the screen and then when I press the mouse button I only move the cue (line) on that angle that the line had immediately before i press the button. I was thinking to save the mouse coordinates and when I click , I see if the x is decreasing and if yes I will decrease the x coordinate of the line and with the line equation I find the y according to that x coordinate of the line . The problem is i can't seem to make it to work... I'm sorry if I'm confusing and hard to understand ,I hope you have the patience to explain me my problem |
ph03nix
Member #15,028
April 2013
|
A pool cue is pretty simple. Here's the pseudocode to get the cue's position: mouseX and mouseY are the mouse's current position, do not stop updating mouseX and mouseY while the mouse is pressed. ballX and ballY are the target ball's position cueAngle is the angle of the cue. Stop updating this when you click. Store it like this: cueAngle = atan2(mouseY - ballY, mouseX - ballX); EDIT: I'm guessing you want the cue to start from the ball's position. To do this just store this in a float called ballDist once when you click: ballDist = sqrt((mouseX-ballX)*(mouseX-ballX) + (mouseY-ballY)*(mouseY-ballY)); Then subtract ballDist from D in the code above. |
chelneru
Member #15,378
November 2013
|
I have this : 1while(!done)
2 {
3 ALLEGRO_EVENT events;
4 al_wait_for_event(event_queue,&events);
5
6
7if(events.type==ALLEGRO_EVENT_MOUSE_AXES)
8{
9
10
11 mx=events.mouse.x;
12 my=events.mouse.y;
13
14
15}
16
17 else if (events.type== ALLEGRO_EVENT_TIMER)
18{
19
20 al_get_mouse_state(&MouseState);
21 if (MouseState.buttons & 1)
22 {
23
24 mx=events.mouse.x;
25 my=events.mouse.y;
26
27 ballDist = sqrt((mx-ballX)*(mx-ballX) + (my-ballY)*(my-ballY));
28 float newAngle = atan2(my - ballY, mx - ballX) - cueAngle;
29 D = sqrt((mx-ballX)*(mx-ballX) + (my-ballY)*(my-ballY)) * cos(newAngle)-ballDist;
30 if(D < 0) D = 0;
31
32cueX = ballX + cos(cueAngle);
33cueY = ballY + sin(cueAngle);
34
35
36}
37
38
39 cueAngle = atan2(my - ballY, mx - ballX);
40
41 draw = true;
42
43}
44if (draw)
45{
46 draw = false;
47
48 al_draw_line(ballX,ballY,cueX,cueY,al_map_rgb(200,100,155),2);
49
50 al_flip_display();
51 al_clear_to_color(al_map_rgb(0,0,0));
52 }
When I run it i Get a line from the top left corner to the ball coordinates.When I press the mouse button I only see a point that it has a static move or something. Can you tell me how to apply your solution corectly ? Also Where I use the D variable ? |
ph03nix
Member #15,028
April 2013
|
Whoops, I wrote the code in wrong (it was pseudocode after all should be: EDIT: Also, this line should only be done once when you click, you seem to do it continuously when the mouse is down: ballDist = sqrt((mx-ballX)*(mx-ballX) + (my-ballY)*(my-ballY));
|
chelneru
Member #15,378
November 2013
|
So , I made the modification but now when I press the mouse button it only appears on ...(let's say the ball coordinates are the centre of the screen) 0 angle I mean it's a line from the ball's coordinates and horizontal to right and is blinking.Here is an image of what I got : click to see image Also ballDist can be optional ? because I have to write an another event so it's calculated only once when the button is pressed. EDIT: The cue's coordinates are wierd...here's another image with the coordinates that i 'am getting (the point is not very accurate but still ) |
ph03nix
Member #15,028
April 2013
|
Without "ballDist" the cue will jump to the mouse's distance relative to the ball instead of relative to the mouse's original position. You don't need another event, you can do something like this: 1//defined outside loop
2bool wasMousePressed = false;
3
4if (events.type== ALLEGRO_EVENT_TIMER) {
5 al_get_mouse_state(&MouseState);
6
7 //if mouse is currently pressed but was not pressed on the previous iteration
8 if((MouseState.buttons & 1) && !wasMousePressed){
9 ballDist = sqrt((mx-ballX)*(mx-ballX) + (my-ballY)*(my-ballY));
10 }
11
12 ...
13
14 //after all the cue logic
15 wasMousePressed = MouseState.buttons & 1;
16}
Try and see if that fixes it. |
chelneru
Member #15,378
November 2013
|
Here is my code : 1 while(!done)
2 {
3 ALLEGRO_EVENT events;
4 al_wait_for_event(event_queue,&events);
5
6if( events.type == ALLEGRO_EVENT_KEY_UP)
7{
8 switch(events.keyboard.keycode)
9 {
10 case ALLEGRO_KEY_ESCAPE:
11 done = true;
12
13 }
14}
15else if(events.type==ALLEGRO_EVENT_MOUSE_AXES)
16{
17
18
19 mx=events.mouse.x;
20 my=events.mouse.y;
21
22
23}
24
25 else if (events.type== ALLEGRO_EVENT_TIMER)
26{
27
28 al_get_mouse_state(&MouseState);
29 if((MouseState.buttons & 1) && !wasMousePressed)
30 {
31
32 ballDist = sqrt((mx-ballX)*(mx-ballX) + (my-ballY)*(my-ballY));
33 }
34
35 mx=events.mouse.x;
36 my=events.mouse.y;
37 float newAngle = atan2(my - ballY, mx - ballX) - cueAngle;
38 D = sqrt((mx-ballX)*(mx-ballX) + (my-ballY)*(my-ballY)) * cos(newAngle)-ballDist;
39 if(D < 0) D = 0;
40
41cueX = ballX + cos(cueAngle)*D;
42cueY = ballY + sin(cueAngle)*D;
43 cueAngle = atan2(my - ballY, mx - ballX);
44
45
46 wasMousePressed = MouseState.buttons & 1;
47}
48 draw = true;
49
50if (draw)
51{
52 draw = false;
53
54 al_draw_line(ballX,ballY,cueX,cueY,al_map_rgb(200,100,155),2);
55
56 al_flip_display();
57 al_clear_to_color(al_map_rgb(0,0,0));
58 }
59}
What/Where is the problem ?? Also it's ok with that wasMousePressed to be the only expression in that event ? I mean I thought "all the cue logic " should be in the braces of the if function where is the ballDist Atribution. |
ph03nix
Member #15,028
April 2013
|
Change this block of code: mx=events.mouse.x; my=events.mouse.y; float newAngle = atan2(my - ballY, mx - ballX) - cueAngle; D = sqrt((mx-ballX)*(mx-ballX) + (my-ballY)*(my-ballY)) * cos(newAngle)-ballDist; if(D < 0) D = 0; cueX = ballX + cos(cueAngle)*D; cueY = ballY + sin(cueAngle)*D; cueAngle = atan2(my - ballY, mx - ballX); to this: if(MouseState.buttons & 1){ mx=events.mouse.x; my=events.mouse.y; float newAngle = atan2(my - ballY, mx - ballX) - cueAngle; D = sqrt((mx-ballX)*(mx-ballX) + (my-ballY)*(my-ballY)) * cos(newAngle)-ballDist; if(D < 0) D = 0; cueX = ballX + cos(cueAngle)*D; cueY = ballY + sin(cueAngle)*D; }else{ cueAngle = atan2(my - ballY, mx - ballX); } hopefully this will make it perfect |
chelneru
Member #15,378
November 2013
|
When I click the line appears on good coordinates but the cue's coordinates are faar long, it keeps blinking and if I want to to move it , it's not any difference it's just blinking .I guess we advanced a little I think the problem is with the distance . In the console the coordinates for the cue are bad when i keep the mouse pressed and move the mouse , there are some negative/positive numbers with some 'e' .If you can help me with that too , i would be very grateful EDIT : The D variable when I keep the mouse button pressed is a changing values , even if the mouse is not moving (sometimes is 0 and some infinite values) |
ph03nix
Member #15,028
April 2013
|
Hard to say now, post the full code. I put the logic into a little flash program to test it and it works perfectly. See attached (If you don't have flash player open the file with your internet browser). |
chelneru
Member #15,378
November 2013
|
Here is the full code : 1#include <stdio.h>
2#include <allegro5/allegro.h>
3#include <allegro5/allegro_native_dialog.h>
4#include <allegro5/allegro_primitives.h>
5#include <allegro5/allegro_image.h>
6#include <iostream>
7#include <stdlib.h>
8#include <math.h>
9using namespace std;
10#define Screenwidth 800
11#define Screenheight 600
12
13#define PI 3.14
14bool wasMousePressed = false;
15
16float ballX=Screenwidth/2 ,ballY = Screenheight/2 ;
17int i,j,k=0;
18float bitmapw,bitmaph;
19float mx,my;
20float x,y,cueAngle,newAngle,cueX,cueY,D,ballDist;
21
22float angle;
23int v[1000][6];
24
25int main(int argc, char **argv)
26{
27 ALLEGRO_DISPLAY *display ;
28 const float FPS = 60.0;
29 if(!al_init()) {
30 al_show_native_message_box(NULL,NULL,NULL,"Could not initialize Allegro 5",NULL,NULL);
31 return -1;
32 }
33
34 al_set_new_display_flags(ALLEGRO_WINDOWED );
35 display = al_create_display(Screenwidth, Screenheight);
36 al_set_window_position(display,200,100);
37 al_set_window_title(display,"Test");
38 if(!display) {
39 al_show_native_message_box(display,"Sample Title","Display Settings","Display window was not created",NULL,ALLEGRO_MESSAGEBOX_QUESTION);
40 return -1;
41 }
42
43 al_init_primitives_addon();
44 al_install_keyboard();
45 al_install_mouse();
46 al_init_image_addon();
47
48
49 ALLEGRO_TIMER *timer= al_create_timer(1.0/FPS);
50 ALLEGRO_EVENT_QUEUE *event_queue = al_create_event_queue();
51 al_register_event_source(event_queue,al_get_timer_event_source(timer));
52 al_register_event_source(event_queue,al_get_display_event_source(display));
53 al_register_event_source(event_queue,al_get_mouse_event_source());
54 al_register_event_source(event_queue,al_get_keyboard_event_source());
55
56 bool done = false, draw = true;
57 ALLEGRO_MOUSE_STATE MouseState;
58
59al_start_timer(timer);
60 while(!done)
61 {
62 ALLEGRO_EVENT events;
63 al_wait_for_event(event_queue,&events);
64
65if( events.type == ALLEGRO_EVENT_KEY_UP)
66{
67 switch(events.keyboard.keycode)
68 {
69 case ALLEGRO_KEY_ESCAPE:
70 done = true;
71
72 }
73}
74else if(events.type==ALLEGRO_EVENT_MOUSE_AXES)
75{
76
77
78 mx=events.mouse.x;
79 my=events.mouse.y;
80
81
82}
83
84 else if (events.type== ALLEGRO_EVENT_TIMER)
85{
86
87 al_get_mouse_state(&MouseState);
88 if((MouseState.buttons & 1) && !wasMousePressed)
89 {
90
91 ballDist = sqrt((mx-ballX)*(mx-ballX) + (my-ballY)*(my-ballY));
92 }
93
94 if(MouseState.buttons & 1)
95
96 {
97 mx=events.mouse.x;
98 my=events.mouse.y;
99 float newAngle = atan2(my - ballY, mx - ballX) - cueAngle;
100 D = sqrt((mx-ballX)*(mx-ballX) + (my-ballY)*(my-ballY)) * cos(newAngle)-ballDist;
101 if(D < 0) D = 0;
102
103
104 cueX = ballX + cos(cueAngle)*D;
105 cueY = ballY + sin(cueAngle)*D;
106}
107 else{
108 cueAngle = atan2(my - ballY, mx - ballX);
109}
110
111
112 wasMousePressed = MouseState.buttons & 1;
113}
114
115
116 draw = true;
117
118
119if (draw)
120{
121 draw = false;
122
123 al_draw_line(ballX,ballY,cueX,cueY,al_map_rgb(200,100,155),2);
124
125 al_flip_display();
126 al_clear_to_color(al_map_rgb(0,0,0));
127 }
128}
129 al_destroy_display(display);
130 al_destroy_timer(timer);
131 al_destroy_bitmap(player);
132 al_destroy_event_queue(event_queue);
133
134 return 0;
135}
It might have some unused variables from my other tries ) EDIT : that flash is EXACTLY what I want to do ! |
ph03nix
Member #15,028
April 2013
|
The logic seems correct. The only problem I see is that you define newAngle at the top of your code and within the loop, maybe that causes it? Also, you should initialize cueAngle to 0 or something just to be safe. |
chelneru
Member #15,378
November 2013
|
If I remove from the top I get an error that it wasn't declared. In the console the cueAngle seems to be okay The newAngle is not really ok . If I click repeatedly in the same place it takes different values like: 0 , infinite values and sometimes normal numbers. EDIT: Can you post the flash's source ? Maybe I can find the problem by spending some time analyzing that perfect flash application |
ph03nix
Member #15,028
April 2013
|
Did you remove the declaration of cueAngle before the loop? I meant the declaration of newAngle before the loop instead. Try that first. Here's the full flash code if you want, but it's mostly identical to yours. 1import flash.events.MouseEvent;
2
3var cueAngle:Number = 0;
4var mousex:Number = 0;
5var mousey:Number = 0;
6var ballDist:Number = 0;
7var ballX:Number = 275;
8var ballY:Number = 200;
9var isDown:Boolean = false;
10var wasDown:Boolean = false;
11
12stage.addEventListener(MouseEvent.MOUSE_DOWN, mouse_isDown);
13stage.addEventListener(MouseEvent.MOUSE_UP, mouse_up);
14addEventListener(Event.ENTER_FRAME, gameLoop);
15
16function mouse_isDown(e:MouseEvent) {
17 isDown = true;
18}
19function mouse_up(e:MouseEvent) {
20 isDown = false;
21}
22function gameLoop(event:Event) {
23 mousex = stage.mouseX;
24 mousey = stage.mouseY;
25 if(!isDown){
26 cue_mc.x = ballX;
27 cue_mc.y = ballY;
28 //flash uses degrees instead of radians for movie clip rotation
29 cue_mc.rotation = Math.atan2(mousey - ballY, mousex - ballX)*180/Math.PI - 90;
30 }
31 if(isDown && !wasDown){
32 cueAngle = Math.atan2(mousey - ballY, mousex - ballX);
33 ballDist = Math.sqrt((mousex-ballX)*(mousex-ballX) + (mousey-ballY)*(mousey-ballY));
34 }
35 if(isDown){
36 var newAngle:Number = Math.atan2(mousey - ballY, mousex - ballX) - cueAngle;
37 var D:Number = Math.sqrt((mousex-ballX)*(mousex-ballX) + (mousey-ballY)*(mousey-ballY)) * Math.cos(newAngle) - ballDist;
38 D = Math.max(D, 0);
39
40 cue_mc.x = ballX + Math.cos(cueAngle) * D;
41 cue_mc.y = ballY + Math.sin(cueAngle) * D;
42 }
43 wasDown = isDown;
44}
|
chelneru
Member #15,378
November 2013
|
So based on your source I made some changes in my program : 1 while(!done)
2 {
3 ALLEGRO_EVENT events;
4 al_wait_for_event(event_queue,&events);
5
6if( events.type == ALLEGRO_EVENT_KEY_UP)
7{
8 switch(events.keyboard.keycode)
9 {
10 case ALLEGRO_KEY_ESCAPE:
11 done = true;
12
13 }
14}
15else if(events.type==ALLEGRO_EVENT_MOUSE_AXES)
16{
17
18
19 mx=events.mouse.x;
20 my=events.mouse.y;
21 cueAngle = atan2(my - ballY, mx - ballX);
22}
23
24 else if (events.type== ALLEGRO_EVENT_TIMER)
25{
26
27 al_get_mouse_state(&MouseState);
28 if((MouseState.buttons & 1) && !wasMousePressed)
29 {
30
31 ballDist = sqrt((mx-ballX)*(mx-ballX) + (my-ballY)*(my-ballY));
32 cueAngle = atan2(my - ballY, mx - ballX);
33 }
34
35 if(MouseState.buttons & 1)
36
37 {
38 float newAngle = atan2(my - ballY, mx - ballX) - cueAngle;
39 cout<<newAngle<<endl;
40 D = sqrt((mx-ballX)*(mx-ballX) + (my-ballY)*(my-ballY)) * cos(newAngle)-ballDist;
41 if(D < 0) D = 0;
42
43 cueX = ballX + cos(cueAngle)*D;
44 cueY = ballY + sin(cueAngle)*D;
45 }
46
47 wasMousePressed = MouseState.buttons & 1;
48}
49
50 draw = true;
51
52
53if (draw)
54{
55 draw = false;
56
57 al_draw_line(ballX,ballY,cueX,cueY,al_map_rgb(200,100,155),2);
58
59
60
61 al_flip_display();
62 al_clear_to_color(al_map_rgb(0,0,0));
63 }
64}
In the console the newAngle is always 0. And if I click the cue's coordinates are ok but if i go further than the ball's coordinates the distance between my mouse and the cue's coorinates gets higher.The other point it's just fixed in the center and the line gets shorter or longer and isn't on the same angle. Hope I didn't go backwards but do you see any more differences in my c source code and your flash source code ? EDIT: Now I declare my newAngle in the loop, and the cueAngle at the top and in the loop. |
ph03nix
Member #15,028
April 2013
|
Maybe take cueAngle = atan2(my - ballY, mx - ballX); out of the events.type==ALLEGRO_EVENT_MOUSE_AXES if statement? |
chelneru
Member #15,378
November 2013
|
Yes, that fixed the angle but the ball's coordinates don't change . I mean the cue doesn't not have a constant lenght and the fixed point just stays there ,fixed, and the line gets shorter or longer. I think this is only a problem at the screening..how I use the al_draw_line() function ? |
ph03nix
Member #15,028
April 2013
|
you should draw a line from cueX,cueY to a point further down the cue, for example al_draw_line(cueX,cueY, cueX + cos(cueAngle) * CUELENGTH, cueY + sin(cueAngle) * CUELENGTH,al_map_rgb(200,100,155),2); set CUELENGTH to some value, for example 100 |
chelneru
Member #15,378
November 2013
|
YES !:D It's working ! Thanks very much I really appreciate your help and sorry if I took much of your time |
|