Update an individual sprite in a game loop - python

I am trying to move only one sprite in a game loop including two sprites. I have included spr1 in the Bit.update() method so if w is pressed spr1.y -= 60. In other words the sprite is assigned to self in the hope that only spr1 will be moved when w is pressed. However, in the current code, pressing w moves both spr1 and spr2. How can I refer to and update only spr1 in the update method?
class Bit(games.Sprite):
def update(self):
if games.keyboard.is_pressed(games.K_w):
self = spr1
self.y -= 60
def main():
spr1_image = games.load_image("spr1.png")
spr1 = Bit(image = spr1_image,
x = games.screen.width / 10,
y = games.screen.height / 10)
spr2_image = games.load_image("spr2.png")
spr2 = Bit(image = spr2_image,
x = games.screen.width * 9 / 10,
y = games.screen.height * 9 / 10)
games.screen.add(spr1)
games.screen.add(spr2)
games.screen.mainloop()
main()

Edited
The two sprites have different behavior, so you need different classes for them.
In Bit, take out the self=spr1 line and you should be OK. In update(), self is whatever the current sprite is - spr1 or spr2.
In main, change spr2 to
spr2 = games.Sprite(image = spr2_image, # <---- changed class
x = games.screen.width * 9 / 10,
y = games.screen.height * 9 / 10)
Since spr2 doesn't need to respond to the keyboard, it doesn't need any behaviour that games.Sprite doesn't already provide. Therefore, you don't need to use Bit for it.
(Caveat: I haven't used livewires, so I may be missing something obvious :) )

Related

Python Turtle hold key function

I am attempting to make pong using Turtle, I have most things working, however, I would like to implement the ability to hold a key to move the bumpers up and down, rather than having to tap the key multiple times. These are my functions for movement so far.
def lbump_move_up():
x = lbump.ycor()
x += bumpspeed
if x > 240:
x = 240
lbump.sety(x)
def lbump_move_down():
x = lbump.ycor()
x -= bumpspeed
if x < -240:
x = -240
lbump.sety(x)
def rbump_move_up():
x = rbump.ycor()
x += bumpspeed
if x > 240:
x = 240
rbump.sety(x)
def rbump_move_down():
x = rbump.ycor()
x -= bumpspeed
if x < -240:
x = -240
rbump.sety(x)
turtle.listen()
turtle.onkey(lbump_move_up,'w')
turtle.onkey(rbump_move_up,'Up')
turtle.onkey(lbump_move_down,'s')
turtle.onkey(rbump_move_down,'Down')
turtle.onkey(ball_move,'Return')
I don't have a complete answer to this, as I came here looking for one myself. However, I have some progress on it that someone else could finish...
You can create a new class that calls like a recursive function as follows:
class function2:
def __init__(self,fun,args=None):
self.fun=fun
self.args=args
def begin_loop(self):
self.looping=True
self.loop()
def loop(self):
self.fun(self.args)
if self.looping: self.loop()
def end_loop(self):
self.looping=False
Now to tie it to your example, you can convert your functions into function2s and thus call them onkeypress as follows:
l_up=function2(lbump_move_up)
r_up=function2(rbump_move_up)
l_down=function2(lbump_move_down)
r_down=function2(rbump_move_down)
Wn=turtle.Screen()
Wn.onkeypress(l_up.begin_loop,'w')
Wn.onkeypress(r_up.begin_loop,'Up')
Wn.onkeypress(l_down.begin_loop,'s')
Wn.onkeypress(r_down.begin_loop,'Down')
Wn.onkeyrelease(l_up.end_loop,'w')
Wn.onkeyrelease(r_up.end_loop,'Up')
Wn.onkeyrelease(l_down.end_loop,'s')
Wn.onkeyrelease(r_down.end_loop,'Down')
Wn.listen()
So to the issue: RecursionErrors
If you want your function to cause a small change, then you'll need to hold the button for a long time and that causes RecursionErrors - which at least in this case don't seem to be affected by try/except statements.
Once again, sorry for the incomplete solution, but I feel like you can probably get away with larger movements in pong.
I had the same issue, but found the "onkeypress" function in the Turtle documentation (https://docs.python.org/3/library/turtle.html#turtle.onkeypress), which resolved the issue for me.
turtle.onkeypress(fun, key=None)
"onkeypress", will move the turtle as long as the key is pressed, while "onkey" will move it once when the key is released.
Example:
from turtle import Turtle, Screen
turtle = Turtle("turtle")
turtle.penup()
screen = Screen()
screen.listen()
def move_forward():
turtle.forward(20)
def move_backward():
turtle.backward(20)
screen.onkeypress(move_forward, "w")
screen.onkey(move_backward, "s")
screen.exitonclick()

Python class parameters, where to define

class Camera(object):
def __init__(self, win, x=0.0, y=0.0, rot=0.0, zoom=1.0):
self.win = win
self.x = x
self.y = y
self.rot = rot
self.zoom = zoom
cam = Camera(Window,1,1,1,1)
vs
class Camera(object):
def __init__(self, win, x, y, rot, zoom):
self.win = win
self.x = x
self.y = y
self.rot = rot
self.zoom = zoom
cam = Camera(Window,1,1,1,1)
So does the first block of code just make the class static where it can only be made and not adjusted with parameters? If so, what's the usefulness of this?
The first block of code just sets default values for those variables. When the class is initialised if they are passed to the class, then they will be set. Otherwise the class variables will contain the default values.
In the second block of code, by not setting a default value you are making those parameters required for the class.
See this question for a better explanation: Why do we use __init__ in python classes?
The difference between the first one and second one is: the first one has default values while the other one dosen't. For example with the first one
cam = Camera(Window) wouldn't give you an error (x=0.0, y=0.0, rot=0.0 and zoom=1.0 have a default assigned value).
But the second code block would give you an error if you were to create new instance of the class like this cam = Camera(Windows). Wich is ultimately the difference between your first code block and your second one.
Cheers!

can't get this python program to work [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 3 years ago.
Improve this question
This is the vector2 module:
class Vector2(object):
"this calculates the vector between two points"
def __init__(self , x = 0.0, y = 0.0):
self.x = x
self.y = y
def __str__(self):
return "( %s,%s )"%(self.x, self.y)
#classmethod
def from_points(cls,p1,p2):
return cls(p2[0]-p1[0],p2[1]-p1[1])
#the magnetude of a vector is the distance between two points
def get_magnetude(self):
return math.sqrt(self.x**2+self.y**2)
def normalize(self):
magnetude = self.get_magnetude()
self.x /= magnetude
self.y /= magnetude
#rhs stands for right hand side
def __add__(self,rhs):
return Vector2(self.x + rhs.x,self.y+rhs.y)
def __sub__(self,rhs):
return Vector2(self.x-rhs.x,self.y-rhs.y)
def __neg__(self):
return Vector2(-self.x, -self.y)
def __mul__(self,scalar):
return Vector2(self.x*scalar,self.y*scalar)
def __div__(self,scalar):
return Vector2(self.x /scalar, self.y/scalar)
And this is the main program, which imports vector2:
background_image_file = 'download.jpeg'
sprite_image_file = 'images.jpeg'
import math
import pygame
from pygame.locals import*
from sys import exit
import vector2
pygame.init()
screen = pygame.display.set_mode((640,480), 0 ,32)
background = pygame.image.load(background_image_file).convert()
sprite = pygame.image.load(sprite_image_file).convert_alpha()
clock = pygame.time.Clock()
position = Vector2(100.0, 100.0)#the starting point coordonates
heading = Vector2()#a vector without its magnetude(unit vector)
speed = 250.0
running = True
while running:
for event in pygame.event.get():
if event.type == QUIT:
exit()
if event.type == MOUSEBUTTONDOWN:
destination_x = event.pos[0]-sprite.get_width()/2
destination_y =event.pos[1]-sprite.get_height()/2
destination = (destination_x, destination_y)
heading = Vector2.get_magnetude(position,destination)#
heading.normalize()#a vector without magnetude,just direction
screen.blit(background, (0,0))
screen.blit(sprite, position)
time_passed = clock.tick()
time_passed_seconds = time_passed / 1000.0
distance_moved = time_passed_seconds * speed
position += (heading * distance_moved)
pygame.display.update()
I am learning Python and pygame by my self with (Beginning Game Development with Python and Pygame - From Novice to Professional (2007)) and I can't get the program to work. Also can someone please explain to me why the author use position = Vector2(100.0,100.0) and position = Vector2() to create new vectors?
It keeps saying :
traceback (most recent call last):
File "/home/moussa/Documents/python /vector_movement.py", line 21, in <module>
position = Vector2(100.0, 100.0)#the starting point coordonates
NameError: name 'Vector2' is not defined
I'm guessing that the code in the question is actually split between two files, one with the Vector2 class (in vector2.py) and the rest in some other file (which imports vector2).
The issue you're running into is that you're not accessing the class correctly. In your main module, you need to use vector2.Vector2 to access the class within its module.
Or, if you'd prefer to have easier access to the class, you could instead change your import from import vector2 to from vector2 import Vector2. This puts the class into the main module's namespace, so you can access it directly as Vector2.
As for the use of position = Vector2(100.0,100.0), this is a call to the Vector2 class's constructor. It creates an instance of the class, initializes it with the values 100 for x and 100 for y, and then binds it to the variable position. You can then use the various methods and operators that the class defines to update the instance, or get new values. For instance, the later line position += (heading * distance_moved) first multiplies the vector heading by the scalar distance_moved, then adds the vector result to position. You could do this with values in lists or tuples, but it would be much more complicated (you'd need to add and multiply the components of the vectors yourself).

Using VPython how to call Class sphere positions?

Through using VPython, I am able to get the program I am working on to generate multiple balls by calling the same class. I am also able to have the balls appear within a selected random range when they are generated (across x, y and z).
However, I am currently stumped on how I get to call the pos / position function from within my loop - as I would like to have the balls move.
Please see my code so far below.
If I call Ball.pos it states as undefined, but if I place my positioning via self.position, only one ball is generated, as they are not being referred to from under the sphere details?
from visual import *
from random import *
scene.title = "Multi Balls"
wallBm = box(pos=(0,-6,0), size=(12.2,0.1,12.1), color=color.blue, opacity=0.4)
vscale = 0.1
deltat = 0.005
t = 0
scene.autoscale = False
i = 0
totalBalls = 10
class Ball:
def __init__(self):
self.velocity = vector(0,5,0)
#vel sample ([5,10,15,20,25],3)
sphere (pos=(randrange (-6,6),randrange (-6,6),randrange (-6,6)), radius=0.5, color=color.cyan)
while True:
rate(100)
if i < totalBalls:
Ball()
i = i + 1
t = 5 + deltat
Try Inheritance from frame:
class Ball(frame):
def __init__(self, pos=(randrange (-6,6),randrange (-6,6),randrange (-6,6))):
frame.__init__(self,pos=pos)
self.velocity = vector(0,5,0)
sphere(frame=self,pos=pos,radius=0.5, color=color.cyan)
listOfBalls=[]
while True:
rate(100)
for i in range(totalBalls):
listOfBalls.append(Ball())
now try again!
You can call each Ball's position by calling listOfBalls[3].pos. I hope this helps!

Error with pymunk space.remove method

I have a ball generator, that "generates" and adds balls(circles) to the simulation.
The ball is to be removed when it hits a static poly in list s_boxes.
This is done by a collision handler ball_wall_collision.
The Error:
The following pop-up window does what it's name says, it pops-up
My code:
Ball Generator
class BallGenerator:
def __init__(self, min_y, max_y, x):
self.min = min_y
self.max = max_y
self.x = x
self.counter = 0
def bowl(self, balls):
global ball_bowled
y = random.randint(self.min, self.max)
pos = to_pymunk((self.x,y))
r = 10
m = 15
i = pm.moment_for_circle(m, 0, r)
b = pm.Body(m,i)
b.position = pos
f_x = random.randint(-600000,-400000)
b.apply_force( (f_x,0.0),(0,0) )
ball = pm.Circle(b, r)
ball.elasticity = 0.75
ball.friction = 0.95
balls.append(ball)
space.add(ball,b)
print 'bowled'
ball_bowled += 1
def handle(self, balls):
if self.counter == FPS:
self.bowl(balls)
self.counter = 0
self.counter += 1
Collision handler
def ball_wall_collision(space, arb, balls, s_boxes):
shapes = arb.shapes
boxes = [box[0] for box in s_boxes] # Get walls
ball = None
wall = None
for ba in balls:
if ba in shapes:
ball = ba
break
for box in boxes:
if box in shapes:
wall = box
break
if wall and ball:
print 'removing'
space.remove(ball, ball.body) # Where the runtime problem happens
balls.remove(ball)
print 'removed'
return False
else:
return True
space.add_collision_handler(0,0,begin=ball_wall_collision,
balls=balls,s_boxes=s_boxes) # Other args to function
What am I doing wrong in the collision handling??
Am I missing something in the call to space.remove?
Is the function not working as I want it to??
Or is the error elsewhere (which I don't think it is)...
It looks like the problem is that you try to remove objects from the space in a collision handler during the simulation step.
Instead you can try with either manually collect all the balls into a list and then call remove after the step, or queue up removes with the post step callback like this:
space.add_post_step_callback(space.remove, ball)
space.add_post_step_callback(space.remove, ball.body)
(untested code)
I should probably try and make this more obvious in the API docs.. I wonder if it would be a good idea to automatically schedule the remove until end of step, or the less intrusive option, trigger a assert in python so you dont get the c++ error.

Categories

Resources