Let's make a breakout with wxPython

Introduction

A video by Google Deepmind that applies Deep Q Learning to ATARI's Break Out to capture it has become popular. (The video is here) I decided to try this myself, and I thought it would be useful later, so I started by making a breakout by myself. The reason I used wxPython was because I wanted the Deep Learning library to be used later to be Python-based.

There is still a long way to go before deep Q-learning, but I wrote an article with the hope that it would be helpful in creating animation apps using wxPython.

It requires wxPython to work. The installation method is [here](http://qiita.com/kanlkan/items/5e6f2e63de406f46b3b1#wxpython%E3%81%AE%E3%82%A4%E3%83%B3%E3%82%B9%E3%83 Please see% 88% E3% 83% BC% E3% 83% AB) and so on.

Source code

It is also posted on GitHub, but it is not so long, so I will post it here as well.

break-wall.py


#!/usr/bin/env python
# -*- coding: utf-8 -*-

# break-wall.py
#

import wx
import random
import math

gVersion = "0.8.0"
gGameState = ("INIT","PLAYING","END")
gTimerInterval = 5 # [msec]
gFieldWidth = 640
gFieldHeight = 720
gFieldColor = (230,230,160)
gBarIniPos = (300, 640)
gBarSize = (120, 20)
gBarColor = (90, 170, 90)
gBarSpeed = 12 
gBallRadius = 8
gBallColor = (0, 0, 255)
gIniBallSpeed = 2
gBlkTop = 120
gBlkVCnt = 8
gBlkHCnt = 3
gBlkSize = (80, 40)
gBlkColor = ((255,0,0),(0,255,0),(0,0,255))

class MainFrame(wx.Frame):
    def __init__(self):
        wx.Frame.__init__(self, None, wx.ID_ANY, 'Break Wall :' + gVersion, \
                          size=(gFieldWidth + 4, gFieldHeight + 4), \
                          style=wx.DEFAULT_FRAME_STYLE & ~(wx.RESIZE_BORDER | wx.MAXIMIZE_BOX))
        self.main_field = FieldPanel(self)

        self.Bind(wx.EVT_CLOSE, self.onClose)
        self.Bind(wx.EVT_TIMER, self.onTimer)

        self.timer = wx.Timer(self)
        self.timer.Start(gTimerInterval)

    def onClose(self, event):
        self.timer.Stop()
        self.Destroy()

    def onTimer(self, event):
        self.main_field.update()


class FieldPanel(wx.Panel):
    def __init__(self, parent, pos=(2, 2), size=(gFieldWidth, gFieldHeight)):
        wx.Panel.__init__(self, parent, pos=pos, size=size)
        self.pos = pos
        self.size = size

        self.SetBackgroundColour(gFieldColor)
        self.SetBackgroundStyle(wx.BG_STYLE_PAINT)
        
        self.bar = Bar(self, gBarIniPos[0], gBarIniPos[1])
        self.ball = Ball(self, gBarIniPos[0], (gBarIniPos[1] - gBallRadius))
        self.blocks = [[Block(i*gBlkSize[0], gBlkTop+j*gBlkSize[1], \
                              gBlkColor[(gBlkVCnt*j+i)%gBlkHCnt]) \
                        for i in range(gBlkVCnt)] for j in range(gBlkHCnt)]
        self.block_exist = [[1 for i in range(gBlkVCnt)] for j in range(gBlkHCnt)]
        self.state = gGameState[0]

        self.Bind(wx.EVT_PAINT, self.onPaint)
        self.Bind(wx.EVT_KEY_DOWN, self.onKey)

    def update(self):
        self.ball.move()
        self.Refresh()
    
    def onPaint(self, event):
        dc = wx.AutoBufferedPaintDC(self)
        dc.Clear()
        # Paint Bar
        dc.SetPen(wx.Pen(self.bar.color))
        dc.SetBrush(wx.Brush(self.bar.color))
        dc.DrawRectangle(self.bar.x, self.bar.y, self.bar.size[0], self.bar.size[1])
        # Paint Ball
        dc.SetPen(wx.Pen(self.ball.color))
        dc.SetBrush(wx.Brush(self.ball.color))
        dc.DrawCircle(self.ball.x, self.ball.y, self.ball.radius)
        # Paint Blovks
        for (i, b_list) in enumerate(self.blocks):
            for (j, b) in enumerate(b_list):
                if self.block_exist[i][j] == 1:
                    dc.SetPen(wx.Pen(b.color,1))
                    dc.SetBrush(wx.Brush(b.color))
                    dc.DrawRectangle(b.x, b.y, b.size[0], b.size[1])

    def onKey(self, event):
        keycode = event.GetKeyCode()
        if keycode == wx.WXK_SPACE:
            if self.state == "INIT":
                self.ball.shoot()
                self.state = gGameState[1]
            elif self.state == "END":
                self.initialize()
                self.state = gGameState[0]
        elif (keycode == wx.WXK_LEFT or keycode == ord('H')) and self.state != "END":
            self.bar.move(-1)
        elif (keycode == wx.WXK_RIGHT or keycode == ord('L')) and self.state != "END":
            self.bar.move(1)

    def initialize(self):
        self.bar.x = gBarIniPos[0]
        self.bar.y = gBarIniPos[1]
        self.ball.x = self.bar.x
        self.ball.y = self.bar.y - self.ball.radius
        self.ball.vec = [0, 0]
        self.block_exist = [[1 for i in range(gBlkVCnt)] for j in range(gBlkHCnt)]


class Bar(object):
    def __init__(self, parent, x, y, size=gBarSize, color=gBarColor, speed=gBarSpeed):
        self.parent = parent
        self.x = x
        self.y = y
        self.size = size
        self.color = color
        self.speed = speed

    def move(self, direction):
        if direction >= 0:
            self.x += self.speed
        elif direction < 0:
            self.x -= self.speed

        if self.x < self.parent.pos[0]:
            self.x = self.parent.pos[0]
        elif self.x > (self.parent.pos[0] + self.parent.size[0] - self.size[0]):
            self.x = self.parent.pos[0] + self.parent.size[0] - self.size[0]


class Ball(object):
    def __init__(self, parent, x, y, radius=gBallRadius, vec=[0.0,0.0], \
                 color=gBallColor, speed=gIniBallSpeed):
        self.parent = parent
        self.x = x
        self.y = y
        self.radius = radius
        self.vec = vec
        self.color = color
        self.speed = speed

    def shoot(self):
        self.parent.state = gGameState[1]
        rand_x = random.randrange(1000, 5000)
        rand_y = random.randrange(2000, 5000)
        self.vec = (-1.0 * float(rand_x)/1000.0, -1.0 * float(rand_y)/1000.0)
        pass

    def move(self):
        if self.parent.state == "INIT":
            self.x = self.parent.bar.x
            self.y = self.parent.bar.y - self.radius
        elif self.parent.state == "END":
            pass
        else:
            unit = self.speed / math.sqrt(pow(self.vec[0],2) + pow(self.vec[1],2))
            self.x += (self.vec[0] * unit)
            self.y += (self.vec[1] * unit)
            self.collision()

    def collision(self):
        # Game Over
        if (self.y + self.radius) >= self.parent.size[1]:
            self.parent.state = gGameState[2]
            return
        
        # Bound at Bar
        if self.x >= self.parent.bar.x and \
           self.x <= (self.parent.bar.x + self.parent.bar.size[0]) and \
           self.y >= (self.parent.bar.y - self.radius) and \
           self.y <  (self.parent.bar.y + self.radius) and \
           self.vec[1] > 0:

            self.vec = [self.vec[0], -1*self.vec[1]]
            return

        # Bound at Frame
        #### left
        if self.vec[0] < 0 and \
           self.x <= (self.parent.pos[0] + self.radius):
            self.vec = [-1*self.vec[0], self.vec[1]]
            return
        #### right
        if self.vec[0] > 0 and \
           self.x >= (self.parent.pos[0] + self.parent.size[0] - self.radius):
            self.vec = [-1*self.vec[0], self.vec[1]]
            return
        
        #### ceiling 
        if self.y <= (self.parent.pos[1] + self.radius):
            self.vec = [self.vec[0], -1*self.vec[1]]
            return

        # Bound at Blocks
        no_block = 1
        for (i, b_exist_list) in enumerate(self.parent.block_exist):
            for (j, b_exist) in enumerate(b_exist_list):
                if b_exist == 1:
                    no_block = 0
                    tgt_block = self.parent.blocks[i][j]
                    # Ball cross the block edge
                    if self.x > (tgt_block.x - self.radius) and \
                       self.x < (tgt_block.x + tgt_block.size[0] + self.radius) and \
                       self.y > (tgt_block.y - self.radius) and \
                       self.y < (tgt_block.y + tgt_block.size[1] + self.radius):

                        self.parent.block_exist[i][j] = 0
                        # update vec
                        x0 = tgt_block.x + tgt_block.size[0] / 2
                        y0 = tgt_block.y + tgt_block.size[1] / 2
                        k = float(tgt_block.size[1]) / float(tgt_block.size[0])
                        #### top
                        if (self.vec[1] > 0) and \
                           (self.x < x0 and \
                            self.y < (k * (self.x - x0) + y0 - self.radius)) or \
                           (self.x > x0 and \
                            self.y < (-1 * k * (self.x - x0) + y0 - self.radius)):

                            self.vec = [self.vec[0], -1*self.vec[1]]
                        #### bottom
                        elif (self.vec[1] < 0) and \
                             (self.x < x0 and \
                              self.y > (-1 * k * (self.x - x0) + y0 + self.radius)) or \
                             (self.x > x0 and \
                              self.y > (k * (self.x - x0) + y0 + self.radius)):

                            self.vec = [self.vec[0], -1*self.vec[1]]
                        #### left
                        elif (self.vec[0] > 0) and (self.x < x0):
                            self.vec = [-1*self.vec[0], self.vec[1]]
                        ### right
                        elif (self.vec[0] < 0) and (self.x > x0):
                            self.vec = [-1*self.vec[0], self.vec[1]]

                        return

        if no_block == 1:
            # Game Clear
            self.parent.state = gGameState[2]


class Block(object):
    def __init__(self, x, y, color, size=gBlkSize):
        self.x = x
        self.y = y
        self.color = color
        self.size = size


if __name__ == "__main__":
    app = wx.App()
    frame = MainFrame().Show()
    app.MainLoop()


Operation check environment

I think wxpython will work with 2.8 as well.

how to play

break-wall.png

reference

Recommended Posts

Let's make a breakout with wxPython
Let's make Othello with wxPython
Let's make a GUI with python.
Let's make a graph with python! !!
Let's make a supercomputer with xCAT
Let's make a shiritori game with Python
Let's make a voice slowly with Python
Let's make a simple language with PLY 1
Let's make a web framework with Python! (1)
Let's make a tic-tac-toe AI with Pylearn 2
Let's make a Twitter Bot with Python!
Let's make a web framework with Python! (2)
Let's replace UWSC with Python (5) Let's make a Robot
Let's make a Discord Bot.
Let's make dice with tkinter
Make a fortune with Python
Let's make a rock-paper-scissors game
Make a fire with kdeplot
[Let's play with Python] Make a household account book
Let's make a simple game with Python 3 and iPhone
Let's make dependency management with pip a little easier
Let's make a Mac app with Tkinter and py2app
Let's make a spherical grid with Rhinoceros / Grasshopper / GHPython
[Super easy] Let's make a LINE BOT with Python.
Let's make a websocket client with Python. (Access token authentication)
Let's make a remote rumba [Software]
Let's make a spot sale service 2
Let's make a spot sale service 1
Let's make Othello AI with Chainer-Part 1-
Make a recommender system with python
Make a filter with a django template
Let's make Othello AI with Chainer-Part 2-
Make a model iterator with PySide
Make a nice graph with plotly
Let's make a diagram that can be clicked with IPython
Let's make a spot sale service 3
Let's make a WEB application for phone book with flask Part 1
Let's make a cycle computer with Raspberry Pi Zero (W, WH)
Let's make a WEB application for phone book with flask Part 2
Let's make a WEB application for phone book with flask Part 3
Let's make a WEB application for phone book with flask Part 4
Let's make a web chat using WebSocket with AWS serverless (Python)!
Make a video player with PySimpleGUI + OpenCV
Let's create a free group with Python
Make a rare gacha simulator with Flask
Make a Notebook Pipeline with Kedro + Papermill
Make a partially zoomed figure with matplotlib
Let's scrape a dynamic site with Docker
Make a drawing quiz with kivy + PyTorch
Make a cascade classifier with google colaboratory
[Python] Let's make matplotlib compatible with Japanese
Make a logic circuit with a perceptron (multilayer perceptron)
Make a Yes No Popup with Kivy
Let's make a multilingual site using flask-babel
Make a wash-drying timer with a Raspberry Pi
Make a GIF animation with folder monitoring
Let's make a combination calculation in Python
Make a desktop app with Python with Electron
Let's make a Backend plugin for Errbot
[Ev3dev] Let's make a remote control program by Python with RPyC protocol
Breakout with Tensorflow