Alright, finally we should be getting into some really cool stuff (how many times have I said that?). According to my book, the whole thing we did with the ball isn't very good for making games. Let's all just take a moment to bang our heads against a wall.
Well, there is a good reason. What if there was an actual background or multiple objects were moving on the screen (two things that you always, always see in a game)? Well, we have to use sprites, and conveniently enough, Pygame has something to help us with that.
Okay, you're probably asking, "what's a sprite?" People use that term to refer to practically anything in a 2D game (usually animated). Sprites have animations and interact with other objects on the screen. They also have sprite classes, the base class being Sprite (whoa, didn't see that coming). We use it as a template to create our own subclass, and the code to create it looks a little something like this:
class ObjClass(pygame.sprite.Sprite):
def __init__(self, image_file, location):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.image.load(image_file)
self.rect = self.image.get_rect()
self.rect.left, self.rect.top = location
So we basically tell the program we want to create a subclass (ObjClass), then we promise to define itself, the image, and the location. We initialize, or as I like to remember, "set" the self, and then we load the image. After that, we find the size of the image (because no matter the transparency, all pictures are square) and find the location. The location contains 2 items, x and y, so we were able to assign them to two items on the other side, left and top (the order in which they are listed counts!). Oh, and I almost forgot; the two main properties of a sprite is the image itself and the rectangular area around it.
Now that the subclass has been defined, we should actually use it. I'm thinking of using a different ball image (the old one is just a bit too big), so here's a new one! This image's size is 50x50.
That's better. I saved it as tinyball.png (but you can always use a different name if you want to). Since we used generic variables, we'll have to define those variables. I guess I'll add a bunch of balls so we'll be using a for loop in the program.
First, we have to define the image_file.
img_file="tinyball.png"
Note that img_file is a different variable than the one we used, image_file. This is because we do not directly define the image_file in the def block. Remember, you specify the object in the parenthesis of a def function when you trigger it.
Speaking of triggering the def, let's specify the location and image with for loops.
for x in range(0, 3):
for y in range(0, 3):
pos = [x * 130 + 10, y * 130 + 10]
ball = ObjClass(img_file, pos)
screen.blit(ball.image, ball.rect)
pygame.display.flip()
X resembles the x axis, and, you guessed it, y resembles the y axis. The x loop triggers the y loop which triggers the other stuff. Don't hurt your head thinking about it. It defines the position by taking the value of x and y's current iterations and doing a little math to them to change the position. We then assign the ObjClass to a variable called ball, in which we also define image_file as img_file and location as pos. It then is blitted onto the screen and the screen flips.
Remember, it's always a good idea to keep your programs as flexible as possible. There might be better ways to write this, but this was the only solution I found to the bug I encountered. You can try creating a more flexible version of this if you please.
Anyway, the program will then look like this.
...Nine balls? I'm honestly not entirely sure why there are NINE. But, I guess Python's going to do what Python's going to do.
I'm feeling pretty wasted by this article now. I guess I'll see you when I see you! But before I go...
Everyone programs a different way. I challenge you to find ways to program that feel the most comfortable, flexible, and/or efficient to you. You'll really have to think about this one!
Monday, February 9, 2015
Sunday, January 4, 2015
A Quick Tip: Perfect Side Switching
Last night I came up with an idea. Actually, I read it from my programming book, but it gave me an even better idea. So, I added a second challenge to the last article. The challenge was to make it so that when the ball went off one side of the screen, it reappeared on the other. The likeliest code you may have chosen would probably be the following.
import pygame, sys
import time
pygame.init()
screen=pygame.display.set_mode([640, 480])
screen.fill([255, 255, 255])
ball = pygame.image.load("Ball.png")
x=50
y=50
yspeed=5
screen.blit(ball, [x, y])
pygame.display.flip()
while True:
pygame.time.delay(20)
pygame.draw.rect(screen, [255, 255, 255], [x, y, 150, 150], 0)
y = y + yspeed
if y > screen.get_height():
y = -150
screen.blit(ball, [x, y])
pygame.display.flip()
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
sys.exit()
import pygame, sys
import time
pygame.init()
screen=pygame.display.set_mode([640, 480])
screen.fill([255, 255, 255])
ball = pygame.image.load("Ball.png")
x=50
y=50
yspeed=5
screen.blit(ball, [x, y])
pygame.display.flip()
while True:
pygame.time.delay(20)
pygame.draw.rect(screen, [255, 255, 255], [x, y, 150, 150], 0)
y = y + yspeed
if y > screen.get_height():
y = -150
screen.blit(ball, [x, y])
pygame.display.flip()
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
sys.exit()
This makes it so that if the y position goes past the bottom of the screen, it reappears 150 pixels (the ball's height) above the screen and sink back down again. This is nice and all, but the ball completely disappears before reappearing up top. That's when I started thinking, "What if you want to make a game with a topview but do not want players to hide freakin' off screen?" I, my friend, spent countless minutes to figure out the answer, but I have discovered it.
The trick I found is that we have to add TWO balls. This way, when a ball starts going off of the bottom of the screen, the other one starts appearing up top, so it's half of a ball on the bottom, half on the top.
Why don't you think about how to use this idea for a bit. If you want to be a programmer, you have to REALLY think and do your own things. Try tinkering with the code for a while and see what you come up with.
Done yet?
Okay. Well, I'll show you my thought process, step by step.
To start off, the 2nd ball has to be at a different height than the 1st one. The screen is 480 pixels tall, so that's how far apart they need to be at all times (because half on top, half on bottom? there is a 480 pixel difference). Ball 1 is at position 50, so at 480 pixels above is ball 2 at position -430.
import pygame, sys
import time
pygame.init()
screen=pygame.display.set_mode([640, 480])
screen.fill([255, 255, 255])
ball = pygame.image.load("Ball.png")
x=50
y=50
yspeed=5
y2 = -430
screen.blit(ball, [x, y])
pygame.display.flip()
That will set a ball way offscreen, but it will show itself as ball 1 is leaving. Speaking of leaving, when they reach point 480 (the number retrieved from the get_height function), they have to reappear back up. At first, I just set their points to 430, but I noticed that the top ball came down before the bottom ball even actually hit the bottom. Fatal common sense mistake, when in the first part of the program, ball 2 is at point 0 when ball 1 is at point 480. They ALWAYS have to be 480 pixels apart, so the point they teleport to has to be -480.
(Also, don't forget to do all the normal functions you did to ball 1 to ball 2 as well.)
while True:
pygame.time.delay(20)
pygame.draw.rect(screen, [255, 255, 255], [x, y, 150, 150], 0)
pygame.draw.rect(screen, [255, 255, 255], [x, y2, 150, 150], 0)
y = y + yspeed
y2 = y2 + yspeed
if y > screen.get_height():
y = -480
if y2 > screen.get_height():
y2 = -480
screen.blit(ball, [x, y])
screen.blit(ball, [x, y2])
pygame.display.flip()
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
sys.exit()
while True:
pygame.time.delay(20)
pygame.draw.rect(screen, [255, 255, 255], [x, y, 150, 150], 0)
pygame.draw.rect(screen, [255, 255, 255], [x, y2, 150, 150], 0)
y = y + yspeed
y2 = y2 + yspeed
if y > screen.get_height():
y = -480
if y2 > screen.get_height():
y2 = -480
screen.blit(ball, [x, y])
screen.blit(ball, [x, y2])
pygame.display.flip()
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
sys.exit()
Now run that program. the balls should move perfectly. Also, you might be wondering, "But this is insufficient! What if a deadly object hits one ball offscreen?" Come on, use your head! You can turn off the ball's reaction to anything if it is not onscreen. And if you're skeptic if this really is timed perfectly, just try recording it with something and slowing it down. I did that to answer the question, and it is flawless. Your eyes are just messing with you, dude.
Well, that's all I have to say on the matter. See you next time! Until then, I challenge you to, of course, experiment. Also, I believe you now know enough about blitting that you can try creating some sort of animation! Just, try it if you want to.
Oh... I forgot to say something. Just so you know, the pygame.time.delay function measures time in milliseconds, so that's why I set it to 2,000 a couple articles ago. Just thought you should know that.
Oh... I forgot to say something. Just so you know, the pygame.time.delay function measures time in milliseconds, so that's why I set it to 2,000 a couple articles ago. Just thought you should know that.
Subscribe to:
Posts (Atom)