renpy/tutorial/game/indepth_minigame.rpy
2023-01-18 23:13:55 +01:00

287 lines
9.3 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

example minigame:
init python:
class PongDisplayable(renpy.Displayable):
def __init__(self):
renpy.Displayable.__init__(self)
# The sizes of some of the images.
self.PADDLE_WIDTH = 12
self.PADDLE_HEIGHT = 95
self.PADDLE_X = 240
self.BALL_WIDTH = 15
self.BALL_HEIGHT = 15
self.COURT_TOP = 129
self.COURT_BOTTOM = 650
# Some displayables we use.
self.paddle = Solid("#ffffff", xsize=self.PADDLE_WIDTH, ysize=self.PADDLE_HEIGHT)
self.ball = Solid("#ffffff", xsize=self.BALL_WIDTH, ysize=self.BALL_HEIGHT)
# If the ball is stuck to the paddle.
self.stuck = True
# The positions of the two paddles.
self.playery = (self.COURT_BOTTOM - self.COURT_TOP) / 2
self.computery = self.playery
# The speed of the computer.
self.computerspeed = 380.0
# The position, delta-position, and the speed of the
# ball.
self.bx = self.PADDLE_X + self.PADDLE_WIDTH + 10
self.by = self.playery
self.bdx = .5
self.bdy = .5
self.bspeed = 350.0
# The time of the past render-frame.
self.oldst = None
# The winner.
self.winner = None
def visit(self):
return [ self.paddle, self.ball ]
# Recomputes the position of the ball, handles bounces, and
# draws the screen.
def render(self, width, height, st, at):
# The Render object we'll be drawing into.
r = renpy.Render(width, height)
# Figure out the time elapsed since the previous frame.
if self.oldst is None:
self.oldst = st
dtime = st - self.oldst
self.oldst = st
# Figure out where we want to move the ball to.
speed = dtime * self.bspeed
oldbx = self.bx
if self.stuck:
self.by = self.playery
else:
self.bx += self.bdx * speed
self.by += self.bdy * speed
# Move the computer's paddle. It wants to go to self.by, but
# may be limited by it's speed limit.
cspeed = self.computerspeed * dtime
if abs(self.by - self.computery) <= cspeed:
self.computery = self.by
else:
self.computery += cspeed * (self.by - self.computery) / abs(self.by - self.computery)
# Handle bounces.
# Bounce off of top.
ball_top = self.COURT_TOP + self.BALL_HEIGHT / 2
if self.by < ball_top:
self.by = ball_top + (ball_top - self.by)
self.bdy = -self.bdy
if not self.stuck:
renpy.sound.play("pong_beep.opus", channel=0)
# Bounce off bottom.
ball_bot = self.COURT_BOTTOM - self.BALL_HEIGHT / 2
if self.by > ball_bot:
self.by = ball_bot - (self.by - ball_bot)
self.bdy = -self.bdy
if not self.stuck:
renpy.sound.play("pong_beep.opus", channel=0)
# This draws a paddle, and checks for bounces.
def paddle(px, py, hotside):
# Render the paddle image. We give it an 800x600 area
# to render into, knowing that images will render smaller.
# (This isn't the case with all displayables. Solid, Frame,
# and Fixed will expand to fill the space allotted.)
# We also pass in st and at.
pi = renpy.render(self.paddle, width, height, st, at)
# renpy.render returns a Render object, which we can
# blit to the Render we're making.
r.blit(pi, (int(px), int(py - self.PADDLE_HEIGHT / 2)))
if py - self.PADDLE_HEIGHT / 2 <= self.by <= py + self.PADDLE_HEIGHT / 2:
hit = False
if oldbx >= hotside >= self.bx:
self.bx = hotside + (hotside - self.bx)
self.bdx = -self.bdx
hit = True
elif oldbx <= hotside <= self.bx:
self.bx = hotside - (self.bx - hotside)
self.bdx = -self.bdx
hit = True
if hit:
renpy.sound.play("pong_boop.opus", channel=1)
self.bspeed *= 1.10
# Draw the two paddles.
paddle(self.PADDLE_X, self.playery, self.PADDLE_X + self.PADDLE_WIDTH)
paddle(width - self.PADDLE_X - self.PADDLE_WIDTH, self.computery, width - self.PADDLE_X - self.PADDLE_WIDTH)
# Draw the ball.
ball = renpy.render(self.ball, width, height, st, at)
r.blit(ball, (int(self.bx - self.BALL_WIDTH / 2),
int(self.by - self.BALL_HEIGHT / 2)))
# Check for a winner.
if self.bx < -50:
self.winner = "eileen"
# Needed to ensure that event is called, noticing
# the winner.
renpy.timeout(0)
elif self.bx > width + 50:
self.winner = "player"
renpy.timeout(0)
# Ask that we be re-rendered ASAP, so we can show the next
# frame.
renpy.redraw(self, 0)
# Return the Render object.
return r
# Handles events.
def event(self, ev, x, y, st):
import pygame
# Mousebutton down == start the game by setting stuck to
# false.
if ev.type == pygame.MOUSEBUTTONDOWN and ev.button == 1:
self.stuck = False
# Ensure the pong screen updates.
renpy.restart_interaction()
# Set the position of the player's paddle.
y = max(y, self.COURT_TOP)
y = min(y, self.COURT_BOTTOM)
self.playery = y
# If we have a winner, return him or her. Otherwise, ignore
# the current event.
if self.winner:
return self.winner
else:
raise renpy.IgnoreEvent()
screen pong():
default pong = PongDisplayable()
add "bg pong field"
add pong
text _("Player"):
xpos 240
xanchor 0.5
ypos 25
size 40
text _("Eileen"):
xpos (1280 - 240)
xanchor 0.5
ypos 25
size 40
if pong.stuck:
text _("Click to Begin"):
xalign 0.5
ypos 50
size 40
label demo_minigame:
e "You may want to mix Ren'Py with other forms of gameplay. There are a couple of ways to do this."
e "The first is with the screen system, which can be used to display data and create button and menu based interfaces."
e "Screens will work for many simulation-style games and RPGs."
e "When screens are not enough, you can write a creator-defined displayable to extend Ren'Py itself. A creator-defined displayable can process raw events and draw to the screen." id demo_minigame_a92baa6b
e "That makes it possible to create all kinds of minigames. Would you like to play some pong?"
example minigame hide:
label play_pong:
window hide # Hide the window and quick menu while in pong
$ quick_menu = False
call screen pong
$ quick_menu = True
window show
show eileen vhappy
if _return == "eileen":
e "I win!"
else:
e "You won! Congratulations."
label pong_done:
show eileen happy
menu:
e "Would you like to play again?"
"Sure.":
jump play_pong
"No thanks.":
pass
show example minigame large
e "Here's the source code for the minigame. It's very complex, and assumes you understand Python well."
e "I won't go over it in detail here. You can read more about it in the {a=https://www.renpy.org/doc/html/udd.html}Creator-Defined Displayable documentation{/a}."
hide example
e "Minigames can spice up your visual novel, but be careful not every visual novel player wants to be good at arcade games."
e "Part of the reason Ren'Py works well is that it's meant for certain types of games, like visual novels and life simulations."
e "The further afield you get from those games, the more you'll find yourself fighting Ren'Py. At some point, it makes sense to consider other engines."
show eileen vhappy
e "And that's fine with us. We'll always be here for you when you're making visual novels."
show eileen happy
return