wxPython和pycairo练习记录7

继续写障碍,选几个典型的来写。有个问题,有调用图片文件的类,每次生成新实例,都重新加载一次图片。应该把素材统一加载为全局变量,具体使用只需要引用素材变量。积重难返,记住这个教训,以后写其他的再注意吧。

7.1 铁块

刚想起障碍尺寸还有四分之一块的,之前的就不改了,这里铁块基础尺寸写成24*24大小。

class Iron(Obstacle):# 铁块def __init__(self, x, y):surface = self.Draw()super(Iron, self).__init__(x, y, surface)self._canCross = False # 不可穿行self._canDestroy = False # 不可打破self._layer = 0 # 层级,0 和坦克同一层self._canBulletCross = False # 子弹不可穿行self._buff = False # 没有特殊效果def Draw(self):# 尺寸24*24surface = cairo.ImageSurface(cairo.FORMAT_RGB24, 24, 24)ctx = cairo.Context(surface)# 底色ctx.set_source_rgb(0.7, 0.7, 0.7)ctx.paint()# 阴影ctx.move_to(0, 24)ctx.line_to(24, 24)ctx.line_to(24, 0)ctx.close_path()ctx.set_source_rgb(0.5, 0.5, 0.5)ctx.fill()# 高光ctx.rectangle(6, 6, 12, 12)ctx.set_source_rgb(1, 1, 1)ctx.fill()return surface

7.2 碉堡

它不同于普通障碍,检测到坦克到达一定范围就开始射击。不能无限制射击,不然就打成一条直线了,给武器类加上开火间隔时间。给障碍类新加 isRemote 属性,专门用于有远程作用的障碍。

因为是四方向的,只检测上下左右四个方向正方向是否有坦克经过。左上角坐标定位,实际检测坐标范围需要计算尺寸。

测试一下,碉堡图片找了两张图拼了一下。

class Blockhouse(Obstacle):# 碉堡def __init__(self, x, y, path="wall_blockhouse.png", radius=150):# 从文件加载 surfacetry:surface = cairo.ImageSurface.create_from_png(path)except IOError as e:print(e.message)super(Blockhouse, self).__init__(x, y, surface)self._canCross = False # 不可穿行self._canDestroy = True # 可打破self._layer = 0 # 层级,0 和坦克同一层self._canBulletCross = False # 子弹不可穿行self._buff = True # 有特殊效果self._isRemote = True # 有远程作用self._radius = radius # 火力覆盖半径self._direction = wx.WXK_UP # 射击方向# 加载武器和子弹self._weapon = Weapon(capacity=50, speed=1, interval=500)self._weapon.Loaded(self)for i in range(50):self._weapon.AddBullet(Bullet(type=3))def LoadWeapon(self, weapon):weapon.Loaded(self)self._weapon = weapondef GetWeapon(self):return self._weapondef GetRadius(self):return self._radiusdef GetDirection(self):return self._directiondef Act(self, tank=None):# 向坦克调整射击方向并射击direction = tank.GetDirection()tx, ty, tw, th = tank.GetRect()x, y, w, h = self.GetRect()if tx > x - tw and tx < x + w:if ty < y:# print("up")self._direction = wx.WXK_UPelse:# print("down")self._direction = wx.WXK_DOWNself._weapon.Fire()if ty > y - th and ty < y + h:if tx < x:# print("left")self._direction = wx.WXK_LEFTelse:# print("right")self._direction = wx.WXK_RIGHTself._weapon.Fire()

7.3 泥坑

坦克经过泥坑速度就减为1,离开后速度恢复,需要给坦克父类添加速度读写方法。在哪存储原始速度呢?给坦克父类再加个原始速度属性。

那么怎么判断离开的动作?试试像碉堡一样给它也添加一个远程作用,作用半径设为它本身的尺寸1.5倍。也许远程作用可以独立出一个雷达…

找的图片有点像沙地,修修补补又三年。两块泥坑相邻,作用相互影响,把探测半径减到极小,也不太理想,暂时没想到怎么解决。

class Mud(Obstacle):# 泥坑def __init__(self, x, y, path="wall_mud.png"):# 从文件加载 surfacetry:surface = cairo.ImageSurface.create_from_png(path)except IOError as e:print(e.message)super(Mud, self).__init__(x, y, surface)self._canCross = True # 可穿行self._canDestroy = False # 不可打破self._layer = -1 # 子弹可以在泥坑上层飞过self._canBulletCross = True # 子弹可穿行self._buff = True # 有特殊效果self._isRemote = True # 有远程作用self._radius = self._width * 1.5 # 作用半径def GetRadius(self):return self._radiusdef Act(self, tank=None):# 离开范围tx, ty, tw, th = tank.GetRect()x, y, w, h = self.GetRect()if tank.GetSpeed() == 1 and (tx < x - tw or tx > x + w or ty < y - th or ty > y + h):tank.ResetSpeed()def SecondAct(self, tank=None):# 进入范围if tank.GetSpeed() > 1:tank.SetSpeed(1)

