本游戏为本科的毕业设计,开贴旨在用来用来记录。目前所写的角色扮演游戏(RPG)已经有了一个成品,但是部分实现上不便于扩展,故进行第三次重构。

本游戏基于SDL_Engine进行开发(简化版的cocos2d-x)。

首先需要构建框架。

本游戏采用MVC设计模式,GameScene为MVC中的Control控制器,主要起到负责全局的管理,逻辑处理,事件接收与分发等。为了便于以后lua脚本的接入,故GameScene为单例类。先看看代码吧。

GameScene.h

#ifndef __GameScene_H__
#define __GameScene_H__
#include <string>#include "SDL_Engine/SDL_Engine.h"using namespace std;
USING_NS_SDL;class MapLayer;class GameScene : public Scene
{
private:static GameScene* s_pInstance;
public:static GameScene* getInstance();static void purge();
private:MapLayer* m_pMapLayer;
public:static const int CHARACTER_LOCAL_Z_ORDER = 9999;//需要比tmx地图总图块大
private:GameScene();~GameScene();bool init();bool initializeMapAndPlayers();
public://改变场景void changeMap(const string& mapName, const Point& tileCoodinate);//设置视图中心点void setViewPointCenter(const Point& position, float duration = 0.f);
};
#endif

目前的GameScene类中的内容还是比较少的,仅仅包含了一个MapLayer指针和CHARACTER_LOCAL_Z_ORDER,这个静态成员主要是为了处理角色和tmx地图的图块之间的遮挡关系的,它会在MapLayer类中和GameScene中的设置角色的localZOrder中等用到。

GameScene.cpp

#include "GameScene.h"
#include "MapLayer.h"
#include "StaticData.h"
#include "DynamicData.h"
//static
GameScene* GameScene::s_pInstance = nullptr;GameScene* GameScene::getInstance()
{//仅在场景在运行时才会分配新的对象if (s_pInstance == nullptr && Director::getInstance()->isRunning()){s_pInstance = new GameScene();s_pInstance->init();}return s_pInstance;
}void GameScene::purge()
{SDL_SAFE_RELEASE_NULL(s_pInstance);
}GameScene::GameScene():m_pMapLayer(nullptr)
{
}GameScene::~GameScene()
{StaticData::purge();DynamicData::purge();
}bool GameScene::init()
{m_pMapLayer = MapLayer::create();this->addChild(m_pMapLayer);//初始化地图和角色this->initlizeMapAndPlayers();return true;
}bool GameScene::initializeMapAndPlayers()
{//获取地图auto dynamicData = DynamicData::getInstance();//TODO:暂时使用存档1dynamicData->initializeSaveData(1);auto mapFilePath = dynamicData->getMapFilePath();auto tileCooridinate = dynamicData->getTileCoordinateOfPlayer();//改变地图this->changeMap(mapFilePath, tileCooridinate);return true;
}void GameScene::changeMap(const string& mapName, const Point &tileCoodinate)
{//改变当前地图m_pMapLayer->clear();m_pMapLayer->init(mapName);//改变当前中心点this->setViewPointCenter(tileCoodinate);
}void GameScene::setViewPointCenter(const Point& position, float duration)
{Size visibleSize = Director::getInstance()->getVisibleSize();const int tag = 10;//地图跟随点移动float x = (float)MAX(position.x, visibleSize.width / 2);float y = (float)MAX(position.y, visibleSize.height / 2);//获取地图层的地图auto tiledMap = m_pMapLayer->getTiledMap();auto tileSize = tiledMap->getTileSize();auto mapSize = tiledMap->getMapSize();auto mapSizePixel = Size(tileSize.width * mapSize.width, tileSize.height * mapSize.height);//不让显示区域超过地图的边界x = (float)MIN(x, (mapSizePixel.width - visibleSize.width / 2.f));y = (float)MIN(y, (mapSizePixel.height - visibleSize.height / 2.f));//实际移动的位置Point actualPosition = Point(x, y);//屏幕中心位置坐标Point centerOfView = Point(visibleSize.width / 2, visibleSize.height / 2);Point delta = centerOfView - actualPosition;Action* action = nullptr;//地图运动if (duration < FLT_EPSILON){action = Place::create(delta);}else{action = MoveTo::create(duration, delta);}action->setTag(tag);if (tiledMap->getActionByTag(tag) != nullptr){tiledMap->stopActionByTag(tag);}tiledMap->runAction(action);
}

