Pygame move object position from one point to another at constant speed - python

I have a bunch of objects at different coordinates, and I need to animate them moving to another coordinate
ie.
one object is at coodinate (234,30) and I need it to go to (310,540).
How do I do this in pygame? I tried messing around with slope and stuff like that but I couldn't get my object,s position to smoothly go there.

Well, you should just change it's coordinates in your game loop.
There's two ways you can do this.
First, for example, if you want your object to move 50px per second, you should send your update function ticks in every frame, and then change your object's x and y coordinates by x + x_speed * ticks / 1000 (here, ticks is in miliseconds, so you should convert it to seconds).
def update_object(ticks):
object.x += float(x_speed) * ticks / 1000 # converting to float is needed
# this is your main game loop
time = pygame.time.Clock()
ticks = 0
while running:
...
update_object(ticks)
ticks = time.tick(30) # this 30 means time.tick() waits enough to make your max framerate 30
Note that you may need to convert object.x to int while you're blitting(or drawing) it to a surface. With this, your object moves same amount in every second.
Second way is moving your object in every frame. This means your object's speed may change depending on your frame rate(for example, in a crowded scene, your framerate may drop and this makes your objects move slower).
def update_object():
object.x += object_vx
object.y += object.vy
# this is your main game loop
while running:
...
update_object()
BTW, I forgot to mention your object implementation. My preferred way to save coordinates in my objects is by using pygame.Rect's. pygame.Rect has 4 properties, x, y, height, and width. With this you can also hold your object's sprite's length and height.
For example:
character = pygame.Rect(10, 10, 20, 30)
character_image = pygame.image.load(...)
screen.blit(character_image, character) # screen is you surface
And when you want to change your character's coordinates:
character.x += x_amount
character.y += y_amount

Related

Tkinter map mouse coordinates to figure size

I'm using Tkinter where an ASCII figure is printed on a label. I want it to change depending on where I click with the mouse, but I do not know how to tackle that problem. How would I map the mouse's coordinates so that it is restricted by a range, say [-n, n]? I am printing my mouse's (event.x, event.y) and I need those values restricted by the earlier stated interval. So instead of the values I get by moving my mouse ranging from 300 to 400, how can I map them to range from -15 to 15, for example?
Thank you in advance!
Edit: Here is what the program looks like - the center is the (0, 0) coordinate and I only want to be able to click on the sphere to rotate it. Therefore, I want to have my interval range from [-r, r] when clicking width the mouse.
Depends on your intervals. lets assume you have [-15,15], and mouse movement from 0-300, you map -15,15 onto [-150,150], which means that every spatial entity you move your mouse (1/150) is 15/150 = 0.1 step in the scale of your choice [-n,n], which you multiply with your mouse coordinate to get the corresponding value within your range [-n, n]. therefore its n*(n/m) with n being target interval and m being the coordinate interval. Why negative values? You must determine your [0,0] for your coordinate system, and this also depends on whether you want to increase size only or also shrink the figure. Maybe give some additional information or a code snippet!

Using Loops to Create Iterations of Graphic Objects

I have looked around for an answer to this but cannot seem to find a solution. I'd like the word function to create 10 identical circles with center points that have the same y coordinates but different x coordinates so that their spacing is 25 from one center point to the other. The functions that I have created are only drawing one iteration of the object and I cannot figure out how to fix this. Thank you for any help.
I have tried to create two separate functions. One defines the loop function that I would like to print 10 circles while appending a list of circles. The other function calls upon the draw function to draw all 13 circles.
def draw(window):
circles=[]
for i in range(10):
x=25
circle=Circle(Point(0+x,370),10)
circle.setFill("yellow")
circles.append(circle)
circle.draw(window)
return circles
def circleRow():
window=GraphWin("Window",400,400)
window.setBackground("red")
cicles1=draw(window)
circleRow()
I expected an output of 10 circles evenly spaced along the same y-coordinate but am only getting a single circle.
We could replace the (unused) iteration variable i with x instead and explicitly describe what range of values it should take on:
from graphics import *
def draw(window):
circles = []
for x in range(25, 275, 25):
circle = Circle(Point(x, 370), 10)
circle.setFill('yellow')
circle.draw(window)
circles.append(circle)
return circles
def circleRow():
window = GraphWin("Window", 400, 400)
window.setBackground('red')
circles = draw(window)
window.getMouse()
window.close()
circleRow()
There are various other valid ways to approach this.

