[python]wxPython学习记录4——贪吃蛇

时间:2021-12-23 07:11:21

要离职了,忙着写项目交接文档,真心累。明年去南京工作,还不知道能不能找着东家,苦逼[python]wxPython学习记录4——贪吃蛇以后就不能去北高峰爬山啦,这个礼拜最后再去看次妹纸撒

今天用wxPython做了个贪吃蛇,当是对wxPythonGDI的巩固。

关于如何在屏幕上绘画,请参见wxPython In Action的第六章1.1在屏幕上绘画

贪吃蛇源码下载不要积分

贪吃蛇源码及py2exe打包结果下载骗一个积分

突然发现一个bug,buffer的实际面积比窗口显示的要大,也就是说,当snakeHead的X是600的时候,snake已经超出右边界了,此时游戏还未失败-  -晚上用sizer修改一下。

资源中的代码与最终代码不同,请参考贪吃蛇全部代码

来画一条蛇吧

贪吃蛇首先得要有一条蛇才行,蛇细细长长的,就是一条线,那么怎么画一条线呢?以下代码就是如何画一条线,这与贪吃蛇无关,仅仅只是先初步了解怎么画。请注意OnPaint中的

dc = wx.BufferedPaintDC(self, self.buffer)
可以注释掉试试

# -*- coding:utf-8 -*-
'''
Created on 2013-1-16

@author: jincheng
'''
import wx

class SnakeWindow(wx.Window):
'''
贪吃蛇
'''
def __init__(self,parent):
wx.Window.__init__(self,parent,-1)
self.snakeColor='black'
self.SetBackgroundColour('green')
self.snakeThickness = 10
self.snake = [(100,100),(100,200)]
self.pen = wx.Pen(self.snakeColor, self.snakeThickness, wx.SOLID)
self.buffer = wx.EmptyBitmap(800,600)
dc = wx.BufferedDC(wx.ClientDC(self),self.buffer)
dc.SetPen(self.pen)
dc.DrawLine(100,200,300,400)
self.Bind(wx.EVT_PAINT, self.OnPaint)
#self.Bind(wx.EVT_LEFT_UP, self.OnLeftUp)

def OnPaint(self, event):
dc = wx.BufferedPaintDC(self, self.buffer)#处理一个paint(描绘)请求
print 'onpaint'

def OnLeftUp(self, event):
dc = wx.BufferedDC(wx.ClientDC(self),self.buffer)
dc.SetPen(self.pen)
pos = event.GetPositionTuple()
dc.DrawPoint(*pos)
print 'drawpoint'

class SnakeFrame(wx.Frame):
def __init__(self,parent):
wx.Frame.__init__(self,parent,-1,'title',size=(800,600))
self.sketch = SnakeWindow(self)


if __name__ == '__main__':
app = wx.PySimpleApp()
frame = SnakeFrame(None)
frame.Show(True)
app.MainLoop()

让蛇动起来

现在我知道了怎么画一条线,但是线不会动啊,不会动的蛇是死蛇而不是贪吃蛇,下面要让蛇动起来。

蛇应该怎么动?鼠标点一下动一下呢还是键盘按一下动一下?方向键不动的时候蛇也应该会动才对,不然的话该叫懒蛇。

这里需要用到wx.Timer,添加一个timer事件。

        self.runtime = wx.Timer(self)
        self.runtime.Start(100)#100毫秒动一下
        self.Bind(wx.EVT_TIMER, self.OnTimer)

    #每一百毫秒做一件事
    def OnTimer(self,event):
        self.SnakeMove()
SnakeMove顾名思义是贪吃蛇开始移动了。

此时我们需要考虑两件事:1、蛇往哪个方向移动;2、蛇每次移动多少距离。当然这条蛇只会或垂直方向或水平方向移动

蛇默认是向下移动的,设一个属性self.snakeDire = 317。为什么设317呢?

