深圳大学计算机游戏开发实验5 游戏中的人工智能

2024-01-30 14:30

本文主要是介绍深圳大学计算机游戏开发实验5 游戏中的人工智能,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

目录

一、实验目的与要求

二、实验内容与方法

1.完成游戏编译

2.完成修改内容一 

3.完成修改内容二 

4.完成修改内容三 

5.完成修改内容四 

6.完成Bug修改

7.添加配乐、音效

8. 游戏优化升级

三、实验步骤与过程

1. 完成游戏编译并修改游戏名称和窗口大小。

2. 添加DANGEROUS区域。

3. 增加按键监听,当按下R键时,游戏重新开始。

4. 添加地图层次,将迷宫地图设置为两层。

5. 修改游戏中出现的Bug。

Bug1:点击smile所处的位置会显示“No Way!”,按照正常逻辑,宝箱出现的位置与smile相同应该成功找到宝箱才对。

Bug2:点击笑脸出现“No Way” 和“Found Treasure”文字的叠加。这是因为代码中只是简单地向场景中添加Label,而显示新的Label时,原来的Label不会被清除。

Bug3:smile精灵和box精灵的碰撞矩阵太大,相隔一个图块的情况下,程序将其判定为碰撞。

Bug4:当距离危险区域只剩一个图块时,点击进入危险区域,不会显示危险区域提示。

Bug5:下方的“Click Map To Put Treasure”文字无法完全显示。

6. 为游戏添加配乐和音效。

 7. 优化游戏。

优化1:增加迷宫地图层数至4层和增加返回上一层的楼梯。

优化2:显示当前smile位于哪一层地图。

优化3:显示smile的得分,每次找到一个宝箱加一分。

四、实验结论或心得体会


一、实验目的与要求

1. 理解A*寻路算法原理。

2. 进一步熟悉地图编辑器的使用。

3. 实现游戏中的人工智能。

二、实验内容与方法

1.完成游戏编译

成功编译并运行教材P200“游戏AI实例-迷宫寻宝”。

2.完成修改内容一 

修改游戏代码,实现修改内容一,即修改窗口大小。

3.完成修改内容二 

修改游戏代码,实现修改内容二,即增加DANGEROUS区域。

4.完成修改内容三 

修改游戏代码,实现修改内容三,即增加按键监听。

5.完成修改内容四 

修改游戏代码,实现修改内容四,即增加地图层次。

6.完成Bug修改

通过更改游戏代码的方式修复BUG,如:点击笑脸出现“No Way” 和“Found Treasure”的叠加。

7.添加配乐、音效

为游戏添加配乐、音效。

8. 游戏优化升级

自行发挥想象力,优化游戏功能。

三、实验步骤与过程

1. 完成游戏编译并修改游戏名称和窗口大小。

(1)创建游戏项目,详细步骤见我的实验1的文章。

(2)根据地图文件中显示的地图的宽度、高度、图块宽度和高度信息,计算出地图的宽为32 x 32=1024,高为20 x 32=640。如下图所示,aStar.h文件中定义的3个变量也证明了这一点。

 

(3) 在AppDelegate.cpp中,将游戏窗口大小改为1024x640。

static cocos2d::Size designResolutionSize = cocos2d::Size(1024, 700);

2. 添加DANGEROUS区域。

(1)使用Tiled打开地图文件,在地图中添加危险区域的图块,四个图块的编号分别是251、252、275和276。

(2)在aStar.h中定义两个新的变量DANGEROUS和NOT_DANGEROUS,表示方块是否为危险区域,然后在mapNode结构体中添加一个新的成员变量isdangerous,用于记录当前节点是否为危险区域。

