负责游戏架构和网络通信
工作量:40%
负责UI设计
工作量:30%
负责视觉效果设计
工作量:15%
负责地图和音乐设计
工作量:15%
-
- 支持地图绘制、人物绘制、水泡效果绘制等
- 支持鼠标和键盘操作交互
- 支持障碍物
- 支持泡泡的放置与爆炸
- 支持三种基本增强型道具(鞋子,泡泡,药水)
- 实现服务端:支持局域网联机对战(自由对抗模式),且支持多人在同一个地图游戏
- 支持动画效果
-
- 支持房间列表
- 支持 >= 2 张地图
- 临终礼物
-
- STL 容器,如 std::vector
- 迭代器
- 类和多态
-
- 初始化列表
- 类型推断
- Lambda 表达式
-
- 图形化描述
graph TB A[地图]-->B[障碍物] A-->C[道路] B-->D[道具块] B-->E[固定块]
- 实现细节
for (int i = 0; i < 15; ++i) { std::vector<Vec2> map; std::vector<int> prop; for (int j = 0; j < 15; ++j) { map.push_back(road->getPositionAt(Vec2(i, j)) + Vec2(deltaX + 16, deltaY - 480 + 16)); auto tileGidCol = collidable->getTileGIDAt(Point(i,j)); auto tileGidIte = _item->getTileGIDAt(Point(i, j)); if (tileGidCol > 0) prop.push_back(1);//1代表该块为碰撞块 else if (tileGidIte > 0) prop.push_back(4);//4代表该块为道具块 else prop.push_back(0);//0代表无障碍物 } _mapCoord.push_back(map); _mapProp.push_back(prop); }
- 说明
地图的块属性被储存在
std::vector<std::vector> _mapProp;
中
每个块的位置被储存在std::vector<std::vector> _mapCoord;
中
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 4 4 4 0 0 0 0 0 4 4 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 0 0 0 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 4 4 4 4 4 0 0 0 0 0 0 0 0 0 0 0 4 4 4 0 0 0 0 0 0 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 -
- 图形化描述
graph TB A[Player]-->B[移动] A-->C[动画] A-->D[人物属性] B-->E[描述移动方向的参数] D-->F[人物自身属性] D-->G[炸弹相关属性]
-
人物实体
使用精灵帧中的图片实现
-
人物移动
以“瞬移”的形式移动
移动的距离为速度的大小,单位是像素点
移动的同时播放动画 -
碰撞
将player图片的四个角设置为碰撞点,则
碰撞点检查 左上 左下 右上 右下 向左移动 O O X X 向右移动 X X O O 向上移动 O X O X 向下移动 X O X O 由碰撞点的坐标计算出碰撞点所处的块
再由块的属性决定是否发生了碰撞 -
动画
人物向A方向移动
- 若向A方向移动的动画未播放,则播放此动画
- 若向A方向移动的动画正在播放,则不做操作
- 向A方向移动结束后,停止向A方向移动的动画
-
人物属性
graph TB A[人物自身属性]-->B[移动速度] A-->C[是否存活]
graph TB A[炸弹相关属性]-->B[炸弹数量上限] A-->C[当前炸弹数量] A-->D[炸弹威力]
-
-
种类
- 增加移动速度
- 增加炸弹数量上限
- 增加炸弹威力
-
道具位置
藏在道具块下
数量一定,位置随机,由服务端产生的随机数种子确定
-
-
-
性质
- 属于障碍物
- 安放两秒后爆炸
- 爆炸产生的波持续0.6秒
- Player碰到波后将会死亡
- 有些小技巧
-
碰撞
bool MainScene::onContactBegin(const PhysicsContact& contact) { auto objA = static_cast<Sprite*>(contact.getShapeA()->getBody()->getNode()); auto objB = static_cast<Sprite*>(contact.getShapeB()->getBody()->getNode()); auto nameA = objA->getName(); auto nameB = objB->getName(); if (nameA == "player"&&nameB == "bomb") { log("player has been slayed"); auto player = static_cast<Player*>(objA); player->_isAlive = false; } else if (nameA == "bomb"&&nameB == "player") { log("player has been slayed"); auto player = static_cast<Player*>(objB); player->_isAlive = false; } return true; }
借助物理碰撞的事件监听器,发生碰撞后,若是一方为波,一方为Player,则判定Player一方被消灭
-
-
- 加载项
- 地图
- Player
- Item
- 监听器
- 键盘监听器
- 碰撞监听器
- 交互
- 人物移动
- 安放炸弹
- 炸弹爆炸
- 胜负判定
- 网络通信
- 服务端
- 客户端(发射器)
- 客户端(接收器)
- 加载项
使用了boost库进行多线程(thread)运行和网络通信(asio)
-
-
通信协议
UDP -
数据处理
同步 -
规则
- 创建房间的计算机作为服务器运行
- 每个计算机都作为客户端运行
- 服务器进行局域网广播
room: 123, player: 0, map: 0, mapSeed: 32
- 客户端接收广播,读取信息
- 客户端请求连接
connect
- 服务器收到消息,回复客户端并分配Player
successfully connected! player1
-
-
-
通信协议
UDP -
数据处理
同步 -
规则
- 当本机人物位置发生变化或者安放炸弹时,客户端发出消息
p2 u l b [123.45,123.45]
- 服务端接收消息,并向其他连接的客户端转发
- 客户端收到消息,解析消息,更新Player状态
- 游戏中的逻辑判断发生在客户端本地而非服务端
-
class Room : public cocos2d::Layer
{
public:
//...
void static initBroadcast(Room* ptr);
void static initClient(Room* ptr);
void static initReceiver(Room* ptr);
//...
}
类中的成员函数无法直接作为线程函数的参数,是因为成员函数隐含this指针,不符合调用函数的参数要求
所以需要将这些用于多线程的成员函数声明为static
而为了使这些函数能够处理类中的数据,必须将类的指针作为参数传入
_threadGroup.create_thread(std::bind(&initBroadcast, this));
-
- 图形化描述
graph TB A[Start]-->|选择地图|C[创建房间] A-->D[搜索房间] C-->E[房间命名] D-->F[房间列表] E-->G[进入房间] F-->|选择房间|G G-->H[进入游戏]
-
选择地图
- 提供两张比赛地图和一张测试地图
- 不选择地图则默认使用测试地图
-
创建房间
- 无法创建房间名为空的房间
- 房间名长度 <= 10 个英文字符
-
房间列表
- 创建或寻找并加入房间后跳转到相应房间界面
- 显示房间的名称、人数、地图
-
房间相关类
- 图形化描述
graph TB A[RoomVec]-->B[RoomItem_1] A-->C[RoomItem_2] B-->E[房间名] B-->F[玩家数量] B-->G[IP地址] C-->H[房间名] C-->I[玩家数量] C-->J[IP地址]
-
单个房间的类:RoomItem
- 属性
- 房间名称
- 玩家数量
- IP地址
- 方法
- 获取房间名、玩家数量、IP地址
- 修改玩家数量、IP地址(房间名不可更改)
- 属性
-
房间集合类:RoomVec
- 属性
- 封装std::vector
- 方法
- 向集合中添加新房间
- 获取集合中房间数量
- 通过名称查找集合中的房间
- 通过IP地址查找集合中的房间
- 获取指向房间首、末元素的迭代器
- []运算符查找房间
- 属性