Problem only drawing a line a certain length in game

• (7 Pages)
• 1
• 2
• 3
• Last »

103 Replies - 5585 Views - Last Post: 27 September 2011 - 07:40 AMRate Topic: //<![CDATA[ rating = new ipb.rating( 'topic_rate_', { url: 'https://www.dreamincode.net/forums/index.php?app=forums&module=ajax&section=topics&do=rateTopic&t=245442&amp;s=6fd6d7724aa0161d29ba70effdd37803&md5check=' + ipb.vars['secure_hash'], cur_rating: 0, rated: 0, allow_rate: 0, multi_rate: 1, show_rate_text: true } ); //]]>

#1 izthrower

Reputation: 13
• Posts: 233
• Joined: 11-February 09

Problem only drawing a line a certain length in game

Posted 30 August 2011 - 08:08 AM

```import pygame
from pygame.locals import *
from pygame.color import *
import pymunk as pm
from pymunk import Vec2d
import math
import sys
X,Y = 0,1
### Physics collision types
COLLTYPE_DEFAULT = 0
COLLTYPE_MOUSE = 1

def flipy(y):
"""Small hack to convert chipmunk physics to pygame coordinates"""
return -y+600

def mouse_coll_func(space, arbiter):
"""Simple callback that increases the radius of circles touching the mouse"""
s1,s2 = arbiter.shapes
return False

def main():

pygame.init()
screen = pygame.display.set_mode((600, 600))
clock = pygame.time.Clock()
running = True

### Physics stuff
pm.init_pymunk()
space = pm.Space()
space.gravity = Vec2d(0.0, -900.0)

#space.resize_static_hash()
#space.resize_active_hash()

## Balls
balls = []

### Mouse
mouse_body = pm.Body(pm.inf, pm.inf)
mouse_shape = pm.Circle(mouse_body, 3, Vec2d(0,0))
mouse_shape.collision_type = COLLTYPE_MOUSE

space.add_collision_handler(COLLTYPE_MOUSE, COLLTYPE_DEFAULT, None, mouse_coll_func, None, None)

### Static line
line_point1 = None
static_lines = []
run_physics = True

while running:
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
running = False

elif event.type == KEYDOWN and event.key == K_ESCAPE:
pygame.quit()
running = False

elif event.type == MOUSEBUTTONDOWN and event.button == 3:
p = event.pos[X], flipy(event.pos[Y])
body = pm.Body(10, 100)
body.position = p
shape = pm.Circle(body, 10, (0,0))
shape.friction = 0.5
balls.append(shape)

elif event.type == MOUSEBUTTONDOWN and event.button == 1:
if line_point1 is None:
line_point1 = Vec2d(event.pos[X], flipy(event.pos[Y]))
l1 = flipy(line_point1.y)
elif event.type == MOUSEBUTTONUP and event.button == 1:
if line_point1 is not None:

line_point2 = Vec2d(event.pos[X], flipy(event.pos[Y]))
l2 = flipy(line_point2.y)
lenline = l2-l1
print lenline
body = pm.Body(pm.inf, pm.inf)
shape= pm.Segment(body, line_point1, line_point2, 0.0)
shape.friction = 0.99
static_lines.append(shape)
line_point1 = None

elif event.type == KEYDOWN and event.key == K_SPACE:
run_physics = not run_physics

if running == False :
break

p = pygame.mouse.get_pos()
mouse_pos = Vec2d(p[X],flipy(p[Y]))
mouse_body.position = mouse_pos

if pygame.key.get_mods() & KMOD_SHIFT and event.type == MOUSEBUTTONDOWN and event.button == 3:
body = pm.Body(10, 10)
body.position = mouse_pos
shape = pm.Circle(body, 10, (0,0))
balls.append(shape)

### Update physics
if run_physics:
dt = 1.0/60.0
for x in range(1):
space.step(dt)

### Draw stuff
screen.fill(THECOLORS["white"])

# Display some text
font = pygame.font.Font(None, 16)
text = """RMB: Create ball
RMB + Shift: Create many balls
LMB: Drag to create wall, release to finish
Space: Pause physics simulation"""
y = 5
for line in text.splitlines():
text = font.render(line, 1,THECOLORS["black"])
screen.blit(text, (5,y))
y += 10

for ball in balls:
v = ball.body.position
rot = ball.body.rotation_vector
p = int(v.x), int(flipy(v.y))
p2 = Vec2d(rot.x, -rot.y) * r * 0.9
pygame.draw.circle(screen, THECOLORS["blue"], p, int(r), 2)
pygame.draw.line(screen, THECOLORS["red"], p, p+p2)

if line_point1 is not None:
p1 = line_point1.x, flipy(line_point1.y)
p2 = mouse_pos.x, flipy(mouse_pos.y)
pygame.draw.lines(screen, THECOLORS["black"], False, [p1,p2])

for line in static_lines:
body = line.body

pv1 = body.position + line.a.rotated(body.angle)
pv2 = body.position + line.b.rotated(body.angle)
p1 = pv1.x, flipy(pv1.y)
p2 = pv2.x, flipy(pv2.y)
pygame.draw.lines(screen, THECOLORS["lightgray"], False, [p1,p2])

### Flip screen
pygame.display.flip()
clock.tick(50)
pygame.display.set_caption("fps: " + str(clock.get_fps()))

if __name__ == '__main__':
doprof = 0
if not doprof:
main()
else:
import cProfile, pstats

prof = cProfile.run("main()", "profile.prof")
stats = pstats.Stats("profile.prof")
stats.strip_dirs()
stats.sort_stats('cumulative', 'time', 'calls')
stats.print_stats(30)

```