#define DANGEROUS 7   //方格是否为危险区域
#define NOT_DANGEROUS 8//定义节点结构:
struct mapNode
{int status;           //节点的状态标志int isdangerous;       //节点是否为危险区域int xCoordinate;	   //节点的横、纵坐标int yCoordinate;int fValue;		   //节点的f值,g值,h值int gValue;int hValue;mapNode* parent;    //节点的父节点指针
};

 (3)在MazeScene类的initMap函数中,遍历地图每一个图块时,先通过getTileGIDAt函数获取当前的图块编号,如果图块编号是251、252、275或276时,表示当前图块为危险区域,将当前图块的结构体mapNode的isdangerous的值设为DANGEROUS,否则设为NOT_DANGEROUS。

//依次扫描地图数组每一个单元for (int i = 0; i< MAP_WIDTH; i++){for (int j = 0; j< MAP_HEIGHT; j++){int temp_isdangerous = NOT_DANGEROUS;//危险区域if (m_mapLayer->getTileGIDAt(Vec2(i, j)) == 251 || m_mapLayer->getTileGIDAt(Vec2(i, j)) == 252|| m_mapLayer->getTileGIDAt(Vec2(i, j)) == 275 || m_mapLayer->getTileGIDAt(Vec2(i, j)) == 276|| m_mapLayer->getTileGIDAt(Vec2(i, j)) == 169 || m_mapLayer->getTileGIDAt(Vec2(i, j)) == 170|| m_mapLayer->getTileGIDAt(Vec2(i, j)) == 185 || m_mapLayer->getTileGIDAt(Vec2(i, j)) == 186){temp_isdangerous = DANGEROUS;//CCLOG("dangreous\n");}//若当前位置为墙体瓦片设置为不可通过if (m_mapLayer->getTileGIDAt(Vec2(i, j)) == NOT_ACCESS_TILE|| m_mapLayer->getTileGIDAt(Vec2(i, j)) == NOT_ACCESS_TILE1){mapNode temp={NOT_ACCESS,temp_isdangerous, i, j, 0, 0, 0, nullptr };m_map[i][j] = temp;}//否则设置为可以通过else{mapNode temp={ ACCESS,temp_isdangerous, i, j, 0, 0, 0, nullptr };m_map[i][j] = temp;}}}

(4)在MazeScene类的移动路径moveOnPath函数中,定义一个变量dangerous_num记录危险区域在当前路径上的编号,当路径中出现危险区域时,立即记录该编号,否则为默认值-2,由于此时路径是从终点向起点遍历的,所以一定能够获取到smile第一次遇到危险区域时的编号。

//危险区域在当前路径上的编号int dangerous_num = -2;while (tempNode != nullptr){//判断是1否存在危险区域if (tempNode->isdangerous == DANGEROUS){dangerous_num = loopNum;}path[loopNum].x = tempNode->xCoordinate;path[loopNum].y = tempNode->yCoordinate;loopNum++;tempNode = tempNode->parent;}

在遍历路径的结构体数组时,将结构体的编号和dangerous_num进行比较,如果相等表示存在危险区域,显示危险区的提示文字,并直接退出遍历。

 (5)运行程序,当smile移动路线上有危险区域时,显示“Dangerous! You die!”文字,路径被危险区域阻挡,无法移动至新的区域。

3. 增加按键监听,当按下R键时,游戏重新开始。

(1)在MazeScene类的init函数中调用EventListenerKeyboard类的create函数定义变量listener,使用onKeyReleased函数为监听器添加键盘事件,当按下R按键时,调用replaceScene函数重新加载场景,最后调用addEventListenerWithSceneGraphPriority函数设置键盘监听优先级。

//增加R按键监听auto listener = EventListenerKeyboard::create();listener->onKeyReleased=[&](EventKeyboard::KeyCode code, Event* e){switch (code){case EventKeyboard::KeyCode::KEY_R:Director::getInstance()->replaceScene(this->createScene());break;default:break;}};Director::getInstance()->getEventDispatcher()->addEventListenerWithSceneGraphPriority(listener, this);

4. 添加地图层次,将迷宫地图设置为两层。

(1)使用Tiled设计一个1024x640的新地图,由于图块元素太多会让代码写起来更复杂,因此我让不可通行的区域用同一种图块,这样代码写起来比较简洁。

