'''
Created on 13.3.2016
worm game
#author: Hai
'''
import pygame
import random
from pygame import * ##
class Worm:
def __init__(self, surface):
self.surface = surface
self.x = surface.get_width() / 2
self.y = surface.get_height() / 2
self.length = 1
self.grow_to = 50
self.vx = 0
self.vy = -1
self.body = []
self.crashed = False
self.color = 255, 255, 0
def key_event(self, event):
""" Handle keyboard events that affect the worm. """
if event.key == pygame.K_UP and self.vy != 1:
self.vx = 0
self.vy = -1
elif event.key == pygame.K_RIGHT and self.vx != -1:
self.vx = 1
self.vy = 0
elif event.key == pygame.K_DOWN and self.vy != -1:
self.vx = 0
self.vy = 1
elif event.key == pygame.K_LEFT and self.vx != 1:
self.vx = -1
self.vy = 0
def move(self):
""" Moving worm """
self.x += self.vx # add vx to x
self.y += self.vy
if (self.x, self.y) in self.body:
self.crashed = True
self.body.insert(0, (self.x, self.y))
# Changes worm to right size so it is grow_to
if self.grow_to > self.length:
self.length += 1
# If body is longer than length then pop
if len(self.body) > self.length:
self.body.pop()
"""
def draw(self):
self.surface.set_at((int(self.x), int(self.y)), (255, 255, 255))
self.surface.set_at((int(self.last[0]),int(self.last[1])), (0,0,0))
"""
def position(self):
return self.x, self.y
def eat(self):
self.grow_to += 25
def draw(self):
x, y = self.body[0]
self.surface.set_at((int(x), int(y)), self.color)
x, y = self.body[-1]
self.surface.set_at((int(x), int(y)), (0, 0, 0))
# for x, y in self.body:
# self.surface.set_at((int(x), int(y)), self.color)
# pygame.draw.rect(self.surface, self.color, (self.x, self.y, 6, 6), 0)
# worm's head
class Food:
def __init__(self, surface):
self.surface = surface
self.x = random.randint(0, surface.get_width())
self.y = random.randint(0, surface.get_height())
self.color = 255,255,255
def draw(self):
self.surface.set_at((int(self.x),int(self.y)), self.color)
pygame.draw.rect(self.surface, self.color, (self.x, self.y, 6, 6), 0)
def position(self):
return self.x, self.y
""" Check if worm have eaten this food """
def check(self, x, y):
if x < self.x or x > self.x + 6:
return False
elif y < self.y or y > self.y + 6:
return False
else:
return True
def erase(self):
pygame.draw.rect(self.surface, (0,0,0), (int(self.x), int(self.y), 6, 6), 0)
w = h = 500
screen = pygame.display.set_mode((w, h))
clock = pygame.time.Clock()
pygame.mixer.init()
chomp = pygame.mixer.Sound("bow.wav")
score = 0
worm = Worm(screen) ###
food = Food(screen)
running = True
while running:
# screen.fill((0, 0, 0)) optimized in worm draw()
worm.draw()
food.draw()
worm.move()
if worm.crashed or worm.x <= 0 or worm.x >= w-1 or worm.y <= 0 or worm.y >= h-1:
print("U lose")
running = False
elif food.check(worm.x, worm.y):
worm.eat()
food.erase()
chomp.play()
score += 1
print("Score is: %d" % score)
food = Food(screen)
for event in pygame.event.get():
if event.type == pygame.QUIT: # Pressed X
running = False
elif event.type == pygame.KEYDOWN: # When pressing keyboard
worm.key_event(event)
pygame.display.flip()
clock.tick(100)
hello i am getting error
x, y = self.body[0]
IndexError: list index out of range
and i am doing this tutorial:
https://lorenzod8n.wordpress.com/2008/03/01/pygame-tutorial-9-first-improvements-to-the-game/
I am very new to python, plz help me
The problem is that in your class's __init__ function, you define self.body = []. This means that the list contains 0 items.
Later in your code, you reference self.body[0] and self.body[1], which are the first and second items in the list. Since these do not exist, an error is raised. To fix this, you need to initialize self.body with two items.
Based on the order of the operations you are doing, your body list is actually still empty. Follow the logic of your code, and you will see.
You start by instantiating your worm here:
worm = Worm(screen) ###
So, if you look at the __init__ of Worm, you are setting self.body to an empty list [].
If you follow all the code that happens from then until you actually call:
worm.draw()
You are never actually inserting anything on to your body list. So, when you try to access your body list inside your draw method:
error x, y = self.body[0]
You are definitely going to get an index out of range error, since there is nothing to access.
To rectify this you need to either provide a default like:
# arbitrary data
self.body = [0, 0]
Or, determine in your draw method how to handle empty lists using some condition like:
if self.body:
# do things
In your Worm's __init__ function you can set self.body[] to self.body[(0, 0)], this works. The error is raised because you defined an empty list at the beginning and later you tried to get an item from the list by passing an index (self.body[0]). But because the list is empty, Python cannot get the asked value.
Hope this helps!
Related
This question already has an answer here:
How do I get the snake to grow and chain the movement of the snake's body?
(1 answer)
Closed 2 years ago.
I finally figured out how to add body parts to my snake, but they add on in an unusual way. I have been struggling on this for a while, and finally made it so they append. But they don't do it correctly. It seems like they append 1 pixel behind instead of a full bodies length. Does anyone know why?
# Constants
WIN_WIDTH = 500
WIN_HEIGHT = 600
HALF_WIN_WIDTH = WIN_WIDTH / 2
HALF_WIN_HEIGHT = WIN_HEIGHT / 2
FPS = 10
# Colors
WHITE = (255, 255, 255)
BLACK = (0, 0, 0)
RED = (255, 0, 0)
GREEN = (0, 255, 0)
BLUE = (0, 0, 255)
DARK_GREEN = (0, 100, 0)
YELLOW = (255, 255, 0)
# Variables
screen = pygame.display.set_mode((WIN_WIDTH, WIN_HEIGHT))
pygame.display.set_caption("Snake")
clock = pygame.time.Clock()
running = True
class Text:
def __init__(self, x, y, size, font, color, text):
self.x = x
self.y = y
self.size = size
self.font = font
self.color = color
self.text = text
def draw(self):
self.my_font = pygame.font.SysFont(self.font, self.size)
self.text_surface = self.my_font.render(self.text, True, self.color)
screen.blit(self.text_surface, (self.x, self.y))
class Food:
def __init__(self, x, y):
self.x = x
self.y = y
self.width = 25
self.height = 25
def draw(self):
self.rect = (self.x, self.y, self.width, self.height)
pygame.draw.rect(screen, BLUE, self.rect)
def events(self):
pass
def update(self):
pass
class Body:
def __init__(self, x, y):
self.x = x
self.y = y
self.width = 25
self.height = 25
def draw(self):
self.rect = pygame.Rect(self.x, self.y, self.width, self.height)
pygame.draw.rect(screen, YELLOW, self.rect)
# Snake class
class Snake:
def __init__(self, x, y):
self.x = x
self.y = y
self.width = 25
self.height = 25
self.direction = 1
self.kill = False
self.collide = False
self.speed = 3
self.score = 0
self.bodies = []
def draw(self):
self.rect = pygame.Rect(self.x, self.y, self.width, self.height)
pygame.draw.rect(screen, BLACK, self.rect)
def events(self):
# change direction on key press
self.keys = pygame.key.get_pressed()
if self.keys[pygame.K_UP] and self.direction != 3:
self.direction = 1
if self.keys[pygame.K_DOWN] and self.direction != 1:
self.direction = 3
if self.keys[pygame.K_LEFT] and self.direction != 2:
self.direction = 4
if self.keys[pygame.K_RIGHT] and self.direction != 4:
self.direction = 2
if self.rect.colliderect(food.rect):
self.speed += 0.5
food.x = random.randint(0, WIN_WIDTH)
food.y = random.randint(0, WIN_HEIGHT)
self.score += 5
self.colliide = False
self.bodies.append(Body(0, 0))
# Move the end bodies first in reverse order
for i in range(len(self.bodies)-1, 0, -1):
x = snake.bodies[i-1].x
y = snake.bodies[i-1].y
snake.bodies[i].x = x
snake.bodies[i].y = y
snake.bodies[i].draw()
# Move body 0 to where the head is
if len(snake.bodies) > 0:
x = snake.x
y = snake.y
snake.bodies[0].x = x
snake.bodies[0].y = y
snake.bodies[0].draw()
def update(self):
# move
if self.direction == 1:
self.y -= self.speed
if self.direction == 2:
self.x += self.speed
if self.direction == 3:
self.y += self.speed
if self.direction == 4:
self.x -= self.speed
# if on edge of screen
if self.rect.right > WIN_WIDTH:
self.kill = True
if self.x < 0:
self.kill = True
if self.y < 0:
self.kill = True
if self.rect.bottom > WIN_HEIGHT:
self.kill = True
# Create the snake object
snake = Snake(HALF_WIN_WIDTH, HALF_WIN_HEIGHT)
food = Food(random.randint(0, WIN_WIDTH), random.randint(0, WIN_HEIGHT))
# Main Loop
while running:
score_text = Text(220, 5, 40, 'arial', WHITE, f'Score: {snake.score}')
# Draw
screen.fill(DARK_GREEN)
snake.draw()
food.draw()
score_text.draw()
# Event handling
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
sys.exit()
if snake.kill:
running = False
snake.events()
# Update
snake.update()
food.update()
clock.tick(60)
pygame.display.update()
Thank you very much!
You have to track the positions which have been met by the snake. Add a list attribute self.position to the class Snake:
class Snake:
def __init__(self, x, y):
# [...]
self.positions = [(self.x, self.y)]
# [...]
Add the new position to the list when the snake moves:
class Snake:
# [...]
def update(self):
# move
if self.direction == 1:
self.y -= self.speed
if self.direction == 2:
self.x += self.speed
if self.direction == 3:
self.y += self.speed
if self.direction == 4:
self.x -= self.speed
# add ne position
if self.x != self.positions[0][0] or self.y != self.positions[0][1]:
self.positions.insert(0, (self.x, self.y))
Update the x and y coordinate of the body along the stored positions in events. Define a distance between the parts of the body (e.g. 35). And use a method getPos to get the position of a part, by its index:
class Snake:
# [...]
def events(self):
# change direction on key press
self.keys = pygame.key.get_pressed()
if self.keys[pygame.K_UP] and self.direction != 3:
self.direction = 1
if self.keys[pygame.K_DOWN] and self.direction != 1:
self.direction = 3
if self.keys[pygame.K_LEFT] and self.direction != 2:
self.direction = 4
if self.keys[pygame.K_RIGHT] and self.direction != 4:
self.direction = 2
if self.rect.colliderect(food.rect):
self.speed += 0.5
food.x = random.randint(100, WIN_WIDTH - 125)
food.y = random.randint(150, WIN_HEIGHT - 175)
self.score += 5
self.colliide = False
self.bodies.append(Body(0, 0))
# Move the end bodies first in reverse order
for i in range(len(self.bodies)):
pos = self.getPos(i+1, 35, i == len(self.bodies)-1)
snake.bodies[i].x = pos[0]
snake.bodies[i].y = pos[1]
snake.bodies[i].draw()
The arguments to method getPos are the index of the body part, the distance between the parts and delToEnd. delToEnd becomes true, when the last part of the body is get and indicates, that the positions at the end of the list, which are "behind" the last part of the snake can be deleted:
class Snake:
# [...]
def getPos(self, i, dist, delToEnd):
lenToI = i * dist
lenAct = 0
px, py = self.positions[-1]
for j in range(len(self.positions)-1):
px, py = self.positions[j]
pnx, pny = self.positions[j+1]
delta = math.sqrt((px-pnx)*(px-pnx) + (py-pny)*(py-pny))
lenAct += delta
if lenAct >= lenToI:
w = (lenAct - lenToI) / delta
px = pnx - (pnx-px) * w
py = pny - (pny-py) * w
if delToEnd:
del self.positions[j:]
break
return (round(px), round(py))
I have a question concerning the colliderect function and variables embedded in classes and functions in general.
I created "hitboxes" around my important elements (player, finish line, monsters), and I want actions to be triggered when those hitboxes "meet".
I understand that the colliderect function from pygame is meant to do that, but somehow I can't implement it.
Could someone explain to me, how I would use the feature in the following code, specifically when the variables I have to call are embedded in separate classes and functions?
Thank you very much, here is my code so far:
#!/usr/bin/python
import sys, pygame, glob, math
from pygame import *
from random import randint
import time
pygame.init()
h = 600
w = 800
screen = pygame.display.set_mode((w, h))
clock = pygame.time.Clock()
jump_height = 0
class finish_line:
def __init__(self):
self.n = 600
self.b = 200
self.img_finish = pygame.image.load("finish.png")
self.update_finish(0)
def update_finish(self, pos_finish):
screen.blit(self.img_finish, (self.n, self.b))
class player:
def __init__(self):
self.x = 11
self.y = 200
self.speed = 5
self.ani_speed_init = 5
self.ani_speed = self.ani_speed_init
self.ani = glob.glob("animation/run*.png")
self.ani.sort()
self.ani_pos = 0
self.ani_max = len(self.ani)-1
self.img = pygame.image.load(self.ani[0])
self.update(0)
def update(self, pos):
if pos > 0:
if self.x >= (w - 100):
self.x = self.x
else:
self.x += self.speed
self.ani_speed -= 1
if self.ani_speed == 0:
self.img = pygame.image.load(self.ani[self.ani_pos])
self.ani_speed = self.ani_speed_init
if self.ani_pos == self.ani_max:
self.ani_pos = 0
else:
self.ani_pos += 1
elif pos < 0:
if self.x <= 9:
self.x = self.x
else:
self.x -= self.speed
self.ani_speed -= 1
if self.ani_speed == 0:
self.img = pygame.image.load(self.ani[self.ani_pos])
self.ani_speed = self.ani_speed_init
if self.ani_pos == self.ani_max:
self.ani_pos = 0
else:
self.ani_pos += 1
if jump_height == 1:
if self.y <= 10:
self.y = self.y
else:
self.y -= self.speed
elif jump_height == -1:
if self.y >= 500:
self.y = self.y
else:
self.y += self.speed
rectplayer = pygame.draw.rect(screen, (0, 0, 0), ((self.x + 10), (self.y + 15), 65, 70), 1)
screen.blit(self.img, (self.x, self.y))
return self.x, self.y
class monster:
rectmonster = 0
def __init__(self):
self.v = 650
self.c = 200
self.speed_monster = 0.3
self.img_monster = pygame.image.load("orange.png")
self.update_monster(0)
def update_monster(self, pos_monster):
if pos_monster == 1:
self.v = self.v + ((randint(-5, 1)) * self.speed_monster)
self.c = self.c + ((randint(-1, 3)) * self.speed_monster)
if self.v >= 660:
self.v = self.v + ((randint(-2, 0)) * self.speed_monster)
elif self.v <= 140:
self.v = self.v + ((randint(0, 2)) * self.speed_monster)
if self.c <= 140:
self.c = self.c + ((randint(0, 2)) * self.speed_monster)
elif self.c >= 460:
self.c = self.c + ((randint(-2, 0)) * self.speed_monster)
rectmonster = pygame.draw.rect(screen, (0, 0, 0), ((self.v + 12), (self.c + 5), 76, 90), 1)
screen.blit(self.img_monster, (self.v, self.c))
finish1 = finish_line()
player1 = player()
monster1 = monster()
monster2 = monster()
pos = 0
pos_monster = 1
pos_finish = 0
while 1:
screen.fill((255, 204, 229))
pygame.draw.rect(screen, (0,0,0,), (610, 210, 200, 180), 1)
clock.tick(60)
for event in pygame.event.get():
if event.type == pygame.QUIT:
sys.exit()
elif event.type == KEYDOWN and event.key == K_RIGHT:
pos = 1
elif event.type == KEYUP and event.key == K_RIGHT:
pos = 0
elif event.type == KEYDOWN and event.key == K_LEFT:
pos = -1
elif event.type == KEYUP and event.key == K_LEFT:
pos = 0
elif event.type == KEYDOWN and event.key == K_UP:
jump_height = 1
elif event.type == KEYUP and event.key == K_UP:
jump_height = 0
elif event.type == KEYDOWN and event.key == K_DOWN:
jump_height = -1
elif event.type == KEYUP and event.key == K_DOWN:
jump_height = 0
finish1.update_finish(pos_finish)
monster1.update_monster(pos_monster)
monster2.update_monster(pos_monster)
player1.update(pos)
pygame.display.flip()
This is my two cents on the problem based of two comments above.
You're assuming pygame.draw.rect automatically gives your class a size property, it does not.
You store the return value of rect() in rectplayer like so:
rectplayer = pygame.draw.rect(...)
And I bet rect() returns None to begin with. Besides that the variable isn't stored as self.rectplayer so it's a local function variable not a class-owned variable - so Pygame can't check against it.
This is an easy mistake to make and if that was the only root to the problem here, it would be an easy fix.
Unfortunately there's more assumptions here, such as the fact that colliderrect is a global function of Pygame.
colliderect & What is sprites?
There's a key note on this internal function of Pygame that states:
all sprites must have a “rect” value, which is a rectangle of the
sprite area, which will be used to calculate the collision.
It's a internal function called by pygame.sprite.spritecollide() that mentions the fact that you should be using Sprites.
Here's a minimal example of a sprite object:
class Player(pygame.sprite.Sprite):
def __init__(self, color, width, height):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.Surface([width, height])
self.image.fill(color)
self.rect = self.image.get_rect()
At the bottom of the initialization process of this sprite we define our rectangle self.rect that contains our (start_x, start_y), (width, height) data. These are size properties that you haven't defined in your above example.
Most likely, you could define something along the lines of:
class player:
def __init__(self):
self.rect = ...
But remember, your <class player> has no function called spritecollide() or collide_rect(), these functions is a inheritance either from pygame.sprite.Sprite or pygame.Surface, so you're better off sticking to these as your inherited object for your custom classes.
See my above example of class Player(...) how to do that.
I know this doesn't solve your entire code base, but hopefully it will give you some sense or idea of what's needed to complete your code.
End note
A friendly reminder, if you ever think that something is done for you - double check it. Assuming a class gets size properties because you drew a rectangle, check if your class actually did.
player1 = player()
print(dir(player1))
Is there anything in there remotely resembling width, height, size or rectangle? If not, this should indicate where something is funky.
I'm trying to add a def main to the end of my pong game to make it easier to read, but i've ran into problems trying to do that. When I add the def main, I just get a black screen, but without it I get the whole game.
import pygame
SCR_WID, SCR_HEI = 640, 480
class Player():
def __init__(self):
self.x, self.y = 16, SCR_HEI/2
self.speed = 3
self.padWid, self.padHei = 8, 64
self.score = 0
self.scoreFont = pygame.font.Font("imagine_font.ttf", 64)
def scoring(self):
scoreBlit = self.scoreFont.render(str(self.score), 1, (255, 255, 255))
screen.blit(scoreBlit, (32, 16))
if self.score == 10:
print ("player 1 wins!")
exit()
def movement(self):
keys = pygame.key.get_pressed()
if keys[pygame.K_w]:
self.y -= self.speed
elif keys[pygame.K_s]:
self.y += self.speed
if self.y <= 0:
self.y = 0
elif self.y >= SCR_HEI-64:
self.y = SCR_HEI-64
def draw(self):
pygame.draw.rect(screen, (255, 255, 255), (self.x, self.y, self.padWid, self.padHei))
class Enemy(Player):
def __init__(self):
self.x, self.y = SCR_WID-16, SCR_HEI/2
self.speed = 3
self.padWid, self.padHei = 8, 64
self.score = 0
self.scoreFont = pygame.font.Font("imagine_font.ttf", 64)
def scoring(self):
scoreBlit = self.scoreFont.render(str(self.score), 1, (255, 255, 255))
screen.blit(scoreBlit, (SCR_HEI+92, 16))
if self.score == 10:
print ("Player 2 wins!")
exit()
def movement(self):
keys = pygame.key.get_pressed()
if keys[pygame.K_UP]:
self.y -= self.speed
elif keys[pygame.K_DOWN]:
self.y += self.speed
if self.y <= 0:
self.y = 0
elif self.y >= SCR_HEI-64:
self.y = SCR_HEI-64
def draw(self):
pygame.draw.rect(screen, (255, 255, 255), (self.x, self.y, self.padWid, self.padHei))
class Ball():
def __init__(self):
self.x, self.y = SCR_WID/2, SCR_HEI/2
self.speed_x = -3
self.speed_y = 3
self.size = 8
def movement(self):
self.x += self.speed_x
self.y += self.speed_y
#wall col
if self.y <= 0:
self.speed_y *= -1
elif self.y >= SCR_HEI-self.size:
self.speed_y *= -1
if self.x <= 0:
self.__init__()
enemy.score += 1
elif self.x >= SCR_WID-self.size:
self.__init__()
self.speed_x = 3
player.score += 1
##wall col
#paddle col
#player
for n in range(-self.size, player.padHei):
if self.y == player.y + n:
if self.x <= player.x + player.padWid:
self.speed_x *= -1
break
n += 1
#enemy
for n in range(-self.size, enemy.padHei):
if self.y == enemy.y + n:
if self.x >= enemy.x - enemy.padWid:
self.speed_x *= -1
break
n += 1
##paddle col
def draw(self):
pygame.draw.rect(screen, (255, 255, 255), (self.x, self.y, 8, 8))
SCR_WID, SCR_HEI = 640, 480
screen = pygame.display.set_mode((SCR_WID, SCR_HEI))
pygame.display.set_caption("Pong")
pygame.font.init()
clock = pygame.time.Clock()
FPS = 60
def main():
ball = Ball()
player = Player()
enemy = Enemy()
while True:
#process
for event in pygame.event.get():
if event.type == pygame.QUIT:
print ("Game exited by user")
exit()
##process
#logic
ball.movement()
player.movement()
enemy.movement()
##logic
#draw
screen.fill((0, 0, 0))
ball.draw()
player.draw()
player.scoring()
enemy.draw()
enemy.scoring()
##draw
#_______
pygame.display.flip()
clock.tick(FPS)
main()
The call for main() on the end should be
if __name__ == "__main__":
main()
So that you can run your code and get the function to run. Also your indentation seems a little off. Is your code structured correctly with regard to spaces?
As already answered, you should insert the following statement at the end of the script:
if __name__ == "__main__":
main()
This answer will give you more info about the meaning of that statement.
What does if __name__ == "__main__": do?
In short, it tells the interpreter what it has to do with the function main():
1) Run it automatically if the file has been executed as stand alone script.
2) Don't run if the file has been imported as module from another script.
In your case, the wanted behaviour is the number one.
My character won't jump properly, he keeps glitching through the ground. If i hold key up, my character won't stop going higher. Do you have some ideas for how I could fix it?
import pygame,sys
from pygame.locals import *
pygame.init()
screen = pygame.display.set_mode((1200, 800))
screen.fill((0,0,0))
pygame.display.set_caption('Jump and Run')
BLACK = (0,0,0)
WHITE = (250, 250,250)
RED = (250, 0, 0)
BLUE = (0,0,250)
direction = 'right'
way = 0
jump_high = 0
class Hero():
def __init__(self, x, y):
self.x = x
self.y = y
self.image = pygame.image.load('hero.bmp')
self.groundcontact = True
self.vy = 0
alive = True
def check_pos(self):
if self.y >= 400:
self.groundcontact = True
elif self.y <= 400:
self.groundcontact = False
def load_picture(self,surface):
surface.blit(self.image,(self.x, self.y))
def check_input(self):
key = pygame.key.get_pressed()
if key[pygame.K_RIGHT]:
self.x += 10
elif key[pygame.K_LEFT]:
self.x -= 10
elif key[pygame.K_UP]:
self.y -= 50
if not self.groundcontact:
self.vy += 1 #max(min(2,200), -200)
#self.y += self.vy
print "not self.groundcontact"
else:
self.vy = 0
#self.y += self.vy
self.y += self.vy
class Monster():
def __init__(self, x, y):
self.x = x
self.y = y
self.image = pygame.image.load('monster.bmp')
self.collision = False
self.alive = True
def load_picture(self,surface):
surface.blit(self.image,(self.x, self.y))
def walk(self):
global direction
global way
if direction == "right":
self.x += 4
way += 1
if way == 100:
direction = "left"
elif direction == "left":
self.x -= 4
way -= 1
if way == 0:
direction = "right"
monster2 = Monster( 200, 333)
monster1 = Monster(400, 450)
hero = Hero(0, 400)
clock = pygame.time.Clock()
pygame.draw.rect(screen, WHITE,(0,500, 1200, 50))
while True:
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
sys.exit()
hero.check_pos()
monster1.walk()
monster2.walk()
hero.check_input()
screen.fill(BLACK)
hero.load_picture(screen)
monster1.load_picture(screen)
monster2.load_picture(screen)
pygame.draw.rect(screen, WHITE,(0,500, 1200, 50))
pygame.display.update()
clock.tick(40)
Regarding my comment above, changing the Hero class to somthing like this:
JUMP_POWER = 10
class Hero():
...
def check_input(self):
key = pygame.key.get_pressed()
...
elif key[pygame.K_UP]:
if self.groundcontact:
self.vy -= JUMP_SPEED
In using this script for simple vector math, I can add the speed vector when the values are integers such as 1 and 2, but when the speed vector is initialized with a float .5 there is no movement. As far as I can tell python doesn't require declaring float or int, but I have a feeling that the resulting number is being truncated
import pygame
from pygame.locals import *
pygame.init()
screen = pygame.display.set_mode((800, 600))
background = pygame.Surface(screen.get_size())
rectangle = pygame.Rect(65, 45, 50, 50)
class Vector2D:
def __init__(self, x, y):
self.x = x
self.y = y
def __iadd__(self, vector):
self.x += vector.x
self.y += vector.y
return self
def __isub__(self, vector):
self.x -= vector.x
self.y -= vector.y
return self
def copy(self, vector):
self.x = vector.x
self.y = vector.y
speed = Vector2D(.5, .5)
going = True
while going:
#Handle Input Events
for event in pygame.event.get():
if event.type == QUIT:
going = False
elif event.type == KEYDOWN and event.key == K_ESCAPE:
going = False
rectangle.left += speed.x
rectangle.top += speed.y
#Draw Everything
screen.blit(background, (0, 0))
pygame.draw.rect(screen, (255, 255, 255), rectangle, 1)
pygame.display.flip()
pygame.quit()
Since there is nothing like half a pixel, the Rect class truncates the decimal of the floats you are adding.
So keeping track of the position within the Vector2D class is a better Idea:
class Vector2D:
def __init__(self, x, y, vx, vy):
self.x = x
self.y = y
self.vx = vx
self.vy = vy
def update(self):
self.x += self.vx
self.y += self.vy
def copyto(self, rect):
rect.x = int(round(self.x,0))
rect.y = int(round(self.y,0))
speed = Vector2D(100, 100, .5, .5)
And have this:
speed.update()
speed.copyto(rectangle)
In place of:
rectangle.left += speed.x
rectangle.top += speed.y