我们知道,按方向键是可以控制蛇的前进方向的,所以我们要加一个键盘事件。可以打出keycode看看,注意贪吃蛇不能向尾巴方向倒车,不知道两头蛇行不行。

        self.Bind(wx.EVT_KEY_UP,self.OnKeyUp)
   
    def OnKeyUp(self,event):
        code = event.GetKeyCode()
        if code >= 314 and code <=317 and code != self.snakeDire - 2 and code != self.snakeDire + 2:
            self.snakeDire = code
获得了蛇行动的方向,就可以开始Move了

    def SnakeMove(self):
length = len(self.snake)
self.snake.pop(length-1)#shift
space = self.snakeSpace
x = 0
y = 0
if self.snakeDire == 317:
y = space
elif self.snakeDire == 316:
x = space
elif self.snakeDire == 315:
y = -space
elif self.snakeDire == 314:
x = -space
newhead = (self.snakeHead[0] + x,self.snakeHead[1] + y)
self.snake.insert(0,newhead)
self.snakeHead = newhead
dc = wx.BufferedDC(wx.ClientDC(self),self.buffer)
dc.SetPen(self.pen)
print self.snake
接着将画蛇的代码整理到一个方法里

def SnakeInstantiate(self,dc):    
'''
画出蛇
'''
last = self.snake[0]
length = len(self.snake)
for s in self.snake[1:length]:
line = last + s
dc.DrawLine(*line)
last = s

此阶段全部代码

# -*- coding:utf-8 -*-
'''
Created on 2013-1-16

@author: jincheng
'''
import wx

class SnakeWindow(wx.Window):
'''
贪吃蛇
'''
def __init__(self,parent):
wx.Window.__init__(self,parent,-1)
self.snakeColor='black'
self.SetBackgroundColour('green')
self.snakeThickness = 10
self.snake = [(100,100),(100,200),(100,300)]
self.snakeHead = (100,300)
self.snakeSpace = 10
self.pen = wx.Pen("red", 10, wx.SOLID)
self.winsize = self.GetClientSize()
self.buffer = wx.EmptyBitmap(800,600)

self.snakeDire = 317#蛇头向下

self.runtime = wx.Timer(self)
self.runtime.Start(100)#100毫秒动一下

self.Bind(wx.EVT_PAINT, self.OnPaint)
self.Bind(wx.EVT_KEY_UP,self.OnKeyUp)
self.Bind(wx.EVT_TIMER, self.OnTimer)
#self.Bind(wx.EVT_LEFT_UP, self.OnLeftUp)

def SnakeMove(self):
length = len(self.snake)
self.snake.pop(length-1)#shift
space = self.snakeSpace
x = 0
y = 0
if self.snakeDire == 317:
y = space
elif self.snakeDire == 316:
x = space
elif self.snakeDire == 315:
y = -space
elif self.snakeDire == 314:
x = -space
newhead = (self.snakeHead[0] + x,self.snakeHead[1] + y)
self.snake.insert(0,newhead)
self.snakeHead = newhead
dc = wx.BufferedDC(wx.ClientDC(self),self.buffer)
dc.SetPen(self.pen)
        #dc.Clear()
        print self.snake
self.SnakeInstantiate(dc)


def SnakeInstantiate(self,dc):
'''
画出蛇
'''
last = self.snake[0]
length = len(self.snake)
for s in self.snake[1:length]:
line = last + s
dc.DrawLine(*line)
last = s

def OnTimer(self,event):
self.SnakeMove()

def OnKeyUp(self,event):
code = event.GetKeyCode()
if code >= 314 and code <=317 and code != self.snakeDire - 2 and code != self.snakeDire + 2:
self.snakeDire = code


def OnPaint(self, event):
dc = wx.BufferedPaintDC(self, self.buffer)#13 处理一个paint(描绘)请求
print 'onpaint'

def OnLeftUp(self, event):
dc = wx.BufferedDC(wx.ClientDC(self),self.buffer)
dc.SetPen(self.pen)
pos = event.GetPositionTuple()
dc.DrawPoint(*pos)
print 'drawpoint'