7.4 传送阵

两个传送阵,碰撞其中一个,传送到另一个传送阵位置。在传送阵上需要等待时间才能传送,不然无限互传。出传送阵范围,等待时间归零。

class Transmission(Obstacle):# 传送阵def __init__(self, x, y):surface = self.Draw()super(Transmission, self).__init__(x, y, surface)self._canCross = True # 可穿行self._canDestroy = False # 不可打破self._layer = -1 # 层级,0 和坦克同一层self._canBulletCross = True # 子弹可穿行self._buff = True # 没有特殊效果self._isRemote = True # 有远程作用self._radius = self._width * 1.5  # 作用半径self._waitTime = 3000 # 等待时间3秒self._dest = None # 传送目的法阵def GetRadius(self):return self._radiusdef Draw(self):# 画个六芒星surface = cairo.ImageSurface(cairo.FORMAT_RGB24, 48, 48)ctx = cairo.Context(surface)# 填充紫色底色ctx.set_source_rgb(0.27, 0.1, 0.47)ctx.paint()ctx.save()ctx.set_source_rgb(1, 1, 1)for i in range(2):if i == 1:# 对称翻转ctx.scale(1, -1)  # (x * dx, y * dy)ctx.translate(0, -48)  # 设置坐标轴原点# 画直角三角形ctx.move_to(0, 12)ctx.line_to(48, 12)ctx.line_to(24, 48)ctx.close_path()ctx.stroke()ctx.restore()# 紫色底不太明显,画四个角,标识下边缘ctx.set_source_rgb(0.6, 0.6, 0.6)for i in range(2):if i == 1:# 关于 x 轴对称ctx.scale(1, -1)ctx.translate(0, -48)for j in range(2):if j == 1:# 关于 y 轴对称ctx.scale(-1, 1)ctx.translate(-48, 0)ctx.move_to(0, 6)ctx.line_to(0, 0)ctx.line_to(6, 0)ctx.close_path()ctx.fill()return surfacedef Act(self, tank=None):# 离开范围,等待时间归零tx, ty, tw, th = tank.GetRect()x, y, w, h = self.GetRect()if tx < x - tw or tx > x + w or ty < y - th or ty > y + h:tank.SetTransTime(0)def SecondAct(self, tank=None):# 进入法阵范围# 新进入,设置进入时间if tank.GetTransTime() == 0:tank.SetTransTime(cv.times * cv.SPEED)# 符合时间,开始传送if tank.GetTransTime() + self._waitTime <= cv.times * cv.SPEED:tank.SetX(self._dest.GetX())tank.SetY(self._dest.GetY())tank.SetTransTime(0)def Bind(self, transmission):# 法阵双向绑定self._dest = transmissiontransmission.SetDest(self)def GetDest(self):return self._destdef SetDest(self, dest):self._dest = dest

7.5 代码