Im attempting a sort of line rider game in python. The one thing that im trying to figure out and having a problem with is while
the user is drawing a line is to only alow the line to be a curtain length before drawing another line, basicly im trying to create something like the pencil tool in MS paint so it alows the user to create curves without having to release the mouse button. Any ideas?
Thanks

Is This A Good Question/Topic? 0

Replies To: Problem only drawing a line a certain length in game

#2 Motoma

Reputation: 452
• Posts: 798
• Joined: 08-June 10

Re: Problem only drawing a line a certain length in game

Posted 30 August 2011 - 08:45 AM

The general algorithm for this would be:

• While the cursor is held down, poll the position of the mouse.
• If the position is a certain distance away from the last position, end the last line at this position, create a new line starting at this position.

#3 izthrower

Reputation: 13
• Posts: 233
• Joined: 11-February 09

Re: Problem only drawing a line a certain length in game

Posted 30 August 2011 - 05:10 PM

This is what i got so far.

```elif event.type == MOUSEBUTTONDOWN and event.button == 1:
if line_point1 is None:
line_point1 = Vec2d(event.pos[X], flipy(event.pos[Y]))
i = 0
x =0
while x == 0:
while i <= 100:
l1 = pygame.mouse.get_pos()
l2 = Vec2d(l1[X],flipy(l1[Y]))
body = pm.Body(pm.inf, pm.inf)
shape= pm.Segment(body, line_point1, l2, 0.0)
shape.friction = 0.99
static_lines.append(shape)
line_point1 = l2
i = i + 1
if event.type == MOUSEBUTTONUP and event.button == 1:
if line_point1 is not None:
line_point2 = Vec2d(event.pos[X], flipy(event.pos[Y]))
body = pm.Body(pm.inf, pm.inf)
shape= pm.Segment(body, line_point1, line_point2, 0.0)
shape.friction = 0.99
static_lines.append(shape)
line_point1 = None
x = 1

```

this is the changes to the program everything else is the same. So basicly what im doing is recording a point the first click then waiting and then recording where the mouse moved to and then drawing a line between the two points. The problems im having now is that
its not continuously recording the points and is stoping after the first two points. Also when releasing the mouse the line stays atached to the mouse. Any help?
Thanks

#4 Motoma

Reputation: 452
• Posts: 798
• Joined: 08-June 10

Re: Problem only drawing a line a certain length in game

Posted 30 August 2011 - 06:16 PM

The source of your problem is if line_point1 is None:. You see, line_point1 is only None on your first line.

#5 izthrower

Reputation: 13
• Posts: 233
• Joined: 11-February 09

Re: Problem only drawing a line a certain length in game

Posted 31 August 2011 - 07:45 AM

So do you think just removing that one line will fix the problem, because if you try to set line_point1 to none in
the while loops it works just like before i put in the while loops.
Thanks for your help so far.

#6 Motoma

Reputation: 452
• Posts: 798
• Joined: 08-June 10

Re: Problem only drawing a line a certain length in game

Posted 31 August 2011 - 08:16 AM

If I remember correctly, Pygame tracks mouse clicks and mouse releases, but not holding a mouse button down. As such, you will need to track the state of the drawing.