changeMap函数用的很是广泛,其主要功能就是起到切换地图的功能。需要注意的是,切换地图只是更换了MapLayer对象中的m_pTiledMap指针的指向,GameScene对象中的MapLayer对象是不变的。而setViewPointCenter函数的主要功能则是是让界面跟随角色进行移动,以保证角色能一直显示在屏幕中间,这个函数不依赖于任何一个角色,故其用途广泛。

MapLayer.h

#ifndef __MapLayer_H__
#define __MapLayer_H__
#include <string>
#include "SDL_Engine/SDL_Engine.h"using namespace std;
USING_NS_SDL;class MapLayer : public Layer
{
private:TMXTiledMap* m_pTiledMap;//地图文件路径string m_filepath;
public:MapLayer();~MapLayer();CREATE_FUNC(MapLayer);static MapLayer* create(const string& filepath);bool init();bool init(const string& filepath);//清除void clear();//获取该地图的文件路径string& getFilepath();//获取地图名字string getMapName() const;//获取碰撞层TMXLayer* getCollisionLayer() const;//获取脚本对象TMXObjectGroup* getScriptObjectGroup() const;TMXTiledMap* getTiledMap() const;
private:void resetLocalZOrderOfTile();
};
#endif

MapLayer.cpp

#include "MapLayer.h"
#include "StaticData.h"
#include "GameScene.h"MapLayer::MapLayer():m_pTiledMap(nullptr)
{
}MapLayer::~MapLayer()
{
}MapLayer* MapLayer::create(const string& filepath)
{auto layer = new MapLayer();if (layer && layer->init(filepath))layer->autorelease();elseSDL_SAFE_DELETE(layer);return layer;
}bool MapLayer::init()
{return true;
}bool MapLayer::init(const string& filepath)
{m_filepath = filepath;m_pTiledMap = TMXTiledMap::create(filepath);this->addChild(m_pTiledMap);this->resetLocalZOrderOfTile();return true;
}void MapLayer::clear()
{if (m_pTiledMap != nullptr){m_pTiledMap->removeFromParent();m_pTiledMap = nullptr;}
}string& MapLayer::getFilepath()
{return m_filepath;
}string MapLayer::getMapName() const
{auto text = m_pTiledMap->getPropertyForName("name").asString();return text;
}TMXLayer* MapLayer::getCollisionLayer() const
{auto layerName = STATIC_DATA_STRING("collision_layer_name");return static_cast<TMXLayer*>(m_pTiledMap->getLayer(layerName));
}TMXObjectGroup* MapLayer::getScriptObjectGroup() const
{auto layerName = STATIC_DATA_STRING("script_layer_name");return m_pTiledMap->getObjectGroup(layerName);
}TMXTiledMap* MapLayer::getTiledMap() const
{return m_pTiledMap;
}void MapLayer::resetLocalZOrderOfTile()
{//保存所有优先级为2的图块vector<int> tileIds;auto tilesets = m_pTiledMap->getTilesets();for (auto tileset : tilesets){auto& properties = tileset->getProperties();for(auto itMap = properties.cbegin(); itMap != properties.cend(); itMap++){auto id = itMap->first;auto& valueMap= itMap->second;auto it = valueMap.find("priority");if (it != valueMap.cend() && it->second.asInt() == 2)tileIds.push_back(id + tileset->firstGrid);}}//设置优先级为2的图块localZOrderauto& children = this->getCollisionLayer()->getChildren();for (auto child : children){//获取名字auto name = child->getName();if (name.empty())continue;int id = SDL_atoi(name.c_str());//设置localZOrderif (find(tileIds.begin(),tileIds.end(),id) != tileIds.end()){child->setLocalZOrder(child->getLocalZOrder() + GameScene::CHARACTER_LOCAL_Z_ORDER);}}
}