接着我新建一个图层覆盖在其上面,这个图层仅仅起到让地图更加美观的作用。

最后的地图效果如下图所示,图中白色的草为危险区域,绿色、黄色图块和桥都是可通行区域,水域和墙面都是不可通行区域。

(2)在MazeScene类中添加两个新的成员变量,一个用于记录当前游戏进入第几层的迷宫,另一个变量用于判断smile是否位于楼梯。

//位于第几层迷宫int map_layer = 0;//是否位于楼梯bool is_starts_up = false;

(3)修改MazeScene类的init函数,当map_layer等于0时,加载第一层的地图,当map_layer等于1时,加载第二层的地图。

(4)修改MazeScene类的initMap函数,在危险区域和不可通过区域的判断条件中添加第二层的地图对应的图块编号。

//危险区域if (m_mapLayer->getTileGIDAt(Vec2(i, j)) == 251 || m_mapLayer->getTileGIDAt(Vec2(i, j)) == 252|| m_mapLayer->getTileGIDAt(Vec2(i, j)) == 275 || m_mapLayer->getTileGIDAt(Vec2(i, j)) == 276|| m_mapLayer->getTileGIDAt(Vec2(i, j)) == 169 || m_mapLayer->getTileGIDAt(Vec2(i, j)) == 170|| m_mapLayer->getTileGIDAt(Vec2(i, j)) == 185 || m_mapLayer->getTileGIDAt(Vec2(i, j)) == 186){temp_isdangerous = DANGEROUS;//CCLOG("dangreous\n");}//若当前位置为墙体瓦片设置为不可通过if (m_mapLayer->getTileGIDAt(Vec2(i, j)) == NOT_ACCESS_TILE|| m_mapLayer->getTileGIDAt(Vec2(i, j)) == NOT_ACCESS_TILE1){mapNode temp={NOT_ACCESS,temp_isdangerous, i, j, 0, 0, 0, nullptr };m_map[i][j] = temp;}

 (5)当点击的图块为楼梯时,应该不显示宝箱。在MazeScene类的onTouchBegan中,要为点击的地图单元添加宝箱精灵,通过getTileGIDAt函数获取点击的图块的编号,如果其编号为4即楼梯,就通过setVisible函数将宝箱精灵设为不可见,并将is_starts变量设为true。

//在当前地图单元添加宝箱精灵auto box = this->getChildByTag(BOX_TAG);box->setPosition(0.5 * UNIT + x * UNIT, m_visibleSize.height - 0.5 * UNIT - y * UNIT);box->setVisible(true);
//终点为楼梯if (m_mapLayer->getTileGIDAt(Vec2(x, y)) == 4){box->setVisible(false);is_starts_down = true;}

(6)在MazeScene类的update函数中,通过intersectsRect函数判断smile是否到达宝箱的位置,如果到达宝箱的位置,通过is_starts的值判断目的地是否为楼梯,如果为楼梯,则根据map_layer的值判断进入下一层还是回到第一层,最后调用removeAllChildren函数将本类的所有子节点移除,并调用init函数重新初始化场景,这样就能加载新的地图。

5. 修改游戏中出现的Bug。

Bug1:点击smile所处的位置会显示“No Way!”,按照正常逻辑,宝箱出现的位置与smile相同应该成功找到宝箱才对。

(1)在MazeScene类的aStar函数中,通过判断OPEN表是否为空来判断寻路失败与否,但是当点击的位置正好就是smile所处的位置时,OPEN表也是空的,因此,此时要判断起点m_origin和终点destination的x,y坐标是否相同,如果相同,就不显示“No Way”文字。

	//循环检验8个方向的相邻节点while (checkNeighboringNodes(map, open, open->openNode, destination)){//从OPEN表中选取节点插入CLOSED表insertNodeToClosedList(close, open);//若OPEN表为空,表明寻路失败if (open == nullptr){//点击自身不显示no wayif (m_origin->xCoordinate != destination->xCoordinate&& m_origin->yCoordinate != destination->yCoordinate)
