Implement a reset feature in Kivy App - python

Below is a little Kivy app I'm working on. At the moment I'm trying to implement a basic reset feature. Essentially, if an enemy collides with the player, I want the game to reset. The games ends by unscheduling clock schedules upon collision with an enemy. I thought after that I could just call main() afterwards, but this simply causes massive bugs where the game spews out errors left and right. I also tried added reschedule rules after the unshedule, but that just overrides the unshedule and keeps the game going.
Note: The game is handled mostly from the game class towards the bottom of the code. It's also where you'll see clock schedule rules.
import kivy
kivy.require('1.1.1')
from kivy.app import App
from kivy.uix.widget import Widget
from kivy.properties import ObjectProperty, ListProperty, NumericProperty, BooleanProperty
from kivy.core.audio import SoundLoader
import math
from kivy.clock import Clock
import time
import random
sound = SoundLoader.load('gamemusic.mp3')
PLAYER_SPEED = 10
ENEMY_SPEED = 4
ENEMY_SPAWN = 5
UPDATE_SPEED = .01
MIN_INITIAL_PLAYER_MINION_DISTANCE = 200
UPDATE_SCORE = 1
MAX_DECOYS = 3
if sound:
sound.loop = True
sound.play()
class Movable(Widget):
velocity_x = NumericProperty(0)
velocity_y = NumericProperty(0)
target = ListProperty([])
def move(self):
dx = self.target[0] - self.center[0]
dy = self.target[1] - self.center[1]
total = math.sqrt(dx**2 + dy**2)
if total >0:
self.velocity_x = (dx / total) * self.speed
self.velocity_y = (dy / total) * self.speed
new_x = self.pos[0] + self.velocity_x
new_y = self.pos[1] + self.velocity_y
self.pos = (new_x,new_y)
elif total <=0:
self.velocity_x = self.speed
self.velocity_y = self.speed
class Player(Movable):
target = ListProperty([])
def __init__(self, **kwargs):
Widget.__init__(self)
self.target = [399.0, 399.0]
self.speed = PLAYER_SPEED
def update_target(self, new_target):
self.target = new_target
if distance_pos(self.center, self.target) <= self.speed*2:
self.target = self.center
class Enemy(Movable):
randomColor = random.randint(0,1)
alert = BooleanProperty(False)
def __init__(self, **kwargs):
Widget.__init__(self)
self.world_width = kwargs.get("width",0)
self.world_height = kwargs.get("height",0)
self.speed = ENEMY_SPEED
x_target = float(random.randint(0, self.world_width))
y_target = float(random.randint(0, self.world_height))
self.target = [x_target, y_target]
self.center = kwargs.get('start_pos',[0,0])
def update_target(self, player, enemies, decoys):
alert_list = self.alerted(enemies)
if len(decoys) > 0:
self.target = decoys[0].center
self.alert = False
elif distance(player, self) < 150:
self.alert = True
self.target = player.center
elif len(alert_list) > 0:
self.target = alert_list[0].center
self.alert = False
else:
if distance_pos(self.center, self.target) <= self.speed*2:
x_new_target = float(random.randint(0, self.world_width))
y_new_target = float(random.randint(0, self.world_height))
self.target = [x_new_target, y_new_target]
def alerted(self, enemies):
alert_list = []
for item in enemies:
if item.alert == True and distance(self, item) < 150:
alert_list.append(item)
return alert_list
class Decoy(Widget):
def __init__(self, **kwargs):
Widget.__init__(self)
self.center = kwargs.get('start_pos',[0,0])
pass
def distance(widget1, widget2):
return distance_pos(widget1.center, widget2.center)
def distance_pos(pos1, pos2):
dist = math.sqrt((pos1[0]-pos2[0])**2 + (pos1[1]-pos2[1])**2)
return dist
class Game(Widget):
player1 = ObjectProperty(None)
enemies = ListProperty([])
decoys = ListProperty([])
score = NumericProperty()
def setup(self):
self.enemies = []
self.decoys = []
self.player1.center = self.center
self.setup_schedules()
#Don't forget about good code organization!
def setup_schedules(self):
Clock.schedule_interval(self.update, UPDATE_SPEED)
Clock.schedule_interval(self.spawn_enemy, ENEMY_SPAWN)
Clock.schedule_interval(self.increase_score, UPDATE_SCORE)
def update(self,dt):
self.player1.move()
for item in self.enemies:
item.update_target(self.player1,self.enemies,self.decoys)
item.move()
if self.player1.collide_widget(item):
Clock.unschedule(self.spawn_enemy)
Clock.unschedule(self.update)
Clock.unschedule(self.increase_score)
"""
def death_restart(self, player):
if self.collide_widget(player):
print("error")
#main()
"""
def spawn_enemy(self, dt):
if len(self.enemies) <= 8:
x = float(random.randint(0, self.width))
y = float(random.randint(0, self.height))
enemy = Enemy(start_pos = (x,y),width = self.width,height = self.height)
while distance(enemy, self.player1)< MIN_INITIAL_PLAYER_MINION_DISTANCE:
x = float(random.randint(0, self.width))
y = float(random.randint(0, self.height))
enemy.pos = (x,y)
self.enemies.append(enemy)
self.add_widget(enemy)
def spawn_decoy(self, location):
x = location[0]
y = location[1]
decoy = Decoy(start_pos = (x,y))
self.decoys.append(decoy)
self.add_widget(decoy)
def increase_score(self, dt):
self.score += 1
#on_touch_move vs on_touch_down
def on_touch_move(self, touch):
self.player1.update_target([touch.x, touch.y])
def on_touch_down(self, touch):
if touch.is_double_tap and len(self.decoys) < MAX_DECOYS:
self.spawn_decoy([touch.x, touch.y])
#Entry Point into app
class GameApp(App):
def build(self):
game = Game()
game.setup()
return game
def main():
GameApp().run()
main()

