您听说过吸血鬼吗? 不管答案如何-欢迎来到他的任期!在本文中,我想告诉您我为Android创建游戏的故事。 根据读者的能力,我传达的经验,思想和决定或多或少会有用。 但是,我希望至少我的故事会有趣。
目录内容
1.
简介2.
资金选择3.
项目构想4.
我给一只乌贼喝5.
基础知识-项目结构6.
吸血鬼迷宫的产生并与之合作7.
存储游戏消息及其输出给玩家8.
第一个结果9.
即使是小游戏也值得历史。10.
吸血鬼转化和最终结果11.
结论1.简介
目录内容首先,关于您自己的几句话。 不幸的是,编程不是我的主要活动,但我很乐意将自己的空闲时间投入其中。
由于某种原因,我选择了创建手机游戏的方式。 我以前的移动设备项目是在Qt环境中与QML和C ++语言一起创建的。 我从这三人中获得了极大的乐趣,但是,在分析自己的想法时,我意识到,将来以我所知道的方法解决某些问题将花费太多的时间和精力。 因此,考虑下一个项目,我决定寻找新的,更合适的开发工具并从中获得经验。
2.资金选择
目录内容以前,我只关注Android,在新项目中,我决定专注于此OS,了解其原生的Android Studio,为自己尝试新的Java(并且在将来,如果您喜欢它,也希望Kotlin)。
我以前从未使用过AS或Java,并且面对许多新任务需要面对巨大的工作,因此我随时准备着手进行战斗,只是想出一个项目而已。
3.项目构想
目录内容众所周知,最重要的是,培训是针对实际任务进行的,尤其是那些有趣的任务。 对我来说,这样的培训项目应该成为一款游戏,为此我提出了许多要求:
- 重播价值。
- 游戏机制的简单性。
- 最少使用图形。
- 游戏玩法应迫使玩家思考。
- 游戏聚会应该不长。
- 快速实施项目(2个月)。
- UI的简单性和易用性。
整理了许多选择并客观地评估了我的长处之后,我想起了无论开始时花了多少时间和资源,实际上都要花很多时间,我得出的结论是,最好将经过测试的经典作为基础而不是发明自己的东西。 我绝对不想制造条件蛇,因此我开始研究旧游戏。 于是我发现了好奇的亨特·沃普斯。
4.我给一只乌贼喝
目录内容Vampus Hunting是由Gregory Yob于1972年发明的经典文字游戏。同年,他在杂志文章中对这款游戏进行了描述,并提供了源代码。
游戏的本质是玩家研究十二面体迷宫(这是邪恶的吸血鬼的故乡),并尝试根据游戏日志中显示的指示信息猜测位于顶层房间的迷宫。 除了吸血鬼本人(发出难闻的气味)外,还有蝙蝠(听到噪音)将玩家运送到一个随机的房间,并进站(穿透),击中导致比赛结束。 游戏的目标是杀死吸血鬼,玩家有5个箭头,可以一次从1个房间飞到5个房间(玩家自己决定要进行射击的“强度”)。 因此,玩家有两个动作:从弓箭射击,进入房间。 结果将取决于运气和意识程度。
总的来说,我喜欢这种机制:它很简单,但同时又带有风险元素。 Google Play上的Vampus上没有有趣的游戏(当时Lovecraft世界中有一款新鲜的游戏,但后来我发现它是基于相同的Vampus机制制作的。但是
本文是关于在Habré上创建游戏的),因此被接受以吸血鬼为基础的决定。 我设定了保留经典游戏的目标,但略作更新并添加了新功能。
5.基础知识-项目结构
目录内容首先,我学习了经典游戏的规则并熟悉了各种Vampus实现。 然后我用游戏的逻辑(可点击)制作了一个图表:
最初,该方案很有用,因为 允许分析游戏的机制,消除缺陷并自行制造东西。 而且,当我后来与艺术家一起解释游戏的本质时,这种方案派上了用场。
我将项目分为四个部分,每个部分都解决了不同的任务。 我只会给他们一些。
1.游戏机制- 有关地牢的信息将以什么形式存储?
- 您需要什么类型和多少个变量?
- 编写算法:组成地牢,吊杆飞行,检查射击结果,使用错误选择的房间顺序进行吊杆飞行,移动玩家,移动时检查房间,用蝙蝠移动玩家等。
- 如何以什么顺序在游戏日志中显示信息?
- 以什么顺序检查房间?
2.用户界面- 申请中应开展哪些活动? 它们应该看起来如何,应该包含哪些元素?
- 可以在设置中更改哪些参数?
- 我需要游戏中的图像吗?
- 通常,应用程序的样式是什么(颜色,心情,消息样式)?
- 使用什么字体?
3.其他- 连接到Google Play服务
- 处理XML文件
- 使用什么字体?
4.编写游戏文字描述所有内容是没有必要的,而不是没有可能的,因此,我将仅关注某些点,然后说明获得的第一个结果。
6.吸血鬼迷宫的产生并与之合作
目录内容吸血鬼迷宫是十二面体,可以表示为尺寸为20x20的矩阵
G。 我们将顶点从0编号为19。如果矩阵元素为1,则在顶点(房间)之间有一个通道,否则为否。
我们还引入了一个20×3
N的矩阵,该矩阵存储每个房间的邻居索引。 此矩阵将加快使用
G的速度
。矩阵
G和
N被缝在游戏代码中,并且不会改变(当然,存储
G是不必要的,因为您只能使用
N ,但现在就这样吧)。 这些是一劳永逸的十二面体的“真实”顶点指数。 对于玩家而言,将“游戏”索引形成
为维度20的向量
V ,这是“真实”索引的一种掩饰,如下所示:
因此,获得以下图片:
每个新游戏都会形成向量V,从而为玩家提供了一个“新”地牢。
为了建立“真实”和“游戏”房间索引之间的对应关系,使用了
indByNmb转换方法:
public byte indByNmb(int room) { byte ind = -1; for (byte i = 0; i < V.length; i++) { if (V[i] == room) { ind = i; break; } } return ind; }
在输入处,
indByNmb方法获取房间
房间的“游戏”索引,在输出处,其给出“ true”
ind 。
生成了地牢的结构后,我们放置:2组蝙蝠,2个孔,一个吸血鬼和一个玩家:
byte[] randomRooms = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19}; for (int i = 0; i < 20; i++) { int tmpRand = random.nextInt(20); byte tmpVar = randomRooms[i]; randomRooms[i] = randomRooms[tmpRand]; randomRooms[tmpRand] = tmpVar; } P = randomRooms[0]; W = randomRooms[1]; Pits[0] = randomRooms[2]; Pits[1] = randomRooms[3]; Bats[0] = randomRooms[4]; Bats[1] = randomRooms[5];
这样的放置确保了一个房间中不会有两个居民,而且玩家从一开始就不会被扔到房间里去吸血鬼。
完整的地牢生成如下:
现在,您可以实现游戏机制的所有算法。 因此,例如,当玩家使用
currentRoom索引
进入房间时,就会发生相邻房间的输出:
public void printNearRooms(byte currentRoom) { byte ind = indByNmb(currentRoom); appendText(V[N[ind][0]], V[N[ind][1]], V[N[ind][2]]); }
在输入处,
printNearRooms方法获取
currentRoom房间的当前“游戏”索引。
考虑示例的机制。 让玩家移到新房间,然后出现一条消息:“现在我在房间8中”。 数字8是游戏指数。 房间的“真实”索引为6(请参见上面的屏幕截图)。 该代码专门用于“ true”索引,即 6.对于6,确定“真实”邻居的指数:2、5、7。“游戏”的指数分别是:10、0、7。我们在日志中显示玩家:“我可以去10、0、7房间”。
因此,通过将向量
V形成每个新游戏并使用迷宫图的“真”和“游戏”索引,可以创建每个游戏都是唯一的事实的外观。
多亏了
appendText函数
,消息以指定的时间间隔显示。 我们待会儿见。
这是检查房间是否靠近老鼠的示例:
public boolean isBatsNear() { boolean answer = false; byte indP = indByNmb(P); for (int i = 0; i < 3; i++) { if ((V[N[indP][i]] == Bats[0]) || (V[N[indP][i]] == Bats[1])) { answer = true; break; } } return answer; }
7.存储游戏消息及其输出给玩家
目录内容经典游戏是玩家与游戏机之间互动的过程,即 游戏纯粹是文字游戏。 我想保存此功能,以便将所有游戏消息分解成块,例如:
- 新游戏的第一条消息。
- 玩家移动时的消息。
- 信息在坑附近。
- 移动吸血鬼时的消息。
- 掉进洞里的消息。
文本存储在XML文件中。 为了各种游戏玩法,每个块都有几个消息选项。
如果相邻房间之一中有孔,将显示一个消息块的示例:
<string name="g_pitsNear_1">— \n</string> <string name="g_pitsNear_2">— \n</string> <string name="g_pitsNear_3">— \n</string> <string name="g_pitsNear_4">— , \n</string> <string name="g_pitsNear_5">— \n</string> <string-array name="g_pitsNear"> <item>@string/g_pitsNear_1</item> <item>@string/g_pitsNear_2</item> <item>@string/g_pitsNear_3</item> <item>@string/g_pitsNear_4</item> <item>@string/g_pitsNear_5</item> </string-array>
通过这种结构,您可以轻松地编辑现有消息或添加新消息,而不会影响Java代码。
例如,如果在检查房间时,前面显示的
isBatsNear方法返回
true ,那么我们从XML获取所需的消息块,然后随机将其中一个作为
appendText的参数:
if (isBatsNear()) { String[] g_batsNear = getResources().getStringArray(R.array.g_batsNear); appendText(g_batsNear[random.nextInt(g_batsNear.length)]); }
游戏消息被输出到控制台,该控制台是一个
TextView对象。 让我们看一下
appendText方法。
public void appendText(final String str) { msgBuffer.add(str); if (!isTimerGameMsgWork) { mTimerGameMsg.run(); isTimerGameMsgWork = true; } }
当需要显示游戏消息时,将
调用appendText方法,该方法将其作为参数。 在方法本身中,首先将一行添加到
msgBuffer缓冲区。 接下来是检查布尔变量
isTimerGameMsgWork 。 当
mTimerGameMsg计时器
启动时,它接受
true 。 当此计时器工作时,然后根据FIFO原则(先进先出)从
msgBuffer缓冲区中
接收消息,并以指定的间隔
mIntervalGameMsg接收消息,并将消息添加到游戏日志
-txtViewGameLog中 。
完整的消息输出代码:
代号 ArrayList<String> msgBuffer = new ArrayList<>(); Handler mHandlerGameMsg; private int mIntervalGameMsg = 1000; boolean isTimerGameMsgWork = false; public void appendText(final String str) { msgBuffer.add(str); if (!isTimerGameMsgWork) { mTimerGameMsg.run(); isTimerGameMsgWork = true; } } final Runnable mTimerGameMsg = new Runnable() { @Override public void run() { if (msgBuffer.size() == 0) { mHandlerGameMsg.removeCallbacks(mTimerGameMsg); isTimerGameMsgWork = false; } else { txtViewGameLog.append(msgBuffer.get(0)); msgBuffer.remove(0); mHandlerGameMsg.postDelayed(mTimerGameMsg, mIntervalGameMsg); } } };
8.第一个结果
目录内容经过一个月的开发,该游戏的第一个可玩版本具有完全实现的功能。 我附上截图:
在显示的屏幕截图上,您可以看到:主菜单,规则窗口,设置窗口,游戏窗口。
当然,我知道结果完全没有意思。 最主要的是我获得了AS和Java的实践经验,这是第一个任务。
与经典游戏一样,玩家必须通过控制台进行交互:输入要移动的房间号或箭头飞行的路线。 在设置中,我可以更改字体大小和背景的透明度。 我假设每个游戏窗口都有自己的图片背景(为了使游戏玩法稍微多样化,哈哈!)。
接下来,我计划用艺术家绘制的图像替换现有的图像(我从互联网上不道德地拍摄)。 然后,我将游戏发布到Play市场,并放心地将其忘却,并将获得的经验应用到新项目中。 然后我无法想象吸血鬼会改变多少...
9.即使是小游戏也值得历史。
目录内容当一个人与灵魂一起工作时,该项目只会从中受益。 我很幸运,艺术家
Anastasia Frolikova竟然是这样的人。 即 她不仅画了我需要的东西,还对游戏世界产生了兴趣,并想了解它的工作原理。 突然之间,事实证明,总体上没有和平! 这个吸血鬼是谁? 玩家为什么要杀死他? 吸血鬼房间是什么样的? 依此类推,依此类推,我没有考虑过,也没有打算告诉玩家。 结果,我们同意,即使是一个看似很小的游戏也应该有自己的故事。 她出现了。
根据我们的传说,吸血鬼虽然古老,却不是一个喜欢取笑人的邪恶神话生物。 是的,他住在迷宫中,但这个迷宫不是经典的阴沉地牢,而是一堆难以想象的房子,其中包括一堆房间,其中的内容就是吸血鬼的特征。 因此,例如,在其中一个房间中有一个电影院,墙上有他最喜欢的电影的海报,在另一个房间中有他的壁橱,他在准备他的“恶作剧”。
一位来自无名猎人的玩家变成了密码学论坛的常客,他想证明吸血鬼的存在。 我们用照相机和胶卷代替了经典的弓箭,游戏的目的不是杀死Vampus,而是得到他的照片。 顺便说一句,主菜单已重做一个论坛,供人们讨论吸血鬼,玩家可以从讨论中了解它。
至于其他方面,它们几乎保持不变:鼠标的行为方式相同,进入漏洞开始导致崩溃,相机故障和游戏结束(而不是玩家死亡)。
关于相机的另一刻。 在经典游戏中,玩家可以在1到5个房间的范围内射箭,看起来很合逻辑。 我们有一个摄像头,而不是弓形相机(一次拍摄1到3个房间的照片,但是就像打到吸血鬼的经典箭头一样工作)。 那看起来很奇怪,不是吗? 有一种想法是将摄像机范围缩小到一个房间,以便只能拍摄下一个房间,但是,这首先使游戏变得复杂,其次,当无法赢得游戏时会出现这种情况,这是错误的。 通常,这是我个人仍然困扰的时刻,但我尚未找到解决方案。
关于游戏的风格和气氛。 几乎所有有关吸血鬼的游戏都是用无聊的灰色调制作的,动作发生在地下城的黑暗地方。 因此,我们决定我们的游戏应该与此不同,并以幽默和鲜艳的色彩来完成。
10.吸血鬼转化和最终结果
目录内容然后又有2个月的游戏工作在等我们。 由于Vampus有20个房间,每个房间都有自己的内部。 此外,绘制了成就的图标,游戏中的图标,并就总体设计和UI做出了决策。 还添加了整个游戏文本,对代码进行了补充和优化,添加了新功能(例如,出现了一个记事本,用于在游戏过程中记录信息)。 总的来说,吸血鬼发生了重大变化。
例如,房间的创建如下:

