Hello.
I've noticed that a number of people seem to have questions about things like 'jumping' 'collisions' and 'gravity' in recent times, so thought that I might try to post something a little constructive/helpful about the matter.
In the code shown below I have commented each line to attempt to explain what is happening at each stage of the program. In the program, the player is able to walk around a 3d environment, mouse look, walk up stairs, fall off ledges, and jump.
This is not necessarily the best way of doing this, and it is far from the only way of doing this but you may find it useful.
Feel free to use the code in any way you want and/or reuse it in your own projects.
The media is found at this web address (<1 MB)
http://home.swiftdsl.com.au/%7ETmalcolm/Tutorial/Environment.zip
It contains a single 3d model and really basic texture which you are free to use as you wish as well.
Here is the sourcecode, fully commented:
from Matt
I've noticed that a number of people seem to have questions about things like 'jumping' 'collisions' and 'gravity' in recent times, so thought that I might try to post something a little constructive/helpful about the matter.
In the code shown below I have commented each line to attempt to explain what is happening at each stage of the program. In the program, the player is able to walk around a 3d environment, mouse look, walk up stairs, fall off ledges, and jump.
This is not necessarily the best way of doing this, and it is far from the only way of doing this but you may find it useful.
Feel free to use the code in any way you want and/or reuse it in your own projects.
The media is found at this web address (<1 MB)
http://home.swiftdsl.com.au/%7ETmalcolm/Tutorial/Environment.zip
It contains a single 3d model and really basic texture which you are free to use as you wish as well.
Here is the sourcecode, fully commented:
;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,0,10,0 ;Place the player at an arbitrary location, in this case above the centre of the environment. Level=LoadAnimMesh("Environment.x") ;Load level mesh I've used loadanimmesh although could equally have used loadmesh 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# = 1.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=1 ;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 0,0,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
from Matt