简单的战旗游戏开发学习
在网上找寻教程之后搞出了这么个雏形

游戏介绍
游戏实现了战斗场景的回合制玩法: 对战双方每个生物每一轮有一次行动机会,可以行走或攻击对方。 每个生物属性有:行走范围,速度,生命,伤害,防御,攻击 和 是否是远程兵种。 当把对方生物都消灭时,即胜利。

代码介绍
对于战旗类游戏的核心还是地图,虽然网上有六边形的地图教程但是没看太懂就做正方形的吧 首先定义函数,width 和 height 为地图的宽度和长度,bg_map 设置方格的背景颜色, entity_map 保存哪个方格上有生物。active_entity表示当前要行动的生物。

class Map():def __init__(self, width, height, grid):self.width = widthself.height = heightself.bg_map = [[0 for x in range(self.width)] for y in range(self.height)]self.entity_map = [[None for x in range(self.width)] for y in range(self.height)]self.active_entity = Noneself.select = Noneself.setupMapImage(grid)self.setupMouseImage()

当我方生物选择行动时,设置生物可行走范围内的方格背景为 c.BG_RANGE 。active_entity 的 inRange 函数判断一个方格是否在行走范围内。

 def updateMap(self):for y in range(self.height):for x in range(self.width):self.bg_map[y][x] = c.BG_EMPTYif self.entity_map[y][x] is not None and self.entity_map[y][x].isDead():self.entity_map[y][x] = Noneif self.active_entity is None or self.active_entity.state != c.IDLE:returnmap_x, map_y = self.active_entity.map_x, self.active_entity.map_yself.bg_map[map_y][map_x] = c.BG_ACTIVEfor y in range(self.height):for x in range(self.width):if not self.isMovable(x,y) or not self.isValid(x,y):continueif self.active_entity.inRange(self, x, y):self.bg_map[y][x] = c.BG_RANGEmouse_x, mouse_y = pg.mouse.get_pos()self.checkMouseMove(mouse_x, mouse_y)

接下来完善下我们的map代码

