Compare commits
30 Commits
a6f6f56843
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| 36d646a26f | |||
| 32c33ae613 | |||
| 97bd53e491 | |||
| 0dc6555499 | |||
| 8b47026f0e | |||
| 097dd7486a | |||
| 6adb31f466 | |||
| db4f7d05f7 | |||
| dafeb80b77 | |||
| 3e4907f192 | |||
| 1366c10fd7 | |||
| a12a583444 | |||
| dce162ba4a | |||
| c8b25ff53b | |||
| 94fa33ebd0 | |||
| a1c5641eee | |||
| 471de3ef6e | |||
| e8ee151267 | |||
| 95e4df2810 | |||
| 23d0ca1ee2 | |||
| de4749cac9 | |||
| f2b9ab4d26 | |||
| b2cc7a996f | |||
| b0c752f946 | |||
| 71693518a8 | |||
| a8814fdfe1 | |||
| 585c54f205 | |||
| 54f9d8bc88 | |||
| 914ad5e0ce | |||
| 9643baa093 |
BIN
assets/spinner-tick.mp3
Normal file
BIN
assets/spinner-tick.mp3
Normal file
Binary file not shown.
188
game.py
188
game.py
@ -1,8 +1,83 @@
|
|||||||
|
import math as maths
|
||||||
import logging
|
import logging
|
||||||
import pygame
|
import random
|
||||||
|
import time
|
||||||
|
|
||||||
import gameUtils
|
import gameUtils
|
||||||
import NoPELib
|
import NoPELib
|
||||||
|
|
||||||
|
import numpy as np
|
||||||
|
import pygame
|
||||||
|
|
||||||
|
# TODO: Prevent another animation from starting when the wheel's spinning
|
||||||
|
# TODO: Convert fade in / out time to be random
|
||||||
|
# TODO: Make random finer (to prevent a range of 4-5 only having two possible speeds)
|
||||||
|
|
||||||
|
def translate(value, aMin, aMax, bMin, bMax):
|
||||||
|
"""
|
||||||
|
Translates `value` to go from `aMin`-`aMax` to `bMin`-`bMax`
|
||||||
|
Stolen from StackOverflow because we don't have time to do shit
|
||||||
|
properly here.
|
||||||
|
"""
|
||||||
|
|
||||||
|
aRange = aMax - aMin
|
||||||
|
bRange = bMax - bMin
|
||||||
|
return (((value - aMin) * bRange) / aRange) + bMin
|
||||||
|
|
||||||
|
def rotateRad(surface: pygame.Surface, radians: float) -> pygame.Surface:
|
||||||
|
"""
|
||||||
|
Rotates a surface clockwise in radians and re-centres it.
|
||||||
|
"""
|
||||||
|
# Calculate the degrees
|
||||||
|
deg = radians*(180/maths.pi)
|
||||||
|
# Rotate the surface re-centre
|
||||||
|
return rotateDeg(surface, deg)
|
||||||
|
|
||||||
|
def rotateDeg(surface: pygame.Surface, degrees: float) -> pygame.Surface:
|
||||||
|
"""
|
||||||
|
Rotates a surface clockwise in degrees and re-centres it.
|
||||||
|
"""
|
||||||
|
# Convert to CCW becaus for some reason that's what Pygame uses?
|
||||||
|
degrees *= -1
|
||||||
|
# Rotate surface which will expand it
|
||||||
|
rotSurface = pygame.transform.rotate(surface, degrees)
|
||||||
|
# re-centre it to the orinal surface bounding box
|
||||||
|
rotSurface = gameUtils.centre(rotSurface, surface.size)
|
||||||
|
return rotSurface
|
||||||
|
|
||||||
|
class WCfg:
|
||||||
|
"""
|
||||||
|
Holds all the Wheel Configurations.
|
||||||
|
"""
|
||||||
|
|
||||||
|
# The background colour of the wheel
|
||||||
|
bgColour = (25, 25, 25)
|
||||||
|
# The colour of the dividing lines
|
||||||
|
divColour = (75, 75, 75)
|
||||||
|
# The colour of the text
|
||||||
|
txtColour = (255, 255, 255)
|
||||||
|
# How much space is between the wheel and the screen
|
||||||
|
margin = 50
|
||||||
|
# The minimum and maximum time it takes (in seconds)
|
||||||
|
# for the wheel to get to full speed.
|
||||||
|
spinFadeInTimes = [0.25, 0.25]
|
||||||
|
# The minimum and maximum time it takes (in seconds)
|
||||||
|
# for the wheel to get to go back to being stationary.
|
||||||
|
spinFadeOutTimes = [3, 4]
|
||||||
|
# The minimum and maximum speeds of the wheel in deg/s
|
||||||
|
spinSpeedRange = [360, 1000]
|
||||||
|
# How many pixels away from the outer side of the
|
||||||
|
# circle the text should be
|
||||||
|
textMargin = 10
|
||||||
|
# The font to use for drawing the item text
|
||||||
|
font = pygame.font.SysFont('', 32)
|
||||||
|
|
||||||
|
class WheelItem:
|
||||||
|
# TODO: Add integration with NoPE-Lib
|
||||||
|
# TODO: Allow this to modify game attributes so it can hide the wheel and respin
|
||||||
|
def __init__(self, text):
|
||||||
|
self.text = text
|
||||||
|
|
||||||
class Game(gameUtils.Game):
|
class Game(gameUtils.Game):
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
"""
|
"""
|
||||||
@ -13,10 +88,84 @@ class Game(gameUtils.Game):
|
|||||||
self.pm (NoPELib.PlayerManager): This is where your players are stored.
|
self.pm (NoPELib.PlayerManager): This is where your players are stored.
|
||||||
self.cfg (dict): Everything from the `game.toml` file. You can access it like this: self.details['title']
|
self.cfg (dict): Everything from the `game.toml` file. You can access it like this: self.details['title']
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# Don't remove this. It does important things. :3
|
# Don't remove this. It does important things. :3
|
||||||
super().__init__(*args, **kwargs)
|
super().__init__(*args, **kwargs)
|
||||||
|
|
||||||
|
self.wheelSurf = pygame.Surface([min(self.size)-WCfg.margin*2]*2) # Don't ask.
|
||||||
|
self.wheelRotation = 0
|
||||||
|
# Holds the decided speed of the wheel
|
||||||
|
self.wheelSpinSpeed = 0
|
||||||
|
# Holds the decided fade in time
|
||||||
|
self.animFadeIn = 0
|
||||||
|
# Holds the decided fade out time
|
||||||
|
self.animFadeOut = 0
|
||||||
|
# When the wheel started its spin animation
|
||||||
|
self.wheelAnimStart = 0
|
||||||
|
# The ticker sound effect
|
||||||
|
self.tickSfx = pygame.mixer.Sound("./assets/spinner-tick.mp3")
|
||||||
|
# The last time (in time.perf_counter()) the ticker was played
|
||||||
|
self.lastTickTime = 0
|
||||||
|
# The last index the ticker ticked on
|
||||||
|
self.lastTickItem = -1
|
||||||
|
|
||||||
|
self.items = []
|
||||||
|
self.items.append(WheelItem('Drink 1 shot'))
|
||||||
|
self.items.append(WheelItem('Drink 2 shots'))
|
||||||
|
self.items.append(WheelItem('Get shocked at 50%'))
|
||||||
|
self.items.append(WheelItem('Get shocked at 100%'))
|
||||||
|
self.items.append(WheelItem('Get slapped by\neveryone in the room'))
|
||||||
|
self.items.append(WheelItem('Respin, wheel hidden'))
|
||||||
|
random.shuffle(self.items)
|
||||||
|
|
||||||
|
self.font = pygame.font.SysFont('', 50)
|
||||||
|
self.drawWheel()
|
||||||
|
|
||||||
|
def drawWheel(self):
|
||||||
|
# Calculate circle radius
|
||||||
|
circleR = self.wheelSurf.size[0] / 2
|
||||||
|
|
||||||
|
# Draw the base circle
|
||||||
|
pygame.draw.circle(self.wheelSurf, WCfg.bgColour, (circleR, circleR), circleR)
|
||||||
|
# Calculate the gap, in radians, between each item
|
||||||
|
gap = maths.pi * 2 / len(self.items)
|
||||||
|
|
||||||
|
for idx, item in enumerate(self.items):
|
||||||
|
# Calculate the radians of this item
|
||||||
|
rad = (idx / len(self.items)) * maths.pi * 2
|
||||||
|
# Calculate the vector offset by half the item gap
|
||||||
|
# This is because the text should be in the middle,
|
||||||
|
# and the lines (which is what this is used by) on the edges
|
||||||
|
vector = maths.cos(rad+gap/2), maths.sin(rad+gap/2)
|
||||||
|
# Calculate the end position of a line based on the vector
|
||||||
|
endPos = np.add(np.multiply(vector, circleR), circleR)
|
||||||
|
# Draw the dividing line
|
||||||
|
pygame.draw.line(self.wheelSurf, WCfg.divColour, (circleR, circleR), endPos)
|
||||||
|
|
||||||
|
# Create a surface that our text will be rendered onto
|
||||||
|
textSurf = pygame.Surface(self.wheelSurf.size, pygame.SRCALPHA)
|
||||||
|
# Render the item text
|
||||||
|
text = WCfg.font.render(item.text, True, WCfg.txtColour)
|
||||||
|
# Draw the item text onto the text surface, centred to the right
|
||||||
|
textSurf.blit(text, (textSurf.size[0]-text.get_width()-WCfg.textMargin, textSurf.size[1]//2 - text.get_height()//2))
|
||||||
|
# Draw debug lines
|
||||||
|
#if idx < 1:
|
||||||
|
# pygame.draw.rect(textSurf, (0, 128, 255), (0, 0, textSurf.size[0], textSurf.size[1]), 1)
|
||||||
|
# pygame.draw.line(textSurf, (255, 0, 0), (circleR, circleR), (textSurf.size[0], circleR))
|
||||||
|
# pygame.draw.line(textSurf, (0, 255, 0), (circleR, circleR), (circleR, textSurf.size[1]))
|
||||||
|
# Rotate the text surface
|
||||||
|
textSurf = rotateRad(textSurf, -rad)
|
||||||
|
# Blit the text surface to the wheel surface
|
||||||
|
self.wheelSurf.blit(textSurf, (0, 0))
|
||||||
|
|
||||||
|
def spinnerTick(self):
|
||||||
|
# If there's a tick already playing
|
||||||
|
if time.perf_counter() - self.lastTickTime < self.tickSfx.get_length():
|
||||||
|
return
|
||||||
|
|
||||||
|
self.tickSfx.play()
|
||||||
|
self.lastTickTime = time.perf_counter()
|
||||||
|
|
||||||
def onEvent(self, event):
|
def onEvent(self, event):
|
||||||
"""
|
"""
|
||||||
Ran when an event is fired.
|
Ran when an event is fired.
|
||||||
@ -24,14 +173,45 @@ class Game(gameUtils.Game):
|
|||||||
Args:
|
Args:
|
||||||
event (pygame.Event): The event that was fired.
|
event (pygame.Event): The event that was fired.
|
||||||
"""
|
"""
|
||||||
pass
|
if event.type == pygame.KEYDOWN:
|
||||||
|
if event.key == pygame.K_SPACE:
|
||||||
|
self.wheelSpinSpeed = random.randint(*WCfg.spinSpeedRange)
|
||||||
|
self.wheelAnimStart = time.perf_counter()
|
||||||
|
|
||||||
def update(self):
|
def update(self):
|
||||||
"""
|
"""
|
||||||
Ran once per frame, put your drawing code and any
|
Ran once per frame, put your drawing code and any
|
||||||
game logic that should be ran once per frame in here.
|
game logic that should be ran once per frame in here.
|
||||||
"""
|
"""
|
||||||
pass
|
self.surf.fill((0, 0, 0))
|
||||||
|
self.surf.blit(rotateDeg(gameUtils.centre(self.wheelSurf, self.size), self.wheelRotation), (0, 0))
|
||||||
|
arrowX = (self.size[0] - self.wheelSurf.size[0]) // 2 + self.wheelSurf.size[0]
|
||||||
|
arrowY = self.size[1] // 2
|
||||||
|
arrowSize = 20
|
||||||
|
arrowPollys = ((arrowX, arrowY), (arrowX+arrowSize, arrowY-arrowSize//2), (arrowX+arrowSize, arrowY+arrowSize//2))
|
||||||
|
pygame.draw.polygon(self.surf, (255, 255, 255), arrowPollys)
|
||||||
|
|
||||||
|
animTime = time.perf_counter() - self.wheelAnimStart
|
||||||
|
if animTime < WCfg.spinFadeInTimes[0] + WCfg.spinFadeOutTimes[0]:
|
||||||
|
if animTime < WCfg.spinFadeInTimes[0]:
|
||||||
|
speed = translate(animTime, 0, WCfg.spinFadeInTimes[0], 0, self.wheelSpinSpeed)
|
||||||
|
else:
|
||||||
|
speed = translate(animTime, WCfg.spinFadeInTimes[0], WCfg.spinFadeInTimes[0]+WCfg.spinFadeOutTimes[0], self.wheelSpinSpeed, 0)
|
||||||
|
|
||||||
|
self.wheelRotation += speed * self.timeDelta
|
||||||
|
self.wheelRotation %= 360
|
||||||
|
|
||||||
|
# Calculates the current item index with... I don't know, magic?
|
||||||
|
currentItemIdx = round((self.wheelRotation / 360) * len(self.items)) % len(self.items)
|
||||||
|
|
||||||
|
# If the last tick was on a different index,
|
||||||
|
if currentItemIdx != self.lastTickItem:
|
||||||
|
# Click again
|
||||||
|
self.spinnerTick()
|
||||||
|
# And set the last tick index to the current one
|
||||||
|
self.lastTickItem = currentItemIdx
|
||||||
|
|
||||||
|
self.surf.blit(self.font.render(self.items[currentItemIdx].text, True, (255, 255, 255)), (0, 0))
|
||||||
|
|
||||||
def close(self):
|
def close(self):
|
||||||
"""
|
"""
|
||||||
|
|||||||
@ -1,8 +1,8 @@
|
|||||||
# The ID used for logging
|
# The ID used for logging
|
||||||
# TODO: Filter things like '\', '{}', '\n' etc.-
|
# TODO: Filter things like '\', '{}', '\n' etc.-
|
||||||
id = "changeMe"
|
id = "spinTheSin"
|
||||||
# The name used for setting the windows
|
# The name used for setting the windows
|
||||||
# title, and for displaying in the launcher
|
# title, and for displaying in the launcher
|
||||||
name = "Change me"
|
name = "Spin The Sin"
|
||||||
# The description displayed by the launcher
|
# The description displayed by the launcher
|
||||||
description = "Write something about this game.\nNew lines are supported."
|
description = "Write something about this game.\nNew lines are supported."
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
../GameUtils/
|
../GameUtils/
|
||||||
../NoPELib/
|
../NoPELib/
|
||||||
../PDOLib/
|
../PDOLib/
|
||||||
pygame-ce
|
pygame-ce
|
||||||
|
numpy
|
||||||
Reference in New Issue
Block a user