当前位置: 首页 > news >正文

临淄网站建设yx718网站留言板作用

临淄网站建设yx718,网站留言板作用,aaa免费服务器,企业做网站要目录 前言一、环境配置二、基础框架三、关闭事件四、资源加载五、初始地图六、常量定义七、地图随机八、点击排雷九、格子类化十、 地图类化十一、 接口优化十二、 文件拆分十三、游戏重开 前言 各位小伙伴们#xff0c;这期我们一起学习出贪吃蛇以外另一个基础的项目——扫雷… 目录 前言一、环境配置二、基础框架三、关闭事件四、资源加载五、初始地图六、常量定义七、地图随机八、点击排雷九、格子类化十、 地图类化十一、 接口优化十二、 文件拆分十三、游戏重开 前言 各位小伙伴们这期我们一起学习出贪吃蛇以外另一个基础的项目——扫雷这个项目需要我们自己到网站下载一些需要用的库所以和贪吃蛇比起相对来说要复杂一点这期涉及到面向对象的知识还有文件拆分。 一、环境配置 首先要下载 SFMLhttps://www.sfml-dev.org/download/sfml/2.6.1/解压到本地放代码的文件夹。 因为我们需要#include SFML/Graphics.hpp这个头文件创建好一个项目我们在配置它的环境。点击项目右键属性选择这里的 C/C选择【附加包含目录】选择 SFML 的 include 目录点击确定。 然后点击 附加库 - 常规附加库目录选择 SFML 的 lib 目录 再点击下面的【输入】选择右边的【附加依赖项】把这些内容拷贝进去 这里需要注意对于 sfml-xxx-d.lib 是适用于 debug 模式的sfml-xxx.lib 是适用于 release 模式的 sfml-graphics-d.lib sfml-window-d.lib sfml-system-d.lib sfml-audio-d.lib opengl32.lib freetype.lib winmm.lib gdi32.lib 最后点击应用就配置完毕了。 然后再把 SFML-2.6.0\bin 目录下的 动态链接库文件 dll 都拷贝到项目目录下。 我们写个 main 函数来测试一下。 #include SFML/Graphics.hppint main() {sf::RenderWindow app(sf::VideoMode(816, 576), MineSweeper);while (app.isOpen()) {}return 0; }二、基础框架 1、命名空间 sf 是这个库的命名空间基本上所有的接口都是从这里取的利用两个冒号来获取相应的函数或者类如果不想写这段前缀呢我们可以和 std 一样在代码前面写上这么一句话 using namespace sf;这样一来这些前缀就都可以去掉了。 2、窗口创建 RenderWindow win(VideoMode(816, 576), MineSweeper);这段代码呢就是实例化了一个窗口对象RenderWindow 是一个类win 是一个对象名这一段就是有参构造函数的传参我们可以 F12 进去看它的定义。 这里的 VideoMode 也是一个类这两个参数是 VideoMode 构造函数的传参分别代表了窗口的宽高。 3、字符集 VideoMode 中构造函数的第二个传参是一个字符串代表了窗口的标题然后我们实现一个 while 循环。 while (win.isOpen()) {}并且循环条件是 win.isOpen() 为 True 这个函数的含义就是当窗口 win 被打开的时候就返回真那么一旦关闭就会返回假这时候程序就会结束掉我们来运行一下。 我们看到窗口左上角有个标题这时候我希望这个标题是中文的可以改下这个字符串。 三、关闭事件 #include SFML/Graphics.hpp #include iostream using namespace sf;int main() {RenderWindow win(VideoMode(816, 576), L扫雷);while (win.isOpen()) {Event e;while (win.pollEvent(e)) {if (e.type Event::Closed) {std::cout 按下关闭按钮 std::endl;win.close();}}}return 0; }四、资源加载 接下来我们准备好这么一张图片如果不会画图可以直接用我的这张图用画图工具打开以后大概是宽为 1152高为 96 的图片每个小格子的大小是 96 x 96。 1、纹理对象 首先我们创建一个纹理对象并且把这张图加载到内存中纹理是游戏开发中一个比较重要的概念可以理解成贴图 2D游戏中不同的对象让人能够产生不同的视觉效果就是利用不同的纹理实现的。 Texture t; t.loadFromFile(mine.png);2、精灵 然后我们再实例化一个精灵并且把刚才准备好的纹理对象作为初始化参数传给它。精灵可以这么去理解我拿到一个纹理的某一个矩形区域然后可以对它进行平移、缩放、旋转 等等变换然后绘制到屏幕上的这么一个东西我们叫它精灵。 Sprite s(t);在原先这张纹理贴图上(96, 0) 的坐标上取出一个 (96, 96) 的矩形并且设置坐标为 (16, 16)然后把它的缩放值设置为原来的 1/2 这样就变成了一个 48 x 48 的矩形然后调用 draw 接口绘制到 win 对象上面去这时候其实屏幕上还没有东西直到调用 display 以后才会真正把它绘制到窗口上。 可以这么去理解draw 调用完实际上还没有真正的绘制到窗口上只是把要画的内容画到了一张画布上面display 调用完才会最终把这张画布的内容一次性绘制到你的窗口上。 s.setTextureRect(IntRect(96, 0, 96, 96));s.setPosition(16, 16);s.setScale(Vector2f(0.5, 0.5));win.draw(s);win.display();接下来我们来写这么一段话 int r rand() % 12; s.setTextureRect(IntRect(96 * r, 0, 96, 96));随机一个 0 到 11 的数字然后让它乘上 96 去改变这个纹理矩形左上角的 x 坐标来看看效果你会发现每一帧都在改变图片而实际上 0 到 11 就代表了扫雷这个游戏中每个会用到的格子。 五、初始地图 定义一个 showGrid 的二维数组是一个 15 列 x 10 行 的地图代表实际显示出来的地图元素一开始都为 10 10 就是这个图片代表的是一个未知的元素。 int showGrid[16][11]; for (int i 1; i 15; i) {for (int j 1; j 10; j) {showGrid[i][j] 10;} }然后在绘制的时候遍历每一个地图元素处理精灵的纹理、位置以及缩放并且绘制到 win 这个对象上。 for (int i 1; i 15; i) {for (int j 1; j 10; j) {s.setTextureRect(IntRect(96 * showGrid[i][j], 0, 96, 96));s.setPosition(i * 48, j * 48);s.setScale(Vector2f(0.5, 0.5));win.draw(s);} }最终一次性展现到窗口上运行。这样我们就得到了一张初始的地图。 六、常量定义 这个时候我们发现有太多数字了这个我们叫它们 magic number很难看而且维护起来极其麻烦所以我们想办法把数字变成常量。 首先引入第一个常量 const int ORI_GRID_SIZE 96;它代表了在这张图片中每个格子的像素大小是 96。 const int GRID_SIZE 48;而 GRID_SIZE 呢则代表显示到窗口的时候每个格子实际的像素大小。 然后定义 MAP_COL 和 MAP_ROW 分别代表这个扫雷地图有多少列多少行 const int MAP_COL 15; const int MAP_ROW 10;然后把之前 15 和 10 的地方都替换掉注意下面有个 10 是不能替换因为含义不同 int showGrid[MAP_COL1][MAP_ROW1]; for (int i 1; i MAP_COL; i) {for (int j 1; j MAP_ROW; j) {showGrid[i][j] 10; // 这个10可不是 MAP_ROW} }遍历每个格子进行渲染 s.setScale(Vector2f(GRID_SIZE * 1.0 / ORI_GRID_SIZE, GRID_SIZE * 1.0 / ORI_GRID_SIZE)); for (int i 1; i MAP_COL; i) {for (int j 1; j MAP_ROW; j) {s.setTextureRect(IntRect(ORI_GRID_SIZE * showGrid[i][j], 0, ORI_GRID_SIZE, ORI_GRID_SIZE));s.setPosition(i * GRID_SIZE, j * GRID_SIZE);win.draw(s);} }而对于整个窗口大小可以是 格子数 乘上 列数 2左边加一列格子右边加一列格子上下也是一样的所以窗口大小可以定义成这样的常量 const int WIN_W GRID_SIZE * (1 MAP_COL 1); const int WIN_H GRID_SIZE * (1 MAP_ROW 1);最后showGrid 里面还有一个 10这个我们可以用枚举来实现 enum GridType {GT_EMPTY 0,GT_COUNT_1 1,GT_COUNT_2 2,GT_COUNT_3 3,GT_COUNT_4 4,GT_COUNT_5 5,GT_COUNT_6 6,GT_COUNT_7 7,GT_COUNT_8 8,GT_BOMB 9,GT_HIDE 10,GT_FLAG 11 };七、地图随机 showGrid 代表的是显示出来的格子类型所以再定义一个 grid代表真实的格子类型并且利用随机函数1/6 的概率是炸弹5/6的概率是空。 GridType grid[MAP_COL 1][MAP_ROW 1];GridType showGrid[MAP_COL1][MAP_ROW1];for (int i 1; i MAP_COL; i) {for (int j 1; j MAP_ROW; j) {showGrid[i][j] GridType::GT_HIDE;if (rand() % 6 0) {grid[i][j] GridType::GT_BOMB;}else {grid[i][j] GridType::GT_EMPTY;}}}定义周围的八个方向 const int DIR[8][2] {{-1, -1}, {-1, 0}, {-1, 1},{0, -1}, {0, 1},{1, -1}, {1, 0}, {1, 1}, };并且统计每个非炸弹的格子的周围八个方向进行计数从而改变当前格子的类型 for (int i 1; i MAP_COL; i) {for (int j 1; j MAP_ROW; j) {if (grid[i][j] GridType::GT_EMPTY) {int cnt 0;for (int k 0; k 8; k) {int ti i DIR[k][0];int tj j DIR[k][1];if (grid[ti][tj] GridType::GT_BOMB) {cnt;}}grid[i][j] (GridType)cnt;}}}然后只需要在显示之前把所有的实际格子内容赋值给对应的显示格子就相当于摊牌了。运行一下看看效果。 showGrid[i][j] grid[i][j];八、点击排雷 获取鼠标点击到的格子位置 Vector2i pos Mouse::getPosition(win); int x pos.x / GRID_SIZE; int y pos.y / GRID_SIZE;并且处理鼠标左键 和 鼠标右键 的 按下事件 if (e.type Event::MouseButtonPressed) {if (e.key.code Mouse::Left) {showGrid[x][y] grid[x][y];}else if (e.key.code Mouse::Right) {showGrid[x][y] GridType::GT_FLAG;} }最后如果当前的格子被确认是雷那么所有格子都公开游戏结束 if( showGrid[x][y] GridType::GT_BOMB) showGrid[i][j] grid[i][j];九、格子类化 接下来我们采用面向对象的思想来改造下这个代码首先是一个格子目前用了两个数据来存储一个是实际的格子类型一个是显示的格子类型我现在可以把它封装到一个类里面定义两个私有成员变量。 分别用 m_realGridType 和 m_showGridType 来表示。 然后实现它们的 set 和 get 成员函数。并且把相关代码也进行替换。 class Grid { public:Grid() {m_realGridType GridType::GT_EMPTY;m_showGridType GridType::GT_EMPTY;}void SetRealGridType(GridType realGType) {m_realGridType realGType;}void SetShowGridType(GridType realGType) {m_showGridType realGType;}GridType GetShowGridType() {return m_showGridType;}void ShowGrid() {m_showGridType m_realGridType;}bool IsEmpty() const {return m_realGridType GridType::GT_EMPTY;}bool IsRealBomb() const {return m_realGridType GridType::GT_BOMB;}bool IsShowBomb() const {return m_showGridType GridType::GT_BOMB;} private:GridType m_realGridType;GridType m_showGridType; };改造下初始化地图的代码 Grid grid[MAP_COL 1][MAP_ROW 1];for (int i 1; i MAP_COL; i) {for (int j 1; j MAP_ROW; j) {grid[i][j].SetShowGridType(GridType::GT_HIDE);if (rand() % 6 0) {grid[i][j].SetRealGridType(GridType::GT_BOMB);}else {grid[i][j].SetRealGridType(GridType::GT_EMPTY);}}}for (int i 1; i MAP_COL; i) {for (int j 1; j MAP_ROW; j) {if (grid[i][j].IsEmpty()) {int cnt 0;for (int k 0; k 8; k) {int ti i DIR[k][0];int tj j DIR[k][1];if (grid[ti][tj].IsRealBomb()) {cnt;}}if (cnt 0) {grid[i][j].SetRealGridType((GridType)cnt);}}}}改造下鼠标按键的代码 if (e.key.code Mouse::Left) {grid[x][y].ShowGrid();}else if (e.key.code Mouse::Right) {grid[x][y].SetShowGridType(GridType::GT_FLAG);}改造下渲染的代码 if( grid[x][y].IsShowBomb()) grid[i][j].ShowGrid();s.setTextureRect(IntRect(ORI_GRID_SIZE * grid[i][j].GetShowGridType(), 0, ORI_GRID_SIZE, ORI_GRID_SIZE));十、 地图类化 除了把格子用类来实现整个地图也可以用类来实现。 class Map { public:void init() {for (int i 1; i MAP_COL; i) {for (int j 1; j MAP_ROW; j) {grid[i][j].SetShowGridType(GridType::GT_HIDE);if (rand() % 6 0) {grid[i][j].SetRealGridType(GridType::GT_BOMB);}else {grid[i][j].SetRealGridType(GridType::GT_EMPTY);}}}for (int i 1; i MAP_COL; i) {for (int j 1; j MAP_ROW; j) {if (grid[i][j].IsEmpty()) {int cnt 0;for (int k 0; k 8; k) {int ti i DIR[k][0];int tj j DIR[k][1];if (grid[ti][tj].IsRealBomb()) {cnt;}}if (cnt 0) {grid[i][j].SetRealGridType((GridType)cnt);}}}}}void handleMouseEvent(Event e, int x, int y) {if (e.type Event::MouseButtonPressed) {if (e.key.code Mouse::Left) {grid[x][y].ShowGrid();}else if (e.key.code Mouse::Right) {grid[x][y].SetShowGridType(GridType::GT_FLAG);}}}void draw(RenderWindow win, Sprite s, int x, int y) {s.setScale(Vector2f(GRID_SIZE * 1.0 / ORI_GRID_SIZE, GRID_SIZE * 1.0 / ORI_GRID_SIZE));for (int i 1; i MAP_COL; i) {for (int j 1; j MAP_ROW; j) {if (grid[x][y].IsShowBomb())grid[i][j].ShowGrid();s.setTextureRect(IntRect(ORI_GRID_SIZE * grid[i][j].GetShowGridType(), 0, ORI_GRID_SIZE, ORI_GRID_SIZE));s.setPosition(i * GRID_SIZE, j * GRID_SIZE);win.draw(s);}}}private:Grid grid[MAP_COL 1][MAP_ROW 1]; };int main() {RenderWindow win(VideoMode(WIN_W, WIN_H), L扫雷);Texture t;t.loadFromFile(mine.png);Sprite s(t);Map mp;mp.init();while (win.isOpen()) {Vector2i pos Mouse::getPosition(win);int x pos.x / GRID_SIZE;int y pos.y / GRID_SIZE;Event e;while (win.pollEvent(e)) {if (e.type Event::Closed) {std::cout 按下关闭按钮 std::endl;win.close();}mp.handleMouseEvent(e, x, y);}mp.draw(win, s, x, y);win.display();}return 0; }十一、 接口优化 接下来我们来看这个地图类对外提供的接口只有三个了。一个是初始化一个是处理事件一个是渲染并且渲染接口每次都把 窗口 和 精灵 传进去实际上是没有必要的因为在这个大循环里这两个对象是不变的。 所以这两个对象实际上可以作为 Map 类的成员变量当然这里必须用指针。如果不传指针就会通过拷贝构造函数生成一个新的对象这不是我们想要的我需要它还是原来那个对象。 private:RenderWindow* win;Sprite* sprite;Grid grid[MAP_COL 1][MAP_ROW 1]; };然后修改 Map 类的初始化函数如下 void init(RenderWindow* win, Sprite* sprite) {this-win win;this-sprite sprite;... }mp.init(win, s);这里记住要传指针所以把 win 和 s 的地址传进去就好了。最后修改 draw 函数因为是指针所以所有的 . 变成 - 就好了 void draw(int x, int y) {sprite-setScale(Vector2f(GRID_SIZE * 1.0 / ORI_GRID_SIZE, GRID_SIZE * 1.0 / ORI_GRID_SIZE));for (int i 1; i MAP_COL; i) {for (int j 1; j MAP_ROW; j) {if (grid[x][y].IsShowBomb()) {grid[i][j].ShowGrid();}sprite-setTextureRect(IntRect(ORI_GRID_SIZE * grid[i][j].GetShowGridType(), 0, ORI_GRID_SIZE, ORI_GRID_SIZE));sprite-setPosition(i * GRID_SIZE, j * GRID_SIZE);win-draw(*sprite);}} }sprite 作为 RenderWindow 的成员函数 draw 的参数是一个对象所以采用 * 进行解引用。 十二、 文件拆分 这个时候我们发现这个文件行数太多了所以我们想办法把类拆到其它文件去。首先先把 Grid 类的内容拆出去新建一个 Grid.h 文件实现如下 #pragma onceenum GridType {GT_EMPTY 0,GT_COUNT_1 1,GT_COUNT_2 2,GT_COUNT_3 3,GT_COUNT_4 4,GT_COUNT_5 5,GT_COUNT_6 6,GT_COUNT_7 7,GT_COUNT_8 8,GT_BOMB 9,GT_HIDE 10,GT_FLAG 11 };class Grid { public:Grid() {m_realGridType GridType::GT_EMPTY;m_showGridType GridType::GT_EMPTY;}void SetRealGridType(GridType realGType) {m_realGridType realGType;}void SetShowGridType(GridType realGType) {m_showGridType realGType;}GridType GetShowGridType() {return m_showGridType;}void ShowGrid() {m_showGridType m_realGridType;}bool IsEmpty() const {return m_realGridType GridType::GT_EMPTY;}bool IsRealBomb() const {return m_realGridType GridType::GT_BOMB;}bool IsShowBomb() const {return m_showGridType GridType::GT_BOMB;} private:GridType m_realGridType;GridType m_showGridType; };然后在 main.cpp 里面写上这么一句话 #include “Grid.h” 这时候我们希望 .h 文件里面不要有函数的实现只保留声明。然后在源文件里新建一个 Grid.cpp 文件把函数的实现写在这个文件里。 #pragma onceenum GridType {GT_EMPTY 0,GT_COUNT_1 1,GT_COUNT_2 2,GT_COUNT_3 3,GT_COUNT_4 4,GT_COUNT_5 5,GT_COUNT_6 6,GT_COUNT_7 7,GT_COUNT_8 8,GT_BOMB 9,GT_HIDE 10,GT_FLAG 11 };class Grid { public:Grid();void SetRealGridType(GridType realGType);void SetShowGridType(GridType realGType);GridType GetShowGridType();void ShowGrid();bool IsEmpty() const;bool IsRealBomb() const;bool IsShowBomb() const; private:GridType m_realGridType;GridType m_showGridType; };Grid.cpp 如下 #include Grid.hGrid::Grid() {m_realGridType GridType::GT_EMPTY;m_showGridType GridType::GT_EMPTY; }void Grid::SetRealGridType(GridType realGType) {m_realGridType realGType; } void Grid::SetShowGridType(GridType realGType) {m_showGridType realGType; } GridType Grid::GetShowGridType() {return m_showGridType; } void Grid::ShowGrid() {m_showGridType m_realGridType; } bool Grid::IsEmpty() const {return m_realGridType GridType::GT_EMPTY; } bool Grid::IsRealBomb() const {return m_realGridType GridType::GT_BOMB; } bool Grid::IsShowBomb() const {return m_showGridType GridType::GT_BOMB; }同样在实现一个 Map.h 和 Map.cpp。 #pragma once#include SFML/Graphics.hpp #include Grid.h using namespace sf;class Map { public:void init(RenderWindow* win, Sprite* sprite);void handleMouseEvent(Event e, int x, int y);void draw(int x, int y);private:RenderWindow* win;Sprite* sprite;Grid grid[MAP_COL 1][MAP_ROW 1]; };#include Map.h #include Grid.hvoid Map::init(RenderWindow* win, Sprite* sprite) {this-win win;this-sprite sprite;for (int i 1; i MAP_COL; i) {for (int j 1; j MAP_ROW; j) {grid[i][j].SetShowGridType(GridType::GT_HIDE);if (rand() % 6 0) {grid[i][j].SetRealGridType(GridType::GT_BOMB);}else {grid[i][j].SetRealGridType(GridType::GT_EMPTY);}}}for (int i 1; i MAP_COL; i) {for (int j 1; j MAP_ROW; j) {if (grid[i][j].IsEmpty()) {int cnt 0;for (int k 0; k 8; k) {int ti i DIR[k][0];int tj j DIR[k][1];if (grid[ti][tj].IsRealBomb()) {cnt;}}if (cnt 0) {grid[i][j].SetRealGridType((GridType)cnt);}}}} }void Map::handleMouseEvent(Event e, int x, int y) {if (e.type Event::MouseButtonPressed) {if (e.key.code Mouse::Left) {grid[x][y].ShowGrid();}else if (e.key.code Mouse::Right) {grid[x][y].SetShowGridType(GridType::GT_FLAG);}} }void Map::draw(int x, int y) {sprite-setScale(Vector2f(GRID_SIZE * 1.0 / ORI_GRID_SIZE, GRID_SIZE * 1.0 / ORI_GRID_SIZE));for (int i 1; i MAP_COL; i) {for (int j 1; j MAP_ROW; j) {if (grid[x][y].IsShowBomb()) {grid[i][j].ShowGrid();}sprite-setTextureRect(IntRect(ORI_GRID_SIZE * grid[i][j].GetShowGridType(), 0, ORI_GRID_SIZE, ORI_GRID_SIZE));sprite-setPosition(i * GRID_SIZE, j * GRID_SIZE);win-draw(*sprite);}} }十三、游戏重开 然后一个游戏结束以后我们希望它能够重开在 Map 中引入一个私有成员变量 isRunning并且引入一个 initGame 的函数围绕 isRuning 进行逻辑修改。 一旦按到一个雷那么 isRuning 就从 true 变成 false然后左键按下的时候根据 isRunning 是 true 还是 false 做不同的处理如果为 true则保留原先的逻辑如果为 false则重新初始化游戏开始新的一局。 #include Map.h #include Grid.hvoid Map::init(RenderWindow* win, Sprite* sprite) {this-win win;this-sprite sprite; initGame(); }void Map::initGame() {this-isRunning true;for (int i 1; i MAP_COL; i) {for (int j 1; j MAP_ROW; j) {grid[i][j].SetShowGridType(GridType::GT_HIDE);if (rand() % 6 0) {grid[i][j].SetRealGridType(GridType::GT_BOMB);}else {grid[i][j].SetRealGridType(GridType::GT_EMPTY);}}}for (int i 1; i MAP_COL; i) {for (int j 1; j MAP_ROW; j) {if (grid[i][j].IsEmpty()) {int cnt 0;for (int k 0; k 8; k) {int ti i DIR[k][0];int tj j DIR[k][1];if (grid[ti][tj].IsRealBomb()) {cnt;}}if (cnt 0) {grid[i][j].SetRealGridType((GridType)cnt);}}}} }void Map::handleMouseEvent(Event e, int x, int y) {if (e.type Event::MouseButtonPressed) {if (e.key.code Mouse::Left) {if (isRunning) {grid[x][y].ShowGrid();if (grid[x][y].IsShowBomb()) {isRunning false;}}else {initGame();}}else if (e.key.code Mouse::Right) {grid[x][y].SetShowGridType(GridType::GT_FLAG);}} }void Map::draw(int x, int y) {sprite-setScale(Vector2f(GRID_SIZE * 1.0 / ORI_GRID_SIZE, GRID_SIZE * 1.0 / ORI_GRID_SIZE));for (int i 1; i MAP_COL; i) {for (int j 1; j MAP_ROW; j) {if (!isRunning) {grid[i][j].ShowGrid();}sprite-setTextureRect(IntRect(ORI_GRID_SIZE * grid[i][j].GetShowGridType(), 0, ORI_GRID_SIZE, ORI_GRID_SIZE));sprite-setPosition(i * GRID_SIZE, j * GRID_SIZE);win-draw(*sprite);}} }
http://www.dnsts.com.cn/news/199897.html

