Create an inventory for a python game - python

So I try to create an inventory for the python game Dodger. In the inventory I want to be able to select different players to play the game. But when I run the game, only the option images/player.png is chosen. How can I fix that? thanks
This is what I have tried so far:
//Inventory.py
import pygame
import pygwidgets
import pyghelpers
import random
from Player import Player
import Constants
from Constants import *
class Inventory(pyghelpers.Scene):
def __init__(self, window):
self.window = window
self.player = Player(window)
self.player0 = pygwidgets.CustomButton(self.window, (30, 250), 'images/player_inv.png')
self.player1 = pygwidgets.CustomButton(self.window, (280, 250), 'images/player1_inv.jpg')
self.player2 = pygwidgets.CustomButton(self.window, (30, 450), 'images/char1_inv.png')
self.inventory = []
self.image = pygwidgets.Image(self.window,(0, 0),'images/inventory.png')
self.quitButton = pygwidgets.CustomButton(self.window,
(30, 650),
up='images/quitNormal.png',
down='images/quitDown.png',
over='images/quitOver.png',
disabled='images/quitDisabled.png')
self.backButton = pygwidgets.CustomButton(self.window,
(240, 650),
up='images/backNormal.png',
down='images/backDown.png',
over='images/backOver.png',
disabled='images/backDisabled.png')
def getSceneKey(self):
return SCENE_INVENTORY
def enter(self, data):
pass
def handleInputs(self, eventsList, keyPressedList):
for event in eventsList:
if self.quitButton.handleEvent(event):
self.quit()
elif self.backButton.handleEvent(event):
self.goToScene(Constants.SCENE_PLAY)
if self.player0.handleEvent(event):
self.player.imagelink = 'images/player.png'
self.goToScene(Constants.SCENE_PLAY)
elif self.player1.handleEvent(event):
self.player.imagelink = 'images/player1.jpg'
self.goToScene(Constants.SCENE_PLAY)
elif self.player2.handleEvent(event):
self.player.imagelink = 'images/player2.png'
self.goToScene(Constants.SCENE_PLAY)
def update(self):
pass
def draw(self):
self.image.draw()
self.quitButton.draw()
self.backButton.draw()
self.player0.draw()
self.player1.draw()
self.player2.draw()
//Player.py
import pygame
import pygwidgets
from Constants import *
class Player():
def __init__(self, window):
self.window = window
self.imagelink = 'images/player.png'
self.image = pygwidgets.Image(window,
(-100, -100), self.imagelink)
playerRect = self.image.getRect()
self.maxX = WINDOW_WIDTH - playerRect.width
self.maxY = GAME_HEIGHT - playerRect.height
# Every frame, move the Player icon to the mouse position
# Limits the x- and y-coordinates to the game area of the window
def update(self, x, y):
if x < 0:
x = 0
elif x > self.maxX:
x = self.maxX
if y < 0:
y = 0
elif y > self.maxY:
y = self.maxY
self.image.setLoc((x, y))
return self.image.getRect()
def draw(self):
self.image.draw()
enter image description here

With your code Player.imagelink = 'images/player1.jpg', you are modifying a class attribute and not a class instance attribute. You can fix this by changing self.player.imagelink = 'images/player1.jpg'. You will need to make similar changes for each line that includes Player.imagelink = ...

Related

unable to get the score and game over/reset functions to work