Frame-independent movement issue in PyGame with Rect class

I'm writing a simple game with PyGame, and I've run into a problem getting things moving properly. I'm not experienced with game programming, so I'm not sure if my approach is even correct..
I have a class Ball, which extends PyGame's Sprite class. Each frame, the Ball object is supposed to move around the screen. I'm using frame-independent(?)/time-based movement with the time delta returned by PyGame's Clock object each time around. Such as,
class Ball(pygame.sprite.Sprite):
# . . .
def update(self, delta):
self.rect.x += delta * self.speed # speed is pixels per second
self.rect.y += delta * self.speed # ... or supposed to be, anyway
... and ...
class Game(object):
# . . .
def play(self):
self.clock = pygame.time.Clock()
while not self.done:
delta = self.clock.tick(self.fps) / 1000.0 # time is seconds
self.ball.update(delta)
PyGame's Sprite class is backed by a Rect object (rect) that tracks the sprite's position. And Rect's coordinates are automatically converted to integers whenever a value is updated. So, my problem is that each time update() is called, any extra fraction-of-a-pixel movement is lost, instead of being accumulated over time as it should. Speed in "pixels per second" isn't accurate this way. Even worse, if the amount of movement per frame is less than one pixel, the ball doesn't move at all for those frames, because it's always rounded down to zero. (i.e., no movement if pps < fps)
I'm not sure how to deal with this. I tried adding separate x and y values to Ball which aren't forced to be integers and updating the rect every time those change. That way the x and y values accumulate the fractions of a pixel as normal. As in,
class Ball(pygame.sprite.Sprite):
# . . .
def update(self, delta):
self.x += delta * self.speed
self.y += delta * self.speed
def getx(self):
return self._x
def setx(self, val):
self._x = val # this can be a float
self.rect.x = val # this is converted to int
def gety(self):
return self._y
def sety(self, val):
self._y = val # this can be a float
self.rect.y = val # this is converted to int
x = property(getx,setx)
y = property(gety,sety)
But that ends up being messy: it's easy to update the rect object when x and y change, but not the other way around. Not to mention the Rect object has lots of other useful coordinates that can be manipulated (like centerx, top, bottomleft, etc. -- which is why one would still want to move the rect directly). I'd more or less end up having to re-implement the whole Rect class in Ball, to store floats before it passes them down to the rect object, or else do everything based on just x and y, sacrificing some of the convenience of the Rect class either way.
Is there a smarter way to handle this?
I don't know if you still need the answer, but I figured this out a bit ago and thought I'd give this question an answer since I came across it in trying to figure out what was going on. (Thanks for helping me confirm the issue, by the way.)
You can make use of Python's round function. Pretty much, just throw what you want into that function, and it'll spit out a properly rounded number.
The first way I got it working was like this:
x = box['rect'].x
if leftDown:
x -= 300 * deltaTime
if rightDown:
x += 300 * deltaTime
box['rect'].x = round(x)
(Where my deltaTime is a float, being a fraction of a second.)
As long as you're putting the float value you get through the round function before applying it, that should do the trick. It doesn't have to use separate variables or anything.
It may be worth noting that you cannot draw in fractions of a pixel. Ever. If you're familiar with a Lite-Brite, pixels work in that way, being a single lit up light. That's why the number you use in the end has to be an integer.

Panda 3D updating end HPR in Lerp interval

