目录

10-5:血量、尺寸偏移,遍历敌人数组

目录

安卓单机游戏绘制教程10-1:认识数组

单机安卓游戏绘制教程10-2:IDA找敌人数组相关函数思路(有符号so)

单机安卓游戏绘制教程10-3:IDA找敌人数组相关函数调用关系(有符号so)

单机安卓游戏绘制教程10-4:IDA找敌人数组基址偏移(有符号so)

本文是教程10的最后一篇:遍历敌人数组,

然后今天录一个视频,展示遍历敌人数组的效果(因为我怀疑专栏文章推送几率很低,似乎很多观众不知道有这几篇专栏),如果本系列专栏对你有收获,不妨给这个效果视频点点赞,谢谢啦~

教程系列视频、专栏点过赞的用户名我会记下来,将来会发些小福利(比如开发的软件优先对你们开放测试,诸如此类)

教程11是绘图部分,然后本系列教程就完结了,补前面视频字幕,然后打算讲讲正向开发的内容(比如Bash···如果有时间),或者是做编程科普类视频···

之前答应过,发单机CF(最后战役X)修复无法飞天BUG的思路,最后战役X的GG的Xa功能思路(高空掉落不掉血、一击必杀)、静默自瞄(时间待定)、骨骼绘制(待定),这些仍然会不定期更新。

回到主题,接下来把教程10剩下部分写了:

https://i0.hdslb.com/bfs/article/02db465212d3c374a43c60fa2625cc1caeaab796.png

关于坐标,从代码分析有些复杂了,直接Ctrl+B观察内存就行了,如图所示:

https://i0.hdslb.com/bfs/article/117935f20f03cc2ed53f14694f2ea503af224dad.png

https://i0.hdslb.com/bfs/article/6ce09b86512f88b25995c35b69867339fe914871.png

淡入淡出时间可以改大一些

淡入淡出我设置的6000ms,根据自己习惯改一下,

https://i0.hdslb.com/bfs/article/e05048eda9e8e9020d3d8beec8e6fd3b958f55f0.png

https://i0.hdslb.com/bfs/article/4806ebd0c8f49138a1fd93b4a47354c5d9e59e63.png

https://i0.hdslb.com/bfs/article/39e9e53cc7850fc0d976b8f4ac2a5bac29a1a8b8.png

https://i0.hdslb.com/bfs/article/02db465212d3c374a43c60fa2625cc1caeaab796.png

关于血量,敌人尺寸,可以看如图所示这个函数:

https://i0.hdslb.com/bfs/article/6cbff3bf70094e6c55c334013b729f66d462297d.png

GmSimInitAITanks

注意GmSimAiInitTankFromLevelTankData的参数一,已经相对结构体偏移了0x40,然后在这个函数能看到血量、大小等 初始化代码:

https://i0.hdslb.com/bfs/article/0e220ac07dec514ec994be34a753490fdf5591f5.png

由此可知,当前血量偏移:+0x40+0x4

最大血量偏移:+0x40+0x258

尺寸偏移:+0x40+0x214

v26可能表示“坦克种类”

另外,gAiHitPoints之类的是rodata段数据,可以双击跳转到如图所示:

https://i0.hdslb.com/bfs/article/bb36ad7757d0829fe566244f93c2e88c5b870cc2.png

可以理解成常量

https://i0.hdslb.com/bfs/article/02db465212d3c374a43c60fa2625cc1caeaab796.png

现在基址偏移全都拿到了,开始写C语言代码,为了接下来写起来方便,首先封装几个函数:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
uintptr_t readPtr(uintptr_t addr){
	lseek64(mem_fd, addr, SEEK_SET);
	read(mem_fd, &addr, sizeof(uintptr_t));
	return addr;
}

char readByte(uintptr_t addr){
	char res = 0;
	lseek64(mem_fd, addr, SEEK_SET);
	read(mem_fd, &res, sizeof(char));
	return res;
}

int readInt(uintptr_t addr){
	int res = 0;
	lseek64(mem_fd, addr, SEEK_SET);
	read(mem_fd, &res, sizeof(int));
	return res;
}

float readFloat(uintptr_t addr){
	float res = 0;
	lseek64(mem_fd, addr, SEEK_SET);
	read(mem_fd, &res, sizeof(float));
	return res;
}

void readData(uintptr_t addr, int len, void* target){
	lseek64(mem_fd, addr, SEEK_SET);
	read(mem_fd, target, len);
} 

关于这部分,可以参考我的这个视频:单机安卓手游绘制教程08-1:用读取文件的函数跨进程读内存

https://i0.hdslb.com/bfs/article/98db0c17c545dc1a93d1b3c91ec880b8121928e1.png

main函数

test函数代码:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
void test(){
	printf("test(): \n");

	uintptr_t gmc = readPtr(so_addr + 0x689CC);
	uintptr_t p1 = readPtr( gmc + 0x28 * readPtr(gmc + 0x120) + 0x20 );
	uintptr_t p2 = readPtr( p1 + 0x20 );
	uintptr_t p3 = readPtr( p2 + 0xB890 );
	uintptr_t p4 = readPtr( p3 + 0x20 );
	int count = readInt(p4 + 0x14) ;
	printf("遍历终止条件: i < %d\n", count);
	printf("\n");
	int i = 0;
	while( i < count){
		uintptr_t p5 = p4 + 0x2d4 * i ; //敌人i的结构体地址
		if( readByte(p5 + 0x48) ){
			//照着IDA F5之后的代码写就行了.
			printf("敌人id=%2d\tpos={%f,%f,%f}\tsize=%f\thp= %d/%d \n",
				i,
				readFloat(p5 + 0x19c),
				readFloat(p5 + 0x19c + 4),
				readFloat(p5 + 0x19c + 8),
				readFloat(p5 + 0x40 + 0x214),
				readInt(p5 + 0x40 + 0x4),
				readInt(p5 + 0x40 + 0x258)
			);

		}

		i++;
	}

} 作者:赶码人 https://www.bilibili.com/read/cv15051215?spm_id_from=333.999.0.0 出处:bilibili

最终效果请看视频吧~

做教程、写文章不容易,若有收获,欢迎给视频点赞~感谢鼓励。