I am having problems with the below code. Can someone please help and explain why the game over/reset and score functions are not working?
Below is the code im working from. My problem is that i can not see why the game over/reset function does not work. When the ship crashes into an astroid the game abruptly ends, but when it crashes into the barrier it does not indicate game over. Also, it's not reflecting the score.
Sorry if i wasn't clear before.
Here starts the code:
import kivy
kivy.require('1.8.0')
from kivy.app import App
from kivy.uix.widget import Widget
from kivy.uix.label import Label
from kivy.uix.button import Button
from kivy.uix.floatlayout import FloatLayout
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.image import Image
from kivy.properties import NumericProperty, ObjectProperty
from kivy.clock import Clock
from kivy.core.window import Window
from kivy.graphics import Rectangle, Color, Canvas
from kivy.config import Config
from functools import partial
from random import *
Config.set('graphics', 'resizable', 0)
Window.clearcolor = (0, 0, 0, 1.)
class MyButton(Button):
#class used to get uniform button styles
def __init__(self, **kwargs):
super(MyButton, self).__init__(**kwargs)
self.font_size = Window.width*0.018
class SmartMenu(Widget):
#the instance created by this class will appear
#when the game is started for the first time
buttonList = []
def __init__(self, **kwargs):
#create custom events first
self.register_event_type('on_button_release')
super(SmartMenu, self).__init__(**kwargs)
self.layout = BoxLayout(orientation = 'vertical')
self.layout.width = Window.width/2
self.layout.height = Window.height/2
self.layout.x = Window.width/2 - self.layout.width/2
self.layout.y = Window.height/2 - self.layout.height/2
self.add_widget(self.layout)
def on_button_release(self, *args):
#print 'The on_button_release event was just dispatched', args
#don't need to do anything here. needed for dispatch
pass
def callback(self,instance):
#print('The button %s is being pressed' % instance.text)
self.buttonText = instance.text
self.dispatch('on_button_release') #dispatching the callback event 'on_button_release' to tell teh parent instance to read the button text
def addButtons(self):
for k in self.buttonList:
tmpBtn = MyButton(text = k)
tmpBtn.background_color = [.4, .4, .4, .4]
tmpBtn.bind(on_release = self.callback) #when the button is released the callback function is called
self.layout.add_widget(tmpBtn)
def buildUp(self):
#self.colorWindow()
self.addButtons()
class SmartStartMenu(SmartMenu):
#setup the menu button names
buttonList = ['start', 'about']
def __init__(self, **kwargs):
super(SmartStartMenu, self).__init__(**kwargs)
self.layout = BoxLayout(orientation = 'vertical')
self.layout.width = Window.width/2
self.layout.height = Window.height/2
self.layout.x = Window.width/2 - self.layout.width/2
self.layout.y = Window.height/2 - self.layout.height/2
self.add_widget(self.layout)
self.msg = Label(text = 'Flappy Ship')
self.msg.font_size = Window.width*0.07
self.msg.pos = (Window.width*0.45,Window.height*0.75)
self.add_widget(self.msg)
self.img = Image(source = 'lens2.png')
self.img.size = (Window.width*1.5,Window.height*1.5)
self.img.pos = (-Window.width*0.2,-Window.height*0.2)
self.img.opacity = 0.35
self.add_widget(self.img)
class WidgetDrawer(Widget):
#This widget is used to draw all of the objects on the screen
#it handles the following:
# widget movement, size, positioning
def __init__(self, imageStr, **kwargs):
super(WidgetDrawer, self).__init__(**kwargs)
with self.canvas:
self.size = (Window.width*.002*25,Window.width*.002*25)
self.rect_bg=Rectangle(source=imageStr, pos=self.pos, size=self.size)
self.bind(pos=self.update_graphics_pos)
self.x = self.center_x
self.y = self.center_y
self.pos = (self.x, self.y)
self.rect_bg.pos = self.pos
def update_graphics_pos(self, instance, value):
self.rect_bg.pos = value
def setSize(self, width, height):
self.size = (width, height)
def setPos(self, xpos, ypos):
self.x = xpos
self.y = ypos
class ScoreWidget(Widget):
def __init__(self, **kwargs):
super(ScoreWidget, self).__init__(**kwargs)
self.asteroidScore = 0
self.currentScore = 0
with self.canvas:
tmpPos = (Window.width*0.25, Window.height*0.25)
tmpSize = (Window.width*0.5, Window.height*0.5)
Color(0.1, .1, .1)
self.scoreRect = Rectangle(pos=tmpPos, size=tmpSize)
def prepare(self):
#calculate the score
try:
self.finalScore = self.asteroidScore*100
except:
print 'problems getting score'
self.animateScore()
def animateScore(self):
#display score at 0 and every time interval add 100 until
#we reach the final score
#draw a score widget and schedule updates
scoreText = 'Score: 0'# + str(self.finalScore)
self.scoreLabel = Label(text=scoreText,font_size = '20sp')
self.scoreLabel.x = Window.width*0.3
self.scoreLabel.y = Window.height*0.3
self.add_widget(self.scoreLabel)
Clock.schedule_once(self.updateScore, .1)
self.drawStars()
def updateScore(self,dt):
self.currentScore = self.currentScore +100
self.scoreLabel.text = 'Score: ' + str(self.currentScore)
if self.currentScore < self.finalScore:
Clock.schedule_once(self.updateScore, 0.1)
def drawStars(self):
#0-10 asteroids 0 stars
#11-50 asteroids 1 star
#51-200 asteroids 2 stars
#201-500 asteroids 3 stars
#501-1000 asteroids 4 stars
#1001+ asteroids 5 stars
starNumber = 0
if self.asteroidScore > 10:
starNumber = 1
if self.asteroidScore > 50:
starNumber = 2
if self.asteroidScore > 200:
starNumber = 3
if self.asteroidScore > 500:
starNumber = 4
if self.asteroidScore > 1000:
starNumber = 5
with self.canvas:
#draw stars
#rect one
starPos = Window.width*0.27, Window.height*0.42
starSize = Window.width*0.06,Window.width*0.06
starString = 'gold_star.png'
if starNumber < 1:
starString = 'gray_star.png'
starRectOne = Rectangle(source=starString,pos=starPos, size = starSize)
#rect two
starPos = Window.width*0.37, Window.height*0.42
if starNumber < 2:
starString = 'gray_star.png'
starRectTwo = Rectangle(source=starString,pos=starPos, size = starSize)
#rect three
starPos = Window.width*0.47, Window.height*0.42
if starNumber < 3:
starString = 'gray_star.png'
starRectThree = Rectangle(source=starString,pos=starPos, size = starSize)
#rect four
starPos = Window.width*0.57, Window.height*0.42
if starNumber < 4:
starString = 'gray_star.png'
starRectFour = Rectangle(source=starString,pos=starPos, size = starSize)
#rect five
starPos = Window.width*0.67, Window.height*0.42
if starNumber < 5:
starString = 'gray_star.png'
starRectFive = Rectangle(source=starString,pos=starPos, size = starSize)
class Asteroid(WidgetDrawer):
#Asteroid class. The flappy ship will dodge these
imageStr = './sandstone_1.png'
rect_bg = Rectangle(source=imageStr)
velocity_x = NumericProperty(0)
velocity_y = NumericProperty(0)
def move(self):
self.x = self.x + self.velocity_x*5
self.y = self.y + self.velocity_y
def update(self):
self.move()
class Ship(WidgetDrawer):
#Ship class. This is for the main ship object.
#velocity of ship on x/y axis
#setup constants, health, etc
#choose default image:
impulse = 3
grav = -0.1
velocity_x = NumericProperty(0)
velocity_y = NumericProperty(0)
flameSize = (Window.width*.03, Window.width*.03)
def move(self):
self.x += self.velocity_x
self.y += self.velocity_y
#don't let the ship go too far
if self.y < Window.height*0.05:
#give upwards impulse
Clock.unschedule(self.update)
self.explode()
if self.y > Window.height*0.95:
Clock.unschedule(self.update)
self.explode()
def checkBulletNPCCollision(self, j):
if self.k.collide_widget(j):
j.health = j.health - self.k.bulletDamage
j.attackFlag = 'True'
#age the bullet
self.k.age = self.k.lifespan+10
def checkBulletStageCollision(self,q):
if self.k.collide_widget(q):
#if object type is asteorid
try:
if q.type == 'asteroid':
q.health = q.health - self.k.bulletDamage
self.k.age = self.k.lifespan+10
except:
print 'couldnt hit asteroid'
def determineVelocity(self):
#move the ship up and down
#we need to take into account our acceleration
#also want to look at gravity
self.grav = self.grav*1.05 #increase gravity
#set a grav limit
if self.grav < -4:
self.grav = -4
self.velocity_y = self.impulse + self.grav
self.impulse = 0.95*self.impulse
def drawArrow(self, *largs):
#draw the arrows directly onto the canvas
with self.canvas:
flamePos = (self.pos[0]-Window.width*.02, self.pos[1]+Window.width*.01)
flameRect = Rectangle(source='./flame.png', pos=flamePos, size=self.flameSize)
#schedule removal
def removeArrows(arrow, *largs):
self.canvas.remove(arrow)
Clock.schedule_once(partial(removeArrows, flameRect), .5)
Clock.schedule_once(partial(self.updateArrows, flameRect), 0.1)
def updateArrows(self, arrow, dt):
with self.canvas:
arrow.pos = (arrow.pos[0]-10, arrow.pos[1])
Clock.schedule_once(partial(self.updateArrows, arrow), 0.1)
return
def explode(self):
tmpSize = Window.width*0.25,Window.width*0.2
tmpPos = (self.x-Window.width*0.095, self.y-Window.width*0.08)
with self.canvas:
self.explosionRect = Rectangle(source ='./explosion1.png',pos=tmpPos,size=tmpSize)
def changeExplosion(rect, newSource, *largs):
rect.source = newSource
Clock.schedule_once(partial(changeExplosion, self.explosionRect, './explosion2.png'), 0.2)
Clock.schedule_once(partial(changeExplosion, self.explosionRect, './explosion3.png'), 0.4)
Clock.schedule_once(partial(changeExplosion, self.explosionRect, './explosion4.png'), 0.6)
Clock.schedule_once(partial(changeExplosion, self.explosionRect, './explosion5.png'), 0.8)
def removeExplosion(rect, *largs):
self.canvas.remove(rect)
Clock.schedule_once(partial(removeExplosion, self.explosionRect), 1)
def update(self):
self.determineVelocity()
self.move()
class GUI(Widget):
#this is the main widget that contains the game. This is the primary object
#that runs
asteroidList =[]
#important to use numericproperty here so we can bind a callback
#to use every time the number changes
asteroidScore = NumericProperty(0)
minProb = 1780
def __init__(self, **kwargs):
super(GUI, self).__init__(**kwargs)
#setup label for the score
self.score = Label(text = '0')
self.score.y = Window.height*0.8
self.score.x = Window.width*0.2
def check_score(self, obj):
#update credits
self.score.text = str(self.asteroidScore)
self.bind(asteroidScore = check_score)
self.add_widget(self.score)
#now we create a ship object
self.ship = Ship(imageStr = './ship.png')
self.ship.x = Window.width/4
self.ship.y = Window.height/2
self.add_widget(self.ship)
#self.ship.drawArrow()#start the flames
Clock.schedule_interval((self.ship.drawArrow), 0.1)
def addAsteroid(self):
#add an asteroid to the screen
#self.asteroid
imageNumber = randint(1, 4)
imageStr = './sandstone_'+str(imageNumber)+'.png'
tmpAsteroid = Asteroid(imageStr)
tmpAsteroid.x = Window.width*0.99
#randomize y position
ypos = randint(1, 16)
ypos = ypos*Window.height*.0625
tmpAsteroid.y = ypos
tmpAsteroid.velocity_y = 0
vel = 550#randint(10,25)
tmpAsteroid.velocity_x = -0.1*vel
self.asteroidList.append(tmpAsteroid)
self.add_widget(tmpAsteroid)
def drawTouchResponse(self,x,y):
#draw the arrows directly onto the canvas
with self.canvas:
tmpSize = Window.width*0.07, Window.width*0.07
tmpPos = (x-self.width/4,y-self.height/4)
self.arrowRect = Rectangle(source='./flame1.png',pos=tmpPos, size = tmpSize)
#schedule removal
def removeArrows(arrow, *largs):
self.canvas.remove(arrow)
def changeExplosion(rect, newSource, *largs):
rect.source = newSource
#schedule explosion two
Clock.schedule_once(partial(changeExplosion, self.arrowRect, './flame2.png'), 0.15)
#schedule explosion three
Clock.schedule_once(partial(changeExplosion, self.arrowRect, './flame3.png'), 0.3)
#schedule explosoin four
Clock.schedule_once(partial(changeExplosion, self.arrowRect, './flame4.png'), 0.45)
Clock.schedule_once(partial(removeArrows, self.arrowRect), 0.6)
#handle input events
def on_touch_down(self, touch):
self.ship.impulse = 3
self.ship.grav = -0.1
self.drawTouchResponse(touch.x, touch.y)
def showScore(self):
#this function will draw the score keeping widget, tabulate the score
#and rank with stars
self.scoreWidget = ScoreWidget()
self.scoreWidget.asteroidScore = self.asteroidScore #pass on score
self.scoreWidget.prepare()
self.add_widget(self.scoreWidget)
def removeScore(self):
self.remove_widget(self.scoreWidget)
def gameOver(self):
#add a restart button
restartButton = MyButton(text='Try Again')
#restartButton.background_color = (.5,.5,1,.2)
def restart_button(obj):
#reset game
self.removeScore()
for k in self.asteroidList:
self.remove_widget(k)
self.ship.xpos = Window.width*0.25
self.ship.ypos = Window.height*0.5
self.minProb = 1780
self.asteroidScore = 0
self.asteroidList = []
self.parent.remove_widget(restartButton)
Clock.unschedule(self.update)
Clock.schedule_interval(self.update, 1.0/60.0)
restartButton.size = (Window.width*.3,Window.width*.1)
restartButton.pos = Window.width*0.5-restartButton.width/2, Window.height*0.53
restartButton.bind(on_release=restart_button)
#we will want to bind the parent to listen for things from certain bubbles
#*** It's important that the parent get the button so you can click on it
#otherwise you can't click through the main game's canvas
self.parent.add_widget(restartButton)
#now draw the score widget
self.showScore()
def update(self, dt):
#This update function is the main update function for the game
#All of the game logic has its origin here
#events are setup here as well
#update game objects
#update ship
self.ship.update()
#update asteroids
#randomly add an asteroid
tmpCount = randint(1, 1800)
if tmpCount > self.minProb:
self.addAsteroid()
if self.minProb < 1300:
self.minProb = 1300
self.minProb -= 1
for k in self.asteroidList:
#check for collision with ship
if k.collide_widget(self.ship):
#game over routine
self.gameOver()
Clock.unschedule(self.update)
#add reset button
self.ship.explode()
k.update()
#check to see if asteroid is off of screen
if k.x < -100:
#since it's off the screen, remove the asteroid
self.remove_widget(k)
self.asteroidScore += 1
#remove asteroids off screen
tmpAsteroidList = self.asteroidList
tmpAsteroidList[:] = [x for x in tmpAsteroidList if (x.x > - 100)]
self.asteroidList = tmpAsteroidList
class ClientApp(App):
def build(self):
#this is where the root widget goes
#should be a canvas
self.parent = Widget() #
self.app = GUI()
#Start the game clock (runs update function once every (1/60) seconds
#Clock.schedule_interval(app.update, 1.0/60.0)
#add the start menu
self.sm = SmartStartMenu()
self.sm.buildUp()
def check_button(obj):
#check to see which button was pressed
if self.sm.buttonText == 'start':
#remove menu
self.parent.remove_widget(self.sm)
#start the game
print ' we should start the game now'
Clock.unschedule(self.app.update)
Clock.schedule_interval(self.app.update, 1.0/60.0)
try:
self.parent.remove_widget(self.aboutText)
except:
pass
if self.sm.buttonText == 'about':
self.aboutText = Label(text = 'Flappy Ship is made by Molecular Flow Games \n Check out: https://kivyspacegame.wordpress.com')
self.aboutText.pos = (Window.width*0.45,Window.height*0.35)
self.parent.add_widget(self.aboutText)
#bind a callback function that repsonds to event 'on_button_release' by calling function check_button
self.sm.bind(on_button_release = check_button)
#setup listeners for smartstartmenu
self.parent.add_widget(self.sm)
self.parent.add_widget(self.app) #use this hierarchy to make it easy to deal w/buttons
return self.parent
if __name__ == '__main__':
ClientApp().run()

