Jumping

Blitz3D Forums/Blitz3D Beginners Area/Jumping

OwlEpicurus(Posted 2009) [#1]
I know there are a number of posts addressing this already; however, I can't find them right now and am somewhat pressed for time.

Before a player can jump, I need to check if the player is already jumping. I've found that EntityCollided() can work in certain situations, but it allows the player to jump up vertical surfaces. I remember seeing LinePick() used in the other posts about jumping back when I could find them, but thus far I havn't been able to get it to work (i.e. the player is no longer able to jump at all).

This is the relevant bit of code:




josk(Posted 2009) [#2]
Not using Linepick but this is some jump code someone (sorry not sure who) posted on this forum.
You will need to load your own map.




OwlEpicurus(Posted 2009) [#3]
Actually, it does use LinePick(). Regardless, it does not work, either. Thanks anyways.


Guy Fawkes(Posted 2009) [#4]
Heres a fix. so u dont have to load a level anymore:

;Simple Environment To Demonstrate One of Many Methods To Perform Collision Checking with Gravity
;
;
Graphics3D 800,600,0,2
SetBuffer BackBuffer()

Player=CreatePivot()	;Create a pivot for our player character, the camera will be parented to this
Camera=CreateCamera()	

CameraRange camera,0.1,500 ;Adjust camera range to allow us to get 'close' to things.  Experiment with this if you wish.


EntityParent Camera,Player ;Attach the camera to the player pivot.  This way the camera will move with the player and follow its orientation

MoveEntity camera,0,0.2,0  ;Move the camera up slightly to place it at about eye level 


PositionEntity Player,12,25,-4 ;Place the player at an arbitrary location, in this case above the centre of the environment.

;Level=LoadAnimMesh("C:\Documents and Settings\john\Desktop\easybuilder\Easybuilder mk2\Exported\aliensmap\aliensmap.b3d") ;Load level mesh I've used loadanimmesh although could equally have used loadmesh

Level = CreatePlane()
EntityColor Level, 128, 128, 128

For x = 1 To Rnd(100)
cube = CreateCube()
PositionEntity cube, Rnd(x), 1, Rnd(x)
Next
								
EntityFX Level,1	;Make the level full-bright
AmbientLight 255,255,255 ;make the scene fully lit too!


Const Gravity#=-.15  ;play around with this value, just don't make it positive (now let's see you resist that temptation).

Const COLLISIONTYPE_SCENE = 1	;define our collision types. This way we can classify easily what type of collision something needs
Const COLLISIONTYPE_PLAYER = 2
Const PlayerCollisionRadius# = .150	;this is the player's x-radius (horizontal). I've hardcoded the y-radius below, reason for doing 
									;this is that the normal human is not enclosed by a sphere but more by a cylindrical shape
									;hence the y-radius will be longer than the x-radius.

Const PlayerSpeed# = .075	;How fast the player moves.
Const PlayerJumpSpeed# = 2.0

EntityType Level,COLLISIONTYPE_SCENE,True 	;set the collision types for our scene 
EntityType Player,COLLISIONTYPE_PLAYER		;and set it for the player

EntityRadius Player,PlayerCollisionRadius,0.7	;the 0.7 is the y-radius of the collision radius.

Collisions COLLISIONTYPE_PLAYER,COLLISIONTYPE_SCENE,2,3 
;This command then sets the relationship for collisions between any object with collision type 'player'
;and any object with collision type 'scene' to 'ellipsoid to polygon' and 'slide upwards'



RecursiveSearchMesh(Level);Set our level To pickable, specifically per polygon picking (inside this function...)
						  ;this is not usually needed when using loadmesh, but with loadanimmesh there may be
						  ;a hierarchy of meshes and so we need to parse through them all to set their entitypickmode,
						  ;merely setting the entitypickmode of the entity handle "Level" may not give desired results.



MoveMouse (GraphicsWidth()/2),GraphicsHeight()/2 ;Place the mouse in the centre of the screen/window.
RubbishValue#=MouseXSpeed() ;These 'rubbish values' are designed to discard the mousex/yspeed() values which result
RubbishValue#=MouseYSpeed()	;from moving the mouse back to the centre of the screen.


Repeat



	TurnEntity Player,0,Float(MouseXSpeed())*-0.5,0	;turn our player pivot around the vertical (y) axis when the player moves the mouse left/right
	TurnEntity Camera,Float(MouseYSpeed())*0.5,0,0  ;pitch our vision up/down when the mouse is moved up/down


	MoveMouse (GraphicsWidth()/2),GraphicsHeight()/2 ;reset the mouse position to the centre of the screen.
	
	RubbishValue#=MouseXSpeed() ;see comments from earlier above
	RubbishValue#=MouseYSpeed() ;see comments from earlier above

	
	LinePick EntityX(Player),EntityY(Player)-0.7,EntityZ(Player),0,-0.05,0,0 ;Look beneath the player's feet with a linepick 
	If PickedEntity() = 0 Then PlayerOnGround=0 ;if the linepick hit something then we must be on the ground / able to walk around
	

If PlayerOnGround = True Then ;If the player is on the ground, in contact with the surface then:

	MoveFWD=0	;adjust the MoveForwards/MoveSideways variables back to zero in preparation for receiving new input from the player
	MoveRIGHT=0
	JumpUP=0
	If KeyDown(200) Then MoveFWD=15	;if up arrow / cursor key pressed set the MoveForward flag to +1
	If KeyDown(208) Then MoveFWD=-1	;if down arrow / cursor key pressed set the MoveForward flag to -1 (backwards)
	If KeyDown(205) Then MoveRIGHT=1 ;if right arrow / cursor pressed set the MoveRight flag to +1
	If KeyDown(203) Then MoveRIGHT=-1 ;if left arrow / cursor pressed set the MoveRight flag to -1
	If MouseHit(1) Then JumpUp=1 ;if Left Mouse Button Clicked bar pressed then jump (assign a positive value to PlayerVelocityY)
	
	
	If PlayerVelocityY#<0 Then PlayerVelocityY#=0 ;as we are on the ground we need to ensure that we have no vertical velocity in the 
												  ;downwards direction.
	
	 	If JumpUp=1 Then ;if we are jumping (and only allows jumps when in contact with the ground)
			PlayerVelocityY = PlayerVelocityY + PlayerJumpSpeed
	
	
		EndIf 
		If MoveFwd<>0 Or MoveRight<>0 Then ;if we have pressed a button to order the player to move then:
				
				
				TFormNormal MoveRIGHT,0,MoveFWD,Player,0
				;We need to transform our 'forwards' and 'sideways' direction from the player's local space into
				;the direction in world space.  We also want to convert the resultant vector into a 'unit vector' 
				;so that it represents direction only in order to simply scale the vector by the player's walk speed.
				PlayerVelocityX#=TFormedX()*PlayerSpeed  
				PlayerVelocityZ#=TFormedZ()*PlayerSpeed
		Else
			 	
				
				PlayerVelocityX=0	;no order to move pressed so set our horizontal velocity to zero.
				PlayervelocityZ=0
				
				;an alternative, if you want to have gradual slow down would be as follows: (comment out the two lines above first though)
				PlayerVelocityX=PlayerVelocityX*0.7	;0.7 could be any number between 0 and 1, although I don't recommend using '1' as
				PlayerVelocityZ=PlayerVelocityZ*0.7 ;the player would always be moving.
				
		EndIf 
	
	
		
	
Else ;if the player is not on the ground then :

	;Loop through the player's collisions with all other objects.  If there is no collision or there is a collision with
	;a surface that is too steep then allow the player's vertical velocity to keep increasing in the negative direction.
	
	For ColIndex=1 To CountCollisions(Player)
	
		If CollisionNY(Player,ColIndex)>0.7 Then PlayerOnGround=True:PlayerVelocityY#=0 : Exit 
		;if the collision between the player and the other object is such that the surface collided with has a normal vector
		;pointing upwards at more than 45 degrees relative to the horizontal, (if the surface was flat collisionNY would return 1.0
		;which corresponds to a normal vector pointing upwards at 90 degrees to the horizontal) - then set their 'on ground' flag
		;to 1, and set their vertical velocity back to zero.
	Next
	
EndIf 

PlayerVelocityY#=PlayerVelocityY#+Gravity#	;Gravity acts upon the player's velocity each frame, even if on the ground - although
;if on ground the collision detection will prevent the player falling through the floor.


TranslateEntity Player,PlayerVelocityX,PlayerVelocityY,PlayerVelocityZ ;move the player a distance equal to their velocities in 
;each of the 3 directions x/y/z.


UpdateWorld ;standard blitz command, collision checks are all performed here, and animation.
RenderWorld ;render the environment.

Repeat
	;delay the program for a small amount of time 
	Delay 1
Until Abs(FrameTime-MilliSecs())>15
	
Text 10,10,playeronground


Flip	;flip the backbuffer() into view.





FrameTime=MilliSecs() ;really simple frame limiting, for an example of better timing look elsewhere, it is not covered here.

Until KeyDown(1) ;ESCAPE

FreeEntity level   ;always good to free any entities when finished with them 
FreeEntity camera  
FreeEntity player

End ;end of program.



;Recursive Routine which is used to set the pick mode of meshes which are children of the root node.
Function RecursiveSearchMesh(Mesh)
If CountChildren(Mesh) = 0 And EntityClass(Mesh) = "Mesh" Then EntityPickMode Mesh,2
For C=1 To CountChildren(Mesh)
	Child=GetChild(Mesh,C)
	If EntityClass(Child)="Mesh" Then EntityPickMode Child,2	
	RecursiveSearchMesh(Child)
Next

End Function


Jump still does not work. can somebody plz help fix this?

ANY help is GREATLY appreciated! :)

~DS~


Kryzon(Posted 2009) [#5]
Hey Owl, why are you only using LinePick IF the user presses space? you should be checking it everytime. That result is if the character is on the ground or not.

From then on, based on that result, you allow him to jump if the user presses space.


OwlEpicurus(Posted 2009) [#6]
Kryzon: Very good question.

However, it still doesn't work, even when I move LinePick.

This is what the code looks like now:




GIB3D(Posted 2009) [#7]
LinePick(EntityX(p\entity),EntityY(p\entity),EntityZ(p\entity),0,1,0)


Why are you checking above you?

LinePick(EntityX(p\entity),EntityY(p\entity),EntityZ(p\entity),0,-1,0)
;or
LinePick(EntityX(p\entity),EntityY(p\entity),EntityZ(p\entity),0,-((MeshHeight(p\entity)/2)+.2),0)



OwlEpicurus(Posted 2009) [#8]
I was messing with the code to see if maybe that would work and forgot to set it back. Changing it to -1 doesn't make it work, though.


Guy Fawkes(Posted 2009) [#9]
ur right. didnt work.

heres the code i have so far man:

;Simple Environment To Demonstrate One of Many Methods To Perform Collision Checking with Gravity
;
;
Graphics3D 800,600,0,2
SetBuffer BackBuffer()

Player=CreatePivot()	;Create a pivot for our player character, the camera will be parented to this
Camera=CreateCamera()	

CameraRange camera,0.1,500 ;Adjust camera range to allow us to get 'close' to things.  Experiment with this if you wish.


EntityParent Camera,Player ;Attach the camera to the player pivot.  This way the camera will move with the player and follow its orientation

MoveEntity camera,0,0.2,0  ;Move the camera up slightly to place it at about eye level 


PositionEntity Player,12,25,-4 ;Place the player at an arbitrary location, in this case above the centre of the environment.

;Level=LoadAnimMesh("C:\Documents and Settings\john\Desktop\easybuilder\Easybuilder mk2\Exported\aliensmap\aliensmap.b3d") ;Load level mesh I've used loadanimmesh although could equally have used loadmesh

Level = CreatePlane()
EntityColor Level, 128, 128, 128

For x = 1 To Rnd(100)
cube = CreateCube()
PositionEntity cube, Rnd(x), 1, Rnd(x)
Next
								
EntityFX Level,1	;Make the level full-bright
AmbientLight 255,255,255 ;make the scene fully lit too!


Const Gravity#=-.15  ;play around with this value, just don't make it positive (now let's see you resist that temptation).

Const COLLISIONTYPE_SCENE = 1	;define our collision types. This way we can classify easily what type of collision something needs
Const COLLISIONTYPE_PLAYER = 2
Const PlayerCollisionRadius# = .150	;this is the player's x-radius (horizontal). I've hardcoded the y-radius below, reason for doing 
									;this is that the normal human is not enclosed by a sphere but more by a cylindrical shape
									;hence the y-radius will be longer than the x-radius.

Const PlayerSpeed# = .075	;How fast the player moves.
Const PlayerJumpSpeed# = 2.0

EntityType Level,COLLISIONTYPE_SCENE,True 	;set the collision types for our scene 
EntityType Player,COLLISIONTYPE_PLAYER		;and set it for the player

EntityRadius Player,PlayerCollisionRadius,0.7	;the 0.7 is the y-radius of the collision radius.

Collisions COLLISIONTYPE_PLAYER,COLLISIONTYPE_SCENE,2,3 
;This command then sets the relationship for collisions between any object with collision type 'player'
;and any object with collision type 'scene' to 'ellipsoid to polygon' and 'slide upwards'



RecursiveSearchMesh(Level);Set our level To pickable, specifically per polygon picking (inside this function...)
						  ;this is not usually needed when using loadmesh, but with loadanimmesh there may be
						  ;a hierarchy of meshes and so we need to parse through them all to set their entitypickmode,
						  ;merely setting the entitypickmode of the entity handle "Level" may not give desired results.



MoveMouse (GraphicsWidth()/2),GraphicsHeight()/2 ;Place the mouse in the centre of the screen/window.
RubbishValue#=MouseXSpeed() ;These 'rubbish values' are designed to discard the mousex/yspeed() values which result
RubbishValue#=MouseYSpeed()	;from moving the mouse back to the centre of the screen.


Repeat



	TurnEntity Player,0,Float(MouseXSpeed())*-0.5,0	;turn our player pivot around the vertical (y) axis when the player moves the mouse left/right
	TurnEntity Camera,Float(MouseYSpeed())*0.5,0,0  ;pitch our vision up/down when the mouse is moved up/down


	MoveMouse (GraphicsWidth()/2),GraphicsHeight()/2 ;reset the mouse position to the centre of the screen.
	
	RubbishValue#=MouseXSpeed() ;see comments from earlier above
	RubbishValue#=MouseYSpeed() ;see comments from earlier above

	
;	LinePick EntityX(Player),EntityY(Player)-0.7,EntityZ(Player),0,-0.05,0,0 ;Look beneath the player's feet with a linepick 
LinePick(EntityX(Player),EntityY(Player),EntityZ(Player),0,-((MeshHeight(Player)/2)+.2),0)

If PickedEntity() = 0 Then PlayerOnGround=0 ;if the linepick hit something then we must be on the ground / able to walk around
	

If PlayerOnGround = True Then ;If the player is on the ground, in contact with the surface then:

	MoveFWD=0	;adjust the MoveForwards/MoveSideways variables back to zero in preparation for receiving new input from the player
	MoveRIGHT=0
	JumpUP=0
	If KeyDown(200) Then MoveFWD=15	;if up arrow / cursor key pressed set the MoveForward flag to +1
	If KeyDown(208) Then MoveFWD=-1	;if down arrow / cursor key pressed set the MoveForward flag to -1 (backwards)
	If KeyDown(205) Then MoveRIGHT=1 ;if right arrow / cursor pressed set the MoveRight flag to +1
	If KeyDown(203) Then MoveRIGHT=-1 ;if left arrow / cursor pressed set the MoveRight flag to -1
	If MouseHit(1) Then JumpUp=1 ;if Left Mouse Button Clicked bar pressed then jump (assign a positive value to PlayerVelocityY)
	
	
	If PlayerVelocityY#<0 Then PlayerVelocityY#=0 ;as we are on the ground we need to ensure that we have no vertical velocity in the 
												  ;downwards direction.
	
	 	If JumpUp=1 Then ;if we are jumping (and only allows jumps when in contact with the ground)
			PlayerVelocityY = PlayerVelocityY + PlayerJumpSpeed
	
	
		EndIf 
		If MoveFwd<>0 Or MoveRight<>0 Then ;if we have pressed a button to order the player to move then:
				
				
				TFormNormal MoveRIGHT,0,MoveFWD,Player,0
				;We need to transform our 'forwards' and 'sideways' direction from the player's local space into
				;the direction in world space.  We also want to convert the resultant vector into a 'unit vector' 
				;so that it represents direction only in order to simply scale the vector by the player's walk speed.
				PlayerVelocityX#=TFormedX()*PlayerSpeed  
				PlayerVelocityZ#=TFormedZ()*PlayerSpeed
		Else
			 	
				
				PlayerVelocityX=0	;no order to move pressed so set our horizontal velocity to zero.
				PlayervelocityZ=0
				
				;an alternative, if you want to have gradual slow down would be as follows: (comment out the two lines above first though)
				PlayerVelocityX=PlayerVelocityX*0.7	;0.7 could be any number between 0 and 1, although I don't recommend using '1' as
				PlayerVelocityZ=PlayerVelocityZ*0.7 ;the player would always be moving.
				
		EndIf 
	
	
		
	
Else ;if the player is not on the ground then :

	;Loop through the player's collisions with all other objects.  If there is no collision or there is a collision with
	;a surface that is too steep then allow the player's vertical velocity to keep increasing in the negative direction.
	
	For ColIndex=1 To CountCollisions(Player)
	
		If CollisionNY(Player,ColIndex)>0.7 Then PlayerOnGround=True:PlayerVelocityY#=0 : Exit 
		;if the collision between the player and the other object is such that the surface collided with has a normal vector
		;pointing upwards at more than 45 degrees relative to the horizontal, (if the surface was flat collisionNY would return 1.0
		;which corresponds to a normal vector pointing upwards at 90 degrees to the horizontal) - then set their 'on ground' flag
		;to 1, and set their vertical velocity back to zero.
	Next
	
EndIf 

PlayerVelocityY#=PlayerVelocityY#+Gravity#	;Gravity acts upon the player's velocity each frame, even if on the ground - although
;if on ground the collision detection will prevent the player falling through the floor.


TranslateEntity Player,PlayerVelocityX,PlayerVelocityY,PlayerVelocityZ ;move the player a distance equal to their velocities in 
;each of the 3 directions x/y/z.


UpdateWorld ;standard blitz command, collision checks are all performed here, and animation.
RenderWorld ;render the environment.

Repeat
	;delay the program for a small amount of time 
	Delay 1
Until Abs(FrameTime-MilliSecs())>15
	
Text 10,10,playeronground


Flip	;flip the backbuffer() into view.





FrameTime=MilliSecs() ;really simple frame limiting, for an example of better timing look elsewhere, it is not covered here.

Until KeyDown(1) ;ESCAPE

FreeEntity level   ;always good to free any entities when finished with them 
FreeEntity camera  
FreeEntity player

End ;end of program.



;Recursive Routine which is used to set the pick mode of meshes which are children of the root node.
Function RecursiveSearchMesh(Mesh)
If CountChildren(Mesh) = 0 And EntityClass(Mesh) = "Mesh" Then EntityPickMode Mesh,2
For C=1 To CountChildren(Mesh)
	Child=GetChild(Mesh,C)
	If EntityClass(Child)="Mesh" Then EntityPickMode Child,2	
	RecursiveSearchMesh(Child)
Next

End Function



Kryzon(Posted 2009) [#10]
Look Owl (you mind if I call you Owl?), based on your most recent snippet I'll re-write it the way I think it should be:


[...]

;You're gonna have to tweak the LinePick's -Y value just so it's perfect for the feet of the character. Anything more than that will make him stop while in the air.

If p\jump = 1
   MoveEntity p\entity,0,p\yVel#,0
   p\yVel# = p\yVel# - 0.1
   
   If p\yVel < 0 Then LinePick(EntityX(p\entity,1),EntityY(p\entity,1),EntityZ(p\entity,1),0,-2,0)
   
   If PickedEntity() <> 0 Then Jump = 0   
Else 
   LinePick(EntityX(p\entity,1),EntityY(p\entity,1),EntityZ(p\entity,1),0,-2,0)
   If PickedEntity() <> 0 And KeyHit(SPACEBAR) Then
      p\yVel# = 2
      p\jump = 1
   EndIf    
Endif 

Changed the numbers "signs" too (can't remember the name in english). You don't need them to be negative.

I hope it works!

EDIT: It was wrong, now I corrected it =X


OwlEpicurus(Posted 2009) [#11]
You can call me Owl. I don't mind.

It still doesn't work, but thanks.


Kryzon(Posted 2009) [#12]
Corrected it. It was logically faulty, the character didn't have the chance to get back on ground and turn off the jump.


OwlEpicurus(Posted 2009) [#13]
Still nothing...


josk(Posted 2009) [#14]
I will check when I get home but the original code works for me.
LMB for jump.

Just checked but works fine with mouse button to jump.


OwlEpicurus(Posted 2009) [#15]
I still can't get it to work. It looks like the problem is with LinePick(); no matter what I try, I can't get it 'pick' an entity.

Has anyone else come up with something?

Edit: Disregard that! Predictably, I figured out how to fix it right after I posted.

Edit 2: Is there a way to get LinePick() to check against an entire mesh and not just its handle?


Warner(Posted 2009) [#16]
Then you need to set EntityPickMode for each child entity:
function Recursive_EntityPickMode(ent, mode)
 EntityPickMode ent, mode
 for i = 1 to countchildren(ent)
  Recursive_EntityPickMode(getchild(ent,i), mode)
 next
end function



OwlEpicurus(Posted 2009) [#17]
Thanks!