I have a game I am working on and am trying to increase the level every time I get to a hundred place, i.e., 100, 200, 300...etc.
Here is my function and it is probably something very simple I am forgetting to do
Thanks to #redunderthebed I discovered that the function was in the __init__() and that it was not getting into the if statement. So I moved my level changing into the if loop. So I moved it to my main() method and it still is not going into the if loop when the score goes to a 100 position. What am I doing wrong here?
# Pizza Panic
# Player must catch falling pizzas before they hit the ground
from livewires import games, color
from random import randrange
games.init(screen_width=640, screen_height=480, fps=50)
class Pan(games.Sprite):
""" A pan controlled by player to catch falling pizzas """
image = games.load_image("pan.bmp")
def __init__(self):
""" Initialize the pan object and create Text object for score """
super(Pan, self).__init__(image=Pan.image,
x=games.mouse.x,
bottom=games.screen.height)
self.score = games.Text(value=0, size=25, color=color.black,
top=5, right=games.screen.width - 10)
games.screen.add(self.score)
self.level = 0
def update(self):
""" move to mouse x position """
self.x = games.mouse.x
if self.left < 0:
self.left = 0
if self.right > games.screen.width:
self.right = games.screen.width
self.check_catch()
def check_catch(self):
""" Check if catch pizzas """
for pizza in self.overlapping_sprites:
self.score.value += 10
self.score.right = games.screen.width - 10
pizza.handle_caught()
class Pizza(games.Sprite):
""" a pizza which falls to the ground """
image = games.load_image("pizza.bmp")
speed = 1
def __init__(self, x, y=90):
""" Initialize a pizza object """
super(Pizza, self).__init__(image=Pizza.image,
x=x, y=y,
dy=Pizza.speed)
def update(self):
""" Check if bottom edge has reached screen bottom """
if self.bottom > games.screen.height:
self.end_game()
self.destroy()
def handle_caught(self):
""" Destroy self if caught """
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 Chef(games.Sprite):
""" A chef which moves left and right, dropping pizzas """
image = games.load_image("chef.bmp")
def __init__(self, y=55, speed=2, odds_change=200):
""" Initialize the chef object """
super(Chef, self).__init__(image=Chef.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 randrange(self.odds_change) == 0:
self.dx = -self.dx
self.check_drop()
def check_drop(self):
""" Decrease countdown or drop pizza and reset countdown """
if self.time_til_drop > 0:
self.time_til_drop -= 1
else:
new_pizza = Pizza(x=self.x)
games.screen.add(new_pizza)
# set buffer to approx 30% of pizza height, regardless of pizza
# speed
self.time_til_drop = int(new_pizza.height * 1.3 / Pizza.speed) + 1
def main():
""" Play the game """
wall_image = games.load_image("wall.jpg", transparent=False)
games.screen.background = wall_image
the_chef = Chef()
games.screen.add(the_chef)
the_pan = Pan()
games.screen.add(the_pan)
score = the_pan.score.value
if score % 100 == 0:
the_pan.level += 1
the_pan.level_msg = games.Message(value="LEVEL {}"
.format(the_pan.level),
size=90,
color=color.red,
x=games.screen.width / 2,
y=games.screen.height / 2,
lifetime=5 * games.screen.fps,
after_death=None)
games.screen.add(the_pan.level_msg)
pizza = Pizza(x=0)
pizza.speed += 1
else:
print("not getting into the if statement")
games.mouse.is_visible = False
games.screen.event_grab = True
games.screen.mainloop()
# start it up
main()
I couldn't find any real documentation for Livewires, but I'm going to say based on your code (and assuming it's doing anything) you need to put your level check in here:
def update(self):
""" move to mouse x position """
self.x = games.mouse.x
if self.left < 0:
self.left = 0
if self.right > games.screen.width:
self.right = games.screen.width
self.check_catch()
self.check_level()
Perhaps check_level()
def check_level(self):
if not self.score.value % 100:
self.level += 1
self.level_msg = games.Message(value="LEVEL {}"
.format(the_pan.level),
size=90,
color=color.red,
x=games.screen.width / 2,
y=games.screen.height / 2,
lifetime=5 * games.screen.fps,
after_death=None)
games.screen.add(the_pan.level_msg)
Related
I'm new to this so forgive me.
In the follow code on_draw(), on_update(), on_key_press(), and on_key_release() are never called but I know the code works so they do something, but why does it work?
I was under the impression that you had to do something like Mygame.on_update() to use a class function.
class Player(arcade.Sprite):
""" Player class """
def __init__(self, image, scale):
""" Set up the player """
# Call the parent init
super().__init__(image, scale)
# Create a variable to hold our speed. 'angle' is created by the parent
self.speed = 0
def update(self):
# Convert angle in degrees to radians.
angle_rad = math.radians(self.angle)
# Rotate the ship
self.angle += self.change_angle
# Use math to find our change based on our speed and angle
self.center_x += -self.speed * math.sin(angle_rad)
self.center_y += self.speed * math.cos(angle_rad)
class MyGame(arcade.Window):
"""
Main application class.
"""
def __init__(self, width, height, title):
"""
Initializer
"""
# Call the parent class initializer
super().__init__(width, height, title)
# Set the working directory (where we expect to find files) to the same
# directory this .py file is in. You can leave this out of your own
# code, but it is needed to easily run the examples using "python -m"
# as mentioned at the top of this program.
file_path = os.path.dirname(os.path.abspath(__file__))
os.chdir(file_path)
# Variables that will hold sprite lists
self.player_list = None
# Set up the player info
self.player_sprite = None
# Set the background color
arcade.set_background_color(arcade.color.BLACK)
def setup(self):
""" Set up the game and initialize the variables. """
# Sprite lists
self.player_list = arcade.SpriteList()
# Set up the player
self.player_sprite = Player(":resources:images/space_shooter/playerShip1_orange.png",
SPRITE_SCALING)
self.player_sprite.center_x = SCREEN_WIDTH / 2
self.player_sprite.center_y = SCREEN_HEIGHT / 2
self.player_list.append(self.player_sprite)
def on_draw(self):
"""
Render the screen.
"""
# This command has to happen before we start drawing
self.clear()
# Draw all the sprites.
self.player_list.draw()
def on_update(self, delta_time):
""" Movement and game logic """
# Call update on all sprites (The sprites don't do much in this
# example though.)
self.player_list.update()
def on_key_press(self, key, modifiers):
"""Called whenever a key is pressed. """
# Forward/back
if key == arcade.key.UP:
self.player_sprite.speed = MOVEMENT_SPEED
elif key == arcade.key.DOWN:
self.player_sprite.speed = -MOVEMENT_SPEED
# Rotate left/right
elif key == arcade.key.LEFT:
self.player_sprite.change_angle = ANGLE_SPEED
elif key == arcade.key.RIGHT:
self.player_sprite.change_angle = -ANGLE_SPEED
def on_key_release(self, key, modifiers):
"""Called when the user releases a key. """
if key == arcade.key.UP or key == arcade.key.DOWN:
self.player_sprite.speed = 0
elif key == arcade.key.LEFT or key == arcade.key.RIGHT:
self.player_sprite.change_angle = 0
def main():
""" Main function """
window = MyGame(SCREEN_WIDTH, SCREEN_HEIGHT, SCREEN_TITLE)
window.setup()
arcade.run()
if __name__ == "__main__":
main()
I am trying to create a ScrollView in Kivy with widgets that loop infinitely like in this demo I found online:
I have tried to remove widgets outside the ScrollView's bounds and add them back to the top or bottom, depending on their original location. However, this made the whole app flicker and glitch and ultimately did not work. If anyone has a method of achieving this, it would be greatly appreciated!
I created a custom class based on kivy's Stencilview and RelativeLayout.
It's used pretty much like kivy.uix.recycleview and supports looping. It's somewhat unoptimized but works pretty well. No x-axis scrolling (yet). Should be capable of processing an infinite amount of data without any performance loss. (Tested with 10.000.000 data entries => no lag)).
please don't quote me on anything inside on_touch_down, on_touch_move, on_touch_up, or any function called inside it (the only exception is scroll_y) cause I have no idea how they work.
from functools import partial
from kivy.app import App
from kivy.clock import Clock
from kivy.compat import iteritems
from kivy.lang import Builder
from kivy.metrics import sp
from kivy.properties import DictProperty, ListProperty, NumericProperty, BooleanProperty, ObjectProperty
from kivy.uix.label import Label
from kivy.uix.relativelayout import RelativeLayout
from kivy.uix.stencilview import StencilView
from kivy.uix.widget import Widget
class LoopEntry(Widget):
data_index = NumericProperty(0)
data = DictProperty(None, allow_none=True)
hidden = BooleanProperty(False)
def is_hidden(self):
"""
:return:
"""
return self.hidden
def hide(self):
"""
:return:
"""
self.opacity = 0
self.hidden = True
def show(self):
"""
:return:
"""
self.opacity = 1
self.hidden = False
def update(self, data):
"""
overwrite this function if values other than attributes are needed
:param data:
:return:
"""
assert isinstance(data, dict)
# assign data
self.data = data
# apply values
for key, value in iteritems(data):
setattr(self, key, value)
class LoopContainer(RelativeLayout, StencilView):
pass
class LoopContainerDebug(RelativeLayout):
pass
class LoopScrollView(RelativeLayout):
"""
Main data source. Contains the data that needs to be exchanged.
Data can be manipulated without a whole redraw. Might cause unwanted behaviour
like blank lines and incorrect orders if not properly updated.
Setting this value causes a complete refresh.
"""
data = ListProperty()
"""
Children height. All children need to be the same height else
unwanted behaviour might occur.
Altering this value causes a complete refresh.
"""
children_height = NumericProperty(44)
"""
Amount of widgets added to the minimum widgets. (Very) Big numbers may cause lag.
Altering this value causes a complete refresh
"""
protection_amount = NumericProperty(4)
"""
viewclass is used to set the class type the widgets should be
future version might support manual adding of widgets
Altering this value causes a complete refresh.
"""
viewclass = ObjectProperty(LoopEntry)
"""
controls looping behaviour.
"""
loop = BooleanProperty(True)
"""
debugging option. shows hidden entries. not possible to switch
while running (yet)
"""
debug = BooleanProperty(False)
"""
scroll timeout. If the mouse has not been moved 'scroll_distance' within this time, dispatch the touch to children
in milliseconds
"""
scroll_timeout = NumericProperty(200)
"""
touch distance. Distance mouse needs to be moved
in pixel
"""
scroll_distance = NumericProperty('20dp')
def __init__(self, **kwargs):
"""
:param kwargs:
"""
# minimum widgets controls min/max amount of widgets on screen. Readonly.
self.__minimum_widgets = 0
# controls overscroll blocking if loop is disabled
self.__overscroll_block_y = "free"
# container
_kwargs = {
"size_hint": (None, None),
"size": (0, 0)
}
self.container = LoopContainer(**_kwargs) if not kwargs.get('debug', False) else LoopContainerDebug(**_kwargs)
# init super values
super(LoopScrollView, self).__init__(**kwargs)
# add container
self.add_widget(self.container)
# create widgets
self.__create_widgets()
# no idea
self._drag_touch = None
def on_pos(self, widget, value) -> None:
"""
:param widget:
:param value:
:return:
"""
def on_size(self, widget, value) -> None:
"""
:param widget:
:param value:
:return:
"""
# set container size
self.container.size = self.size
# recreate widgets
self.__create_widgets()
def on_data(self, widget, value) -> None:
"""
called if new data is set. Forces complete refresh. Use with care.
:param widget: widget event belongs to
:param value: event value
:return: None
"""
self.__create_widgets()
def on_protection_amount(self, widget, value) -> None:
"""
Forces complete refresh. Use with care.
:param widget: widget event belongs to
:param value: event value
:return: None
"""
self.__create_widgets()
def on_viewclass(self, widget, value) -> None:
"""
sets the viewclass used to entries
Forces complete refresh
:param widget: widget
:param value: value
:return: None
"""
self.__create_widgets()
def on_children_height(self, widget, value) -> None:
"""
Changes the children height.
Forces complete refresh.
:param widget: widget
:param value: value
:return: None
"""
self.__create_widgets()
def __create_widgets(self) -> None:
"""
clear all widgets and recreate
:return: None
"""
# remove all widgets
self.container.clear_widgets()
# calculate the minimum amount of required widgets
self.minimum_widgets = round(self.height / self.children_height) + self.protection_amount
# adding entries to the stencil view in reversed order to start with the smallest value (index 0) at top
for entry in range(self.minimum_widgets, 0, -1):
# create widget instance
_tmp_entry = self.viewclass(
size_hint=(1, None),
height=self.children_height,
pos=(0, self.height - self.children_height * entry)
)
# add to container
self.container.add_widget(_tmp_entry)
# refresh all widgets from given index and apply data values
self.__refresh_from_index(0)
def __refresh_from_index(self, index=0) -> None:
"""
refreshes widgets from given index
:param index: index to start with (very top entry)
:return: None
"""
# return if data is empty
if not self.data:
return
# reset widget positions to prevent weird behaviour
self.__reset_widget_positions(brute=True)
# reduce overhead. Slightly.
_data_length = len(self.data)
# loop through children and set values from given index
for child in self.container.children:
# if the current index exceeds the lengths and looping is disabled hide the widget
if index >= _data_length and not self.loop:
# Note : I dislike direct changing of values -_-
if not child.is_hidden():
child.hide() # hide child
child.data_index = index
else:
_normalized_index = index % _data_length
# get the new data value for the widget
_data_value = self.data[_normalized_index]
child.update(_data_value)
child.data_index = _normalized_index
if child.is_hidden():
child.show()
# increase index
index += 1
def __reset_widget_positions(self, brute=False) -> None:
"""
resets widget positions. Does not take into account values or
value positions.
If brute is True positions will be reset forcefully meaning data may mix up.
If brute is False positions will be scrolled meaning values will remain ordered.
:param brute: boolean
:return: None
"""
if brute:
# forcefully reset children
for child in self.container.children:
child.y = self.height - (child.height * (self.get_child_index(child) + 1))
else:
# get top child
_top_child = self.container.children[0]
# loop until child's y value matches the top threshold
while _top_child.y != self.height - _top_child.height:
# scroll by up to ensure proper order
self.scroll_y(1)
def __trigger_overscroll(self, entry: (LoopEntry, None), state):
"""
:param entry:
:param state:
:return:
"""
# trigger overscroll for down
if state == "bottom" and entry is not None:
# reset child to a proper spot
while entry.y != 0:
# scroll in the fastest direction
self.scroll_y(1 if entry.y < 0 else -1)
# set overscroll AFTER scrolling
self.__overscroll_block_y = "bottom"
# for up
elif state == "top" and entry is not None:
# reset child to proper spot
while entry.y != self.height - entry.height:
self.scroll_y(1 if entry.y < self.height - entry.height else 1)
# set overscroll AFTER scrolling
self.__overscroll_block_y = "top"
# reset else
else:
# free scrolling
self.__overscroll_block_y = "free"
def __update_entry(self, entry: LoopEntry, direction) -> None:
"""
:param entry:
:param direction:
:return:
"""
# get data length
_data_length = len(self.data)
# check direction
if direction == "down":
# get new index
_data_index = entry.data_index + self.minimum_widgets
if self.loop:
# normalize data index
_normalized_data_index = _data_index % _data_length
# update entry
entry.update(self.data[_normalized_data_index])
# set data index
entry.data_index = _normalized_data_index
# show entry
if entry.is_hidden():
entry.show()
else:
# if loop is disabled and data index exceeds either direction
if _data_index >= _data_length or _data_index < 0:
# hide children
if not entry.is_hidden():
entry.hide()
else:
# update entry from data index
entry.update(self.data[_data_index])
# show entry
if entry.is_hidden():
entry.show()
# set data index
entry.data_index = _data_index
elif direction == "up":
# get new data index
_data_index = entry.data_index - self.minimum_widgets
# if looping is enabled
if self.loop:
# normalize index
_normalized_data_index = _data_index % _data_length
# update entry
entry.update(self.data[_normalized_data_index])
# set data index
entry.data_index = _normalized_data_index
# show entry
if entry.is_hidden():
entry.show()
else:
if _data_index < 0 or _data_index >= _data_length:
# hide children
if not entry.is_hidden():
entry.hide()
else:
# update entry from data index
entry.update(self.data[_data_index])
# show entry
if entry.is_hidden():
entry.show()
# set data index
entry.data_index = _data_index
else:
# error
raise Exception
def get_child_index(self, child) -> (int, None):
"""
returns the index if the child exists in list else None
:param child: child instance
:return: int,None
"""
return self.container.children.index(child) if child in self.container.children else None
def scroll_y(self, delta_y) -> None:
"""
scroll by given amount
:param delta_y: delta value in pixels
:return: None
"""
# set highest and lowest children (needed for rotation)
_highest, _lowest = self.container.children[0], self.container.children[0]
# round delta y
delta_y = round(delta_y)
# get data length
data_length = len(self.data)
# control var
_free_block = True
# loop through children
for child in self.container.children:
# increase/decrease children y position
child.y += delta_y
# update highest and lowest children
_highest = child if child.y > _highest.y else _highest
_lowest = child if child.y < _lowest.y else _lowest
# check for loop condition
if not self.loop:
# if current child's index exceeds or evens data length and is higher than given
# threshold trigger overscroll event for bottom
if child.data_index >= data_length - 1 and child.y >= 0:
self.__trigger_overscroll(child, 'bottom')
_free_block = False
# if current child's index is smaller or evens 0 and is higher than the given
# threshold trigger overscroll event for top
elif child.data_index <= 0 and child.y <= self.height - child.height:
self.__trigger_overscroll(child, 'top')
_free_block = False
# unblock if block is free to be unblocked
if _free_block:
self.__trigger_overscroll(None, 'reset')
# check if swap is needed
if _highest.y > self.height + _highest.height and delta_y > 0:
# set new y for highest if it exceeds max height
_highest.y = _lowest.y - _highest.height
self.__update_entry(_highest, direction="down")
elif _lowest.y < 0 - _lowest.height - _lowest.height and delta_y < 0:
_lowest.y = _highest.y + _highest.height
self.__update_entry(_lowest, direction="up")
def _get_uid(self, prefix='sv'):
return '{0}.{1}'.format(prefix, self.uid)
def on_touch_down(self, touch):
x, y = touch.pos
if not self.collide_point(x, y):
touch.ud[self._get_uid('svavoid')] = True
return super(LoopScrollView, self).on_touch_down(touch)
if self._drag_touch or ('button' in touch.profile and touch.button.startswith('scroll')):
return super(LoopScrollView, self).on_touch_down(touch)
# no mouse scrolling, so the user is going to drag with this touch.
self._drag_touch = touch
uid = self._get_uid()
touch.grab(self)
touch.ud[uid] = {
'mode': 'unknown',
'dx': 0,
'dy': 0
}
Clock.schedule_once(self._change_touch_mode, self.scroll_timeout / 1000.)
return True
def on_touch_move(self, touch):
if self._get_uid('svavoid') in touch.ud or self._drag_touch is not touch:
return super(LoopScrollView, self).on_touch_move(touch) or self._get_uid() in touch.ud
if touch.grab_current is not self:
return True
uid = self._get_uid()
ud = touch.ud[uid]
mode = ud['mode']
if mode == 'unknown':
ud['dx'] += abs(touch.dx)
ud['dy'] += abs(touch.dy)
if ud['dx'] > sp(self.scroll_distance):
mode = 'drag'
if ud['dy'] > sp(self.scroll_distance):
mode = 'drag'
ud['mode'] = mode
if mode == 'drag':
if (touch.dy > 0 and self.__overscroll_block_y == "bottom" or
touch.dy < 0 and self.__overscroll_block_y == "top"):
pass
else:
self.scroll_y(touch.dy)
return True
def on_touch_up(self, touch):
if self._get_uid('svavoid') in touch.ud:
return super(LoopScrollView, self).on_touch_up(touch)
if self._drag_touch and self in [x() for x in touch.grab_list]:
touch.ungrab(self)
self._drag_touch = None
ud = touch.ud[self._get_uid()]
if ud['mode'] == 'unknown':
super(LoopScrollView, self).on_touch_down(touch)
Clock.schedule_once(partial(self._do_touch_up, touch), .1)
else:
if self._drag_touch is not touch:
super(LoopScrollView, self).on_touch_up(touch)
return self._get_uid() in touch.ud
def _do_touch_up(self, touch, *largs):
super(LoopScrollView, self).on_touch_up(touch)
# don't forget about grab event!
for x in touch.grab_list[:]:
touch.grab_list.remove(x)
x = x()
if not x:
continue
touch.grab_current = x
super(LoopScrollView, self).on_touch_up(touch)
touch.grab_current = None
def _change_touch_mode(self, *largs):
if not self._drag_touch:
return
uid = self._get_uid()
touch = self._drag_touch
ud = touch.ud[uid]
if ud['mode'] != 'unknown':
return
touch.ungrab(self)
self._drag_touch = None
touch.push()
touch.apply_transform_2d(self.parent.to_widget)
super(LoopScrollView, self).on_touch_down(touch)
touch.pop()
return
# ------------------ Showcase ------------------ #
from kivy.uix.button import Button
class LoopLabel(LoopEntry, Label):
pass
class LoopButton(LoopEntry, Button):
pass
__style = ("""
<LoopLabel>:
color : 1,1,1
text: "test"
canvas:
Color:
rgb : 1,1,1
Line:
rectangle: (*self.pos,self.width ,self.height )
<LoopContainer,LoopContainerDebug>:
canvas:
Color:
rgb : 1,0,0
Line:
rectangle: (0+1,0+1,self.width - 1,self.height -1 )
width:5
""")
class InfiniteScrollingScrollView(App):
def build(self):
root = RelativeLayout()
root.bind(on_touch_down=lambda x, y: print("-" * 10))
sv = LoopScrollView(
size_hint=(0.5, 0.5), pos_hint={'center': (0.5, 0.5)}, viewclass=LoopLabel, debug=False
)
sv.data = [{'text': str(x)} for x in range(10000000)]
root.add_widget(sv)
return root
if __name__ == "__main__":
Builder.load_string(__style)
InfiniteScrollingScrollView().run()
i think this helpful but not the Answer
and this will help https://youtu.be/l8Imtec4ReQ in minute 59:30
from kivy.app import App
from kivy.uix.label import Label
from kivy.lang.builder import Builder
kv=Builder.load_string('''
ScrollView:
do_scroll_x:False
scroll_type:['bars', 'content']
bar_width:'20dp'
GridLayout:
id:g
cols:1
size_hint:(1,None)
height:self.minimum_height
''')
class a(App):
def build(self):
return kv
def on_start(self):
for i in range(100):self.root.ids.g.add_widget(Label(text=str(i),size_hint=(1, None),size=(1, 20)))
a().run()
I am trying to bind the function validateSubmit to the enter key so the test may be taken at faster speeds, however I cannot figure out where or what to try to bind it to. Inside of the main at the bottom, I commented out the bind that I feel I get the closest results with, however I've been at this long enough to know that its currently beyond my scope of knowledge. This program is my foray into OOP. I also receive a strange error from validateSubmit, however it seems to be caused by tkinter's internal type-casting and has not seemed to do anything more than echo an error back in the terminal.
##########################################################################################
#Imports
import tkinter as tk
from tkinter import ttk
from tkinter import Tk
from random import randint
##########################################################################################
class Storage():
def __init__(self):
self.timeChoice = 0
self.gameScore = 0
self.answer = 0
self.highScore = 0
def set_timeChoice(self,x):
self.timeChoice = x
def set_gameScore(self,x):
self.gameScore = x
def set_answer(self,x):
self.answer = x
def set_highScore(self,x):
self.highScore = x
def save_highScore(self):
timeChoiceVar = str(self.timeChoice)
with open('data' + timeChoiceVar + '.txt',mode='w') as file:
file.write(str(self.highScore))
def get_highScore(self):
timeChoiceVar = str(self.timeChoice)
try:
with open('data' + timeChoiceVar + '.txt',mode='r') as file:
self.highScore = file.read()
except:
with open('data' + timeChoiceVar + '.txt',mode='w') as file:
file.write('0')
##########################################################################################
class AdditionApp(tk.Tk):
def __init__(self):
tk.Tk.__init__(self)
self._frame = None
self.switch_frame(SetTimePage)
def switch_frame(self, frame_class):
new_frame = frame_class(self)
if self._frame is not None:
self._frame.destroy()
self._frame = new_frame
self._frame.grid(column=0,row=0,sticky=tk.W)
##########################################################################################
class SetTimePage(tk.Frame):
def __init__(self, master):
tk.Frame.__init__(self, master)
self.timeVar = tk.IntVar()
data.set_timeChoice(60)
time_frame = ttk.LabelFrame(self,text=' Test Timer Selection ')
time_frame.grid(column=0,row=0,padx=6,pady=8,sticky='WE')
radio1 = tk.Radiobutton(time_frame,text='1 Minute',variable=self.timeVar,value=60,command=lambda: data.set_timeChoice(self.timeVar.get()))
radio1.grid(column=0,row=0,sticky=tk.W)
radio1.select()
radio2 = tk.Radiobutton(time_frame,text='2 Minutes',variable=self.timeVar,value=120,command=lambda: data.set_timeChoice(self.timeVar.get()))
radio2.grid(column=0,row=1,sticky=tk.W)
radio5 = tk.Radiobutton(time_frame,text='5 Minutes',variable=self.timeVar,value=300,command=lambda: data.set_timeChoice(self.timeVar.get()))
radio5.grid(column=0,row=2,sticky=tk.W)
radio10 = tk.Radiobutton(time_frame,text='10 Minutes',variable=self.timeVar,value=600,command=lambda: data.set_timeChoice(self.timeVar.get()))
radio10.grid(column=0,row=3,sticky=tk.W)
start_button = ttk.Button(self,text=' Start ',command=lambda: master.switch_frame(TestPage))
start_button.grid(column=0,row=1,sticky='WE',pady=4)
##########################################################################################
class TestPage(tk.Frame):
def __init__(self, master):
tk.Frame.__init__(self, master)
self.answer = tk.IntVar()
self.scoreVar = 0
data.set_gameScore(0)
data.get_highScore()
self.test_frame = tk.Label(self,text=data.timeChoice)
self.test_frame.grid(column=3,row=0,sticky=tk.N)
self.score_frame = tk.Label(self,text='Score: %d' % data.gameScore)
self.score_frame.grid(column=3,row=1,sticky=tk.N)
self.high_score_frame = tk.Label(self,text='High Score: %s' % data.highScore)
self.high_score_frame.grid(column=3,row=2,sticky=tk.N)
self.solve_frame = ttk.LabelFrame(self,text=' Solve: ')
self.solve_frame.grid(column=0,row=1,columnspan=2,padx=12,sticky=tk.W)
self.equation_label = tk.Label(self.solve_frame,text='')
self.equation_label.grid(column=0,row=0,padx=6,sticky=tk.W)
self.answer_box = ttk.Entry(self.solve_frame,width=2,textvariable=self.answer)
self.answer_box.grid(column=1,row=0,padx=12,sticky=tk.W)
self.answer_box.bind('<Return>', self.validateSubmit)
self.back_button = ttk.Button(self.solve_frame,text=' Back ',command=lambda: master.switch_frame(SetTimePage))
self.back_button.grid(column=3,row=0,padx=12,sticky=tk.N)
self.countdown(data.timeChoice)
def countdown(self, remaining = None):
if remaining is not None:
self.remaining = remaining
self.generateEquation()
if self.remaining < 0:
self.test_frame.configure(text=" Time's up! ")
self.submit_answer.configure(state='disabled')
self.answer_box.configure(state='disabled')
else:
self.test_frame.configure(text="Seconds remaining: %d" % self.remaining)
self.high_score_frame.configure(text='High Score: %s' % data.highScore)
self.submit_answer.bind('<Return>', self.validateSubmit)
self.remaining = self.remaining - 1
self.after(1000, self.countdown)
def generateEquation(self):
self.x = randint(0,10)
self.y = randint(0,10)
self.z = 0
self.equation_label.configure(text='%d + %d' % (self.x , self.y))
self.answer_box.delete(0,3)
self.answer_box.focus()
self.submit_answer = ttk.Button(self.solve_frame,text=' Submit ',command=self.validateSubmit)
self.submit_answer.grid(column=2,row=0,padx=12,sticky=tk.E)
def validateSubmit(self,event=None):
while self.remaining >= 0:
self.z = self.answer.get()
if self.x + self.y == self.z:
self.scoreVar += 1
data.set_gameScore(self.scoreVar)
self.score_frame.configure(text='Score: %d' % data.gameScore)
self.generateEquation()
if int(data.highScore) < data.gameScore:
data.set_highScore(data.gameScore)
data.save_highScore()
elif self.x + self.y != self.z :
self.generateEquation()
##########################################################################################
if __name__ == "__main__":
data = Storage()
program = AdditionApp()
program.title(' Addition Test ')
#program.bind('<Return>', TestPage.validateSubmit)
program.mainloop()
data.save_highScore
If you want the user to be able to press return after entering an answer instead of pressing the Submit button, then the binding needs to go on the entry widget since that is the widget with keyboard focus.
self.answer_box.bind('<Return>', self.validateSubmit)
Also, you need to make sure that validateSubmit can accept the event option that is passed in. Since you want to use it both for a binding and a button click, the easiest way to do that is to make the event argument optional:
def validateSubmit(self, event=None):
I'm writing a program that draws many circles at random positions in Python.
It breaks and spits a "maximum recursion depth exceeded"
I tried to increase the recursion limit but the python shell crushes and restarts
class Game():
def __init__(self, root):
self. root = root
self.c = Canvas(root, bg = 'white')
self.ball = []
self.start = 0
self.elapsed = 0
self.time = 0
self.i = 0
self.root.bind('<Key>', self.key)
self.show()
def show(self):
self.start = time.perf_counter()
for self.i in range(200):
self.ball.append([Balls(self.c)])
Balls.create_balls(self)
self.elapsed = time.perf_counter()
self.time = self.elapsed - self.start
print(self.time)
self.c.pack(fill = BOTH, expand = 1)
self.update()
def update(self):
self.root.after(30, self.update)
def key(self, event):
if event.char == 'c':
#self.ball[57] = self.c.create_oval(Balls.x-12, Balls.y-12, Balls.x+12, Balls.y+12, fill = 'red')
pass
class Balls(Game):
def __init__(self, c):
super(Balls, self).__init__(c)
self.c = c
self.x = random.randint(50.0, 450.0)
self.y = random.randint(50.0, 650.0)
def create_balls(self):
self.ball[self.i] = self.c.create_oval(self.x-12, self.y-12, self.x+12, self.y+12, fill = 'blue')
def main():
root = tkinter.Tk()
root.geometry('500x700')
root.title('Balls Game')
root.resizable(0, 0)
game = Game(root)
root.mainloop()
if __name__ == '__main__':
main()
And the error is very big but is the same thing repeated several times.
This is the error:
https://i.stack.imgur.com/bPcbd.png
Where exactly does it break?
You shouldn't call .bind every time, you only need to bind an event once at the start, so:
...
self.root.bind('<Key>', self.key)
self.show()
is fine.
(Also self.ball.append([Balls(self.c)]) appends a list with one Balls object to the self.ball list, and then you call Balls.create_balls(self) which might add even more items. Is this desired bahaviour?)
I am making a 8bit style platformer. The player falls and gains speed because of the pseudo gravity but he will fall a few pixels into the ground level. Without gravity he will land on the ground and not fall though but it is a constant fall speed.When in the ground you can go up but he will fall when you let up. He will not got down so that is not an issue for now. Any help would be appreciated.
The player class/file.
import pygame,sys
from pygame.locals import *
class Player:
x=0
y=0
offset = 5
L=False
R=False
U=False
D=False
image = None
gravity = .25
velocity = offset
objectDict = None #this si the list of the current objects so that collision can be check with every
#object.. get updated every loop to keep a accurate check of locations
rect = None
grav = True #TODO use this to check if we are paying attention to the gravity
def __init__(self,x,y):
self.x = x
self.y = y
self.image = pygame.image.load('Resources/Pics/player.png')
def draw(self,DISPLAY):
#print('draw will go here')
imgRect = self.image.get_rect()
imgRect.midleft = (self.x,self.y)
self.rect = imgRect
DISPLAY.blit(self.image, imgRect)
#and now im here
def checkCollide(self,otherRect):
return self.rect.colliderect(otherRect)
def checkCollideAll(self):
if(self.objectDict != None):
# print(len(self.objectDict))
# for x in range(1,len(self.objectDict)):
# newb = self.checkCollide(self.objectDict[x].getRect())
# print(self.objectDict[x].getRect())
# if(newb):
# return True
# return False
collideNum = self.rect.collidelist(self.objectDict)
if(collideNum == -1):
return False
else:
return True
def willCollideBelow(self):
if(self.objectDict):
checkRect = (self.x,(self.y),self.image.get_size())
collideNum = self.rect.collidelist(self.objectDict)
if collideNum == -1:
return False
else:
return True
def objUpdate(self,dict):
self.objectDict = dict
def getRect(self):
return self.rect
def update(self):
# while(self.checkCollideAll()):
# print('while happened')
# self.y -= self.offset
# imgRect = self.image.get_rect()
# imgRect.midleft = (self.x,self.y)
# self.rect = imgRect
# print(self.willCollideBelow())
if not self.willCollideBelow():
self.D = True
# print('will fall')
else:
self.D = False
if self.U == True:
self.y -= self.offset
if self.D == True:
self.y += self.velocity
if not self.velocity >= 9.8:
self.velocity += self.gravity
else:
self.velocity = self.offset
if self.L == True:
self.x -= self.offset
if self.R == True:
self.x += self.offset
You didn't provide a running example and your code is hard to read (pascal case, a lot of unnecessary parenthesis), but here's my guess:
In your willCollideBelow function, you check if you hit an object beneath the player:
def willCollideBelow(self):
if(self.objectDict):
checkRect = (self.x,(self.y),self.image.get_size())
collideNum = self.rect.collidelist(self.objectDict)
if collideNum == -1:
return False
else:
return True
instead of just returning True or False, return the object (or the index of the object) you actually collide with:
def will_collide_below(self):
if(self.objectDict):
# using 'collidelistall' would be better, but that's another topic
return self.rect.collidelist(self.objectDict)
Now that you know which object the player collides with, you can adjust the vertical position of the player:
ground_i = self.will_collide_below()
if ground_i:
ground = self.objectDict[ground_i]
self.velocity = 0
self.rect.bottom = ground.top # or self.y = ground.top
You'll get the idea.
Some more notes:
You use different variables to store the position of the player (I see x, y, rect and imgRect). It would make you code a lot simpler if you would just use a single Rect to store the position:
class Player:
...
def __init__(self,x,y):
self.image = pygame.image.load('Resources/Pics/player.png')
self.rect = self.image.get_rect(midleft=(x,y))
def draw(self, display):
display.blit(self.image, self.rect)
def update(self):
...
if self.L: # no need to check == True
self.rect.move_ip(-self.offset)
if self.R: # simply use move_ip to alter the position
self.rect.move_ip(self.offset)
You also use a bunch of class variables where you really should use instance variables, like rect, L, R, U and D.