Simulation using python and graphics.py image - python

I am trying to create a simulator. (referring to John Zelle's graphics.py)
Basically, my object will make use of graphics.py to display the object as a circle. Then, using the .move method in the class in graphics.py, the object will move in the x direction and y direction. If the object is currently drawn, the circle is adjusted to the new position.
Moving just one object can easily be done with the following codes:
win = GraphWin("My Circle", 100, 100)
c = Circle(Point(50,50), 10)
c.draw(win)
for i in range(40):
c.move(30, 0) #speed=30
time.sleep(1)
win.close()
However, I want the program to display multiple circles at once that moves at different speed. I've created a Circle object class which takes speed as an input, and a list with 3 Circle objects in it
circle = []
circle1 = Car(40)
circle2= Car(50)
circle3 = Car(60)
In summary, my question is, how do make use of this list such that I am able to display and move multiple circles in one window at once using the methods available in graphics.py?

That all depends on how you create your Car class, but nothing stops you from using the same code to move multiple circles in the same refresh cycle, e.g.:
win = GraphWin("My Circle", 1024, 400)
speeds = [40, 50, 60] # we'll create a circle for each 'speed'
circles = [] # hold our circles
for speed in speeds:
c = Circle(Point(50, speed), 10) # use speed as y position, too
c.draw(win) # add it to the window
circles.append((c, speed)) # add it to our circle list as (circle, speed) pair
for i in range(40): # main animation loop
for circle in circles: # loop through the circles list
circle[0].move(circle[1], 0) # move the circle on the x axis by the defined speed
time.sleep(1) # wait a second...
win.close()
Of course, if you're already going to use classes, you might as well implement move() in it so your Car instances can remember their speed and then just apply it when you call move() on them in a loop.

Related

Moving a rectangle (or any kivy graphic) between 2 points

I would like to have a rectangle move between 2 points, so when the rectangle reaches point A it then moves back to point B. I am able to create a rectangle and animate the rectangle to move to a point but I'm unsure how I set up an 'if statement' to read the rectangles position and move it back.
def animate_the_button(self, *kwargs):
self.rect = Rectangle(pos=(75,10), size=(10,50))
self.canvas.add(self.rect)
anim = Animation(pos=(75,700))
anim.start(self.rect)
To call a function or method when an animation completes, use bind() with on_complete:
anim.bind(on_complete=self.animate_way_back)
Where animate_way_back() would be a method that sends the rectangle on its way back. See the documentation on Animation.
But since you seem to want it to keep bouncing back and forth, a repeating sequence of animations seems a better fit:
anim = Animation(pos=(75,700)) + Animation(pos=(75,10))
anim.repeat = True
anim.start(self.rect)

Python Turtle: Is it possible to use layers in fill command

I have recently been developing a software which will be used for creating fractal images. But I realized for it to fill the shapes it will need to be done in layers otherwise it will overwrite sections. Here is my current code:
import turtle
def CreatePolygon (turt, Side, Size):
if Size <= 1:
return
else:
#This will create a polygon of a certain size.
#And iterate smaller polygons inside each polygon thus creating a fractal.
for i in range (0, Side):
turt.forward(Size)
turt.left(360/Side)
CreatePolygon(turt, Side, Size/(Side-1))
Size = 250
t = turtle.Turtle()
t.hideturtle()
t.speed(0)
#Calling The Function
CreatePolygon (t, 5, Size)
My main intention is for the polygons to be filled by different colours which I understand how to do. The issue lies in the filled polygon being overwritten once the larger polygon it is inside gets filled. I'm not sure how to fix this issue as the requirements are:
Smaller Item Gets Filled First (Inside Bigger Item).
Bigger Item Gets Filled In Second While Not Filling In Where The Smaller Item Filled In.
We don't have layers in Python turtle but we can still achieve the effect you want with a little bit of duplication and rearrangement of code:
from turtle import Screen, Turtle
COLORS = ['red', 'green', 'blue', 'magenta', 'yellow', 'cyan']
def CreatePolygon(turt, sides, size, color=0):
if size <= 1:
return
# This will create a polygon of a certain size.
turt.fillcolor(COLORS[color])
turt.begin_fill()
for _ in range(sides):
turt.forward(size)
turt.left(360 / sides)
turt.end_fill()
# And iterate smaller polygons inside each polygon thus creating a fractal.
for _ in range(sides):
turt.forward(size)
turt.left(360 / sides)
CreatePolygon(turt, sides, size / (sides - 1), color + 1)
screen = Screen()
turtle = Turtle(visible=False)
# Calling The Function
screen.tracer(False)
CreatePolygon(turtle, 5, 250)
screen.tracer(True)
screen.exitonclick()
We have to draw the larger polygon first, fill it, and then recursively draw the smaller polygons.

PyGame Platformer with Interactive Platforms "Drawn" In

I'm looking for the easiest way to implement this. I'm trying to implement platforms (with full collision detection) that you can draw in via mouse. Right now I have a line drawing function that actually draws small circles, but they're so close together that they more or less look like a line. Would the best solution be to create little pygame.Rect objects at each circle? That's going to be a lot of rect objects. It's not an image so pixel perfect doesn't seem like an option?
def drawGradientLine(screen, index, start, end, width, color_mode):
#color values change based on index
cvar1 = max(0, min(255, 9 * index-256))
cvar2 = max(0, min(255, 9 * index))
#green(0,255,0), blue(0,0,255), red(255,0,0), yellow(255,255,0)
if color_mode == 'green':
color = (cvar1, cvar2, cvar1)
elif color_mode == 'blue':
color = (cvar1, cvar1, cvar2)
elif color_mode == 'red':
color = (cvar2, cvar1, cvar1)
elif color_mode == 'yellow':
color = (cvar2, cvar2, cvar1)
dx = end[0] - start[0]
dy = end[1] - start[1]
dist = max(abs(dx), abs(dy))
for i in xrange(dist):
x = int(start[0]+float(i)/dist*dx)
y = int(start[1]+float(i)/dist*dy)
pygame.draw.circle(screen, color, (x, y), width)
That's my drawing function. And here's my loop that I have put in my main game event loop.
i = 0
while (i < len(pointList)-1):
drawGradientLine(screen, i, pointList[i], pointList[i + 1], r, mode)
i += 1
Thanks for any help, collision detection is giving me a huge headache right now (still can't get it right for my tiles either..).
Any reason you want to stick with circles?
Rectangles will make the line/rectangle a lot more smooth and will make collision detecting a lot easier unless you want to look into pixel perfect collision.
You also don't seem to save your drawn objects anywhere (like in a list or spritegroup), so how are you going to check for collision?
Here's a leveleditor I did for game awhile back, it's not perfect, but it works:
https://gist.github.com/marcusmoller/bae9ea310999db8d8d95
How it works:
The whole game level is divided up into 10x10px grid for easier drawing
The leveleditor check if the mouse is being clicked and then saves that mouse position
The player now moves the mouse to another position and releases the mouse button, the leveleditor now saves that new position.
You now have two different coordinates and can easily make a rectangle out of them.
Instead of creating a whole bunch of rect objects to test collision against, I'm going to recommend creating something called a mask of the drawn-in collideable object, and test for collision against that. Basically, a mask is a map of which pixels are being used and which are not in an image. You can almost think of it as a shadow or silhouette of a surface.
When you call pygame.draw.circle, you are already passing in a surface. Right now you are drawing directly to the screen, which might not be as useful for what I'm suggesting. I would recommend creating a rect which covers the entire area of the line being drawn, and then creating a surface of that size, and then draw the line to this surface. My code will assume you already know the bounds of the line's points.
line_rect = pygame.Rect(leftmost, topmost, rightmost - leftmost, bottommost - topmost)
line_surf = pygame.Surface((line_rect.width, line_rect.height))
In your drawGradientLine function, you'll have to translate the point coordinates to the object space of the line_surf.
while (i < len(pointList)-1):
drawGradientLine(line_surf, (line_rect.x, line_rect.y), i, pointList[i], pointList[i+1], r, mode)
i += 1
def drawGradientLine(surf, offset, index, start, end, width, color_mode):
# the code leading up to where you draw the circle...
for i in xrange(dist):
x = int(start[0]+float(i)/dist*dx) - offset[0]
y = int(start[1]+float(i)/dist*dy) - offset[1]
pygame.draw.circle(surf, color, (x, y), width)
Now you'll have a surface with the drawn object blitted to it. Note that you might have to add some padding to the surface when you create it if the width of the lines you are drawing is greater than 1.
Now that you have the surface, you will want to create the mask of it.
surf_mask = pygame.mask.from_surface(line_surf)
Hopefully this isn't getting too complicated for you! Now you can either check each "active" point in the mask for collision within a rect from your player (or whatever other objects you want to collide withe drawn-in platforms), or you can create a mask from the surface of such a player object and use the pygame.Mask.overlap_area function to check for pixel-perfect collision.
# player_surf is a surface object I am imagining exists
# player_rect is a rect object I am imagining exists
overlap_count = surf_mask.overlap_area(player_surf, (line_rect.x - player_rect.x, line_rect.y - player_rect.y))
overlap_count should be a count of the number of pixels that are overlapping between the masks. If this is greater than zero, then you know there has been a collision.
Here is the documentation for pygame.Mask.overlap_area: http://www.pygame.org/docs/ref/mask.html#pygame.mask.Mask.overlap_area

Python using graphics.py

How do you trace on the graphics window where the user clicks?
I have to create a circle at the point they clicked and am not sure where to begin.
I tried;
win.getMouse()
center = Point(win.getMouse(),win.getMouse())
circ = Circle(center, 30)
circ.draw(win)
but obviously that doesn't work
Your initial code:
win.getMouse()
center = Point(win.getMouse(),win.getMouse())
circ = Circle(center, 30)
circ.draw(win)
can be edited to work and condensed to:
Circle(win.getMouse(), 30).draw(win)
That assumes win is an instance of the GraphWin class and has already been declared. win.getMouse returns a Point object, so there is no need to change a point into coordinate pairs just to change it back into a point...

Update one surface in Pygame

I have a game with a background made of tiles, some are static (grass, mud), but i want water to be flowing. i have created a surface called water, then i have a loop that iterates through a series of 10 pngs for the frames of the water flowing. i want to then update this surface 10x as often as the rest of the game, and blit it to the main surface at 30fps with the other objects.
However all i can achieve is no movement or the water flowing at insane speed(by updating the whole display in the water update loop.)
is there a way i can update just this surface?
here's my code:
#mud, grass and surface are defined earlier.
water = pygame.Surface((100,100))
#create mud tiles
for x in range(0,800,100):
for y in range(0, 500, 100):
screen.blit(mud,(x,y))
#create grass tiles
for x in range(400, 800, 100):
for y in range(0, 300, 100):
screen.blit(grass,(x,y))
#create filenames
for x in range(1,11):
if x < 10:
filename = "images\water\water1000" + str(x) + ".png "
else:
filename = "images\water\water100" + str(x) + ".png "
waterimg = pygame.image.load(filename)
#add to a surface, then tile the surface onto the game.
water.blit(waterimg,(0,0))
for x in range(100, 200, 100):
for y in range(0, 500, 100):
screen.blit(water, (x,y))
pygame.display.flip() #makes it update crazily. removing this line makes it not update at all.
allsprites.draw(screen)
pygame.display.flip()
It looks like you want to use pygame.display.update.
Just pass it a list of all the water tiles' rects, and it will only update those parts of the screen. The only thing is that you can't use it with pygame.OPENGL displays, apparently.
However, are you sure you want to animate your water at 300fps? It seems like you should just tell your draw method what tick you're up to, and use that to figure out which frame to display. e.g.
def draw(tick, (whatever other arguments you have...):
... #draw mud and grass
#the modulo operator % gets the remainder of the two numbers, so 12 % 10 = 2
filename = "images\water\water1000" + str(tick % 10) + ".png"
waterimg = pygame.image.load(filename)
... #blit the waterimg, but don't flip
Even better would be to load all your water tiles into a list before hand and use
waterimg = watertiles[tick % 10]
and number your images from 0-9 instead of 1-10.
Anyway, I hope this helps (and works).
Your code is not right. The general schema is (simplified: 1 update loop - 1 draw loop):
load_all_images_needed()
itime = time.time()
while 1:
now = time.time()
update(now, now - itime) # send absolute time and delta time
itime = now
draw()
flip()
You can use the absolute time to decide which frame water to use (i.e: water_images[int(now*10.0) % len(water_images)] for 10fps in water sprite)

Categories