[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()           

运行一下试试?

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

请注意,在画新的图案前,一定要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()           


吃到食物

吃到食物很好理解,蛇的头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()           
          
一个最最最最简单的贪吃蛇游戏就是这样的啦


  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值