(10-09-2024, 03:33 PM)TerryRitchie Wrote: LOL, yeah, well, I asked for help when I was beginning lesson 17 way back in early 2022 however no one had the time to help. When I finished it I asked those with math inclinations to look it over for correctness. Again, nothing, so I figured what I had was good. I am completely self taught when it comes to math.
What is happening here is my confusion over mixing the need to orientate everything to match the screen versus the correct orientation. I've gotten much better over the past 2.5 years and yes, I see the issues you have pointed out.
I would gladly welcome help to correct this lesson.
An update for you from Discord so you won't be as down with yourself.
Quote::17 PM]Pouli: Yeah maybe, but I am doing a Q64 progammin so that should of been obvious. And since Im doing that, I thinking Qb64 cordinate system. And thats why the lessons are set like that, I think. But I found exact part of that lesson yesterday that I believe has the answer Im looking for. I was thinking to actually dig it in to it today with fresh mind. (edited)
[7:57 PM]Pouli: So... This is what I wanted to do. I was thinking it wrong way as I assumed. And I have made mistakes with the cordinates too.
'Moving one point (x1,y1) towards another (x2,y2)
'Set up screen
screen1 = _NewImage(1280, 720, 32)
Screen screen1
'Point 1 (from)
x1 = 636
y1 = 356
'Point 2 (to)
x2 = 900
y2 = 100
vx = x2 - x1
vy = y2 - y1
D = _Hypot(vx, vy) 'Distance between two points
'Normalize to vectors if distance is not 0
If D <> 0 Then
vx = vx / D
vy = vy / D
Else
vx = 0
vy = 0
End If
Do
Cls
'Move points
x1 = x1 + vx
y1 = y1 + vy
'Draw points
PSet (x1, y1)
PSet (x2, y2)
_Display
_Limit 60
Loop
[8:05 PM]Pouli: I might be able to compress this even further if needed, but the idea works now. I really like Terry's lessons. These topics are not exactly my strong suit, as we have seen. However, the examples and the way the lessons present them help a lot, and now I actually understand how and why it's solved like this. Or maybe this is just one way to do it. This is also why I wanted to try something I'm not super good at, and to learn new things along the way. This is why I think programming is so cool, and QB64 is the perfect tool to try and learn new things. Thanks, Terry, for the lessons, and thanks to everyone for the help and patience.
THIS:
I might be able to compress this even further if needed, but the idea works now. I really like Terry's lessons. These topics are not exactly my strong suit, as we have seen. However, the examples and the way the lessons present them help a lot, and now I actually understand how and why it's solved like this. Or maybe this is just one way to do it. This is also why I wanted to try something I'm not super good at, and to learn new things along the way. This is why I think programming is so cool, and QB64 is the perfect tool to try and learn new things. Thanks, Terry, for the lessons, and thanks to everyone for the help and patience.
Type XYPAIR ' x,y value definition
X As Single ' x value
Y As Single ' y value
End Type
Type SHIP_Type ' ship definition First 2 needed for DrawShip
Loc As XYPAIR ' where the ship center is on screen
Heading As Single ' Degree angle the ship is pointed towards
V As XYPAIR ' Normal vector: V.X = CosD(Ship.Heading) V.Y = SinD(Ship.Heading)
Velocity As Single ' mult. Normal Vector by Velocity add to old Loc for new Location
End Type
Dim ship As SHIP_Type ' get our ship started!
Dim angle ' degrees for the compass
Dim showCompass As Integer ' show Compass toggle flag
showCompass = -1 ' turn the toggle on
ship.Loc.X = 400 ' ship's x coordinate on screen
ship.Loc.Y = 300 ' ship's y coordinate on screen
ship.Heading = 270 ' let's head North for starters
ship.Velocity = 5 ' ship's speed
Do ' begin main loop
Cls ' clear screen
Print ' here are instructions to user cp = Center Print
cp "Right/Left Arrow keys to turn, Up Arrow key to move forward"
cp "Spacebar to toggle Compass Off/On"
DrawShip ship.Loc, ship.Heading
If showCompass Then ' I like your idea Terry to show turn ticks, here is a nice Compass for you.
For angle = 0 To 359 Step 15
PSet (ship.Loc.X + 62 * CosD(angle), ship.Loc.Y + 62 * SinD(angle)) ' draw pixel at 10 degree point
If angle = 0 Then
_PrintString (ship.Loc.X + 62 * CosD(angle) + 3, ship.Loc.Y + 62 * SinD(angle) - 7), "E"
ElseIf angle = 90 Then
_PrintString (ship.Loc.X + 62 * CosD(angle) - 2, ship.Loc.Y + 62 * SinD(angle) + 1), "S"
ElseIf angle = 180 Then
_PrintString (ship.Loc.X + 62 * CosD(angle) - 11, ship.Loc.Y + 62 * SinD(angle) - 7), "W"
ElseIf angle = 270 Then
_PrintString (ship.Loc.X + 62 * CosD(angle) - 2, ship.Loc.Y + 62 * SinD(angle) - 16), "N"
End If
Next
End If
If _KeyDown(18432) Then ' up arrow key pressed? move it!
ship.V.X = CosD(ship.Heading) ' very simple formula for normal x component of vector
ship.V.Y = SinD(ship.Heading) ' very simple formula for normal y component of vector
ship.Loc.X = ship.Loc.X + ship.V.X * ship.Velocity ' new X location for ship
ship.Loc.Y = ship.Loc.Y + ship.V.Y * ship.Velocity ' new Y location for ship
If ship.Loc.X < 0 Then ShipLoc.x = 0 ' keep ship on screen just stop!
If ship.Loc.X > _Width Then ship.Loc.X = _Width ' when at border
If ship.Loc.Y < 0 Then ship.Loc.Y = 0 ' of the screen
If ship.Loc.Y > _Height Then ShipLoc.y = _Height
End If
If _KeyDown(19200) Then ship.Heading = ship.Heading - 1 ' nose heading counter-clockwise to left
If _KeyDown(19712) Then ship.Heading = ship.Heading + 1 ' nose heading clockwise to right
If _KeyHit = 32 Then showCompass = Not showCompass ' toggle flag when space bar pressed
_Display ' update screen with changes
_Limit 60 ' gots to have pause for _keydown release or ship will spin like mad!
Loop Until _KeyDown(27) ' leave when ESC pressed
System
Sub DrawShip (place As XYPAIR, DegreeHeading As Single) ' hey we can use this design in another app!!!
Dim As Single radius
radius = 60 ' nose and wing tips touch radius around central location = placeXY
Dim pts(1 To 3) As XYPAIR 'the 3 outer points for triangle ship with 2 wings fit on radius
pts(1).X = place.X + radius * CosD(0 + DegreeHeading) ' nose at 0 degrees
pts(1).Y = place.Y + radius * SinD(0 + DegreeHeading)
pts(2).X = place.X + radius * CosD(135 + DegreeHeading) ' 180 - 45 SW wing tip
pts(2).Y = place.Y + radius * SinD(135 + DegreeHeading)
pts(3).X = place.X + radius * CosD(225 + DegreeHeading) ' 180 + 45 NW wing tip
pts(3).Y = place.Y + radius * SinD(225 + DegreeHeading)
Line (pts(1).X, pts(1).Y)-(pts(2).X, pts(2).Y)
Line (pts(2).X, pts(2).Y)-(place.X, place.Y)
Line (pts(3).X, pts(3).Y)-(place.X, place.Y)
Line (pts(3).X, pts(3).Y)-(pts(1).X, pts(1).Y)
End Sub
' use angles in degrees units instead of radians (converted inside sub)
Function CosD (degrees)
' Note this function uses whatever the default type is, better not be some Integer Type.
CosD = Cos(_D2R(degrees))
End Function
' use angles in degrees units instead of radians (converted inside sub)
Function SinD (degrees)
' Note this function uses whatever the default type is, better not be some Integer Type.
SinD = Sin(_D2R(degrees))
End Function
Sub cp (s$) ' cp = Center Print string s$ assuming 8 pixel width font on graphics screen
Print Space$(((_Width / 8) - Len(s$)) / 2); s$
End Sub
Here is same exact project in Radians Only for comparison: (I remembered this code was suppose to be a Radian Demo)
Type XYPAIR ' x,y value definition
X As Single ' x value
Y As Single ' y value
End Type
Type SHIP_Type ' ship definition First 2 needed for DrawShip
Loc As XYPAIR ' where the ship center is on screen
Heading As Single ' Degree angle the ship is pointed towards
V As XYPAIR ' Normal vector: V.X = cos(Ship.Heading) V.Y = sin(Ship.Heading)
Velocity As Single ' mult. Normal Vector by Velocity add to old Loc for new Location
End Type
Dim ship As SHIP_Type ' get our ship started!
Dim angle ' degrees for the compass
Dim showCompass As Integer ' show Compass toggle flag
showCompass = -1 ' turn the toggle on
ship.Loc.X = 400 ' ship's x coordinate on screen
ship.Loc.Y = 300 ' ship's y coordinate on screen
ship.Heading = _Pi(3 / 2) ' let's head North for starters
ship.Velocity = 5 ' ship's speed
Do ' begin main loop
Cls ' clear screen
Print ' here are instructions to user cp = Center Print
cp "Right/Left Arrow keys to turn, Up Arrow key to move forward"
cp "Spacebar to toggle Compass Off/On"
DrawShip ship.Loc, ship.Heading
If showCompass Then ' I like your idea Terry to show turn ticks, here is a nice Compass for you.
For angle = 0 To _Pi(1.99) Step _Pi(2 / 24)
PSet (ship.Loc.X + 62 * Cos(angle), ship.Loc.Y + 62 * Sin(angle)) ' draw pixel at 10 degree point
If angle = 0 Then
_PrintString (ship.Loc.X + 62 * Cos(angle) + 3, ship.Loc.Y + 62 * Sin(angle) - 7), "E"
ElseIf Abs(angle - _Pi(.5)) < .0001 Then
_PrintString (ship.Loc.X + 62 * Cos(angle) - 2, ship.Loc.Y + 62 * Sin(angle) + 1), "S"
ElseIf Abs(angle - _Pi) < .0001 Then
_PrintString (ship.Loc.X + 62 * Cos(angle) - 11, ship.Loc.Y + 62 * Sin(angle) - 7), "W"
ElseIf Abs(angle - _Pi(3 / 2)) < .0001 Then
_PrintString (ship.Loc.X + 62 * Cos(angle) - 2, ship.Loc.Y + 62 * Sin(angle) - 16), "N"
End If
Next
End If
If _KeyDown(18432) Then ' up arrow key pressed? move it!
ship.V.X = Cos(ship.Heading) ' very simple formula for normal x component of vector
ship.V.Y = Sin(ship.Heading) ' very simple formula for normal y component of vector
ship.Loc.X = ship.Loc.X + ship.V.X * ship.Velocity ' new X location for ship
ship.Loc.Y = ship.Loc.Y + ship.V.Y * ship.Velocity ' new Y location for ship
If ship.Loc.X < 0 Then ShipLoc.x = 0 ' keep ship on screen just stop!
If ship.Loc.X > _Width Then ship.Loc.X = _Width ' when at border
If ship.Loc.Y < 0 Then ship.Loc.Y = 0 ' of the screen
If ship.Loc.Y > _Height Then ShipLoc.y = _Height
End If
If _KeyDown(19200) Then ship.Heading = ship.Heading - _Pi(1 / 180) ' nose counter-clockwise to left
If _KeyDown(19712) Then ship.Heading = ship.Heading + _Pi(1 / 180) ' nose heading clockwise to right
If _KeyHit = 32 Then showCompass = Not showCompass ' toggle flag when space bar pressed
_Display ' update screen with changes
_Limit 60 ' gots to have pause for _keydown release or ship will spin like mad!
Loop Until _KeyDown(27) ' leave when ESC pressed
System
Sub DrawShip (place As XYPAIR, DegreeHeading As Single) ' hey we can use this design in another app!!!
Dim As Single radius
radius = 60 ' nose and wing tips touch radius around central location = placeXY
Dim pts(1 To 3) As XYPAIR 'the 3 outer points for triangle ship with 2 wings fit on radius
pts(1).X = place.X + radius * Cos(0 + DegreeHeading) ' nose at 0 degrees
pts(1).Y = place.Y + radius * Sin(0 + DegreeHeading)
pts(2).X = place.X + radius * Cos(_Pi(3 / 4) + DegreeHeading) ' 180 - 45 SW wing tip
pts(2).Y = place.Y + radius * Sin(_Pi(3 / 4) + DegreeHeading)
pts(3).X = place.X + radius * Cos(_Pi(5 / 4) + DegreeHeading) ' 180 + 45 NW wing tip
pts(3).Y = place.Y + radius * Sin(_Pi(5 / 4) + DegreeHeading)
Line (pts(1).X, pts(1).Y)-(pts(2).X, pts(2).Y)
Line (pts(2).X, pts(2).Y)-(place.X, place.Y)
Line (pts(3).X, pts(3).Y)-(place.X, place.Y)
Line (pts(3).X, pts(3).Y)-(pts(1).X, pts(1).Y)
End Sub
Sub cp (s$) ' cp = Center Print string s$ assuming 8 pixel width font on graphics screen
Print Space$(((_Width / 8) - Len(s$)) / 2); s$
End Sub
Instead of Asteroid making I did a host or regular Polygons to demo Sin and Cos Function with Angles and Movement for lesson 17
Code: (Select All)
_Title "Regular Polygons Demo of Sin and Cos" ' bplus 2024-10-10
Option _Explicit
Type XYPair
As Single X, Y
End Type
Type PolyType 'first 5 for DrawPoly
As XYPair Loc ' Location on screen
As Long NSides ' Number of sides = Number of points
As Single Radius ' From center to point
As Single Rotation ' Rotation offset = how much is poly turned
As _Unsigned Long Colr ' color
As XYPair V ' Vx, Vy Vector components for movement
As Single RotAmt ' Rotate Poly this angle amount
End Type
Dim Shared NPoly: NPoly = 20
Dim Shared Poly(1 To NPoly) As PolyType
Screen _NewImage(800, 600, 32)
_ScreenMove 250, 60
Dim As Long i
For i = 1 To NPoly
NewPoly i
Next
Do
Cls
For i = 1 To NPoly 'draw amd update polys
DrawPoly Poly(i).Loc, Poly(i).NSides, Poly(i).Radius, Poly(i).Rotation, Poly(i).Colr
' update poly position and rotation
Poly(i).Loc.X = Poly(i).Loc.X + Poly(i).V.X
If Poly(i).Loc.X < 0 Then Poly(i).Loc.X = 0: Poly(i).V.X = -Poly(i).V.X
If Poly(i).Loc.X > _Width Then Poly(i).Loc.X = _Width: Poly(i).V.X = -Poly(i).V.X
Poly(i).Loc.Y = Poly(i).Loc.Y + Poly(i).V.Y
If Poly(i).Loc.Y < 0 Then Poly(i).Loc.Y = 0: Poly(i).V.Y = -Poly(i).V.Y
If Poly(i).Loc.Y > _Height Then
Poly(i).Loc.Y = _Height: Poly(i).V.Y = -Poly(i).V.Y
If Poly(i).NSides < 9 Then Poly(i).NSides = Poly(i).NSides + 1 Else Poly(i).NSides = 3
End If
Poly(i).Rotation = Poly(i).Rotation + Poly(i).RotAmt
Next
_Display
_Limit 30
Loop Until _KeyDown(27) ' escape
Sub DrawPoly (Place As XYPair, NSides As Long, Radius, RadRotation, C As _Unsigned Long)
Dim pAngle: pAngle = _Pi(2 / NSides) ' angles from center to side points
Dim a, savex, savey
For a = 0 To _Pi(1.9999) Step pAngle
If a = 0 Then
PSet (Place.X + Radius * Cos(a + RadRotation), Place.Y + Radius * Sin(a + RadRotation)), C
savex = Place.X + Radius * Cos(a + RadRotation)
savey = Place.Y + Radius * Sin(a + RadRotation)
Else
Line -(Place.X + Radius * Cos(a + RadRotation), Place.Y + Radius * Sin(a + RadRotation)), C
End If
Next
Line -(savex, savey), C
End Sub
Sub clock_EastIsZero_Face (x, y, r)
' x, y center r = radius
' for (x, y) around circle with center (xc, yc)
' if 0 degrees is East as it is for all Basic Trig Functions
' x = xc + r * cos(a)
' y = yc + r * sin(a)
' and hour starts at 3 o'clock for 0 Degrees
hour = 3 ' at a = 0 the first circle for hour will be drawn due East
For a = 0 To 359 Step 6 ' 360/6 = 60 tick for minutes
' mod 30 ? 360/30 = 12 ticks for every hour so make circle big enough to fit 2 digits 16x16
If a Mod 30 = 0 Then r1 = 0 Else r1 = 1 / 75 * r
' !!!!!!!!!!!!!!!!!!!! Regular Formula for x, y around circle center(x, y) !!!!!!!!!!!!!!!
circX = x + r * Cos(_D2R(a))
circY = y + r * Sin(_D2R(a))
' !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
If r1 Then Circle (circX, circY), r1, _RGB32(255, 255, 255)
If r1 Then Paint (circX, circY), _RGB32(255, 255, 255), _RGB32(255, 255, 255)
If a Mod 30 = 0 Then ' label hour
hourStr$ = _Trim$(Str$(hour))
xoffset = _PrintWidth(hourStr$) / 2
yoffset = 32 / 2
_PrintString (circX - xoffset, circY - yoffset), _Trim$(Str$(hour))
hour = hour + 1 ' get ready for next label
If hour > 12 Then hour = 1 ' cycle back to 1 after label 12
End If
Next
' the rest of this is based on regular East = 0 degrees
If Val(Left$(Time$, 2)) + (Val(Mid$(Time$, 4, 2)) / 60) >= 12 Then hrs = Val(Left$(Time$, 2)) + (Val(Mid$(Time$, 4, 2)) / 60) - 12 Else hrs = Val(Left$(Time$, 2)) + (Val(Mid$(Time$, 4, 2)) / 60)
ftri x + 1 / 15 * r * Cos(Val(Mid$(Time$, 4, 2)) * _Pi(1 / 30) - _Pi(1 / 2) + _Pi(1 / 2)), y + 1 / 15 * r * Sin(Val(Mid$(Time$, 4, 2)) * _Pi(1 / 30) - _Pi(1 / 2) + _Pi(1 / 2)), x + 1 / 15 * r * Cos(Val(Mid$(Time$, 4, 2)) * _Pi(1 / 30) - _Pi(1 / 2) - _Pi(1 / 2)), y + 1 / 15 * r * Sin(Val(Mid$(Time$, 4, 2)) * _Pi(1 / 30) - _Pi(1 / 2) - _Pi(1 / 2)), x + r * Cos(Val(Mid$(Time$, 4, 2)) * _Pi(1 / 30) - _Pi(1 / 2)), y + r * Sin(Val(Mid$(Time$, 4, 2)) * _Pi(1 / 30) - _Pi(1 / 2)), _RGB32(255, 0, 0)
ftri x + 1 / 10 * r * Cos(hrs * _Pi(1 / 6) - _Pi(1 / 2) + _Pi(1 / 2)), y + 1 / 10 * r * Sin(hrs * _Pi(1 / 6) - _Pi(1 / 2) + _Pi(1 / 2)), x + 1 / 10 * r * Cos(hrs * _Pi(1 / 6) - _Pi(1 / 2) - _Pi(1 / 2)), y + 1 / 10 * r * Sin(hrs * _Pi(1 / 6) - _Pi(1 / 2) - _Pi(1 / 2)), x + 2 / 3 * r * Cos(hrs * _Pi(1 / 6) - _Pi(1 / 2)), y + 2 / 3 * r * Sin(hrs * _Pi(1 / 6) - _Pi(1 / 2)), _RGB32(0, 0, 255)
Line (x, y)-(x + r * Cos(Val(Right$(Time$, 2)) * _Pi(1 / 30) - _Pi(1 / 2)), y + r * Sin(Val(Right$(Time$, 2)) * _Pi(1 / 30) - _Pi(1 / 2))), _RGB32(255, 255, 0)
Circle (x, y), 1 / 10 * r, _RGB32(255, 255, 255)
Paint (x + 1 / 75 * r, y + 1 / 75 * r), _RGB32(100, 100, 100), _RGB32(255, 255, 255)
Circle (x, y), 1 / 30 * r, _RGB32(0, 0, 0)
End Sub
Sub clock_NorthIsZero_Face (x, y, r)
' x, y center r = radius
' if 0 degrees is North then Rotate -90 degrees the angles
' for (x, y) around circle with center (xc, yc)
' x = xc + r * cos(a) BECOMES x = xc + sin(a) !!!!!!!!!!
' y = yc + r * sin(a) BECOMES y = yc + -cos(a) !!!!!!!!!!
' and hour starts at 12 o'clock for "0 degrees"
hour = 12 ' at a = 0 the first circle for hour will be drawn due East
For a = 0 To 359 Step 6 ' 360/6 = 60 tick for minutes
' mod 30 ? 360/30 = 12 ticks for every hour so make circle big enough to fit 2 digits 16x16
If a Mod 30 = 0 Then r1 = 0 Else r1 = 1 / 75 * r
' !!!!! Formula for (x, y) about circle center(x, y) !!!!!!!!!
circX = x + r * Sin(_D2R(a))
circY = y + r * -Cos(_D2R(a))
' !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
If r1 Then Circle (circX, circY), r1, _RGB32(255, 255, 255)
If r1 Then Paint (circX, circY), _RGB32(255, 255, 255), _RGB32(255, 255, 255)
If a Mod 30 = 0 Then ' label hour
hourStr$ = _Trim$(Str$(hour))
xoffset = _PrintWidth(hourStr$) / 2
yoffset = 32 / 2
_PrintString (circX - xoffset, circY - yoffset), _Trim$(Str$(hour))
hour = hour + 1 ' get ready for next label
If hour > 12 Then hour = 1 ' cycle back to 1 after label 12
End If
Next
' the rest of this is based on normal East = 0 degrees
If Val(Left$(Time$, 2)) + (Val(Mid$(Time$, 4, 2)) / 60) >= 12 Then hrs = Val(Left$(Time$, 2)) + (Val(Mid$(Time$, 4, 2)) / 60) - 12 Else hrs = Val(Left$(Time$, 2)) + (Val(Mid$(Time$, 4, 2)) / 60)
ftri x + 1 / 15 * r * Cos(Val(Mid$(Time$, 4, 2)) * _Pi(1 / 30) - _Pi(1 / 2) + _Pi(1 / 2)), y + 1 / 15 * r * Sin(Val(Mid$(Time$, 4, 2)) * _Pi(1 / 30) - _Pi(1 / 2) + _Pi(1 / 2)), x + 1 / 15 * r * Cos(Val(Mid$(Time$, 4, 2)) * _Pi(1 / 30) - _Pi(1 / 2) - _Pi(1 / 2)), y + 1 / 15 * r * Sin(Val(Mid$(Time$, 4, 2)) * _Pi(1 / 30) - _Pi(1 / 2) - _Pi(1 / 2)), x + r * Cos(Val(Mid$(Time$, 4, 2)) * _Pi(1 / 30) - _Pi(1 / 2)), y + r * Sin(Val(Mid$(Time$, 4, 2)) * _Pi(1 / 30) - _Pi(1 / 2)), _RGB32(255, 0, 0)
ftri x + 1 / 10 * r * Cos(hrs * _Pi(1 / 6) - _Pi(1 / 2) + _Pi(1 / 2)), y + 1 / 10 * r * Sin(hrs * _Pi(1 / 6) - _Pi(1 / 2) + _Pi(1 / 2)), x + 1 / 10 * r * Cos(hrs * _Pi(1 / 6) - _Pi(1 / 2) - _Pi(1 / 2)), y + 1 / 10 * r * Sin(hrs * _Pi(1 / 6) - _Pi(1 / 2) - _Pi(1 / 2)), x + 2 / 3 * r * Cos(hrs * _Pi(1 / 6) - _Pi(1 / 2)), y + 2 / 3 * r * Sin(hrs * _Pi(1 / 6) - _Pi(1 / 2)), _RGB32(0, 0, 255)
Line (x, y)-(x + r * Cos(Val(Right$(Time$, 2)) * _Pi(1 / 30) - _Pi(1 / 2)), y + r * Sin(Val(Right$(Time$, 2)) * _Pi(1 / 30) - _Pi(1 / 2))), _RGB32(255, 255, 0)
Circle (x, y), 1 / 10 * r, _RGB32(255, 255, 255)
Paint (x + 1 / 75 * r, y + 1 / 75 * r), _RGB32(100, 100, 100), _RGB32(255, 255, 255)
Circle (x, y), 1 / 30 * r, _RGB32(0, 0, 0)
End Sub
Sub ftri (x1, y1, x2, y2, x3, y3, K As _Unsigned Long)
a& = _NewImage(1, 1, 32)
_Dest a&
PSet (0, 0), K
_Dest 0
_MapTriangle _Seamless(0, 0)-(0, 0)-(0, 0), a& To(x1, y1)-(x2, y2)-(x3, y3)
_FreeImage a& '<<< this is important!
End Sub
BTW @TerryRitchie it took me forever to figure out why my Asteroids were upside down to yours.
You didn't follow your own rotation formula:
' for (x, y) around circle with center (xc, yc)
' x = xc + r * cos(a) BECOMES x = xc + sin(a) !!!!!!!!!!
' y = yc + r * sin(a) BECOMES y = yc + -cos(a) !!!!!!!!!!
You used a positive Cos eg, y = yc + r * cos(a)
Probably hacking the code because an unmodified _Atan2 was drawing it upside down with the minus sign.
' testing an ATan function that would return 0 for North AND increase going Clockwise around
Screen _NewImage(1200, 600, 32)
_ScreenMove 40, 60
Dim degree30, xc1, xc, yc, xc2, r, a, x1, y1, at, sa$, xoff, yoff, x2, y2
degree30 = _Pi(2 / 12) ' like hours on clock
xc1 = 300: xc2 = 900: yc = 300: r = 200
_PrintString (xc1 - _PrintWidth("Regular East = 0 Deg/Rads Calcs") / 2, 292), "Regular East = 0 Deg/Rads Calcs"
_PrintString (xc2 - _PrintWidth("Terry's North = 0 Deg/Rads Calcs") / 2, 292), "Terry's North = 0 Deg/Rads Calcs"
For a = 0 To _Pi(1.999) Step degree30
' Regular East = 0 calcs
x1 = xc1 + r * Cos(a)
y1 = yc + r * Sin(a)
at = Int(_R2D(_Atan2(y1 - yc, x1 - xc1)) + .0001)
If at < 0 Then at = at + 360
sa$ = _Trim$(Str$(at))
xoff = _PrintWidth(sa$) / 2
yoff = 16 / 2
_PrintString (x1 - xoff, y1 - yoff), sa$
' North = 0 calcs
x2 = xc2 + r * Sin(a)
y2 = yc + r * -Cos(a)
at = Int(_R2D(ATan4North0(y2 - yc, x2 - xc2)) + .0001)
If at < 0 Then at = at + 360
sa$ = _Trim$(Str$(at))
xoff = _PrintWidth(sa$) / 2
yoff = 16 / 2
_PrintString (x2 - xoff, y2 - yoff), sa$
_Limit 1
Next
Function ATan4North0 (dy, dx)
ATan4North0 = _Pi - _Atan2(dx, dy) ' this was totally unexpected!
End Function
See now it fixes a couple mixups in Lesson 17 Asteroid Demo
Code: (Select All)
_Title "** Asteroid demo using radians fix" ' bplus 2024-10-11
' fix -COS and alternate _ATAN2 for North = 0 calcs using ATan4North0
' From Lesson 17
' Vx! = Sin(_D2R(Degree!)) ' calculate the x vector quantity
' Vy! = -Cos(_D2R(Degree!)) ' calculate the y vector quantity
' Notice the negative sign next to Cos.
' This is a rotation of the coordinate system so _Atan2 is not going to return
' correct radian angle to match North = 0
' I added a modified ATan4North function to use in place of _Atan2 for Asteroid Demo
' to work as Terry intended using those Vx Vy forumlas.
Const FALSE = 0, TRUE = Not FALSE ' truth detectors
Const PI = 3.1415926, PI2 = 2 * PI ' useful PI values
Const SPINRATE = PI2 / 360 ' asteroid spin rate
Const SWIDTH = 640, SHEIGHT = 480 ' screen dimensions
Const MAXASTEROIDS = 20 ' number of asteroids on screen
Type XYPAIR ' 2D point location definition
x As Single ' x coordinate
y As Single ' y coordinate
End Type
Type OBJECT ' object definition (points that make up an object)
Radian As Single ' direction of point
Radius As Single ' distance to point from center
End Type
Type ASTEROID ' asteroid definition
Loc As XYPAIR ' asteroid location
Dir As Single ' asteroid radian direction
Speed As Integer ' asteroid speed
Size As Integer ' asteroid size
End Type
Dim Object(10) As OBJECT ' object point data
Dim Asteroid(MAXASTEROIDS) As ASTEROID ' asteroids array
Dim Vector As XYPAIR ' vector calculations
Dim Obj As Integer ' object counter
Dim Ast As Integer ' asteroid counter
Dim P1 As XYPAIR ' first object point for PSET
Dim Np As XYPAIR ' next object point for LINE
Dim Spin As Integer ' TRUE to activate spin, FALSE otherwise
Randomize Timer ' seed RND generator
For Obj = 1 To 10 ' cycle through object points
Read Vector.x, Vector.y ' get object x,y vector point
Object(Obj).Radius = _Hypot(Vector.x, Vector.y) ' calculate radius from vector
' _Atan2 takes y's first , x's 2nd
' so modified ATan4North0(Vector.y, Vector.x)
' uses the same order
Object(Obj).Radian = ATan4North0(Vector.y, Vector.x) ' calculate direction from vector
Next Obj
For Ast = 1 To MAXASTEROIDS ' cycle through asteroids
Asteroid(Ast).Loc.x = Int(Rnd * (SWIDTH - 40)) + 20 ' random location
Asteroid(Ast).Loc.y = Int(Rnd * (SHEIGHT - 40)) + 20
Asteroid(Ast).Dir = Rnd * PI2 ' random direction
Asteroid(Ast).Speed = Int(Rnd * 6) + 2 ' random speed
Asteroid(Ast).Size = 2 ^ Int(Rnd * 3) ' random size
Next Ast
Screen _NewImage(SWIDTH, SHEIGHT, 32) ' graphics screen
Spin = FALSE ' no asteroid spin
Do ' begin main loop
Cls ' clear screen
_Limit 60 ' 60 frames per second
Locate 2, 19: Print "Press the spacebar to activate asteroid spin" ' print directions
If _KeyHit = 32 Then Spin = Not Spin ' flip spin flag if spacebar pressed
If Spin Then ' spin asteroids?
For Obj = 1 To 10 ' yes, cycle through object points
Object(Obj).Radian = Object(Obj).Radian + SPINRATE ' move radian location
If Object(Obj).Radian > PI2 Then Object(Obj).Radian = Object(Obj).Radian - PI2 ' keep within limits
Next Obj
End If
For Ast = 1 To MAXASTEROIDS ' cycle through asteroids
Vector.x = Sin(Object(1).Radian) ' calculate vector from 1st object point
Vector.y = -Cos(Object(1).Radian) ' <<< This should be -Cos
P1.x = Asteroid(Ast).Loc.x + Vector.x * Object(1).Radius * Asteroid(Ast).Size ' plot location on screen
P1.y = Asteroid(Ast).Loc.y + Vector.y * Object(1).Radius * Asteroid(Ast).Size
PSet (P1.x, P1.y) ' draw a pixel
For Obj = 2 To 10 ' cycle through remaining points
' these assume North = 0 so Vectors are rotated 90 degrees
Vector.x = Sin(Object(Obj).Radian) ' calculate vector from object point
Vector.y = -Cos(Object(Obj).Radian) ' <<<< this should be -Cos
Np.x = Asteroid(Ast).Loc.x + Vector.x * Object(Obj).Radius * Asteroid(Ast).Size ' plot location
Np.y = Asteroid(Ast).Loc.y + Vector.y * Object(Obj).Radius * Asteroid(Ast).Size ' on screen
Line -(Np.x, Np.y) ' draw line from previous point
Next Obj
Line -(P1.x, P1.y) ' draw final line back to start
Vector.x = Sin(Asteroid(Ast).Dir) ' get vector from asteroid radian
Vector.y = -Cos(Asteroid(Ast).Dir) ' <<< This should be -Cos
Asteroid(Ast).Loc.x = Asteroid(Ast).Loc.x + Vector.x * Asteroid(Ast).Speed ' plot location on screen
Asteroid(Ast).Loc.y = Asteroid(Ast).Loc.y + Vector.y * Asteroid(Ast).Speed
If Asteroid(Ast).Loc.x < -19 Then Asteroid(Ast).Loc.x = SWIDTH + 19 ' keep asteroids on screen
If Asteroid(Ast).Loc.x > SWIDTH + 19 Then Asteroid(Ast).Loc.x = -19
If Asteroid(Ast).Loc.y < -19 Then Asteroid(Ast).Loc.y = SHEIGHT + 19
If Asteroid(Ast).Loc.y > SHEIGHT + 19 Then Asteroid(Ast).Loc.y = -19
Next Ast
_Display ' update screen with changes
Loop Until _KeyDown(27) ' leave when ESC pressed
System ' return to operating system
' Asteroid object data (10 coordinate vector points)
Data 0,-5,5,-10,10,-5,7,0,10,5,2,10,-5,10,-10,5,-10,-5,-5,-10
Function ATan4North0 (dy, dx)
ATan4North0 = _Pi - _Atan2(dx, dy) ' this was totally unexpected!
End Function
BTW I dislike this immensely:
Code: (Select All)
' From Lesson 17
' Vx! = Sin(_D2R(Degree!)) ' calculate the x vector quantity
' Vy! = -Cos(_D2R(Degree!)) ' calculate the y vector quantity
So much easier and straight forward to use East = 0 degrees and not have to modify _ATan2.
Then
' Vx = Cos(angle)
' Vy = Sin(angle)
Since sin(a)^2 + cos(a)^2 = 1, you have your Normal Vector
(x, y) around the point (xcenter, ycenter)
x = xcenter + radius*Cos(angle)
y = ycenter + radius*Sin(angle)
x is always associated with Cos
y is always associated with Sin.
But it appears Terry has invested heavily in that formula for Vx, Vy from Lesson 17.
Another fix for Asteroids easier than one above but East = 0 degrees
Code: (Select All)
_Title "** Asteroid demo using radians fix 2" ' bplus 2024-10-11
' use forumla
' Vx = cos(a)
' Vy = sin(a)
' and normal _Atan2 but we sacrifice North = 0
Const FALSE = 0, TRUE = Not FALSE ' truth detectors
Const PI = 3.1415926, PI2 = 2 * PI ' useful PI values
Const SPINRATE = PI2 / 360 ' asteroid spin rate
Const SWIDTH = 640, SHEIGHT = 480 ' screen dimensions
Const MAXASTEROIDS = 20 ' number of asteroids on screen
Type XYPAIR ' 2D point location definition
x As Single ' x coordinate
y As Single ' y coordinate
End Type
Type OBJECT ' object definition (points that make up an object)
Radian As Single ' direction of point
Radius As Single ' distance to point from center
End Type
Type ASTEROID ' asteroid definition
Loc As XYPAIR ' asteroid location
Dir As Single ' asteroid radian direction
Speed As Integer ' asteroid speed
Size As Integer ' asteroid size
End Type
Dim Object(10) As OBJECT ' object point data
Dim Asteroid(MAXASTEROIDS) As ASTEROID ' asteroids array
Dim Vector As XYPAIR ' vector calculations
Dim Obj As Integer ' object counter
Dim Ast As Integer ' asteroid counter
Dim P1 As XYPAIR ' first object point for PSET
Dim Np As XYPAIR ' next object point for LINE
Dim Spin As Integer ' TRUE to activate spin, FALSE otherwise
Randomize Timer ' seed RND generator
For Obj = 1 To 10 ' cycle through object points
Read Vector.x, Vector.y ' get object x,y vector point
Object(Obj).Radius = _Hypot(Vector.x, Vector.y) ' calculate radius from vector
' back to normal _Atan2
Object(Obj).Radian = _Atan2(Vector.y, Vector.x) ' calculate direction from vector
Next Obj
For Ast = 1 To MAXASTEROIDS ' cycle through asteroids
Asteroid(Ast).Loc.x = Int(Rnd * (SWIDTH - 40)) + 20 ' random location
Asteroid(Ast).Loc.y = Int(Rnd * (SHEIGHT - 40)) + 20
Asteroid(Ast).Dir = Rnd * PI2 ' random direction
Asteroid(Ast).Speed = Int(Rnd * 6) + 2 ' random speed
Asteroid(Ast).Size = 2 ^ Int(Rnd * 3) ' random size
Next Ast
Screen _NewImage(SWIDTH, SHEIGHT, 32) ' graphics screen
Spin = FALSE ' no asteroid spin
Do ' begin main loop
Cls ' clear screen
_Limit 60 ' 60 frames per second
Locate 2, 19: Print "Press the spacebar to activate asteroid spin" ' print directions
If _KeyHit = 32 Then Spin = Not Spin ' flip spin flag if spacebar pressed
If Spin Then ' spin asteroids?
For Obj = 1 To 10 ' yes, cycle through object points
Object(Obj).Radian = Object(Obj).Radian + SPINRATE ' move radian location
If Object(Obj).Radian > PI2 Then Object(Obj).Radian = Object(Obj).Radian - PI2 ' keep within limits
Next Obj
End If
For Ast = 1 To MAXASTEROIDS ' cycle through asteroids
Vector.x = Cos(Object(1).Radian) ' calculate vector from 1st object point
Vector.y = Sin(Object(1).Radian) ' <<< fix
P1.x = Asteroid(Ast).Loc.x + Vector.x * Object(1).Radius * Asteroid(Ast).Size ' plot location on screen
P1.y = Asteroid(Ast).Loc.y + Vector.y * Object(1).Radius * Asteroid(Ast).Size
PSet (P1.x, P1.y) ' draw a pixel
For Obj = 2 To 10 ' cycle through remaining points
' these assume North = 0 so Vectors are rotated 90 degrees
Vector.x = Cos(Object(Obj).Radian) ' calculate vector from object point
Vector.y = Sin(Object(Obj).Radian) ' <<<< this should be -Cos
Np.x = Asteroid(Ast).Loc.x + Vector.x * Object(Obj).Radius * Asteroid(Ast).Size ' plot location
Np.y = Asteroid(Ast).Loc.y + Vector.y * Object(Obj).Radius * Asteroid(Ast).Size ' on screen
Line -(Np.x, Np.y) ' draw line from previous point
Next Obj
Line -(P1.x, P1.y) ' draw final line back to start
Vector.x = Cos(Asteroid(Ast).Dir) ' get vector from asteroid radian
Vector.y = Sin(Asteroid(Ast).Dir) ' <<< This should be -Cos
Asteroid(Ast).Loc.x = Asteroid(Ast).Loc.x + Vector.x * Asteroid(Ast).Speed ' plot location on screen
Asteroid(Ast).Loc.y = Asteroid(Ast).Loc.y + Vector.y * Asteroid(Ast).Speed
If Asteroid(Ast).Loc.x < -19 Then Asteroid(Ast).Loc.x = SWIDTH + 19 ' keep asteroids on screen
If Asteroid(Ast).Loc.x > SWIDTH + 19 Then Asteroid(Ast).Loc.x = -19
If Asteroid(Ast).Loc.y < -19 Then Asteroid(Ast).Loc.y = SHEIGHT + 19
If Asteroid(Ast).Loc.y > SHEIGHT + 19 Then Asteroid(Ast).Loc.y = -19
Next Ast
_Display ' update screen with changes
Loop Until _KeyDown(27) ' leave when ESC pressed
System ' return to operating system
' Asteroid object data (10 coordinate vector points)
Data 0,-5,5,-10,10,-5,7,0,10,5,2,10,-5,10,-10,5,-10,-5,-5,-10
10-11-2024, 08:51 PM (This post was last modified: 10-11-2024, 08:53 PM by bplus.)
Poly Blast Summary Lesson 17: Uses the ship, bullets and regular polygons from lesson 17 for a little shooting game.
Mouse Right Button shifts nose/gun Right likewise Mouse Left Button to the left
Mouse Wheel Rotates nose/guns.
Type SHIP_Type ' ship definition First 2 needed for DrawShip
Loc As XYPair ' where the ship center is on screen
Heading As Single ' Degree angle the ship is pointed towards
V As XYPair ' Normal vector: V.X = cos(Ship.Heading) V.Y = sin(Ship.Heading)
Speed As Single ' mult. Normal Vector by Speed add to old Loc for new Location
Lives As Integer ' You have this many lives left in game
End Type
Type PolyType 'first 5 for DrawPoly
As XYPair Loc ' Location on screen
As Long NSides ' Number of sides = Number of points
As Single Radius ' From center to point
As Single Rotation ' Rotation offset = how much is poly turned
As _Unsigned Long Colr ' color
As XYPair V ' Vx, Vy Vector components for movement
As Single RotAmt ' Rotate Poly this angle amount
As Integer Live
End Type
Type Bullet ' bullet definition
Loc As XYPair ' location of bullet
V As XYPair ' vector of bullet
Live As Integer ' active status of bullet
End Type
Dim Shared NPoly: NPoly = 10 ' shared for Sub NewPoly index
Dim Shared Poly(1 To NPoly) As PolyType ' ditto
Dim ship As SHIP_Type ' get our ship started!
ship.Loc.X = _Width / 2 ' ship's x coordinate on screen
ship.Loc.Y = _Height / 2 ' ship's y coordinate on screen
ship.Heading = _Pi(3 / 2) ' let's head North for starters
ship.Speed = 5 ' ship's speed
ship.Lives = 20 ' the ship can take this many hits before game over
Dim showCompass As Integer ' show Compass toggle flag use the c key to toggle
Dim As Single angle ' degrees for the compass
showCompass = -1 ' turn the toggle on
Dim MaxBullets: MaxBullets = 50 ' don't need many because slots reused
Dim Bullet(1 To MaxBullets) As Bullet ' setup array
Dim As Integer fire ' fire flag for shooting bullets
Dim As Long hits ' how many polygon you hit with bullets
Dim As Single t, lastt ' control time between bullets
Dim As Long i, j, p ' various counters
Dim f&, s$ ' add font and general string variable s$
f& = _LoadFont("arial.ttf", 128) ' load font and use later
For i = 1 To NPoly ' get some polys going
NewPoly i
Next
Do ' let the shooting begin
Cls
DrawShip ship.Loc, ship.Heading
If showCompass Then ' I like your idea Terry to show turn ticks, here is a nice Compass for you.
For angle = 0 To _Pi(1.99) Step _Pi(2 / 24)
PSet (ship.Loc.X + 62 * Cos(angle), ship.Loc.Y + 62 * Sin(angle)) ' draw pixel at 10 degree point
If angle = 0 Then
_PrintString (ship.Loc.X + 62 * Cos(angle) + 3, ship.Loc.Y + 62 * Sin(angle) - 7), "E"
ElseIf Abs(angle - _Pi(.5)) < .0001 Then
_PrintString (ship.Loc.X + 62 * Cos(angle) - 2, ship.Loc.Y + 62 * Sin(angle) + 1), "S"
ElseIf Abs(angle - _Pi) < .0001 Then
_PrintString (ship.Loc.X + 62 * Cos(angle) - 11, ship.Loc.Y + 62 * Sin(angle) - 7), "W"
ElseIf Abs(angle - _Pi(3 / 2)) < .0001 Then
_PrintString (ship.Loc.X + 62 * Cos(angle) - 2, ship.Loc.Y + 62 * Sin(angle) - 16), "N"
End If
Next
End If
For i = 1 To NPoly 'draw amd update polys
If Poly(i).Live Then
If Sqr((Poly(i).Loc.X - ship.Loc.X) ^ 2 + (Poly(i).Loc.Y - ship.Loc.Y) ^ 2) < Poly(i).Radius + 60 Then
'poly hits ship
For j = 60 To 0 Step -5
Circle (ship.Loc.X, ship.Loc.Y), j, &HFFFFAA00
Next
_Display
_Delay .25
ship.Lives = ship.Lives - 1
NewPoly i
Else
DrawPoly Poly(i).Loc, Poly(i).NSides, Poly(i).Radius, Poly(i).Rotation, Poly(i).Colr
' update poly position and rotation and keep in bounds
Poly(i).Loc.X = Poly(i).Loc.X + Poly(i).V.X
If Poly(i).Loc.X < 0 Then
Poly(i).Loc.X = 0: Poly(i).V.X = -Poly(i).V.X
If Poly(i).NSides < 9 Then Poly(i).NSides = Poly(i).NSides + 1 Else Poly(i).NSides = 3
End If
If Poly(i).Loc.X > _Width Then
Poly(i).Loc.X = _Width: Poly(i).V.X = -Poly(i).V.X
If Poly(i).NSides < 9 Then Poly(i).NSides = Poly(i).NSides + 1 Else Poly(i).NSides = 3
End If
Poly(i).Loc.Y = Poly(i).Loc.Y + Poly(i).V.Y
If Poly(i).Loc.Y < 0 Then
Poly(i).Loc.Y = 0: Poly(i).V.Y = -Poly(i).V.Y
If Poly(i).NSides < 9 Then Poly(i).NSides = Poly(i).NSides + 1 Else Poly(i).NSides = 3
End If
If Poly(i).Loc.Y > _Height Then
Poly(i).Loc.Y = _Height: Poly(i).V.Y = -Poly(i).V.Y
If Poly(i).NSides < 9 Then Poly(i).NSides = Poly(i).NSides + 1 Else Poly(i).NSides = 3
End If
Poly(i).Rotation = Poly(i).Rotation + Poly(i).RotAmt
End If 'poly hits ship
End If
Next
'continuous fire
fire = 0
t = Timer(.01)
If lastt = 0 Or t - lastt > .2 Then fire = 1: lastt = t Else fire = 0
For i = 1 To MaxBullets 'handle bullets
If Bullet(i).Live = 0 And fire = 1 Then 'have inactive bullet to use
Bullet(i).Loc.X = ship.Loc.X + 60 * Cos(ship.Heading)
Bullet(i).Loc.Y = ship.Loc.Y + 60 * Sin(ship.Heading)
Bullet(i).V.X = 20 * Cos(ship.Heading)
Bullet(i).V.Y = 20 * Sin(ship.Heading)
Bullet(i).Live = -1
fire = 0
End If
If Bullet(i).Live Then 'new location
Bullet(i).Loc.X = Bullet(i).Loc.X + Bullet(i).V.X
Bullet(i).Loc.Y = Bullet(i).Loc.Y + Bullet(i).V.Y
If Bullet(i).Loc.X > 0 And Bullet(i).Loc.X < _Width And Bullet(i).Loc.Y > 0 And Bullet(i).Loc.Y < _Height Then 'in bounds draw it
For p = 1 To NPoly 'check for collision with rock
If Poly(p).Live Then
If Sqr((Poly(p).Loc.X - Bullet(i).Loc.X) ^ 2 + (Poly(p).Loc.Y - Bullet(i).Loc.Y) ^ 2) < Poly(p).Radius + 10 Then 'its a hit!
'r(r).explodeFrame = 1 'linger with explosion
Poly(p).Live = 0
For j = Poly(p).Radius To 0 Step -5
Circle (Poly(p).Loc.X, Poly(p).Loc.Y), j, &HFFFFAA00
Next
_Display
NewPoly p
hits = hits + 1
'points = points + ((r(r).speed - 2) * 33.3333 + (50 - (r(r).c - 10)) * 2 + (90 - (r(r).r - 10)) * 1.1111) / 3
Bullet(i).Live = 0 'kill bullet
End If ' hit rock
End If 'rock is there
Next
If Bullet(i).Live Then Circle (Bullet(i).Loc.X, Bullet(i).Loc.Y), 10, _RGB32(255, 255, 0) 'draws bullet
Else
Bullet(i).Live = 0 'out of bounds
End If ' bullet is in bounds
End If ' bullet live
Next ' bullet
_Title "Poly Blast:" + Str$(hits) + " Lives" + Str$(ship.Lives)
_Display
While _MouseInput
ship.Heading = ship.Heading + _MouseWheel * _Pi(1 / 24) ' 22.5 degree changes, Thank Ken for this :)
Wend 'update ship
ship.Loc.X = _MouseX: ship.Loc.Y = _MouseY
If _MouseButton(1) Then ship.Heading = _Pi 'this is new left and right guns
If _MouseButton(2) Then ship.Heading = 0
If _KeyHit = 99 Then showCompass = Not showCompass ' toggle flag when c for compass pressed
_Limit 30
Loop Until _KeyDown(27) Or ship.Lives <= 0 ' escape
_Font f&
s$ = "GAME OVER"
_PrintString ((_Width - _PrintWidth(s$)) / 2, (_Height - 128) / 2), s$
_Display
Sleep
System
Sub NewPoly (index) ' for shared array Poly() as PolyType
Dim red, grn, blu, r As Single, cx As Single, cy As Single, a As Single
cx = _Width / 2: cy = _Height / 2
Poly(index).Radius = Rnd * 60 + 20
r = Int(Rnd * 4)
Select Case r
Case 0 ' from top
Poly(index).Loc.X = Rnd * (_Width - 2 * Poly(index).Radius) + Poly(index).Radius
Poly(index).Loc.Y = 0
Case 1 ' from bottom
Poly(index).Loc.X = Rnd * (_Width - 2 * Poly(index).Radius) + Poly(index).Radius
Poly(index).Loc.Y = _Height
Case 2 ' from left
Poly(index).Loc.Y = Rnd * (_Height - 2 * Poly(index).Radius) + Poly(index).Radius
Poly(index).Loc.X = 0
Case 3 ' from right
Poly(index).Loc.Y = Rnd * (_Height - 2 * Poly(index).Radius) + Poly(index).Radius
Poly(index).Loc.X = _Width
End Select
' this points every poly to pass through center screen
a = _Atan2(cy - Poly(index).Loc.Y, cx - Poly(index).Loc.X)
r = Rnd * 5 + 1 ' random speeds
Poly(index).V.X = r * Cos(a) ' dx distance moved along x direction each loop
Poly(index).V.Y = r * Sin(a) ' dy distance moved along y direction each loop
Poly(index).NSides = 3 '+ Int(Rnd * 7) ' more than 9 looks too much like circle
Poly(index).Rotation = Rnd * _Pi(2) ' start with some rotation
red = -Sgn(Rnd < .5) * (56 * Rnd + 200) ' bright primary and 2nd colors setup
grn = -Sgn(Rnd < .5) * (156 * Rnd + 100)
blu = -Sgn(Rnd < .5) * (156 * Rnd + 100)
Poly(index).Colr = _RGB32(red, grn, blu)
Poly(index).RotAmt = Rnd * _Pi(1 / 10) - _Pi(1 / 20) ' add to rotaion this amount each loop
Poly(index).Live = 1
End Sub
Sub DrawPoly (Place As XYPair, NSides As Long, Radius, RadRotation, C As _Unsigned Long)
Dim pAngle: pAngle = _Pi(2 / NSides) ' angles from center to side points
Dim a, savex, savey
For a = 0 To _Pi(1.9999) Step pAngle
If a = 0 Then
PSet (Place.X + Radius * Cos(a + RadRotation), Place.Y + Radius * Sin(a + RadRotation)), C
'!!!! this is classic formula for points about a central point !!!!
savex = Place.X + Radius * Cos(a + RadRotation) ' save first point to tie at end of loop
savey = Place.Y + Radius * Sin(a + RadRotation)
Else
Line -(Place.X + Radius * Cos(a + RadRotation), Place.Y + Radius * Sin(a + RadRotation)), C
End If
Next
Line -(savex, savey), C
End Sub
Sub DrawShip (place As XYPair, DegreeHeading As Single) ' hey we can use this design in another app!!!
Dim As Single radius
radius = 60 ' nose and wing tips touch radius around central location = placeXY
Dim pts(1 To 3) As XYPair 'the 3 outer points for triangle ship with 2 wings fit on radius
pts(1).X = place.X + radius * Cos(0 + DegreeHeading) ' nose at 0 degrees
pts(1).Y = place.Y + radius * Sin(0 + DegreeHeading)
pts(2).X = place.X + radius * Cos(_Pi(3 / 4) + DegreeHeading) ' 180 - 45 SW wing tip
pts(2).Y = place.Y + radius * Sin(_Pi(3 / 4) + DegreeHeading)
pts(3).X = place.X + radius * Cos(_Pi(5 / 4) + DegreeHeading) ' 180 + 45 NW wing tip
pts(3).Y = place.Y + radius * Sin(_Pi(5 / 4) + DegreeHeading)
Line (pts(1).X, pts(1).Y)-(pts(2).X, pts(2).Y)
Line (pts(2).X, pts(2).Y)-(place.X, place.Y)
Line (pts(3).X, pts(3).Y)-(place.X, place.Y)
Line (pts(3).X, pts(3).Y)-(pts(1).X, pts(1).Y)
End Sub
Probably should add sound, didn't do that Lesson yet