个人关于存储不同类型对象进行碰撞检测的一些思路

(声明:以下面向对象思路是基于C++和2D图形的)

在代码量较小的程序中,我们可能会直接把所有需要的对象的碰撞检测封装在类当中,然后在

角色移动等动作的渲染过程中进行自动的碰撞检测,但这样的做法有个弊端,那就是我们已知了需求,

而我们如果需要扩展程序,则需要不断的在类内部进行添加,这样的做法显然破坏了程序的扩展性,

使得代码难以使用,因此我们需要该角色的类对外提供一个接口,利用这个接口,将那些需要进行

碰撞检测的对象进行检测,然后进行角色的移动等动作的渲染。

但是这里有一个问题,因为碰撞检测的对象并不是唯一的,特别是自定义的怪物类对象,地图对象等,

更是不尽相同的,如果我们为每个对象都提供一个多态版本的对外碰撞检测接口,那么随着需要碰撞检测

类型对象的增多,这些多态函数的数目也会增多,这样一来会使程序更加的累赘,二来会不断的修改角色

类中碰撞检测的内容,使得角色类的通用型,可扩展性和简洁性降低,这样的做法并不比原来好上多少,

因此我们需要换个思路。

一个更有效的做法是在类内部存储一种作为容器的数据结构,然后在该类的public当中提供获得该数据

容器对象的接口,然后在外部环境中,将需要碰撞检测的对象不断插入到该容器数据结构中。而在该角色

类内部,则通过碰撞检测函数不断遍历该容器中的元素,从而实现碰撞检测的功能,这样一来我们就能将

角色类从纷繁复杂中分离出来,从而实现更加模块化的功能。

但是这里依旧有一个问题没有解决,那就是容器中需要存储不同类型的数据结构对象来提供碰撞检测。

对于此,我们可以这样来处理,我们并不存储太过具体的对象,如怪物类,地图类等。我们只存储一些碰撞

检测中用到的比较本源的东西,例如矩形,圆形,三角形对象等,而在那些比较具体的对象中统一提供这些

碰撞检测区域的接口。利用这种方法,我们可以把碰撞检测的类型减缩到个位数,使原来复杂的问题变的

简单化了。但仅仅是这样还是不够的,如果我们分别用矩形,圆形,三角形的容器存储,那么我们就需要

提供三个对外的接口来分别接收不同类型的对象,这样的做法似乎可行,但我依然认为这不够友好和简洁,

我希望用一个容器来存储这些不同类型的对象。

一开始我想自己写这么一个数据结构的容器来存储,但是基于每个对象所占的内存是不同的,我们如何来

让该容器来进行寻址定位呢?保存数据结构的大小可能是一个好的方法,但我想更好的方法是只在该容器中

保存各种对象指针,因为指针的大小只是由操作系统的寻址能力和编译器来决定的,这意味着在同一台机器

上在一个编译平台下各种数据类型的指针大小都是相同的,因此如果我们使用指针则可以使容器很快的寻址

到我们需要的元素。

因为想到了指针,于是我就马上联想到了void*类型,如果我们使用一个void*类型的容器,不就意味着我们

可以用该容器来存储所有数据类型的指针了吗?这似乎是一个很好的思路,但是我们在该角色类内部如何将其

转化为原来具体的类型以供调用呢?这就需要我们的容器在插入的时候同时额外提供一个表示该数据类型的索

引,这样我们就能通过该索引来判断出我们所碰撞检测的对象是什么了!而且还不需要我自己来实现,在STL

当中便提供了这样的容器!!!

具体方法我们可以这样做:

1.首先我们定义一种枚举类型来提供不同数据类型的索引号。

enum CollType
{
	COLL_TYPE_RECT = 0,
	COLL_TYPE_CIRCLE = 1,
	COLL_TYPE_TRIANGLE = 2
};

2.然后在角色类中声明一种将CollType和void*构成pair用来作为双向链表list的元素,例如:

std::list<std::pair<CollType,void*>> mCollList;

这样一来,我们就能用mCollList来存储不同碰撞区域类型的对象来在类内部进行碰撞检测了,这里之所以选用

std::list双向链表而不用线性表的原因有两点:

#1.插入和删除的速度非常快,因为我们可能在之后的一段时间内对某个对象不进行碰撞检测,因此会有频繁的删除。

#1.在碰撞检测时,在算法没有优化的情况下,通常我们是遍历容器每一个元素来进行碰撞检测,这样一来,借助list

的迭代器,我们遍历该容器的时间和线性表相当。

(这里暂时不考虑借用树结构对区域分割来达到算法优化,这一部分以后再考虑实现。)

3.在角色类中提供一个对外的接口以供调用:

std::list<std::pair<CollType, void*>>& getCollList(){ return mCollList; }

4.在角色类内部遍历mCollList的元素来进行碰撞检测。

5.我们在类外环境中通过getCollList()不断的添加需要进行碰撞检测的区域即可。

(如果我的思路中有什么不对地方你可以指出,或者你有更好的方法可以和我一起交流,

让我们一起加油,向着世界不断的进步吧!!)

时间: 2024-10-24 01:37:59

