From CloudModding OoT Wiki

Actors appear to use one of two types of collision models, simple bodies (cylinders, simplistic shapes), and poly based surfaces.

Poly-based Collision

Polygon based collision detection is managed primarily by z_bgcheck.c. Follows the Collision Mesh format. Most meshes are stored in object files, rather than actor files like above.

Poly Lookup Table

Global Context + 0x7C0 is the address of the struct managing background collision information.

00 = ptr to scene collision mesh
04 = float[3] minimum x,y,z for scene bounding box
10 = float[3] maximum x,y,z for scene bounding box
1C = int[3] x,y,z CollisionPoly lookup table length
28 = float[3] x,y,z "unit size" factor for CollisionPoly lookup table
34 = float[3] x,y,z "inverse unit size" for CollisionPoly lookup table
40 = ptr to CollisionPoly lookup table, variable length, 0x06 bytes per record. 
   //record struct
   /* 0x00 */ short floorsId;   //CollisionPolyLink table index
   /* 0x02 */ short wallsId;    //CollisionPolyLink table index
   /* 0x04 */ short ceilingsId; //CollisionPolyLink table index
44 = short, Max Records in CollisionPolyLink table
46 = short, Number of Records Reserved in 0x48 table
48 = ptr, CollisionPolyLink table, 0x04 bytes per record
   //record struct
   /* 0x00 */ short polyId;
   /* 0x02 */ short next; //Next CollisionPolyLink table index
4C = ptr, CollisionPoly has been tested table, 1 byte per record, one record per poly defined in the scene mesh

In order to optimize collision detection, the scene mesh is subdivided into volumes, typically into 10 by 4 by 10 sections. Polys that cross within each section are categorized into floors, walls, and ceilings (likely based on their unit normals), and sorted into a linked list ordered by the polygon's lowest point (low y to high).

Poly Mesh Actors

Actors can have mesh-based collisions as well. The game engine can handle up to a maximum of 50 meshes, plus the scene file's mesh (which is assigned index 50 or 0x32).

Global Context + 0x7C0 + 0x54 is the start address of the first actor mesh record. Each record is 0x64 bytes, as seen below. Global Context + 0x1B9C is an array of halfwords storing whether an actor mesh is loaded or not.

Offset Type Description
0x0000 Ptr Actor Instance
0x0004 Ptr Collision Mesh Pointer
0x0014 float[3] Actor x,y,z scale 1
0x0020 short[3] Actor x,y,z rotation 1
0x0028 float[3] Actor x,y,z coordinates 1
0x0034 float[3] Actor x,y,z scale 2
0x0040 short[3] Actor x,y,z rotation 2
0x0048 float[3] Actor x,y,z coordinates 2

Mesh Locations

"Dep. Actor" should be the Actor Id of the actor that uses the mesh. Offsets are for NTSC 1.0, but offsets for object files should almost always work regardless of version.