值得一提的是resetLocalZOrderOfTile函数,其主要功能就是获取m_tiledMap中引用的图块中的存在property属性,且为2的图块,并进行重新设置其localZOrder,以保证和角色的正确遮挡,比如如下4个图块

上面的两个图块的属性如右

角色在是可以通过上面两个图块的,且角色应该被该树遮挡。这里规定,priority为0,则不可通过;为1则人物遮挡该图块;为2则人物被该图块遮挡。人物的localZOrder一般为CHARACTER_LOCAL_Z_ORDER,故一般情况下,人物的绘制会晚于优先级为0的图块,会早于优先级为2的图块(主要涉及到Node中的成员_localZOrder)。

接下来谈一谈MVC中的Model模型。先谈谈静态数据

StaticData.h

#ifndef __StaticData_H__
#define __StaticData_H__
#include <string>
#include "SDL_Engine/SDL_Engine.h"using namespace std;
USING_NS_SDL;
//定义一些常用的宏
#define STATIC_DATA_PATH "data/static_data.plist"
/*简化使用*/
#define STATIC_DATA_STRING(key) (StaticData::getInstance()->getValueForKey(key)->asString())
#define STATIC_DATA_INT(key) (StaticData::getInstance()->getValueForKey(key)->asInt())
#define STATIC_DATA_FLOAT(key) (StaticData::getInstance()->getValueForKey(key)->asFloat())
#define STATIC_DATA_BOOLEAN(key) (StaticData::getInstance()->getValueForKey(key)->asBool())
#define STATIC_DATA_POINT(key) (StaticData::getInstance()->getPointForKey(key))
#define STATIC_DATA_ARRAY(key) (StaticData::getInstance()->getValueForKey(key)->asValueVector())
#define STATIC_DATA_TOSTRING(key) (StaticData::getInstance()->toString(key))class StaticData : public Object
{
private:static StaticData* s_pInstance;
public:static StaticData* getInstance();static void purge();
private://键值对ValueMap m_valueMap;
private:StaticData();~StaticData();bool init();
public:/**@brief 根据键获取值@key 要查询的键@return 返回的值,如果不存在对应的值,则返回空Value*/Value* getValueForKey(const string& key);
};
#endif

StaticData.cpp

#include "StaticData.h"StaticData* StaticData::s_pInstance = nullptr;StaticData* StaticData::getInstance()
{if (s_pInstance == nullptr){s_pInstance = new StaticData();s_pInstance->init();}return s_pInstance;
}void StaticData::purge()
{SDL_SAFE_RELEASE_NULL(s_pInstance);
}StaticData::StaticData()
{
}StaticData::~StaticData()
{
}bool StaticData::init()
{//读取文件并保存键值对m_valueMap = FileUtils::getInstance()->getValueMapFromFile(STATIC_DATA_PATH);return true;
}Value* StaticData::getValueForKey(const string& key)
{auto iter = m_valueMap.find(key);if(iter != m_valueMap.end())return &iter->second;return nullptr;
}

静态数据即在程序运行期间不会发生改变的数据,其主要功能是提供一些外部文件的读取,比如static_data.plist文件的读取以及以后的角色升级属性文件等也由StaticData类提供。

DynamicData.h

#ifndef __DynamicData_H__
#define __DynamicData_H__
#include <string>
#include "SDL_Engine/SDL_Engine.h"using namespace std;
USING_NS_SDL;class DynamicData : public Object
{
private:static DynamicData* s_pInstance;
public:static DynamicData* getInstance();static void purge();
private:DynamicData();~DynamicData();
private://存档ValueMap m_valueMap;//存档名称string m_fullpath;//是否第一次进入游戏bool m_bFirstGame;//金币数目int m_goldNumber;//出售比例float m_sellRatio;
public://读取存档bool initializeSaveData(int idx);//获取角色mapValueMap& getValueMapOfCharacter();//获取地图文件路径string getMapFilePath() const;//获取角色对应位置Point getTileCoordinateOfPlayer() const;
};
#endif