class SnakeFrame(wx.Frame):
def __init__(self,parent):
wx.Frame.__init__(self,parent,-1,'title',size=(800,600))
self.sketch = SnakeWindow(self)


if __name__ == '__main__':
app = wx.PySimpleApp()
frame = SnakeFrame(None)
frame.Show(True)
app.MainLoop()

运行一下试试?

[python]wxPython学习记录4——贪吃蛇

为什么蛇明明什么都没吃,却越来越长?打印结果也依然娇小啊

[python]wxPython学习记录4——贪吃蛇

请注意,在画新的图案前,一定要clear一下旧的图案 ,凡游过,不留下痕迹。放开dc.Clear()那行代码!!!

食物在哪里

光有蛇没有食物是玩不了贪吃蛇的,食物怎么画?1、食物得出现在某个坐标上(x,y);2、食物得有一定的体积a*b,哪怕是1*1。

我们可以认为食物是一个(x,y,x+a,y+b)的线段,当然,也可以认为是一个长a宽b左上角坐标是(x,y)的矩形。在这里,我使用dc.DrawRectangle

        self.foodLoc = ()
self.foodWidth = 5
#生产食物
self.FoodManufacture()

    def FoodManufacture(self):
        x = random.randint(0,800)
        y = random.randint(0,600)
        self.foodLoc = (x,y)
    
    def foodInstantiate(self,dc):
'''
画出食物
'''
        food = self.foodLoc + (self.foodWidth,self.foodWidth)
        dc.DrawRectangle(*food)

此阶段全部代码

# -*- coding:utf-8 -*-
'''
Created on 2013-1-16

@author: jincheng
'''
import wx
import random

class SnakeWindow(wx.Window):
'''
贪吃蛇
'''
def __init__(self,parent):
wx.Window.__init__(self,parent,-1)
self.snakeColor='black'
self.SetBackgroundColour('green')
self.snakeThickness = 10
self.snake = [(100,100),(100,200),(100,300)]
self.snakeHead = (100,300)
self.snakeSpace = 10

self.foodLoc = ()
self.foodWidth = 5

self.FoodManufacture()

self.pen = wx.Pen("red", 10, wx.SOLID)
self.winsize = self.GetClientSize()
self.buffer = wx.EmptyBitmap(800,600)
self.snakeDire = 317#蛇头向下
#self.foodInstantiate()
self.runtime = wx.Timer(self)
self.runtime.Start(100)#100毫秒动一下

self.Bind(wx.EVT_PAINT, self.OnPaint)
self.Bind(wx.EVT_KEY_UP,self.OnKeyUp)
self.Bind(wx.EVT_TIMER, self.OnTimer)
#self.Bind(wx.EVT_LEFT_UP, self.OnLeftUp)

def FoodManufacture(self):
x = random.randint(0,800)
y = random.randint(0,600)
self.foodLoc = (x,y)

def foodInstantiate(self,dc):
food = self.foodLoc + (self.foodWidth,self.foodWidth)
dc.DrawRectangle(*food)


def SnakeMove(self):
length = len(self.snake)
self.snake.pop(length-1)#shift
space = self.snakeSpace
x = 0
y = 0
if self.snakeDire == 317:
y = space
elif self.snakeDire == 316:
x = space
elif self.snakeDire == 315:
y = -space
elif self.snakeDire == 314:
x = -space
newhead = (self.snakeHead[0] + x,self.snakeHead[1] + y)
self.snake.insert(0,newhead)
self.snakeHead = newhead
dc = wx.BufferedDC(wx.ClientDC(self),self.buffer)
dc.SetPen(self.pen)
dc.Clear()
print self.snake
self.SnakeInstantiate(dc)

def SnakeInstantiate(self,dc):
'''
画出蛇与食物
'''
self.foodInstantiate(dc)
last = self.snake[0]
length = len(self.snake)
for s in self.snake[1:length]:
line = last + s
dc.DrawLine(*line)
last = s

def OnTimer(self,event):
self.SnakeMove()

