范文健康探索娱乐情感热点
投稿投诉
热点动态
科技财经
情感日志
励志美文
娱乐时尚
游戏搞笑
探索旅游
历史星座
健康养生
美丽育儿
范文作文
教案论文
国学影视

游戏设计之路不来推推箱子么?

  大家好,失踪人口回归。新的一年,新的坑位(不是),今年就让我来带领小伙伴们一起设计一款独立游戏吧(*╹▽╹*)。
  言归正传,说起游戏,大家第一印象可能就是次时代主机,PC主机或手机上那些画面绚丽,剧情丰富的游戏:如《GTA系列》,《赛博朋克2077》,《梦幻西游》,《塞尔达传说》等等。但可惜的是,单单靠一个人,是不可能完成这样的大型游戏的。不是技术上的问题,而是人力与成本上的问题。
  但不要灰心,市面上也有很多仅靠1,2个人做出的很多精美的甚至获得国际大奖的独立游戏:如《小小梦魇》,《地狱边境》等等。
  但我们要记住:万丈高楼起于垒土。作为一个初学者,我们需要学习的知识还有很多。所以不要着急,让我们从地基开始,打好基础,一步一步地向最高峰发起进攻。
  一些题外话:游戏设计光靠一片热血是不行的,一些必备的基础知识则是必需的。例如基本的C++,JAVA等计算机语言的掌握,基本的开发环境的安装等。这里我默认读者是掌握了这些知识的。
  ·创建项目
  首先,我们需要在VS上创建一个空的控制台应用
  接着我们可以给项目取一个名字,这里我就叫这个小游戏为《回家吧-小箱子》
  项目名称为"GoHome_SmallBox"
  在项目创建成功后,我们可以看到VS自动为我们创建了一个GoHome_SmallBox.cpp文件 #include    int main() {     std::cout << "Hello World! "; }
  我们将上面的代码修改一下: #include  using namespace std;   int main() {     char c;     cin >> c;     cout << c;     return 0; }
  cin,cout都是istream类和ostream类的全局变量,我们在包含头文件iostream后,并声明using namespace std,就可以在任何位置使用了。
  cin通过>>将输入值写入变量c,cout通过<<将变量值c输出。
  对于大部分游戏程序来说,整个项目可以分为三步操作: while(true){ getInput(); // 获取键盘或者鼠标的输入信息 updateGame(); // 根据输入信息对游戏内容进行修改 draw(); // 对修改后的游戏内容进行绘制并输出结果 }
  ·游戏内容设计
  我们设定箱子为符号Y,箱子的最终目的地为符号X,当箱子到达目的地后,X变为Z,表示箱子成功回到家。而推动的小人则设定为P。
  思考:当我们设计好基本内容后,还需要进行进一步的思考 当P到达边界后,继续向边界移动会发生什么? 当P推动两个箱子时,会发生什么? 朝着边界推箱子,会发生什么?
  假如不解决上面的一些问题,我们直接进行编码实现的话,就会发现箱子有时候会飞出边界,人物P也会移动到边界之外。这样一来,就不符合我们所设定的游戏规则了。
  ·程序设计
  首先我们来定义一些基本的初始变量: // #表示墙壁,p表示玩家,X表示目的地,Y表示箱子 const char gSceneData[] = " ########  # XX p #  #  YY  #  #      #  ########"; const int gSceneWidth = 8; const int gSceneHeight = 5; enum Object {   OBJ_SPACE, // 空白空间   OBJ_WALL,  // 墙壁 #   OBJ_GOAL,  // 目标点 X   OBJ_BOX,   // 盒子 Y   OBJ_BOX_ON_GOAL,  // 盒子在目标点处 Z   OBJ_PLAYER,  // 玩家 p   OBJ_PLAYER_ON_GOAL,  //  玩家在目标点处 P   OBJ_UNKNOW  // 未知 };
  这里我把最初的初始场景数据放在了一个全局变量char数组gSceneData中。然后我们定义了一个枚举变量,这里面使用了几个枚举值描述了所有的游戏状态。
  接下就是我们的主循环的代码 int main() {   // 创建初始状态数组   Object* state = new Object[gSceneWidth * gSceneHeight];   // 初始化场景   initialize(state, gSceneWidth, gSceneHeight, gSceneData);   // 游戏主循环   while (true) {     // 绘制     draw(state, gSceneWidth, gSceneHeight);     // 通关检测     if (check(state, gSceneWidth, gSceneHeight)) {       break;     }     // 获取输入     cout << "w:向上;a:向左;s:向下;d:向右,请输入:" << endl;     char input;     cin >> input;     // 更新数据     update(state, input, gSceneWidth, gSceneHeight);   }   // 胜利后的信息   cout << "恭喜你成功过关!" << endl;   delete[] state;   state = 0;   return 0; }
  注意到其中调用到了下面四个方法: // 初始化方法 void initialize(Object* state, int w, int h, const char* sceneData) {   const char* index = sceneData;   int x = 0;   int y = 0;   while (*index != "") { // 当字符不为NULL时     Object t;     switch (*index) {     case "#": {       t = OBJ_WALL;       break;     }     case " ": {       t = OBJ_SPACE;       break;     }     case "X": {       t = OBJ_GOAL;       break;     }     case "Y": {       t = OBJ_BOX;       break;     }     case "Z": {       t = OBJ_BOX_ON_GOAL;       break;     }     case "p": {       t = OBJ_PLAYER;       break;     }     case "P": {       t = OBJ_PLAYER_ON_GOAL;       break;     }     case " ": { // 到下一行       x = 0; // x返回最左边       ++y; // y进入下一行       t = OBJ_UNKNOW; // t暂时无数据       break;     }     default: {       t = OBJ_UNKNOW; // t为非法数据     }     }     ++index;     if (t != OBJ_UNKNOW) { // 若t为非法数据,则略过       state[y * w + x] = t;// 向状态数据写入数据,这里的位置表示向下第y行,向右第x列的位置。这里是将一个二维数据存放在了一个一维数组里面       ++x;     }   } } // 绘制,将state数组的数据绘制在控制台中 void draw(const Object* state, int w, int h) {   // 按照枚举值的顺序定义该数组   const char front[] = { " ","#","X","Y","Z","p","P" };   for (int y = 0; y < h; ++y) {     for (int x = 0; x < w; ++x) {       Object o = state[y * w + x];       cout << front[o];     }     cout << endl;   } } // 通关检测 bool check(const Object* state, int w, int h) {   // 检查若没有盒子后,则通关   for (int i = 0; i < w * h; ++i) {     if (state[i] == OBJ_BOX) {       return false;     }   }   return true; } // 更新数据 void update(Object* state, char input, int w, int h) {   // 首先获取移动的变换量   int dx = 0;   int dy = 0;   // 这里我们注意一下,我们假设的是左上角为坐标原点,   // 那么向上移动,y则为-1;向下移动,y则为1,y轴正向为向下   // 向左移动,x为-1;向右移动,x为1   switch (input) {   case "a":dx = -1; break;// 向左移动   case "d":dx = 1; break;// 向右移动   case "w":dy = -1; break;// 向上移动   case "s":dy = 1; break;// 向下移动   }   // 查询玩家坐标,这里其实可以设置一个全局变量,记录上一次玩家所在位置,这样就不用每次来寻找一次玩家的位置   int i = -1;   for (i = 0; i < w * h; ++i) {     if (state[i] == OBJ_PLAYER || state[i] == OBJ_PLAYER_ON_GOAL) {       break;     }   }   int x = i % w;// 小人的x轴位置应当为i对宽度的余数   int y = i / w;// 小人的y轴位置应当为i对宽度的商     //玩家移动后的坐标   int tx = x + dx;   int ty = y + dy;   // 对玩家的位置进行判断   if (tx < 0 || ty < 0 || tx >= w || ty >= h) {     return;   }   // 移动位置为空白或者是目标点,则玩家移动   int p = y * w + x;// 玩家的位置   int tp = ty * w + tx;// 玩家移动后的位置   if (state[tp] == OBJ_SPACE || state[tp] == OBJ_GOAL) {     state[tp] = (state[tp] == OBJ_GOAL) ? OBJ_PLAYER_ON_GOAL : OBJ_PLAYER;// 若移动位置为目标点,则变为玩家站在目标点;否则则为玩家本身     state[p] = (state[p] == OBJ_PLAYER_ON_GOAL) ? OBJ_GOAL : OBJ_SPACE;// 若当前位置为目标点,则变为目标点;否则变为空白位置   }   else if (state[tp] == OBJ_BOX || state[tp] == OBJ_BOX_ON_GOAL) { // 如果移动位置为箱子,或者为箱子在目标点,并且箱子的下一个位置为空白或目标点,则可以移动     int tx2 = tx + dx;     int ty2 = ty + dy;     // 检查移动位置同方向的下一个位置是否为合法位置     if (tx2 < 0 || ty2 < 0 || tx2 >= w || ty2 >= h) { //按键无效       return;     }     int tp2 = ty2 * w + tx2;// 移动位置同方向上的下一个位置     if (state[tp2] == OBJ_SPACE || state[tp2] == OBJ_GOAL) {       // 按顺序更改三个位置的数据       state[tp2] = (state[tp2] == OBJ_GOAL) ? OBJ_BOX_ON_GOAL : OBJ_BOX;       state[tp] = (state[tp] == OBJ_BOX_ON_GOAL) ? OBJ_PLAYER_ON_GOAL : OBJ_PLAYER;       state[p] = (state[p] == OBJ_PLAYER_ON_GOAL) ? OBJ_GOAL : OBJ_SPACE;     }   } }
  好啦,今天的任务就算完成啦。但我们可以发现,这仅仅是一个初始版的游戏,还有很多可以优化改进的地方。那么我们下一次还将继续深入,对我们的第一个小游戏进行优化。
  谢谢阅读(*╹▽╹*)

2023为奋斗者加鸡腿!盛年不重来,一日难再晨。及时当勉励,岁月不待人,陶渊明的诗句总是让我们五味杂陈。时光荏苒,韶华易逝。不经意间,2023已经到来。站在新的起跑线上,每个人每家企业每个行业都在新年献词风情人事皆经历,欢喜触动存心底我的生活也是头条爱风景人事在经历,欢喜触动存心底!早说过我最大的欢喜,就是感恩有你。短暂的激情碰撞之后,依依不舍地告别。看着车越走越远,心里有好多不舍,今天我在笑,没有哭,眼泪却不把红尘烟雨付于余生最后一次回眸烟雨孤舟,承载了几多情深几许愁绪。红尘羁旅,辜负了一帘幽梦半月朦胧。林花谢了春红,冰雪辞去秋霜,流年里,错过了花期花语,失信了月圆月缺。时光清浅,渐次逝去,余生淡然,慵懒无意,偶尔鲜与鲜寻冬虫夏草冬虫夏草的最佳吃法是什么?冬虫夏草怎么吃?基本上注重养生的人都买过冬虫夏草,但是很多人会疑惑如何去吃冬虫夏草,担心如果没有用合适的方法去食用的话会影响其效果,害怕营养价值不能够被吸收。那么冬虫夏草的最佳吃法是什么?冬虫夏草linux常用命令之文档编辑cat命令在终端设备上显示文件内容cat命令来自于英文单词concatenate的缩写,其功能是用于查看文件内容。在Linux系统中有很多用于查看文件内容的命令,例如moretaiMC年度评选两款金士顿重磅新品获2022年度编辑选择奖时间匆匆流过,转眼又到了2022年年末,微型计算机2022年度硬件盘点在这个冬天如约而至。作为一年一度的重磅科技产品颁奖盛典,我们将与大家一起见证多项年度荣誉奖项的诞生,并为众多优动力电池回收江湖千亿的买卖,倒爷扎堆淘金转发来源未来汽车Daily作者崔秋阳编辑王妍当新能源汽车以迅猛势头在市场上攻城掠地,动力电池回收的热度也持续走高。如何处理废旧动力电池,在这个被行家视为千亿蓝海的市场里分得一杯羹,乐动力卡币商城迎跨年重头戏,卡币乐兑嘉年华活动今日上线随着全民健身与全民健康的不断融合,以运动促健康的理念逐渐深入人心,运动与激励的转换关系同样成为大家热议的话题。运动得卡币,卡币换权益。在乐动力平台的卡币商城,这不是一句平淡无奇的口湖北加速打造动力电池绿色增长极来源消费日报湖北正全力打造国内重要动力电池生产基地。记者从近日在湖北省荆门市召开的湖北省动力电池产业技改示范经验交流暨工业经济形势分析会上获悉,目前湖北省已集聚动力电池骨干企业50新架构突破能效边界,NV为玩家及创作者打造多款强动力笔记本电脑凭借最大的代际飞跃DLSS3和第五代MaxQ技术,GeForceRTX40系列笔记本电脑实现全新发烧级PC性能表现NVIDIACES硬件新闻今天,NVIDIA发布GeForceRT一席一果(二十二)佛手柑形似佛手,能止咳又能观赏的宝藏水果一席一果(二十二)佛手柑形似佛手,味美甘醇既能止咳又能观赏的宝藏水果老家有一种外形像柚子,划开里面没有果核和果肉的水果,我们叫香橼。每年秋冬时节,都会用来蘸蜂蜜吃,说是可以润肺止咳
曾经的世界第一美如今满身纹身!韩国论坛争议千楼,是她做错了吗演员纹身是错吗?近日,韩国女子组合afterschool成员出身的演员NANA(林珍娜)出席了在首尔广津区乐天影院建国大学入口店举行的电影自白制作报告会。报告会上,NANA身着黑色可以和不可以人的一生,应该有崇高的品德,高尚的情操,为祖国为人民建功立业。垂范百世,流芳千古,青史留名。为善则流芳百世,为恶则遗臭万年。民族英雄岳飞留芳百世,大汉奸秦桧遗臭万年。做人,可以行善秋夜随笔在我的后花园,可以看见两株树,一株是枣树,还有一株也是枣树。这是鲁迅先生秋夜里开头的一段句子。我不知道当时鲁迅的心情是怎样的,也体验不到他看完一株枣树,再看另一株枣树的感觉。是否与仅一夜之间,我的心判若两人嗨,晚上好,我是你们的情感小博主邮递员十三。今晚跟大家分享来自第419个故事。仅一夜之间,我的心判若两人。人间失格十三,你好,我想投稿,说说我的故事。我是一个内向的人,以前上学那会幼稚糊糊的人,总是喜欢去结交人脉,却不想着去提升自身的价值作家胡夫兰德说世上一切不利的影响中,最能使人功败垂成的,往往就是过度的情绪。生活里的苦,大多都是情绪种下的毒。人们往往控制不好自己情绪,容易冲动,容易暴躁,容易抱怨,时时刻刻都能让段廷水岸稻花香两山夹一水,稻花香两岸滚石经停处,寿阳小江南。第一次写段廷,是在今年的正月十三。那一天,古老的段廷瑞雪纷飞银妆素裹,别有一番景致。那时候,稻香在我飘逸的思绪里,在我期盼的梦境中。这夜之随笔在这个夜深人静的夜晚,除了一把摇头扇以外,便是发着诱人光亮的手机。端着手机,那是我们现代人之无可割舍的生命一部分了,翻开通讯软件的通讯录,却不知谁还在线,应该与谁聊天,内心彷徨且不盼你好的人是谁?人的一生,有许多亲情,亲情连绵不断,代代相传。人的一生,也有许多的友情,友情犹如纽带,连接着朋友间的友好感情。人间有爱,花香鸟语无限好,人间有情,山水相逢有可期。有人惦记,再远的路国庆期间来爬泰山的朋友请注意!泰山景区发布温馨提示关于国庆假日旅游服务的温馨提示为全面落实限量预约错峰总要求,统筹抓好疫情防控和经济运行,确保实现安全秩序质量效益文明五统一目标,现就泰山景区国庆长假旅游服务有关事宜提示如下。一游览人民日报金句选摘(8)1。不忘初心牢记使命,不负重托接续奋斗。2。凝心聚力创伟业,万众一心向未来。3。俯身拨开草丛,水珠轻轻抖落,沁润曾被染黑的土地。4。沧海横流显砥柱,万山磅礴看主峰。5。惟其艰难,方世间总有弱者被人欺世间有生命的地方,总会有强者与弱者。人也好,动物也好,弱肉强食已是自然的法则!人类随着文明的发展,早已脱去野蛮的外衣,那种凶残暴虐的真实场景,或许可以去动物世界观摩!从古至今到未来