DynamicData.cpp

#include "DynamicData.h"DynamicData* DynamicData::s_pInstance = nullptr;DynamicData* DynamicData::getInstance()
{if (s_pInstance == nullptr){s_pInstance = new DynamicData();s_pInstance->init();}return s_pInstance;
}void DynamicData::purge()
{SDL_SAFE_RELEASE_NULL(s_pInstance);
}DynamicData::DynamicData():m_bFirstGame(true),m_goldNumber(0),m_sellRatio(0.f)
{
}DynamicData::~DynamicData()
{
}bool DynamicData::initializeSaveData(int idx)
{auto fileUtil = FileUtils::getInstance();//获取存档路径string path = fileUtil->getWritablePath();//对应的存档完整路径string filepath = m_fullpath = StringUtils::format("%ssave%d.plist", path.c_str(), idx);//不存在对应存档,则使用默认存档if ( !fileUtil->isFileExist(m_fullpath)){filepath = "data/default_data.plist";m_bFirstGame = true;}elsem_bFirstGame = false;//获得对应存档的键值对m_valueMap = fileUtil->getValueMapFromFile(filepath);//获取有用的数据m_goldNumber = m_valueMap.at("gold").asInt();m_sellRatio = m_valueMap.at("sell_ratio").asFloat();//TODO:解析背包中的物品并生成Goodreturn true;
}ValueMap& DynamicData::getValueMapOfCharacter()
{return m_valueMap.at("character").asValueMap();
}string DynamicData::getMapFilePath() const
{return m_valueMap.at("map").asString();
}Point DynamicData::getTileCoordinateOfPlayer() const
{auto strPoint = m_valueMap.at("tile_position").asString();auto position = PointFromString(strPoint);return position;
}

DynamicData类主要功能就是负责动态数据的提供和更新,比如主角的金钱数目,主角所处的地图名和位置,背包物品以及主角的属性,穿戴的装备,技能(以后添加)等等。目前的DynamicData类主要就是负责读取存档。如果是第一次进行游戏的话,则使用默认存档,并解析出有用的属性,此为initializeSaveData函数所做的功能,且为了可扩展性,添加了一个idx形参,允许RPG游戏有不同的存档。

StaticData和DynamicData都为单例类,且为了保证其功能的单一性,这两个类都是只与数据相关,都不包含与渲染相关的功能。

本节运行界面如下:

本节代码:链接:https://pan.baidu.com/s/1MiB-b5AZUlDUlpHypxklxg 密码:z529

