Hi Everyone,
I'll post here rather than in code snippets since this forum is where everyone with a problem with Dark Physics looks first.
I'm new to Dark Physics and having encountered the same problems with the character controller as everyone else I've been feeling rather sorry for Mike. Everyone complains about the character controller, and I agree it would be nice if it worked like a controllable dynamic rigid body...but if it can't, it can't...however, DP provides lots of other really cool tools to make life easier.
I've read a lot of the posts on jumping/falling etc...and a lot of the solutions are rather awkward half fixes so I've come up with a new (perhaps) way of doing it. The principle is simple. When jumping and falling you generally don't need to control your character, so why not delete the character controller and turn your player object into a dynamic rigid body. Then when they land on something flat(ish) turn the player object back into a controller.
Anyway my code is below. It works fairly well with one or two little glitches mainly related to rotation when falling. No media is required. Screen shot attached. Use arrow keys to move.
Rem Project: An Improved Character Controller
Rem Created: Saturday, July 03, 2010
Rem ***** This code shows a method for jump and freefall based on a dynamic rigid body
Rem this allows the player to interact with scenery and other dynamic objects during jumping and free fall
Rem On jump or freefall the character controller is deleted and the player is defined as a dynamic rigid body.
Rem when a collision with a horizontal (ish) surface occurs the player again becomes a character controller.
Rem No media is required for this project
Rem I've used a type for my player data just to allow scaling to numerous players
Type playerstype
x as float
y as float
z as float
angle as float
v as float
obj as integer
jumpcount as integer
mass as float
Endtype
Dim players(20) as playerstype
Rem This type will store collision data for the player
Type playercol
obj as integer
cny as float rem contact normal y
cx as float rem contact position x
cy as float rem contact position y
cz as float rem contact position z
Endtype
Dim player_collisions(20, 10) as playercol
global num_playercollisions = 0
REm Camera Variables
global camdist# = 100.0
global camangle# = 0.0
global camx# = 200.0
global camz#= 200.0
global camy# = 200.0
Rem Object pointers
global obj_player = 1
phy start
Rem I have used a large gravity because my sync rate is set to 30
phy set gravity 0.0, -240.0, 0.0
Rem ***********Set up display*******
SYS_init_graphics_mode()
Rem ***********Set up level********
WORLD_load_level()
Rem ***********Set up players********
GAME_load_player()
Rem **********Set up Camera**********
SYS_setup_camera()
Do
Rem Get keyboard input and set variables
SYS_get_input()
Rem Read collisions from the collision stack
SYS_get_collisions()
Rem Update objects based on player collisions
GAME_update_objects()
Rem Update the player based on keyboard and collisions
GAME_update_player()
Rem Let Dark Physics update object positions
phy update
Rem Update camera based on player position
SYS_update_camera()
sync
loop
end
Function GAME_load_player()
Rem I've chosen to set up a material to make the player object less bouncy
phy make material 1, "player"
phy set material restitution 1, 0.0
phy build material 1
Rem set player data
players(1).x = 0.0
players(1).y = 20.0
players(1).z = -100.0
players(1).angle = 0.0
players(1).mass = 1.0
Rem Setup player and create controller.
make object box obj_player, 10.0, 25.0, 10.0
position object obj_player, players(1).x, players(1).y, players(1).z
color object obj_player, rgb(255, 0, 0)
phy make box character controller obj_player, object position x(obj_player), object position y(obj_player), object position z(obj_player), object size x(obj_player)/2, object size y(obj_player)/2, object size z(obj_player)/2, 1, 5.0, 45.0
Endfunction
Function GAME_update_objects()
Rem This function applies an impulse to dynamic objects hit by the player based on scaled momentum
For i=1 to num_playercollisions
if phy get rigid body exist(player_collisions(1, i).obj)
Rem object is a dynamic object, apply force as momentum
Rem Note this does not need to take into account the momentum of the object
mvx# = players(1).v*sin(players(1).angle)*players(1).mass*10000.0
mvz# = players(1).v*cos(players(1).angle)*players(1).mass*10000.0
phy add rigid body force player_collisions(1, i).obj, mvx#, 0.0, mvz#, player_collisions(1, i).cx, player_collisions(1, i).cy, player_collisions(1, i).cz, 1
endif
next i
ENDFUNCTION
Function GAME_update_player()
Rem Test for fall if not jumping or falling already
if phy get character controller exist(obj_player)
Rem If there is within a threshold distance below the character then considers it is standing on it
col = phy ray cast closest shape (object position x(obj_player),object position y(obj_player), object position z(obj_player), 0.0, -1.0, 0.0)
standingonsomething=0
if col>0
dist# = phy get ray cast distance()
Rem The threshold distance is arbitary. Better performance near edges could be obtained with more ray casts
Rem Note: The character controller positions the object not to
if dist#<object size y(obj_player)/1.5 then standingonsomething = 1
endif
if standingonsomething=0
Rem Not standing on anything...delete character controller and set-up as a dynamic rigid body
set cursor 10, 10
Print "FALLING!"
UTIL_create_dynamicplayer(0.0)
players(1).jumpcount = 0.0
endif
endif
Rem if jumping or in freefall the player object exists as a rigid body
if phy get rigid body exist(obj_player) and players(1).jumpcount<=0
Rem Test for player colliding with an object below. If the surface is almost flat the player will be allowed to land
col = phy ray cast closest shape (object position x(obj_player),object position y(obj_player)-object size y(obj_player)/2.0, object position z(obj_player), 0.0, -1.0, 0.0)
rayobj = phy get ray cast object()
if rayobj>0 and num_playercollisions>0
Rem an object is below the player, evaluate for collision if the player is moving down
cny#=0.0
For i=1 to num_playercollisions
if player_collisions(1, i).obj = rayobj then cny# = player_collisions(1, i).cny
next i
if cny#<-0.5
Rem Has landed in an almost flat surface
phy delete rigid body obj_player
rotate object obj_player, 0.0, players(1).angle, 0.0
phy make box character controller obj_player, object position x(obj_player), object position y(obj_player),object position z(obj_player), 5.0, 12.0, 5.0, 1, 5.0, 45.0
endif
endif
if phy get rigid body exist(obj_player)
rem Prevent player from rotating in the air
phy set rigid body angular velocity obj_player, 0.0, 0.0, 0.0
endif
else
if players(1).jumpcount>0 then dec players(1).jumpcount
endif
Rem Move player forwards or backwards
if players(1).v<>0.0 and phy get character controller exist(obj_player)
phy set character controller displacement obj_player, 200.0, 0.0
phy move character controller obj_player, players(1).v
if players(1).v>0.0
players(1).v = players(1).v - 3.0
endif
if players(1).v<0.0
players(1).v = players(1).v + 3.0
endif
if abs(players(1).v)<3.0 then players(1).v = 0.0
endif
Rem Rotate player
yrotate object obj_player, players(1).angle
num_playercollisions = 0
ENDFUNCTION
Function SYS_get_collisions()
Rem This function handles any collisions, this is necessary to run each time step as
Rem collisions remain on the collision stack until they are read, if you don't read
Rem them each timestep bizarre collision will appear to have occurred
icol=1
while phy get collision data ( )
a = phy get collision object a ( )
b = phy get collision object b ( )
if a = obj_player or b = obj_player
if a=obj_player then obj=b
if b=obj_player then obj=a
inc num_playercollisions
player_collisions(1, num_playercollisions).obj = obj
Rem notice the next line stores the contact normal and positions of the collision on the object the player has collided with
player_collisions(1, num_playercollisions).cny = phy get collision contact normal y(obj, icol)
player_collisions(1, num_playercollisions).cx = phy get collision contact point x(obj, icol)
player_collisions(1, num_playercollisions).cy = phy get collision contact point y(obj, icol)
player_collisions(1, num_playercollisions).cz = phy get collision contact point z(obj, icol)
endif
inc icol
endwhile
Rem The collision stack is now empty
ENDFUNCTION
Function SYS_get_input()
Rem This function updates variables based on input and on whether the
Rem player is in freefall/jumping
if upkey()
if phy get character controller exist(obj_player)
if players(1).v>70.0
players(1).v = 70.0
else
players(1).v = players(1).v + 6.0
endif
endif
endif
if downkey()
if phy get character controller exist(obj_player)
if players(1).v<-30.0
players(1).v = players(1).v - 5.0
else
players(1).v = -30.0
endif
endif
endif
if leftkey()
if phy get character controller exist(obj_player)
players(1).angle = wrapvalue(players(1).angle - 2.0)
endif
endif
if rightkey()
if phy get character controller exist(obj_player)
players(1).angle = wrapvalue(players(1).angle + 2.0)
endif
endif
if spacekey()
Rem jump key. If the player is not already in the air delete the character controller
Rem and make the player a dynamic rigid body. Initialise the linear velocity
if phy get character controller exist(obj_player)
Rem Note, there is an issue with run-jumping uphill on slopes if the vertical speed is too low
Rem here I set a high vertical jump speed but you could use a ray cast to prevent run jumping up slope
UTIL_create_dynamicplayer(140.0)
endif
endif
ENDFUNCTION
Function SYS_init_graphics_mode()
Rem This function sets the optimum graphics mode for the users system
Rem Choose highest display mode
perform checklist for display modes
for c=1 to checklist quantity()
depth1=checklist value c(c)
if depth1=32
width=checklist value a(c)
height=checklist value b(c)
depth=depth1
endif
next c
maximize window
set display mode width, height, depth
sync on Rem sets to code screen refresh
sync rate 30 Rem Will attempt to refresh every 30 seconds
autocam off
endfunction
Function SYS_setup_camera()
position camera object position x(obj_player), object position y(obj_player)+8.0, object position z(obj_player)
set camera to object orientation obj_player
pitch camera down 15.0
move camera -camdist#
Endfunction
Function SYS_update_camera()
position camera object position x(obj_player), object position y(obj_player)+8.0, object position z(obj_player)
set camera to object orientation obj_player
pitch camera down 15.0
move camera -camdist#
Endfunction
Function UTIL_create_dynamicplayer(upvel#)
Rem This function deletes the character controller and makes the player a dynamic object
phy delete character controller obj_player
phy make rigid body dynamic box obj_player, 1
Rem set angular damping to minimise rotation in the air
phy set rigid body angular damping obj_player, 1.0
rem Initialise the cartesian velocities
vx# = players(1).v*sin(players(1).angle)
vz# = players(1).v*cos(players(1).angle)
Rem Set a counter to ignore collisions immediately after jumping
players(1).jumpcount = 10
phy set rigid body linear velocity obj_player, vx#, upvel#, vz#
ENDFUNCTION
Function WORLD_load_level()
Rem Create a floor
make object box 10, 1000, 1, 1000
position object 10, 0, 0, 0
color object 10, rgb(0, 255, 0)
phy make rigid body static mesh 10
Rem Create a platform
make object box 11, 100, 100, 100
position object 11, 0, 0, 137
color object 11, rgb(0, 0, 255)
phy make rigid body static mesh 11
Rem Create a ramp
make object box 12, 50, 5, 200
position object 12, 0, 0, 0
pitch object up 12, 27
phy make rigid body static mesh 12
Rem Create a second platform
make object box 13, 100, 270, 100
position object 13, -240, 0, 137
color object 13, rgb(0, 0, 255)
phy make rigid body static mesh 13
Rem Create a second ramp
make object box 14, 50, 5, 200
position object 14, -100, 90, 137
turn object left 14, 90
pitch object up 14, 27
phy make rigid body static mesh 14
Rem Create a third platform
make object box 15, 100, 270, 100
position object 15, -240, 0, -100
color object 15, rgb(0, 0, 255)
phy make rigid body static mesh 15
Rem Create a fourth platform
make object box 16, 20, 5, 100
position object 16, -240, 128, 0
phy make rigid body static mesh 16
Rem Create a few dynamic objects to push around
make object sphere 17, 20, 20, 20
position object 17, 0, 100, 137
color object 17, rgb(0, 255, 255)
phy make rigid body dynamic sphere 17
Rem Create a few dynamic objects to push around
make object sphere 18, 10, 10, 10
position object 18, -240, 278, 0
color object 18, rgb(0, 255, 255)
phy make rigid body dynamic sphere 18
Endfunction
p.s. It also allows the player to push dynamic objects about. That bit was easy.
GrumpyOne - the natural state of the programmer