You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
173 lines
6.0 KiB
173 lines
6.0 KiB
#!/usr/bin/env python3 |
|
|
|
# MIT License |
|
# |
|
# Copyright (c) 2023 Eugenio Parodi <ceccopierangiolieugenio AT googlemail DOT com> |
|
# |
|
# Permission is hereby granted, free of charge, to any person obtaining a copy |
|
# of this software and associated documentation files (the "Software"), to deal |
|
# in the Software without restriction, including without limitation the rights |
|
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
|
# copies of the Software, and to permit persons to whom the Software is |
|
# furnished to do so, subject to the following conditions: |
|
# |
|
# The above copyright notice and this permission notice shall be included in all |
|
# copies or substantial portions of the Software. |
|
# |
|
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
|
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
|
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
|
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
|
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
|
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE |
|
# SOFTWARE. |
|
|
|
import sys, os, math |
|
from dataclasses import dataclass |
|
|
|
sys.path.append(os.path.join(sys.path[0],'../../../libs/pyTermTk')) |
|
import TermTk as ttk |
|
|
|
@dataclass |
|
class BreakOutParams(): |
|
colors = { |
|
'lines': [ |
|
ttk.TTkColor.fg("#FF0000"), |
|
ttk.TTkColor.fg("#FF0000"), |
|
ttk.TTkColor.fg("#FF8800"), |
|
ttk.TTkColor.fg("#FF8800"), |
|
ttk.TTkColor.fg("#00FF00"), |
|
ttk.TTkColor.fg("#00FF00"), |
|
ttk.TTkColor.fg("#FFFF00"), |
|
ttk.TTkColor.fg("#FFFF00")], |
|
'bar' : ttk.TTkColor.fg("#0088FF"), |
|
} |
|
delay: float = 0.05 |
|
lineBlocks: int = 14 |
|
blocksOffset: int = 5 |
|
size: tuple([int,int]) = (lineBlocks*8-1, blocksOffset+8+17) |
|
# The ball use a float |
|
# It ijs rasterized in the paint |
|
ballPos = [[20,blocksOffset+10],[math.sin(math.pi/4),math.cos(math.pi/4)]] |
|
barSize: int = 20 |
|
barPos: int = (size[0]-barSize)//2 |
|
|
|
class BreakOutDisplay(ttk.TTkWidget): |
|
_params = BreakOutParams() |
|
_blocks = [] |
|
|
|
def __init__(self, **kwargs): |
|
size = self._params.size |
|
self._initBlocks() |
|
super().__init__(**kwargs|{"size":size,"minSize":size,"maxSize":size}) |
|
self._timer = ttk.TTkTimer() |
|
self._timer.timeout.connect(self._timerEvent) |
|
self._timer.start(self._params.delay) |
|
|
|
def _initBlocks(self): |
|
self._blocks = [ |
|
[True for _ in range(self._params.lineBlocks)] |
|
for _ in range(8)] |
|
|
|
@ttk.pyTTkSlot() |
|
def _timerEvent(self): |
|
w,h = self._params.size |
|
[posx,posy],[vx,vy] = self._params.ballPos |
|
newposx=posx+vx |
|
newposy=posy+vy |
|
lineBlocks = self._params.lineBlocks |
|
blocksOffset = self._params.blocksOffset |
|
barPos = self._params.barPos |
|
barSize = self._params.barSize |
|
|
|
# Check if the border is hit: |
|
if newposx >= w: vx=-abs(vx) |
|
elif newposx <= 0: vx= abs(vx) |
|
if newposy >= h: vy=-abs(vy) |
|
elif newposy <= 0: vy= abs(vy) |
|
|
|
# Check if a block is hit: |
|
# get the block |
|
bx, by = int(newposx)//8, int(newposy)-blocksOffset |
|
if 0 <= by < 8: |
|
if 0 <= bx < lineBlocks: |
|
if self._blocks[by][bx]: |
|
self._blocks[by][bx] = False |
|
# check if coming from down: |
|
if vy < 0 and by==7 or (by<7 and not self._blocks[by+1][bx]): |
|
vy=abs(vy) |
|
# check if coming from up: |
|
elif vy > 0 and by==0 or (by>0 and not self._blocks[by-1][bx]): |
|
vy=-abs(vy) |
|
# check if coming from left: |
|
elif vx > 0 and bx==0 or (bx>0 and not self._blocks[by][bx-1]): |
|
vx=-abs(vx) |
|
else: |
|
vx= abs(vx) |
|
|
|
# Check if the bar is hit: |
|
if newposy >= h-1: |
|
if barPos < newposx < barPos+barSize: |
|
poff = newposx-barPos |
|
prel = poff-barSize/2 |
|
delta = prel/barSize |
|
vx = math.sin(math.pi*delta) |
|
vy = -math.cos(math.pi*delta) |
|
# Force a cap on the vertical speed |
|
vy = min(-1,vy) |
|
|
|
posx=posx+vx |
|
posy=posy+vy |
|
|
|
self._params.ballPos = [[posx,posy],[vx,vy]] |
|
self._timer.start(self._params.delay) |
|
self.update() |
|
|
|
|
|
def mouseMoveEvent(self, evt) -> bool: |
|
w = self._params.size[0] |
|
barsize = self._params.barSize |
|
self._params.barPos = min(max(0,evt.x-barsize//2),w-barsize) |
|
self.update() |
|
|
|
def paintEvent(self, canvas: ttk.TTkCanvas): |
|
colors = self._params.colors |
|
w,h = self._params.size |
|
lineBlocks = self._params.lineBlocks |
|
blocksOffset = self._params.blocksOffset |
|
barPos = self._params.barPos |
|
barSize = self._params.barSize |
|
posx,posy = self._params.ballPos[0] |
|
posx = int(posx) |
|
posy = int(posy) |
|
|
|
for by in range(8): |
|
for bx in range(lineBlocks): |
|
if self._blocks[by][bx]: |
|
canvas.drawText(pos=(bx*8,by+blocksOffset), |
|
text='▇'*7, |
|
color=colors['lines'][by]) |
|
|
|
canvas.drawText( |
|
pos=(barPos,h-1), |
|
text='▛'+'▀'*(barSize-2)+'▜', |
|
color=colors['bar']) |
|
|
|
ball = ['▘','▝', |
|
'▖','▗'][(posx%2)+2*(posy%2)] |
|
|
|
canvas.drawText( |
|
pos=(posx,posy), |
|
text=ball) |
|
root = ttk.TTk(title="breakout Demo", mouseTrack=True, layout=ttk.TTkGridLayout()) |
|
|
|
frame = ttk.TTkFrame(layout=ttk.TTkGridLayout(), title="BreakOuTTk") |
|
breakout = BreakOutDisplay(parent=frame) |
|
|
|
root.layout().addWidget(frame,1,1) |
|
root.layout().addItem(ttk.TTkLayout(),0,0) |
|
root.layout().addItem(ttk.TTkLayout(),2,0) |
|
root.layout().addItem(ttk.TTkLayout(),0,2) |
|
root.layout().addItem(ttk.TTkLayout(),2,2) |
|
|
|
root.mainloop()
|
|
|