def OnKeyUp(self,event):
code = event.GetKeyCode()
if code >= 314 and code <=317 and code != self.snakeDire - 2 and code != self.snakeDire + 2:
self.snakeDire = code


def OnPaint(self, event):
dc = wx.BufferedPaintDC(self, self.buffer)#13 处理一个paint(描绘)请求
print 'onpaint'

def OnLeftUp(self, event):
dc = wx.BufferedDC(wx.ClientDC(self),self.buffer)
dc.SetPen(self.pen)
pos = event.GetPositionTuple()
pos = pos + (10,10)
dc.Clear()
dc.DrawRectangle(*pos)
print 'drawpoint'

class SnakeFrame(wx.Frame):
def __init__(self,parent):
wx.Frame.__init__(self,parent,-1,'title',size=(800,600))
self.sketch = SnakeWindow(self)


if __name__ == '__main__':
app = wx.PySimpleApp()
frame = SnakeFrame(None)
frame.Show(True)
app.MainLoop()

[python]wxPython学习记录4——贪吃蛇

吃到食物

吃到食物很好理解,蛇的头snakeHead碰到食物的位置foodLoc,就算吃到了,蛇也长大一节,随后重新投放食物

此阶段全部代码

# -*- coding:utf-8 -*-
'''
Created on 2013-1-16

@author: jincheng
'''
import wx
import random

class SnakeWindow(wx.Window):
'''
贪吃蛇
'''
def __init__(self,parent):
wx.Window.__init__(self,parent,-1)
self.snakeColor='black'
self.SetBackgroundColour('green')
self.snakeThickness = 10
self.snake = [(100,100),(100,200),(100,300)]
self.snakeHead = (100,300)
self.snakeSpace = 10

self.foodLoc = ()
self.foodWidth = 1

self.FoodManufacture()

self.pen = wx.Pen(self.snakeColor, self.snakeThickness, wx.SOLID)
self.winsize = self.GetClientSize()
self.buffer = wx.EmptyBitmap(800,600)
self.snakeDire = 317#蛇头向下
#self.foodInstantiate()
self.runtime = wx.Timer(self)
self.runtime.Start(100)#100毫秒动一下

self.Bind(wx.EVT_PAINT, self.OnPaint)
self.Bind(wx.EVT_KEY_UP,self.OnKeyUp)
self.Bind(wx.EVT_TIMER, self.OnTimer)
#self.Bind(wx.EVT_LEFT_UP, self.OnLeftUp)

def FoodManufacture(self):
x = random.randint(0,80)
y = random.randint(0,60)
self.foodLoc = (x*10,y*10)

def foodInstantiate(self,dc):
food = self.foodLoc + (self.foodWidth,self.foodWidth)
dc.DrawRectangle(*food)


def SnakeMove(self):
length = len(self.snake)
self.snake.pop(length-1)#shift
space = self.snakeSpace
x = 0
y = 0
if self.snakeDire == 317:
y = space
elif self.snakeDire == 316:
x = space
elif self.snakeDire == 315:
y = -space
elif self.snakeDire == 314:
x = -space
newhead = (self.snakeHead[0] + x,self.snakeHead[1] + y)
self.snake.insert(0,newhead)
self.snakeHead = newhead
dc = wx.BufferedDC(wx.ClientDC(self),self.buffer)
dc.SetPen(self.pen)
dc.Clear()
self.SnakeInstantiate(dc)

def SnakeInstantiate(self,dc):
'''
画出蛇与食物
'''
self.foodInstantiate(dc)
last = self.snake[0]
length = len(self.snake)
for s in self.snake[1:length]:
line = last + s
dc.DrawLine(*line)
last = s

if self.Eat():
pass

def Eat(self):
print self.snakeHead,self.foodLoc
if self.snakeHead == self.foodLoc:
self.snake.insert(0, self.foodLoc)
self.FoodManufacture()
#print self.snake
return True
else :
return False

def OnTimer(self,event):
self.SnakeMove()