有20个房间,所有房间都是唯一的,玩家在每次游戏中都会收到一个“新”迷宫。 如何将每个新的游戏图片附加到新房间? 最简单的方法是使用相同的“ true”和“ game”索引方法:
public void changeImgOfRoom() { ImageView img = findViewById(R.id.imgRoom); int ind = indByNmb(P); String imgName = "room_" + ind; int id = getResources().getIdentifier(imgName, "drawable", this.getPackageName()); Glide.with(this) .load(id) .transition(DrawableTransitionOptions.withCrossFade()) .into(img); }
正方形格式的图片(以减少在不同屏幕上查看时的失真)存储在名称为[room_0; 房间_1; ...,room_19]。 实际上,它们与“真实的”十二面体索引相关联,但是对于玩家来说,同一个房间的每个新游戏将具有不同的图片。 为什么需要这个? 为了让特定的游戏聚会有机会将文字信息与特定房间的图像相关联(“是的,我记得在X室,这是客厅,有一个草稿”),但并没有得出“为什么它总是在我的房间里”的信息X是同一张图片吗?” 多样化和对播放器有帮助的一切(但是,经验显示,视觉记忆并没有帮助,使用文本更有效)。
最终,我们获得了游戏的新版本。 你知道吗? 吸血鬼变得非常吸引人,最重要的是,它仍然是经典的吸血鬼,只是在一个舒适的新房子里!
在屏幕截图上:主菜单,规则窗口,设置窗口,游戏窗口。
在机械方面,它只是稍作修改和重命名(实际上,有什么区别:如果需要执行相同的操作,是摄像机还是弓?)。 机械方面最明显的变化是简化了玩家与游戏之间的交互过程-删除了使用键盘输入房间号的经典方法。 现在,要在房间之间切换,您需要在弹出窗口中选择3个数字中的1个,并形成拍照的“路线”,只需滚动感光鼓上的轮子即可:
在下面的视频中,您可以看到最终结果:
11.结论
目录内容我在一个月的开发中就收到了游戏的第一版,下班后要花1-2个小时。 同时,我以前都不熟悉AS和Java。 游戏的第二版又花了两个月的时间。 因此,只有3个月的休闲时间。
当然,这种形式的游戏范围不广,因为 对于现代玩家来说,这看起来似乎并不复杂,但并不令人兴奋,但更重要的是,也许可以保持经典游戏的精神,是吗?
我对结果满意吗? 绝对可以。 我在编程和团队合作方面都积累了很多经验。 我既喜欢游戏的结果机制,也喜欢它的视觉组件。 我有什么想改变的吗? 当然,完美无极限,您可以随时添加/改进某些东西,但不能永远做到这一点!
这个游戏有趣吗? 好吧,这不是我决定的。 但是,让吸血鬼在我们为他建造的房子中以极大的爱和关怀感到舒适。
祝你成功!
谢谢您,提防吸血鬼!
PS不断出现的任务和解决它们的乐趣正是我喜欢编程的目的。 希望您能获得更多的快乐。