Ok, here we go. First the code!
Graphics 800,600,0,2
SeedRnd MilliSecs()
Global gravity# = 0.7
Global drag# = .8
Global tilewidth = 32
Type block
Field image
Field x
Field y
End Type
Type player
Field image
Field x#
Field y#
Field xspeed#
Field yspeed#
Field jump_speed_angle#
Field jump_speed#
Field jump_strength#
Field jumping
Field topimage
Field top_x
Field top_y
Field bottomimage
Field bottom_x
Field bottom_y
Field leftimage
Field left_x
Field left_y
Field rightimage
Field right_x
Field right_y
Field speed#
Field maxspeed#
End Type
For x=0 To 50
b.block = New block
b\x = Rand(25)*tilewidth
b\y = (Rand(6)*tilewidth)+(11*tilewidth)
b\image = CreateImage(tilewidth,tilewidth)
SetBuffer(ImageBuffer(b\image))
grey = Rand(50)+205
ClsColor grey,grey,grey
Cls
SetBuffer BackBuffer()
Next
For x=0 To 24
b.block = New block
b\x = x*tilewidth
b\y = 18*tilewidth
b\image = CreateImage(tilewidth,tilewidth)
SetBuffer(ImageBuffer(b\image))
grey = Rand(50)+205
ClsColor grey,grey,grey
Cls
SetBuffer BackBuffer()
Next
p.player = New player
p\image = CreateImage(tilewidth,tilewidth)
p\x = 9*tilewidth
p\y = 10*tilewidth
; new variables for jumping
p\jump_strength = 10
p\jump_speed_angle# = 0 ; leave this at zero
p\jump_speed# = 5
p\speed = 1
p\maxspeed =5
SetBuffer ImageBuffer(p\image)
Color 255,0,0
Oval 0,0,tilewidth,tilewidth
; DrawImage p\topimage , p\x+3 , p\y
; DrawImage p\bottomimage , p\x+3 , p\y+tilewidth-3
; DrawImage p\leftimage , p\x , p\y+3
; DrawImage p\rightimage , p\x+tilewidth-3 , p\y+3
p\topimage = CreateImage(tilewidth-6,3)
p\top_x = p\x + 3
p\top_y = p\y
SetBuffer ImageBuffer(p\topimage)
Color 0,255,0
Rect 0,0,tilewidth-6,3
p\top_x = p\x + 3
p\top_y = p\y
p\bottom_x = p\x + 3
p\bottom_y = p\y + tilewidth - 3
p\left_x = p\x
p\left_y = p\y + 3
p\right_x = p\x + tilewidth - 3
p\right_y = p\y + 3
p\bottomimage = CreateImage(tilewidth-6,3)
p\bottom_x = p\x + 3
p\bottom_y = p\y + tilewidth - 3
SetBuffer ImageBuffer(p\bottomimage)
Color 0,255,0
Rect 0,0,tilewidth-6,3
p\rightimage = CreateImage(3,tilewidth-6)
p\right_x = p\x + tilewidth - 3
p\right_y = p\y + 3
SetBuffer ImageBuffer(p\rightimage)
Color 0,255,0
Rect 0,0,3,tilewidth-6
p\leftimage = CreateImage(3,tilewidth-6)
p\left_x = p\x
p\left_y = p\y + 3
SetBuffer ImageBuffer(p\leftimage)
Color 0,255,0
Rect 0,0,3,tilewidth-6
SetBuffer(BackBuffer())
ClsColor 0,0,0
While Not KeyHit(1)
Cls
drawblocks()
updateplayer()
Flip()
Wend
Function drawblocks()
For b.block = Each block
DrawImage b\image,b\x,b\y,0
Next
End Function
Function updateplayer()
For p.player = Each player
; grab x and y co-ords before you move anything
old_px = p\x
old_py = p\y
If KeyDown(57) And p\jumping = 0
p\jumping = 1
EndIf
If KeyDown(203)
p\xspeed = p\xspeed-p\speed
ElseIf KeyDown(205)
p\xspeed = p\xspeed+p\speed
Else
p\xspeed = p\xspeed * drag
End If
; I have created 2 jump stages
; p\jumping = 1 - this is when the player is jumping upwards.
; p\jumping = 2 - this is when the player is falling
; Below i am using cos to make use of the sin waves. Basically, inputting a value into COS
; will produce a number, a ratio. If you were to drawing every single number from 0 to 180, you would come
; across a half circle. As you know, a circle curves, reaching an extremety.
; FOR EXAMPLE
; angle = 0 - cos(0) = 1
; angle = 10 - cos(10) = 0.984
; angle = 20 - cos(20) = 0.939
; angle = 30 - cos(30) = 0.866
; angle = 40 - cos(40) = 0.766
; angle = 50 - cos(50) = 0.642
; angle = 60 - cos(60) = 0.500
; angle = 70 - cos(70) = 0.342
; angle = 80 - cos(80) = 0.173
; angle = 90 - cos(90) = 0.000
; as you can see from above, inputting a linear number, outputs an ever decreasing number. So, if you use this
; for a jump, you can make the jump start off quick, and quickly dimishing, replicating the effect of gravity,
; without fiddling about with physics. For the falling, continue to angles for 100 - 180, this will start off,
; slowly, and increase exponentially, again, simulating the effect of gravity fairly well.
If p\jumping = 1 Then
p\jump_speed_angle = p\jump_speed_angle + p\jump_speed
If p\jump_speed_angle >= 90 Then
p\jump_speed_angle = 90
p\jumping = 2
End If
ElseIf p\jumping = 2 Then
p\jump_speed_angle = p\jump_speed_angle + p\jump_speed
If p\jump_speed_angle => 180 Then
p\jump_speed_angle = 180
End If
End If
If p\xspeed > p\maxspeed Then p\xspeed = p\maxspeed
If p\xspeed < -p\maxspeed Then p\xspeed = -p\maxspeed
; below is where you add the jump/fall speed to the players co-ords. see below for expanation of COS
; Firstly check to see if the jumping flag has been set. If so, adjust the players y position.
; If NOT, then don't bother with them.
If p\jumping <> 0 Then
p\y = p\y-(Cos(p\jump_speed_angle) * p\jump_strength)
End If
p\x = p\x+p\xspeed
; you must update the image edges, so the collisions will register properly
update_edges(p.player)
; you pass across the player object "p", as it's locally created to this function.
; The same applies with "old_px" and "old_py". The collision routine needs to reset to these co-ords.
update_collisions(p.player,old_px,old_py)
; you must again update the image egdes, as the collision code may have reset the main image co-ords.
update_edges(p.player)
; check collisions with blocks
Text 0,0,"jumping : "+p\jumping
Text 0,10,"jump_speed_angle : "+ jump_speed_angle
Text 0,20,"jump_speed : "+p\jump_speed
DrawImage p\topimage , p\top_x , p\top_y
DrawImage p\bottomimage , p\bottom_x , p\bottom_y
DrawImage p\leftimage , p\left_x , p\left_y
DrawImage p\rightimage , p\right_x , p\right_y
DrawImage p\image,p\x,p\y,0
Next
End Function
; you must pass across the old p\x and p\y co-ords so the collision routine may reset positions, if future positions,
; cause a collision.
Function update_collisions(p.player,old_px,old_py)
collide_down = 0
collide_up = 0
collide_left = 0
collide_right = 0
For b.block = Each block
If ImagesCollide(p\bottomimage,p\bottom_x,p\bottom_y,0,b\image,b\x,b\y,0)
p\jumping = 0 ; switching jumping OFF
p\jump_speed_angle = 0 ; reset jump_speed_angle to 0
collide_down = 1 ; set collide_down flag
p\y = old_py
EndIf
If ImagesCollide(p\topimage,p\top_x,p\top_y,0,b\image,b\x,b\y,0)
p\jumping = 2
p\jump_speed_angle = 90
collide_up = 1
p\y = old_py
EndIf
update_edges(p.player)
If ImagesCollide(p\leftimage,p\left_x,p\left_y,0,b\image,b\x,b\y,0)
p\xspeed=0
collide_left = 1
p\x = old_px
EndIf
If ImagesCollide(p\rightimage,p\right_x,p\right_y,0,b\image,b\x,b\y,0)
p\xspeed=0
collide_right = 1
p\x = old_px
EndIf
Next
If collide_down = 0 Then ; did not hit the ground
If p\jumping = 0 Then
p\jumping = 2 ; set to falling
p\jump_speed_angle = 90 ; set the angle of cos to simulate falling
End If
End If
End Function
Function update_edges(p.player)
p\top_x = p\x + 3
p\top_y = p\y
p\bottom_x = p\x + 3
p\bottom_y = p\y + tilewidth - 3
p\left_x = p\x
p\left_y = p\y + 3
p\right_x = p\x + tilewidth - 3
p\right_y = p\y + 3
End Function
I reworked some of your code, created a few function to seperate everything. I also created some fields in your player type:
Field top_x
Field top_y
Field left_x
Field left_y
Field right_x
Field right_y
Field bottom_x
Field bottom_y
Field jump_speed_angle
Field jump_speed
NOTE: the "jump_speed_angle" field isn't really an angle of such, it's just named as such, as it's put into COS to retrieve a value.
I removed the max_jump field.
I implemented your jumping and falling using COS. I have provided a more detailed explanation inside the code via comments.
I have split the jumping into 3 stages.
p\jumping = 0 - the player is on flat ground. This is set to zero when a collision is detected below the player, via "p\bottom_image"
p\jumping = 1 - the player is actually jumping. Increments "jump_speed_angle" by "jump_speed"
eg - jump_speed_angle = jump_speed_angle + jump+speed
"jump_speed_angle" is limited to 90, as this is quater of a circle, and is the 0 point into COS wave. Once "jump_speed_angle" = 90, the p.jumping flag gets set to 2
p\jumping = 2 - the player is now falling. This variable is set to falling if:
- the player jump has reached it's peak.
- the player has walked off of a platform.
This increases the "jump_speed_angle" up to 180. This is another quarter of a circle which leads to the lowest point in the COS wave.
For example: "jump_speed_angle" = 0. Stick this into COS and it returns 1. So the jump starts at the highest speed. As "jump_speed_angle" = 90 the value COS returns is 0, meaning the speed is non-existant.
Increasing "jump_speed_angle" beyond 90 cause the values returned to go below 0. When "jump_speed_angle" reaches 180, COS will return -1. It will peak at that, and beyond 180, will return to 0, then 1.
That is why the code cuts off at 180, as it is the biggest minus number COS will return.
The beauty of this, is all you need to do is plug in the "jump_speed_angle" and it will return value going from 1 (jumping upwards) to -1 (falling downwards), without you having to do anything, except change the jumping_flag. Additionally, COS will produce numbers have increase and decrease exponentially, acting like gravity :o)
I have put all the co-ords of the edges images into their own variables, and made them longer, as the image was getting caught through the corners which were showing. I put them in their own variables just for reading sake. You need to update their co-ords though, as they are based on the main images co-ords. Call "update_edges(p.player" passing across the player object. You will need to do this anytime you update the main images co-ords.
I have put the collisions all into the one loop and stuck them in a function, so to cut down the amount of code you have to read through and tidied up the code. I have also recorded the player images co-ords at the beginning of the "updateplayer" so you can reset them, if the the new co-ords fall within a collision. You must pass them across to the function, along with the player object "p.player".
Added or changed the left/right movement to:
If KeyDown(203)
p\xspeed = p\xspeed-p\speed
ElseIf KeyDown(205)
p\xspeed = p\xspeed+p\speed
Else
p\xspeed = p\xspeed * drag
End If
This will check to see if the left or right key has been pressed. If not, then it will apply drag. Therefore not applying drag whilst moving. Just simplifies things a touch.
Changed the jump code to a simple coupld of lines:
If KeyDown(57) And p\jumping = 0
p\jumping = 1
EndIf
Check to see if jump key is pressed (best with Keydown() because keyhit() only registers once per loop. So you couldn't check for jump keyhit() twice per loop). If so, also check to see if the p\jumping flag is at 0. If so, set to 1 (jumping) and let the rest of the code handle this.
I think i've covered the things i have altered :o) Btw your code was very good. impressed by your implementation if this is a first go at it!
I'll be hanging about here for a while, so feel free to post back about anything in there :o) Good luck!