Collision detection for interlocking shapes
I?m looking for some advice as I?m not sure how to resolve the following problem. I have an in memory structure that holds information about shapes. Note that the shapes are drawn / displayed as coloured attributes and not as a pixel / line representation.
X
Y
Height
Width
Screen Address
Number of elements that make up the shape
List of elements that define how the shape is drawn (see below)
The list of elements defines where each part of the shape is drawn based on the previous position. For example, if I wanted to draw an ?L? shape the structure could look like this:
0 ; X position
0 ; Y Position
3 ; 3 characters high
2 ; 2 characters wide
22528 ; starting address
3 ; 3 elements to draw, note that the item placed at 22528 is not included as part of the elements list
32 ; Add 32 to the starting address (so directly below the first item drawn at 22528
32 ; Add 32 to the item drawn previously, so again directly below it.
1; Add 1 to the item drawn previously so this would be drawn to its right.
I would now have an image on the screen starting at 22528 in this shape:
H
H
HH
I have code that draws these and all works fine. I now want to test for collision so that the shapes cannot overlap. At first I decided to use collision detection based to the X,Y and Width & Height of each shape, which would work. I then realised that the shape bounding rectangles could overlap but the shapes wouldn't necessarily be touching. They could interlock, for example:
HMM
H M
HHM
I'm now thinking of using the bounding rectangles to do some basic "fast" collision detection and then looking more carefully when this is detected to see if any of the individual shape elements are actually touching. My first thought was to create a list of attribute address for the two shapes I am checking and then testing for matching addresses. For the type of game I am writing, both speed and memory size aren't too important so I guess I'm looking for a way of testing that just works and could be refactored at a later date if required. Anyone got some views on this? Could I change the way I hold the shape data to make the collision detection easier?
X
Y
Height
Width
Screen Address
Number of elements that make up the shape
List of elements that define how the shape is drawn (see below)
The list of elements defines where each part of the shape is drawn based on the previous position. For example, if I wanted to draw an ?L? shape the structure could look like this:
0 ; X position
0 ; Y Position
3 ; 3 characters high
2 ; 2 characters wide
22528 ; starting address
3 ; 3 elements to draw, note that the item placed at 22528 is not included as part of the elements list
32 ; Add 32 to the starting address (so directly below the first item drawn at 22528
32 ; Add 32 to the item drawn previously, so again directly below it.
1; Add 1 to the item drawn previously so this would be drawn to its right.
I would now have an image on the screen starting at 22528 in this shape:
H
H
HH
I have code that draws these and all works fine. I now want to test for collision so that the shapes cannot overlap. At first I decided to use collision detection based to the X,Y and Width & Height of each shape, which would work. I then realised that the shape bounding rectangles could overlap but the shapes wouldn't necessarily be touching. They could interlock, for example:
HMM
H M
HHM
I'm now thinking of using the bounding rectangles to do some basic "fast" collision detection and then looking more carefully when this is detected to see if any of the individual shape elements are actually touching. My first thought was to create a list of attribute address for the two shapes I am checking and then testing for matching addresses. For the type of game I am writing, both speed and memory size aren't too important so I guess I'm looking for a way of testing that just works and could be refactored at a later date if required. Anyone got some views on this? Could I change the way I hold the shape data to make the collision detection easier?
Post edited by Mr Millside on
Comments
When the same value, no collission when different collission
example
11100000
and
00011111
wil give 11111111 in both cases
where
11110000
00011111
will give 11101111 by XOR and 11111111 by OR
Bytes:Chuntey - Spectrum tech blog.
One very simple way you could do it is to make a shadow buffer of the attributes. So basically 1 byte per character location. Each character location on screen relates to a shadow buffer location and when you draw on the screen you set the shadow buffer locations to non-zero.
So when you start a screen draw do this :-
1. Clear the shadow buffer
2. Get a shape to draw
3. If all the shape locations in the shadow buffer are clear draw the shape
4. else do whatever you want when you don't draw a shape
5. Loop back to 2 for each shape
Does that do what you require?
It'll take 768 bytes for the shadow buffer, but the code should be very simple.
- IONIAN-GAMES.com -
...Great minds & all that - uncanny..! :razz:
1. clear shadow buffer
2. value = 1
3. do inner part as before, but check shadow (buffer & value) == value
4. value = value * 2
5. if value == 256 then goto 1, else goto 3
Imagine you have two sorted lists: {1, 2, 5, 8, 15} and {3, 4, 8, 11} you start comparing the first elements: 1 and 3, no match, then pick the lower of the two numbers and replace it with the next number in that list, so compare 2 and 3, then 5 and 3, 5 and 4, 5 and 8, 8 and 8. OK these two are the same so it's a match. If you reach the end of both lists, there's no match.
bool collision = false; address1 = start_address_of_shape1 + shape1_offset[0] address2 = start_address_of_shape2 + shape2_offset[0] index1 = 1 // this is the position in the array shape1_offset index2 = 1 // this is the position in the array shape2_offset while (index1 < num_elements_in_shape1) and (index2 < num_elements_in_shape2) { bool addr1_is_lowest; if (index1 == num_elements_in_shape1) addr1_is_lowest = false; else if (index2 == num_elements_in_shape2) addr1_is_lowest = true; else { addr1_is_lowest = (address1 < address2); } if (addr1_is_lowest) { address1 += shape1_offset[index1]; index1++; } else { address2 += shape2_offset[index2]; index2 ++; } if (address1 == address2) { collision = true; } }In Z80 ASM it might look something like this (I've not checked this or even know if all the opcodes are valid and it's certainly not optimal even if it works)
; IX and IY point to the two objects, arranged as below: ; Structure { byte x, y, w, h; word address; byte numOffsets; byte offsets[]; } LD HL, (IX+4) ; get initial addresses of objects LD BC, (IY+4) SUB HL, BC ; D,E contain the number of remaining elements in the respective lists of offsets. LD D, (IX+6) DEC D LD E, (IY+6) DEC E ; add difference from first offset pair LD B, 0 LD C, (IX+7) ADD HL, BC LD C, (IY+7) SUB HL, BC ; get the addresses of the second offsets ADD IX, 8 ; you don't need this if you replace (IX+0) with (IX+8) below, ADD IY, 8 ; same with IY, but it's easier to understand loop: ; if HL is 0 we have collided. LD A, H OR L J Z, collision ; now replace the smaller of the two pairs, unless we have finished with ; one of the lists. ; check if list1 still has elements LD A, D XOR A JZ iy_lower ; check if list2 still has elements LD A, E XOR A JZ ix_lower ; no, so check if HL>0 or <0 based on the sign bit of H. BIT 7, H JNZ iy_lower ix_lower: ; read the next element from list 1; add to HL. LD B, 0 LD C, (IX+0) ADD HL, BC INC IX DEC D J check_done iy_lower: ; read the next element from list 2; subtract from HL. LD B, 0 LD C, (IY+0) SUB HL, BC INC IY DEC E check_done: LD A, D J NZ, loop LD A, E J NZ loop no_collision: ; if we get here, no collision occurred. collision: ; if we get here, a collision occurred; work out where from IX and IY.