+硬件趣学Python编程做一个融入集体的方块,俄罗斯方块的游戏制作牛艾科技目录ContentsSuccessWords2第二部分对象的封装第三部分继承和多态第四部分游戏基本设计思路第五部分俄罗斯方块的代码分析第一部分面向对象目录ContentsSuccessWords3第一部分面向对象4面向对象•面相过程和面相对象基本概念面相过程——怎么做?1.把完成某一个需求的所有步骤从头到尾逐步实现2.根据开发需求,将某些功能独立的代码封装成一个又一个函数3.最后完成的代码,就是顺序地调用不同的函数特点:1.注重步骤与过程,不注重职责分工2.如果需求复杂,代码会变得很复杂3.开发复杂项目,没有固定的套路,开发难度很大!5面向对象•面向对象——谁来做?相比较函数,面向对象是更大的封装,根据职责在一个对象中封装多个方法1.在完成某一个需求前,首先确定职责——要做的事情(方法)2.根据职责确定不同的对象,在对象内部封装不同的方法(多个)3.最后完成的代码,就是顺序地让不同的对象调用不同的方法特点:1.注重对象和职责,不同的对象承担不同的职责2.更加适合应对复杂的需求变化,是专门应对复杂项目开发,提供的固定套路3.需要在面向过程基础上,再学习一些面向对象的语法6面向对象•类类是对一群具有相同特征或者行为的事物的一个统称,是抽象的,不能直接使用特征被称为属性行为被称为方法类:就相当于制造飞机时的图纸,是一个模板,是负责创建对象的7面向对象•对象对象是由类创建出来的一个具体存在,可以直接使用由哪一个类创建出来的对象,就拥有在哪一个类中定义的:属性、方法对象就相当于用图纸制造的飞机在程序开发中,应该先有类,再有对象目录ContentsSuccessWords8第二部分对象的封装对象的封装•内置函数序号方法名类型作用01__new__方法创建对象时,会被自动调用02__init__方法对象被初始化时,会被自动调用03__del__方法对象被从内存中销毁前,会被自动调用04__str__方法返回对象的描述信息,print函数输出使用10对象的封装•定义只包含方法的类•方法的定义格式和之前学习过的函数几乎一样•区别在于第一个参数必须是self,大家暂时先记住,稍后介绍self•注意:类名的命名规则要符合大驼峰命名法class类名:def方法1(self,参数列表):passdef方法2(self,参数列表):pass11对象的封装•创建对象对象变量=类名()•第一个面向对象程序•需求小猫爱吃鱼,小猫要喝水分析定义一个猫类Cat定义两个方法eat和drink按照需求——不需要定义属性classCat:这是一个猫类defeat(self):print(小猫爱吃鱼)defdrink(self):print(小猫在喝水)tom=Cat()tom.drink()tom.eat()12对象的封装•对象的属性在Python中,要给对象设置属性,非常的容易,但是不推荐使用因为:对象属性的封装应该封装在类的内部只需要在类的外部的代码中直接通过.设置一个属性即可注意:这种方式虽然简单,但是不推荐使用!tom.name=Tom...lazy_cat.name=大懒猫13对象的封装•方法中的self参数由哪一个对象调用的方法,方法内的self就是哪一个对象的引用在类封装的方法内部,self就表示当前调用方法的对象自己调用方法时,程序员不需要传递self参数在方法内部可以通过self.访问对象的属性也可以通过self.调用其他的对象方法改造代码如下:classCat:defeat(self):print(%s爱吃鱼%self.name)tom=Cat()tom.name=Tomtom.eat()lazy_cat=Cat()lazy_cat.name=大懒猫lazy_cat.eat()14对象的封装•初始化方法之前代码存在的问题——在类的外部给对象增加属性将案例代码进行调整,先调用方法再设置属性,观察一下执行效果在日常开发中,不推荐在类的外部给对象增加属性如果在运行时,没有找到属性,程序会报错对象应该包含有哪些属性,应该封装在类的内部tom=Cat()tom.drink()tom.eat()tom.name=Tomprint(tom)AttributeError:'Cat'objecthasnoattribute'name'属性错误:'Cat'对象没有'name'属性15对象的封装•初始化方法当使用类名()创建对象时,会自动执行以下操作:为对象在内存中分配空间——创建对象为对象的属性设置初始值——初始化方法(init)这个初始化方法就是__init__方法,__init__是对象的内置方法__init__方法是专门用来定义一个类具有哪些属性的方法!classCat:这是一个猫类def__init__(self):print(初始化方法)16对象的封装•初始化方法在初始化方法内部定义属性在__init__方法内部使用self.属性名=属性的初始值就可以定义属性定义属性之后,再使用Cat类创建的对象,都会拥有该属性classCat:def__init__(self):print(这是一个初始化方法)#定义用Cat类创建的猫对象都有一个name的属性self.name=Tomdefeat(self):print(%s爱吃鱼%self.name)#使用类名()创建对象的时候,会自动调用初始化方法__init__tom=Cat()tom.eat()17对象的封装•初始化方法改造初始化方法——初始化的同时设置初始值在开发中,如果希望在创建对象的同时,就设置对象的属性,可以对__init__方法进行改造把希望设置的属性值,定义成__init__方法的参数在方法内部使用self.属性=形参接收外部传递的参数在创建对象时,使用类名(属性1,属性2...)调用classCat:def__init__(self,name):print(初始化方法%s%name)self.name=name...tom=Cat(Tom)...lazy_cat=Cat(大懒猫)...目录ContentsSuccessWords18第三部分继承和多态19继承•面向对象三大特性1.封装根据职责将属性和方法封装到一个抽象的类中2.继承实现代码的重用,相同的代码不需要重复的编写3.多态不同的对象调用相同的方法,产生不同的执行结果,增加代码的灵活度20继承•继承的概念、语法和特点继承的概念:子类拥有父类的所有方法和属性21继承•继承的语法class类名(父类名):pass子类继承自父类,可以直接享受父类中已经封装好的方法,不需要再次开发子类中应该根据职责,封装子类特有的属性和方法例子:Dog类是Animal类的子类,Animal类是Dog类的父类,Dog类从Animal类继承Dog类是Animal类的派生类,Animal类是Dog类的基类,Dog类从Animal类派生22继承•继承的传递性C类从B类继承,B类又从A类继承那么C类就具有B类和A类的所有属性和方法子类拥有父类以及父类的父类中封装的所有属性和方法提问哮天犬能够调用Cat类中定义的catch方法吗?答案不能,因为哮天犬和Cat之间没有继承关系23继承•方法的重写子类拥有父类的所有方法和属性子类继承自父类,可以直接享受父类中已经封装好的方法,不需要再次开发当父类的方法实现不能满足子类需求时,可以对方法进行重写(override)24继承•重写父类方法有两种情况:1)覆盖父类的方法2)对父类方法进行扩展如果在开发中,父类的方法实现和子类的方法实现,完全不同就可以使用覆盖的方式,在子类中重新编写父类的方法实现具体的实现方式,就相当于在子类中定义了一个和父类同名的方法并且实现重写之后,在运行时,只会调用子类中重写的方法,而不再会调用父类封装的方法如果在开发中,子类的方法实现中包含父类的方法实现父类原本封装的方法实现是子类方法的一部分就可以使用扩展的方式在子类中重写父类的方法在需要的位置使用super().父类方法来调用父类方法的执行代码其他的位置针对子类的需求,编写子类特有的代码实现25多态•多态是指不同的子类对象调用相同的父类方法,产生不同的执行结果,也就是定义时的类型和运行时的类型不一样,此时就称为多态,多态可以增加代码的灵活度,多态以继承和重写父类方法为前提,是调用方法的技巧,不会影响到类的内部设计。•Python崇尚“鸭子类型”,“鸭子类型”可以这样表述:“当看到一只鸟走起来像鸭子、游泳起来像鸭子、叫起来也像鸭子,那么这只鸟就可以被称为鸭子”,也就是关注的不是对象的类型本身,而是它是如何使用的。26多态•多态更容易编写出出通用的代码,做出通用的编程,以适应需求的不断变化!目录ContentsSuccessWords27第四部分游戏基本设计思路28游戏基本设计思路•画背景棋盘俄罗斯方块屏幕有两个区域,一个是游戏区域,一个是方块预览区域。游戏区域用于下落方块进行堆积。预览区域用于显示下一个要下落的方块类型。29游戏基本设计思路•将界面拆分成若干个的网格•每个格是10*10的大小•将预览窗口也同样拆分成网格•游戏就是控制在不同的时机渲染不同的网格30游戏基本设计思路•消除机制:当某行没有空的方块时,会消除这行,同时对这行以上的所有行进行移动,向下移动一行。•失败条件当第0行不为空时,则游戏结束目录ContentsSuccessWords31第五部分俄罗斯方块代码分析32俄罗斯方块的代码分析•画背景网格主要使用方法:1、画直线screen.drawline(x1,y1,x2,y2,pensize,pencolor)#x1:起点横坐标,y1:起点纵坐标,#x2:终点横坐标,y2:终点纵坐标,#pensize:画笔宽度,pencolor:画笔颜色2、输出文本text.draw(str,x,y,textColor,bgColor)#str:文本,x:左上角顶点横坐标,y:左上角顶点纵坐标,#textColor:前景颜色,bgColor:背景颜色33俄罗斯方块的代码分析•画背景网格classGrid(object):def__init__(self,master=None,x=10,y=10,w=193,h=303):self.x=xself.y=yself.w=wself.h=hself.rows=h//10self.cols=w//10self.bg=0x000000;print(self.rows,self.cols)#画背景foriinrange(320):screen.drawline(0,i,239,i,1,self.bg);#画边界screen.drawline(x,y,x+w-1,y,1,0xFFFFFF);screen.drawline(x+w-1,y,x+w-1,y+h,1,0xFFFFFF);screen.drawline(x,y+h,x+w-1,y+h,1,0xFFFFFF);screen.drawline(x,y,x,y+h,1,0xFFFFFF);初始化参数渲染背景颜色画左侧区域的边框34俄罗斯方块的代码分析•画背景网格#画提示框边界screen.drawline(204,10,204+32-1,10,1,0xFFFFFF);screen.drawline(204+32-1,10,204+32-1,10+32,1,0xFFFFFF);screen.drawline(204,10+32,204+32-1,10+32,1,0xFFFFFF);screen.drawline(204,10,204,10+32,1,0xFFFFFF);defdrawgrid(self,pos,color):x=pos[1]*10+self.x+2y=pos[0]*10+self.y+2foriinrange(9):screen.drawline(x,y+i,x+9-1,y+i,1,color);defdrawpre(self,pos,color):x=pos[1]*10+