Mäkiä tosiaan saa näkymään kivasti kuvien avulla, mutta itse toiminallisuuden toteuttaminen voikin olla hieman hankalampaa. Tein aikoinani pöytälaatikkoon tälläisen systeemin tasohyppelypelejä varten joka auttaa vinojen kulmien törmäystarkistusten kanssa. Käytännössä ukkeli voi olla aivan normaali kuva/objekti, mutta törmäykset tarkistetaan kentän törmäysviivojen (rails) ja ukon liikesuunnan perusteella. Törmäysviivoja voi sitten ketjuttaa toisiinsa kiinni, lisäillä, poistaa tai muuttaa lennossa. Näin saadaan esim. tilekarttoihin verrattuna huomattavasti enemmän ominaisuuksia kuten maasta nousevia pylväitä, hissejä, katkeavia siltoja, yms.
Tässä vielä testikoodi jossa voi nuolinäppäimillä hyppiä pallolla dynaamisesti muuttuvassa maastossa. Hiirellä voi luoda paikallaan pysyviä viivoja.
Code: Select all
SCREEN 1024,768
//Rail MemoryMap
Const RailStartX = 0
Const RailStartY = 4
Const RailEndX = 8
Const RailEndY = 12
Const RailLenght = 16
Const RailAngle = 20
Const PreviousRail = 24
Const NextRail = 28
Const RailMemorySize = 32
Const RailMemoryType = "ffffffii"
Global RailMap
Global RailMapSize
Railmap = MakeMEMBlock(4)
RailMapSize = 4
//CBSDK FUNCTION
Global IntersX#, IntersY#
Global LinesOnTop
//game
Const railamount = 50
railMargin = 1024/railamount
Dim rails(railamount)
For i=0 To railamount
If (i>0) Then
rails(i) = AddRail(i*railMargin,PeekFloat(rails(i-1),RailEndY),(i+1)*railMargin,Min(Max(PeekFloat(rails(i-1),RailEndY)+Rand(-50,50),50),700),rails(i-1))
Else
rails(0) = AddRail(i*railMargin,350,(i+1)*railMargin,Rand(50,700))
EndIf
Next i
GuyRail=rails(0)
GuyPosition#=0.0
speed# = 2.0
guyYSpeed# = 0.0
Repeat
If MouseHit(1) Then
If Not railstart Then
railsx=MouseX()
railsy=MouseY()
railstart =1
ClearMouse
Else
AddRail(railsx,railsy,MouseX(),MouseY())
railstart=0
EndIf
EndIf
//deform rails
deformAmount# = 0.2
For i=0 To railamount
deformTime = (Timer()/10)+i*30
If (i = 0) Then DeformRail(rails(i),PeekFloat(rails(i),RailStartX),PeekFloat(rails(i),RailStartY)+Sin(deformTime)*deformAmount#,PeekFloat(rails(i),RailEndX)+Sin(deformTime)*deformAmount#,PeekFloat(rails(i),RailEndY)+Sin(deformTime)*deformAmount#)
If (i <> 0) Then DeformRail(rails(i),PeekFloat(rails(i-1),RailEndX),PeekFloat(rails(i-1),RailEndY),PeekFloat(rails(i),RailEndX)+Sin(deformTime)*deformAmount#,PeekFloat(rails(i),RailEndY)+Sin(deformTime)*deformAmount#)
Next i
If GuyRail>0 Then
speedPros# = (speed#/PeekFloat(GuyRail,RailLenght))
If LeftKey() Then
If inverted Then GuyPosition#=Min(GuyPosition#+speedPros#,1.0) Else GuyPosition#=Max(GuyPosition#-speedPros#,0.0)
If Guyposition# = 0.0 And PeekInt(GuyRail,PreviousRail) Then
GuyRail=PeekInt(GuyRail,PreviousRail)
GuyPosition# = 1.0
EndIf
ElseIf RightKey()
If inverted Then GuyPosition#=Max(GuyPosition#-speedPros#,0.0) Else GuyPosition#=Min(GuyPosition#+speedPros#,1.0)
If Guyposition#=1.0 And PeekInt(GuyRail,NextRail) Then
GuyRail=PeekInt(GuyRail,NextRail)
GuyPosition = 0.0
EndIf
EndIf
guyx# = GetRailFloatPointX(GuyRail,GuyPosition#)
guyy# = GetRailFloatPointY(GuyRail,GuyPosition#)
If UpKey() Then GuyRail = 0 : guyYSpeed# = -5.0
EndIf
If GuyRail = 0
oldx# = guyx#
oldy# = guyy#
guyYSpeed# = guyYSpeed# + 0.3
guyXSpeed# = (RightKey()-LeftKey())*speed#
guyx=guyx + guyXSpeed#
guyy=guyy + guyYSpeed#
If (notCollided) Then
GuyRail = RailIntersectingLine(oldx#-guyXSpeed#,oldy#-guyYSpeed#,guyx#+guyXSpeed#,guyy#+guyYSpeed#)
Else
GuyRail = RailIntersectingLine(oldx#,oldy#,guyx#+guyXSpeed#,guyy#+guyYSpeed#)
EndIf
If GuyRail Then
GuyPosition# = (Distance(PeekFloat(GuyRail,RailStartX),PeekFloat(GuyRail,RailStartY),IntersX,IntersY)/PeekFloat(GuyRail,RailLenght))
guyx# = GetRailFloatPointX(GuyRail,GuyPosition)
guyy# = GetRailFloatPointY(GuyRail,GuyPosition)
ClearKeys
notCollided=0
Else
notCollided=1
EndIf
EndIf
DrawRails()
Color cbred
Circle guyx#-5,guyy#-10,10
Color cbwhite
If (guyrail) Then Text 0,0,guyx#+","+guyy#+" "+GuyPosition#+" "+PeekFloat(GuyRail,RailAngle)
DrawScreen
Forever
//Rails lib
Function DrawRails()
If Railmap And RailMapSize>4 Then
For i=4 To RailMapSize-1 Step 4
rail = PeekInt(Railmap,i)
For o=0 To MEMBlockSize(rail)-1 Step RailMemorySize
Color cbwhite
Line PeekFloat(rail,o+RailStartX),PeekFloat(rail,o+RailStartY),PeekFloat(rail,o+RailEndX),PeekFloat(rail,o+RailEndY)
'Text (PeekFloat(rail,o+RailEndX)+PeekFloat(rail,o+RailStartX))/2,(PeekFloat(rail,o+RailEndX)+PeekFloat(rail,o+RailStartX))/2,PeekFloat(rail,o+RailAngle)
//MakeError PeekFloat(rail,o+RailStartX)+","+PeekFloat(rail,o+RailStartY)+","+PeekFloat(rail,o+RailEndX)+","+PeekFloat(rail,o+RailEndY)
Next o
Next i
Else
Return 0
EndIf
End Function
Function AddRail(x1#,y1#,x2#,y2#,p=0,n=0,stopinvert=1)
//Makes Rail, adds pointer to Railmap and returns pointer
rail = MakeMEMBlock (RailMemorySize)
ang# = GetAngle(x1#,y1#,x2#,y2#)
If stopinvert = 1 Then
If ang#>90.0 And ang#<270.0 Then
temp# = x1#
x1# = x2#
x2# = temp#
temp# = y1#
y1# = y2#
y2# = temp#
ang# = WrapAngle(ang#+180.0)
EndIf
EndIf
PokeFloat rail,RailStartX,x1#
PokeFloat rail,RailStartY,y1#
PokeFloat rail,RailEndX,x2#
PokeFloat rail,RailEndY,y2#
PokeFloat rail,RailLenght,Distance(x1#,y1#,x2#,y2#)
PokeFloat rail,RailAngle, ang#
PokeInt rail,PreviousRail,p
PokeInt rail,NextRail,n
If p Then PokeInt p,NextRail,rail
If n Then PokeInt n,PreviousRail,rail
oldsize = RailMapSize
ResizeMEMBlock Railmap,RailMapSize+4
RailMapSize = oldsize+4
PokeInt Railmap,oldsize,rail
Return rail
End Function
Function DeformRail(rail,x1#,y1#,x2#,y2#,p=0,n=0)
//Changes rail properties
// use -1 to remove rail pointers (next and previous)
If rail Then
ang# = GetAngle(x1#,y1#,x2#,y2#)
If ang#>90.0 And ang#<270.0 Then
temp# = x1#
x1# = x2#
x2# = temp#
temp# = y1#
y1# = y2#
y2# = temp#
ang# = WrapAngle(ang#+180.0)
EndIf
PokeFloat rail,RailStartX,x1#
PokeFloat rail,RailStartY,y1#
PokeFloat rail,RailEndX,x2#
PokeFloat rail,RailEndY,y2#
PokeFloat rail,RailLenght,Distance(x1#,y1#,x2#,y2#)
PokeFloat rail,RailAngle, ang#
If p Then
PokeInt rail,PreviousRail,p
ElseIf p=-1 Then
PokeInt rail,PreviousRail,0
EndIf
If n Then
PokeInt rail,NextRail,n
ElseIf n=-1 Then
PokeInt rail,NextRail,0
EndIf
Else
MakeError "Trying to deform nonexisting rail: "+rail
EndIf
End Function
Function DeleteRail(rail)
//Deletes rail and erases pointers from Railmap and adjecant rails
If rail Then
For i=4 To RailMapSize-1 Step 4
iRail = PeekInt(Railmap,i)
If iRail = rail Then
If RailMapSize>i+4 Then MemCopy Railmap,i+4,Railmap,i,RailMapSize-(i+4)
ResizeMEMBlock Railmap,RailMapSize-4
RailMapSize = RailMapSize-4
Exit
EndIf
Next i
p = PeekInt(rail,PreviousRail)
n = PeekInt(rail,NextRail)
If p Then PokeInt p,NextRail,0
If n Then PokeInt n,PreviousRail,0
DeleteMEMBlock rail
Else
MakeError "Trying to delete nonexisting rail: "+rail
EndIf
End Function
//returns point just a little over line
Function GetRailFloatPointX(rail,position#)
railangle# = PeekFloat(rail,RailAngle)
If (railangle# <= 90 ) Then Return PeekFloat(rail,RailStartX)+position#*PeekFloat(rail,RailLenght)*Cos(railangle#) - Cos(railangle#)*0.1
If (railangle# >= 270) Then Return PeekFloat(rail,RailStartX)+position#*PeekFloat(rail,RailLenght)*Cos(railangle#) + Cos(railangle#)*0.1
End Function
//returns point just a little over line
Function GetRailFloatPointY(rail,position#)
railangle# = PeekFloat(rail,RailAngle)
Return PeekFloat(rail,RailStartY)+position#*PeekFloat(rail,RailLenght)*-Sin(railangle#) - 0.1
End Function
Function DistanceToRail(rail,x#,y#)
' Modified from Jonhu´s MinDistToLine
If rail Then
lx1# = PeekFloat(rail,RailStartX)
ly1# = PeekFloat(rail,RailStartY)
lx2# = PeekFloat(rail,RailEndX)
ly2# = PeekFloat(rail,RailEndX)
// järjestetään, että (lx1, ly1) on pienempi
If lx1 > lx2 Then
mx1# = lx1 : my1# = ly1
lx1 = lx2 : ly1 = ly2
lx2 = mx1 : ly2 = my1
EndIf
// lasketaan muutama kulma
line_ang# = GetAngle(lx1#,ly1#, lx2#,ly2#)
ang1# = Abs( GetAngle(x#,y#, lx1#,ly1#) - line_ang# ) + 90
ang2# = Abs( GetAngle(x#,y#, lx2#,ly2#) - line_ang# ) + 90
If WrapAngle( ang1# ) <= 180
dist# = Distance(x#,y#, lx1#,ly1#) ' abs(px#-lx1#) + abs(py#-ly1#)
ElseIf WrapAngle( ang2# ) => 180
dist# = Distance(x#,y#, lx2#,ly2#)
Else // jos lähin etäisyys ei ole päätepisteissä joudutaan hieman laskea..
dist# = ( Abs( (lx2-lx1)(ly1-y)-(lx1-x)(ly2-ly1) ) / Sqrt( (lx2-lx1)^2.0 + (ly2-ly1)^2.0 ) )
EndIf
Return dist#
Else
MakeError "Trying to measure distance to nonexisting rail: "+rail
EndIf
EndFunction
Function RailIntersectingLine(x1#,y1#,x2#,y2#)
For i=4 To RailMapSize-1 Step 4
rail = PeekInt(Railmap,i)
lx1# = PeekFloat(rail,RailStartX)
ly1# = PeekFloat(rail,RailStartY)
lx2# = PeekFloat(rail,RailEndX)
ly2# = PeekFloat(rail,RailEndY)
If LinesIntersect(x1#,y1#,x2#,y2#, lx1#,ly1#,lx2#,ly2#) Then Return rail
Next i
Return 0
End Function
Function LinesIntersect(Ax#, Ay#, Bx#, By#, Cx#, Cy#, Dx#, Dy#)
LinesOnTop = False
// Tarkastetaan ovatko suorat toistensa päällä yhdensuuntaisina
If Collinear(Ax#,Ay#,Bx#,By#,Cx#,Cy#) = True And Collinear(Ax#,Ay#,Bx#,By#,Dx#,Dy#) = True Then 'ovatko yhdensuuntaisia
If Between(Ax#,Ay#,Bx#,By#,Cx#,Cy#) = True Or Between(Ax#,Ay#,Bx#,By#,Dx#,Dy#) = True Or Between(Cx#,Cy#,Dx#,Dy#,Ax#,Ay#) = True Or Between(Cx#,Cy#,Dx#,Dy#,Bx#,By#) = True Then 'ovatko sisäkkäin
IntersX# = 0
IntersY# = 0
LinesOnTop = True
Return True
EndIf
EndIf
Rn# = (Ay#-Cy#)*(Dx#-Cx#) - (Ax#-Cx#)*(Dy#-Cy#)
Rd# = (Bx#-Ax#)*(Dy#-Cy#) - (By#-Ay#)*(Dx#-Cx#)
If Rd# = 0
Return False
Else
Sn# = (Ay#-Cy#)*(Bx#-Ax#) - (Ax#-Cx#)*(By#-Ay#)
Intersection_AB# = Rn# / Rd#
Intersection_CD# = Sn# / Rd#
If Intersection_AB# > 1 Or Intersection_CD# > 1 Or Intersection_AB# < 0 Or Intersection_CD# < 0 Then Return False
IntersX = Ax# + Intersection_AB#*(Bx#-Ax#)
IntersY = Ay# + Intersection_AB#*(By#-Ay#)
Return True
EndIf
End Function
// Tarkastaa onko jokin piste kahden pisteen määrittämällä suoralla
Function Collinear(x1#,y1#,x2#,y2#,x3#,y3#)
If x1*(y2-y3) + x2*(y3-y1) + x3*(y1-y2) = 0 Then Return True Else Return False
End Function
// Tarkastaa onko jokin piste kahden pisteen määrittämällä janalla
Function Between(x1#,y1#,x2#,y2#,x3#,y3#)
If Collinear(x1#,y1#,x2#,y2#,x3#,y3#) = False Then Return False
If Distance(x1,y1,x3,y3) + Distance(x3,y3,x2,y2) = Distance(x1,y1,x2,y2) Then Return True Else Return False
End Function