# -*- coding: utf-8 -*-
# obstacle.pyimport math
import wx
import cairo
from display import Sprite
from weapon import Weapon, Bullet
import boardclass cv(board.cv):"""常量,用类属性避免使用全局变量"""# 面板尺寸BOARD_WIDTH = 600BOARD_HEIGHT = 400class Obstacle(Sprite):def __init__(self, x, y, surface):# 重写 Sprite 的构造函数, 直接传入 surfaceself._x = xself._y = yself._destroyed = False # 销毁状态self._surface = surface# 获取图像尺寸self._width = self._surface.get_width()self._height = self._surface.get_height()self._canCross = False # 是否可穿行self._canDestroy = False # 是否可打破self._layer = 0 # 层级,0 和坦克同一层,-1 下层, 1 上层self._canBulletCross = False # 是否子弹可穿行self._buff = False # 是否有为有特殊效果的self._isRemote = False # 可远程作用def CanCross(self):return self._canCrossdef CanDestroy(self):return self._canDestroydef GetLayer(self):return self._layerdef CanBulletCross(self):return self._canBulletCrossdef HasBuff(self):return self._buffdef IsRemote(self):return self._isRemotedef Act(self, tank=None):# 与坦克的交互行为,比如加滑行 _buff,比如碉堡直接开火passdef Update(self, times, speed):# 用于被定时器处理函数调用刷新,静态障碍不需要重写passclass Brick(Obstacle):# 砖墙def __init__(self, x, y):surface = self.Draw() # 直接绘制砖墙super(Brick, self).__init__(x, y, surface)self._canCross = False # 不可穿行self._canDestroy = True # 可打破self._layer = 0 # 层级,0 和坦克同一层self._canBulletCross = False # 子弹不可穿行self._buff = False # 没有特殊效果def Draw(self):# 绘制砖墙# 按坦克尺寸48创建图像,颜色不需要透明surface = cairo.ImageSurface(cairo.FORMAT_RGB24, 48, 48)# 砖块是错落砌在一起的,先建一个2倍障碍宽度的矩形,作为一行砖块rect1 = cairo.ImageSurface(cairo.FORMAT_RGB24, 96, 12)# 画一个小24*12的矩形砖块,然后重复平铺rect2 = cairo.ImageSurface(cairo.FORMAT_RGB24, 24, 12)ctx = cairo.Context(rect2)# 填充灰色作底,水泥ctx.set_source_rgb(0.4, 0.4, 0.4)ctx.paint()# 画矩形,填充砖红色,砖ctx.set_source_rgb(0.6, 0.3, 0)ctx.rectangle(2, 2, 20, 8)ctx.fill()# 画线,更深的砖色,阴影ctx.set_source_rgb(0.42, 0.02, 0)ctx.set_line_width(4)ctx.move_to(3, 10)ctx.line_to(3, 3)ctx.line_to(22, 3)ctx.stroke()# 以 rect2 重复填充 rect1ctx = cairo.Context(rect1)pattern = cairo.SurfacePattern(rect2)pattern.set_extend(cairo.Extend.REPEAT)ctx.set_source(pattern)ctx.paint()# 把 rect1 错位绘制到 surfacectx = cairo.Context(surface)ctx.set_source_surface(rect1, -12, 0)ctx.paint()ctx.set_source_surface(rect1, 0, 12)ctx.paint()ctx.set_source_surface(rect1, -12, 24)ctx.paint()ctx.set_source_surface(rect1, 0, 36)ctx.paint()return surfaceclass Grass(Obstacle):# 草地def __init__(self, x, y, path="wall_grass.png"):# 从文件加载 surfacetry:surface = cairo.ImageSurface.create_from_png(path)except IOError as e:print(e.message)super(Grass, self).__init__(x, y, surface)self._canCross = True # 可穿行self._canDestroy = False # 不可打破self._layer = 1 # 层级,0 和坦克同一层self._canBulletCross = True # 子弹可穿行self._buff = False # 没有特殊效果class Water(Obstacle):# 水面def __init__(self, x, y, path="wall_water.png"):# 从文件加载 surfacetry:surface = cairo.ImageSurface.create_from_png(path)except IOError as e:print(e.message)super(Water, self).__init__(x, y, surface)self._canCross = False # 不可穿行self._canDestroy = False # 不可打破self._layer = -1 # 子弹可以在水面上层飞过self._canBulletCross = True # 子弹可穿行self._buff = False # 没有特殊效果class Ice(Obstacle):# 冰面def __init__(self, x, y):surface = self.Draw()super(Ice, self).__init__(x, y, surface)self._canCross = True # 可穿行self._canDestroy = False # 不可打破self._layer = -1 # 层级,0 和坦克同一层self._canBulletCross = True # 子弹可穿行self._buff = True # 有特殊效果self._distance = 20 # 滑行距离def Draw(self):surface = cairo.ImageSurface(cairo.FORMAT_RGB24, 48, 48)ctx = cairo.Context(surface)# 填充底色ctx.set_source_rgb(0.1, 0.85, 0.95)ctx.paint()# 以中心逆向旋转45度ctx.translate(24, 24)ctx.rotate(math.pi * 3 / 4)ctx.translate(-24, -24)# 画几条表示冰面纹理的线ctx.set_source_rgb(0, 0.64, 0.8)for i in range(10):if i % 2 == 0:ctx.set_dash([5, 1])else:ctx.set_dash([10, 15])ctx.move_to(-10, 6 * i)ctx.line_to(70, 6 * i)ctx.stroke()return surfacedef Act(self, tank=None):# 与坦克的交互行为,比如加滑行 _buff,比如碉堡直接开火direction = tank.GetDirection()x = tank.GetX()y = tank.GetY()if direction == wx.WXK_UP:tank.SetY(y - self._distance)elif direction == wx.WXK_DOWN:tank.SetY(y + self._distance)elif direction == wx.WXK_LEFT:tank.SetX(x - self._distance)elif direction == wx.WXK_RIGHT:tank.SetX(x + self._distance)class Iron(Obstacle):# 铁块def __init__(self, x, y):surface = self.Draw()super(Iron, self).__init__(x, y, surface)self._canCross = False # 不可穿行self._canDestroy = False # 不可打破self._layer = 0 # 层级,0 和坦克同一层self._canBulletCross = False # 子弹不可穿行self._buff = False # 没有特殊效果def Draw(self):# 尺寸24*24surface = cairo.ImageSurface(cairo.FORMAT_RGB24, 24, 24)ctx = cairo.Context(surface)# 底色ctx.set_source_rgb(0.7, 0.7, 0.7)ctx.paint()# 阴影ctx.move_to(0, 24)ctx.line_to(24, 24)ctx.line_to(24, 0)ctx.close_path()ctx.set_source_rgb(0.5, 0.5, 0.5)ctx.fill()# 高光ctx.rectangle(6, 6, 12, 12)ctx.set_source_rgb(1, 1, 1)ctx.fill()return surfaceclass Blockhouse(Obstacle):# 碉堡def __init__(self, x, y, path="wall_blockhouse.png", radius=150):# 从文件加载 surfacetry:surface = cairo.ImageSurface.create_from_png(path)except IOError as e:print(e.message)super(Blockhouse, self).__init__(x, y, surface)self._canCross = False # 不可穿行self._canDestroy = True # 可打破self._layer = 0 # 层级,0 和坦克同一层self._canBulletCross = False # 子弹不可穿行self._buff = True # 有特殊效果self._isRemote = True # 有远程作用self._radius = radius # 火力覆盖半径self._direction = wx.WXK_UP # 射击方向# 加载武器和子弹self._weapon = Weapon(capacity=50, speed=1, interval=500)self._weapon.Loaded(self)for i in range(50):self._weapon.AddBullet(Bullet(type=3))def LoadWeapon(self, weapon):weapon.Loaded(self)self._weapon = weapondef GetWeapon(self):return self._weapondef GetRadius(self):return self._radiusdef GetDirection(self):return self._directiondef Act(self, tank=None):# 向坦克调整射击方向并射击direction = tank.GetDirection()tx, ty, tw, th = tank.GetRect()x, y, w, h = self.GetRect()if tx > x - tw and tx < x + w:if ty < y:# print("up")self._direction = wx.WXK_UPelse:# print("down")self._direction = wx.WXK_DOWNself._weapon.Fire()if ty > y - th and ty < y + h:if tx < x:# print("left")self._direction = wx.WXK_LEFTelse:# print("right")self._direction = wx.WXK_RIGHTself._weapon.Fire()class Mud(Obstacle):# 泥坑def __init__(self, x, y, path="wall_mud.png"):# 从文件加载 surfacetry:surface = cairo.ImageSurface.create_from_png(path)except IOError as e:print(e.message)super(Mud, self).__init__(x, y, surface)self._canCross = True # 可穿行self._canDestroy = False # 不可打破self._layer = -1 # 子弹可以在泥坑上层飞过self._canBulletCross = True # 子弹可穿行self._buff = True # 有特殊效果self._isRemote = True # 有远程作用self._radius = self._width * 1.5 # 作用半径def GetRadius(self):return self._radiusdef Act(self, tank=None):# 离开范围tx, ty, tw, th = tank.GetRect()x, y, w, h = self.GetRect()if tank.GetSpeed() == 1 and (tx < x - tw or tx > x + w or ty < y - th or ty > y + h):tank.ResetSpeed()def SecondAct(self, tank=None):# 进入范围if tank.GetSpeed() > 1:tank.SetSpeed(1)class Transmission(Obstacle):# 传送阵def __init__(self, x, y):surface = self.Draw()super(Transmission, self).__init__(x, y, surface)self._canCross = True # 可穿行self._canDestroy = False # 不可打破self._layer = -1 # 层级,0 和坦克同一层self._canBulletCross = True # 子弹可穿行self._buff = True # 没有特殊效果self._isRemote = True # 有远程作用self._radius = self._width * 1.5  # 作用半径self._waitTime = 3000 # 等待时间3秒self._dest = None # 传送目的法阵def GetRadius(self):return self._radiusdef Draw(self):# 画个六芒星surface = cairo.ImageSurface(cairo.FORMAT_RGB24, 48, 48)ctx = cairo.Context(surface)# 填充紫色底色ctx.set_source_rgb(0.27, 0.1, 0.47)ctx.paint()ctx.save()ctx.set_source_rgb(1, 1, 1)for i in range(2):if i == 1:# 对称翻转ctx.scale(1, -1)  # (x * dx, y * dy)ctx.translate(0, -48)  # 设置坐标轴原点# 画直角三角形ctx.move_to(0, 12)ctx.line_to(48, 12)ctx.line_to(24, 48)ctx.close_path()ctx.stroke()ctx.restore()# 紫色底不太明显,画四个角,标识下边缘ctx.set_source_rgb(0.6, 0.6, 0.6)for i in range(2):if i == 1:# 关于 x 轴对称ctx.scale(1, -1)ctx.translate(0, -48)for j in range(2):if j == 1:# 关于 y 轴对称ctx.scale(-1, 1)ctx.translate(-48, 0)ctx.move_to(0, 6)ctx.line_to(0, 0)ctx.line_to(6, 0)ctx.close_path()ctx.fill()return surfacedef Act(self, tank=None):# 离开范围,等待时间归零tx, ty, tw, th = tank.GetRect()x, y, w, h = self.GetRect()if tx < x - tw or tx > x + w or ty < y - th or ty > y + h:tank.SetTransTime(0)def SecondAct(self, tank=None):# 进入法阵范围# 新进入,设置进入时间if tank.GetTransTime() == 0:tank.SetTransTime(cv.times * cv.SPEED)# 符合时间,开始传送if tank.GetTransTime() + self._waitTime <= cv.times * cv.SPEED:tank.SetX(self._dest.GetX())tank.SetY(self._dest.GetY())tank.SetTransTime(0)def Bind(self, transmission):# 法阵双向绑定self._dest = transmissiontransmission.SetDest(self)def GetDest(self):return self._destdef SetDest(self, dest):self._dest = dest
# -*- coding: utf-8 -*-
# example3.pyimport random
import math
import wx
import wx.lib.wxcairo
import cairo
import board
from display import MovieClip
from tank import Player, Enemy
from weapon import Weapon, Bullet
from obstacle import *class cv(board.cv):"""常量,用类属性避免使用全局变量"""# 面板尺寸BOARD_WIDTH = 600BOARD_HEIGHT = 400class Board(board.Board):def DrawBackground(self, ctx):super().DrawBackground(ctx)text = "SmileBasic"ctx.set_font_size(40)_, _, w, h, _, _ = ctx.text_extents(text)x = (cv.BOARD_WIDTH - w) // 2y = (cv.BOARD_HEIGHT - h) // 2# 文字是以首个字左下角坐标定位,而矩形是以左上角定位,y轴相差文字的高度,不需要考虑线条宽度。# 另外PaintDC是不含标题栏的。ctx.rectangle(x - 10, y - 10 - h, w + 20, h + 20)ctx.set_source_rgb(1, 0, 0)ctx.stroke()ctx.move_to(x, y)ctx.set_source_rgb(1, 1, 1)ctx.show_text(text)def InitSceneObjects(self):super().InitSceneObjects()self.InitPlayer()self.InitObstacles()def InitPlayer(self):self.player = Player(60, 50) # 实例化一个玩家坦克self.sceneObjects.append(self.player)# 初始武器系统,并装弹self.bullets = []weapon = Weapon(capacity=100, speed=2)for i in range(50):bullet = Bullet(type=3) # 装载第4行子弹weapon.AddBullet(bullet)self.bullets.append(bullet)self.sceneObjects.append(bullet)bullet = Bullet(type=6) # 装载第7行子弹weapon.AddBullet(bullet)self.bullets.append(bullet)self.sceneObjects.append(bullet)self.player.LoadWeapon(weapon) # 玩家坦克加载武器系统def InitObstacles(self):self.obstacles = []# 生成4个砖墙brick1 = Brick(10, 50)brick2 = Brick(58, 98)brick3 = Brick(106, 98)brick4 = Brick(230, 220)# 生成1个草地grass = Grass(300, 50)# 生成1个水面water = Water(360, 50)# 生成1个冰面ice = Ice(230, 50)# 生成3个小铁块iron1 = Iron(230, 120)iron2 = Iron(254, 120)iron3 = Iron(254, 144)# 生成碉堡blockhouse = Blockhouse(10, 220)# 需要把碉堡子弹也加入对象列表进行绘制和碰撞检测self.bullets += blockhouse.GetWeapon().GetClip()self.sceneObjects += blockhouse.GetWeapon().GetClip()# 生成两个泥坑mud1 = Mud(290, 220)mud2 = Mud(338, 220)# 生成两个传送阵transmission1 = Transmission(390, 220)transmission2 = Transmission(500, 120)transmission1.Bind(transmission2)self.obstacles += [brick1, brick2, brick3, brick4, grass, water,ice, iron1, iron2, iron3, blockhouse, mud1, mud2, transmission1, transmission2]self.sceneObjects += [brick1, brick2, brick3, brick4, grass, water,ice, iron1, iron2, iron3, blockhouse, mud1, mud2, transmission1, transmission2]def DrawSceneObjects(self, ctx):# print("绘制", self.player.GetRect())# 后绘制的对象在上层显示for obstacle in self.obstacles:if obstacle.GetLayer() == -1:self.DrawSprite(ctx, obstacle)self.DrawSprite(ctx, self.player)for bullet in self.bullets:self.DrawSprite(ctx, bullet)for obstacle in self.obstacles:if obstacle.GetLayer() >= 0:self.DrawSprite(ctx, obstacle)def DrawSprite(self, ctx, sprite):ctx.set_source_surface(sprite.GetSurface(), sprite.GetX(), sprite.GetY())ctx.paint()def OnKeyDown(self, e):self.player.OnKeyDown(e)self.Refresh()def OnKeyUp(self, e):self.player.OnKeyUp(e)def CheckStrategies(self):self.CheckCollisions()def CheckCollisions(self):# 检测子弹砖墙碰撞# print("碰撞检测", self.player.GetRect())for obstacle in self.obstacles[:]:# 子弹可穿行,则跳过检测if obstacle.CanBulletCross():continuerect = obstacle.GetRect()for bullet in self.bullets[:]:if rect.Intersects(bullet.GetRect()):# 如果可摧毁,则碰撞后子弹和障碍都销毁if obstacle.CanDestroy():obstacle.Destroy()self.obstacles.remove(obstacle)self.sceneObjects.remove(obstacle)bullet.Destroy()self.bullets.remove(bullet)self.sceneObjects.remove(bullet)break# 检测坦克和砖墙碰撞,碰撞后坦克位置重置for obstacle in self.obstacles[:]:# 坦克可穿行并且没有特殊效果,则跳过检测if obstacle.CanCross() and not obstacle.HasBuff():continuerect = obstacle.GetRect()if obstacle.IsRemote():x, y, w, h = rectradius = obstacle.GetRadius()# 根据作用半径求出扩大范围后的矩形参数,因为是四方向,所以半径为一半边长x = x - (radius - w / 2)y = y - (radius - h / 2)width = height = radius * 2rect = wx.Rect(x, y, width, height)if rect.Intersects(self.player.GetRect()):# print("检测到碰撞", self.player.GetRect())# 如果有特殊效果则只不执行后续位置重置if obstacle.HasBuff():obstacle.Act(self.player)# 无远程作用障碍跳过if not obstacle.IsRemote():continue# 远程作用障碍判断障碍本身与坦克碰撞rect = obstacle.GetRect()if not rect.Intersects(self.player.GetRect()):continue# buff + 远程作用 + 能通行 + 本身碰撞,二次作用,泥坑定制if obstacle.CanCross():obstacle.SecondAct(self.player)continuedirection = self.player.GetDirection()x, y, w, h = rect_, _, pw, ph = self.player.GetRect()if direction == wx.WXK_UP:self.player.SetY(y + h)elif direction == wx.WXK_DOWN:self.player.SetY(y - ph)elif direction == wx.WXK_LEFT:self.player.SetX(x + w)elif direction == wx.WXK_RIGHT:self.player.SetX(x - pw)# print("碰撞重置为", self.player.GetRect())
# -*- coding: utf-8 -*-
# weapon.pyimport wx
import wx.lib.wxcairo
import cairo
from display import MovieClip
import boardclass cv(board.cv):"""常量,用类属性避免使用全局变量"""# 面板尺寸BOARD_WIDTH = 600BOARD_HEIGHT = 400class Weapon:def __init__(self, capacity=10, speed=20, interval=100):self._clip = [] # 弹夹self._capacity = capacity # 弹夹容量self._speed = speed # 发射出的子弹速度self._isFire = False # 开火状态self._tank = None # 被装载对象self._currentBullet = None # 当前要发射的子弹self._fireTime = -interval - 1 # 上次开火时间,首次开火时间必然满足self._fireInterval = interval # 默认开火间隔时间0.1秒def GetCapacity(self):return self._capacitydef GetSpeed(self):return self._speeddef GetBulletNum(self):return len(self._clip)def GetClip(self):return self._clipdef isFire(self):return self._isFiredef Loaded(self, tank):# 被装载self._tank = tankdef AddBullet(self, bullet):# 装弹并返回装弹结果if len(self._clip) < self._capacity:self._clip.append(bullet)return Trueelse:return Falsedef Fire(self, state=True):# 开火或停火self._isFire = state# 判断状态及开火间隔时间是否大于武器限定间隔时间if state and (self._fireTime + self._fireInterval) < cv.times * cv.SPEED and len(self._clip) > 0:# 记录开火时间self._fireTime = cv.times * cv.SPEEDself._currentBullet = self._clip.pop()# 根据坦克坐标和尺寸计算子弹起始位置direction = self._tank.GetDirection()x, y, w, h = self._tank.GetRect()_, _, bw, bh = self._currentBullet.GetRect()if direction == wx.WXK_UP:bx = x + w / 2 - bw / 2by = y - bhelif direction == wx.WXK_DOWN:bx = x + w / 2 - bw / 2by = y + helif direction == wx.WXK_LEFT:bx = x - bwby = y + h / 2 - bh / 2elif direction == wx.WXK_RIGHT:bx = x + wby = y + h / 2 - bh / 2# 设置子弹方向self._currentBullet.SetDirection(direction)# 设置发射初始坐标self._currentBullet.SetX(bx)self._currentBullet.SetY(by)# 设置子弹速度self._currentBullet.SetSpeed(self._speed)# 发射self._currentBullet.Fired()class Bullet(MovieClip):def __init__(self, x=-100, y=0, path="bullets.png", rect=(0, 0, 16, 16), fps=100, type=0):super(Bullet, self).__init__(x, y, path, rect, fps)self._speed = 0 # 子弹初始速度self._type = typeself._direction = Nonedef SetDirection(self, direction):self._direction = directiondef SetSpeed(self, speed):self._speed = speeddef Fired(self):# 尽量只用中心对称的子弹,避免换方向发射还要做旋转处理self.GotoAndPlay(0, self._type)def Fly(self):if not self._destroyed and self._speed > 0:if self._direction == wx.WXK_UP:self._y -= self._speedelif self._direction == wx.WXK_DOWN:self._y += self._speedelif self._direction == wx.WXK_LEFT:self._x -= self._speedelif self._direction == wx.WXK_RIGHT:self._x += self._speeddef Update(self, times, speed):self.Fly()super().Update(times, speed)
# -*- coding: utf-8 -*-
# tank.pyimport random
import wx
import wx.lib.wxcairo
import cairo
from display import MovieClip
import boardclass cv(board.cv):"""常量,用类属性避免使用全局变量"""# 面板尺寸BOARD_WIDTH = 600BOARD_HEIGHT = 400class Tank(MovieClip):def __init__(self, *args, **kwargs):super(Tank, self).__init__(*args, **kwargs)self._speed = 10 # 移动速度self._dx = 0 # x 轴方向self._dy = 0 # y 轴方向self._weapon = None # 武器self._originSpeed = 10 # 原始速度,用于恢复self._transTime = 0 # 等待法阵传送时间def Up(self):self._dy = -1self._dx = 0# 同一方向时需要需要排除,不然动画一直停留在第1帧if self._currentScene != 0:self.GotoAndPlay(0, 0)def Down(self):self._dy = 1self._dx = 0if self._currentScene != 1:self.GotoAndPlay(0, 1)def Left(self):self._dx = -1self._dy = 0if self._currentScene != 2:self.GotoAndPlay(0, 2)def Right(self):self._dx = 1self._dy = 0if self._currentScene != 3:self.GotoAndPlay(0, 3)def LoadWeapon(self, weapon):weapon.Loaded(self)self._weapon = weapondef GetWeapon(self):return self._weapondef GetSpeed(self):return self._speeddef SetSpeed(self, speed):self._speed = speeddef ResetSpeed(self):self._speed = self._originSpeeddef GetTransTime(self):return self._transTimedef SetTransTime(self, time):self._transTime = timeclass Player(Tank):def __init__(self, x, y, path="tank_T1_0.png", rect=(0, 0, 48, 48), fps=100):super(Player, self).__init__(x, y, path, rect, fps)self._direction = wx.WXK_UPdef OnKeyDown(self, e):key = e.GetKeyCode()if key == wx.WXK_UP:self.Up()self._direction = wx.WXK_UPif key == wx.WXK_DOWN:self.Down()self._direction = wx.WXK_DOWNif key == wx.WXK_LEFT:self.Left()self._direction = wx.WXK_LEFTif key == wx.WXK_RIGHT:self.Right()self._direction = wx.WXK_RIGHTself._x += self._dx * self._speedself._y += self._dy * self._speed# 开火if key == wx.WXK_SPACE and self._weapon:self._weapon.Fire(True)def OnKeyUp(self, e):key = e.GetKeyCode()if key == wx.WXK_UP or key == wx.WXK_DOWN:self._dy = 0if key == wx.WXK_LEFT or key == wx.WXK_RIGHT:self._dx = 0if self._dx == 0 and self._dy == 0:self.Stop()# 停火if key == wx.WXK_SPACE and self._weapon:self._weapon.Fire(False)def GetDirection(self):return self._directionclass Enemy(Tank):def __init__(self, x, y, path="tank_T1_0.png", rect=(0, 0, 48, 48), fps=100, mixColor=(0, 1, 1, 0.8)):self._mixColor = mixColor # 自定义混合颜色super(Enemy, self).__init__(x, y, path, rect, fps)# 初始随机方向self._direction = random.choice([wx.WXK_UP, wx.WXK_DOWN, wx.WXK_LEFT, wx.WXK_RIGHT])self._speed = 1self._originSpeed = 1self._isPlaying = Truedef LoadFrames(self, rect):# 将图像载为帧前,先改变图像的色相surface = cairo.ImageSurface.create_from_png("tank_T1_0.png")sw = surface.get_width()sh = surface.get_height()# 创建只显示坦克的 surface 作为混合层surface2 = cairo.ImageSurface(cairo.FORMAT_ARGB32, sw, sh)ctx = cairo.Context(surface2)ctx.set_source_rgba(*self._mixColor)ctx.mask_surface(surface)# 与目标图像混合ctx = cairo.Context(surface)ctx.set_source_surface(surface2)ctx.set_operator(cairo.Operator.HSL_HUE) # 将色相和目标图像色相混合ctx.paint()self._surface = surfacesuper().LoadFrames(rect)def GetDirection(self):return self._directiondef SetDirection(self, direction):self._direction = directiondef ChangeDirection(self, direction):# 方向转换为除指定方向以外的方向,总觉得这样写不太好 加个# TODOdirections = [wx.WXK_UP, wx.WXK_DOWN, wx.WXK_LEFT, wx.WXK_RIGHT]directions.remove(direction)self._direction = random.choice(directions)def AutoWalk(self):if self._direction == wx.WXK_UP:self.Up()elif self._direction == wx.WXK_DOWN:self.Down()elif self._direction == wx.WXK_LEFT:self.Left()elif self._direction == wx.WXK_RIGHT:self.Right()# 遇边界转向,坦克宽高明明是48,可是按48处理显示不对# TODOif self._x < 0:self._x = 0self.ChangeDirection(wx.WXK_LEFT)elif self._x > cv.BOARD_WIDTH - 68:self._x = cv.BOARD_WIDTH - 68self.ChangeDirection(wx.WXK_RIGHT)else:self._x += self._dx * self._speedif self._y < 0:self._y = 0self.ChangeDirection(wx.WXK_UP)elif self._y > cv.BOARD_HEIGHT - 96:self._y = cv.BOARD_HEIGHT - 96self.ChangeDirection(wx.WXK_DOWN)else:self._y += self._dy * self._speeddef Update(self, times, speed):# 由主程序刷新时更新self.AutoWalk()super().Update(times, speed)