def OnKeyUp(self,event):
code = event.GetKeyCode()
if code >= 314 and code <=317 and code != self.snakeDire - 2 and code != self.snakeDire + 2:
self.snakeDire = code
#self.SnakeMove()

def OnPaint(self, event):
dc = wx.BufferedPaintDC(self, self.buffer)#13 处理一个paint(描绘)请求
print 'onpaint'

def OnLeftUp(self, event):
dc = wx.BufferedDC(wx.ClientDC(self),self.buffer)
dc.SetPen(self.pen)
pos = event.GetPositionTuple()
pos = pos + (10,10)
dc.Clear()
dc.DrawRectangle(*pos)
print 'drawpoint'

class SnakeFrame(wx.Frame):
def __init__(self,parent):
wx.Frame.__init__(self,parent,-1,'title',size=(800,600))
self.sketch = SnakeWindow(self)


if __name__ == '__main__':
app = wx.PySimpleApp()
frame = SnakeFrame(None)
frame.Show(True)
app.MainLoop()
到此贪吃蛇的基本功能就实现了,还剩下判断游戏失败。

恭喜,GAME OVER

怎么判断游戏失败:1、蛇头超出窗口;2、蛇咬到自己(snakeHead in snake)

    def GameOver(self,newhead):
if newhead in self.snake:
self.runtime.Stop()
print 'autotomy'
return True
elif self.snakeHead[0] < 0 or self.snakeHead[0] > 800 or self.snakeHead[1] <1 or self.snakeHead[1] >600:
self.runtime.Stop()
print 'out'
return True
else :
return False

贪吃蛇全部代码

最新代码,已修正边界坐标  2013.1.18

# -*- coding:utf-8 -*-
'''
Created on 2013-1-16

@author: jincheng
'''
import wx
import random