相关文章:

  • t恤定制网站哪个好网站开发代码归属
  • html5网站开发环境的搭建网站设计费报价表
  • 腾讯与中国联通长沙百度快照优化排名
  • 上海保洁服务网站建设做网站接专线费用
  • 杭州模板网站建设wordpress页面排版
  • 接网站开发外包东莞东城国际酒店
  • 网站开发的app莱芜金点子最新招聘信息招聘网
  • 做感恩网站的图片大全承德市宽城县建设局网站
  • thinkphp做网站有什么好处济南建站详情
  • 武进区住房和城乡建设局网站公明网站建设
  • 淮南网站seo天河微网站建设
  • 网站开发技术包括小程序推广网站
  • 做网站需要会哪些知识顺德网站建设咨询
  • 前端网站如何做全景图哈国际现货交易平台
  • 锦州网站建设渠道视频拍摄公司
  • 郑州网站建设商城定制轻创网
  • 娄底网站建设公司拟定网络设计方案
  • 网站程序的设计费用福州网站开发fjfzwl
  • 网站意识形态建设买微单的网站建设
  • 自己建网站收费吗电子元器件商城
  • 烟台网站优化推广网站空间转移
  • 策划案网站云南软件开发公司
  • 网站域名解析时间网站虚拟主持人代码
  • 公司网站制作知乎怎么制作网站设计
  • 网站建设费会计处理quark搜索引擎入口
  • wordpress作企业网站好吗企业网站建设 毕业设计
  • dw做网站模版高德地图导航放弃重庆
  • 建个官方网站要多少钱建设网站赚钱
  • 网站开发多少人广告设计公司简介模板范文
  • 北京网站设计制作关键词北京建设教育协会