wxPython和pycairo练习记录7相关推荐

  1. 2020年数据术语的故事

    点击上方蓝色字体,选择"设为星标" 回复"资源"获取更多资源 2020年整个技术圈子要说话题最多的,应该是大数据方向.新感念层出不穷,数据湖概念就是其中之一.这 ...

  2. 【问题记录】python的py文件生成exe可执行程序闪退

    今天想弄一下这个,记录一下过程: 1. pip install pyinstaller -i https://pypi.tuna.tsinghua.edu.cn/simple pyinstaller ...

  3. wxPython:Python首选的GUI库 | CSDN博文精选

    作者 | 天元浪子 来源 | CSDN博客 文章目录 概述 窗口程序的基本框架 事件和事件驱动 菜单栏/工具栏/状态栏 动态布局 AUI布局 DC绘图 定时器和线程 后记 概述 跨平台的GUI工具库, ...

  4. AI:基于计算机视觉和语音识别案例项目打包过程记录20181226-19

    AI:基于计算机视觉和语音识别案例项目打包过程记录20181226-19 基于计算机视觉和语音识别案例项目打包过程 521 INFO: PyInstaller: 3.3.1 521 INFO: Pyt ...

  5. wxpython开发的软件_Python GUI开发环境的搭建(wxPython)

    最近对Python的开发又来了兴趣,对于Python的开发一直停留在一个表面层的认识. Python的入手简单,语法让人爱不释手,在网络通信方面自带有成熟的类库,还有第三方开发的开源包. 在GUI的开 ...

  6. python wxpython radiobutton 能不能默认不选择_Python啥都行_Robot自动化测试

    文章目录 Robot介绍与环境搭建 Robot特性初探 Robot 技术架构 WxPython GUI工具箱 Robot Framework+RIDE安装 第一个案例 启动RIDE 自定义一个函数 新 ...

  7. wxpython使用简介_wxpython简介

    Python ​ Python是一种成功的脚本语言,它最初是由Guido van Rossum开发的.它于1991年首次发布.Python的灵感来自于ABC和Haskell编程语言.Python是一种 ...

  8. wxpython如何分开界面和运行代码_如何调试wxPython Demon源代码及几个细节

    在调试demon代码时,常会碰到一些模块无法导入的情况,这是因为好多模块不是Python的标准库, 而是demon安装目录下的库文件,所以学习demon源码的时候,要把这些库copy到同一个目录下, ...

  9. python安装wxpython库_wxPython:python 首选的 GUI 库

    原标题:wxPython:python 首选的 GUI 库 作者:许向武 blog.csdn.net/xufive/article/details/82665460 概述 跨平台的GUI工具库,较为有 ...

