ID:141670
 
I decided to shrink the collision boxes in my collision handling proc with the below algorithm (it's in C++):

    object->width = <ACTUAL BITMAP WIDTH>;
object->height = <ACTUAL BITMAP HEIGHT>;

object->col_width = object->width * 0.80;
object->col_height = object->height * 0.80;

object->col_x_offset = (object->width - object->col_width) / 2;
object->col_y_offset = (object->height - object->col_height) / 2;

// Object-to-object, reduced bounding-box collision detector:
short int Sprite_Collide(sprite_ptr object1, sprite_ptr object2) {

int left1, left2;
int right1, right2;
int top1, top2;
int bottom1, bottom2;

left1 = object1->x + object1->col_x_offset;
left2 = object2->x + object2->col_x_offset;
right1 = left1 + object1->col_width;
right2 = left2 + object2->col_width;
top1 = object1->y + object1->col_y_offset;
top2 = object2->y + object1->col_y_offset;
bottom1 = top1 + object1->col_height;
bottom2 = top2 + object2->col_height;

if (bottom1 < top2) return(0);
if (top1 > bottom2) return(0);

if (right1 < left2) return(0);
if (left1 > right2) return(0);

return(1);

};


And I translated it into DM fairly well. However, I don't think I got my chain of greater than and less than's correct; it wrongly detects collision when I bump into an object while moving down (only when I collided with the top of an object and began to move down) and when I bump into an object's left side while moving right. I'm using the procs below:

atom/proc
set_loc()
pixx = pixel_x+32*x
pixy = pixel_y+32*y

top = pixy+col_height+col_y_offset
bottom = pixy+col_y_offset
left = pixx+col_x_offset
right = pixx+col_width+col_x_offset

midy = pixy+((col_height+col_y_offset) >> 1)
midx = pixx+((col_width+col_x_offset) >> 1)

set_size(nwidth,nheight)

width = nwidth
height = nheight

col_height = round(height*0.8)
col_width = round(width*0.8)

col_x_offset = round((width - col_width) >> 1)
col_y_offset = round((height - col_height) >> 1)

atom/movable/proc
iscolliding(xp,yp)
if(!density) return

var
top1 = top+yp
bottom1 = bottom+yp
left1 = left+xp
right1 = right+xp

var/list/L = range(1,src)-src

QuickSort(L,/proc/Sort_By_Dist,src)

for(var/atom/A in L)

if(!A.density) continue

if(bottom1 > A.top) continue
if(top1 < A.bottom) continue
if(right1 < A.left) continue
if(left1 > A.right) continue

return A


It worked correctly before I attempted to shrink the collision boxes, any insight into the issue?
I'll have to look at his a little more closely, but I think your top and bottom sides are backwards.

        bottom1 = object1->y + object1->col_y_offset;
bottom2 = object2->y + object1->col_y_offset;
top1 = bottom1 + object1->col_height;
top2 = bottom2 + object2->col_height;
Yeah. You have to keep in mind that code written in C, or C derivative languages, almost always start their coordinates in the top-left corner at 0,0. This means that code snippet is backwards in DM, since coordinates in BYOND start at 1,1 in the bottom-left corner. You'll have to swap the top and bottom like I showed, and you might have to re-check your other code snippets to make sure they're all talking the same coordinates.

[edit]

Oh, and if you're not aware, arctan2() returns values from -179 to 180, with 0 pointing East and increasing counter-clockwise.

So...



This demonstrates how arctan2() works when getting angles between objects. You see that if you click on a turf, the direction from the turf to you is outlined in the chart above.

proc/arctan2(x,y)
.=(y>=0)?(arccos(x/sqrt(x*x+y*y))):(-arccos(x/sqrt(x*x+y*y)))

mob
icon = 'mobs.dmi'

turf
icon = 'grass.dmi'

Click()
world << arctan2(x-usr.x,y-usr.y)


Some people (myself included), prefer a different orientation. I like having 0 facing north, with negatives along the West and positive along the East, 180 South. You can alter the orientation to match this by first subtracting the angle from 90 degrees, then adjusting withing range if it goes over 180, by subtracting 360 if it does.

turf
icon = 'grass.dmi'

Click()
var/degree = 90-arctan2(x-usr.x,y-usr.y)
if(degree > 180) degree -= 360
world << degree


Some people like to use 0 to 360, but I think that's silly to throw out easy to get directional info in favor of unsigned values (you can tell if it's generally east or west by the sign).
In response to Xooxer
I *think* took that into account, I completely read the code wrong, though. I read object2->col_height/width + object1->col_x/y_offset as object2->col_height/width + object2->col_x/y_offset. Thanks for the info on arctan2() and for helping me realize I read it wrong!
In response to Jeff8500
Nevermind, the problem still persists. For some reason, it's over detecting collision regardless. Would anyone please mind taking a closer look? I can't tell how long I've been trying to figure out the problem. If it helps, the problem also persists when I add/subtract a constant from the pixx and pixy variables in the set_size() proc rather than the offsets and col_height/col_width vars. Also, note that when I say subtraction, I mean I'm adding the original dimensions before I do that.

atom/proc
set_loc()
pixx = pixel_x + 32 * (x-1)
pixy = pixel_y + 32 * (y-1)

top = pixy + col_height
bottom = pixy + col_y_offset
left = pixx + col_x_offset
right = pixx + col_width

midy = pixy +(height >> 1)
midx = pixx +(width >> 1)

set_size()

col_height = round(height*0.8)
col_width = round(width*0.8)

col_x_offset = round((width - col_width) >> 1)
col_y_offset = round((height - col_height) >> 1)

iscolliding(xp,yp)
if(!density) return

var
top1 = top + yp
bottom1 = bottom + yp
left1 = left + xp
right1 = right + xp

var/list/L = range(1,src)-src

QuickSort(L,/proc/Sort_By_Dist,src)

for(var/atom/A in L)

if(!A.density) continue

if(bottom1 > A.top) continue
if(top1 < A.bottom) continue
if(right1 < A.left) continue
if(left1 > A.right) continue

return A
In response to Jeff8500
Your sides were backwards again. :P Try this: (Notice I'm adding the col_width to the already defined left side, instead of from the pixx location, which is the visible edge, not the collision edge (so I assume).

atom/proc
set_loc()
pixx = pixel_x + 32 * (x-1)
pixy = pixel_y + 32 * (y-1)

bottom = pixy + col_y_offset
top = bottom + col_height
left = pixx + col_x_offset
right = left + col_width

midy = pixy +(height >> 1)
midx = pixx +(width >> 1)
In response to Xooxer
The problem still persists, I'm beginning to wonder whether the problem might be elsewhere. To see the very strange problem I'm having, run this.
In response to Jeff8500
I can't seem to download that. Drop me a line at [email protected] and we'll see if we can't work this out. I have a top-down engine, as well as my old platform demo that both use pixel movement, which I'd be glad to share if t'll help.

Theodis would be another person to ask, since he's one of the few of us who actually went to school to learn to program video games, and has a better grasp of all this than I do. He helped straighten out my code problems with one of my pixel movement setups, and I'm sure he'd be able to give you some clue as to what could be the problem.