Pygame only advances on keypress

I imagine this is a simple fix and have seen similar questions, but this is really frustrating me. Basically when you run the game, it only advances the simulation on a keypress, and not at a set framerate.
https://pastebin.com/aP6LsMMA
The main code is:
pg.init()
clock = pg.time.Clock()
FPS = 10
# ...
Game = Control()
while not Game.done:
Game.main_loop()
pg.display.update()
clock.tick(FPS)
pg.quit()
and the event handler method - within the Control class - is:
def event_handler(self):
for event in pg.event.get():
if event.type == pg.QUIT:
self.done = True
elif event.type == pg.KEYDOWN:
self.scene.process_event(event)
The weird thing to me is that, at the bottom of the pastebin, is my old testing code that is not done with classes for Scenes/Control. However, to my eye it should work exactly the same. I've tried putting in the clock both in and out of the Control class to no avail.
Any help (and general tips!) greatly appreciated.
Thanks
process_event() should only change variables which depend on events but it shouldn't update other values which should be updated in every frame. You have to move some elements to new method update() and execute it in every loop.
More or less
class Scene:
def process_event(self, event):
pass
def update(self):
pass
class GamePlayState(Scene):
def process_event(self, event):
self.snake.get_key(event)
def update(self):
self.snake.update()
self.snake.food_check(self.apple)
self.snake.collision_check()
if self.snake.alive == False:
print("GAME OVER")
print(self.snake.points)
self.done = True
class Control:
def update(self):
self.scene.update()
def main_loop(self):
self.event_handler()
self.update()
self.scene_checker()
self.draw()
Full working code
import pygame as pg
import sys
import random
import queue
# TODO: Walls, queue for keypress, scene stuff, 2 player, difficulty(?)
""" ######################
PREAMBLE
###################### """
""" Dictionaries for direction/velocity mapping - stolen from https://github.com/Mekire """
DIRECT_DICT = {"left" : (-1, 0), "right" : (1, 0),
"up" : (0,-1), "down" : (0, 1)}
KEY_MAPPING = {pg.K_LEFT : "left", pg.K_RIGHT : "right",
pg.K_UP : "up", pg.K_DOWN : "down"}
OPPOSITES = {"left" : "right", "right" : "left",
"up" : "down", "down" : "up"}
""" Colour Mapping """
BLACK = (0, 0, 0)
WHITE = (255, 255, 255)
DARK_GREY = (70, 70, 70)
GREY = (211, 211, 211)
GREEN = (0, 255, 0)
RED = (255, 0, 0)
COLOUR_MAP = {"snake": GREEN, "apple": RED, "wall": BLACK, "surface": GREY, "background": DARK_GREY }
""" ################
CLASSES
################ """
""" ####################### Object Classes ########################## """
class Square:
""" All other objects in the game will be built up from this """
def __init__(self, pos, colour, length):
self.xi, self.yi = pos # i for index, p for pixel
self.colour = colour
self.length = length
def display(self):
xp, yp = self.sq_to_pixs(self.xi, self.yi) # (x = left side, y = top edge)
pg.draw.rect(screen, self.colour, (xp, yp, self.length, self.length), 0)
def sq_to_pixs(self, x, y):
# Converts index of square to pixel coords
px = (x+1)*(2*MARGIN + SQUARE_SIZE) - MARGIN - SQUARE_SIZE
py = (y+1)*(2*MARGIN + SQUARE_SIZE) - MARGIN
return (px, py)
def index_coords(self): # TODO - remove for direct ref?
return (self.xi, self.yi)
class Arena:
""" A grid within which the game takes place """
def __init__(self, size, square_length, colour):
self.size = size # i.e. number of squares = size**2 for square arena
self.length = square_length # i.e. per square dimension
self.colour = colour
self.squares = [ [] for i in range(self.size) ]
for y in range(self.size):
for x in range(self.size):
self.squares[y].append(Square((x,y), self.colour, self.length))
def display(self):
for y in self.squares:
for square in y:
square.display()
class Snake:
""" Class for the agent(s) """
def __init__(self, pos, colour, square_length):
self.xi, self.yi = pos
self.colour = colour
self.size = 3
self.length = square_length
self.direction = "right"
self.direction_queue = queue.Queue(4) # TODO
self.points = 0
self.growing = False
self.alive = True
self.squares = []
for x in range(self.size): # horizontal initial orientation
self.squares.append(Square((self.xi - x, self.yi), self.colour, self.length))
def display(self):
for square in self.squares:
square.display()
def food_check(self, apple):
if self.squares[0].index_coords() == apple.square.index_coords():
self.growing = True
self.points += apple.points_value
apple.respawn([self])
def collision_check(self, walls = None):
xh, yh = self.squares[0].index_coords()
body = self.squares[-1:0:-1] # going backwards thru array as forwards [0:-1:1] didnt work...
def _collide(obstacles):
for sq in obstacles:
_x, _y = sq.index_coords()
if (_x == xh) and (_y == yh):
self.alive = False
_collide(body)
if walls is not None:
_collide(walls)
def update(self):
# Add new head based on velocity and old head
velocity = DIRECT_DICT[self.direction]
head_coords = [ (self.squares[0].index_coords()[i] + velocity[i]) for i in (0,1) ]
# Wrap around screen if reach the end
for i in (0, 1):
if head_coords[i] < 0:
head_coords[i] = SQUARES_PER_ARENA_SIDE - 1
elif head_coords[i] > SQUARES_PER_ARENA_SIDE - 1:
head_coords[i] = 0
self.squares.insert(0, Square(head_coords, self.colour, self.length))
if self.growing:
self.growing = False
else:
del self.squares[-1]
"""
def queue_key_press(self, key):
for keys in KEY_MAPPING:
if key in keys:
try:
self.direction_queue.put(KEY_MAPPING[keys], block=False)
break
except queue.Full:
pass
"""
class Player(Snake):
""" Human controlled snake via arrow keys """
def __init__(self, pos, colour, size):
Snake.__init__(self, pos, colour, size)
def get_key(self, event):
if event.type == pg.KEYDOWN and event.key in KEY_MAPPING:
new_direction = KEY_MAPPING[event.key]
if new_direction != OPPOSITES[self.direction]:
self.direction = new_direction
class Apple:
""" Food our (veggie) snake is greedily after """
def __init__(self, colour, length, points_value, snake):
self.colour = colour
self.length = length
self.xi, self.yi = self._rand_coords()
self.points_value = points_value
self.square = Square((self.xi, self.yi), self.colour, self.length)
def _rand_coords(self):
rand_num = lambda x: random.randint(0, x)
_x = rand_num(SQUARES_PER_ARENA_SIDE-1)
_y = rand_num(SQUARES_PER_ARENA_SIDE-1)
return _x, _y
def respawn(self, obstacles):
_x, _y = self._rand_coords()
for ob in obstacles:
for sq in ob.squares:
while sq.index_coords() == (_x, _y):
_x, _y = self._rand_coords()
self.square.xi, self.square.yi = _x, _y
def display(self):
self.square.display()
""" ################ SCENES ####################### """
class Scene:
""" Overload most of this - barebones structure
A bit pointless in current state but easily expanded """
def __init__(self):
self.done = False
def when_activated(self):
pass
def reset(self):
self.done = False
def render(self):
pass
def process_event(self, event):
pass
def update(self):
pass
class StartUp(Scene):
def __init__(self):
Scene.__init__(self)
def render(self):
# test placeholder
pass
def when_activated(self):
print("Press any key to continue")
def process_event(self, event):
if event.type == pg.KEYDOWN:
self.done = True
class GamePlayState(Scene):
def __init__(self):
Scene.__init__(self)
self.arena = Arena(SQUARES_PER_ARENA_SIDE, SQUARE_SIZE, COLOUR_MAP["surface"])
self.snake = Player(SNAKE_START, COLOUR_MAP["snake"], SQUARE_SIZE)
self.apple = Apple(COLOUR_MAP["apple"], SQUARE_SIZE, 1, self.snake)
self.font = pg.font.SysFont("courier new", 50)
def render(self):
screen.fill(COLOUR_MAP["background"])
self.arena.display()
self.apple.display()
self.snake.display()
text = self.font.render(str(self.snake.points), True, [255,255,255])
screen.blit(text, (500, 400))
def process_event(self, event):
self.snake.get_key(event)
def update(self):
self.snake.update()
self.snake.food_check(self.apple)
self.snake.collision_check()
if self.snake.alive == False:
print("GAME OVER")
print(self.snake.points)
self.done = True
""" ################## CONTROL CLASS #########################"""
class Control:
def __init__(self):
#self.clock = pg.time.Clock()
#self.fps = FPS
self.done = False
self.scene_array = [StartUp(), GamePlayState()]
self.scene_index = 0 # dirty way whilst dict method needs tinkering
#self.scene_dict = {"START": StartUp(), "GAME": GamePlayState()} #TODO
self.scene = self.scene_array[self.scene_index]
#self.scene = self.scene_dict["START"]
self.scene.when_activated()
def event_handler(self):
for event in pg.event.get():
if event.type == pg.QUIT:
self.done = True
elif event.type == pg.KEYDOWN:
self.scene.process_event(event)
def scene_checker(self):
if self.scene.done:
self.scene.reset() # for reuse - TODO
self.scene_index = (self.scene_index + 1) % len(self.scene_array)
self.scene = self.scene_array[self.scene_index]
self.scene.when_activated()
#self.scene = self.scene_dict[self.scene.next]
def update(self):
self.scene.update()
def draw(self):
self.scene.render()
def main_loop(self):
self.event_handler()
self.update()
self.scene_checker()
self.draw()
""" ################ RUN GAME ################ """
""" Game paramaters """
SQUARE_SIZE = 20 # pixels
SQUARES_PER_ARENA_SIDE = 20 # squares
MARGIN = 2 # pixels
SNAKE_START = (int(SQUARES_PER_ARENA_SIDE/2), int(SQUARES_PER_ARENA_SIDE/2)) # square coords
pg.init()
clock = pg.time.Clock()
# Square.display() and a few others need a direct reference to "screen" TODO implement better
w, h = 620, 620
SCREEN_SIZE = [w, h]
FPS = 10
screen = pg.display.set_mode(SCREEN_SIZE)
Game = Control()
while not Game.done:
Game.main_loop()
pg.display.update()
clock.tick(FPS)
pg.quit()