最新文章

  1. 初级java开发学习路线_成为初级全栈Web开发人员的10分钟路线图
  2. 笔试算法题(58):二分查找树性能分析(Binary Search Tree Performance Analysis)
  3. html网页怎么向文章,一篇文章教你学会HTML
  4. andorid 第一天 搭建环境(于本博另一篇文章 ubuntu下安装andoird SDK相同内容)
  5. python获取app信息的库_基于python3抓取pinpoint应用信息入库
  6. Veeam ONE v10.0.2.1094 安装教程+许可证
  7. 《JAVA与模式》— 原型模式
  8. Robocode:下载安装及迁移至IntelliJ
  9. win10u盘被写保护怎么解除_如何去掉写保护?tf磁盘被写保护?win10如何去掉写保护?【U盘写保护怎么去掉?】Microsoft Windows...
  10. 大数据时代网络安全问题分析
  11. 2021年焊工(初级)考试报名及焊工(初级)实操考试视频
  12. 联想笔记本电脑重装系统按F几
  13. 貌似高大上,实则黑中介
  14. 计算机科学主题 一亩三分地 每日答题 题库
  15. 已经解决globalsign证书导致淘宝京东等chrome safari无法访问
  16. Lists.partition用法
  17. [回顾]清华申请退学博士作品:完全用Linux工作
  18. 多机房UPS及环境集中监控方案丨UPS环境综合监控主机
  19. xp php mysql_WindowsXP+IIS+PHP5+MySQL5+Zend+GD库+phpMyAdmin+PHPW
  20. 我的Linux学习之路(纯小白)

热门文章

  1. [转]《设计模式》python实现
  2. 博士申请 | 新加坡管理大学庞观松助理教授招收机器学习方向全奖博士生
  3. UE4(虚幻4)基础:编辑样条曲线实现道路
  4. 北交大研究生计算机专硕好考么,北京交通大学考研难度 北交的研究生好考吗...
  5. dota缴械技能增强
  6. 今年5号台风在福建登陆
  7. html实现魔方相册,css实现魔方动画特效
  8. ActiveReports 报表控件 初体验
  9. 我们为基金做一次京东配送
  10. 我的第一个响应式网站zz