Bug2:点击笑脸出现“No Way” 和“Found Treasure”文字的叠加。这是因为代码中只是简单地向场景中添加Label,而显示新的Label时,原来的Label不会被清除。

(1)在MazeScene类定义3个变量,分别表示3种情况下要显示的Label的TAG。

#define TIP_TAG 5
#define WAY_TAG 6
#define DANGEROUS_TAG 7

(2)在MazeScene类的init函数中,添加3种情况下要显示的文字,并且调用setVisible函数将Label设为不可见。

//预置找到宝箱的提示,将其设置为不可见auto successTip = Label::createWithBMFont("fonts/futura-48.fnt", "Found Treasure!");successTip->setPosition(m_visibleSize.width / 2, m_visibleSize.height / 2);this->addChild(successTip, 2,TIP_TAG);successTip->setVisible(false);//预置屏幕中央显示寻路失败的提示auto failedTip = Label::createWithBMFont("fonts/futura-48.fnt", "No Way!");failedTip->setPosition(m_visibleSize.width / 2, m_visibleSize.height / 2);this->addChild(failedTip, 2, WAY_TAG);failedTip->setVisible(false);//预置屏幕中央显示危险区的提示auto dangerousTip = Label::createWithBMFont("fonts/futura-48.fnt", "Dangerous! You die!");dangerousTip->setPosition(m_visibleSize.width / 2, m_visibleSize.height / 2);this->addChild(dangerousTip, 2, DANGEROUS_TAG);dangerousTip->setVisible(false);

(3)在要显示文字的时候,通过getChildByTag获取3个Label的实例,然后通过setVisible将要显示的Label设为可见,其他两个Label设为不可见。

//显示寻路成功的标签提示auto tip1 = this->getChildByTag(TIP_TAG);auto tip2 = this->getChildByTag(WAY_TAG);auto tip3 = this->getChildByTag(DANGEROUS_TAG);tip1->setVisible(true);tip2->setVisible(false);tip3->setVisible(false);
Bug3:smile精灵和box精灵的碰撞矩阵太大,相隔一个图块的情况下,程序将其判定为碰撞。

(1)这实际上是因为MazeScene类的update中判断smile精灵是否移动到box精灵位置的条件中使用了getBoundingBox获取的矩形,这个区域太大了,不符合要求。

 (2)其实smile和box精灵的位置是根据地图图块像素和地图宽高计算出来的,因为是用的同样的计算方法,所以它们在每个相同图块中对应的实际位置也是相同的,只需要用getPosition函数获取其实际坐标进行比较即可。

//如果笑脸精灵达到宝箱位置if ( smile->getPosition().equals( box->getPosition() ) )
Bug4:当距离危险区域只剩一个图块时,点击进入危险区域,不会显示危险区域提示。

(1)这实际上是因为在MazeScene类的moveOnPath函数中,结构体的是从loopNum-2开始扫描的,即直接扫描其下一个图块,而我的判断条件是j-1,当只差一个时,loopNum值为2,此时不满足危险区域条件,这是我代码设计的漏洞。

(2)如下图所示,让结构体的扫描从loopNum-1开始,这样smile移动的第一个位置变成其当前所处的位置,这样即使相差一个图块也能让j-1的判断条件生效了。

	//从结构体数组尾部开始扫描for (int j = loopNum - 1; j >= 0; j--)
Bug5:下方的“Click Map To Put Treasure”文字无法完全显示。

(1)将窗口高度改为700,这样就能让文字完全显示了。

(2)尝试运行程序,成功让文字完全显示。

6. 为游戏添加配乐和音效。

(1)将背景音乐和音效要使用的文件添加到Resources文件夹中。

(2)由于要让背景音乐在切换地图时不重新播放,要在MazeScene类的createScene方法中加载背景音乐并且循环播放,预加载3个音效。