RPG游戏制作-01-搭建游戏框架,初进游戏世界相关推荐

  1. 技校计算机系游戏制作,计算机游戏制作教学质量怎么样_孙进技校模式新颖

    计算机游戏制作教学质量怎么样,孙进技校模式新颖,优秀教师李依.康超伟.谷龙.国亚娟等被评为香坊工匠.专业大师.社区厨神.市级专业技术拔尖人才标兵等荣誉称号. 计算机游戏制作教学质量怎么样, 主题创造性 ...

  2. Ruby‘s Adventrue游戏制作笔记(十七)Unity添加游戏胜利条件和失败条件和导出游戏

    Ruby's Adventrue游戏制作笔记(十七)Unity添加游戏胜利条件和失败条件和导出游戏 前言 一.添加两个相应的UI 二.导出游戏 系列链接 源代码和素材及游戏程序 前言 本文章是我学习U ...

  3. Unity3D游戏制作-----环境搭建

    目录 一.环境搭建 1.工具下载(有兴趣可以评论) 2.用户注册 2.添加许可证 3.添加游戏 4.正在下载配置 5.飞机大战游戏(简单版) 6.建模 一.环境搭建 1.工具下载(有兴趣可以评论) 2 ...

  4. python游戏制作rpg_用 Python 语言来写游戏

    原标题:用 Python 语言来写游戏 题图:拍摄于 R1 鸟巢发布会 每个程序员差不多都是从计算机爱好者开始的,尤其是那些令人心醉神迷的电脑游戏,不仅造就了整个游戏产业,推动了计算机行业软硬件的升级 ...

  5. 计算机游戏制作课程标准,计算机动漫与游戏制作专业《动漫绘画技巧》课程标准.doc...

    文档介绍: 计算机动漫与游戏制作专业<动漫绘画技巧>课程标准.doc计算机动漫与游戏制作专业<动漫绘画技巧>课程标准<动漫绘画技巧>课程标准一.概述(一) 课程性质 ...

  6. 微信小游戏制作大厅里的排行榜(跟游戏内的排行榜有区别)

    微信游戏大厅里的排行榜制作: var kvDataList = new Array(); var tempJson = {wxgame: {score: currentLevel, update_ti ...

  7. 怎样架设游戏服务器 怎样搭建一个属于自己的游戏服 5分钟学会游戏架设 3D手游搭建视频教程 自己做游戏GM

    直接视频教程-对照操作 [天使圣域 linux 架设教程] 大家都知道游戏外网联机需要服务器,这里给大家推荐一款很便宜的阿里云服务器,如果你手里己经有服务器,可以忽略! 其实服务器和电脑一样,内存越大 ...

  8. 2048游戏制作html,一个自制的2048小游戏(一)

    导语 本次将会从头到尾讲一个2048游戏的制作过程,中间也会穿插自己的理解 一.项目结构 除了html和css文件外,分了main.js,support.js,showanimation.js,以及引 ...

  9. html五子棋游戏制作原理,原生JS+Canvas实现五子棋游戏

    功能模块 先看下现在做完的效果: 代码详解 人机对战功能实现 从效果图可以看到,棋盘的横竖可以放的位置为15*15,通过canvas画棋盘: //绘画棋盘 var drawChessBoard = f ...

  10. 游戏制作之路(18)隐藏游戏里的鼠标

    前面介绍使用子弹来杀伤怪物,但是总是有一个鼠标在界面里显示,这样感觉起来非常不舒服,因为你玩别人的游戏时,发现这个鼠标没有显示的,并且不小心点了别的窗口,也会失去焦点.因此,下面就来解决这个问题.先按 ...

最新文章

  1. 要在 create-react-app 脚手架里使用 less 的方法
  2. 应用程序基础知识:activity和intent——Android开发秘籍
  3. 【笔记】Error while loading PyV8 binary: exit code 1解决方法
  4. 【原译】简单的Malloc实现
  5. tomact如何处理一个http请求?
  6. 【Java数据库】CLOB BLOB 在数据库中存入/取出大量文本数据、二进制文件(图片)
  7. flink 异步io使用
  8. GeneratedKeyHolder的作用:获得新建主键值
  9. win10修改服务器地址,win10 修改服务器地址
  10. python 收发邮件_python发送各类邮件的主要基本方法
  11. java中IO写文件工具类
  12. C++中回调函数(CALLBACK)初探
  13. sklearn knn 算法
  14. Linux视频编解码库,Ubuntu 18.04 FFMPEG最新版本安装总结
  15. 如何判断一个点在三角形内部
  16. java抽奖系统的设计参考文献,抽奖系统的设计与实现论文范文论文
  17. 热伤风和感冒有什么区别
  18. 【转】如何成为一名黑客--Eric Steven Raymond
  19. RTL概念与常用RTL建模
  20. 机械硬盘显示容量0字节要如何办啊

热门文章

  1. 11发布自己的镜像(阿里云)
  2. Stop worrying and start living
  3. WordPress缩略图出现A TimThumb error has occured解决办法
  4. mysql数据库系统时区_mysql 杂记 —— 时区问题
  5. ezw证件照芯片压缩算法
  6. 中国传统色的魅力|这8组中国风传统颜色你一定要收藏
  7. computed 和 watch的区别
  8. 工业相机基础知识详述 —— 焦平面,像平面,弥散圆,光圈,分辨率,景深,接口,靶面尺寸
  9. 爱签:如何在线签订电子合同
  10. 智源首席科学家孙茂松当选欧洲科学院外籍院士