Pseudocode:
```if event.type == MOUSEBUTTONDOWN and event.button == 1:
draw = True
line_pos_1 = pygame.mouse.get_pos()
elif event.type == MOUSEBUTTONUP and event.button == 1:
draw = False
line_pos_2 = pygame.mouse.get_pos()
if draw:
if dist(line_pos_1, pygame.mouse.get_pos()) > 10:
line_pos_2 = pygame.mouse.get_pos()
line_pos_1 = pygame.mouse.get_pos()

```

#7 izthrower

Reputation: 13
• Posts: 233
• Joined: 11-February 09

Re: Problem only drawing a line a certain length in game

Posted 01 September 2011 - 08:46 AM

```elif event.type == MOUSEBUTTONDOWN and event.button == 1:
draw == True
line = pygame.mouse.get_pos()
line_point1 = Vec2d(line[X], flipy(line[Y]))

elif event.type == MOUSEBUTTONUP and event.button == 1:
draw == False
line2 = pygame.mouse.get_pos()
line_point2 = Vec2d(line2[X], flipy(line2[Y]))
body = pm.Body(pm.inf, pm.inf)
shape= pm.Segment(body, line_point1, line_point2, 0.0)
shape.friction = 0.99
static_lines.append(shape)

elif draw:
x = 0
while x < 100:
x=x +1

l1 = pygame.mouse.get_pos()
l2 = Vec2d(l1[X],flipy(l1[Y]))
body = pm.Body(pm.inf, pm.inf)
shape= pm.Segment(body, line_point1, l2, 0.0)
shape.friction = 0.99
static_lines.append(shape)
line_point1 = l2

```

Mabey what you trying to explain is going way over my head and is alot easyer that im making it to be but even with the changes above, its still not recording the points and when your release the mouse the line will draw but a new one will apear where the first one started and will stay atached to the mouse untill you click again and this happens every time. Any more help on how to get it to track the points properly?
Thanks

#8 Motoma

Reputation: 452
• Posts: 798
• Joined: 08-June 10

Re: Problem only drawing a line a certain length in game

Posted 01 September 2011 - 08:59 AM

Unfortunately this won't quite work how you anticipate:
```x = 0
while x < 100:
x=x +1

```

What I expect you are trying to do is base the length of the line on how long it has been held down. The code above is not quite right in this case.

You'll want it closer to something like this:
```            elif event.type == MOUSEBUTTONDOWN and event.button == 1:
draw == True
line = pygame.mouse.get_pos()
line_point1 = Vec2d(line[X], flipy(line[Y]))
x = 0
elif event.type == MOUSEBUTTONUP and event.button == 1:
draw == False
line2 = pygame.mouse.get_pos()
line_point2 = Vec2d(line2[X], flipy(line2[Y]))
body = pm.Body(pm.inf, pm.inf)
shape= pm.Segment(body, line_point1, line_point2, 0.0)
shape.friction = 0.99
static_lines.append(shape)
elif draw:
x += 1
if x > 100:
line2 = pygame.mouse.get_pos()
line_point2 = Vec2d(line2[X], flipy(line2[Y]))
body = pm.Body(pm.inf, pm.inf)
shape= pm.Segment(body, line_point1, line_point2, 0.0)
shape.friction = 0.99
static_lines.append(shape)
line_point1 = line2
x = 0

```

#9 izthrower

Reputation: 13
• Posts: 233
• Joined: 11-February 09

Re: Problem only drawing a line a certain length in game

Posted 01 September 2011 - 09:16 AM

```elif event.type == MOUSEBUTTONDOWN and event.button == 1:
draw == True
line = pygame.mouse.get_pos()
line_point1 = Vec2d(line[X], flipy(line[Y]))
x = 0

elif event.type == MOUSEBUTTONUP and event.button == 1:
line2 = pygame.mouse.get_pos()
line_point2 = Vec2d(line2[X], flipy(line2[Y]))
body = pm.Body(pm.inf, pm.inf)
shape= pm.Segment(body, line_point1, line_point2, 0.0)
shape.friction = 0.99
static_lines.append(shape)
draw == False
line_point1 = None

elif draw:
x += 1
if x > 2:
l1 = pygame.mouse.get_pos()
l2 = Vec2d(l1[X],flipy(l1[Y]))
body = pm.Body(pm.inf, pm.inf)
shape= pm.Segment(body, line_point1, l2, 0.0)
shape.friction = 0.99
static_lines.append(shape)
line_point1 = l2
x= 0

```