Type Id Offset Dep. Actor
Actor 0106 0024C0 0106
Actor 016B 004C20 016B
Object 0002 0041B0 00D0
Object 0003 004E98 00FF
Object 0003 005FB8 012A
Object 000E 005FC8 000A
Object 0019 0250A8 0059
Object 001C 01D9D0 002E
Object 002A 000E94 003E
Object 002B 001DDC 003F
Object 002B 003CE0 0058
Object 002B 004F30 005C
Object 002C 00DA10 0040
Object 002C 00E2CC 006F
Object 002C 00D054 0041
Object 002F 0005E0 004A
Object 002F 000280 004A
Object 0036 006460 000F
Object 0038 000118 0054
Object 0040 001830 005A
Object 0040 000A1C 005A
Object 0059 0003F0 0064
Object 0059 003590 0064
Object 0059 000998 0064
Object 0059 0073F0 01BB
Object 0059 001DE8 01BA
Object 0061 000658 006E
Object 0069 00A938 00F7
Object 0069 010E10 00F7
Object 0069 0131C4 00F7
Object 0069 004780 00AE
Object 0069 0044D0 00AE
Object 006A 000EE8 00D5
Object 006B 002594 01C7
Object 0070 0043D0 0068
Object 0072 0035F8 0087
Object 0072 00221C 0086
Object 0072 0063B8 0088
Object 0072 0089E0 00E3
Object 0072 0087AC 0089
Object 0074 0039D4 01A8
Object 0076 0000C0 0026
Object 008D 000C2C 00BE
Object 008D 001830 00AE
Object 0096 005CF8 00E6
Object 0096 005580 00C8
Object 0096 005048 00C8
Object 0096 008CE0 00C8
Object 0099 007860 0093
Object 009A 00169C 0092
Object 009C 000D68 00AC
Object 00A1 0128D8 009C
Object 00A1 0133EC 009C
Object 00A2 000428 009D
Object 00AE 00283C 00B8
Object 00AF 002154 015C
Object 00AF 000368 01C3
Object 00AF 000534 01C4
Object 00AF 00261C 00B9
Object 00AF 002FE4 00B9
Object 00B1 000A38 01A9
Object 00E2 0180F8 0166
Object 00F0 000348 0107
Object 00F0 0004D0 00F8
Object 00F1 0004A8 018E
Object 00F9 00075C 0103
Object 0100 001438 0108
Object 0112 000C98 011F
Object 011C 000730 012D
Object 011C 000578 012D
Object 0125 007564 0136
Object 0130 000DB8 0148
Object 0161 000918 018D
Object 0161 0012C0 018D
Object 0162 00238C 0191
Object 0162 0011EC 0190
Object 0166 000AF0 0194
Object 0166 000908 0194
Object 016C 000D48 0169
Object 016C 001430 0169
Object 016F 001A58 019F
Object 0170 000B70 01A0
Object 0181 001C58 019D
Object 0181 001DA8 0100
Object 018A 000118 0059
Object 0190 000B30 01D1

Just look up any function calls to external_func_8005C050 in a disassembled actor file and you're sure to find what you need by looking at argument 3 which contains what seems to be the actor's hitbox header.

Simple Body Collision

The simple body collision engine detects collision between three basic geometric shapes: cylinders, triangles, and quadrilaterals. Cylinders are used most often, typically to represent the body of something, like an NPC or sign. Quadrilaterals are typically used for sword attacks, Link's shield, and hit detection for bombable walls. Triangle collections are used for collision detection with the web in the center of the first room of the Deku Tree.

A CollisionBody represents one of the following things:

  • A collection of cylinders (Type 0)
  • A single cylinder (Type 1)
  • A collection of triangles (Type 2)
  • A single quad (Type 3)

In order to perform collision testing, an entity will "subscribe" a CollisionBody to one of three collision "category" on every frame (game update). After all actors have been processed, collision checks will processed. The results of these collision checks will become available to the actor on the next update frame.

Name Purpose
AT Attack
AC Attack Checker
OT Object Toucher?

CollisionBody elements subscribed to group AT will be collided into group AC. I believe group OT will be collided amongst themselves.

Global Context

//1DA300, start of collision array AT (Gohma, Skullwalltulas)
0x11E60 short	//number of elements to process this frame
0x11E64 ptr 	//first element in array 

//1DA3CC, start of collision array AC (more inclusive, seems to follow actor category order, only one with 3d heart actor)
0x11F2C int 	//number of elements to process this frame

//1DA4C0, start of collision array OT (contains the most actors in Deku Tree)

CollisionBody struct (Instance)

Addresses in the following notes are for NTSC 1.0

/* 0x00 */ actor_t*    //Actor Instance
/* 0x04 */ actor_t*    //Colliding Actor Instance Type 1?
/* 0x08 */ actor_t*    //Colliding Actor Instance Type 2?
/* 0x0C */ actor_t*    //Colliding Actor Instance Type 3?
/* 0x10 */ u8          //CSO 0x01 Collides Flags (opposite 0x11)
                            //if not & 0x0001, skip attack detection
                            // & 0x0040 == ?
/* 0x11 */ u8          //CSO 0x02 Collision Check Flags (opposite 0x10)
                            //if not & 0x0001, skip collision with attack.
                            //if & 0x0002, is detecting a Deku Nut hit?
/* 0x12 */ byte        //CSO 0x03, bitwise-and compared to opposing collision's 0x13 byte
/* 0x13 */ byte        //CSO 0x04, bitwise-and compared to opposing collision's 0x12 byte
/* 0x14 */ byte        //CSO 0x00
/* 0x15 */ u8          //CSO 0x05, Type
                        //00 = Cylinder Collection
                        //01 = Cylinder
                        //02 = ? (potentially sphere, per debug rom console output)
                        //03 = Triangles (2)
                        //references function pointer, start location at 800EFAB8
                        //used to reference function pointer, start location at 800EFB4C.
                        //Basically, on left compare to right, 
                        //left's value * 0x10 + right's value * 0x04 = pointer look up

