09-06-2025, 08:00 AM
(This post was last modified: 09-06-2025, 08:03 AM by Unseen Machine.)
Hi all,
I love this kinda stuff so whilst im now onto incorporating circles and polygons into this, for now heres rectangles!
SAT btw is separated axis theory, basically if you can draw a line between two things then they arent colliding, if you cant they are...its faster acurate and easily expandable to fit almost complex shapes....
This demo runs as is, needs no files or anyting for once!
Unseen
I love this kinda stuff so whilst im now onto incorporating circles and polygons into this, for now heres rectangles!
SAT btw is separated axis theory, basically if you can draw a line between two things then they arent colliding, if you cant they are...its faster acurate and easily expandable to fit almost complex shapes....
This demo runs as is, needs no files or anyting for once!
Code: (Select All)
'///////////////////////////////////////////////////////////////////////////////////////////////////////////////
'// Unseen GDK 3 - Collisions Dev - Rects Only For now Just To Demo \\
'///////////////////////////////////////////////////////////////////////////////////////////////////////////////
RANDOMIZE TIMER
'// REM $INCLUDE:'UnseenGDK2\GDK2.bi'
CONST GDK_Vector_Size = 8
CONST GDK_TRUE = -1, GDK_FALSE = 0
'///////////////////////////////////////////////////////////////////////////////////////////////////////////////
'///////////////////////////////////// System Initialisation ////////////////////////////////////////////////
'/GDK2_System_New "UnseenGDK2\Projects\", 800, 600, GDK_FALSE, "GDK Rectangle Demo"
SCREEN _NEWIMAGE(800, 600, 32)
_SCREENMOVE 0, 0
_DELAY 1
'///////////////////////////////////////////////////////////////////////////////////////////////////////////////
CONST MAX_BOXES = 10
CONST FLASH_TIME = 0.5
DIM SHARED Boxes(MAX_BOXES) AS GDK_Box
DIM SHARED GT#, LastGT#
GT# = TIMER(.001): LastGT# = GT#
InitBoxes
'//////////////////////////////////////// Main Loop ////////////////////////////////////////////////////////////
DO
GT# = TIMER(.001)
dt = GT# - LastGT#
UpdateBoxes dt
CLS
FOR I = 0 TO MAX_BOXES - 1
IF Boxes(I).FlashTimer > 0 THEN
GDK_DrawBox Boxes(I), _RGB32(255, 255, 0)
ELSE
GDK_DrawBox Boxes(I), Boxes(I).pColor
END IF
NEXT I
_DISPLAY
LastGT# = GT#
LOOP UNTIL INKEY$ = CHR$(27)
SYSTEM
'///////////////////////////////////////////////////////////////////////////////////////////////////////////////
'REM $INCLUDE:'UnseenGDK2\GDK2.bm'
'///////////////////////////////////////////////////////////////////////////////////////////////////////////////
TYPE GDK_Vector
X AS SINGLE
Y AS SINGLE
END TYPE
'The new GDK_Box type for a rotated rectangle, without pre-calculated corners
TYPE GDK_Box
Position AS GDK_Vector
WidthHeight AS GDK_Vector
Rotation AS SINGLE
RotationPointOffset AS GDK_Vector
Rotation_Speed AS SINGLE ' New: For rotational speed
Velocity AS GDK_Vector ' Movement vector for this box
pColor AS LONG ' Color for drawing
IsColliding AS INTEGER ' Flag to indicate collision state
FlashTimer AS SINGLE ' Timer for collision flash
END TYPE
'///////////////////////////////////////////////////////////////////////////////////////////////////////////////
' Draws a box using its calculated corner vertices.
SUB GDK_DrawBox (Box AS GDK_Box, bcolor AS LONG)
DIM Corners(3) AS GDK_Vector
CALL GDK_GetBoxCorners(Box, Corners())
LINE (Corners(0).X, Corners(0).Y)-(Corners(1).X, Corners(1).Y), bcolor
LINE (Corners(1).X, Corners(1).Y)-(Corners(2).X, Corners(2).Y), bcolor
LINE (Corners(2).X, Corners(2).Y)-(Corners(3).X, Corners(3).Y), bcolor
LINE (Corners(3).X, Corners(3).Y)-(Corners(0).X, Corners(0).Y), bcolor
END SUB
'///////////////////////////////////////////////////////////////////////////////////////////////////////////////
' Rotates a point around a pivot point by a given angle (in radians)
SUB GDK_RotatePoint (Result AS GDK_Vector, p AS GDK_Vector, pivot AS GDK_Vector, angle AS SINGLE)
DIM temp_x AS SINGLE, temp_y AS SINGLE
temp_x = p.X - pivot.X
temp_y = p.Y - pivot.Y
Result.X = temp_x * COS(angle) - temp_y * SIN(angle)
Result.Y = temp_x * SIN(angle) + temp_y * COS(angle)
Result.X = Result.X + pivot.X
Result.Y = Result.Y + pivot.Y
END SUB
'///////////////////////////////////////////////////////////////////////////////////////////////////////////////
' Calculates the corner vertices for a given box
SUB GDK_GetBoxCorners (Box AS GDK_Box, Corners() AS GDK_Vector)
DIM HalfW AS SINGLE, HalfH AS SINGLE
DIM UnrotatedCorner AS GDK_Vector
DIM Center AS GDK_Vector
HalfW = Box.WidthHeight.X / 2
HalfH = Box.WidthHeight.Y / 2
Center = Box.Position
UnrotatedCorner.X = Center.X - HalfW
UnrotatedCorner.Y = Center.Y - HalfH
CALL GDK_RotatePoint(Corners(0), UnrotatedCorner, Center, Box.Rotation)
UnrotatedCorner.X = Center.X + HalfW
UnrotatedCorner.Y = Center.Y - HalfH
CALL GDK_RotatePoint(Corners(1), UnrotatedCorner, Center, Box.Rotation)
UnrotatedCorner.X = Center.X + HalfW
UnrotatedCorner.Y = Center.Y + HalfH
CALL GDK_RotatePoint(Corners(2), UnrotatedCorner, Center, Box.Rotation)
UnrotatedCorner.X = Center.X - HalfW
UnrotatedCorner.Y = Center.Y + HalfH
CALL GDK_RotatePoint(Corners(3), UnrotatedCorner, Center, Box.Rotation)
END SUB
'///////////////////////////////////////////////////////////////////////////////////////////////////////////////
' Checks for overlap of projections on a given axis
FUNCTION GDK_Overlap_On_Axis (Corners1() AS GDK_Vector, Corners2() AS GDK_Vector, Axis AS GDK_Vector)
DIM Min1 AS SINGLE, Max1 AS SINGLE, Min2 AS SINGLE, Max2 AS SINGLE
DIM Projection AS SINGLE, I AS LONG
Min1 = 9999999!: Max1 = -9999999!
Min2 = 9999999!: Max2 = -9999999!
FOR I = 0 TO 3
Projection = Corners1(I).X * Axis.X + Corners1(I).Y * Axis.Y
IF Projection < Min1 THEN Min1 = Projection
IF Projection > Max1 THEN Max1 = Projection
NEXT I
FOR I = 0 TO 3
Projection = Corners2(I).X * Axis.X + Corners2(I).Y * Axis.Y
IF Projection < Min2 THEN Min2 = Projection
IF Projection > Max2 THEN Max2 = Projection
NEXT I
IF Max1 >= Min2 AND Max2 >= Min1 THEN GDK_Overlap_On_Axis = -1 ELSE GDK_Overlap_On_Axis = 0
END FUNCTION
'///////////////////////////////////////////////////////////////////////////////////////////////////////////////
'///////////////////////////////////////////////////////////////////////////////////////////////////////////////
' Checks for intersection using SAT
FUNCTION GDK_Box_Intersect (Box1 AS GDK_Box, Box2 AS GDK_Box)
DIM Box1_Corners(3) AS GDK_Vector, Box2_Corners(3) AS GDK_Vector
DIM Axis(3) AS GDK_Vector, length AS SINGLE, I AS LONG
CALL GDK_GetBoxCorners(Box1, Box1_Corners())
CALL GDK_GetBoxCorners(Box2, Box2_Corners())
Axis(0).X = -(Box1_Corners(1).Y - Box1_Corners(0).Y): Axis(0).Y = Box1_Corners(1).X - Box1_Corners(0).X
Axis(1).X = -(Box1_Corners(0).Y - Box1_Corners(3).Y): Axis(1).Y = Box1_Corners(0).X - Box1_Corners(3).X
FOR I = 0 TO 1
length = SQR(Axis(I).X * Axis(I).X + Axis(I).Y * Axis(I).Y)
IF length > 0 THEN Axis(I).X = Axis(I).X / length: Axis(I).Y = Axis(I).Y / length
IF NOT GDK_Overlap_On_Axis(Box1_Corners(), Box2_Corners(), Axis(I)) THEN GDK_Box_Intersect = 0: EXIT FUNCTION
NEXT I
Axis(2).X = -(Box2_Corners(1).Y - Box2_Corners(0).Y): Axis(2).Y = Box2_Corners(1).X - Box2_Corners(0).X
Axis(3).X = -(Box2_Corners(0).Y - Box2_Corners(3).Y): Axis(3).Y = Box2_Corners(0).X - Box2_Corners(3).X
FOR I = 2 TO 3
length = SQR(Axis(I).X * Axis(I).X + Axis(I).Y * Axis(I).Y)
IF length > 0 THEN Axis(I).X = Axis(I).X / length: Axis(I).Y = Axis(I).Y / length
IF NOT GDK_Overlap_On_Axis(Box1_Corners(), Box2_Corners(), Axis(I)) THEN GDK_Box_Intersect = 0: EXIT FUNCTION
NEXT I
GDK_Box_Intersect = -1
END FUNCTION
'///////////////////////////////////////////////////////////////////////////////////////////////////////////////
'// DEMO For Simple Box collision
'///////////////////////////////////////////////////////////////////////////////////////////////////////////////
' --- Main Logic ---
SUB InitBoxes
DIM I AS LONG, W AS SINGLE, H AS SINGLE, R AS SINGLE, S AS SINGLE
FOR I = 0 TO MAX_BOXES - 1
W = 10 + RND * 50
H = 10 + RND * 50
R = RND * 2 * _PI
S = 10 + RND * 50
Boxes(I).Position.X = RND * 800
Boxes(I).Position.Y = RND * 600 '_HEIGHT
Boxes(I).WidthHeight.X = W
Boxes(I).WidthHeight.Y = H
Boxes(I).Rotation = R
Boxes(I).Rotation_Speed = (RND * .3)
Boxes(I).RotationPointOffset.X = W / 2: Boxes(I).RotationPointOffset.Y = H / 2
Boxes(I).Velocity.X = (RND * 5) * S
Boxes(I).Velocity.Y = (RND * 5) * S
Boxes(I).pColor = _RGB32(RND * 255, RND * 255, RND * 255)
Boxes(I).IsColliding = GDK_FALSE
Boxes(I).FlashTimer = 0
NEXT I
END SUB
'///////////////////////////////////////////////////////////////////////////////////////////////////////////////
SUB UpdateBoxes (dt AS SINGLE)
DIM I AS LONG, J AS LONG
DIM Box_Hit AS INTEGER
' Screen wrapping
DIM BoxLeft AS SINGLE, BoxRight AS SINGLE, BoxTop AS SINGLE, BoxBottom AS SINGLE
DIM tempX AS SINGLE, tempY AS SINGLE
FOR I = 0 TO MAX_BOXES - 1
' Update position and rotation
Boxes(I).Position.X = Boxes(I).Position.X + Boxes(I).Velocity.X * dt
Boxes(I).Position.Y = Boxes(I).Position.Y + Boxes(I).Velocity.Y * dt
Boxes(I).Rotation = Boxes(I).Rotation + Boxes(I).Rotation_Speed * dt
BoxLeft = Boxes(I).Position.X - Boxes(I).WidthHeight.X / 2
BoxRight = Boxes(I).Position.X + Boxes(I).WidthHeight.X / 2
BoxTop = Boxes(I).Position.Y - Boxes(I).WidthHeight.Y / 2
BoxBottom = Boxes(I).Position.Y + Boxes(I).WidthHeight.Y / 2
IF BoxRight < 0 THEN Boxes(I).Position.X = _WIDTH + Boxes(I).WidthHeight.X / 2
IF BoxLeft > _WIDTH THEN Boxes(I).Position.X = 0 - Boxes(I).WidthHeight.X / 2
IF BoxBottom < 0 THEN Boxes(I).Position.Y = _HEIGHT + Boxes(I).WidthHeight.Y / 2
IF BoxTop > _HEIGHT THEN Boxes(I).Position.Y = 0 - Boxes(I).WidthHeight.Y / 2
' Check for collision with other boxes
Box_Hit = GDK_FALSE
FOR J = I + 1 TO MAX_BOXES - 1
IF GDK_Box_Intersect(Boxes(I), Boxes(J)) THEN
Box_Hit = GDK_TRUE
' Simple bounce logic
tempX = Boxes(I).Velocity.X: tempY = Boxes(I).Velocity.Y
Boxes(I).Velocity.X = Boxes(J).Velocity.X: Boxes(I).Velocity.Y = Boxes(J).Velocity.Y
Boxes(J).Velocity.X = tempX: Boxes(J).Velocity.Y = tempY
Boxes(J).FlashTimer = FLASH_TIME
END IF
NEXT J
' Manage flash timer
IF Box_Hit THEN
Boxes(I).FlashTimer = FLASH_TIME
ELSEIF Boxes(I).FlashTimer > 0 THEN
Boxes(I).FlashTimer = Boxes(I).FlashTimer - dt
END IF
NEXT I
END SUB
'///////////////////////////////////////////////////////////////////////////////////////////////////////////////
SUB GDK_ClosestPointOnBox (Result AS GDK_Vector, Box AS GDK_Box, vPoint AS GDK_Vector)
DIM Box_Corners(3) AS GDK_Vector
CALL GDK_GetBoxCorners(Box, Box_Corners())
DIM Closest AS GDK_Vector
DIM I AS LONG, J AS LONG
DIM MinDistanceSquared AS SINGLE, CurrentDistanceSquared AS SINGLE
MinDistanceSquared = 9999999!
FOR I = 0 TO 3
J = (I + 1) MOD 4
DIM SegmentStart AS GDK_Vector, SegmentEnd AS GDK_Vector
SegmentStart = Box_Corners(I)
SegmentEnd = Box_Corners(J)
DIM dx AS SINGLE, dy AS SINGLE
dx = SegmentEnd.X - SegmentStart.X
dy = SegmentEnd.Y - SegmentStart.Y
DIM t AS SINGLE
t = ((vPoint.X - SegmentStart.X) * dx + (vPoint.Y - SegmentStart.Y) * dy) / (dx * dx + dy * dy)
IF t < 0 THEN t = 0
IF t > 1 THEN t = 1
DIM ClosestPointOnSegment AS GDK_Vector
ClosestPointOnSegment.X = SegmentStart.X + t * dx
ClosestPointOnSegment.Y = SegmentStart.Y + t * dy
CurrentDistanceSquared = (vPoint.X - ClosestPointOnSegment.X) ^ 2 + (vPoint.Y - ClosestPointOnSegment.Y) ^ 2
IF CurrentDistanceSquared < MinDistanceSquared THEN
MinDistanceSquared = CurrentDistanceSquared
Closest = ClosestPointOnSegment
END IF
NEXT I
Result = Closest
END SUB
Unseen