import pygame as pg
from .. import tool
from .. import constants as cclass Map():def __init__(self, width, height, grid):self.width = widthself.height = heightself.bg_map = [[0 for x in range(self.width)] for y in range(self.height)]self.entity_map = [[None for x in range(self.width)] for y in range(self.height)]self.active_entity = Noneself.select = Noneself.setupMapImage(grid)self.setupMouseImage()def setupMapImage(self, grid):self.grid_map = [[0 for x in range(self.width)] for y in range(self.height)]if grid is not None:for data in grid:x, y, type = data['x'], data['y'], data['type']self.grid_map[y][x] = typeself.map_image = pg.Surface((self.width * c.REC_SIZE, self.height * c.REC_SIZE)).convert()self.rect = self.map_image.get_rect()self.rect.x = 0self.rect.y = 0for y in range(self.height):for x in range(self.width):type = self.grid_map[y][x]if type != c.MAP_EMPTY:if c.MAP_HEXAGON:base_x, base_y = tool.getHexMapPos(x, y)self.map_image.blit(tool.GRID[type], (base_x, base_y))else:self.map_image.blit(tool.GRID[type], (x * c.REC_SIZE, y * c.REC_SIZE))self.map_image.set_colorkey(c.BLACK)def setupMouseImage(self):self.mouse_frames = []frame_rect = (0, 0, 25, 27)self.mouse_image = tool.get_image(tool.GFX[c.MOUSE], *frame_rect, c.BLACK, 1)self.mouse_rect = self.mouse_image.get_rect()pg.mouse.set_visible(False)def isValid(self, map_x, map_y):if c.MAP_HEXAGON:if map_y % 2 == 0:max_x = self.widthelse:max_x = self.width - 1else:max_x = self.widthif (map_x < 0 or map_x >= max_x ormap_y < 0 or map_y >= self.height):return Falsereturn Truedef isMovable(self, map_x, map_y):return (self.entity_map[map_y][map_x] == None and self.grid_map[map_y][map_x] != c.MAP_STONE)def getMapIndex(self, x, y):if c.MAP_HEXAGON:return tool.getHexMapIndex(x, y)else:return (x//c.REC_SIZE, y//c.REC_SIZE)def getDistance(self, x1, y1, map_x2, map_y2):if c.MAP_HEXAGON:x2, y2 = tool.getHexMapPos(map_x2, map_y2)x2 += c.HEX_X_SIZE // 2y2 += c.HEX_Y_SIZE // 2distance = (abs(x1 - x2) + abs(y1 - y2))else:map_x1, map_y1 = self.getMapIndex(x1, y1)x2 = map_x2 * c.REC_SIZE + c.REC_SIZE//2y2 = map_y2 * c.REC_SIZE + c.REC_SIZE//2distance = (abs(x1 - x2) + abs(y1 - y2))if map_x1 != map_x2 and map_y1 != map_y2:distance -= c.REC_SIZE//2return distancedef checkMouseClick(self, x, y):if self.active_entity is None:return Falsemap_x, map_y = self.getMapIndex(x, y)if not self.isValid(map_x, map_y):return Falseentity = self.entity_map[map_y][map_x]if ((entity is None or entity == self.active_entity) and self.active_entity.inRange(self, map_x, map_y)):self.active_entity.setDestination(map_x, map_y)return Trueelif entity is not None:if self.active_entity.isRemote():self.active_entity.setTarget(entity)return Trueelif self.select is not None:self.active_entity.setDestination(self.select[0], self.select[1], entity)return Truereturn Falsedef checkMouseMove(self, x, y):if self.active_entity is None:return Falsemap_x, map_y = self.getMapIndex(x, y)if not self.isValid(map_x, map_y):return Falseself.select = Noneentity = self.entity_map[map_y][map_x]if ((self.isMovable(map_x, map_y) or entity == self.active_entity) and self.active_entity.inRange(self, map_x, map_y)):self.bg_map[map_y][map_x] = c.BG_SELECTelif entity is not None:if entity.group_id != self.active_entity.group_id:if self.active_entity.isRemote():self.bg_map[map_y][map_x] = c.BG_ATTACKelse:dir_list = tool.getAttackPositions(map_x, map_y)res_list = []for offset_x, offset_y in dir_list:if self.isValid(map_x + offset_x, map_y + offset_y):type = self.bg_map[map_y + offset_y][map_x + offset_x]if type == c.BG_RANGE or type == c.BG_ACTIVE:res_list.append((map_x + offset_x, map_y + offset_y))if len(res_list) > 0:min_dis = c.MAP_WIDTHfor tmp_x, tmp_y in res_list:distance = self.getDistance(x, y, tmp_x, tmp_y)if distance < min_dis:min_dis = distanceres = (tmp_x, tmp_y)self.bg_map[res[1]][res[0]] = c.BG_SELECTself.bg_map[map_y][map_x] = c.BG_ATTACKself.select = resdef setEntity(self, map_x, map_y, value):self.entity_map[map_y][map_x] = valuedef drawMouseShow(self, surface):x, y = pg.mouse.get_pos()map_x, map_y = self.getMapIndex(x, y)if self.isValid(map_x, map_y):self.mouse_rect.x = xself.mouse_rect.y = ysurface.blit(self.mouse_image, self.mouse_rect)def updateMap(self):for y in range(self.height):for x in range(self.width):self.bg_map[y][x] = c.BG_EMPTYif self.entity_map[y][x] is not None and self.entity_map[y][x].isDead():self.entity_map[y][x] = Noneif self.active_entity is None or self.active_entity.state != c.IDLE:returnmap_x, map_y = self.active_entity.map_x, self.active_entity.map_yself.bg_map[map_y][map_x] = c.BG_ACTIVEfor y in range(self.height):for x in range(self.width):if not self.isMovable(x,y) or not self.isValid(x,y):continueif self.active_entity.inRange(self, x, y):self.bg_map[y][x] = c.BG_RANGEmouse_x, mouse_y = pg.mouse.get_pos()self.checkMouseMove(mouse_x, mouse_y)def drawBackground(self, surface):if c.MAP_HEXAGON:return self.drawBackgroundHex(surface)pg.draw.rect(surface, c.LIGHTYELLOW, pg.Rect(0, 0, c.MAP_WIDTH, c.MAP_HEIGHT))for y in range(self.height):for x in range(self.width):if self.bg_map[y][x] == c.BG_EMPTY:color = c.LIGHTYELLOWelif self.bg_map[y][x] == c.BG_ACTIVE:color = c.SKY_BLUEelif self.bg_map[y][x] == c.BG_RANGE:color = c.NAVYBLUEelif self.bg_map[y][x] == c.BG_SELECT:color = c.GREENelif self.bg_map[y][x] == c.BG_ATTACK:color = c.GOLDpg.draw.rect(surface, color, (x * c.REC_SIZE, y * c.REC_SIZE, c.REC_SIZE, c.REC_SIZE))surface.blit(self.map_image, self.rect)for y in range(self.height):# draw a horizontal linestart_pos = (0, 0 + c.REC_SIZE * y)end_pos = (c.MAP_WIDTH, c.REC_SIZE * y)pg.draw.line(surface, c.BLACK, start_pos, end_pos, 1)for x in range(self.width):# draw a horizontal linestart_pos = (c.REC_SIZE * x, 0) end_pos = (c.REC_SIZE * x, c.MAP_HEIGHT)pg.draw.line(surface, c.BLACK, start_pos, end_pos, 1)def calHeuristicDistance(self, x1, y1, x2, y2):if c.MAP_HEXAGON:dis_y = abs(y1 - y2)dis_x = abs(x1 - x2)half_y = dis_y // 2if dis_y >= dis_x:dis_x = 0else:dis_x -= half_yreturn (dis_y + dis_x)else:return abs(x1 - x2) + abs(y1 - y2)def drawBackgroundHex(self, surface):Y_LEN = c.HEX_Y_SIZE // 2X_LEN = c.HEX_X_SIZE // 2pg.draw.rect(surface, c.LIGHTYELLOW, pg.Rect(0, 0, c.MAP_WIDTH, c.MAP_HEIGHT))for y in range(self.height):for x in range(self.width):if self.bg_map[y][x] == c.BG_EMPTY:color = c.LIGHTYELLOWelif self.bg_map[y][x] == c.BG_ACTIVE:color = c.SKY_BLUEelif self.bg_map[y][x] == c.BG_RANGE:color = c.NAVYBLUEelif self.bg_map[y][x] == c.BG_SELECT:color = c.GREENelif self.bg_map[y][x] == c.BG_ATTACK:color = c.GOLDbase_x, base_y = tool.getHexMapPos(x, y)points = [(base_x, base_y + Y_LEN//2 + Y_LEN), (base_x, base_y + Y_LEN//2),(base_x + X_LEN, base_y), (base_x + X_LEN * 2, base_y + Y_LEN//2),(base_x + X_LEN * 2, base_y + Y_LEN//2 + Y_LEN), (base_x + X_LEN, base_y + Y_LEN*2)]pg.draw.polygon(surface, color, points)surface.blit(self.map_image, self.rect)for y in range(self.height):for x in range(self.width):if y % 2 == 1 and x == self.width - 1:continuebase_x, base_y = tool.getHexMapPos(x, y)points = [(base_x, base_y + Y_LEN//2 + Y_LEN), (base_x, base_y + Y_LEN//2),(base_x + X_LEN, base_y), (base_x + X_LEN * 2, base_y + Y_LEN//2),(base_x + X_LEN * 2, base_y + Y_LEN//2 + Y_LEN), (base_x + X_LEN, base_y + Y_LEN*2)]pg.draw.lines(surface, c.BLACK, True, points)

接下来我们要搞定的就是人物类,我们的函数要实现:1.生物属于敌我哪一方 2.初始时生物在地图上的位置 3.保存生物的所有属性 4.生物的行走 5.生物的三种形态那么看代码

import pygame as pg
from .. import tool
from .. import constants as c
from .. import AStarSearch
from . import mapclass FireBall():def __init__(self, x, y, enemy, hurt):# first 3 Frames are flying, last 4 frams are explodingframe_rect = (0,0,14,14)self.image = tool.get_image(tool.GFX[c.FIREBALL], *frame_rect, c.BLACK, c.SIZE_MULTIPLIER)self.rect = self.image.get_rect()self.rect.centerx = xself.rect.centery = yself.enemy = enemyself.hurt = hurtself.done = Falseself.calVelocity()def calVelocity(self):#print('calVelocity: x:', self.enemy.rect.centerx, self.rect.centerx, 'y:', self.enemy.rect.centery,self.rect.centery)dis_x = self.enemy.rect.centerx - self.rect.centerxdis_y = self.enemy.rect.centery - self.rect.centerydistance = (dis_x ** 2 + dis_y ** 2) ** 0.5self.x_vel = (dis_x * 10)/distanceself.y_vel = (dis_y * 10)/distancedef update(self):self.rect.x += self.x_velself.rect.y += self.y_velif abs(self.rect.x - self.enemy.rect.x) + abs(self.rect.y - self.enemy.rect.y) < 25:self.enemy.setHurt(self.hurt)self.done = Truedef draw(self, surface):surface.blit(self.image, self.rect)class EntityAttr():def __init__(self, data):self.max_health = data[c.ATTR_HEALTH]self.range = data[c.ATTR_RANGE]self.damage = data[c.ATTR_DAMAGE]self.attack = data[c.ATTR_ATTACK]self.defense = data[c.ATTR_DEFENSE]self.speed = data[c.ATTR_SPEED]if data[c.ATTR_REMOTE] == 0:self.remote = Falseelse:self.remote = Truedef getHurt(self, enemy_attr):offset = 0if self.attack > enemy_attr.defense:offset = (self.attack - enemy_attr.defense) * 0.05elif self.attack < enemy_attr.defense:offset = (self.attack - enemy_attr.defense) * 0.025hurt = int(self.damage * (1 + offset))return hurtclass Entity():def __init__(self, group, sheet, map_x, map_y, data):self.group = groupself.group_id = group.group_idself.map_x = map_xself.map_y = map_yself.frames = []self.frame_index = 0self.loadFrames(sheet)self.image = self.frames[self.frame_index]self.rect = self.image.get_rect()self.rect.x, self.rect.y = self.getRectPos(map_x, map_y)self.attr = EntityAttr(data)self.health = self.attr.max_healthself.weapon = Noneself.enemy = Noneself.state = c.IDLEself.animate_timer = 0.0self.current_time = 0.0self.move_speed = c.MOVE_SPEEDdef getRectPos(self, map_x, map_y):if c.MAP_HEXAGON:base_x, base_y = tool.getHexMapPos(map_x, map_y)return (base_x + 4, base_y + 6)else:return(map_x * c.REC_SIZE + 5, map_y * c.REC_SIZE + 8)def getRecIndex(self, x, y):if c.MAP_HEXAGON:x += c.HEX_X_SIZE // 2 - 4y += c.HEX_Y_SIZE // 2 - 6map_x, map_y = tool.getHexMapIndex(x, y)else:map_x, map_y = (x//c.REC_SIZE, y//c.REC_SIZE)return (map_x, map_y)def loadFrames(self, sheet):frame_rect_list = [(64, 0, 32, 32), (96, 0, 32, 32)]for frame_rect in frame_rect_list:self.frames.append(tool.get_image(sheet, *frame_rect, c.BLACK, c.SIZE_MULTIPLIER))def setDestination(self, map_x, map_y, enemy=None):self.dest_x, self.dest_y = self.getRectPos(map_x, map_y)self.next_x, self.next_y = self.rect.x, self.rect.yself.enemy = enemyself.state = c.WALKdef setTarget(self, enemy):self.enemy = enemyself.state = c.ATTACKdef getHealthRatio(self):if self.health > 0:return self.health / self.attr.max_healthelse:return 0def isDead(self):return self.health <= 0def isRemote(self):return self.attr.remotedef inRange(self, map, map_x, map_y):location = AStarSearch.AStarSearch(map, (self.map_x, self.map_y), (map_x, map_y))if location is not None:_, _, distance = AStarSearch.getFirstStepAndDistance(location)if distance <= self.attr.range:return Truereturn Falsedef putHurt(self, enemy):hurt = self.attr.getHurt(enemy.attr)enemy.setHurt(hurt)def setHurt(self, damage):self.health -= damageif self.isDead():self.group.removeEntity(self)def shoot(self, enemy):hurt = self.attr.getHurt(enemy.attr)self.weapon = FireBall(*self.rect.center, self.enemy, hurt)def walkToDestination(self, map):if self.rect.x == self.next_x and self.rect.y == self.next_y:source = self.getRecIndex(self.rect.x, self.rect.y)dest = self.getRecIndex(self.dest_x, self.dest_y)location = AStarSearch.AStarSearch(map, source, dest)if location is not None:map_x, map_y, _ = AStarSearch.getFirstStepAndDistance(location)self.next_x, self.next_y = self.getRectPos(map_x, map_y)else:self.state = c.IDLEif c.MAP_HEXAGON and self.rect.x != self.next_x and self.rect.y != self.next_y:self.rect.x += self.move_speed if self.rect.x < self.next_x else -self.move_speedself.rect.y += self.move_speed if self.rect.y < self.next_y else -self.move_speedelif self.rect.x != self.next_x:self.rect.x += self.move_speed if self.rect.x < self.next_x else -self.move_speedelif self.rect.y != self.next_y:self.rect.y += self.move_speed if self.rect.y < self.next_y else -self.move_speeddef update(self, game_info, map):self.current_time = game_info[c.CURRENT_TIME]if self.state == c.WALK:if (self.current_time - self.animate_timer) > 250:if self.frame_index == 0:self.frame_index = 1else:self.frame_index = 0self.animate_timer = self.current_timeif self.rect.x != self.dest_x or self.rect.y != self.dest_y:self.walkToDestination(map)else:map.setEntity(self.map_x, self.map_y, None)self.map_x, self.map_y = self.getRecIndex(self.dest_x, self.dest_y)map.setEntity(self.map_x, self.map_y, self)if self.enemy is None:self.state = c.IDLEelse:self.state = c.ATTACKelif self.state == c.ATTACK:if self.attr.remote:if self.weapon is None:self.shoot(self.enemy)else:self.weapon.update()if self.weapon.done:self.weapon = Noneself.enemy = Noneself.state = c.IDLEelse:self.putHurt(self.enemy)self.enemy = Noneself.state = c.IDLEif self.state == c.IDLE:self.frame_index = 0def draw(self, surface):self.image = self.frames[self.frame_index]surface.blit(self.image, self.rect)width = self.rect.width * self.getHealthRatio()height = 5pg.draw.rect(surface, c.RED, pg.Rect(self.rect.left, self.rect.top - height - 1, width, height))if self.weapon is not None:self.weapon.draw(surface)class EntityGroup():def __init__(self, group_id):self.group = []self.group_id =  group_idself.entity_index = 0def createEntity(self, entity_list, map):for data in entity_list:entity_name, map_x, map_y = data['name'], data['x'], data['y']if map_x < 0:map_x = c.GRID_X_LEN + map_xif map_y < 0:map_y = c.GRID_Y_LEN + map_yentity = Entity(self, tool.GFX[entity_name], map_x, map_y, tool.ATTR[entity_name])self.group.append(entity)map.setEntity(map_x, map_y, entity)#self.group = sorted(self.group, key=lambda x:x.attr.speed, reverse=True)def removeEntity(self, entity):for i in range(len(self.group)):if self.group[i] == entity:if (self.entity_index > i or(self.entity_index >= len(self.group) - 1)):self.entity_index -= 1self.group.remove(entity)def isEmpty(self):if len(self.group) == 0:return Truereturn Falsedef nextTurn(self):self.entity_index = 0def getActiveEntity(self):if self.entity_index >= len(self.group):entity = Noneelse:entity = self.group[self.entity_index]return entitydef consumeEntity(self):self.entity_index += 1def update(self, game_info, map):for entity in self.group:entity.update(game_info, map)def draw(self, surface):for entity in self.group:entity.draw(surface)

完成这两个类后我们的游戏(手游)基本上就完成了

游戏运行截图

pygame 游戏开发相关推荐

  1. 《Python和Pygame游戏开发指南》——2.16 pygame.display.update()函数

    本节书摘来自异步社区<Python和Pygame游戏开发指南>一书中的第2章,第2.16节,作者[美]Al Sweigart(斯维加特), 李强 译,更多章节内容可以访问云栖社区" ...

  2. 《Python和Pygame游戏开发指南》——1.12 图书中的文本折行

    本节书摘来自异步社区<Python和Pygame游戏开发指南>一书中的第1章,第1.12节,作者[美]Al Sweigart(斯维加特), 李强 译,更多章节内容可以访问云栖社区" ...

  3. 01-初识 pygame 游戏开发

    你好,我是悦创.接下来三十天,我将持续更新 Python pygame 的基础游戏开发教程.文章都会对应视频教程,视频教程将在公众号:AI悦创,发布. 目录 本次,文章目标: Python 的第三方库 ...

  4. Pygame 游戏开发 实战 1

    Pygame 游戏开发 第三课 实战 1 动态彩色圆环 选择数字 指针时钟 动态彩色圆环 通过圆形和线的绘制, 和文字的添加, 来实现一个简单的数字选择小游戏. 代码: import pygame f ...

  5. python和pygame游戏开发指南_学习记录

    <python和pygame游戏开发指南> Making Games With Python and Palme [美]Ai Sweigart 著,李强 译,2015.12第一版 文章目录 ...

  6. Pygame 游戏开发 图形绘制 键鼠事件

    [Pygame] 游戏开发 第二课 图形绘制 & 键鼠事件 图形绘制 圆形绘制 绘制矩形 绘制直线 绘制圆弧 案例 键鼠事件 键盘事件 鼠标事件 图形绘制 圆形绘制 格式: pygame.dr ...

  7. python编程之pygame游戏开发系列——软件简介与安装

    视频地址 编程工具选择 IDLE:初级入门 vscode:我们将使用的软件. pycharm:免费 anaconda:科学计算 vscode 的安装 下载 地址 地址2:自动下载符合你系统的安装程序 ...

  8. python编写游戏怎么打包——详解python+pygame游戏开发之使用Py2exe打包游戏为exe文件

    python编写游戏怎么打包 1.简介 2.软件准备 3.打包流程 最近在用python+pygame 开发游戏,写完以后在分享给朋友玩的时候遇到了很大的问题,只有搭建了环境才能运行python脚本. ...

  9. python血条游戏代码_手把手Python和pygame游戏开发教程(二)

    欢迎,来自IP地址为:114.99.15.226 的朋友 前面教程第一部分已经成了小兔子的正确移动和转向,现在需要给它添加更多的动作以进行游戏的进一步开发. 让小兔子可以射箭 你的小兔子可以正确移动后 ...

最新文章

  1. NGUI创建Camera参数为Simple 2D的UI UI对象的结构UI Root(2D)
  2. 11.编写一个Java程序,计算半径为3.0的圆周长和面积并输出结果。把圆周率π定义为常量,半径定义为变量,然后进行计算并输出结果。...
  3. Unity中UGUI之Canvas属性解读版本二
  4. python opencv3 检测人
  5. 【Vue US国际会议】使用Vue和NativeScript来开发吸引人的原生手机app
  6. Ajax(从json中提取数据)
  7. Java中Spring面试基础题20190302
  8. Android 色彩设计理念
  9. Arcgis Android - HelloWorld
  10. 在Windows Server 2012R2离线安装.net framework3.5
  11. Java全栈学习路线
  12. 医院防统方软件解决方案
  13. postgresql 客户端 uri 设置时区
  14. 【图像压缩】基于matlab余弦变换及霍夫曼编码jpeg压缩和解压【含Matlab源码 2086期】
  15. [转载]document.readyState
  16. 《创业算法》:技术人做CEO的优势和劣势
  17. 谷露专访伯周咨询创始人Tiger Pan:在退潮后蜕变
  18. 数据结构c语言进制转换八进制,C语言数据结构中数制转换实例代码
  19. 常用APP的OpenUrl
  20. str.charAt(0);

热门文章

  1. 疯狂星期四,抢980元超值美食卡,尊享超级特价!
  2. springboot项目 o.s.b.d.LoggingFailureAnalysisReporter 错误解决方法
  3. 多模态机器学习概述及其音视频融合总结
  4. 12款浏览器兼容性测试工具推荐
  5. 微信小程序前端各种酷炫的动画特效实例,这一篇就够了,复制开箱就用,赶快收藏好了
  6. MODTRAN辐射传输模型使用笔记
  7. python提取cad坐标_教你一个实用的CAD坐标提取技巧
  8. 防雷工程专业术语及雷电浪涌保护器名词解释
  9. 美国陪审团裁定福特向车祸遇难者家属赔偿17亿美元
  10. AutoCAD在指定布局中如何隐藏指定的图形?