//If Type == 0 (Cylinder Collection) or Type == 2 (Triangle Collection), the following variables exist:
/* 0x18 */ int     //Number of Cylinders or Triangles
/* 0x1C */ ptr     //Collection Array Start


Every cylinder, quad, and triangle contains a CollisionBodyInfo struct. This struct seems to store the collision properties for that shape.

0x00 s32 //Toucher Attack Identifier Flags
0x04 u8
0x05 u8 //damage dealt when touched/stun timer
0x08 s32 //Bumper Exclusion Mask
0x0C u8 //Effect when collided into
0x0D u8 //
0x14 u8 //flags?
0x15 u8 //Toucher flags?
0x16 u8 //Bumper flags?
0x17 u8 //flags?
0x1C //stores pointer to CollisionBody? in some situations
0x24 //pointer to CollisionBodyInfo of colliding entity

Cylinder Body Collision Struct (Overlay)

This is how the data is stored on file. Addresses are NTSC 1.0

//803AAE7C for Link
//0x2C bytes long, not the only type of collision struct
0x00	byte	//?
0x01	byte	//?
0x02	byte	//?
0x03	byte	//?
0x04	byte	//?
0x05	byte	//?
0x08	byte	//?
0x0C	int	//? (FFCF FFFF, used to compare to Link's FFCF FFFF?)
0x10	byte	//?
0x11	byte	//Damage dealt when touched
0x14	int 	//? (FFCF FFFF)
0x18	byte	//?
0x19	byte	//?
0x1C	byte	//?
0x1D	byte	//?
0x1E	byte	//?
0x20	int?	//Contains cylinder radius or diameter
0x24	int?	//?
0x28	int?	//? (thought this struct was only 0x24 bytes)

Cylinder Body Collision Struct (Actor Instance)

This information is somewhat outdated.

This is the in-memory struct used for actor collision related stuff. In NTSC 1.0 at least, this struct is 0x4C bytes long

//To simplify, CSO = Collision Struct (Overlay) reference, the struct above
//801DAEB8 for Link
0x00	ptr 	//Actor Instance
0x08	ptr		//Colliding Actor Instance?
0x10	byte	//CSO 0x01  collider_flags
0x11	byte	//CSO 0x02  collide_flags //if & 0x0002, is detecting a Deku Nut hit?
0x12	byte	//CSO 0x03, mask_a bitwise-and compared to opposing collision's 0x13 byte
0x13	byte	//CSO 0x04, mask_b bitwise-and compared to opposing collision's 0x12 byte
0x14	byte	//CSO 0x00
0x15	byte	//CSO 0x05, used to reference function pointer, start location at 800EFB4C.
				//Basically, on left compare to right, left's value * 0x10 + right's value * 0x04 = pointer look up
0x18	int 	//CSO 0x0C
0x1C	byte	//CSO 0x10  Damage effect (normal, burn, freeze, shock, knockback)
0x1D	byte	//CSO 0x11, Damage Dealt when touched
0x20	int 	//CSO 0x14  Collision exclusion mask (FFCF FFFF)
0x24	byte	//CSO 0x18
0x25	byte	//CSO 0x19
0x2C	byte	//CSO 0x08 Flags
0x2D	byte	//CSO 0x1C toucher_flags
0x2E	byte	//CSO 0x1D bumper_flags
0x2F	byte	//CSO 0x1E flags_2
0x40	short	//CSO 0x20 Cylinder radius or diameter
0x42	short	//CS0 0x22 Cylinder Height
0x44	short	//CSO 0x24 y_shift
0x46	short	//Cylinder X
0x48	short	//Cylinder Y
0x4A	short	//Cylinder Z

Older Notes

For some old notes, see Notes/Collision.

C Code

