I'm not sure how to explain, but I'm trying to make game where player can walk on window and meet enemies etc.
I have code with one window. Like this:
window = pygame.display.set_mode((500, 480))
And my character can move left, right and jump on this window, but when he gets to the corner he stops. So my question is how to make him move further and, for example, change background, meet another enemies etc. when he walks?
Do I have to make a class and call her when character touch corner maybe?
I hope you understand.
Thanks.
You need to understand when your character touch / is close enough to the border of the screen and then take appropriate action.
In a game I'm writing for fun, the class representing the main character has a method to check when the character is inside a surface sface. I copy-paste its skeleton here to show an example:
def insidesurf(self, sface):
if sface.get_rect().contains(self.rect):
return None
else:
if self.rect.top < sface.get_rect().top:
#the character is going out from the screen from the top-side
elif self.rect.left < sface.get_rect().left:
#the character is going out from the screen from the left-side
elif self.rect.bottom > sface.get_rect().bottom:
#the character is going out from the screen from the bottom-side
elif self.rect.right > sface.get_rect().right:
#the character is going out from the screen from the right-side
This method is called at each iteration of the main loop after the character is moved (after a key press). The argument sface is your window.
What to do exactly in the various if statements is up to you. In my case, it redraws the screen replacing the character at the opposite side of the screen. If the character is exiting from left side, it's redrawn at right side, to give the impression that the camera is showing the next room and the character is at the same position.
You may also wish to not pass your window but a smaller surface in order to scroll the scenario instead of redrawing it all.
Related
The problem is that I need to write a function which will move the drawn circle around the field, an when the circle is going to leave the field it must appear from the opposite side of it (like that snake game on nokia phones, you know)
My progress at this:
def move_wrap(canvas, obj, move):
canvas.move(obj, move[0], move[1])
# if <left the field>:
# <move to the opposite edge>
I am sorry for such a question, UI is really not my thing. But I'm asked to write a game on tkinter, and I have to learn how it all works
I am using pygame 1.9.6 and python 3.7.7. I am looking for a way to have something drawn by pygame(or maybe even an image) that stays inside the window border(and stops when I release the key. I started with the “if keys[]:” method:
if keys[pygame.K_LEFT] and x>0:
x-=speed
that made it stay in bounds, but it only moved a few pixels and then did not repeat.
Next I tried the “event.key” method:
if event.type==pygame.KEYDOWN:
if event.key==pygame.K_LEFT:
xchange=-speed
ychange=-0
but that just makes the object move forever. I tried putting “and x>0” on the same line right after the direction, an “if x>0:” before, an “if x<0:” after, but the event never updates to see that the coordinates are past the edge, even with update commands. It just keeps going and going. I also don’t know how to make the object stop moving when I release the key, since event.key’s have the event always on.
Thank you for all the help you can offer.
In order for something to stay within a frame, you must check if it's coordinates are not past the border before moving it.
keys = pygame.key.get_pressed()
if(keys[K_LEFT]):
if(square.left > 0):
square.left -= 10
if(keys[K_RIGHT]):
if(square.right < 600):
square.left += 10
if(keys[K_UP]):
if(square.top > 0):
square.top -= 10
if(keys[K_DOWN]):
if(square.bottom < 600):
square.bottom += 10
This is an example of how you would do this with a Rect object, it checks for border and then moves the object if its within those border and the appropriate key is being pressed. I can't apply this to your code as I cannot see enough of it but you just have to replace the coordinates. For example, you might have thing.x instead of square.left
I am trying to create a game that places a cat which I can move left and right at the bottom of the screen.
Then I make a ball appear at a random position on the top of the screen and fall down the screen at a steady rate.
If the cat catches the ball by colliding with it, I make the ball disappear.
Meanwhile, I make a new ball each time the cat catches the ball or whenever the ball disappears off the bottom of the screen.
My question is: how do I make the ball disappear after being caught by the cat and then create a new ball over and over?
Currently I can think of two approaches to this problem:
First, I create a single ball. Once the cat catches the ball, I write some codes to make THAT ball disappear. Then, write some codes to create a new ball. Put these codes in a loop somehow to keep a ball disappear and reappear over and over. The problem is, I am not sure which codes to write to make a ball disappear and then create a new one.
Second approach is, I create a group of balls balls = Group() using pygame.sprite. I let those balls drop one after another. When a cat catches a ball, I remove that ball from the group of balls. Then let another ball in the group drop.
for ball in balls.copy():
if cat.rect.colliderect(ball.rect):
balls.remove(ball)
This second approach has somehow created another problem. When I wanted to specify the collision between the cat and each ball, I sometimes received the error message saying that either the name "ball" is not define or the name "balls" is not defined. Plus, I don't know whether it is really necessary to use a for loop whenever I want to specify a cat-ball collision. I feel that there has to be a more straight-forward and efficient way than this.
Would the first approach be better? If yes, please let me know how to make a ball disappear and to create a new ball immediately afterwards. THANK YOU SO MUCH!!
Probably the easiest way is to create a sprite with the following template:
class Ball(pygame.sprite.Sprite):
""" falls and restarts the ball position when ball hits the cat or the ground"""
def __init__(self):
""" setting up the ball image, rect, caught_by_cat flag etc. """
def update(self):
if self.hits_the_ground():
self.reset()
elif self.caught_by_cat:
self.reset()
else:
self.fall()
def reset(self):
""" randomize the ball position and set the ball rect to this position and resets the caught_by_cat flag """
def hits_the_ground(self):
""" checks whether ball hits the bottom of the board """
def fall(self):
""" move the ball rectangle with a steady speed """
and then after the initialization and adding it to the pygame.sprite.Group, in the game event loop simply:
sprite_group.update()
sprite_group.draw(screen)
Check for collision
if cat_collides_with_ball:
ball.caught_by_cat = True
This way you don't need to create many ball objects, you just need to restart the ball rect attribute to draw it in other place.
I have a single ball sprite and I don't really have a need for a group. I want to set that sprite to be deleted (or killed) when it reaches the end of the screen, also so it generates another one. I am trying to do this without a group and wanted to know if this is possible. Thank you for your expertise.
I tried self.kill() and kill.self in an update method for the sprite class. That didn't work. I tried to do a kill in the screen update loop for the application. That didn't work. I have done extensive research and all the answer are only when using groups. I also tried to do "if not pygame.surface.rect.contains(Ball())" and that didn't work. (It is something like that, I tried several variations of that expression.)
def update(self):
"""Move the ball down"""
self.y = self.y + 1
self.rect.y = self.y
#print("Screen is: " + str(pygame.surface.rect()))
print("Object is: " + str(self.rect))
if (self.rect.y >= 800):
self.kill()
def update_screen(screen, ball, lamp):
#Show on the screen
screen.fill((135,206,250))
lamp.blitme()
ball.blitme()
ballgen(screen)
ball.update()
lamp.update()
pygame.display.flip()
I expected the results to stop counting the rect of the ball, but it keeps counting up, thus making me think that it is not being removed.
If you don't use the Group class, there's no point in calling the Sprite.kill method. All it does is to remove the Sprite from all of its groups. Calling kill does not magically remove the Sprite from your game.
If you want to have a Sprite removed, just stop using it: either stop calling ball.blitme() and ball.update() in your update_screen function, or replace ball with a new instance of your Sprite's class.
But consider starting to actually use the Group class. It'll make your life easier.
To check if the ball is inside the screen, instead of
if not pygame.surface.rect.contains(Ball())
use
if not pygame.display.get_surface().get_rect().contains(self.rect):
self.rect.center = (whatever_new_position, ....)
in Ball's update method. pygame.display.get_surface() will get you the screen surface, get_rect() will get you the Rect of that Surface, and contains() will check if the Rect of the Ball is still inside the screen.
Then we just set a new position for the ball.
Also note that there's usually no need for an x and y attribute in a sprite class since the position is already stored in the rect attribute.
Assuming that my character is falling, and headed toward some sprite platform, and I flag that my character has landed once a collision is detected, what is the best way to reset my character's position - so that he is above the platform's rectangle or so that he is still clipping it?
My concerns are that if my character is above the platform's rectangle, than my function fall() will be called because he isn't touching anything, and if my character is clipping the platform's rectangle, than my jump() function may be hindered, because it may think he's landed as soon as he takes off. Obviously there are work arounds for either, but I'm really just looking for the convention, if there is one.
(I can post code if necessary, but the code isn't the issue. I'm really just looking for the right method)
Thanks,
Mike
I would have him touching the platform so that fall() is not called again.
and if my character is clipping the platform's rectangle, than my jump() function may be hindered, because it may think he's landed as soon as he takes off.
In the jump() function, when it moves the character make it so it cannot stop until it moves a minimum of x pixels.
You can do this by making a boolean to False at the beginning of jump() and having a counter to make it True after x pixels have been traversed. Make sure that x is just enough to get the character to stop clipping the platform, and not too much so it can collide with other things.
Once it has moved x pixels, then allow the collision testing to commence to see when the character hits something again.
So for example:
MINIMUM_DISTANCE = x
# ^ how many pixels you want to move to stop clipping
count = 0 #used for counting
def jump():
global count
in_air = False
#do your movements here, and increase count each time you move a pixel
if count >= MINIMUM_DISTANCE: in_air=True
if in_air:
#collision detection here
#once there is a collision:
if collision:
count = 0
return
And just for future reference, its better to post the code you have, even if it isn't a code related error. just so we can maybe see and get a feel for your approach
hope I could help