个人关于存储不同类型对象进行碰撞检测的一些思路的相关文章

GreenDao存储自定义类型对象解决方案(转)

最近公司项目选用GreenDao作为Android客户端本地数据库的对象关系映射框架.对于GreenDao虽然以往也有简单用过,但这还是笔者第一次在实际业务中使用.碰到了题目所述的两个问题,虽然在Tutorial里和百度没找到答案,但在官方issue里搜了一圈果然有方案,遂记录下来帮助更多人. 综合主键 需求场景:某张表里需要两个或多个column组合在一起成为一个综合主键.比如你的表里需要存储一个用户的账单,虽然账单也有id,但是你希望一张表存储所有用户,那么就需要把userId和账单id放在

C# CLR via 对象内存中堆的存储【类型对象指针、同步块索引】

最近在看书,看到了对象在内存中的存储方式. 讲到了对象存储在内存堆中,分配的空间除了类型对象的成员所需的内存量,还有额外的成员(类型对象指针. 同步块索引 ),看到这个我就有点不懂了,不知道类型对象指针是什么,指向的什么? 从网上找也没有找到,最后往下看,书中有些描述.说下我的理解: 类型对象指针:指向类型对象存储的地址,假如有一个类型Person,它在堆中有一块区域存储它内部的字段和成员以及两个额外成员(类型对象指针. 同步块索引 ),类型对象的类型对象指针指向的是System.Type的地址

个人存储不同类型的对象有一些想法的碰撞检测

(声明:在下面是基于这样的思想的对象C++和2D图像) 在代码量较小的程序中.我们可能会直接把全部须要的对象的碰撞检測封装在类其中,然后在 角色移动等动作的渲染过程中进行自己主动的碰撞检測.但这种做法有个弊端,那就是我们已知了需求, 而我们假设须要扩展程序,则须要不断的在类内部进行加入.这种做法显然破坏了程序的扩展性, 使得代码难以使用,因此我们须要该角色的类对外提供一个接口,利用这个接口,将那些须要进行 碰撞检測的对象进行检測,然后进行角色的移动等动作的渲染. 但是这里有一个问题,由于碰撞检測

Core Data存储自定义类型数据

目录: 一.使用CoreData存储基本数据 二.使用CoreData存储自定义类型数据 简单介绍CoreData CoreData是iOS编程中使用持久化数据存储的一种方式,我们知道CoreData并不是数据库本身,而是Apple提供的对象持久化技术--Object Persistent technology.CoreData框架为我们的数据变更.管理.对象存储.读取和恢复提供了支持.下面我们来尝试创建一个简单的CoreData Project. 操作 1. 打开x-code,为你的proje

怎样在Redis通过StackExchange.Redis 存储集合类型List

StackExchange 是由StackOverFlow出品, 是对Redis的.NET封装,被越来越多的.NET开发者使用在项目中. 绝大部分原先使用ServiceStack的开发者逐渐都转了过来,由于SS在其新版中不再开源,并对免费版本有所限制. 实际问题 那么用.NET的开发者会发现,其根本没有对List类型的存储封装,那么要实现一个类似如下需求:假如我有一个Customer的模型. public class Customer { public string FirstName { ge

《C#图解教程》读书笔记之二:存储、类型和变量

一.类型初窥:掀起你的盖头来 (1)C程序是一组函数和数据类型,C++程序是一组函数和类,而C#程序是一组类型声明: (2)类型是一种模板:模板本身不是数据结构,但它详细说明了由该模板构造的对象的特征: (3)C#提供了16种预定义类型:13种简单类型(数值类型:int,float,double,decimal等:非数值类型:bool,char),3种非简单类型(object,string,dynamic): 所有的预定义类型都直接映射到底层的.NET类型.C#的类型名称其实就是.NET类型的别

关于Redis五种类型对象的学习笔记

我们在使用Redis的时候,直接接触到的是字符串对象(String),列表对象(List),哈希对象(Hash),集合对象(Set),有序集合对象(SortedSet)这五种类型的对象,基本的命令如:String(get set) List(lpush rpush lpop rpop lrange) Hash(hget hset hlen hgetall) Set(sadd smembers smov) SortedSet(Zadd Zrange)等. 我们首先看一下redis对象的数据结构:

localStorage存储数组或者对象的问题总结

在做  保存选中的复选框记录(跳转到下个页面返回时希望原先选中的东西还在)时, 用到了localStorage存储数据. 由于复选框的内容有点多,就在localStorage中存入了对象(因为考虑到复选框有可能会多选,长度不一定,没有用二维数组). //首先先声明了存储复选框的对象checkarr var checkarr={}; //将数据存入checkarr中 function storeCheckarr(checkname){ //每列复选框都是一条数组:checkname:[] chec

PHP内核探索:变量存储与类型

先回答前面一节的那个问题吧. 01 <?php 02 $foo = 10; 03 $bar = 20; 04    05 function change() { 06     global $foo; 07     //echo '函数内部$foo = '.$foo.'<br />'; 08     //如果不把$bar定义为global变量,函数体内是不能访问$bar的 09     $bar = 0; 10     $foo++; 11 } 12    13 change(); 14