So Panda3D has this option to update the starting position of a Lerp interval by using the parameter "bakeInStart", if we set it equal to 0. However, I can't find a solution to overcome this problem, which is updating the end HPR (yaw, pitch, roll) value each time there is a new iteration of the Lerp interval loop. I've managed to work around this to get the desired effect, but a whole screen of code had to be written (because of multiple intervals written in sequence). I've tried this so far to minimize code:
self.rotateTargets(0)
def rotateTargets(self, angle):
# Create Lerp intervals for each target orbit node to rotate all of the targets
# in a parallel sequence with easing
self.angle = angle
self.rotateTargets = Sequence(
Parallel(
LerpHprInterval(self.orbitNodes["orbit0"], 4, Point3(0, 0, self.angle+90), blendType = "easeInOut", bakeInStart = 0),
name = "rotateTargets0"), Func(self.targetReparent(self.orbitNodes["orbit0"].getR()))
self.rotateTargets.loop()
def targetReparent(self, newAngle):
# Define new angle
self.newAngle = newAngle
self.angle = self.newAngle
An assertion error appears in the console, but it is related to the imported functions, and not my code.

How to 'zoom' in on a section of the Mandelbrot set?

I have created a Python file to generate a Mandelbrot set image. The original maths code was not mine, so I do not understand it - I only heavily modified it to make it about 250x faster (Threads rule!).
Anyway, I was wondering how I could modify the maths part of the code to make it render one specific bit. Here is the maths part:
for y in xrange(size[1]):
coords = (uleft[0] + (x/size[0]) * (xwidth),uleft[1] - (y/size[1]) * (ywidth))
z = complex(coords[0],coords[1])
o = complex(0,0)
dotcolor = 0 # default, convergent
for trials in xrange(n):
if abs(o) <= 2.0:
o = o**2 + z
else:
dotcolor = trials
break # diverged
im.putpixel((x,y),dotcolor)
And the size definitions:
size1 = 500
size2 = 500
n=64
box=((-2,1.25),(0.5,-1.25))
plus = size[1]+size[0]
uleft = box[0]
lright = box[1]
xwidth = lright[0] - uleft[0]
ywidth = uleft[1] - lright[1]
what do I need to modify to make it render a certain section of the set?
The line:
box=((-2,1.25),(0.5,-1.25))
is the bit that defines the area of coordinate space that is being rendered, so you just need to change this line. First coordinate pair is the top-left of the area, the second is the bottom right.
To get a new coordinate from the image should be quite straightforward. You've got two coordinate systems, your "image" system 100x100 pixels in size, origin at (0,0). And your "complex" plane coordinate system defined by "box". For X:
X_complex=X_complex_origin+(X_image/X_image_width)*X_complex_width
The key in understanding how to do this is to understand what the coords = line is doing:
coords = (uleft[0] + (x/size[0]) * (xwidth),uleft[1] - (y/size[1]) * (ywidth))
Effectively, the x and y values you are looping through which correspond to the coordinates of the on-screen pixel are being translated to the corresponding point on the complex plane being looked at. This means that (0,0) screen coordinate will translate to the upper left region being looked at (-2,1.25), and (1,0) will be the same, but moved 1/500 of the distance (assuming a 500 pixel width window) between the -2 and 0.5 x-coordinate.
That's exactly what that line is doing - I'll expand just the X-coordinate bit with more illustrative variable names to indicate this:
mandel_x = mandel_start_x + (screen_x / screen_width) * mandel_width
(The mandel_ variables refer to the coordinates on the complex plane, the screen_ variables refer to the on-screen coordinates of the pixel being plotted.)
If you want then to take a region of the screen to zoom into, you want to do exactly the same: take the screen coordinates of the upper-left and lower-right region, translate them to the complex-plane coordinates, and make those the new uleft and lright variables. ie to zoom in on the box delimited by on-screen coordinates (x1,y1)..(x2,y2), use:
new_uleft = (uleft[0] + (x1/size[0]) * (xwidth), uleft[1] - (y1/size[1]) * (ywidth))
new_lright = (uleft[0] + (x2/size[0]) * (xwidth), uleft[1] - (y2/size[1]) * (ywidth))
(Obviously you'll need to recalculate the size, xwidth, ywidth and other dependent variables based on the new coordinates)
In case you're curious, the maths behind the mandelbrot set isn't that complicated (just complex).
All it is doing is taking a particular coordinate, treating it as a complex number, and then repeatedly squaring it and adding the original number to it.
For some numbers, doing this will cause the result diverge, constantly growing towards infinity as you repeat the process. For others, it will always stay below a certain level (eg. obviously (0.0, 0.0) never gets any bigger under this process. The mandelbrot set (the black region) is those coordinates which don't diverge. Its been shown that if any number gets above the square root of 5, it will diverge - your code is just using 2.0 as its approximation to sqrt(5) (~2.236), but this won't make much noticeable difference.
Usually the regions that diverge get plotted with the number of iterations of the process that it takes for them to exceed this value (the trials variable in your code) which is what produces the coloured regions.

Categories

Resources