Python Class Syntax Error

I have been following a guide to make my game. However, when I try to run the program I get a syntax Error with the Class Circle and not sure why? I can't figure out the reason and I'm sure there are more issue afterward the Class Circle but can't fix it.
import pygame
from pygame.locals import *
from uagame import Window
import time
import random
def main():
window = Window('Pong', 500, 400)
window.set_auto_update(False)
game = Game(window)
game.play()
window.close()
class Rect:
def __init__(self, center, radius, color, window):
self.center = center
self.radius = radius
self.color = color
self.window = window
def draw(self):
pygame.draw.rect(self.window.get_surface(), self.color, Rect((100, 200), (20, 30))
class Circle: # Syntax Error: class Circle:: <string>, line 28, pos 5
def __init__(self, center, radius, color, window):
self.center = center
self.radius = radius
self.color = color
self.window = window
def draw(self):
pygame.draw.circle(self.window.get_surface(), self.color, self.center,self.radius)
def get_color(self):
return self.color
def move(self):
window_size = (self.window.get_width() , self.window.get_height())
for index in range(0,2):
self.center[index] = (self.center[index] + 1) % window_size[index]
def enlarge(self,increment):
self.radius = self.radius + increment
class Game:
def __init__(self, window):
self.window = window
self.bg_color = pygame.Color('black')
self.fg_color = 'green'
self.rect_color = 'green'
self.pause_time = 0.02
self.close_clicked = False
self.continue_game = True
self.circle = Ball([200,200], 20, pygame.Color(self.fg_color),window)
self.rect = Rect([100,200], 50 , pygame.Color(self.fg_color),window)
self.radius_increment = 5
def play(self):
while not self.close_clicked:
self.handle_event()
self.draw()
if self.continue_game:
self.update()
self.decide_continue()
time.sleep(self.pause_time)
def handle_event(self):
event = pygame.event.poll()
if event.type == QUIT:
self.close_clicked = True
elif event.type == MOUSEBUTTONUP and self.continue_game:
self.handle_mouse_up()
def handle_mouse_up(self):
self.circle.enlarge(self.radius_increment)
def draw(self):
self.window.clear()
self.circle.draw()
self.rect.draw()
if not self.continue_game:
self.window.set_bg_color(self.fg_color)
self.window.clear()
self.window.update()
def update(self):
self.circle.move()
def decide_continue(self):
pass
main()
Your error actually lies in the line above. See that your code is missing a parenthesis to close the rect() function. Always remember to count the parenthesis on long functions like this.
def draw(self):
pygame.draw.rect(self.window.get_surface(), self.color, Rect((100, 200), (20, 30))) #<-

Sprite in Pyglet not doing what I want

I am trying to have a circle that, when clicked, moves somewhere else on the screen. However, when I click the circle, nothing happens.
#IMPORT STUFF
import pyglet as pg
from random import randint
mouse = pg.window.mouse
#VARS
window = pg.window.Window(width = 640, height = 480)
score = 0
circleImg = pg.image.load("circle.png")
circle = pg.sprite.Sprite(circleImg, randint(1, window.width), randint(1, window.height))
text = pg.text.Label("Click red!", font_name = "Times New Roman", font_size = 18, x = 260, y = 10)
#DETECT MOUSE PRESS ON CIRCLE
#window.event
def on_mouse_press(x, y, button, modifiers):
if x == circle.x and y == circle.y:
circle.x = randint(1, window.width)
circle.y = randint(1, window.height)
#window.event
def on_draw():
window.clear()
text.draw()
circle.draw()
pg.app.run()
import pyglet
from pyglet.gl import *
from random import randint
glEnable(GL_BLEND)
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)
class Circle(pyglet.sprite.Sprite):
def __init__(self, radiance=5, x=0, y=0):
self.texture = pyglet.image.load('circle.png')
super(Circle, self).__init__(self.texture)
def click(self, x, y):
if x >= self.x and y >= self.y:
if x <= self.x + self.texture.width and y <= self.y + self.texture.height:
return self
mouse = pyglet.window.mouse
#VARS
window = pyglet.window.Window(width = 640, height = 480)
score = 0
#circleImg = pyglet.image.load("circle.png")
#circle = pyglet.sprite.Sprite(circleImg, randint(1, window.width), randint(1, window.height))
circle = Circle(x=50, y=50)
text = pyglet.text.Label("Click red!", font_name = "Times New Roman", font_size = 18, x = 260, y = 10)
#DETECT MOUSE PRESS ON CIRCLE
#window.event
def on_mouse_press(x, y, button, modifiers):
if circle.click(x, y):
print('Clicked in circle')
circle.x = randint(0, window.width - 10)
circle.y = randint(0, window.height - 10)
#window.event
def on_draw():
window.clear()
text.draw()
circle.draw()
pyglet.app.run()
A short description of what this does is it creates a custom class called Circle that inherits the Sprite class. It loads the circle.png as a texture with a alpha channel that gets blended by the GL library.
We add a custom function called click that checks if the lowest x,y coordinates are higher than the circles lowest x,y, then we check if the cursor is below x+width and same for y of the image region.
If that's the case, we return the circle sprite class as a True value in case we want to use the sprite.
Future enhancements:
You should draw the circle using gl functions, hence why I've defined radiance in the class definitions. However radiance here is never used, it's a placeholder for the future.
This is so you can use math to defined if you actually clicked within the circle, but this is beyond my scope of quick answers.. I would have to do a lot of debugging myself in order to get the math to add up (it's not my strong side).
What makes it work now is that we use the image width, height, x and y data to crudely check if we're within the image, aka "the circle".
trying to draw over sprite or change picture pyglet
As a bonus, I'll add this answer to the list of enhancements because it contains some stuff that might be useful. One would be to replace 90% of your code with a custom pyglet.window.Window class to replace global variables and decorators and stuff.
And it would look something like this:
import pyglet
from pyglet.gl import *
from random import randint
glEnable(GL_BLEND)
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)
key = pyglet.window.key
class Circle(pyglet.sprite.Sprite):
def __init__(self, radiance=5, x=0, y=0):
self.texture = pyglet.image.load('circle.png')
super(Circle, self).__init__(self.texture)
def click(self, x, y):
if x >= self.x and y >= self.y:
if x <= self.x + self.texture.width and y <= self.y + self.texture.height:
return self
class MainScreen(pyglet.window.Window):
def __init__ (self):
super(MainScreen, self).__init__(800, 600, fullscreen = False)
self.x, self.y = 0, 0
self.bg = pyglet.sprite.Sprite(pyglet.image.load('background.jpg'))
self.sprites = {}
self.sprites['circle'] = Circle(x=50, y=50)
self.sprites['label'] = pyglet.text.Label("Click red!", font_name = "Times New Roman", font_size = 18, x = 260, y = 10)
self.alive = 1
def on_draw(self):
self.render()
def on_close(self):
self.alive = 0
def on_mouse_press(self, x, y, button, modifiers):
if self.sprites['circle'].click(x, y):
print('Clicked in circle')
self.sprites['circle'].x = randint(0, self.width - 10)
self.sprites['circle'].y = randint(0, self.height - 10)
def on_key_press(self, symbol, modifiers):
if symbol == key.ESCAPE: # [ESC]
self.alive = 0
def render(self):
self.clear()
self.bg.draw()
for sprite_name, sprite_obj in self.sprites.items():
sprite_obj.draw()
self.flip()
def run(self):
while self.alive == 1:
self.render()
# -----------> This is key <----------
# This is what replaces pyglet.app.run()
# but is required for the GUI to not freeze
#
event = self.dispatch_events()
x = MainScreen()
x.run()
I'm not familiar with pyglet, but I'm guessing the problem is that you're checking whether x == circle.x etc, which means it only moves when you click the single pixel at the exact centre of the circle. Try some kind of maximum distance from the centre (e.g. a hypotenuse math.sqrt( (x-circle.x)**2 + (y-circle.y)**2) < circle.radius

