网站免费建站 图标,个人网站怎么做 简历,中国电商建站程序,网页设计模板免费网站我正在博客之星评选#xff0c;欢迎投票给我 会从投票人中抽奖机械键盘书#xff0c;中了会私聊地址
投票连接是#xff1a;https://bbs.csdn.net/topics/603955346 投票连接是#xff1a;https://bbs.csdn.net/topics/603955346 投票连接是#xff1a;https://bbs.csdn.…我正在博客之星评选欢迎投票给我 会从投票人中抽奖机械键盘书中了会私聊地址
投票连接是https://bbs.csdn.net/topics/603955346 投票连接是https://bbs.csdn.net/topics/603955346 投票连接是https://bbs.csdn.net/topics/603955346 非常感谢给个五星好评拉到页面最下面就可以打分了
底部有完整代码想试验的可以去看一下。 然后推一下我一篇文章《外国人最喜欢吃的中国美食是酱油python数据分析》 想要素材看评论区
突然来的兴趣
这个坦克大战是基于 pygame 的由于没有完整的学过 pygame之前一直以为 pygame 对于长按键不支持监听就在几天前我竟然发现了可以然后就打开了我的世界大门。
由于这个辅助类我随便写了几个小时还有很多问题咱们先慢慢来先做个坦克大战好了。
这是演示效果
目前这辅助类的功能有
使用这个辅助类只需要配置信息自己创建对应对象主角只需要创建后就可以自动可以移动敌人也可以自己随机“AI”进行移动并且子弹自动触碰敌人和墙壁会互相“销毁”完成射击效果。 我们先来看如何使用这辅助类。
使用示例 坦克大战
首先创建一个地图
map_srpirte[[-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-],[-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-],[-,-,-,-,-,-,-,-,w,w,w,w,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-],[-,-,-,-,-,-,-,-,-,w,w,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-],[-,-,-,-,-,-,-,-,-,w,w,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-],[-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-],[-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-],[-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-],[-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-],[-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-],[-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-],[-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-],[-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-],[-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-],[-,-,-,-,-,-,-,-,w,w,w,w,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-],[-,-,-,-,-,-,-,-,-,w,w,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-],[-,-,-,-,-,-,-,-,-,w,w,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-],[-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-],[-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-],[-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-],[-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-],[-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-],[-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-],[-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-],]用个list就是可以了w就是障碍物简单吧 接下来设置地图配置
mapConf{space:-,w:./tank/scene/brick.png,height:12,weight:20
}space表示空间w表示障碍物的精灵图宽高为精灵图大小。 接下来写下宽高内容
screenWmapConf[weight]*34
screenHmapConf[height]*48接下来创建组设置屏幕
pygame.init()
screen pygame.display.set_mode((screenW,screenH))
group_wallt pygame.sprite.Group()
pygame.key.set_repeat(10)
framerate pygame.time.Clock()
group_hero pygame.sprite.Group()
enemy_hero pygame.sprite.Group()接下来使用我们的自己写的辅助类 ESprite
sprite_hero ESprite(screen,group_hero)接着设置图片与设置组
sprite_hero.load(./tank/playerTank/tank_T1_2.png,48, 48, 4, 2)
up./tank/bullet/bullet_up.png
down./tank/bullet/bullet_down.png
left./tank/bullet/bullet_left.png
right./tank/bullet/bullet_right.png
group_hero.add(sprite_hero)使用我们自己写的敌人类循环创建敌人
enemy_list[]
for v in range(0,20):enemy Enemy(screen,enemy_hero)enemy.load(./tank/enemyTank/enemy_1_0.png,48, 48, 4, 2)enemy_hero.add(enemy)enemy_list.append(enemy)接下来使用自己写的精灵类创建不可触碰体并且把这个对象添加到主角、敌人不可触碰体设置之中
posx,posy0,0
wallet[]
for rows in map_srpirte:for v in rows:posx24if v!mapConf[space]:sprite_wallt ESprite(screen,group_wallt)sprite_wallt.load(mapConf[w],24, 24, 1, 1,posx,posy)group_wallt.add(sprite_wallt)sprite_hero.setCollision(sprite_wallt)#添加不可触碰enemy.setCollision(sprite_wallt)#添加不可触碰print(str(posx),str(posy))posy24posx0最后开启主循环进行监听、刷新即可
#主循环
while True:print((screenW,screenH))framerate.tick(30)ticks pygame.time.get_ticks()for event in pygame.event.get():if event.type pygame.QUIT:pygame.quit()exit()elif event.typepygame.KEYDOWN:print(key down ......)sprite_hero.control.moveControl(event)pos{up_x:18,up_y:-10,down_x:18,down_y:50,left_x:-6,left_y:16,right_x:50,right_y:18,}sprite_hero.shoot(up,down,left,right,12,12,1,1,pos,ticks,enemy_list)screen.fill((0,0,100))group_hero.update(ticks)group_hero.draw(screen)enemy_hero.update(ticks)enemy_hero.draw(screen)group_wallt.update(ticks)group_wallt.draw(screen)for v in enemy_list:v.autoMove((screenW,screenH))pygame.display.update()一、写个精灵类
1.1 初始化
首先创建一个python 文件名为 Etank.py并在如下引入依赖
import pygame,random
from pygame.locals import *pygame 、 random 是所需库pygame.locals import * 主要是用来找到KEY。
接下来创建一个类名为 ESprite 继承于pygame 的Sprite 基类
class ESprite(pygame.sprite.Sprite):在 ESprite 中给到一个 init 方法
def __init__(self,screen,groupNone):其中 screen 是需要进行屏幕刷新的屏幕对象group 是当前类实例化后所对应的组。
接下来在 init 中调用父类初始化
pygame.sprite.Sprite.__init__(self)接下来在 init 方法中初始化一些内容
def __init__(self,screen,groupNone):#target是屏幕pygame.sprite.Sprite.__init__(self)#self.target_surface target#精灵渲染目标为屏幕self.screenscreenself.image None#初始化图片Noneself.main_image None#主图片self.rect None#需要画图的区域self.rframe 0 #图片序列号 行self.cframe 0 #图片序列号 列self.old_frame -1#老图片序列号self.frame_width 1#图片宽self.frame_height 1#图片高self.cols 1 #列self.rows 1 #行self.last_time 0 #上次更换时的总帧数用于判断更换帧self.X0self.Y0self.speedX1self.speedY1self.controlSpriteController(self)#控制初始化self.groupgroupself.shootobj[]self.upImg,self.downImg,self.leftImg,self.rightImgNone,None,None,Noneself.collisions[]self.enemy_list[]这些初始化后的该类属性之后将会在方法中用到咱们用到时再做说明。
1.2 添加不可碰撞体
在游戏中有很多的不可碰撞体例如墙壁、障碍物、这些内容对于可活动的游戏觉得是有障碍的在这里设置一个方法为当前的精灵设置一个不可碰撞体
#添加不可触碰体
def setCollision(self,collision):self.collisions.append(collision)1.3加载主图方法
在2d游戏中每一个98%的角色都是需要图片给予对象视觉呈现此时写一个方法 load 用于加载当前主图内容
#加载用
def load(self, filename, width, height,rows,cols,posx100,posy100):self.main_image pygame.image.load(filename).convert_alpha()#加载主图self.frame_width width#宽高记录self.frame_height heightself.rect [posx,posy,width,height]#绘制self.cols colsself.rows rows该方法的参数说明如下
filename 图片路径width 每个图片宽height 每个图片高rows 行cols 列posx 主图起始绘制位置xposy 主图起始绘制位置y
在以上方法中通过 filename 加载主图通过宽高选择主图所绘制的区域图片示例如下 宽高指的是图片大小的宽高posx 和 posy 指图片左上角形成的坐标轴的位置例如图片大小是4848总长度是宽 482 长是 48*8那就是8行2列内容那么 8 就是 rows 2就是参数 colsposx 和 posy 就是左上角0和0。
1.5刷新方法
加载图片后还需要刷新内容创建一个方法 update接收两个参数一个是 current_time 是当前帧数rate 为刷新时的帧值。
#每次图片动态更新绘制区域 动画播放
def update(self, current_time, rate60):#当前帧总数如果已经超过了最初的 last_time 60那么表示#已经超过了60帧那么 frame 图片序列号1开始下一张图片if current_time self.last_time rate:self.rframe 1 #图片序列号1 if self.rframeself.cols-1:#大于图片最大列就说明进行了一个循环因为 self.frame 初始值是 0self.rframe0self.last_time current_time#每次更改图片时就记录更换后的帧if self.rframe ! self.old_frame:#新老次序不一 表示更换frame#frame_x绘制矩形的位置x就等于图片数*每个宽度得到x坐标值frame_xself.rframe * self.frame_widthframe_yself.cframe * self.frame_height#y值跟随上下左右按键切换图图片规定同一行一个动作# 不同按键对应上下左右# 绘制的区域使用 frame_width frame_height 代替rect ( frame_x, frame_y, self.frame_width, self.frame_height )self.image self.main_image.subsurface(rect)#选择区域进行图片提取self.old_frame self.rframe以上代码中 if current_time self.last_time rate: 表示当前帧是否大于最后一次更换帧数60大于则需要刷新那么则 self.rframe 1 图片序列号1 表示更换图片 但是不能大于本身图片序列的行和列 if self.rframeself.cols-1大于则将 self.rframe0 。
接着就替换一下 self.last_time current_time 为最后一次的更换帧数接下来则替换显示图片的坐标值也就是 rect 值
if self.rframe ! self.old_frame:#新老次序不一 表示更换frame#frame_x绘制矩形的位置x就等于图片数*每个宽度得到x坐标值frame_xself.rframe * self.frame_widthframe_yself.cframe * self.frame_height#y值跟随上下左右按键切换图图片规定同一行一个动作# 不同按键对应上下左右# 绘制的区域使用 frame_width frame_height 代替rect ( frame_x, frame_y, self.frame_width, self.frame_height )self.image self.main_image.subsurface(rect)#选择区域进行图片提取self.old_frame self.rframe1.6 #创建发射对象
子弹上下左右的主图不一样朝向不一如图所示 此时编写一个方法 shoot
def shoot(self,upImg,downImg,leftImg,rightImg,width,height,rows,cols,pos,ticksNone,enemy_list[]):self.enemy_listenemy_listif self.control.isShootTrue:#创建发射物shootobjESprite(self.screen)self.group.add(shootobj)posx,posy0,0sprite_imgif self.control.shoot_directionself.control.direction_UP:posxself.rect[0]pos[up_x]posyself.rect[1]pos[up_y]sprite_imgupImgelif self.control.shoot_directionself.control.direction_DOWN:posxself.rect[0]pos[down_x]posyself.rect[1]pos[down_y]sprite_imgdownImgelif self.control.shoot_directionself.control.direction_LEFT:posxself.rect[0]pos[left_x]posyself.rect[1]pos[left_y]sprite_imgleftImgelif self.control.shoot_directionself.control.direction_RIGHT:posxself.rect[0]pos[right_x]posyself.rect[1]pos[right_y]sprite_imgrightImgshootobj.load(sprite_img, width, height, rows, cols,posxposx,posyposy)self.shootobj.append({obj:shootobj,shoot_direction:self.control.shoot_direction}) print(SHOOT!!!!!!!!!!...)#print(self.shootobj.rect)print(len(self.shootobj))#加组后一定要刷新不然会读不到 surface.image 也就是没有在页面之上self.group.update(ticks)self.group.draw(self.screen)#数组中已经创建的继续移动for s in self.shootobj:if s[obj]!None:SPEEDXself.control.shoot_SPEEDXSPEEDYself.control.shoot_SPEEDYif s[shoot_direction]self.control.direction_UP:print(direction_UP...)SPEEDX0SPEEDY-SPEEDYelif s[shoot_direction]self.control.direction_DOWN:print(direction_DOWN...)SPEEDX0SPEEDYSPEEDYelif s[shoot_direction]self.control.direction_LEFT:print(direction_LEFT...)SPEEDX-SPEEDXSPEEDY0elif s[shoot_direction]self.control.direction_RIGHT:print(direction_RIGHT...)SPEEDXSPEEDXSPEEDY0s[obj].rects[obj].rect[0]SPEEDX,s[obj].rect[1]SPEEDY,s[obj].frame_width,s[obj].frame_heightif self.collisions![]:for index, v in enumerate(self.collisions):if s[obj]!None:if pygame.sprite.collide_mask(s[obj],v):s[obj].rect-1000,-1000,s[obj].frame_width,s[obj].frame_heights[obj].kill()self.collisions[index].rect-1000,-1000,self.collisions[index].rect[2],self.collisions[index].rect[3]self.collisions[index].kill()#s[obj]False#s[obj]Noneif self.enemy_list![]:for index, v in enumerate(self.enemy_list):if s[obj]!None:if pygame.sprite.collide_mask(s[obj],v):s[obj].rect-1000,-1000,s[obj].frame_width,s[obj].frame_heights[obj].kill()self.enemy_list[index].rect-1000,-1000,self.enemy_list[index].rect[2],self.enemy_list[index].rect[3]self.enemy_list[index].kill()以上方法中参数 upImg,downImg,leftImg,rightImg 为上下左右子弹的图片width,height,rows,cols,pos,ticksNone,enemy_list[] 一次是宽高行列和ticks 刷新帧enemy_list 敌人。
因为之后还需要检测敌人碰撞后销毁。
在该函数中第一行打码是 self.enemy_listenemy_list 表示设置当前的敌人列表。 接着 if self.control.isShootTrue: 这个判断表示是否按发射键之后会在控制中进行讲解 按下发射键后就开始创建发射对象同样这个对象是ESprite 对象
#创建发射物
shootobjESprite(self.screen)
self.group.add(shootobj)
posx,posy0,0
sprite_img接下来判断此时朝向根据之后会有一个控制方法检测朝向不同朝向的方位创建不同朝向的子弹
if self.control.shoot_directionself.control.direction_UP:posxself.rect[0]pos[up_x]posyself.rect[1]pos[up_y]sprite_imgupImg
elif self.control.shoot_directionself.control.direction_DOWN:posxself.rect[0]pos[down_x]posyself.rect[1]pos[down_y]sprite_imgdownImg
elif self.control.shoot_directionself.control.direction_LEFT:posxself.rect[0]pos[left_x]posyself.rect[1]pos[left_y]sprite_imgleftImg
elif self.control.shoot_directionself.control.direction_RIGHT:posxself.rect[0]pos[right_x]posyself.rect[1]pos[right_y]sprite_imgrightImg接着加载图片并且记录方向如果不记录方向之后使用同一个方法时将会与自身按键操作重合会意外的控制子弹前进路线
shootobj.load(sprite_img, width, height, rows, cols,posxposx,posyposy)
self.shootobj.append({obj:shootobj,shoot_direction:self.control.shoot_direction}) 接下来开始检测碰撞检测碰撞前需要在屏幕刷新当前的sprite因为检测膨胀是需要判断该精灵是否在屏幕之上
self.group.update(ticks)
self.group.draw(self.screen)加下来创建一个循环
#数组中已经创建的继续移动
for s in self.shootobj:if s[obj]!None:这个循环遍历子弹是否与某些物体发生碰撞并且进行位置移动。首先编写位置移动的内容
SPEEDXself.control.shoot_SPEEDX
SPEEDYself.control.shoot_SPEEDY
if s[shoot_direction]self.control.direction_UP:print(direction_UP...)SPEEDX0SPEEDY-SPEEDY
elif s[shoot_direction]self.control.direction_DOWN:print(direction_DOWN...)SPEEDX0SPEEDYSPEEDY
elif s[shoot_direction]self.control.direction_LEFT:print(direction_LEFT...)SPEEDX-SPEEDXSPEEDY0
elif s[shoot_direction]self.control.direction_RIGHT:print(direction_RIGHT...)SPEEDXSPEEDXSPEEDY0
s[obj].rects[obj].rect[0]SPEEDX,s[obj].rect[1]SPEEDY,s[obj].frame_width,s[obj].frame_height判断刚刚所记录的方向给予不同位置移动的坐标。 接着判断是否发生碰撞
if self.collisions![]:for index, v in enumerate(self.collisions):if s[obj]!None:if pygame.sprite.collide_mask(s[obj],v):s[obj].rect-1000,-1000,s[obj].frame_width,s[obj].frame_heights[obj].kill()self.collisions[index].rect-1000,-1000,self.collisions[index].rect[2],self.collisions[index].rect[3]self.collisions[index].kill()只要设置了 collisions 阻碍物那么就遍历阻碍物是否与子弹发生碰撞如果发生膨胀首先将该物体移动到屏幕之外调用 kill() 方法对其进行销毁。这样就实现了子弹设计到物体物体和子弹都同时消失。
最后判断子弹和敌人是否发生碰撞遍历敌人
if self.enemy_list![]:
for index, v in enumerate(self.enemy_list):if s[obj]!None:if pygame.sprite.collide_mask(s[obj],v):s[obj].rect-1000,-1000,s[obj].frame_width,s[obj].frame_heights[obj].kill()self.enemy_list[index].rect-1000,-1000,self.enemy_list[index].rect[2],self.enemy_list[index].rect[3]self.enemy_list[index].kill()实现方法与墙体类似。 最后在遍历之外加一个设计关闭即可因为按一次就发射一个子弹
self.control.isShootFalse#创建完一个后又关闭二、写个精灵控制类
首先创建一个精灵控制类和初始化方法
#精灵控制类
class SpriteController():def __init__(self,sprite): self.spritespriteself.directionNoneself.shoot_direction1self.direction_UP1self.direction_DOWN2self.direction_LEFT3self.direction_RIGHT4self.shoot_SPEEDX10self.shoot_SPEEDY10self.isShootFalse接着编写精灵控制响应的方法
#移动控制
def moveControl(self,event):stepXself.sprite.speedXstepYself.sprite.speedY#if self.isShoot!True:if event.key pygame.K_RIGHT:stepY0stepXstepXself.sprite.cframe3self.shoot_direction4elif event.key pygame.K_LEFT:stepX-stepXstepY0self.sprite.cframe2self.shoot_direction3elif event.key pygame.K_UP:stepY-stepYstepX0self.sprite.cframe0self.shoot_direction1elif event.key pygame.K_DOWN:stepYstepYstepX0self.sprite.cframe1self.shoot_direction2elif event.key pygame.K_SPACE:self.isShootTrue stepX,stepY0,0 self.sprite.rectself.sprite.rect[0]stepX,self.sprite.rect[1]stepY,self.sprite.frame_width,self.sprite.frame_heightif self.sprite.collisions![]:for v in self.sprite.collisions:result pygame.sprite.collide_mask(self.sprite,v)while result:#bug 墙壁反弹错位unstepX,unstepYstepX,stepYif unstepX!0:if unstepX0:unstepX10else:unstepX-10if unstepY!0:if unstepY0:unstepY10else:unstepY-10result pygame.sprite.collide_mask(self.sprite,v)#for vi in range(0,20):self.sprite.rectself.sprite.rect[0]-stepX,self.sprite.rect[1]-stepY,self.sprite.frame_width,self.sprite.frame_heightprint (Collision occurred)moveControl 方法接收1个参数event判断按下键的内容根据不同按键响应不同的移动参数其他内容都是基础内容主要是对于阻碍物的阻碍效果
if self.sprite.collisions![]:for v in self.sprite.collisions:result pygame.sprite.collide_mask(self.sprite,v)while result:#bug 墙壁反弹错位unstepX,unstepYstepX,stepYif unstepX!0:if unstepX0:unstepX10else:unstepX-10if unstepY!0:if unstepY0:unstepY10else:unstepY-10result pygame.sprite.collide_mask(self.sprite,v)#for vi in range(0,20):self.sprite.rectself.sprite.rect[0]-stepX,self.sprite.rect[1]-stepY,self.sprite.frame_width,self.sprite.frame_heightprint (Collision occurred)遍历后如果发生碰撞直接给予回退
self.sprite.rectself.sprite.rect[0]-stepX,self.sprite.rect[1]-stepY,self.sprite.frame_width,self.sprite.frame_height三、敌人AI类
敌人类属于 ESprite 类首先创建一个类及初始化方法
#敌人
class Enemy(ESprite):def __init__(self, screen, groupNone):super().__init__(screen, groupgroup)self.screenscreenself.groupgroup#self.AIControlSpriteController()self.movieStep0self.stepY,self.stepX0,10movieStep 为默认自动运行次数self.stepY,self.stepX0,10 为默认行走值。
接下来编写自动运行方法
def autoMove(self,Size):self.group.update(ticks)self.group.draw(self.screen)if self.movieStep0:random.seed(random.randint(0,100))drandom.randint(1,16)if d0 and d5:#上self.stepY-10self.stepX0elif d4 and d9:#下self.stepY10self.stepX0elif d8 and d13:#左self.stepX-10self.stepY0elif d12 and d17:#右self.stepX10self.stepY0self.movieStep20if self.movieStep!0:if (self.rect[0],self.rect[1])(60,60) and (self.rect[0],self.rect[1]) (Size[0]-60,Size[1]-60):self.rectself.rect[0]self.stepX,self.rect[1]self.stepY,self.frame_width,self.frame_heightself.movieStep-1if self.collisions![]:for v in self.collisions:#self.group.update(ticks)#self.group.draw(self.screen)result pygame.sprite.collide_mask(self,v)while result:#bug 墙壁反弹错位unstepX,unstepYself.stepX,self.stepYif unstepX!0:if unstepX0:unstepX10else:unstepX-10if unstepY!0:if unstepY0:unstepY10else:unstepY-10result pygame.sprite.collide_mask(self,v)#for vi in range(0,20):self.rectself.rect[0]-self.stepX,self.rect[1]-self.stepY,self.frame_width,self.frame_heightprint (Collision occurred)以上代码中以下代码表示该AI随机上下左右
if self.movieStep0:random.seed(random.randint(0,100))drandom.randint(1,16)if d0 and d5:#上self.stepY-10self.stepX0elif d4 and d9:#下self.stepY10self.stepX0elif d8 and d13:#左self.stepX-10self.stepY0elif d12 and d17:#右self.stepX10self.stepY0self.movieStep20
if self.movieStep!0:if (self.rect[0],self.rect[1])(60,60) and (self.rect[0],self.rect[1]) (Size[0]-60,Size[1]-60):self.rectself.rect[0]self.stepX,self.rect[1]self.stepY,self.frame_width,self.frame_heightself.movieStep-1不同方向他有不同值对应self.movieStep运行次数为0则重新置于20若不等于0则自动运行只需要设置对应的 rect 即可。
接着就是判断是否碰到障碍物实现与控制方法一致
if self.collisions![]:for v in self.collisions:#self.group.update(ticks)#self.group.draw(self.screen)result pygame.sprite.collide_mask(self,v)while result:#bug 墙壁反弹错位unstepX,unstepYself.stepX,self.stepYif unstepX!0:if unstepX0:unstepX10else:unstepX-10if unstepY!0:if unstepY0:unstepY10else:unstepY-10result pygame.sprite.collide_mask(self,v)#for vi in range(0,20):self.rectself.rect[0]-self.stepX,self.rect[1]-self.stepY,self.frame_width,self.frame_heightprint (Collision occurred)完整代码
import pygame,random
from pygame.locals import *class MySprite(pygame.sprite.Sprite):def __init__(self,screen,groupNone):#target是屏幕pygame.sprite.Sprite.__init__(self)#self.target_surface target#精灵渲染目标为屏幕self.screenscreenself.image None#初始化图片Noneself.main_image None#主图片self.rect None#需要画图的区域self.rframe 0 #图片序列号 行self.cframe 0 #图片序列号 列self.old_frame -1#老图片序列号self.frame_width 1#图片宽self.frame_height 1#图片高self.cols 1 #列self.rows 1 #行self.last_time 0 #上次更换时的总帧数用于判断更换帧self.X0self.Y0self.speedX1self.speedY1self.controlSpriteController(self)#控制初始化self.groupgroupself.shootobj[]self.upImg,self.downImg,self.leftImg,self.rightImgNone,None,None,Noneself.collisions[]self.enemy_list[]#添加不可触碰体def setCollision(self,collision):self.collisions.append(collision)#加载用def load(self, filename, width, height,rows,cols,posx100,posy100):self.main_image pygame.image.load(filename).convert_alpha()#加载主图self.frame_width width#宽高记录self.frame_height heightself.rect [posx,posy,width,height]#绘制self.cols colsself.rows rows#每次图片动态更新绘制区域 动画播放def update(self, current_time, rate60):#当前帧总数如果已经超过了最初的 last_time 60那么表示#已经超过了60帧那么 frame 图片序列号1开始下一张图片if current_time self.last_time rate:self.rframe 1 #图片序列号1 if self.rframeself.cols-1:#大于图片最大列就说明进行了一个循环因为 self.frame 初始值是 0self.rframe0self.last_time current_time#每次更改图片时就记录更换后的帧if self.rframe ! self.old_frame:#新老次序不一 表示更换frame#frame_x绘制矩形的位置x就等于图片数*每个宽度得到x坐标值frame_xself.rframe * self.frame_widthframe_yself.cframe * self.frame_height#y值跟随上下左右按键切换图图片规定同一行一个动作# 不同按键对应上下左右# 绘制的区域使用 frame_width frame_height 代替rect ( frame_x, frame_y, self.frame_width, self.frame_height )self.image self.main_image.subsurface(rect)#选择区域进行图片提取self.old_frame self.rframe#设置上下左右发射对象def setShootSprite(self,up,down,left,right,width,height,rows,cols):self.upImgupself.downImgdownself.leftImgleftself.rightImgrightself.swidthwidthself.sheightheightself.srowsrowsself.scolscols#创建发射对象def shoot(self,upImg,downImg,leftImg,rightImg,width,height,rows,cols,pos,ticksNone,enemy_list[]):self.enemy_listenemy_listif self.control.isShootTrue:#创建发射物shootobjMySprite(self.screen)self.group.add(shootobj)posx,posy0,0sprite_imgif self.control.shoot_directionself.control.direction_UP:posxself.rect[0]pos[up_x]posyself.rect[1]pos[up_y]sprite_imgupImgelif self.control.shoot_directionself.control.direction_DOWN:posxself.rect[0]pos[down_x]posyself.rect[1]pos[down_y]sprite_imgdownImgelif self.control.shoot_directionself.control.direction_LEFT:posxself.rect[0]pos[left_x]posyself.rect[1]pos[left_y]sprite_imgleftImgelif self.control.shoot_directionself.control.direction_RIGHT:posxself.rect[0]pos[right_x]posyself.rect[1]pos[right_y]sprite_imgrightImgshootobj.load(sprite_img, width, height, rows, cols,posxposx,posyposy)self.shootobj.append({obj:shootobj,shoot_direction:self.control.shoot_direction}) print(SHOOT!!!!!!!!!!...)#print(self.shootobj.rect)print(len(self.shootobj))#加组后一定要刷新不然会读不到 surface.image 也就是没有在页面之上self.group.update(ticks)self.group.draw(self.screen)#数组中已经创建的继续移动for s in self.shootobj:if s[obj]!None:SPEEDXself.control.shoot_SPEEDXSPEEDYself.control.shoot_SPEEDYif s[shoot_direction]self.control.direction_UP:print(direction_UP...)SPEEDX0SPEEDY-SPEEDYelif s[shoot_direction]self.control.direction_DOWN:print(direction_DOWN...)SPEEDX0SPEEDYSPEEDYelif s[shoot_direction]self.control.direction_LEFT:print(direction_LEFT...)SPEEDX-SPEEDXSPEEDY0elif s[shoot_direction]self.control.direction_RIGHT:print(direction_RIGHT...)SPEEDXSPEEDXSPEEDY0s[obj].rects[obj].rect[0]SPEEDX,s[obj].rect[1]SPEEDY,s[obj].frame_width,s[obj].frame_heightif self.collisions![]:for index, v in enumerate(self.collisions):if s[obj]!None:if pygame.sprite.collide_mask(s[obj],v):s[obj].rect-1000,-1000,s[obj].frame_width,s[obj].frame_heights[obj].kill()self.collisions[index].rect-1000,-1000,self.collisions[index].rect[2],self.collisions[index].rect[3]self.collisions[index].kill()#s[obj]False#s[obj]Noneif self.enemy_list![]:for index, v in enumerate(self.enemy_list):if s[obj]!None:if pygame.sprite.collide_mask(s[obj],v):s[obj].rect-1000,-1000,s[obj].frame_width,s[obj].frame_heights[obj].kill()self.enemy_list[index].rect-1000,-1000,self.enemy_list[index].rect[2],self.enemy_list[index].rect[3]self.enemy_list[index].kill()self.control.isShootFalse#创建完一个后又关闭#精灵控制类
class SpriteController():def __init__(self,sprite): self.spritespriteself.directionNoneself.shoot_direction1self.direction_UP1self.direction_DOWN2self.direction_LEFT3self.direction_RIGHT4self.shoot_SPEEDX10self.shoot_SPEEDY10self.isShootFalse#移动控制def moveControl(self,event):stepXself.sprite.speedXstepYself.sprite.speedY#if self.isShoot!True:if event.key pygame.K_RIGHT:stepY0stepXstepXself.sprite.cframe3self.shoot_direction4elif event.key pygame.K_LEFT:stepX-stepXstepY0self.sprite.cframe2self.shoot_direction3elif event.key pygame.K_UP:stepY-stepYstepX0self.sprite.cframe0self.shoot_direction1elif event.key pygame.K_DOWN:stepYstepYstepX0self.sprite.cframe1self.shoot_direction2elif event.key pygame.K_SPACE:self.isShootTrue stepX,stepY0,0 self.sprite.rectself.sprite.rect[0]stepX,self.sprite.rect[1]stepY,self.sprite.frame_width,self.sprite.frame_heightif self.sprite.collisions![]:for v in self.sprite.collisions:result pygame.sprite.collide_mask(self.sprite,v)while result:#bug 墙壁反弹错位unstepX,unstepYstepX,stepYif unstepX!0:if unstepX0:unstepX10else:unstepX-10if unstepY!0:if unstepY0:unstepY10else:unstepY-10result pygame.sprite.collide_mask(self.sprite,v)#for vi in range(0,20):self.sprite.rectself.sprite.rect[0]-stepX,self.sprite.rect[1]-stepY,self.sprite.frame_width,self.sprite.frame_heightprint (Collision occurred)#敌人
class Enemy(MySprite):def __init__(self, screen, groupNone):super().__init__(screen, groupgroup)self.screenscreenself.groupgroup#self.AIControlSpriteController()self.movieStep0self.stepY,self.stepX0,10def autoMove(self,Size):self.group.update(ticks)self.group.draw(self.screen)if self.movieStep0:random.seed(random.randint(0,100))drandom.randint(1,16)if d0 and d5:#上self.stepY-10self.stepX0elif d4 and d9:#下self.stepY10self.stepX0elif d8 and d13:#左self.stepX-10self.stepY0elif d12 and d17:#右self.stepX10self.stepY0self.movieStep20if self.movieStep!0:if (self.rect[0],self.rect[1])(60,60) and (self.rect[0],self.rect[1]) (Size[0]-60,Size[1]-60):self.rectself.rect[0]self.stepX,self.rect[1]self.stepY,self.frame_width,self.frame_heightself.movieStep-1if self.collisions![]:for v in self.collisions:#self.group.update(ticks)#self.group.draw(self.screen)result pygame.sprite.collide_mask(self,v)while result:#bug 墙壁反弹错位unstepX,unstepYself.stepX,self.stepYif unstepX!0:if unstepX0:unstepX10else:unstepX-10if unstepY!0:if unstepY0:unstepY10else:unstepY-10result pygame.sprite.collide_mask(self,v)#for vi in range(0,20):self.rectself.rect[0]-self.stepX,self.rect[1]-self.stepY,self.frame_width,self.frame_heightprint (Collision occurred)map_srpirte[[-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-],[-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-],[-,-,-,-,-,-,-,-,w,w,w,w,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-],[-,-,-,-,-,-,-,-,-,w,w,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-],[-,-,-,-,-,-,-,-,-,w,w,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-],[-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-],[-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-],[-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-],[-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-],[-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-],[-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-],[-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-],[-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-],[-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-],[-,-,-,-,-,-,-,-,w,w,w,w,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-],[-,-,-,-,-,-,-,-,-,w,w,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-],[-,-,-,-,-,-,-,-,-,w,w,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-],[-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-],[-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-],[-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-],[-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-],[-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-],[-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-],[-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-],]
mapConf{space:-,w:./tank/scene/brick.png,height:12,weight:20
}
#map_srpirteConf{[w,24,24,1,1]}
screenWmapConf[weight]*34
screenHmapConf[height]*48pygame.init()
screen pygame.display.set_mode((screenW,screenH))
group_wallt pygame.sprite.Group()
pygame.key.set_repeat(10)
framerate pygame.time.Clock()group_hero pygame.sprite.Group()
enemy_hero pygame.sprite.Group()
sprite_hero MySprite(screen,group_hero)sprite_hero.load(./tank/playerTank/tank_T1_2.png,48, 48, 4, 2)
up./tank/bullet/bullet_up.png
down./tank/bullet/bullet_down.png
left./tank/bullet/bullet_left.png
right./tank/bullet/bullet_right.png
#sprite_hero.setShootSprite()
group_hero.add(sprite_hero)enemy_list[]
for v in range(0,20):enemy Enemy(screen,enemy_hero)enemy.load(./tank/enemyTank/enemy_1_0.png,48, 48, 4, 2)enemy_hero.add(enemy)enemy_list.append(enemy)posx,posy0,0
wallet[]
for rows in map_srpirte:for v in rows:posx24if v!mapConf[space]:sprite_wallt MySprite(screen,group_wallt)sprite_wallt.load(mapConf[w],24, 24, 1, 1,posx,posy)group_wallt.add(sprite_wallt)sprite_hero.setCollision(sprite_wallt)enemy.setCollision(sprite_wallt)print(str(posx),str(posy))posy24posx0#sprite_wallt MySprite(screen,group_wallt)
#sprite_wallt.load(mapConf[w],24, 24, 1, 1,posx,posy)
#group_wallt.add(sprite_wallt)
#主循环
while True:print((screenW,screenH))framerate.tick(30)ticks pygame.time.get_ticks()for event in pygame.event.get():if event.type pygame.QUIT:pygame.quit()exit()elif event.typepygame.KEYDOWN:print(key down ......)sprite_hero.control.moveControl(event)pos{up_x:18,up_y:-10,down_x:18,down_y:50,left_x:-6,left_y:16,right_x:50,right_y:18,}sprite_hero.shoot(up,down,left,right,12,12,1,1,pos,ticks,enemy_list)screen.fill((0,0,100))group_hero.update(ticks)group_hero.draw(screen)enemy_hero.update(ticks)enemy_hero.draw(screen)group_wallt.update(ticks)group_wallt.draw(screen)for v in enemy_list:v.autoMove((screenW,screenH))pygame.display.update()