Loading [MathJax]/jax/output/CommonHTML/jax.js

Prijavi problem


Obeleži sve kategorije koje odgovaraju problemu

Još detalja - opišite nam problem


Uspešno ste prijavili problem!
Status problema i sve dodatne informacije možete pratiti klikom na link.
Nažalost nismo trenutno u mogućnosti da obradimo vaš zahtev.
Molimo vas da pokušate kasnije.

Reading mouse position

In PyGame, there is an easy way to to read the current state of the mouse. The data we are usually most interested in are mouse position and buttons being pressed. In this lesson we will use mouse position reading, and in the next mouse buttons. Aside from the position and the button presses, there is other information about the mouse that we can get, but we won’t do that here. Those interested can find more details for example here .

We can get the mouse position by calling the function pg.mouse.get_pos(), which returns an ordered pair of coordinates of the point where the mouse cursor is currently located.

As we will see in the examples and tasks that follow, the use of this function is very simple, and we can further use the read position of the mouse in various ways.

Examples and tasks

Example - a butterfly follows the mouse:

In this example, we load two butterfly images and display them alternately, as we did in the animations. What is new is that where we show the butterfly is determined by the mouse position we have obtained from the pg.mouse.get_pos() function.

../_images/butterfly1.png ../_images/butterfly2.png
 
1
import pygame as pg, petljapg, random
2
(width, height) = (400, 400)
3
canvas = petljapg.open_window(width, height, "Butterfly follows the mouse")
4
5
butterfly_images = [pg.image.load("butterfly1.png"), pg.image.load("butterfly2.png")]
6
i_image = 0
7
8
def new_frame():
9
    global i_image
10
    i_image = 1 - i_image # the two images are displayed alternately
11
    canvas.fill(pg.Color("white"))
12
    (mouse_x, mouse_y) = pg.mouse.get_pos()
13
    image = butterfly_images[i_image] # image to display
14
    # show the image centered
15
    (x, y) = (mouse_x - image.get_width() / 2, mouse_y - image.get_height() / 2)
16
    canvas.blit(image, (x, y))
17
18
petljapg.frame_loop(5, new_frame)
19

(PyGame__interact_butterfly1_eng)

You have probably noticed that when you move the mouse faster, the butterfly lags a little. This happens because only 5 frames are displayed per second, so the delay can be up to 0.2 seconds.

This delay is easily eliminated by increasing the frame rate (showing more frames per second), but then the images are switched too often and the butterfly flaps its wings too fast. The solution is to increase the frame rate, while displaying each image during multiple frames.

Task - move fast, flap slowly:

Copy the previous program here, then modify it so that the butterfly does not lag behind the mouse while the flapping speed remains the same.

Hint: in order for the butterfly not to lag, we certainly need more frames per second, for example n times more. This means that the new_frame function is called n times more often than before. In order to maintain the same flapping speed, each image needs to be displayed n times longer, that is, during n consecutive frames.

2

(PyGame__interact_butterfly2_eng)

Task - towards mouse: Write a program in which a green ball is moving towards the mouse, like in the example (“Play task” button).

Hint: In this task the key point is how the coordinates (x,y) of the center of the ball change. In a situation like the one in the picture, we want to increase x by dx and y by dy. Depending on how we want the ball to move, values dx, dy can be calculated in different ways. One easy way is to choose dx=110(xmx),dy=110(ymy).

../_images/towards_mouse.png
2

(PyGame__interact_towards_mouse_eng)

Task - towards mouse with trace: Copy the previous program and then modify it so that the ball leaves a gray trace, like in the example (“Play task” button).

Hint: The motion of the ball is same as in the previous example. To make a trace, we need to store a list of several (we used 20) previous positions of the ball.

When calculating a new state, we add the most recent position to the list, and if the list has become too long, we delete the oldest position.

When drawing a trace, for each circle we use color (shade, shade, shade), where shade equals 255 (white) before the loop, and in the loop it decreases by a certain value, so that in the last pass through the loop it becomes zero (black), or as close to zero as possible.

So, for example, if the list is called trace, these or similar statements should appear in your program:

trace = []
...

def new_frame():

    ...
    trace.append((x, y))
    ...
    if ...
        trace = trace[1:]
2

(PyGame__interact_towards_mouse_with_trace_eng)