//bgmSimpleAudioEngine::getInstance()->preloadBackgroundMusic("boss1_bgm.wav");SimpleAudioEngine::getInstance()->playBackgroundMusic("boss1_bgm.wav", true);//音效SimpleAudioEngine::getInstance()->preloadEffect("found.wav");SimpleAudioEngine::getInstance()->preloadEffect("press.wav");SimpleAudioEngine::getInstance()->preloadEffect("wrong.wav");

 (3)接着添加开启和关闭背景音乐的按钮,创建关闭和开启音乐的Button的实例,将两个按钮的位置设置在右下角,然后调用setVisible函数将开启音乐按钮设置为不可见。

//按钮Button* button_v = Button::create("Chapter11/v_btn.png","Chapter11/v_btn.png");Button* button_nv = Button::create("Chapter11/nv_btn.png","Chapter11/nv_btn.png");button_v->setScale(0.5);button_nv->setScale(0.5);button_v->setPosition(Vec2(Vec2(visibleSize.width - 20, 20)));button_nv->setPosition(Vec2(Vec2(visibleSize.width - 20, 20)));//隐藏button_nv->setVisible(false);scene->addChild(button_v, 113);scene->addChild(button_nv, 113);

(4)添加触摸事件,当按下关闭音乐按钮时,调用setVisible函数将关闭音乐按钮设置为不可见,开启音乐按钮设置为可见,接着调用SimpleAudioEngine类的stopBackgroundMusic函数关闭背景音乐。

接着为开启按钮添加触摸事件,按下按钮时,将关闭音乐按钮设置为可见,开启音乐按钮设置为不可见,接着调用SimpleAudioEngine类的playBackgroundMusic函数播放背景音乐。

//关闭bgmbutton_v->addTouchEventListener([button_v, button_nv](Ref* sender, Widget::TouchEventType type){switch (type){case cocos2d::ui::Widget::TouchEventType::BEGAN:break;case cocos2d::ui::Widget::TouchEventType::MOVED:break;case cocos2d::ui::Widget::TouchEventType::ENDED:button_nv->setVisible(true);button_v->setVisible(false);SimpleAudioEngine::getInstance()->stopBackgroundMusic();SimpleAudioEngine::getInstance()->stopAllEffects();bgm = false;break;}});//开启bgmbutton_nv->addTouchEventListener([button_v, button_nv](Ref* sender, Widget::TouchEventType type){switch (type){case cocos2d::ui::Widget::TouchEventType::BEGAN:break;case cocos2d::ui::Widget::TouchEventType::MOVED:break;case cocos2d::ui::Widget::TouchEventType::ENDED:button_v->setVisible(true);button_nv->setVisible(false);SimpleAudioEngine::getInstance()->playBackgroundMusic("2D MUSIC LOOP.wav", true);bgm = true;break;}});

(5)在按钮的触摸事件中直接使用stopAllEffects函数无法关闭音效,因为音效不是一直播放的,只播放几秒钟的时间,因此我在aStar类中添加一个静态变量控制音效的开关,当关闭按钮的触摸事件触发时,其值为false,当开启按钮的触摸事件触发时,其值为true。

static bool bgm;

(6)添加“no way”和“dangerous”时的音效,在MazeScene类的aStar函数中会通过判断OPEN表是否为空来判断寻路是否成功,如果寻路失败则使用stopAllEffects函数停止正在播放的音效,然后根据静态bgm的值判断是否通过playEffect函数播放音效。

//音效SimpleAudioEngine::getInstance()->stopAllEffects();if (bgm){SimpleAudioEngine::getInstance()->playEffect("wrong.wav", false);}

在MazeScene类的moveOnPath函数中,判断路径中存在危险区域时,也要以同样的规则播放音效。

//判断是否存在危险区域if (j - 1 == dangerous_num){//音效SimpleAudioEngine::getInstance()->stopAllEffects();if (bgm){SimpleAudioEngine::getInstance()->playEffect("wrong.wav", false);}