class SnakeWindow(wx.Window):
    '''
    贪吃蛇
    '''
    def __init__(self,parent,size,offset):
        wx.Window.__init__(self,parent,-1,size=size)
        print self.GetBorder(wx.BOTTOM)
        self.area = (size[0]-offset,size[1]-offset)
        self.snakeColor='black'
        self.SetBackgroundColour('green')
        self.snakeThickness = 10
        self.snake = [(100,100),(100,110),(100,120)]
        self.snakeHead = (100,120)
        self.snakeSpace = 10
        self.snakeDebris = []
        
        self.foodLoc = ()
        self.foodWidth = 1
        
        self.FoodManufacture()
        
        self.pen = wx.Pen(self.snakeColor, self.snakeThickness, wx.SOLID)
        self.winsize = self.GetClientSize()
        self.buffer = wx.EmptyBitmap(*self.area)
        self.snakeDire = 317#蛇头向下
        #self.foodInstantiate()
        self.runtime = wx.Timer(self)
        self.runtime.Start(100)#100毫秒动一下

        self.Bind(wx.EVT_PAINT, self.OnPaint)
        self.Bind(wx.EVT_KEY_UP,self.OnKeyUp)
        self.Bind(wx.EVT_TIMER, self.OnTimer)
        #self.Bind(wx.EVT_LEFT_UP, self.OnLeftUp)
    
    def __RandPoint(self):
        x = random.randint(1,self.area[0]/10)*10
        y = random.randint(1,self.area[1]/10)*10
        return (x,y)
    
    def FoodManufacture(self):
        self.foodLoc = self.__RandPoint()
    
    def foodInstantiate(self,dc):
        food = self.foodLoc + (self.foodWidth,self.foodWidth)
        dc.DrawRectangle(*food)
    
    def __Fission(self):   
        '''
        抛洒尸骸
        '''
        point = self.__RandPoint()
        if point in self.snakeDebris or point == self.foodLoc:
            self.__Fission()
        else:
            return point
        
    def SnakeFission(self):
        '''
        蛇断尾
        '''
        length = len(self.snake)/2
        while length > 0:
            index = len(self.snake) - 1
            self.snake.pop(index)#删除末位
            point = self.__Fission()
            self.snakeDebris.append(point)
            length -= 1
            
    def SnakeFissionInstantiate(self,dc):
        for debris in self.snakeDebris:
            d = debris +  (self.foodWidth,self.foodWidth)
            dc.DrawRectangle(*d)
                
    def SnakeMove(self):
        length = len(self.snake)
        self.snake.pop(length-1)#shift
        space = self.snakeSpace
        x = 0
        y = 0
        if self.snakeDire == 317:
            y = space
        elif self.snakeDire == 316:
            x = space
        elif self.snakeDire == 315:
            y = -space
        elif self.snakeDire == 314:
            x = -space
        newhead = (self.snakeHead[0] + x,self.snakeHead[1] + y)
        self.GameOver(newhead)
            
        self.snake.insert(0,newhead)
        self.snakeHead = newhead
        dc = wx.BufferedDC(wx.ClientDC(self),self.buffer)
        dc.SetPen(self.pen)
        dc.Clear()
        self.SnakeInstantiate(dc)
        
    def SnakeInstantiate(self,dc):    
        '''
        画出蛇与食物
        '''
        self.foodInstantiate(dc)
        last = self.snake[0]
        length = len(self.snake)
        for s in self.snake[1:length]:
            line = last + s
            dc.DrawLine(*line)
            last = s
        
        if self.Eat():
            if len(self.snake) > 5:
                self.SnakeFission()
        pen = wx.Pen('red',self.snakeThickness,wx.SOLID)
        dc.SetPen(pen)
        self.SnakeFissionInstantiate(dc)
        
    def Eat(self):
        if self.snakeHead == self.foodLoc:
            self.snake.insert(0, self.foodLoc)
            self.FoodManufacture()
            return True
        else :
            return False
    
    def GameOver(self,newhead):
        print newhead
        if newhead in self.snake or newhead in self.snakeDebris:
            self.runtime.Stop()
            print 'autotomy'
            return True
        elif newhead[0] < 0 or newhead[0] > self.area[0] or newhead[1] < 0 or newhead[1] > self.area[1]:
            self.runtime.Stop()
            print 'out'
            return True
        else :
            return False
    
    def OnTimer(self,event):
        self.SnakeMove()
            
    def OnKeyUp(self,event):
        code = event.GetKeyCode()
        if code >= 314 and code <=317 and code != self.snakeDire - 2 and code != self.snakeDire + 2:
            self.snakeDire = code
        #self.SnakeMove()    
        
    def OnPaint(self, event):
        dc = wx.BufferedPaintDC(self, self.buffer)#13 处理一个paint(描绘)请求

    def OnLeftUp(self, event):
        dc = wx.BufferedDC(wx.ClientDC(self),self.buffer)
        dc.SetPen(self.pen)
        pos = event.GetPositionTuple()
        pos = pos + (10,10)
        dc.Clear()
        dc.DrawRectangle(*pos)
        print 'drawpoint'
    
class SnakeFrame(wx.Frame):
    def __init__(self,parent):
        wx.Frame.__init__(self,parent,-1,'title',size=(800,600))
        
        size = self.__AreaSize(self.GetClientSize())
        
        panel = wx.Panel(self)
        panel.SetBackgroundColour('#4f5049')
        
        border = 10
        
        self.sketch = SnakeWindow(panel,size,2*border)
    
        box = wx.BoxSizer(wx.VERTICAL)
        
        box.Add(self.sketch,1,wx.ALIGN_TOP|wx.ALL,border)
        panel.SetSizer(box)

    def __AreaSize(self,size):
        width = self.__AreaMath(size[0])
        height = self.__AreaMath(size[1])
        return (width,height)
    
    def __AreaMath(self,intparam):
        if intparam%10 < 5:
            return intparam/10 * 10
        else:
            return (intparam/10 + 1)*10
 
if __name__ == '__main__':
    app = wx.PySimpleApp()
    frame = SnakeFrame(None)
    frame.Show(True)
    app.MainLoop()          
一个最最最最简单的贪吃蛇游戏就是这样的啦