[RESOLVED] [VB6] - Building games with API functions
Collisions:
i need some advices about collsions(like what is more faster).
the 'if' code:
Code:
Public Function CollisionPrecise(X1 As Long, Y1 As Long, Width1 As Long, Height1 As Long, X2 As Long, Y2 As Long, Width2 As Long, Height2 As Long) As Boolean
If (X1 + Width1 >= X2 And X1 <= X2 + Width2) And (Y1 + Height1 >= Y2 And Y1 <= Y2 + Height2) Then
CollisionPrecise = True
Else
CollisionPrecise = False
End If
End Function
is more faster than:
IntersectRect() API function?
I never work with the IntersectRect API. Even professional game programmers don't use API's for collision. I actually have 2 fast methods of collison I can give you along with collision response. The first one is called rigid body collision detecton, which is used for polygons of any shape and size such as triangles, squares, rectangles, pentagons, hexagons, etc. And it's very accurate. Lets go ahead and setup a sample project so we have something to work with, with better controls and some math functions you'll need for rigid body collision:
vb Code:
Option Explicit
Private Type Vector
X As Single
Y As Single
End Type
Private Type Sprite_Type
Position As Vector
Width As Long
Height As Long
'Collision Stuff
Collided As Boolean
NColl As Vector
DColl As Single
End Type
Private Player As Sprite_Type
Private Monster As Sprite_Type
Private Running As Boolean
Private Const BUTTON_UP As Long = vbKeyW
Private Const BUTTON_DOWN As Long = vbKeyS
Private Const BUTTON_LEFT As Long = vbKeyA
Private Const BUTTON_RIGHT As Long = vbKeyD
Private Const BUTTON_UP_FLAG As Long = 1
Private Const BUTTON_DOWN_FLAG As Long = 2
Private Const BUTTON_LEFT_FLAG As Long = 4
Private Const BUTTON_RIGHT_FLAG As Long = 8
Public Key_State As Long
Private Function Check_Key(Key_Flag As Long) As Long
Check_Key = Key_State And Key_Flag
End Function
Private Sub Keyboard_Controls()
If Check_Key(BUTTON_UP_FLAG) Then
Player.Position.Y = Player.Position.Y - 1
End If
If Check_Key(BUTTON_DOWN_FLAG) Then
Player.Position.Y = Player.Position.Y + 1
End If
If Check_Key(BUTTON_LEFT_FLAG) Then
Player.Position.X = Player.Position.X - 1
End If
If Check_Key(BUTTON_RIGHT_FLAG) Then
Player.Position.X = Player.Position.X + 1
End If
End Sub
Private Sub Draw_Filled_Rectangle(ByVal X As Long, ByVal Y As Long, ByVal Width As Long, ByVal Height As Long, ByVal Color As Long)
frmMain.Line (X, Y)-(X + Width, Y + Height), Color, BF
End Sub
Private Function Vector_New(ByVal X As Single, ByVal Y As Single) As Vector
Vector_New.X = X
Vector_New.Y = Y
End Function
Private Function Vector_Subtract(A As Vector, B As Vector) As Vector
Vector_Subtract.X = A.X - B.X
Vector_Subtract.Y = A.Y - B.Y
End Function
Private Function Vector_Multiply(A As Vector, B As Vector) As Single
Vector_Multiply = A.X * B.X + A.Y * B.Y
End Function
Private Function Vector_Multiply2(A As Vector, ByVal Value As Single) As Vector
Private Sub Form_KeyDown(KeyCode As Integer, Shift As Integer)
Select Case KeyCode
Case BUTTON_UP
Key_State = Key_State Or BUTTON_UP_FLAG
Case BUTTON_DOWN
Key_State = Key_State Or BUTTON_DOWN_FLAG
Case BUTTON_LEFT
Key_State = Key_State Or BUTTON_LEFT_FLAG
Case BUTTON_RIGHT
Key_State = Key_State Or BUTTON_RIGHT_FLAG
End Select
End Sub
Private Sub Form_KeyUp(KeyCode As Integer, Shift As Integer)
Select Case KeyCode
Case BUTTON_UP
Key_State = Key_State And (Not BUTTON_UP_FLAG)
Case BUTTON_DOWN
Key_State = Key_State And (Not BUTTON_DOWN_FLAG)
Case BUTTON_LEFT
Key_State = Key_State And (Not BUTTON_LEFT_FLAG)
Case BUTTON_RIGHT
Key_State = Key_State And (Not BUTTON_RIGHT_FLAG)
End Select
End Sub
Private Sub Form_Load()
Main
End Sub
Private Sub Form_Unload(Cancel As Integer)
Running = False
Unload frmMain
End Sub
For rigid body collision, you'll need these:
vb Code:
Private Function Collide(A() As Vector, B() As Vector, Number_Of_VerticesA As Long, Number_Of_VerticesB As Long, Offset As Vector, N As Vector, T As Single) As Boolean
Dim Axis(64) As Vector
Dim TAxis(64) As Single
Dim Number_Of_Axes As Long: Number_Of_Axes = 0
Dim I As Long, J As Long
Dim E0 As Vector
Dim E1 As Vector
Dim E As Vector
J = Number_Of_VerticesA - 1
For I = 0 To J
E0 = A(J)
E1 = A(I)
E = Vector_Subtract(E1, E0)
Axis(Number_Of_Axes).X = -E.Y
Axis(Number_Of_Axes).Y = E.X
If (Interval_Intersect(A(), B(), Number_Of_VerticesA, Number_Of_VerticesB, Axis(Number_Of_Axes), Offset, TAxis(Number_Of_Axes))) = False Then
Collide = False
Exit Function
End If
Number_Of_Axes = Number_Of_Axes + 1
J = I
Next I
J = Number_Of_VerticesB - 1
For I = 0 To J
E0 = B(J)
E1 = B(I)
E = Vector_Subtract(E1, E0)
Axis(Number_Of_Axes).X = -E.Y
Axis(Number_Of_Axes).Y = E.X
If (Interval_Intersect(A(), B(), Number_Of_VerticesA, Number_Of_VerticesB, Axis(Number_Of_Axes), Offset, TAxis(Number_Of_Axes))) = False Then
Collide = False
Exit Function
End If
Number_Of_Axes = Number_Of_Axes + 1
J = I
Next I
If (Find_Minimum_Translation_Distance(Axis(), TAxis(), Number_Of_Axes, N, T)) = False Then
Collide = False
Exit Function
End If
If Vector_Multiply(N, Offset) < 0 Then
N.X = -N.X
N.Y = -N.Y
End If
Collide = True
End Function
Private Sub Get_Interval(Vertex_List() As Vector, Number_Of_Vertices As Long, Axis As Vector, Min As Single, Max As Single)
Min = Vector_Multiply(Vertex_List(0), Axis)
Max = Vector_Multiply(Vertex_List(0), Axis)
Dim I As Long
For I = 1 To Number_Of_Vertices - 1
Dim D As Single: D = Vector_Multiply(Vertex_List(I), Axis)
If (D < Min) Then
Min = D
ElseIf (D > Max) Then
Max = D
End If
Next I
End Sub
Private Function Interval_Intersect(A() As Vector, B() As Vector, Number_Of_VerticesA As Long, Number_Of_VerticesB As Long, Axis As Vector, Offset As Vector, TAxis As Single) As Boolean
The other method of collision I use is Box to Box collision detection which is easier. Only with this it'll return the side it collided on. When calling Collision_Detection2 however, use 1 for accurate collision. Values above will offset the sprite.
vb Code:
Private Function Collision_Box_To_Box(ByVal B1_X As Single, ByVal B1_Y As Single, ByVal B1_Width As Single, ByVal B1_Height As Single, ByVal B2_X As Single, ByVal B2_Y As Single, ByVal B2_Width As Single, ByVal B2_Height As Single) As Long
Const NO_COLLISION As Long = 0
Const COL_LEFT As Long = 1
Const COL_RIGHT As Long = 2
Const COL_UP As Long = 3
Const COL_DOWN As Long = 4
Dim Side As Long
Dim Overlap As Long
If Not (B1_X < (B2_X + B2_Width) And _
(B1_X + B1_Width) > B2_X And _
B1_Y < (B2_Y + B2_Height) And _
(B1_Y + B1_Height) > B2_Y) Then
Collision_Box_To_Box = 0
Exit Function
End If
Side = COL_LEFT
Overlap = Abs(B1_X - (B2_X + B2_Width))
If Abs((B1_X + B1_Width) - B2_X) < Overlap Then
Side = COL_RIGHT
Overlap = Abs((B1_X + B1_Width) - B2_X)
End If
If Abs(B1_Y - (B2_Y + B2_Height)) < Overlap Then
Side = COL_UP
Overlap = Abs(B1_Y - (B2_Y + B2_Height))
End If
If Abs((B1_Y + B1_Height) - B2_Y) < Overlap Then
Side = COL_DOWN
Overlap = Abs((B1_Y + B1_Height) - B2_Y)
End If
Collision_Box_To_Box = Side
End Function
Private Function Collision_Detection2(ByVal Overlap As Long)
Const NO_COLLISION As Long = 0
Const COL_LEFT As Long = 1
Const COL_RIGHT As Long = 2
Const COL_UP As Long = 3
Const COL_DOWN As Long = 4
Dim Side As Long
With Player
Side = Collision_Box_To_Box(Player.Position.X, Player.Position.Y, Player.Width, Player.Height, Monster.Position.X, Monster.Position.Y, Monster.Width, Monster.Height)
If Side <> 0 Then
Collision_Detection2 = True
.Collided = True
'Collision Response
Select Case Side
Case COL_LEFT: .Position.X = .Position.X + Overlap
Case COL_RIGHT:: .Position.X = .Position.X - Overlap
Case COL_UP:: .Position.Y = .Position.Y + Overlap
Case COL_DOWN:: .Position.Y = .Position.Y - Overlap
(Continued from above post) Also just to let ya know, if the collision isn't a sprite and its a tile in a tile engine, I do something differently but with the same algorithm. Most people would make the fatal mistake of looping through the whole map one tile at a time to check if a collision took place with the sprite. But if your map is gigantic in size, this would be sluggish. The faster way would be to check all 9 sides of the sprite to see if it collided into the tile surrounding it. Why check all 9 sides and not just the sprite itself? Cause if you are approaching the walls at an angle or move into a corner, you end up going through the walls! So for example, if you use rigid body collision, you do this, assuming you got a tile engine going:
(Continued from above post) Also just to let ya know, if the collision isn't a sprite and its a tile in a tile engine, I do something differently but with the same algorithm. Most people would make the fatal mistake of looping through the whole map one tile at a time to check if a collision took place with the sprite. But if your map is gigantic in size, this would be sluggish. The faster way would be to check all 9 sides of the sprite to see if it collided into the tile surrounding it. Why check all 9 sides and not just the sprite itself? Cause if you are approaching the walls at an angle or move into a corner, you end up going through the walls! So for example, if you use rigid body collision, you do this, assuming you got a tile engine going:
Animation:
in Game Loop. how you calculate de milliseconds for the sprite animation?
(i understand that these questions are a basic game questions, but i can't find any manual that tell us these basic things. i know use transparentblt()(i don't use bitblt() because is more difficulty for mask). the GetTickCount() is more complicate to understand, but ok. i even didn't knew if you use form keyboard events or the keystate() api function. instead ask very things like these basic normal things, can you advice some nice toturial?)
(sorry if i bored you, but "if i don't have the path i can't walk")
in Game Loop. how you calculate de milliseconds for the sprite animation?
Could you be a little more specific? Are you referring to animation speed? Or how long it took to fully animate? Or what
Originally Posted by joaquim
the GetTickCount() is more complicate to understand, but ok
I personally don't use GetTickCount(). Instead I use a high resolution timer for more accurate time using QueryPerformanceCounter and QueryPerformanceFrequency API's. Heres an example program and some typical functions I use with them in action:
vb Code:
Option Explicit
Private Declare Function QueryPerformanceCounter Lib "kernel32" (lpPerformanceCount As Currency) As Long
Private Declare Function QueryPerformanceFrequency Lib "kernel32" (lpPerformanceCount As Currency) As Long
Private Ticks_Per_Second As Currency
Private Start_Time As Currency
Private Time As Single
Private Milliseconds As Single
Private Running As Boolean
'Some boolean variable to control time
Private Time_Enabled As Boolean
Private Function Hi_Res_Timer_Initialize() As Boolean
If QueryPerformanceFrequency(Ticks_Per_Second) = 0 Then
Another function I use for non DirectX apps since DirectX handles the framerate for you is Lock_Framerate, which is also dependent on the QueryPerformanceCounter API:
thanks for everything Jacob.
"Could you be a little more specific? Are you referring to animation speed? Or how long it took to fully animate? Or what???"
yes animation speed. the time what you use for change the frame.
how you do that?
Here's an example program, although I haven't tested it:
vb Code:
Option Explicit
Private Type Vector
X As Single
Y As Single
End Type
Private Type RECT
Left As Long
Top As Long
Right As Long
Bottom As Long
End Type
Private Type Animation_Type
Frame_Size() As RECT
Number_Of_Frames As Long
Number_Of_Textures As Long
Current_Frame As Single
Current_Texture As Long
Frame_Counter As Long
Speed As Single
Mode As Long 'Single Shot, Loop, etc.
Offset() As Vector
Texture_Number() As Long
End Type
Private Type Sprite_Type
X As Single
Y As Single
Animation_State() As Animation_Type
Texture_Path() As String
Texture_List() As Image
Total_Number_Of_Textures As Long
Transparency_Color As Long
Number_Of_Animation_States As Long
Current_Animation_State As Long
End Type
Private Declare Function TransparentBlt Lib "msimg32.dll" (ByVal hDC As Long, ByVal X As Long, ByVal Y As Long, ByVal nWidth As Long, ByVal nHeight As Long, ByVal hSrcDC As Long, ByVal xSrc As Long, ByVal ySrc As Long, ByVal nSrcWidth As Long, ByVal nSrcHeight As Long, ByVal crTransparent As Long) As Boolean
Private Const ANIMATION_MODE_SINGLE_SHOT As Long = 0
Private Const ANIMATION_MODE_LOOP As Long = 1
Private Sprite As Sprite_Type
Private Running As Boolean
Private Sub Load_Textures()
Dim Width As Long
Dim Height As Long
Dim Current_Texture As Long
With Sprite
ReDim .Texture_Path(.Total_Number_Of_Textures) As String
ReDim .Texture_List(.Total_Number_Of_Textures) As Image
"It's better if you lock the framerate at 60 or itll go too fast for ya."
what you mean by that?
instead you give me an entire code, can you tell me how you calculate a the time?
thanks
PS: it's better create a class(to be a padron for wall's\persons\objects\others) or a normal type?
(the class can have everything. frames count\time\images, position\size and more)
'Getting FPS should be at the end of the game loop
Frame_Count = Frame_Count + 1
If Get_Elapsed_Time - Milliseconds >= 1 Then
Get_FPS = Frame_Count
Frame_Count = 0
Milliseconds = Get_Elapsed_Time
End If
Lock_Framerate 60 '60 frames per second
DoEvents
Loop
End Sub
Private Sub Form_Unload(Cancel As Integer)
Running = False
Unload Me
End Sub
You just need to blend that code with the animation stuff I gave ya. Also you can go either or with modules or classes. They both work. With me though, I personally just stick with modules but thats just me. It was just easier for me to handle than classes. Do whatever is easier for you
Yes you can. And the reason why its looping inside another is cause it needs to lock the frame rate. You can have the framerate whatever you wish but typically in games its 60 FPS. It's similar to the Sleep API only different. But like I said, if you ever tap into DirectX, it does it for you so you wouldnt need to lock the framerate then.
Yes you can. And the reason why its looping inside another is cause it needs to lock the frame rate. You can have the framerate whatever you wish but typically in games its 60 FPS. It's similar to the Sleep API only different. But like I said, if you ever tap into DirectX, it does it for you so you wouldnt need to lock the framerate then.
thanks for everything. thanks for your time.
(sorry i can't rate you more)