typedef struct { /* Common CollisionBody Struct (Instance) */
    z_actor_t  *actor;          /* 0x00 */
    z_actor_t  *unk_actor_1;    /* 0x04 */
    z_actor_t  *unk_actor_2;    /* 0x08 */
    z_actor_t  *unk_actor_3;    /* 0x0C */
    uint8_t     collider_flags; /* 0x10 */ /* compared to 0x11 */
    uint8_t     collide_flags;  /* 0x11 */ /* compared to 0x10 */
    /* values checked against opposing collision */
    uint8_t     mask_a;         /* 0x12 */ /* bitwise-and compared to 0x13 */
    uint8_t     mask_b;         /* 0x13 */ /* bitwise-and compared to 0x12 */ 
    uint8_t     unk_0x14;       /* 0x14 */
    uint8_t     type;           /* 0x15 */ 
                /* 00 = Cylinder Collection 
                   01 = Cylinder            
                   02 = Tri Collection     
                   03 = Quad */
} z_collider_t; /* 0x18 */

typedef struct { 
    int32_t     flags;      /* 0x00 */ /* Toucher Attack Identifier Flags */
    uint8_t     unk_0x04;   /* 0x04 */
    uint8_t     damage;     /* 0x05 */ /* damage or stun timer */ 

} z_collider_touch_t; /* 0x08 */

typedef struct {
    int32_t     flags;      /* 0x00 */ /* Collision exclusion mask */
    uint8_t     effect;     /* 0x04 */
    uint8_t     unk_0x05;   /* 0x05 */
    int32_t     unk_0x08;   /* 0x08 */ 
} z_collider_bump_t; /* 0x0C */

typedef struct z_collider_body_s z_collider_body_t;
struct z_collider_body_s { /* Common CollisionBodyInfo: 0x28 bytes */
    z_collider_touch_t  toucher;        /* 0x00 */    
    z_collider_bump_t   bumper;         /* 0x08 */
    uint8_t             flags;          /* 0x14 */
    uint8_t             toucher_flags;  /* 0x15 */
    uint8_t             bumper_flags;   /* 0x16 */
    uint8_t             flags_2;        /* 0x17 */
    int32_t             unk_0x18;       /* 0x18 */
    z_collider_t       *collider;       /* 0x1C */
    int32_t             unk_0x20;       /* 0x20 */
    z_collider_body_t  *colliding;      /* 0x24 */
}; /* 0x28 */

typedef struct {
    z_collider_body_t   body;           /* 0x00 */
    vec3_f32_t          pointA;         /* 0x28 */
    vec3_f32_t          pointB;         /* 0x34 */
    vec3_f32_t          pointC;         /* 0x40 */
    vec3_f32_t          unit_normal;    /* 0x4C */
    float               normal_dist;    /* 0x58 */    
} z_collider_tri_t; /* 0x5C */

typedef struct {
    z_collider_body_t   body;           /* 0x00 */
    vec3_s16_t          unk_0x28;       /* 0x28 */
    int16_t             unk_0x2E;       /* 0x2E */
    vec3_s16_t          position;       /* 0x30 */
    int16_t             unk_0x36;       /* 0x36 */
    int32_t             unk_0x38;       /* 0x38 */
    uint8_t             unk_0x3C;       /* 0x3C */
} z_collider_cylinder_t; /* 0x40 */

typedef struct {    /* Type 0 */
    z_collider_t        base;   /* 0x00 */
    int32_t             count;  /* 0x18 */
    z_collider_cylinder_t   *list;   /* 0x1C */
} z_collider_cylinder_collection_t;

typedef struct {    /* Type 1 */
    z_collider_t        base;       /* 0x00 */
    z_collider_body_t   body;       /* 0x18 */
    int16_t             radius;     /* 0x40 */ 
    int16_t             height;     /* 0x42 */
    int16_t             y_shift;    /* 0x44 */
    vec3_s16_t          position;   /* 0x46 */
} z_collider_cylinder_main_t; /* 0x4C? */

typedef struct {    /* Type 2 */
    z_collider_t        base;   /* 0x00 */
    int32_t             count;  /* 0x18 */
    z_collider_tri_t   *list;   /* 0x1C */
} z_collider_tri_collection_t;

typedef struct {    /* Type 3 */
    z_collider_t        base;           /* 0x00 */
    z_collider_body_t   body;           /* 0x18 */
    vec3_f32_t          pointA;         /* 0x40 */    
    vec3_f32_t          pointB;         /* 0x4C */
    vec3_f32_t          pointC;         /* 0x58 */
    vec3_f32_t          pointD;         /* 0x64 */
    vec3_s16_t          bounding_max;   /* 0x70 */
    vec3_s16_t          bounding_min;   /* 0x76 */
} z_collider_quad_t; /* 0x7C? */