I was writing a simple ping pong game as an introduction to arcade and in the loop on line 51. It is supposed to stop the sprites moving but it just isn't happening. I tried to remove the self., but got an error, tried replacing self. with arcade., but still getting an error.
import arcade
screen_width = 900
screen_height = 800
screen_title = 'Pingpong'
class MainGame(arcade.Window):
def __init__(self, width, height, title):
super().__init__(width, height, title)
self.ball = ball('ball.png', 0.4)
self.bar = bar('barman.png', 0.5)
self.live = 3
self.score = 0
def setup(self):
self.ball.center_x = 450
self.ball.center_y = 400
self.ball.stepx = 15
self.ball.stepy = 15
self.bar.center_x = 400
self.bar.center_y = 70
self.bar.stepx = 0
def on_draw(self):
arcade.start_render()
self.ball.draw()
self.bar.draw()
arcade.set_background_color(arcade.color.DARK_GRAY)
life = f'Жизней: {self.live}'
scrore = f'Счёт: {self.score}'
arcade.draw_text(life, 750, 740, arcade.color.BLACK, 20)
arcade.draw_text(scrore, 10, 740, arcade.color.BLACK, 20)
if self.live == 0:
arcade.draw_text('Вы лох', 400, 400, arcade.color.RED_DEVIL, 60)
arcade.finish_render()
def update(self, delta_time: float):
self.ball.update()
self.bar.update()
colliding = arcade.check_for_collision(self.ball, self.bar)
if colliding:
self.ball.bottom = self.example.top
self.ball.stepy = -self.ball.stepy
self.score += 1
if self.ball.bottom < 0:
self.live -= 1
self.ball.center_x = 450
self.ball.center_y = 400
if self.live == 0:
ball.stop()
bar.stop()
def on_key_press(self, key, modifiers):
if key == arcade.key.A:
self.bar.stepx = -15
if key == arcade.key.D:
self.bar.stepx = 15
def on_key_release(self, key, modifiers):
if key == arcade.key.A or key == arcade.key.D:
self.bar.stepx = 0
class ball(arcade.Sprite):
def update(self):
self.center_x += self.stepx
self.center_y += self.stepy
if self.bottom < 0 or self.top > screen_height:
self.stepy = -self.stepy
if self.left < 0 or self.right > screen_width:
self.stepx = -self.stepx
class bar(arcade.Sprite):
def update(self):
self.center_x += self.stepx
if self.left < 0 or self.right > screen_width:
self.stepx = 0
game = MainGame(screen_width, screen_height, screen_title)
game.setup()
arcade.run()
I tried removing the self. and got an error, tried replacing the self. with an arcade, got an error too. The loop works too it seems
Calling stop doesn't make sense in your code because at the same time you're updating your sprites coordinates. You need to update ball and bar only wnen live is above 0:
import arcade
screen_width = 900
screen_height = 800
screen_title = 'Pingpong'
class MainGame(arcade.Window):
def __init__(self, width, height, title):
super().__init__(width, height, title)
self.ball = ball('ball.png', 0.4)
self.bar = bar('barman.png', 0.5)
self.live = 3
self.score = 0
def setup(self):
self.ball.center_x = 450
self.ball.center_y = 400
self.ball.stepx = 15
self.ball.stepy = 15
self.bar.center_x = 400
self.bar.center_y = 70
self.bar.stepx = 0
def on_draw(self):
arcade.start_render()
self.ball.draw()
self.bar.draw()
arcade.set_background_color(arcade.color.DARK_GRAY)
life = f'Жизней: {self.live}'
score = f'Счёт: {self.score}'
arcade.draw_text(life, 750, 740, arcade.color.BLACK, 20)
arcade.draw_text(score, 10, 740, arcade.color.BLACK, 20)
if self.live == 0:
arcade.draw_text('Вы лох', 400, 400, arcade.color.RED_DEVIL, 60)
arcade.finish_render()
def update(self, delta_time: float):
if self.live > 0:
self.ball.update()
self.bar.update()
colliding = arcade.check_for_collision(self.ball, self.bar)
if colliding:
self.ball.bottom = self.bar.top
self.ball.stepy = -self.ball.stepy
self.score += 1
if self.ball.bottom < 0:
self.live -= 1
self.ball.center_x = 450
self.ball.center_y = 400
def on_key_press(self, key, modifiers):
if key == arcade.key.A:
self.bar.stepx = -15
if key == arcade.key.D:
self.bar.stepx = 15
def on_key_release(self, key, modifiers):
if key == arcade.key.A or key == arcade.key.D:
self.bar.stepx = 0
class ball(arcade.Sprite):
def update(self):
self.center_x += self.stepx
self.center_y += self.stepy
if self.bottom < 0 or self.top > screen_height:
self.stepy = -self.stepy
if self.left < 0 or self.right > screen_width:
self.stepx = -self.stepx
class bar(arcade.Sprite):
def update(self):
self.center_x += self.stepx
if self.left < 0 or self.right > screen_width:
self.stepx = 0
game = MainGame(screen_width, screen_height, screen_title)
game.setup()
arcade.run()
Output:
Related
My code
`
import pgzero.music
import pgzrun
import pygame
import time
from pgzero.actor import Actor
WIDTH = 600
HEIGHT = 700
RED = 200, 0, 0
Darkviolet = 104, 34, 139
COLOR1 = 71,60,139
WHITE = (255, 255, 255)
BOX = Rect((20, 100), (100,10))
RADIUS = 13
ball_speed_x = -3
ball_speed_y = 3
hearts = [Actor("heart", (20, 20)), Actor("heart", (55, 20)), Actor("heart", (90, 20))]
class Vector:
def __init__(self, x, y):
self.x = x
self.y = y
def __add(self, other):
return Vector(self.x + other.x, 0)
def __sub__(self, other):
return Vector(self.x - other.x, 0)
class Paddle:
def __init__(self, l, h, s1, s2):
self.position = [l, h]
self.size = s1, s2
def draw(self):
screen.draw.filled_rect(Rect(self.position, self.size), RED)
my_paddle = Paddle(200, 600, 100, 20)
class Rectangle:
def __init__(self,x, y, w, h):
self.x = x
self.y = y
self.h = h
self.w = w
def draw(self):
rect = Rect(self.x, self.y, self.h, self.w)
screen.draw.filled_rect(rect, "blue")
rectangles = []
rectan_count = 0
x = 30
y = 50
while rectan_count < 18:
rectangles.append(Rectangle(x, y, 20, 50))
rectan_count += 1
x += 80
if rectan_count == 7:
y += 30
x = 70
elif rectan_count == 13:
y += 30
x = 110
class Ball:
def __init__(self, x, y):
self.position = Vector(x, y)
def draw(self):
screen.draw.filled_circle((self.position.x, self.position.y), RADIUS, "darkviolet")
def update(self):
pass
ball = Ball(300, 300)
def draw():
global ball_speed_x, ball_speed_y
screen.clear()
my_paddle.draw()
ball.draw()
if hearts:
for heart in hearts:
heart.draw()
for rectangle in rectangles:
if (rectangle.x <= ball.position.x <= (rectangle.x + rectangle.w)) and (rectangle.y <= ball.position.y <= (rectangle.y + rectangle.h)):
ball_speed_y *= -1
rectangles.remove(rectangle)
rectangle.draw()
else:
screen.draw.text("Sorry, you lose!!", (150, 200), color="blue", fontsize=50)
quit()
def on_mouse_move(pos):
x = pos[0]
my_paddle.position[0] = x
def update_ball(dt, paddle_x, paddle_y):
global ball_speed_x, ball_speed_y
ball.position.x -= ball_speed_x
ball.position.y -= ball_speed_y
if (ball.position.x >= WIDTH) or (ball.position.x <= 0):
ball_speed_x *= -1
if (ball.position.y >= HEIGHT) or (ball.position.y <= 0):
ball_speed_y *= -1
if ((paddle_x + 100) >= ball.position.x >= paddle_x) and (paddle_y <= ball.position.y):
ball_speed_y *= -1
if ball.position.y >= HEIGHT:
ball.position.x = WIDTH // 2
ball.position.y = HEIGHT // 2
if hearts:
hearts.pop()
ball_speed_y += 1
def update(dt):
update_ball(dt, my_paddle.position[0], my_paddle.position[1])
pgzrun.go()`
I'm doing ping pong on pgzrun and I don't understand exactly how to make lose and win labels and have the game pause and the ball stop and then restart it again. And I still don't understand how to make rectangular barriers that my ball can bounce off. Many thanks in advance for your help!!
For the past few days I've been trying to implement the so called "Smart dots" game. I first saw it on Code Bullet youtube channel: https://www.youtube.com/watch?v=BOZfhUcNiqk. Unfortunately it was coded in Processing language, while the only language I barely know is Python. I finished my python version of the game but some bugs have appeared.
The problem is that on the second generation dots that are selected to be the best just stop moving almost instantly. I think that it has something to do with me being bad at OOP and copying the Brain class wrong. Steps(which i use for movement) Jump from zero(that is set at the beginning) to max value(200) at the first or second looping of the main loop. But the problems don't stop there. At the next generation, when i try to set brain step to zero, it just breaks with:
AttributeError: 'NoneType' object has no attribute 'brain'
I tried setting up the new brain manually but i still get the same errors. If anyone who already made this or has time to spare can help me with this error or even project i would appreciate it.
I know the code has a lot of unused things but that's just the product of me trying to fix it
:(
The commented out code is some of the old code i used.
main2.py(main loop):
import pygame
import klase2
pygame.init()
def main():
win = pygame.display.set_mode((klase2.WIN_W, klase2.WIN_H))
clock = pygame.time.Clock()
population = klase2.Population()
dots = population.return_dots(1000)
goal = klase2.Goal()
run = True
while run:
clock.tick(30)
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
win.fill((255, 255, 255))
goal.draw_goal(win)
for dot in dots:
dot.draw_dot(win)
dot.update_dot()
if population.all_dots_dead():
# natural selection
population.natural_selection()
# mutation
dots = population.mutate_dots()
population.gen += 1
print(population.gen)
pygame.display.update()
main()
kase2(handles all the functions and classes):
import pygame
import numpy as np
from pygame import gfxdraw
import math
import random
pygame.init()
WIN_W = 500
WIN_H = 500
class Brain:
def __init__(self, size):
self.step = 0
self.size = size
self.directionsx = np.array(np.random.uniform(low=-2.5, high=2.5, size=int(self.size / 2)))
self.directionsy = np.array(np.random.uniform(low=-2.5, high=2.5, size=int(self.size / 2)))
def clone(self):
self.size = self.size
self.directionsx = self.directionsx
self.directionsy = self.directionsy
self.step = 0
class Goal:
def __init__(self):
self.x = WIN_W / 2
self.y = 10
self.color = (255, 20, 20)
self.r = 5
def draw_goal(self, win):
pygame.gfxdraw.aacircle(win, int(self.x), int(self.y), self.r, self.color)
pygame.gfxdraw.filled_circle(win, int(self.x), int(self.y), self.r, self.color)
class Dot:
goal = Goal()
def __init__(self):
self.tick = 0
self.goal = Goal()
self.brain = Brain(400)
self.velx = 0
self.vely = 0
self.accx = 0
self.accy = 0
self.x = WIN_W / 2
self.y = WIN_H - 10
self.r = 3
self.color = (0, 0, 0)
self.alive = True
self.velLimit = 5
self.fitness = 0
def draw_dot(self, win):
pygame.gfxdraw.aacircle(win, int(self.x), int(self.y), self.r, self.color)
pygame.gfxdraw.filled_circle(win, int(self.x), int(self.y), self.r, self.color)
def move_dot(self):
if self.brain.size / 2 > self.brain.step:
self.accx = self.brain.directionsx[self.brain.step]
self.accy = self.brain.directionsy[self.brain.step]
self.brain.step += 1
else:
self.alive = False
self.velx += self.accx
self.vely += self.accy
if self.velx > self.velLimit:
self.velx = self.velLimit
elif self.velx < -self.velLimit:
self.velx = -self.velLimit
if self.vely > self.velLimit:
self.vely = self.velLimit
elif self.vely < -self.velLimit:
self.vely = -self.velLimit
self.x += self.velx
self.y += self.vely
def update_dot(self):
if not self.reached_goal():
self.tick += 1
if self.alive:
self.move_dot()
if self.x < 0 + self.r or self.x > WIN_W - self.r or self.y < 0 + self.r or self.y > WIN_H - self.r or self.reached_goal():
self.alive = False
def distance_to_goal(self):
a = abs(self.x - self.goal.x)
b = abs(self.y - self.goal.y)
return math.sqrt(a**2 + b**2)
def reached_goal(self):
if self.distance_to_goal() <= self.r + self.goal.r:
return True
return False
def fitness_dot(self):
if self.reached_goal():
self.fitness = 1 / (self.brain.step)
else:
self.fitness = 1 / (self.distance_to_goal()**2)
return self.fitness
class Population:
def __init__(self):
self.dots = []
self.newDots = []
self.gen = 0
self.mutateChance = 800
self.size = 0
self.fitness_sum = 0
def return_dots(self, size):
self.size = size
for _ in range(size):
self.dots.append(Dot())
return self.dots
def all_dots_dead(self):
for i in range(len(self.dots)):
if self.dots[i].alive:
return False
return True
def sort_dots(self):
self.dots = sorted(self.dots, key=lambda dot: dot.fitness, reverse=True)
def sum_fitness(self):
for dot in self.dots:
self.fitness_sum += dot.fitness_dot()
return self.fitness_sum
def get_parent(self):
rand = random.uniform(0, self.fitness_sum)
running_sum = 0
for dot in self.dots:
running_sum += dot.fitness
if running_sum >= rand:
return dot
def natural_selection(self):
for dot in self.dots:
dot.fitness_dot()
self.sort_dots()
self.newDots.append(self.dots[0])
self.sum_fitness()
for i in range(1, len(self.dots)):
parent = self.get_parent()
self.newDots.append(Dot())
self.newDots[i].brain = parent.brain
self.newDots[i].brain.step = 0
self.dots = self.newDots
def mutate_dots(self):
for i in range(1, len(self.dots)):
rand = random.randint(0, 1000)
if rand > self.mutateChance:
self.dots[i].brain.directionsx = np.array(np.random.uniform(low=-2.5, high=2.5, size=int(self.dots[i].brain.size / 2)))
self.dots[i].brain.directionsy = np.array(np.random.uniform(low=-2.5, high=2.5, size=int(self.dots[i].brain.size / 2)))
return self.dots
# def natural_selection(self):
# self.selectedDots = []
# for dot in self.dots:
# dot.fitness_dot()
# self.sort_dots()
# for i in range(0, int(len(self.dots) / 3)):
# self.selectedDots.append(self.dots[i])
# self.selectedDots[i].tick = 0
# self.selectedDots[i].velx = 0
# self.selectedDots[i].vely = 0
# self.selectedDots[i].accx = 0
# self.selectedDots[i].accy = 0
# self.selectedDots[i].x = WIN_W / 2
# self.selectedDots[i].y = WIN_H - 10
# self.selectedDots[i].alive = True
# self.selectedDots[i].fitness = 0
# self.selectedDots[i].brain.step = 0
# self.selectedDots[i].goal = Goal()
#
# def new_dots(self):
# for i in range(len(self.selectedDots), len(self.dots)):
# self.selectedDots.append(Dot())
# self.dots = self.selectedDots
#
# def mutate_dots(self):
# for i, dot in enumerate(self.dots):
# isMutating = random.randint(0, 1000)
# if self.mutateChance > isMutating and i > int(len(self.dots) / 3) and i < (2 * int((len(self.dots) / 3))):
# for j in range(len(dot.brain.directionsx)):
# isMutatingDir = random.randint(0, 1000)
# if isMutatingDir >= 800:
# dot.brain.directionsx[j] = np.random.uniform(low=-2.5, high=2.5, size=1)
# for j in range(len(dot.brain.directionsy)):
# isMutatingDir = random.randint(0, 1000)
# if isMutatingDir >= 800:
# dot.brain.directionsy[j] = np.random.uniform(low=-2.5, high=2.5, size=1)
# return self.dots
'''
def natural_selection(self):
self.selectedDots = []
for dot in self.dots:
dot.fitness_dot()
self.sort_dots()
self.selectedDots = self.dots[0:int(0.3 * len(self.dots))]
def new_dots(self):
for i in range(len(self.dots) - int(0.3 * len(self.dots))):
self.selectedDots.append(self.dots[i])
self.dots = []
def mutate_dots(self):
for i, selectedDot in enumerate(self.selectedDots):
self.tick = 0
self.x = WIN_W / 2
self.y = WIN_H - 10
self.r = 3
self.alive = True
self.velLimit = 5
self.fitness = 0
self.dots = self.selectedDots
return self.dots
'''
'''
def mutate_dots(self):
for i, selectedDot in enumerate(self.selectedDots):
selectedDot.alive = True
if i >= 1:
isMutating = random.randint(0, 1000)
if isMutating <= self.mutateChance:
for j in range(len(selectedDot.brain.directionsx)):
isMutatingDir = random.randint(0, 1000)
if isMutatingDir >= 800:
selectedDot.brain.directionsx[j] = np.random.uniform(low=-2.5, high=2.5, size=1)
for j in range(len(selectedDot.brain.directionsy)):
isMutatingDir = random.randint(0, 1000)
if isMutatingDir >= 800:
selectedDot.brain.directionsy[j] = np.random.uniform(low=-2.5, high=2.5, size=1)
elif isMutating <= 800:
selectedDot.brain.directionsx = np.array(np.random.uniform(low=-2.5, high=2.5, size=200))
selectedDot.brain.directionsy = np.array(np.random.uniform(low=-2.5, high=2.5, size=200))
self.newDots.append(selectedDot)
return self.newDots
'''
The NoneType error is caused by the get_parent method. It searches for a child dot, but has no return value if the search fails (same effect as return None). This code will get past that error
def get_parent(self):
rand = random.uniform(0, self.fitness_sum)
running_sum = 0
for dot in self.dots:
running_sum += dot.fitness
if running_sum >= rand:
return dot
return self.dots[0] # search failed, return 1st dot
I am working on a program that evolves creatures over time using a genetic algorithm. However, for some reason, my pygame display stopped working and I have absolutely no idea why. When I run the program, the window opens but then it just sits on a black screen. I have tested to see where the program gets to and about 38 creatures die then nothing happens. However, these creatures should be displaying before their deaths also, but they aren't.Any help would be wonderful! Thank you for all your time!
Here's my code:
import numpy as np
import pygame
import random
#Initializes Pygame & Creates Window
pygame.init()
backgroundColor = (255, 255, 255)
screenSize = (800, 600)
screen = pygame.display.set_mode(screenSize)
pygame.display.set_caption("Genetic Algorithm")
screen.fill(backgroundColor)
clock = pygame.time.Clock()
#Loads Images & Rectangles
creaturePNG = pygame.image.load("Creature.png").convert_alpha()
foodPNG = pygame.image.load("Food.png").convert_alpha()
#Establishes Size Of Population
creatureCount = 40
deadCreatures = []
numGenerations = 10
#Generates Random 12 Digit DNA For First Generation
def initialDNA():
while True:
randomDNA = ""
total = 0
for i in range(12):
digit = random.randint(1, 9)
total += digit
digit = str(digit)
randomDNA = randomDNA + digit
if total <= 60:
break
return randomDNA
def reproduce(deadCreatureList, creatureCount):
reproducingCreatures = deadCreatureList[0.5*creatureCount:creatureCount]
for i in range(0.25*creatureCount):
creature1 = reproducingCreatures[0]
del reproducingCreatures[0]
creature2 = reproducingCreatures[0]
del reproducingCreatures[0]
DNA1 = str(creature1.DNA)
DNA2 = str(creature2.DNA)
crosspoint = random.randint(0, 12)
newDNA1 = int(DNA1[0:crosspoint] + DNA2[crosspoint:])
newDNA2 = int(DNA2[0:crosspoint] + DNA1[crosspoint:])
return newDNA1, newDNA2
#Creates Creatures From DNA
class Creature:
def __init__(self, DNA, image):
self.DNA = DNA
self.speed = (int(self.DNA[0:2])/100) + 1
self.strength = int(DNA[2:4])/10
self.foodCap = int(DNA[4:6])
self.maxHealth = int(DNA[6:8])
self.health = self.maxHealth
self.regeneration = int(DNA[8:10])/10
self.turnProbability = int(DNA[10:12])
self.currentFood = self.foodCap
self.image = image
self.rect = self.image.get_rect()
self.directions = [-1, 1]
self.directionX = random.choice(self.directions)
self.directionY = random.choice(self.directions)
self.isAlive = True
def spawn(self):
self.x = random.randint(25, 775)
self.y = random.randint(25, 575)
self.loc = (self.x, self.y)
self.rect = pygame.Rect(0, 0, 25, 25)
self.rect.center = self.loc
def move(self):
changeDirection = random.randint(0, 100)
if changeDirection < self.turnProbability:
self.directionX = random.choice(self.directions)
self.directionY = random.choice(self.directions)
self.x += self.directionX * self.speed
self.y += self.directionY * self.speed
if self.x > 775:
self.x = 775
elif self.x < 25:
self.x = 25
elif self.y > 575:
self.y = 575
elif self.y < 25:
self.y = 25
self.loc = (self.x, self.y)
self.rect.center = self.loc
def foodCollision(self, foodList):
foodRects = []
for i in range(25):
food = foodList[i]
foodRect = food.rect
foodRects.append(foodRect)
collision = self.rect.collidelist(foodRects)
if collision > 0:
self.currentFood += 20
if self.currentFood > self.foodCap:
self.currentFood = self.foodCap
def creatureCollision(self, creatureList, creatureCount, creatureNumber):
creatureRects = []
for i in range(creatureCount):
creature = creatures[i]
creatureRect = creature.rect
creatureRects.append(creatureRect)
collision = self.rect.collidelist(creatureRects)
creature = creatures[collision]
if collision >= 0:
if collision != creatureNumber:
if creature.health > 0:
self.health -= creature.strength
if self.health < 0:
self.health = 0
def starve(self):
if self.currentFood == 0:
self.health -= 1
def display(self):
screen.blit(self.image, self.loc)
#Creates Food Objects For Creatures To Eat
class Food:
def __init__(self, image):
self.image = image
self.rect = self.image.get_rect()
def spawn(self):
self.x = random.randint(25, 775)
self.y = random.randint(25, 575)
self.loc = (self.x, self.y)
self.rect = pygame.Rect(0, 0, 25, 25)
self.rect.center = self.loc
def creatureCollision(self, creatureList, creatureCount):
creatureRects = []
for i in range(creatureCount):
creature = creatures[i]
creatureRects.append(creature.rect)
collision = self.rect.collidelist(creatureRects)
creature = creatures[collision]
if collision >= 0:
if creature.health > 0:
self.spawn()
def display(self):
screen.blit(self.image, self.loc)
running = True
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
screen.fill(backgroundColor)
for i in range(numGenerations):
if i == 0:
#Spawns Creatures Into World
creatures = []
for i in range(creatureCount):
DNA = initialDNA()
print (DNA)
creature = Creature(DNA, creaturePNG)
creature.spawn()
creatures.append(creature)
elif i > 0:
creatures = []
for i in range(0.5*creatureCount):
DNA1, DNA2 = reproduce(deadCreatures, creatureCount)
print (DNA1, DNA2)
creature1, creature2 = Creature(DNA1, creaturePNG), Creature(DNA2, creaturePNG)
creature.spawn()
creatures.append(creature)
#Spawns Food Into World
foodList = []
for i in range(25):
food = Food(foodPNG)
food.spawn()
foodList.append(food)
livingCreatures = True
while livingCreatures:
for i in range(25):
food = foodList[i]
food.creatureCollision(creatures, creatureCount)
food.display()
for i in range(creatureCount):
creature = creatures[i]
if creature.health > 0:
creature.move()
creature.foodCollision(foodList)
creature.creatureCollision(creatures, creatureCount, i)
creature.currentFood -= 0.5
if creature.currentFood < 0:
creature.currentFood = 0
if creature.currentFood > 0:
creature.health += creature.regeneration
if creature.health > creature.maxHealth:
creature.health = creature.maxHealth
creature.starve()
creature.display()
if creature.isAlive == True:
if creature.health == 0:
print ("DEATH")
deadCreatures.append(i)
creature.isAlive = False
if len(deadCreatures) == creatureCount:
livingCreatures = False
pygame.display.flip()
clock.tick(10)
I suspect the livingCreatures variable is never set to False, so the pygame.display.flip() never gets called--and you won't see anything on the screen at all until you flip the buffers. The fact that you're filling the screen with a color, but then still seeing black, is a dead giveaway for this sort of problem.
In the future, you should also try to reproduce the problem in a simpler example without domain-specific, irrelevant code.
I am working on a project for my CS class, I am near where I fell comfortable to call it complete, but I am getting this error:
exceptions.AttributeError: type object 'protaganist' has no attribute 'hearts'
also i am trying to make my protaganist class move up.... i have tried
if keys[pygame.K_SPACE]:
self.y += self.dy # (where dy was defined as 10 in init)
i dont know what else to try
lastly how i might set somthing with a random position of x with a set y position
it highlights here: ( it is calling another classe's attribute, but i dnt know why its causing error:
class coinandheartscore(gameEngine.SuperSprite):
def __init__(self, scene):
gameEngine.SuperSprite.__init__(self, scene)
self.font = pygame.font.SysFont("None", 50)
def update(self):
self.text = "hearts X: %d, Coins X: %d" % (protaganist.hearts, protaganist.coins)
self.image = self.font.render(self.text, 1, (255, 255, 0))
self.rect = self.image.get_rect()
here is my overall code:
import gameEngine
import pygame
import math
pygame.init()
screen = pygame.display.set_mode((640, 480))
pygame.mixer.init()
sndAtk = pygame.mixer.Sound("OOT_AdultLink_Attack1.wav")
sndWalk = pygame.mixer.Sound("OOT_Steps_Dirt1.wav")
sndPoof = pygame.mixer.Sound("OOT_Enemy_Poof1.wav")
sndWalk.set_volume(.1)
sndAtk.set_volume(.5)
sndPoof.set_volume(.9)
#sndRun = pygame.mixer.Sound("")
#goal is to create a game
#must have menu to start game
#menu should have a start and quit button.. start runs gaming operations and quit exits program
#sprites for character and enemies and bullets maybe, use one large image and simply move visibiliy
#this saves memory as 1 image is loaded instead of many
"""
protaganist is our hero sprite
should run left and right, jump left and right
and attack left and right...
I might add in the bow and jump attack
"""
class scrollinggrass(gameEngine.SuperSprite):
def __init__(self, scene):
gameEngine.SuperSprite.__init__(self, scene)
self.setImage("gamebackground.jpg")
self.rect = self.imageMaster.get_rect()
self.setPosition((400,247))
self.checkKeys()
self.dy = 3
def checkKeys(self):
keys = pygame.key.get_pressed()
if keys[pygame.K_d]:
self.forward(-6)
sndWalk.play()
if keys[pygame.K_a]:
self.forward(6)
sndWalk.play()
class coins(gameEngine.SuperSprite):
def __init__(self, scene):
gameEngine.SuperSprite.__init__(self, scene)
self.loadImages()
self.image = self.imageMaster
self.frame = -1
self.pause = 0
self.delay = 3
def loadImages(self):
self.coinImgList = []
for i in range(3):
nameImage = "linkimages/coins/greenrupee%d.png" % i
self.setImage(nameImage)
tempImage = self.imageMaster
transparentColor = tempImage.get_at((1,1))
tempImage.set_colorkey(transparentColor)
self.coinImgList.append(tempImage)
def update(self):
self.pause += .25
if self.pause >= self.delay:
self.pause = 0
self.frame += 1
if self.frame >= len(self.coinImgList):
self.frame = 0
self.image = self.coinImgList[self.frame]
class hearts(gameEngine.SuperSprite):
def __init__(self, scene):
gameEngine.SuperSprite.__init__(self, scene)
self.setImage("heart.png")
self.setTransparentColor = self.imageMaster.get_at((1,1))
self.imageMaster.set_colorkey(self.setTransparentColor)
self.setPosition((550 , 30))
class badguy(gameEngine.SuperSprite):
def __init__(self, scene):
gameEngine.SuperSprite.__init__(self, scene)
self.setImage("badguy1.png")
self.setTransparentColor = self.imageMaster.get_at((1,1))
self.imageMaster.set_colorkey(self.setTransparentColor)
self.rect = self.imageMaster.get_rect()
# self.CONTINUE = 4
self.boundAction = self.CONTINUE
self.health = 2
self.DEAD = 1
self.state = 0
self.setPosition((200,375))
self.checkKeys()
def checkKeys(self):
keys = pygame.key.get_pressed()
if keys[pygame.K_d]:
self.forward(-3)
if keys[pygame.K_a]:
self.forward(3)
def reset(self):
self.setPosition((1000, 375))
self.health = 2
# def update(self):
class protaganist(gameEngine.SuperSprite):
def __init__(self, scene):
gameEngine.SuperSprite.__init__(self, scene)
self.imageList = []
self.pause = 0
self.delay = 3
self.rect = self.imageMaster.get_rect()
self.STANDING = 0
self.RIGHT = 0
self.LEFT = 1
self.direction = self.RIGHT
self.RUNNING = 1
self.ATTACKING = 2
self.JUMPING = 3
self.DEAD = 10
self.frame = -1
self.state = self.STANDING
self.coins = 0
self.hearts = 1
self.heartPts = self.hearts * 3
self.stats()
self.dy = 20
self.loadImages()
self.image = self.imageMaster
self.checkKeys()
def stats(self):
#sets it up so each heart is essentially 3 hit points
if self.heartPts >= 3:
self.hearts = 1
elif self.heartPts >= 6:
self.hearts = 2
elif self.heartPts == 9:
self.hearts = 3
elif self.heartPts > 9:
self.heartPts = 9
# changes state to dead if hp == 0
if self.heartPts == 0:
self.state = DEAD
def loadImages(self):
self.setImage("heroSTANDINGLeft.gif")
self.setTransparentColor = self.imageMaster.get_at((1,1))
self.imageMaster.set_colorkey(self.setTransparentColor)
self.imageSTANDINGLeft = self.imageMaster
self.setImage("heroSTANDING.gif")
self.setTransparentColor = self.imageMaster.get_at((1,1))
self.imageMaster.set_colorkey(self.setTransparentColor)
self.imageSTANDING = self.imageMaster
self.heroATKList = []
self.heroATKleft = []
self.heroDEAD = []
self.heroRUNList = []
self.heroRUNLeftList = []
for i in range(4):
nameImage = "linkimages/DEAD/heroDEAD%d.gif" % i
self.setImage(nameImage)
tempImage = self.imageMaster
transparentColor = tempImage.get_at((1,1))
tempImage.set_colorkey(transparentColor)
self.heroDEAD.append(tempImage)
for i in range(5):
nameImage = "linkimages/runningRIGHT/heroRUN%d.gif" % i
self.setImage(nameImage)
tempImage = self.imageMaster
transparentColor = tempImage.get_at((1,1))
tempImage.set_colorkey(transparentColor)
self.heroRUNList.append(tempImage)
for i in range(5):
nameImage = "linkimages/runningLEFT/heroRUN%d.gif" % i
self.setImage(nameImage)
tempImage = self.imageMaster
transparentColor = tempImage.get_at((1,1))
tempImage.set_colorkey(transparentColor)
self.heroRUNLeftList.append(tempImage)
for i in range(4):
nameImage = "linkimages/ATTACKING/heroATTACKING%d.gif" % i
self.setImage(nameImage)
tempImage = self.imageMaster
transparentColor = tempImage.get_at((1,1))
tempImage.set_colorkey(transparentColor)
self.heroATKList.append(tempImage)
for i in range(4):
nameImage = "linkimages/ATTACKING/heroATTACKINGLeft%d.gif" % i
self.setImage(nameImage)
tempImage = self.imageMaster
transparentColor = tempImage.get_at((1,1))
tempImage.set_colorkey(transparentColor)
self.heroATKleft.append(tempImage)
def update(self):
self.rect = self.imageMaster.get_rect()
self.rect.x = 275
self.rect.y = 350
if self.state == self.STANDING:
if self.direction == self.RIGHT:
self.image = self.imageSTANDING
self.setPosition((200,200))
elif self.direction == self.LEFT:
self.image = self.imageSTANDINGLeft
if self.state == self.RUNNING:
if self.direction == self.RIGHT:
self.frame += 1
if self.frame >= len(self.heroRUNList):
self.frame = 0
self.image = self.heroRUNList[self.frame]
elif self.direction == self.LEFT:
self.frame += 1
if self.frame >= len(self.heroRUNLeftList):
self.frame = 0
self.image = self.heroRUNLeftList[self.frame]
if self.state == self.DEAD:
self.frame += 1
if self.frame >= len(self.heroDEAD):
self.frame = 0
self.image = self.heroDEAD[self.frame]
self.pause += .5
if self.pause >= self.delay:
self.pause = 0
if self.state == self.ATTACKING:
if self.direction == self.RIGHT:
self.frame += 1
sndAtk.play()
if self.frame >= len(self.heroATKList):
self.frame = 0
self.image = self.heroATKList[self.frame]
elif self.direction == self.LEFT:
self.frame += 1
sndAtk.play()
if self.frame >= len(self.heroATKleft):
self.frame = 0
self.image = self.heroATKleft[self.frame]
def checkKeys(self):
keys = pygame.key.get_pressed()
if keys[pygame.K_d]:
self.direction = self.RIGHT
self.state = self.RUNNING
self.x += self.dx
else:
self.state = self.STANDING
if keys[pygame.K_a]:
self.state = self.RUNNING
self.direction = self.LEFT
if keys[pygame.K_g]:
self.state = self.ATTACKING
#sndAtk.play()
if keys[pygame.K_SPACE]:
self.addDY(3)
if self.state == self.DEAD:
self.image = self.deadImgList[0]
self.frame += 1
self.image = self.deadImgList[self.frame]
#self.image = self.image.get_rect()
#self.rect.center = (320, 240)
class coinandheartscore(gameEngine.SuperSprite):
def __init__(self, scene):
gameEngine.SuperSprite.__init__(self, scene)
self.font = pygame.font.SysFont("None", 50)
def update(self):
self.text = "hearts X: %d, Coins X: %d" % (protaganist.hearts, protaganist.coins)
self.image = self.font.render(self.text, 1, (255, 255, 0))
self.rect = self.image.get_rect()
class game(gameEngine.Scene):
def __init__ (self):
gameEngine.Scene.__init__(self)
pygame.display.set_caption("Link's Mediocre Adventure")
background = pygame.Surface(screen.get_size())
background.fill((0, 0, 0))
screen.blit(background, (0, 0))
coin = coins(self)
pro = protaganist(self)
baddy = badguy(self)
baddy1 = badguy(self)
heart = hearts(self)
grass = scrollinggrass(self)
score = coinandheartscore(self)
goodlySprites = self.makeSpriteGroup((grass, coin, pro, heart))
baddySprites = self.makeSpriteGroup((baddy, baddy1))
cnhrtSprites = self.makeSpriteGroup((score))
self.addGroup((cnhrtSprites))
self.addGroup((goodlySprites))
self.addGroup((baddySprites))
clock = pygame.time.Clock()
keepGoing = True
while keepGoing:
clock.tick(30)
for event in pygame.event.get():
if event.type == pygame.QUIT:
keepGoing = False
if pro.state == pro.ATTACKING:
if pro.collidesGroup(baddySprites):
baddy.health -= 1
baddy1.health -= 1
if baddy.health == 0:
sndPoof.play()
baddy.reset()
elif baddy1.health == 0:
sndPoof.play()
baddy1.reset()
elif pro.state != pro.ATTACKING:
if pro.collidesGroup(baddySprites):
pro.heartPts -= 1
baddy.checkKeys()
grass.checkKeys()
pro.checkKeys()
pro.loadImages()
goodlySprites.clear(screen, background)
baddySprites.clear(screen, background)
cnhrtSprites.clear(screen, background)
goodlySprites.update()
baddySprites.update()
cnhrtSprites.update()
goodlySprites.draw(screen)
baddySprites.draw(screen)
cnhrtSprites.draw(screen)
pygame.display.flip()
def main():
game.start()
if __name__ == "__main__":
game()
At least one of the problems is in your naming of your classes: the PEP8 convention calls for capitalized class names (Protagonist) and lower-case instances of them (pro). You've called your class protagonist and instantiated as pro. It looks like you're referring to protagonist.hearts (no such class attribute exists) when you mean pro.hearts (attribute of an instance of the protagonist class.
As a general rule, if you have two questions (even about the same piece of code), you should post two separate questions on Stack Overflow. That said...
1: Moving Up
The code you quoted in your question looks OK. Unfortunately, it's nothing like the code you're actually running in protaganist.checkKeys:
if keys[pygame.K_SPACE]:
self.addDY(3)
There is no protaganist.addDY method, so trying to call it should raise an exception. The hard-wired argument to the non-existent method is 3, not 10. Finally (to correct your comment), protaganist.__init__ sets protaganist.dy to 20, not 10.
2: AttributeError
Your protaganist class has no hearts attribute, which is almost exactly what the error message said. (Note that it's typically spelled with an "o": protagonist.)
Instances of your protaganist class do have a hearts attribute, but you can't access that by going through the class name. (How would the Python interpreter know which of possibly-many protaganist instances you meant?)
To get a particular protaganist object's hearts value, you'll need a reference to that specific instance:
class coinandheartscore(gameEngine.SuperSprite):
# New protagonist parameter is required.
def __init__(self, scene, protagonist):
gameEngine.SuperSprite.__init__(self, scene)
self.font = pygame.font.SysFont("None", 50)
# Save it for later use.
self.protagonist = protagonist
def update(self):
# self.protagonist refers to _one_ specific
# protaganist instance, which _does_ have
# hearts and coins attributes.
self.text = "hearts X: %d, Coins X: %d" % (
self.protagonist.hearts,
self.protagonist.coins,
)
# Remainder unchanged...
Later, in the game.__init__ method, you'll have to provide the new argument when you instantiate coinandheartscore:
# New self.pro argument.
score = coinandheartscore(self, self.pro)
3: PEP-8
Finally, I second xnx's comments about naming conventions... The strange names made this much harder to read than it had to be.
Although xnx didn't link to PEP-8 in his answer, it is literally the first Google result. He or she was specifically talking about the section on Naming Conventions.
4: Freebies
protaganist.checkKeys: d and a are not the inverses you would expect. d adds self.dx ( which does not exist) to self.x, while a adds nothing.
protaganist.stats sets self.state to DEAD, which does not exist. You probably meant self.DEAD.
In general, test more and code less. The more you write between tests, the more bugs you will have to track down, and the more places they can be hiding.
It's still an incomplete program, but for some reason the value of the textbox doesn't increase when it should... Why is this??
When the Pizza sprite overlaps with the Pan sprite, the score in the textbox is supposed to increase in value by 10. Why does this not occur?
Thanks!
'''
Created on Jul 1, 2011
#author: ******* Louis
'''
#Watch me do.
from livewires import games, color
import random
games.init (screen_width = 640, screen_height = 480, fps = 50)
#Pizza Class
class Pizza (games.Sprite):
pizzaimage = games.load_image ("pizza.bmp", transparent = True)
def __init__(self, x = random.randrange(640), y = 90, dy = 4):
super (Pizza, self).__init__(x = x,
y = y,
image = Pizza.pizzaimage,
dy = dy)
def handle_caught (self):
self.destroy()
class Pan (games.Sprite):
panimage = games.load_image ("pan.bmp", transparent = True)
def __init__ (self, x = games.mouse.x, y = games.mouse.y):
super (Pan, self).__init__(x = x,
y = y,
image = Pan.panimage)
self.score = 0
self.textbox = games.Text (value = str(self.score),
size = 20,
color = color.black,
x = 550,
y = 50)
games.screen.add(self.textbox)
def update (self): #WWWWOW There is actually an *update* method
self.x = games.mouse.x
self.y = games.mouse.y
if self.left < 0:
self.left = 0
if self.right >640:
self.right = 640
if self.top < 0:
self.top = 0
if self.bottom > 480:
self.bottom = 480
self.check_collision()
def check_collision (self):
for Pizza in self.overlapping_sprites:
self.score = self.score + 10
Pizza.handle_caught()
#main
def main():
wallbackground = games.load_image ("wall.jpg", transparent = False)
games.screen.background = wallbackground
games.screen.add(Pizza())
games.screen.add(Pan())
games.mouse.is_visible = False
games.screen.event_grab = True
games.screen.mainloop()
main()
The textbox takes a value that is a string. When you create the textbox, you create a string from the current value of score, and set the text to that string. No lasting connection between score and textbox is made.
The textbox probably has a method available to update its text; call that method with the value str(self.score) after you increment the score.