thats what im trying to do basicly when the user click the mouse have the computer basicly wait a set amount of time them find the mouse posision then draw the line to that possision, then set the begining point of the next segment to the end of the last segment. Figured out why the line was following the mouse had to put the line_point1 to none when the user releases the mouse. I can see where your going with this but i implemented it in to the code and it wont work idk if it me not using it right when the game starts or what. Also do i need to nest the elif draw statment in to one of the previous ones? And one last thing with the code you provided wont x always be zero cuz the computer will notice the mouse is down then will go to the draw statment add one to x and then will check to see what else is going on then notice that the mouse is down and set x to zero again? I just want to thank you for your help so far it has been rly helpful, it has gotten me closer to figuring out this pen thing. Any more help you can provide tho?
Thanks

#10 Motoma

Reputation: 452
• Posts: 798
• Joined: 08-June 10

Re: Problem only drawing a line a certain length in game

Posted 01 September 2011 - 10:40 AM

The event.MOUSEBUTTONDOWN event will only fire once, when the button is pressed, and will not fire again until the button is released and repressed. Therefore, in my code, x will only be set to zero when a new line gets created.

I don't usually do this, but I felt generous during my lunch break and fixed up your code.
```import pygame
from pygame.locals import *
from pygame.color import *
import pymunk as pm
from pymunk import Vec2d
import math
import sys
X,Y = 0,1
### Physics collision types
COLLTYPE_DEFAULT = 0
COLLTYPE_MOUSE = 1

def flipy(y):
"""Small hack to convert chipmunk physics to pygame coordinates"""
return -y+600

def mouse_coll_func(space, arbiter):
"""Simple callback that increases the radius of circles touching the mouse"""
s1,s2 = arbiter.shapes
return False

def main():

pygame.init()
screen = pygame.display.set_mode((600, 600))
clock = pygame.time.Clock()
running = True

### Physics stuff
pm.init_pymunk()
space = pm.Space()
space.gravity = Vec2d(0.0, -900.0)

#space.resize_static_hash()
#space.resize_active_hash()

## Balls
balls = []

### Mouse
mouse_body = pm.Body(pm.inf, pm.inf)
mouse_shape = pm.Circle(mouse_body, 3, Vec2d(0,0))
mouse_shape.collision_type = COLLTYPE_MOUSE

space.add_collision_handler(COLLTYPE_MOUSE, COLLTYPE_DEFAULT, None, mouse_coll_func, None, None)

### Static line
line_point1 = None
static_lines = []
run_physics = True

draw = False
while running:
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
running = False

elif event.type == KEYDOWN and event.key == K_ESCAPE:
pygame.quit()
running = False

elif event.type == MOUSEBUTTONDOWN and event.button == 3:
p = event.pos[X], flipy(event.pos[Y])
body = pm.Body(10, 100)
body.position = p
shape = pm.Circle(body, 10, (0,0))
shape.friction = 0.5
balls.append(shape)

elif event.type == MOUSEBUTTONDOWN and event.button == 1:
draw = True
dstep = 0

point1 = pygame.mouse.get_pos()
line_point1 = Vec2d(point1[X], flipy(point1[Y]))

elif event.type == MOUSEBUTTONUP and event.button == 1:
draw = False
point2 = pygame.mouse.get_pos()

line_point2 = Vec2d(point2[X], flipy(point2[Y]))
body = pm.Body(pm.inf, pm.inf)
shape= pm.Segment(body, line_point1, line_point2, 0.0)
shape.friction = 0.99
static_lines.append(shape)

elif event.type == KEYDOWN and event.key == K_SPACE:
run_physics = not run_physics

if running == False :
break

p = pygame.mouse.get_pos()
mouse_pos = Vec2d(p[X],flipy(p[Y]))
mouse_body.position = mouse_pos

if pygame.key.get_mods() & KMOD_SHIFT and event.type == MOUSEBUTTONDOWN and event.button == 3:
body = pm.Body(10, 10)
body.position = mouse_pos
shape = pm.Circle(body, 10, (0,0))
balls.append(shape)

### Update physics
if run_physics:
dt = 1.0/60.0
for x in range(1):
space.step(dt)

### Draw stuff
screen.fill(THECOLORS["white"])

if draw:
dstep += 1
print dstep

p1 = line_point1.x, flipy(line_point1.y)
p2 = mouse_pos.x, flipy(mouse_pos.y)
pygame.draw.lines(screen, THECOLORS["black"], False, [p1,p2])

if dstep > 5:
dstep = 0
point2 = pygame.mouse.get_pos()

line_point2 = Vec2d(point2[X], flipy(point2[Y]))
body = pm.Body(pm.inf, pm.inf)
shape= pm.Segment(body, line_point1, line_point2, 0.0)
shape.friction = 0.99
static_lines.append(shape)

line2 = pygame.mouse.get_pos()
line_point2 = Vec2d(line2[X], flipy(line2[Y]))
body = pm.Body(pm.inf, pm.inf)
shape= pm.Segment(body, line_point1, line_point2, 0.0)
shape.friction = 0.99
static_lines.append(shape)
line_point1 = line_point2

# Display some text
font = pygame.font.Font(None, 16)
text = """RMB: Create ball
RMB + Shift: Create many balls
LMB: Drag to create wall, release to finish
Space: Pause physics simulation"""
y = 5
for line in text.splitlines():
text = font.render(line, 1,THECOLORS["black"])
screen.blit(text, (5,y))
y += 10

for ball in balls:
v = ball.body.position
rot = ball.body.rotation_vector
p = int(v.x), int(flipy(v.y))
p2 = Vec2d(rot.x, -rot.y) * r * 0.9
pygame.draw.circle(screen, THECOLORS["blue"], p, int(r), 2)
pygame.draw.line(screen, THECOLORS["red"], p, p+p2)

for line in static_lines:
body = line.body

pv1 = body.position + line.a.rotated(body.angle)
pv2 = body.position + line.b.rotated(body.angle)
p1 = pv1.x, flipy(pv1.y)
p2 = pv2.x, flipy(pv2.y)
pygame.draw.lines(screen, THECOLORS["lightgray"], False, [p1,p2])

### Flip screen
pygame.display.flip()
clock.tick(50)
pygame.display.set_caption("fps: " + str(clock.get_fps()))

if __name__ == '__main__':
doprof = 0
if not doprof:
main()
else:
import cProfile, pstats

prof = cProfile.run("main()", "profile.prof")
stats = pstats.Stats("profile.prof")
stats.strip_dirs()

```