Menu for a game made in Pygame

I have no clue how I would implement a game menu into the game I've made, I was thinking about having buttons for instructions credits and a 'play game' button. So would someone mind helping me out in figuring how to make a simple menu in pygame or livewires? Thanks in advance :)
This is the complete code to my game:
# Asteroid Dodger
# Player must avoid asteroids
# make the score a global variable rather than tied to the asteroid.
import pygame
from livewires import games, color
import math, random
#score
games.init(screen_width = 640, screen_height = 480, fps = 50)
score = games.Text(value = 0, size = 25, color = color.green,
top = 5, right = games.screen.width - 10)
games.screen.add(score)
#lives
lives = games.Text(value = 3, size = 25, color = color.green,
top = 5, left = games.screen.width - 620)
games.screen.add(lives)
#inventory
inventory=[]
#Asteroid images
images = [games.load_image("asteroid_small.bmp"),
games.load_image("asteroid_med.bmp"),
games.load_image("asteroid_big.bmp")]
class Ship(games.Sprite):
"""
A Ship controlled by player that explodes when it by Asteroids.
"""
image = games.load_image("player.bmp")
VELOCITY_STEP = .05
def __init__(self):
""" Initialize Ship object """
super(Ship, self).__init__(image = Ship.image,
bottom = games.screen.height)
def update(self):
global inventory
""" uses A and D keys to move the ship """
if games.keyboard.is_pressed(games.K_a):
self.dx -= Ship.VELOCITY_STEP * 2
if games.keyboard.is_pressed(games.K_d):
self.dx += Ship.VELOCITY_STEP * 2
if self.left < 0:
self.left = 0
if self.right > games.screen.width:
self.right = games.screen.width
self.check_collison()
def ship_destroy(self):
self.destroy()
new_explosion = Explosion(x = self.x, y = self.y)
games.screen.add(new_explosion)
def check_collison(self):
""" Check for overlapping sprites in the ship. """
global lives
for items in self.overlapping_sprites:
items.handle_caught()
if lives.value <=0:
self.ship_destroy()
class Explosion(games.Animation):
sound = games.load_sound("explosion.wav")
images = ["explosion1.bmp",
"explosion2.bmp",
"explosion3.bmp",
"explosion4.bmp",
"explosion5.bmp",
"explosion6.bmp",
"explosion7.bmp",
"explosion8.bmp",
"explosion9.bmp"]
def __init__(self, x, y):
super(Explosion, self).__init__(images = Explosion.images,
x = x, y = y,
repeat_interval = 4, n_repeats = 1,
is_collideable = False)
Explosion.sound.play()
class Asteroid(games.Sprite):
global lives
global score
global inventory
"""
A asteroid which falls through space.
"""
image = games.load_image("asteroid_med.bmp")
speed = 3
def __init__(self, x,image, y = 10):
""" Initialize a asteroid object. """
super(Asteroid, self).__init__(image = image,
x = x, y = y,
dy = Asteroid.speed)
def update(self):
""" Check if bottom edge has reached screen bottom. """
if self.bottom>games.screen.height:
self.destroy()
score.value+=10
def handle_caught(self):
if lives.value>0:
lives.value-=1
self.destroy_asteroid()
if lives.value <= 0:
self.destroy_asteroid()
self.end_game()
def destroy_asteroid(self):
self.destroy()
def die(self):
self.destroy()
def end_game(self):
""" End the game. """
end_message = games.Message(value = "Game Over",
size = 90,
color = color.red,
x = games.screen.width/2,
y = games.screen.height/2,
lifetime = 5 * games.screen.fps,
after_death = games.screen.quit)
games.screen.add(end_message)
class Spawner(games.Sprite):
global images
"""
Spawns the asteroids
"""
image = games.load_image("spawner.bmp")
def __init__(self, y = 10, speed = 5, odds_change = 50):
super(Spawner, self).__init__(image = Spawner.image,
x = games.screen.width / 2,
y = y,
dx = speed)
self.odds_change = odds_change
self.time_til_drop = 0
def update(self):
""" Determine if direction needs to be reversed. """
if self.left < 0 or self.right > games.screen.width:
self.dx = -self.dx
elif random.randrange(self.odds_change) == 0:
self.dx = -self.dx
self.check_drop()
self.check_for_lives()
def check_drop(self):
""" Decrease countdown or drop asteroid and reset countdown. """
if self.time_til_drop > 0:
self.time_til_drop -= 0.7
else:
asteroid_size = random.choice(images)
new_asteroid = Asteroid(x = self.x,image = asteroid_size)
games.screen.add(new_asteroid)
# makes it so the asteroid spawns slightly below the spawner
self.time_til_drop = int(new_asteroid.height * 1.3 / Asteroid.speed) + 1
def check_for_lives(self):
droplives = random.randrange(0, 4000)
if droplives == 5:
lifetoken = Extralives(x = self.x)
g ames.screen.add(lifetoken)
class Extralives(games.Sprite):
global lives
image = games.load_image('addlives.png')
speed = 2
sound = games.load_sound("collectlives.wav")
def __init__(self,x,y = 10):
""" Initialize a asteroid object. """
super(Extralives, self).__init__(image = Extralives.image,
x = x, y = y,
dy = Extralives.speed)
def update(self):
""" Check if bottom edge has reached screen bottom. """
if self.bottom>games.screen.height:
self.destroy()
def handle_caught(self):
Extralives.sound.play()
lives.value+=1
self.destroy()
def main():
""" Play the game. """
bg = games.load_image("space.jpg", transparent = False)
games.screen.background = bg
the_spawner = Spawner()
games.screen.add(the_spawner)
pygame.mixer.music.load("Jumpshot.ogg")
pygame.mixer.music.play()
the_ship = Ship()
games.screen.add(the_ship)
games.mouse.is_visible = False
games.screen.event_grab = True
games.screen.mainloop()
#starts the game
main()
The Pygbutton module provides a way to create buttons in Pygame programs. You can download it via "pip install pygbutton". There are demos on the github: https://github.com/asweigart/pygbutton
Try this code out:
Game Menu function
def game_intro():
intro = True
while intro:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
quit()
gameDisplay.fill(white)
titleText = gameDisplay.blit(title, (170, 200)) # title is an image
titleText.center = ((display_width / 2), (display_height / 2))
# button(x, y, w, h, inactive, active, action=None)
button(100, 350, 195, 80, startBtn, startBtn_hover, game_loop)
button(300, 350, 195, 80, creditsBtn, creditsBtn_hover, #Your function)
pygame.display.update()
clock.tick(15)
you can call this menu above your game loop.
Button function
Pygame doesn't have buttons but it is pretty easy to make one!
def button(x, y, w, h, inactive, active, action=None):
mouse = pygame.mouse.get_pos()
click = pygame.mouse.get_pressed()
if x + w > mouse[0] > x and y + h > mouse[1] > y:
gameDisplay.blit(active, (x, y))
if click[0] == 1 and action is not None:
action()
else:
gameDisplay.blit(inactive, (x, y))
you can call this function inside your game menu like this:
#Example function call
button(340, 560, 400, 200, randomBtn, randomBtn_hover, random_func)
Here's what each parameter means in button():
x: x-coordinate of button
y: y-coordinate of button
w: button width(in pixels)
h: button height(in pixels)
active: the picture of the button when it is active(e.g when the mouse is hovering ver it)
inactive: the picture of the button when it is idle
action: the function to be executed when the button is pressed
Note: It is better to make a button function since it is easier to make one and it saves a lot of time
Hope this helped!

Categories

Resources