Welcome!
This is the community forum for my apps Pythonista and Editorial.
For individual support questions, you can also send an email. If you have a very short question or just want to say hello — I'm @olemoritz on Twitter.
Help building a touch menu
-
Do you think I might be able to get some help with Multi scene? Or perhaps a more efficient way of doing this? I've tried but cannot seem to get anything from the examples.
-
@tjferry14, I can say nothing but what @ccc said. You should probably use multiscene. But I've never heard of it before, so I can't help you with this.
Good luck with it!
-
So, I implemented the air hockey code into the multi scene examples, and I am still presented with the error from my first post.
Quite frustrating.
-
You need to have the menu app and the hockey app use the SAME multiscene. If you are calling scene.run() twice, it will not work.
-
from scene import *
from sound import *
from copy import copy
from math import modf, floor
import timescreen_size = Size() class Player (object): # Player object... def __init__(self, name, color): # define the player color self.color = color # set color as the color of player self.score = 0 # set score as zero self.name = name # set name as the name as the player def __str__(self): return self.name class Puck (object): # Puck object def __init__(self, pos, scene): # define the puck self.vector = Vector3(0, 0, 0) # set the puck as a vector self.pos = pos # set the puck position def reverse_vector(self): v = self.vector self.vector = Vector3(-v.x, -v.y, 0) class Game (Scene): def setup(self): self.left_player = Player("Green Player", Color(0.50, 1.00, 0.00)) # sets green player color self.right_player = Player("Gold Player", Color(1.00, 0.80, 0.40)) # sets gold player color self.players = (self.left_player, self.right_player) # sets players in left corner and right corner self.start_time = 0.0 self.stop_time = 0.0 self.last_seconds = 0 self.running = False self.start_time = time.time() self.running = True for s in ('Drums_06', 'Woosh_1', 'Powerup_2'): # for these sound effects... load_effect(s) # load the sound effects in center = self.size.w / 2 # sets center as center of the screen middle = self.size.h / 2 # sets middle as middle of the screen gh = self.size.h / 4 # sets goal height self.puck_radius = gh / 2.5 # sets puck size/radius self.puck = self.centered_puck() # makes puck start out centered # the last time the puck was hit; Used to animate its slow down self.puck_start_t = 0 # sets puck start to the dead center of the screen pr = self.puck_radius # set pr to puck radius self.line_width = self.puck_radius / 6 # sets puck radius inside the center line lw = self.line_width # sets lw to line width self.red_line = Rect(center - lw / 2, 0, lw, self.size.h) # sets red center line self.red_circle = Rect(w=gh, h=gh) # sets circle in the red center line self.red_circle.center(self.bounds.center()) # set the size of the circle in the center line self.left_goal = Rect(w=gh, h=gh) # sets left goal as a rectangle self.right_goal = Rect(w=gh, h=gh) # sets right goal as a rectangle self.left_goal.center(0, middle) # sets the left goal to be centered self.right_goal.center(self.size.w, middle) # sets the right goal to be centered self.winner = None # when someone reaches seven goals, save them to show a message def score_goal(self, player): player.score += 1 # sets player score to plus one for backend purposes self.puck = self.centered_puck() # sets up variable for the puck being centered # following block of code sets the score so when a player reaches 7 they win for p in self.players: if p.score > 6: self.winner = p break overlay = Layer(self.bounds) # sets the cover as an overlay, so its not behind the ice def hide_overlay(): overlay.animate('alpha', 0.0, 1, completion=lambda: overlay.remove_layer()) if self.winner: message = "%s Wins" % (self.winner) # shows a message for whatever player wins on_completion = None self.hide_overlay = hide_overlay else: message = "Goal!" # shows a message for when a player scores a goal on_completion = hide_overlay self.stop_time = time.time() self.running = True # restart the puck on the other player's side if player == self.left_player: self.puck.pos.x += self.size.w / 4 + self.puck_radius else: self.puck.pos.x -= self.size.w / 4 + self.puck_radius size = self.puck_radius * 1.0 # sets puck radius text_layer = TextLayer(message, 'AvenirNext-Heavy', size) # sets text font to Futura text_layer.frame.center(self.bounds.center()) # sets the text to display from the center text_layer.frame.y += self.size.h / 4 # sets the text to autosize itself text_layer.animate('scale_x', 1.3, 0.3, autoreverse=True) # sets the x animation display time/size text_layer.animate('scale_y', 1.3, 0.3, autoreverse=True) # sets the y animation display time/size overlay.add_layer(text_layer) # sets the text layer to overlay #following code sets color, etc. for when a player scores a goal start_color, end_color = copy(player.color), copy(player.color) start_color.a = 0 end_color.a = .5 overlay.background = start_color overlay.animate('background', end_color, .10, completion=on_completion) self.add_layer(overlay) play_effect('Woosh_1') # sets effect of puck scoring to Woosh def centered_puck(self): # set center pos = Rect(w=self.puck_radius, h=self.puck_radius) pos.center(self.bounds.center()) return Puck(pos, self) def move_puck(self): # this lets the puck move by touching it once, like a real air hockey game puck = self.puck ease_x = (self.t - self.puck_start_t) / 4.0 ease = max(0, 1 - curve_ease_out(ease_x)) puck.pos.x += puck.vector.x * ease puck.pos.y += puck.vector.y * ease if puck.pos.right() > self.size.w and not puck.pos.intersects(self.right_goal): # if puck hits the side, play the drum sound effect puck.vector.x *= -1 play_effect('Drums_06') puck.pos.x = min(self.size.w - puck.pos.w, puck.pos.x) if puck.pos.left() > self.size.w: # sets the left goal self.score_goal(self.left_player) return if puck.pos.left() < 0 and not puck.pos.intersects(self.left_goal): puck.vector.x *= -1 play_effect('Drums_06') puck.pos.x = max(0, puck.pos.x) if puck.pos.right() < 0: # sets the right goal self.score_goal(self.right_player) return if puck.pos.top() > self.size.h or puck.pos.bottom() < 0: # if puck hits the side, play the drum sound effect puck.vector.y *= -1 play_effect('Drums_06') puck.pos.y = max(0, puck.pos.y) puck.pos.y = min(self.size.h - puck.pos.h, puck.pos.y) def draw(self): stroke_weight(self.line_width) background(1, 1, 1) # red lines on ice in middle stroke(1.00, 0.40, 0.40) fill(1.00, 0.40, 0.40) rect(*self.red_line.as_tuple()) fill(1, 1, 1) ellipse(*self.red_circle.as_tuple()) # red goal markers for goal in (self.left_goal, self.right_goal): rect(*goal.as_tuple()) for touch in self.touches.values(): self.handle_touch(touch) # black puck no_stroke() fill(0, 0, 0) ellipse(*self.puck.pos.as_tuple()) self.draw_scores() self.move_puck() if self.root_layer: self.root_layer.update(self.dt) self.root_layer.draw() if self.winner is not None: # shows message/allows player to tap to play again c = Rect() c.center(self.bounds.center()) tint(1, 1, 1) message = "Tap to Play Again" y_offset = self.size.h / 4 size = self.puck_radius text(message, x=c.x, y=c.y-y_offset, font_size=size, font_name='AvenirNext-Heavy') def draw_scores(self): # sets score font/size for p, x in zip(self.players, (50, self.size.w - 50)): tint(*p.color.as_tuple()) text(str(p.score), x=x, y=self.size.h- 50, font_size=32, font_name='AvenirNext-Heavy') tint(0.00, 0.50, 1.00) #Format the elapsed time (dt): dt = 0.0 if self.running: dt = (time.time() - self.start_time) else: dt = (self.stop_time - self.start_time) minutes = abs(dt) / 60 # absolute value of dt divided by 60 seconds = abs(dt) % 60 # absolute value times percentage of 60 centiseconds = modf(abs(dt))[0] * 100 s = '%02d:%02d.%02d' % (minutes, seconds, centiseconds) text(s, x=510, y=700, font_size=34, font_name='AvenirNext-Heavy') def handle_touch(self, touch): if self.winner: # check for winner overlay and clear. # Overlays to restart game to play again self.winner = None self.hide_overlay() del self.hide_overlay self.left_player.score = 0 self.right_player.score = 0 # stops the clock self.stop_time = time.time() self.running = False # resets the clock self.start_time = 0.0 self.last_seconds = 0 self.stop_time = 0.0 # starts the clock self.start_time = time.time() self.running = True return tx = touch.location.x # sets x touch location... ty = touch.location.y # sets y touch location... finger = Rect(tx - 20, ty - 20, 40, 40) # sets touch location for finger size if finger.intersects(self.puck.pos): dx = tx - touch.prev_location.x dy = ty - touch.prev_location.y # Richochet for unmoving finger, to make it like a real air hockey game if abs(dx) < 5 and abs(dy) < 5: self.puck.reverse_vector() # Slide puck out from the finger. No puck holding. if dx == 0: dx = self.puck.vector.x if dy == 0: dy = self.puck.vector.y if not any([dx, dy]): return while finger.intersects(self.puck.pos): self.puck.pos.x += dx self.puck.pos.y += dy else: self.step = 0 self.puck_start_t = self.t self.puck.vector = Vector3(dx * .8, dy * .8, 0) self.puck.pos.x += dx self.puck.pos.y += dy class Start (Scene): def draw(self): background(0.40, 0.80, 1.00) # light blue background color fill(0.50, 1.00, 0.00) # play button fill color rect(320, 350, 358, 100) # play button rectangle tint(1.00, 1.00, 1.00) # white text color text('Play Game', font_name='AvenirNext-Heavy', font_size=60.0, x=500.0, y=400.0) def touch_ended(self, touch): main_scene.switch_scene(Game) class GameOver (Scene): def setup(self): self.button = Button(Rect((screen_size.w/2)-100, (screen_size.h/2)-50, 200, 100), 'RESTART') self.button.action = self.restart self.add_layer(self.button) def restart(self): main_scene.switch_scene(Game) def draw(self): background(0,0,0) self.button.draw() no_tint() text('Your score was: {0}'.format(score), x=screen_size.w/2, y=screen_size.h-50, font_size=24) class MultiScene (Scene): def __init__(self, start_scene): self.active_scene = start_scene() def switch_scene(self, new_scene): self.active_scene = new_scene() self.setup() def setup(self): global screen_size screen_size = self.size self.active_scene.add_layer = self.add_layer self.active_scene.size = self.size self.active_scene.setup() def draw(self): self.active_scene.touches = self.touches self.active_scene.draw() def touch_began(self, touch): self.active_scene.touch_began(touch) def touch_moved(self, touch): self.active_scene.touch_moved(touch) def touch_ended(self, touch): self.active_scene.touch_ended(touch) main_scene = MultiScene(Start) run(main_scene)
-
Not sure why this isn't working, as I'm not calling the run twice.
-
It should work if you change your MultiScene class to this:
class MultiScene (Scene): def __init__(self, start_scene): self.active_scene = start_scene() def switch_scene(self, new_scene): self.active_scene = new_scene() self.setup() def setup(self): global screen_size screen_size = self.size self.active_scene.add_layer = self.add_layer self.active_scene.size = self.size self.active_scene.bounds = self.bounds self.active_scene.root_layer = self.root_layer self.active_scene.setup() def draw(self): self.active_scene.touches = self.touches self.active_scene.t = self.t self.active_scene.draw() def touch_began(self, touch): self.active_scene.touch_began(touch) def touch_moved(self, touch): self.active_scene.touch_moved(touch) def touch_ended(self, touch): self.active_scene.touch_ended(touch)
-
@Sebastian, your solution works fine, but the overlays don't show their color for goals. They show up, but with a white background. Same with the game over layer.
-
This post is deleted! -
Two things to try...
In the draw() method of "sub-scenes", instead of calling background(r, g, b) try calling main_scene.background(r, g, b)... I am not sure if it will work but it is worth a try.
If that does not work, you could try putting your overlays directly onto main_scene instead of onto sub-scenes.
-
Nope, first method does not work. I'm gonna try putting the overlays directly onto main_scene then try.
-
This post is deleted!