Related

Snake Game: How to make the snake's body gets trimmed when its head touches its body?

I have a assignment that ask me to make a snake game with Python. The assignment asks me to make the snake's body gets trimmed when its head touches the body.
The snake body is a queue, so here is the code for forming a queue:
The snake's head is defined as the rear node and the snake's tail is defined as the front node, as shown in the picture below.
#The code of forming a queue, it cannot be modified
class Node:
def __init__(self, x, y):
self.x = x
self.y = y
self.pre = None
self.next = None
class Queue:
def __init__(self):
self.front = None
self.rear = None
def len(self):
length = 0
cur = self.front
while cur:
cur = cur.next
length += 1
return length
def enQueue(self, x, y):
new = Node(x, y)
if self.len() == 0:
self.front = new
self.rear = new
else:
new.pre = self.rear
self.rear.next = new
self.rear = new
def deQueue(self):
if self.len() <= 1:
self.front = None
self.rear = None
else:
self.front = self.front.next
self.front.pre = None
def reverse(self):
cur = self.front
self.rear, self.front = self.front , self.rear
while cur:
cur.next, cur.pre = cur.pre, cur.next
cur = cur.pre
def printQueue(self):
cur = self.front
print("front", end=" ")
while cur:
print(f"[{cur.x}, {cur.y}]", end=" ")
cur = cur.next
print("rear")
And this is the main code for the game:
import pygame, sys, time, random
from pygame.locals import *
from pathlib import Path, os
from coor_queue import Node, Queue
from item_stack import Stack
class SnakeGame:
def __init__(self):
self.g = 30 #The width of each grid
self.dir = "right" #Initial Direction
self.snake = Queue() #Queue of the snake
for i in range(9):
self.snake.enQueue(i*self.g,9*self.g)
self.init_params()
self.init_pygame()
self.init_objects()
self.init_images()
#The code above cannot be modified
# =========================== Movement ===========================
def move(self):
headx = self.snake.rear.x
heady = self.snake.rear.y
if self.dir == "down":
heady += self.g
self.snake.enQueue(headx, heady)
self.snake.deQueue()
if self.dir == "up":
heady -= self.g
self.snake.enQueue(headx, heady)
self.snake.deQueue()
if self.dir == "left":
headx -= self.g
self.snake.enQueue(headx, heady)
self.snake.deQueue()
if self.dir == "right":
headx += self.g
self.snake.enQueue(headx, heady)
self.snake.deQueue()
# =========================== Add Tails ===========================
def add_tail(self):
tailx = self.snake.front.x
taily = self.snake.front.y
newtail = Node(tailx, taily)
newtail.next = self.snake.front
self.snake.front.pre = newtail
self.snake.front = newtail
# =========================== Trim the snake's body ===========================
def eat_body(self):
# If the snake's head touches a grid (node) of the body
# Then the part from original tail to the grid which the snake's head touches
# Hint: Use self.snake
# ============The code below cannot be modified======================
def main(self):
while True:
self.keyboard_input()
self.check_input_valid()
self.move()
self.eat()
self.display()
if self.is_dead():
self.game_over()
self.fps.tick(8 + self.speed//5)
def keyboard_input(self): # Keyboard input
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
sys.exit()
if event.type == KEYDOWN:
if event.key == ord("d") or event.key == K_RIGHT: self.input_dir = "right"
if event.key == ord("a") or event.key == K_LEFT: self.input_dir = "left"
if event.key == ord("w") or event.key == K_UP: self.input_dir = "up"
if event.key == ord("s") or event.key == K_DOWN: self.input_dir = "down"
if event.key == K_ESCAPE: pygame.event.post(pygame.event.Event(QUIT))
def check_input_valid(self): #If the input direction is the opposite of the original direction, the input will be invalid
if (self.input_dir == "right" and self.dir != "left") or (self.input_dir == "left" and self.dir != "right") or \
(self.input_dir == "up" and self.dir != "down") or (self.input_dir == "down" and self.dir != "up"):
self.dir = self.input_dir
def eat(self): #Eat body or food
self.eat_food()
self.eat_body()
def display(self):
#Background
self.blit_map()
#Snake body
cur = self.snake.rear.pre
while cur:
self.blit_image("body", cur.x, cur.y, self.g, self.g)
cur = cur.pre
#Snake head
if self.snake.rear.x < self.width:
self.blit_image("head", self.snake.rear.x, self.snake.rear.y, self.g, self.g)
#Food
self.blit_image(self.food, self.foodPos.x, self.foodPos.y, self.g, self.g)
#Status Bar
self.blit_status_bar()
pygame.display.flip()
def is_dead(self):
return (self.snake.rear.x == self.width or self.snake.rear.x < 0) or \
(self.snake.rear.y == self.height or self.snake.rear.y < 0)
def game_over(self): # Game Over
self.play_theme("game_over1")
time.sleep(3)
pygame.quit()
sys.exit()
def init_params(self): #Basic parameters
self.screen_width = 1140
self.screen_height = 540
self.width = 960
self.height = 540
self.speed = 0
self.prob = 25
self.score = 0
self.spf = 10
self.satiety = 0
self.input_dir = None
def init_pygame(self): #Initialize pygame
pygame.init()
self.fps = pygame.time.Clock() #
self.screen = pygame.display.set_mode((self.screen_width, self.screen_height)) #
pygame.display.set_caption("Snake Game") #
pygame.mixer.init()
def init_objects(self):
self.food_list = [food.split(".")[0] for food in os.listdir(Path("src/image/food"))]
self.food = None
self.select_food()
self.foodPos = Node(self.width//2, self.height//2)
def init_images(self):
self.img_StatusBar = pygame.image.load(Path("src/image/other/StatusBar.jpg")).convert_alpha()
self.img_head = pygame.image.load(Path("src/image/snake/SnakeHead.jpg")).convert_alpha()
self.img_body = pygame.image.load(Path("src/image/snake/SnakeBody.jpg")).convert_alpha()
self.img_map = pygame.image.load(Path("src/image/map/Map1.jpg")).convert_alpha()
for food in self.food_list:
exec(f"self.img_{food} = pygame.image.load(Path('src/image/food/{food}.jpg')).convert_alpha()")
def eat_food(self):
if self.snake.rear.x == self.foodPos.x and self.snake.rear.y == self.foodPos.y:
self.satiety += 1
self.speed += 1
self.spf = 10 + ((self.satiety-1)//10)*10
self.score += self.spf
self.play_effect("eat_food")
x = random.randrange(1, self.width//self.g)
y = random.randrange(1, self.height//self.g)
self.foodPos.x = x*self.g
self.foodPos.y = y*self.g
self.select_food()
self.add_tail()
def select_food(self):
while True:
next_food = self.food_list[random.randrange(len(self.food_list))]
if next_food != self.food:
self.food = next_food
break
def play_theme(self, theme):
pygame.mixer.music.load(Path(f"src/sound/theme/{theme}.mp3"))
pygame.mixer.music.set_volume(0.5)
pygame.mixer.music.play()
def play_effect(self, effect):
sound = pygame.mixer.Sound(Path(f"src/sound/effect/{effect}.mp3"))
sound.set_volume(0.7)
sound.play()
def blit_image(self, name, coor_x = 0, coor_y = 0, size_x = 0, size_y = 0):
exec(f"self.img_{name} = pygame.transform.scale(self.img_{name}, size=(size_x, size_y))")
exec(f"self.screen.blit(self.img_{name}, (coor_x, coor_y))")
def blit_rect(self, data, coor_x = 0, coor_y = 0, font_size = 80, color = (0, 0, 0)):
self.Font = pygame.font.SysFont("", font_size)
self.Surf = self.Font.render(str(data), True, color)
self.Rect = self.Surf.get_rect()
self.Rect.center = (coor_x, coor_y)
self.screen.blit(self.Surf, self.Rect)
def blit_map(self):
self.blit_image("map", 0, 0, self.width, self.height)
def blit_status_bar(self):
self.blit_image("StatusBar", 960, 0, 180, self.screen_height)
self.blit_rect(self.score, 35*self.g, 1.87*self.g, font_size = 50, color = (238, 0, 0))
self.blit_rect(int(8 + self.speed)-7, 35*self.g, 4.13*self.g, font_size = 50, color = (178, 58, 238))
self.blit_rect(self.snake.len(), 35*self.g, 6.28*self.g, font_size = 50, color = (50, 205, 50))
# ==================================================================
game = SnakeGame()
game.main()
The picture below explains how trimming snake body works, the Python logo is the head.
I understand that the condition of trimming the body is when the head reaches the same grid as a part of the body. But I have no idea how to write this condition because I'm not sure if there is a way to get the coordinate from the nodes between front node and rear node.
Some further explanation is appreciated, thanks in advance.
Use a loop to compare the head of the queue against all elements of the body. The loop is similar to the loop in the print method. Return true if the position of the head is equal to a body position, else return false:
def isHeadEqualAnyBodyItem(snake):
head = snake.front
if not head:
return False
body = head.next
while body:
if head.x == body.x and head.y == body.y
return True
body = body.next
return False

Kivy app shows on the left bottom of screen

My Kivy app shows on left bottom of screen of phone (You can see in shared screenshot).But I want to make it fullscreen.I make value of "fullscreen" equal to 1 in "buildozer.spec" file.But nothing changed.Here is my code:
from kivy.app import App
from kivy.core.window import Window
from kivy.uix.gridlayout import GridLayout
from kivy.uix.widget import Widget
from kivy.uix.image import Image
from kivy.clock import Clock
from kivy.uix.behaviors import ButtonBehavior
from kivy.core.audio import SoundLoader
Window.size = (320,640)
opart = False
vpart = False
rpart = False
och = False
vch = False
rch = False
ofin = False
vfin = False
rfin = False
fin = True
snd_part = SoundLoader.load("part.wav")
music = SoundLoader.load("music.wav")
music.play()
class Orange(ButtonBehavior,Image):
def __init__(self,**kwargs):
super(Orange,self).__init__(**kwargs)
self.source = "obal.png"
self.size = (85,113)
self.pos = (32,300)
def on_press(self):
global opart
opart = True
Clock.schedule_interval(self.todown,0.1)
def todown(self,*args):
global och
if not och:
snd_part.play()
self.source = "effect.png"
och = True
else:
self.x = 28
self.source = "esma.png"
if self.y > 250:
self.y -= 4
else:
self.y = 250
global ofin,fin
ofin = True
if vfin and rfin and fin:
fin = False
win.kill_platform()
class Violet(ButtonBehavior,Image):
def __init__(self,**kwargs):
super(Violet,self).__init__(**kwargs)
self.source = "vbal.png"
self.size = (85,113)
self.pos = (117,364)
def on_press(self):
global vpart
vpart = True
Clock.schedule_interval(self.todown,0.1)
def todown(self,*args):
global vch
if not vch:
snd_part.play()
self.source = "effect.png"
vch = True
else:
self.x = 113
self.source = "yaxsiki.png"
if self.y > 250:
self.y -= 4
else:
self.y = 250
global vfin,fin
vfin = True
if ofin and rfin and fin:
fin = False
win.kill_platform()
class Red(ButtonBehavior,Image):
def __init__(self,**kwargs):
super(Red,self).__init__(**kwargs)
self.source = "rbal.png"
self.size = (85,113)
self.pos = (202,300)
def on_press(self):
global rpart
rpart = True
Clock.schedule_interval(self.todown,0.1)
def todown(self,*args):
global rch
if not rch:
snd_part.play()
self.source = "effect.png"
rch = True
else:
self.x = 198
self.source = "varsan.png"
if self.y > 250:
self.y -= 4
else:
self.y = 250
global rfin,fin
rfin = True
if ofin and vfin and fin:
fin = False
win.kill_platform()
class Platform(Widget):
def __init__(self,**kwargs):
super(Platform,self).__init__(**kwargs)
self.size = (320,640)
self.bgimage = Image(source = "bg.jpg")
self.bgimage.size = (320,640)
self.obeta = False
self.vbeta = False
self.rbeta = False
self.obal = Orange()
self.vbal = Violet()
self.rbal = Red()
Clock.schedule_interval(self.moveOrange,0.1)
Clock.schedule_interval(self.moveViolet,0.1)
Clock.schedule_interval(self.moveRed,0.1)
self.bgimage.add_widget(self.obal)
self.bgimage.add_widget(self.vbal)
self.bgimage.add_widget(self.rbal)
self.add_widget(self.bgimage)
def moveOrange(self,*args):
if not opart:
if not self.obeta:
self.obal.y += 2
else:
self.obal.y -= 2
if self.obal.y <= 280:
self.obeta = False
if self.obal.y >= 320:
self.obeta = True
def moveViolet(self,*args):
if not vpart:
if not self.vbeta:
self.vbal.y += 1
else:
self.vbal.y -= 1
if self.vbal.y <= 344:
self.vbeta = False
if self.vbal.y >= 384:
self.vbeta = True
def moveRed(self,*args):
if not rpart:
if not self.rbeta:
self.rbal.y += 3
else:
self.rbal.y -= 3
if self.rbal.y <= 280:
self.rbeta = False
if self.rbal.y >= 320:
self.rbeta = True
class Platform2(Widget):
def __init__(self,**kwargs):
super(Platform2,self).__init__(**kwargs)
self.size = (320,640)
self.bgimage = Image(source = "bg.jpg")
self.bgimage.size = (320,640)
self.add_widget(self.bgimage)
class MainApp(App):
def build(self):
self.layout = GridLayout()
self.platform = Platform()
self.layout.add_widget(self.platform)
return self.layout
def kill_platform(self):
self.platform = Platform2()
self.layout.add_widget(self.platform)
win = MainApp()
win.run()
Here you can see screenshot.That's how it shows on my phone:
enter image description here
Replace the Window.size = (320,640) line with:
from kivy.utils import platform
if platform not in ["android", "ios"]:
Window.size = (320,640)
Side notes, you might wanna change the attributes that use the 320x640 pixel count or at least smaller than it to something like size_hint=(1,1). This answer might be unclear for most, but this is the best I can do

How do I use a .jpg or .png as a background picture?

I found a nice image of space that I'd like sitting in the background of this tiny game I'm working on and can't figure out what and where to write it. It needs to be placed behind all classes to make sure that it doesn't block the screen. I thought it might be in class Window, but I'm not sure. I am brand new to python so any help is much appreciated! This is the entire project so far.
import sys, logging, os, random, math, open_color, arcade
#check to make sure we are running the right version of Python
version = (3,7)
assert sys.version_info >= version, "This script requires at least Python {0}.{1}".format(version[0],version[1])
#turn on logging, in case we have to leave ourselves debugging messages
logging.basicConfig(format='[%(filename)s:%(lineno)d] %(message)s', level=logging.DEBUG)
logger = logging.getLogger(__name__)
SCREEN_WIDTH = 800
SCREEN_HEIGHT = 600
MARGIN = 30
SCREEN_TITLE = "Intergalactic slam"
NUM_ENEMIES = 5
STARTING_LOCATION = (400,100)
BULLET_DAMAGE = 10
ENEMY_HP = 10
HIT_SCORE = 10
KILL_SCORE = 100
PLAYER_HP = 100
class Bullet(arcade.Sprite):
def __init__(self, position, velocity, damage):
'''
initializes the bullet
Parameters: position: (x,y) tuple
velocity: (dx, dy) tuple
damage: int (or float)
'''
super().__init__("PNG/laserPink3.png", 0.5)
(self.center_x, self.center_y) = position
(self.dx, self.dy) = velocity
self.damage = damage
def update(self):
'''
Moves the bullet
'''
self.center_x += self.dx
self.center_y += self.dy
class Enemy_Bullet(arcade.Sprite):
def __init__(self, position, velocity, damage):
super().__init__("PNG/laserGreen1.png", 0.5)
(self.center_x, self.center_y) = position
(self.dx, self.dy) = velocity
self.damage = damage
def update(self):
self.center_x += self.dx
self.center_y += self.dy
class Player(arcade.Sprite):
def __init__(self):
super().__init__("PNG/shipYellow_manned.png", 0.5)
(self.center_x, self.center_y) = STARTING_LOCATION
self.hp = PLAYER_HP
class Enemy(arcade.Sprite):
def __init__(self, position):
'''
initializes an alien enemy
Parameter: position: (x,y) tuple
'''
super().__init__("PNG/shipGreen_manned.png", 0.5)
self.hp = ENEMY_HP
(self.center_x, self.center_y) = position
class Window(arcade.Window):
def __init__(self, width, height, title):
super().__init__(width, height, title)
file_path = os.path.dirname(os.path.abspath(__file__))
os.chdir(file_path)
self.set_mouse_visible(True)
arcade.set_background_color(open_color.black)
self.bullet_list = arcade.SpriteList()
self.enemy_list = arcade.SpriteList()
self.enemy_bullet_list = arcade.SpriteList()
self.player = Player()
self.score = 0
self.win = False
self.lose = False
def setup(self):
'''
Set up enemies
'''
for i in range(NUM_ENEMIES):
x = 120 * (i+1) + 40
y = 500
enemy = Enemy((x,y))
self.enemy_list.append(enemy)
def update(self, delta_time):
self.bullet_list.update()
self.enemy_bullet_list.update()
if (not (self.win or self.lose)):
for e in self.enemy_list:
for b in self.bullet_list:
if (abs(b.center_x - e.center_x) <= e.width / 2 and abs(b.center_y - e.center_y) <= e.height / 2):
self.score += HIT_SCORE
e.hp -= b.damage
b.kill()
if (e.hp <= 0):
e.kill()
self.score += KILL_SCORE
if (len(self.enemy_list) == 0):
self.win = True
if (random.randint(1, 75) == 1):
self.enemy_bullet_list.append(Enemy_Bullet((e.center_x, e.center_y - 15), (0, -10), BULLET_DAMAGE))
for b in self.enemy_bullet_list:
if (abs(b.center_x - self.player.center_x) <= self.player.width / 2 and abs(b.center_y - self.player.center_y) <= self.player.height / 2):
self.player.hp -= b.damage
b.kill()
if (self.player.hp <= 0):
self.lose = True
def on_draw(self):
arcade.start_render()
arcade.draw_text(str(self.score), 20, SCREEN_HEIGHT - 40, open_color.white, 16)
arcade.draw_text("HP: {}".format(self.player.hp), 20, 40, open_color.white, 16)
if (self.player.hp > 0):
self.player.draw()
self.bullet_list.draw()
self.enemy_bullet_list.draw()
self.enemy_list.draw()
if (self.lose):
self.draw_game_loss()
elif (self.win):
self.draw_game_won()
def draw_game_loss(self):
arcade.draw_text(str("LOSER!"), SCREEN_WIDTH / 2 - 90, SCREEN_HEIGHT / 2 - 10, open_color.white, 30)
def draw_game_won(self):
arcade.draw_text(str("WINNER!"), SCREEN_WIDTH / 2 - 90, SCREEN_HEIGHT / 2 - 10, open_color.white, 30)
def on_mouse_motion(self, x, y, dx, dy):
'''
The player moves left and right with the mouse
'''
self.player.center_x = x
def on_mouse_press(self, x, y, button, modifiers):
if button == arcade.MOUSE_BUTTON_LEFT:
x = self.player.center_x
y = self.player.center_y + 15
bullet = Bullet((x,y),(0,10),BULLET_DAMAGE)
self.bullet_list.append(bullet)
def main():
window = Window(SCREEN_WIDTH, SCREEN_HEIGHT, SCREEN_TITLE)
window.setup()
arcade.run()
if __name__ == "__main__":
main()
One way to do it would be to load the .jpg or .png as a texture, and draw that texture each frame, as big as the screen is (or bigger!).
I haven't tested this, but as an example, loading the texture could be done in Window.__init__, like so (reference):
self.background = arcade.load_texture('PNG/background.png')
And then in on_draw, just after you call start_render, you would draw it (reference), passing the required center coordinates, as well as width and height:
self.background.draw(SCREEN_WIDTH/2, SCREEN_HEIGHT/2, SCREEN_WIDTH, SCREEN_HEIGHT)
The reason it needs to be the first thing is because everything is drawn back-to-front, like you would do in a painting.
If the image is not the exact same size as your screen/window, your background will probably be stretched/squished. If that's not what you want, the easiest fix would be to change the image so that it's the right size.
Yes, you should be able to add it to class window...
You could do something like this to add it:
def __init__(self, width, height, title):
super().__init__(width, height, title)
file_path = os.path.dirname(os.path.abspath(__file__))
os.chdir(file_path)
self.set_mouse_visible(True)
arcade.set_background_color(open_color.black)
self.bullet_list = arcade.SpriteList()
self.enemy_list = arcade.SpriteList()
self.enemy_bullet_list = arcade.SpriteList()
self.player = Player()
self.score = 0
self.win = False
self.lose = False
self.background = None
def setup(self):
'''
Set up enemies
'''
self.background = arcade.load_texture("images/background.jpg")
for i in range(NUM_ENEMIES):
x = 120 * (i+1) + 40
y = 500
enemy = Enemy((x,y))
self.enemy_list.append(enemy)

Tkinter canvas doesn't show my "player" symbol

I am beginner in Python and want just to make a red square that will move by pressed keys on keyboard. But after I had run this, only green canvas showed up, no red square. Here is the code:
Imports:
try:
import Tkinter
except:
import tkinter as Tkinter
import time
Here just some constants
__author__ = "Brano"
print(__author__)
GAME_WIDTH = 800
GAME_HEIGHT = 600
GAME_BG = 'green'
MOVE_SPEED = 10
Main class with initialization:
class Game(Tkinter.Tk):
def __init__(self, *args, **kwargs):
Tkinter.Tk.__init__(self, *args, **kwargs)
# Trigger Of Other Functions
self.x = GAME_WIDTH/2
self.y = GAME_HEIGHT/2
self.create_board()
self.create_men()
self.bind('<Any-KeyPress>',self.move)
Creating board:
def create_board(self):
self.board = Tkinter.Canvas(width=GAME_WIDTH, height=GAME_HEIGHT,
bg=GAME_BG)
self.board.pack(padx=10, pady=10)
return
Creating red square:
def create_men(self):
self.men = self.board.create_rectangle(300, 300, 310, 310, fill='red')
return
Move square after pressing keys:
def move(self, event=None):
key = event.keysym
if key=='Left':
self.x = MOVE_SPEED
elif key=='Right':
self.x = -MOVE_SPEED
elif key=='Up':
self.y = MOVE_SPEED
elif key=='Down':
self.y = -MOVE_SPEED
else:
pass
return
Just tkinter updates:
def TkUpdate(self):
self.update()
self.update_idletasks()
return
My main move update:
def GameUpdate(self):
self.board.move(self.men, self.x, self.y)
return
Checking if it is imported:
if __name__ == '__main__':
root=Game(className=" Snake Game ")
while True:
root.TkUpdate()
root.GameUpdate()
time.sleep(0.09)
else :
print("U cannot import me !")
Here is the canvas I have
Here is the whole class:
class Game(Tkinter.Tk):
def __init__(self, *args, **kwargs):
Tkinter.Tk.__init__(self, *args, **kwargs)
# Trigger Of Other Functions
self.x = GAME_WIDTH/2
self.y = GAME_HEIGHT/2
self.create_board()
self.create_men()
self.bind('<Any-KeyPress>',self.move)
def create_board(self):
self.board = Tkinter.Canvas(width=GAME_WIDTH, height=GAME_HEIGHT, bg=GAME_BG)
self.board.pack(padx=10, pady=10)
return
def create_men(self):
self.men = self.board.create_rectangle(300, 300, 310, 310, fill='red')
return
def move(self, event=None):
key = event.keysym
if key=='Left':
self.x = MOVE_SPEED
elif key=='Right':
self.x = -MOVE_SPEED
elif key=='Up':
self.y = MOVE_SPEED
elif key=='Down':
self.y = -MOVE_SPEED
else:
pass
return
def TkUpdate(self):
self.update()
self.update_idletasks()
return
def GameUpdate(self):
self.board.move(self.men, self.x, self.y)
return
Avoid calling update and sleep. Instead use after and mainloop. Your code should schedule your gameloop using after and enter the mainloop after setting up everything. Then keep scheduling the gameloop with after calls.
Your actual problem is you have confused using self.x and self.y as a position in the setup but then use these as a relative move in the game loop. So when you first call GameUpdate you move the rectangle by half the canvas size and it immediately moves out of view. Below is a version that uses these as the 'man' position and asserts the position using coords each time around the game loop.
import tkinter as tk
GAME_WIDTH = 800
GAME_HEIGHT = 600
GAME_BG = 'green'
MOVE_SPEED = 10
MAN_SIZE = 20
class Game(tk.Tk):
def __init__(self, *args, **kwargs):
tk.Tk.__init__(self, *args, **kwargs)
# Trigger Of Other Functions
self.x = GAME_WIDTH/2
self.y = GAME_HEIGHT/2
self.create_board()
self.create_men()
self.bind('<Any-KeyPress>',self.move)
def create_board(self):
self.board = tk.Canvas(width=GAME_WIDTH, height=GAME_HEIGHT, bg=GAME_BG)
self.board.pack(padx=10, pady=10)
def create_men(self):
self.men = self.board.create_rectangle((self.x, self.y, self.x + MAN_SIZE, self.y + MAN_SIZE), fill='red', outline='black')
def move(self, event=None):
key = event.keysym
print(key)
if key=='Left':
self.x = self.x - MOVE_SPEED
elif key=='Right':
self.x = self.x + MOVE_SPEED
elif key=='Up':
self.y = self.y - MOVE_SPEED
elif key=='Down':
self.y = self.y + MOVE_SPEED
else:
pass
return
def game_loop(self):
self.board.coords(self.men, (self.x, self.y, self.x + MAN_SIZE, self.y + MAN_SIZE))
self.after(10, self.game_loop)
def main():
game = Game(className="Snake")
game.after(10, game.game_loop)
game.mainloop()
if __name__ == '__main__':
main()

calling attributes from other classes error

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.

Categories