(7)添加寻宝成功的音效,因为寻宝成功的文字是在smile到达宝箱位置时才显示,所以音效也要在此时播放。先在MazeScene类中添加一个成员变量is_found,用来判断是否播放寻宝成功的音效。

	//音效bool is_found = false;

MazeScene类的aStar函数寻路成功时,就要将is_found的值改为true。

在MazeScene类的update函数中,当smile到达宝箱位置时,要在bgm和is_found的值都为true的情况下才播放寻宝成功的音效,并将is_found的值重新改为false。

(8)添加鼠标点击的音效,在MazeScene类的onTouchBegan函数中根据bgm的值判断是否播放音效即可。

 7. 优化游戏。

优化1:增加迷宫地图层数至4层和增加返回上一层的楼梯。

(1)在Tiled创建两个新的地图superMaze3.tmx和superMaze4.tmx,并用如下图所示的图块分别表示“返回上一层”和“进入下一层”,并且第一层地图只有向下的楼梯,第四层地图只有向上的楼梯。

 

 (2)在MazeScene类的init函数中,根据map_layer的值判断加载哪一层的地图,并且每个地图的主图层都是“layer1”。

//载入地图,将放置到适当位置TMXTiledMap* tileMap;switch (map_layer){case 0:tileMap = TMXTiledMap::create("Chapter11/superMaze1.tmx");break;case 1:tileMap = TMXTiledMap::create("Chapter11/superMaze2.tmx");break;case 2:tileMap = TMXTiledMap::create("Chapter11/superMaze3.tmx");break;case 3:tileMap = TMXTiledMap::create("Chapter11/superMaze4.tmx");break;default:break;}tileMap->setPosition(0, m_visibleSize.height - MAP_HEIGHT * UNIT);this->addChild(tileMap, 1);//获取地图中的主图层m_mapLayer = tileMap->getLayer("layer1");//初始化地图数组initMap();

(3)在MazeScene类添加成员变量is_starts_up和is_starts_down,用于判断smile是否位于楼梯图块。

	//是否位于楼梯bool is_starts_up = false;bool is_starts_down = false;

(4)当点击的图块为楼梯时,应该不显示宝箱。在MazeScene类的onTouchBegan中,通过getTileGIDAt函数获取点击的图块的编号,如果其编号为4即向下楼梯,就通过setVisible函数将宝箱精灵设为不可见,并将is_starts_down变量设为true,如果编号为61,将is_starts_up变量设为true。

//终点为楼梯if (m_mapLayer->getTileGIDAt(Vec2(x, y)) == 4){box->setVisible(false);is_starts_down = true;//不得分goal--;}else if (m_mapLayer->getTileGIDAt(Vec2(x, y)) == 61){box->setVisible(false);is_starts_up = true;//不得分goal--;bgm = true;}

(5)在MazeScene类的update函数中,通过intersectsRect函数判断smile是否到达宝箱的位置,如果到达宝箱的位置,通过is_starts_down和is_starts_dp的值判断目的地是否为楼梯,如果为向下楼梯,则进入下一层,map_layer值加一,如果为向上的楼梯,则返回上一层,map_layer值减一,最后调用removeAllChildren函数将本类的所有子节点移除,并调用init函数重新初始化场景,这样就能加载新的地图。

//判断是否到达楼梯if (is_starts_down){map_layer++;//移除所有结点,重新初始化this->removeAllChildren();this->init();is_starts_down = false;}else if (is_starts_up){map_layer--;//移除所有结点,重新初始化this->removeAllChildren();this->init();is_starts_up = false;}
优化2:显示当前smile位于哪一层地图。

(1)在MazeScene类的init函数中添创建一个Label的实例,用于显示地图层数,将map_layer+1的值显示在游戏左下角。