Finally, you can try out the following two programs and play around with them.

In order to make programs like these, in addition to the programming techniques shown here, one needs some knowledge of physics (elastic force, Newton’s second law) and mathematics (Pythagorean theorem). Take a look at the programs without having to fully understand them. If you like, try modifying some constants a bit, so you can see how this affects the program’s behavior.

Example: Yо-yо

35
 
1
import pygame as pg, petljapg, math
2
(width, height) = (250, 250)
3
canvas = petljapg.open_window(width, height, "yoyo")
4
5
def distance(A, B):
6
    (xa, ya) = A
7
    (xb, yb) = B
8
    return math.sqrt((xa - xb)**2 + (ya - yb)**2)
9
10
(x, y) = (width // 2, height // 2) # ball position
11
(vx, vy) = (0, 0)                   # ball speed
12
rubber_band_length = 80
13
14
def new_frame():
15
    global x, y, vx, vy
16
    xm, ym = pg.mouse.get_pos()       # mouse position coordinates
17
    r = distance((x, y), (xm, ym))    # ball to mouse distance
18
    ax, ay = 0, 0                     # ball acceleration vector
19
    if r > rubber_band_length:
20
        # elastic force produces acceleration toward the mouse
21
        k = 0.0001*(r-rubber_band_length) 
22
        ax, ay = k * (xm - x), k * (ym - y)
23
    ay += 0.3                         # acceleration from ball weight
24
25
    vx, vy = vx + ax, vy + ay         # new speed
26
    x, y   = x + vx, y + vy           # new position
27
28
    # draw a green ball with a black rubber band on a white background
29
    canvas.fill(pg.Color("white")) 
30
    ix, iy = int(x), int(y)
31
    pg.draw.line(canvas, pg.Color("black"), (ix, iy), (xm, ym), 2)
32
    pg.draw.circle(canvas, pg.Color("green"), (ix, iy), 10)
33
34
petljapg.frame_loop(40, new_frame)
35

(PyGame__interact_yoyo_eng)

Example: Eyes

This program also requires a little more knowledge of mathematics, so we will not go into detail. If you are interested in how this program works and you аrе good at math, try to understand the details with some help.

33
 
1
import pygame as pg, petljapg, math
2
(width, height) = (400, 400)
3
canvas = petljapg.open_window(width, height, "Eyes")
4
5
# Function draws an eye whose center is at (cx, cy), radius is r, 
6
# and its pupil is positioned to look at the position of the mouse (mx, my)
7
def draw_eye(cx, cy, r, mx, my):
8
    pg.draw.circle(canvas, pg.Color("black"), (cx, cy), 2*r, 1)        # draw an eye
9
    D = math.sqrt((mx-cx)**2 + (my-cy)**2)          # mouse to eye center distance 
10
    # k is the part of the vector CM for which we move from the center of the eye
11
    k = r/D if D > r else 1 
12
    pupil_center = (cx + round(k*(mx-cx)), cy + round(k*(my-cy))) 
13
    pg.draw.circle(canvas, pg.Color("black"), pupil_center, r)     # draw pupil
14
15
def new_frame():
16
    global mouse_x, mouse_y
17
    (mouse_x, mouse_y) = pg.mouse.get_pos()     # mouse position coordinates
18
19
    canvas.fill(pg.Color("white"))   # paint background to white
20
    # draw both eyes using the auxiliary function
21
    draw_eye(left_eye_xc, left_eye_yc, pupil_r, mouse_x, mouse_y)
22
    draw_eye(right_eye_xc, right_eye_yc, pupil_r, mouse_x, mouse_y)
23
    
24
(canvas_xc, canvas_yc) = (width // 2, height // 2) # center of the window
25
eye_r = width // 8                                 # eye radius
26
pupil_r = eye_r // 2                               # pupil radius
27
left_eye_xc = canvas_xc - 3 * pupil_r              # x coordinate of center of left eye
28
right_eye_xc = canvas_xc + 3 * pupil_r             # x coordinate of center of right eye
29
left_eye_yc = right_eye_yc = canvas_yc             # y coordinate of centers of both eyes
30
(mouse_x, mouse_y) = pg.mouse.get_pos()
31
    
32
petljapg.frame_loop(50, new_frame)
33

(PyGame__interact_eyes_eng)