This post has been edited by Motoma: 01 September 2011 - 10:42 AM

#11 izthrower

Reputation: 13
• Posts: 233
• Joined: 11-February 09

Re: Problem only drawing a line a certain length in game

Posted 01 September 2011 - 02:33 PM

Reasons why your awesome. Thanks so much. Just so i know what you did could you just explain briefly what you changed from my code to make it work? So i can understand whats happening so i can improve my coding skills?
Thanks

#12 Motoma

Reputation: 452
• Posts: 798
• Joined: 08-June 10

Re: Problem only drawing a line a certain length in game

Posted 02 September 2011 - 06:12 AM

A number of things:

• I pulled the indentation for the if draw: to a higher scope (my mistake).
• I changed the draw == True and draw == False to draw = True and draw = False (I don't test my code before I post, apologies!)
• Moved the actual drawing of the line (while the mouse is held down) to inside the if draw: statement.
• Did some refactoring to make things more understandable.

#13 izthrower

Reputation: 13
• Posts: 233
• Joined: 11-February 09

Re: Problem only drawing a line a certain length in game

Posted 02 September 2011 - 06:53 AM

Thanks alot man. So as you know im making a line rider game basicly. In implementing a new type of line (a bouncy line) we ran in to problems. We basicly reused most of the code from the normal line to create this new type of line.
But like i said we ran in to some problems we are using a shift click now instead of a regular click like for the new line. Everything works fine but when you release the shift click it some times creates a new line by its self from the end to the beging of the line that you just drew, also some time it draws a double line. Not current by my computer or id provide some code for you. Any ideas on the trouble shoot, ill provide some code about 12 oclock this afternoon. and thanks for your help before
Thanks

#14 Motoma

Reputation: 452
• Posts: 798
• Joined: 08-June 10

Re: Problem only drawing a line a certain length in game

Posted 02 September 2011 - 06:57 AM

You've probably reused a variable (through errant copy-pasta) and are triggering both line drawing routines.

#15 izthrower

Reputation: 13
• Posts: 233
• Joined: 11-February 09

Re: Problem only drawing a line a certain length in game

Posted 02 September 2011 - 07:02 AM

Thats what i thought as well but we double checked them. The only other thing i thought was mabye that we didnt put the statments in the while running loop where the original ones are. And could be some how potentialy store the first and end point in there some how. Hopefuly when i post the code youll get a better idea what im talking about.