Just posting what I have so far, is still a work in progress(feel to comment/change/adjust/improve)..
[EDIT: While debugging I've just realized there's a whoooole lot of Bltz3D way of thinking nonsense in there, so corrected and of course collisions do ok now.]
Universal 1st/3rd Person Framework V4.2(updated)
// Project: Universal 1st/3rd person framework.
// Created: 2017-09-17
// Objective: flexible controller for 3d games without physics.
// Features:
// -switch between 1st / 3rd person cam
// -player to obstacles collisions
// -plater to ground(either plane, other objects or terrain)
// -jumping
// Thanks to:
// -Janbo for initial ObstacleAvoidingCam routine.
// -Sphinx for fixing cam turnbug using A and D keys.
//
// Setup..
WindowAndDisplaySetup()
// Initialization..
AssignKeys()
#constant version#=4.2
#constant MaxCameraDistance#= 7.0
NewCameraDistance#=MaxCameraDistance#
UserCameraDistance#=MaxCameraDistance#
Global CameraAngleX#
Global adjustfactor#=0
Global mouselocked=0
Global cammode=0
Global endgame=0
Global infodisplay=1
Global helpdisplay=0
Global playerheight#=2
Global playerwidth#=1
Global hspeed#= 2
Global vspeed#=.5
Global speed#=2
Global gravity#=0.4
Global jump=0
Global upy#=0
Global maxjump#=5
Global falling=0
CreateWorld()
CreatePlayer()
// main loop..
do
FrameTime#=GetFrameTime()
If GetRawKeyState(KEY_SHIFT) // Shift = speedup
speed#=2
else
speed#=1
Endif
If GetRawKeyState(KEY_SPACE) and falling=0 // Space = jump
If jump=0 // inair=0 // if not juming/inair already..
jump=1 // intitiate new jump
Endif
Endif
if jump=1 // if jump has been initiated ..
upy#=upy#+1 // increase y
if upy#>=maxjump# // if maxheight reached then reset y to 0 and no end jump..
upy#=0
jump=0
else
MoveObjectLocalY(PlayerObjectID,1)
endif
endif
// get input from mouse pointer..
PointerX#=GetPointerX()
PointerY#=GetPointerY()
If mouseLocked=0
setrawmouseposition(GetVirtualWidth()*0.5,GetVirtualHeight()*0.5) // recenter mouseon screen
EndIf
GetPointerMoveX#=(PointerX#-GetPointerX()) // calculate distance moved
GetPointerMoveY#=(PointerY#-GetPointerY())
// for turning left/right..
If GetRawKeyState(KEY_LEFT) OR GetRawKeyState(KEY_A) // Left/A = turn player left
GetPointerMoveX# = 40 * -hspeed#
Endif
If GetRawKeyState(KEY_RIGHT) OR GetRawKeyState(KEY_D) // Right/D = turn player right
GetPointerMoveX# = 40 * hspeed#
Endif
CameraAngleX#=CameraAngleX#+GetPointerMoveY#*FrameTime#
CameraAngleY#=CameraAngleY#+GetPointerMoveX#*FrameTime# // calc camera angle
UserCameraDistance#=UserCameraDistance#-GetRawMouseWheelDelta()*0.1 // zoom in/out when used mousewheel
if UserCameraDistance#>MaxCameraDistance# then UserCameraDistance#=MaxCameraDistance# //limit max dist from cam
if UserCameraDistance#<MaxCameraDistance#*0.5 then UserCameraDistance#=MaxCameraDistance#*0.5 // limit minimum dist from cam
//store players x,y,z and angles before any movement..
oldPlayerX#=GetObjectX(PlayerObjectID)
oldPlayerY#=GetObjectY(PlayerObjectID)
oldPlayerZ#=GetObjectZ(PlayerObjectID)
// get player virtual joystick input..
joystick_x# = GetJoyStickX()*hspeed#
joystick_y# = GetJoyStickY()*-vspeed#
// get keybpard input (PC only)..
// for moving forward/backward..
If GetRawKeyState(KEY_UP) = 1 or GetRawMouseRightState() // Up/W/RBM = move player forward
joystick_y#=1*vspeed# *speed# //addjust z
endif
If GetRawKeyState(KEY_DOWN) = 1 // Down/S = move player backward
joystick_y#=1*-vspeed# *speed#
Endif
// move player based on the input of joystick and mouse..
RotateObjectLocalY(PlayerObjectID,joystick_x#) // seems redundant,but somehow makes cam movement more fluid?
MoveObjectLocalZ(PlayerObjectID,joystick_y#)
SetObjectRotation(PlayerObjectID,0,CameraAngleY#,0) // set player at Y angle calculated according to mousemovement, don't move X angle for player will then tilt up/down
// for strafe.. ( if not put here then doesn''t work )
If GetRawKeyState(KEY_Q) // Q = move (strafe) player left
joystick_y# = .1*-hspeed#
MoveObjectLocalX(PlayerObjectID,joystick_y#)
Endif
If GetRawKeyState(KEY_E) // E = move (strafe) player right
joystick_y# = .1*hspeed#
MoveObjectLocalX(PlayerObjectID,joystick_y#)
Endif
MoveObjectLocalY(PlayerObjectID,-gravity#) // apply gravity ""always on''..
falling=1
// get players new x,y,z's for usage with cam and collisions..
newPlayerX#=GetObjectX(PlayerObjectID)
newPlayerY#=GetObjectY(PlayerObjectID)
newPlayerZ#=GetObjectZ(PlayerObjectID)
// ################### manage collision checking for the player #######################
// sphere cast between the old and new positions of the player to see if we hit something while moving to new location..
object_hit = ObjectSphereSlide(0,oldPlayerX#,oldPlayerY#,oldPlayerZ#,newPlayerX#,newPlayerY#,newPlayerZ#,playerwidth#)
// if the sphere has collided with an object then calculate sphere new position to give sliding collision
If object_hit <> 0 // we've hit something..
newPlayerX#=GetObjectRayCastSlideX(0)
newPlayerY#=GetObjectRayCastSlideY(0)
newPlayerZ#=GetObjectRayCastSlideZ(0)
falling=0
//SetObjectPosition(PlayerObjectID, PlayerX#, PlayerY#, PlayerZ# ) //process all modifications made above.
EndIf
If newPlayerY# <=playerheight#/2 //1 // so if gravity aplied but now ending up below the btm floor..
newPlayerY#=playerheight#/2 //1 // limit/reset y to minimm y so don't fall through floor
falling=0
endif
// posiition onto new location
SetObjectPosition(PlayerObjectID, newPlayerX#, newPlayerY#, newPlayerZ# ) //process all modifications made above.
// get players new x,y,z's for usage with cam ..??
PlayerX#=GetObjectX(PlayerObjectID)
PlayerY#=GetObjectY(PlayerObjectID)
PlayerZ#=GetObjectZ(PlayerObjectID)
// #################### manage camera avoiding geometry inbetween player and cam #########
If cammode=0 // 3rd person mode(default)..
SetCameraPosition(1,PlayerX#,PlayerY#,PlayerZ#) // place camera at player position
//SetCameraRotation(1,GetObjectAngleX(PlayerObjectID), GetObjectAngleY(PlayerObjectID) ,GetObjectAngleZ(PlayerObjectID) ) //
// limit cam x angle otherwise may tiltl too far..
If CameraAngleX#<0
adjustfactor#=CameraAngleX#/5+.3
//CameraAngleX#=0
if CameraAngleX#<= -20
CameraAngleX#=-20
endif
//adjustfactor#=CameraAngleX#/4
else
adjustfactor#=0
endif
If CameraAngleX#>90 then CameraAngleX#=90
SetCameraRotation(1,CameraAngleX#,CameraAngleY#,0) // set camera at angle calculated according to mousemovent
MoveCameraLocalZ(1,-MaxCameraDistance#) // move cam behind player
// obstacle avoiding cam..
RayObjectID=ObjectRayCast(0,PlayerX#,PlayerY#,PlayerZ#,GetCameraX(1),GetCameraY(1),GetCameraZ(1)) // sent a ray from players pos to cam behind player.
if RayObjectID<>0 // if an object is hit, this means there's an object between player and cam, obstructing the view'
NewCameraDistance#=GetObjectRayCastDistance(0) // set distance to where has been hit.
else
NewCameraDistance#=UserCameraDistance# // nothing's wrong's so set to user defined zoom distance.
endif
CameraDistance#=CurveValue(NewCameraDistance#,CameraDistance#,10) // calc new camdistance
SetCameraPosition(1,PlayerX#,PlayerY#,PlayerZ#) // redundant?
MoveCameraLocalZ(1,-CameraDistance#) // move cam to new position behind the player.
MoveCameraLocaly(1,-adjustfactor#) // move cam to new position behind the player.
ElseIf cammode =1 // 1st person mode..
SetCameraPosition(1,PlayerX#,PlayerY#,PlayerZ#-1) // place camera at player position
SetCameraRotation(1,CameraAngleX#,CameraAngleY#,0) // set camera at angle calculated according to mousemovent
///SetObjectVisible(PlayerObjectID,0)
Elseif cammode =2
Endif
CheckAdditiionalKeys()
DisplayInfo()
DisplayHelp()
If endgame=1 then exit
sync()
loop
end // exit game..
// Functions..
function CurveValue(Destination#,Current#,Steps#)
Current#=Current#+((Destination#-Current#)/Steps#)
endfunction Current#
Function CreateWorld()
// create a plane, turn its collision off, rotate it and position it under the middle box to act as a ground
// this is purely cosmetic
Global planeID
planeID=CreateObjectPlane(1000,1000)
SetObjectCollisionMode(planeID,0) // this is to stop it interfering with the collision with the map
// ensure everything is at correct starting point an orientation at creation.
SetObjectPosition(planeID,0,0,0) : SetObjectRotation(planeID,0,0,0)
// put where we want it..
SetObjectRotation(planeID,90,0,0) // put it flat
SetObjectPosition(planeID,0,0,0) //realign with origin
SetObjectColor(planeID,50,200,100,255) // color it lawn style
Global centerpoleID // mark center of our world..
centerpoleID=CreateObjectCylinder(6,.2,12)
SetObjectPosition(centerpoleID,0,3,0) : SetObjectRotation(centerpoleID,0,0,0) // ensure is at correct starting point.
SetObjectColor( centerpoleID ,0,0,0,255)
SetObjectCastShadow(centerpoleID,1)
// Create some static scenery objects to test with..
Global Dim obstacle[20]
For i=2 To 20
r=Random(1,4)
if r=1
obstacle[i]=CreateObjectBox( random(1,20), random(1,20) , random(1,20) )
SetObjectPosition(obstacle[i],0,0,0) : SetObjectRotation(obstacle[i],0,0,0) // ensure is at correct starting point.
SetObjectPosition( obstacle[i], Random(-50,50),0,Random(-50,50))
SetObjectRotation (obstacle[i],0.0,Random(0,360),0.0)
elseif r=2
obstacle[i]=CreateObjectCone(random(1,20),random(25,50),random(1,30))
SetObjectPosition(obstacle[i],0,0,0) : SetObjectRotation(obstacle[i],0,0,0) // ensure is at correct starting point.
SetObjectPosition( obstacle[i], Random(-50,50),0,Random(-50,50))
SetObjectRotation (obstacle[i],0.0,Random(0,360),0.0)
elseif r=3
obstacle[i]=CreateObjectCylinder(random(1,7),random(1,15),random(1,30))
SetObjectPosition(obstacle[i],0,0,0) : SetObjectRotation(obstacle[i],0,0,0) // ensure is at correct starting point.
SetObjectPosition( obstacle[i], Random(-50,50),0,Random(-50,50))
SetObjectRotation (obstacle[i],Random(0,360),Random(0,360),0.0)
//SetObjectScale (obstacle[i],-Random(.2,1),-Random(.2,1),-Random(.2,1))
else
//( diameter, rows, columns )
diameter#= random(.5,25)
rows#=random(.1,25)
colums#=random(5,32)
obstacle[i]=CreateObjectsphere(diameter#,rows# ,colums# )
SetObjectPosition(obstacle[i],0,0,0) : SetObjectRotation(obstacle[i],0,0,0) // ensure is at correct starting point.
SetObjectPosition( obstacle[i], Random(-50,50),-diameter#/5+random(0,1),Random(-50,50))
// SetObjectScale (obstacle[i],Random(.2,1),Random(.2,1),Random(.2,1))
SetObjectRotation (obstacle[i],0.0,Random(0,360),0.0)
endif
//SetObjectScale (obstacle[i],Random(.2,2),Random(.2,2),Random(.2,2))
SetObjectRotation (obstacle[i],0.0,Random(0,360),0.0)
SetObjectColor (obstacle[i],Random(0,255),Random(0,255),Random(0,255),Random(0,255))
SetObjectCollisionMode(obstacle[i],1)
SetObjectCastShadow(obstacle[i],1)
Next
EndFunction
Function CreatePlayer()
Global PlayerObjectID
PlayerObjectID=CreateObjectCapsule(playerwidth#,playerheight#,1) // ( diameter, height, axis )
SetObjectPosition(PlayerObjectID,0,1,-10)
SetObjectCastShadow(PlayerObjectID,1)
SetObjectCollisionMode(PlayerObjectID,0) //prevent self hiting
// add some detail so orientation of player is more clear..
gunID= CreateObjectCylinder(1.2,.2,10)
SetObjectPosition(gunID,0,0,0) : SetObjectRotation(gunID,0,0,0) // ensure is at correct starting point.
SetObjectPosition(gunID,.5,0,.4)
SetObjectRotation(gunID,0,90,90)
FixObjectToObject(gunID,PlayerObjectID)
SetObjectColor(gunID,0,0,0,255) //
SetObjectCollisionMode(gunID,0) //prevent self hiting
SetObjectCastShadow(gunID,1)
unaBrow = CreateObjectCone(.4,.8,12):SetObjectColor( unaBrow ,0,0,0,255)
SetObjectPosition(unaBrow,0,0,0) : SetObjectRotation(unaBrow,0,0,0) // ensure is at correct starting point.
SetObjectPosition( unaBrow ,0,.4,.3)
SetObjectRotation( unaBrow ,-180,0,0)
SetObjectCastShadow(unaBrow,1)
SetObjectCollisionMode(unaBrow,0) //prevent self hiting
FixObjectToObject(unaBrow,PlayerObjectID)
nose = CreateObjectSphere(.2,1.2,12):SetObjectColor( nose,255,0,0,255)
SetObjectPosition(nose,0,0,0) : SetObjectRotation(nose,0,0,0) // ensure is at correct starting point.
SetObjectPosition( nose,0,.2,.5)
SetObjectCastShadow(nose,1)
SetObjectCollisionMode(nose,0) //prevent self hiting
FixObjectToObject(nose,PlayerObjectID)
tail = CreateObjectcone(.2,.3,12):SetObjectColor( tail,255,255,255,255)
SetObjectPosition(tail,0,0,0) : SetObjectRotation(tail,0,0,0) // ensure is at correct starting point.
SetObjectPosition( tail,0,-.9,-.4)
SetObjectRotation(tail,-130,0,0)
SetObjectCastShadow(tail,1)
SetObjectCollisionMode(tail,0) //prevent self hiting
FixObjectToObject(tail,PlayerObjectID)
EndFunction
Function WindowAndDisplaySetup()
// ------------not really needed for this example -------
// set window properties
SetWindowTitle("Universal 1st/3rd Person Framework V"+str(version#,1) )
// set display properties
//SetWindowSize(1920,1080,0)
SetWindowSize(1024,600,0)
SetWindowAllowResize(1) // allow the user to resize the window
//SetVirtualResolution(1920,1080) // doesn't have to match the window
setvirtualresolution(1024,600)
SetOrientationAllowed(1,1,1,1) // allow both portrait and landscape on mobile devices
SetSyncRate(30,0) // 30fps instead of 60 to save battery
SetScissor(0,0,0,0) // use the maximum available screen space, no black borders
UseNewDefaultFonts(1) // since version 2.0.22 we can use nicer default fonts
SetPrintSize( 20 )
SetPrintColor( 00, 00, 00,255 )
SetClearColor(1,128,198)
SetGlobal3DDepth(10000) // Sets the position of all 3D objects relative to 2D objects.
SetResolutionMode(1)
SetAntialiasMode(1)
SetImmersiveMode(1)
SetRawMouseVisible(0)
SetCameraRange(1,1,1000)
SetAmbientColor(128,128,128)
SetGenerateMipmaps(1)
// -----------------------------------------------------------
fog=1
// add some atmospheric fog
SetFogMode( fog )
SetFogColor( 161,183,209 )
SetFogRange( 50, 700 )
//SetFogRange( 60,95 )
SetFogSunColor( 255,230,179 )
// -----------------------------------------------------------
SetShadowMappingMode(3)
SetShadowSmoothing(1)
SetShadowMapSize(2048,2024)
EndFunction
Function CheckAdditiionalKeys()
// check additional keys..
remstart
if GetRawKeyState(KEY_SPACE) = 1 //Space(jump)
initJump(grav decrease for while, jump_time)
endif
if GetRawKeyState(KEY_Alt = 1 //C(crouch)
crouchPlayer = 1
endif
if GetRawKeyState(KEY_CONTROL) = 1 //Ctrl/LMB
if item=weapon
launchProjectile
else
useCurrentItem
endif
endif
remend
If GetRawKeyState(KEY_F) = 1 // F= toggle focus (lock mouse to screen).
mouseLocked=1-mouseLocked
SetRawMouseVisible (mouseLocked)
period#=Timer()+1000000
For delay#=0 to period#
Next delay# // make sure doesn't get pressed right after again.
Endif
If GetRawKeyState(KEY_F1) = 1
helpdisplay=1-helpdisplay // F1= help
period#=Timer()+1000000
For delay#=0 to period#
Next delay# // make sure doesn't get pressed right after again.
EndIf
If GetRawKeyState(KEY_F2) = 1
infodisplay=1-infodisplay // F2= info
period#=Timer()+1000000
For delay#=0 to period#
Next delay# // make sure doesn't get pressed right after again.
EndIf
If GetRawKeyState(KEY_F3) = 1
cammode=cammode+1
if cammode=2 then MoveCameraLocalZ(1,-10) // move cam to new position behind the player.
if cammode=2 then MoveCameraLocalY(1,3) // move cam to new position behind the player.
if cammode=3 then cammode=0 // F3= toggle (1st/3rd person)
period#=Timer()+1000000
For delay#=0 to period#
Next delay# // make sure doesn't get pressed right after again.
EndIf
If GetRawKeyState(KEY_F4) = 1
cammode=1-cammode // F3= toggle (1st/3rd person)
period#=Timer()+1000000
For delay#=0 to period#
Next delay# // make sure doesn't get pressed right after again.
EndIf
remstart
If GetRawKeyState(KEY_I) = 1 then inventoryMode=1-inventoryMode //toggle inventory/zoom
If Tab/MMBwheel and inventoryMode=True then select weapon/item+ or -
If Tab/MMBwheel and inventoryMode=False then zoom+ or -
If Enter/MMB and mulitPlayer then chat=1-chat
If M(map) then mapDisplay=1-mapDisplay
If L(light) then torchOn=-torchOn
If P/Pause then pauseGame=1-pauseGame
If F1(help) then helpDisplay=1-helpDisplay
If F4(fog)
If F5
If F5 then audioOn=1-audioOn
If F6
gfxMode=gfxMode+1
if gfxMode=gfxMax
gfxMode=gfxModeMin(PC only)
endif
endif
endif
remend
If GetRawKeyPressed(KEY_ESC) then endgame=1 // Esc = exit(windows only)
EndFunction
Function DisplayInfo()
If infodisplay
// print info on screen..
Print ("FPS: " + str( ScreenFPS() ))
Print ("FrameTime: " + str( GetFrameTime() ))
Print ("Seconds: " + str( GetSeconds() ))
Print ("Polygons: " + str( GetPolygonsDrawn () ))
Print("CameraAngleX: "+ str(CameraAngleX#))
if cammode=0 then camdis$="3rd person(default)"
if cammode=1 then camdis$="1st person"
if cammode=2 then camdis$="detached"
Print("Cammode: "+ camdis$)
Print("")
Print ("F1 = Help")
EndIf
EndFunction
Function DisplayHelp()
If helpdisplay
// print info on screen..
Print ("F2 = toggle tech info")
Print ("F3 = toggle 1st/3rd person mode")
Print ("F4 = toggle fly/walk mode")
Print ("F5 = toggle audio on/off")
Print ("F6 = toggle fog on/off")
Print ("F7 = toggle gfxmode")
Print ("F8 = toggle sun on/off")
Print("")
Print ("W, A, S, D, RMB = move")
Print ("Q, E = strafe")
Print ("Mouse to look round")
Print ("Mousewheel = zoom in/out")
Print ("Shift + move = run")
Print ("Space = jump, Alt = crouch")
Print ("-Not implemented yet-")
Print ("Ctrl / LMB = fire/use item")
Print ("Tab / i = cycle inventory items")
Print ("T = torch, M = map, C = compass ")
Print ("")
Print ("F = toggle Mouse lock")
Print ("Esc = exit, P = pause" )
EndIf
EndFunction
Function AssignKeys()
#constant KEY_BACK 8
#constant KEY_TAB 9
#constant KEY_ENTER 13
#constant KEY_SHIFT 16
#constant KEY_CONTROL 17
#constant KEY_ALT 18 // added
#constant KEY_ESC 27
#constant KEY_SPACE 32
#constant KEY_PAGEUP 33
#constant KEY_PAGEDOWN 34
#constant KEY_END 35
#constant KEY_HOME 36
#constant KEY_LEFT 37
#constant KEY_UP 38
#constant KEY_RIGHT 39
#constant KEY_DOWN 40
#constant KEY_INSERT 45
#constant KEY_DELETE 46
#constant KEY_0 48
#constant KEY_1 49
#constant KEY_2 50
#constant KEY_3 51
#constant KEY_4 52
#constant KEY_5 53
#constant KEY_6 54
#constant KEY_7 55
#constant KEY_8 56
#constant KEY_9 57
#constant KEY_A 65
#constant KEY_B 66
#constant KEY_C 67
#constant KEY_D 68
#constant KEY_E 69
#constant KEY_F 70
#constant KEY_G 71
#constant KEY_H 72
#constant KEY_I 73
#constant KEY_J 74
#constant KEY_K 75
#constant KEY_L 76
#constant KEY_M 77
#constant KEY_N 78
#constant KEY_O 79
#constant KEY_P 80
#constant KEY_Q 81
#constant KEY_R 82
#constant KEY_S 83
#constant KEY_T 84
#constant KEY_U 85
#constant KEY_V 86
#constant KEY_W 87
#constant KEY_X 88
#constant KEY_Y 89
#constant KEY_Z 90
#constant KEY_F1 112
#constant KEY_F2 113
#constant KEY_F3 114
#constant KEY_F4 115
#constant KEY_F5 116
#constant KEY_F6 117
#constant KEY_F7 118
#constant KEY_F8 119
#constant KEY_SEMICOL 186
#constant KEY_EQUALS 187
#constant KEY_COMMA 188
#constant KEY_MINUS 189
#constant KEY_POINT 190
#constant KEY_SLASH 191
#constant KEY_SINGLQUOTE 192
#constant KEY_SQRBRLEFT 219
#constant KEY_BACKSLASH 220
#constant KEY_SQRBRRIGHT 221
#constant KEY_HASH 222
#constant KEY_ACCENT 223 // ' << is called ?
EndFunction