//显示地图层数和得分auto layerTip = Label::createWithBMFont("fonts/futura-48.fnt", "Map Layer: "+Value(map_layer+1).asString());layerTip->setPosition(130, 0.5 * (m_visibleSize.height - MAP_HEIGHT * UNIT));layerTip->setScale(0.8);this->addChild(layerTip, 1);
优化3:显示smile的得分,每次找到一个宝箱加一分。

(1)在MazeScene类中添加2个新的成员变量,一个用于记录当前的分数,一个用于显示当前的分数。

	//得分int goal = 0;Label* goalTip;

(2)在MazeScene类的init函数中添创建一个Label的实例,用于显示当前得分,将goal的值显示在游戏右下角。

 goalTip = Label::createWithBMFont("fonts/futura-48.fnt", "Goal: " + Value(goal).asString());goalTip->setPosition(m_visibleSize.width-150, 0.5 * (m_visibleSize.height - MAP_HEIGHT * UNIT));goalTip->setScale(0.8);this->addChild(goalTip, 1);

因为得分会变化,所以要在MazeScene类的update函数中将新的goal的值赋予Label。

void MazeScene::update(float delta)
{auto smile = this->getChildByTag(SMILE_TAG);auto box = this->getChildByTag(BOX_TAG);//更新得分goalTip->setString("Goal: " + Value(goal).asString());

(3)在MazeScene类的aStar函数中,更新goal的值。当寻路成功时,goal值加一。

(4)当点击楼梯或者危险区域时,根据我设计的代码逻辑,也会将goal值加一,这显然错误的,因此,我在判断是否为楼梯和是否为危险区域的代码中添加一行“goal--”,这样就能让goal的值保持不变了。

四、实验结论或心得体会

在本次实验中,我成功运行了“迷宫寻宝”游戏,增加了DANGEROUS区域、1层新的迷宫地图和游戏配乐与音效,设计了进入下一层地图和返回上一层地图的机制,修改了5个bug。在这些基础上,我还优化了游戏,将地图层数增加到了4,添加了显示地图层数和得分的功能。通过本次实验,我熟练掌握了添加游戏配乐与音效的方法,学习了使用多个图层绘制地图的技巧。

本次实验比较简单,读懂代码之后就非常容易上手了,游戏的Bug比较少,修改起来非常简单。实验最复杂的部分是地图的绘制,如果想要设计比较美观的地图需要花费较长时间,设计地图可以使用多个图层,第一个图层可以作为代码逻辑判断的依据,在这一层规定哪些图块是可通过的,哪些是不可通过的,其他图层会覆盖第一层,因此这些图层的功能仅仅是美化地图,这样达到代码简洁,地图美观的效果,这个地图设计的技巧是我本实验最大的收获。

这篇关于深圳大学计算机游戏开发实验5 游戏中的人工智能的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/660536

相关文章

这15个Vue指令,让你的项目开发爽到爆

1. V-Hotkey 仓库地址: github.com/Dafrok/v-ho… Demo: 戳这里 https://dafrok.github.io/v-hotkey 安装: npm install --save v-hotkey 这个指令可以给组件绑定一个或多个快捷键。你想要通过按下 Escape 键后隐藏某个组件,按住 Control 和回车键再显示它吗?小菜一碟: <template

基于人工智能的图像分类系统

目录 引言项目背景环境准备 硬件要求软件安装与配置系统设计 系统架构关键技术代码示例 数据预处理模型训练模型预测应用场景结论 1. 引言 图像分类是计算机视觉中的一个重要任务,目标是自动识别图像中的对象类别。通过卷积神经网络(CNN)等深度学习技术,我们可以构建高效的图像分类系统,广泛应用于自动驾驶、医疗影像诊断、监控分析等领域。本文将介绍如何构建一个基于人工智能的图像分类系统,包括环境

Hadoop企业开发案例调优场景

需求 (1)需求:从1G数据中,统计每个单词出现次数。服务器3台,每台配置4G内存,4核CPU,4线程。 (2)需求分析: 1G / 128m = 8个MapTask;1个ReduceTask;1个mrAppMaster 平均每个节点运行10个 / 3台 ≈ 3个任务(4    3    3) HDFS参数调优 (1)修改:hadoop-env.sh export HDFS_NAMENOD

嵌入式QT开发:构建高效智能的嵌入式系统

摘要: 本文深入探讨了嵌入式 QT 相关的各个方面。从 QT 框架的基础架构和核心概念出发,详细阐述了其在嵌入式环境中的优势与特点。文中分析了嵌入式 QT 的开发环境搭建过程,包括交叉编译工具链的配置等关键步骤。进一步探讨了嵌入式 QT 的界面设计与开发,涵盖了从基本控件的使用到复杂界面布局的构建。同时也深入研究了信号与槽机制在嵌入式系统中的应用,以及嵌入式 QT 与硬件设备的交互,包括输入输出设

OpenHarmony鸿蒙开发( Beta5.0)无感配网详解

1、简介 无感配网是指在设备联网过程中无需输入热点相关账号信息,即可快速实现设备配网,是一种兼顾高效性、可靠性和安全性的配网方式。 2、配网原理 2.1 通信原理 手机和智能设备之间的信息传递,利用特有的NAN协议实现。利用手机和智能设备之间的WiFi 感知订阅、发布能力,实现了数字管家应用和设备之间的发现。在完成设备间的认证和响应后,即可发送相关配网数据。同时还支持与常规Sof

活用c4d官方开发文档查询代码

当你问AI助手比如豆包,如何用python禁止掉xpresso标签时候,它会提示到 这时候要用到两个东西。https://developers.maxon.net/论坛搜索和开发文档 比如这里我就在官方找到正确的id描述 然后我就把参数标签换过来

Linux_kernel驱动开发11

一、改回nfs方式挂载根文件系统         在产品将要上线之前,需要制作不同类型格式的根文件系统         在产品研发阶段,我们还是需要使用nfs的方式挂载根文件系统         优点:可以直接在上位机中修改文件系统内容,延长EMMC的寿命         【1】重启上位机nfs服务         sudo service nfs-kernel-server resta

计算机毕业设计 大学志愿填报系统 Java+SpringBoot+Vue 前后端分离 文档报告 代码讲解 安装调试

🍊作者:计算机编程-吉哥 🍊简介:专业从事JavaWeb程序开发,微信小程序开发,定制化项目、 源码、代码讲解、文档撰写、ppt制作。做自己喜欢的事,生活就是快乐的。 🍊心愿:点赞 👍 收藏 ⭐评论 📝 🍅 文末获取源码联系 👇🏻 精彩专栏推荐订阅 👇🏻 不然下次找不到哟~Java毕业设计项目~热门选题推荐《1000套》 目录 1.技术选型 2.开发工具 3.功能

【区块链 + 人才服务】区块链集成开发平台 | FISCO BCOS应用案例

随着区块链技术的快速发展,越来越多的企业开始将其应用于实际业务中。然而,区块链技术的专业性使得其集成开发成为一项挑战。针对此,广东中创智慧科技有限公司基于国产开源联盟链 FISCO BCOS 推出了区块链集成开发平台。该平台基于区块链技术,提供一套全面的区块链开发工具和开发环境,支持开发者快速开发和部署区块链应用。此外,该平台还可以提供一套全面的区块链开发教程和文档,帮助开发者快速上手区块链开发。

Vue3项目开发——新闻发布管理系统(六)

文章目录 八、首页设计开发1、页面设计2、登录访问拦截实现3、用户基本信息显示①封装用户基本信息获取接口②用户基本信息存储③用户基本信息调用④用户基本信息动态渲染 4、退出功能实现①注册点击事件②添加退出功能③数据清理 5、代码下载 八、首页设计开发 登录成功后,系统就进入了首页。接下来,也就进行首页的开发了。 1、页面设计 系统页面主要分为三部分,左侧为系统的菜单栏,右侧