Rpg style movement

Blitz3D Forums/Blitz3D Programming/Rpg style movement

I have bin playing with this code for a couple weeks now. It is diablo style movement using a target entity that the player_mesh points at and if is far away the player_mesh moves to it. I have two versions the first is a no media and has bin posted in the code archives. The second one has
the ninja animation (for a place holder) from pacemaker.
I have not done much with 3d animations yet so if your have time I would apriciate any helpful coments, or if you know a better way to do this style movement I would like to here about it.
Some problems I am having are...
Jumping is difficult to achieve becouse pointentity seems to override any other movement comands.
With just a plane and the ninja I'm getting about 30-45 fps.
I don't know the polycount of the ninja but it seems to me I should be getting a better frame rate. So some tips on achieving optimal perfomace would be nice.

Graphics3D 640,480
AutoMidHandle True 
SeedRnd(MilliSecs)
;; FPS
MFPS = 5
Period = 1000/MFPS
Time = MilliSecs()-Period

Global fps,timenext,frames
;player info_________________________________________________________________________________________
;____________________________________________________________________________________________________
Global player_mesh
;The players Pointer Location
Global marker_X#
Global marker_Y#
Global marker_Z#
player_mesh=CreateCube()
ScaleEntity player_mesh,2,2,2
EntityShininess player_mesh,.015
PositionEntity player_mesh,10,1,10
EntityOrder player_mesh,0
camera=CreateCamera()
CameraRange camera,35,150 

light=CreateLight(2)
PositionEntity light,0,130,500
LightRange light,6000

terra_size=16 ; initial size of terrain, and no. of grids segments, along each  side
x_scale=100 ; x scale of terrain
y_scale=1 ; y scale of terrain
z_scale=100 ; z scale of terrain

terra=CreateTerrain(terra_size)
ScaleEntity terra,x_scale,y_scale,z_scale
EntityPickMode terra,2
TerrainDetail terra,100,1 ; Set terrain detail, vertex morphing 
grid_tex=CreateTexture( 32,32,8 )
ScaleTexture grid_tex,.5,.5
SetBuffer TextureBuffer( grid_tex )
Color 0,0,64:Rect 0,0,32,32
Color 0,0,255:Rect 0,0,32,32,False
SetBuffer BackBuffer()
EntityTexture terra,grid_tex

Global marker=CreateSphere()
ScaleEntity marker,1,1,1
EntityColor marker,255,0,0

While Not KeyDown(1)
PointEntity light,player_mesh

;temperary move cam function
move_cam(camera)
;keep track of mouse position relative to visable grid function
track_mouse(marker,camera)
;move the player to a picked position 
update_player(player_mesh,marker,camera)










UpdateWorld
RenderWorld

If KeyHit(57)=True  m=m+1
If m=2 Then m=0
If m=1 Then 
	Text 0,40,"PickedX: "+PickedX#()
	Text 0,60,"PickedY: "+PickedY#()
	Text 0,80,"PickedZ: "+PickedZ#()
	Text 180,40,"marker_X: "+marker_X
	Text 180,60,"marker_Y: "+marker_Y
	Text 180,80,"marker_Z: "+marker_Z
	Text 0,100,"targetangle#"+targetangle#
	Text 0,120,"currentangle#"+currentangle#
	
EndIf 
Text 2,2,"FPS: "+GetFPS(False)

Flip False 
;VWait : Flip False
Wend

End

;camera movement
Function move_cam(camera)
	If KeyDown( 205 )=True Then TurnEntity camera,0,-1,0
	If KeyDown( 203 )=True Then TurnEntity camera,0,1,0
	If KeyDown( 208 )=True Then TurnEntity camera,0,0,-1
	If KeyDown( 200 )=True Then TurnEntity camera,0,0,1
End Function

;keep track of mouse position relative to visable grid function
Function track_mouse(marker,camera)
	marker_X#=Int(PickedX#())
	marker_Z#=Int(PickedZ#())
	marker_Y#=Int(PickedY#())
	CameraPick(camera,MouseX(),MouseY())
End Function

Function update_player(player_mesh,marker,camera)
	If MouseDown(1) Then 
		FlushKeys 
		PositionEntity marker,marker_X#,marker_Y#,marker_Z#
		;Playerwalking=1 
	;Else Playerwalking=0 
	EndIf
	
	If EntityDistance(player_mesh,marker)>5
		PointEntity player_mesh,marker
		MoveEntity player_mesh,0,0,2
		PositionEntity camera,EntityX(player_mesh)-22.5,EntityY(player_mesh)+65,EntityZ(player_mesh)-22.5 
		PointEntity camera,player_mesh
		;Playerwalking=1
		
	;Else Playerwalking=0 
	EndIf
End Function

Function GetFPS(JustChecking = False)
     If Not JustChecking Then frames = frames+1

     If MilliSecs() > timenext Then
          timenext = MilliSecs()+1000
          fps = frames
          frames = 0
     EndIf
     Return fps
End Function




and the real code


Graphics3D 640,480
AutoMidHandle True 
SeedRnd(MilliSecs)
;; FPS
MFPS = 5
Period = 1000/MFPS
Time = MilliSecs()-Period

Global fps,timenext,frames

;Globals_____________________________________________________________________________________________
;____________________________________________________________________________________________________
;ninja animation sequences
Global  Walk
Global	Stealth
Global	PunchSwipe
Global	Overhead
Global	Block
Global	ForwardKick
Global	Pickup
Global	Jump
Global	JumpNoHeight
Global	HightKill
Global	SideKick
Global	SpinAttack
Global	BackFlip
Global	Climb
Global	Death1
Global	Death2
Global	Idle1
Global	Idle2
Global	Idle3
;player info_________________________________________________________________________________________
;____________________________________________________________________________________________________
Global player_mesh

;The players Pointer Location
Global marker_X#
Global marker_Y#
Global marker_Z#
;is the player walking or standing still?: True or false
Global Playerwalking
Global Playerjumping
Global fight_mode
Global Jumpspeed
;enemydata___________________________________________________________________________________________
;____________________________________________________________________________________________________
Global enemy_x,enemy_y,enemy_z
Global Enemywalking
;Global enemy_mesh
enemy_mesh=Get_NinjaAnima(enemy_mesh)
ScaleEntity enemy_mesh,2,2,2
EntityShininess enemy_mesh,.02


Dim red_enemy_mesh(2)

For R = 0 To 1
	
	red_enemy_mesh(R)=CopyEntity( enemy_mesh)
	EntityColor red_enemy_mesh(R),255,0,0
	PositionEntity red_enemy_mesh(R),100+Rnd(400),0,(R*15)+Rnd(400)
	
	;Animate red_enemy_mesh(R),1,Rnd(.75,1),Walk,Rnd(100)
Next

Dim blue_enemy_mesh(2)

For B = 0 To 1
	
	blue_enemy_mesh(B)=CopyEntity( enemy_mesh)
	ScaleEntity blue_enemy_mesh(B),6.25,2.5,6.25
	EntityColor blue_enemy_mesh(B),0,255,0
	PositionEntity blue_enemy_mesh(B),150+Rnd(400),0,(B*15)+Rnd(400)
	;Animate blue_enemy_mesh(B),1,Rnd(.75,1),Walk,Rnd(100)
Next 
 


terra_size=16 ; initial size of terrain, and no. of grids segments, along each  side
x_scale=100 ; x scale of terrain
y_scale=1 ; y scale of terrain
z_scale=100 ; z scale of terrain

;load the player mesh and animations
player_mesh=Get_NinjaAnima(player_mesh)
ScaleEntity player_mesh,2,2,2
EntityShininess player_mesh,.015
PositionEntity player_mesh,10,1,10
EntityOrder player_mesh,0
camera=CreateCamera()
CameraRange camera,35,150 

light=CreateLight(2)
PositionEntity light,0,130,500
LightRange light,6000

; Create terrain
terra=CreateTerrain(terra_size)
ScaleEntity terra,x_scale,y_scale,z_scale
EntityPickMode terra,2
TerrainDetail terra,100,1 ; Set terrain detail, vertex morphing 
grid_tex=LoadTexture("Floor 11.jpg")
ScaleTexture grid_tex,.5,.5
EntityFX terra,1
;EntityShininess terra, 1
;EntityAlpha terra,.6
;HideEntity terra
SetBuffer BackBuffer()
EntityTexture terra,grid_tex


; Create marker
Global marker=CreateSphere()
ScaleEntity marker,1,1,1
EntityColor marker,255,0,0
;HideEntity marker

;box= CreateCube()
;ScaleEntity box,20,1,20
;PositionEntity box,0,1,0
;rocktex=LoadTexture("rock_01.png")
;EntityTexture box,rocktex
;EntityPickMode box,2

;box2= CreateCube()
;ScaleEntity box2,20,1,20
;PositionEntity box2,50,3,50
;rocktex=LoadTexture("rock_01.png")
;EntityTexture box2,rocktex
;EntityPickMode box2,2

;box3= CreateCube()
;ScaleEntity box3,80,1,80
;PositionEntity box3,150,5,150
;rocktex=LoadTexture("rock_01.png")
;EntityTexture box3,rocktex
;EntityPickMode box3,2

;box4= CreateCube()
;ScaleEntity box4,70,1,70
;PositionEntity box4,150,7,150
;rocktex=LoadTexture("rock_01.png")
;EntityTexture box4,rocktex
;EntityPickMode box4,2


While Not KeyDown(1)
PointEntity light,player_mesh
;self-explanatory
enemy_AI()
choose_fight_mode()

;check and update the animation to see if the animation currently playing is the correct animation
check_animation(player_mesh,Playerwalking)
;temperary move cam function
move_cam(camera)
;keep track of mouse position relative to visable grid function
track_mouse(marker,camera)
;move the player to a picked position 
update_player(player_mesh,marker,camera)



UpdateWorld
RenderWorld

If KeyHit(57)=True  m=m+1
If m=2 Then m=0
If m=1 Then 
	Text 0,40,"PickedX: "+PickedX#()
	Text 0,60,"PickedY: "+PickedY#()
	Text 0,80,"PickedZ: "+PickedZ#()
	Text 180,40,"marker_X: "+marker_X
	Text 180,60,"marker_Y: "+marker_Y
	Text 180,80,"marker_Z: "+marker_Z
	Text 0,100,"targetangle#"+targetangle#
	Text 0,120,"currentangle#"+currentangle#
	Text 0,140,"fightmode "+fight_mode
EndIf 
Text 2,2,"FPS: "+GetFPS(False)

Flip False 
;VWait : Flip False
Wend

End


;camera movement
Function move_cam(camera)
	If KeyDown( 205 )=True Then TurnEntity camera,0,-1,0
	If KeyDown( 203 )=True Then TurnEntity camera,0,1,0
	If KeyDown( 208 )=True Then TurnEntity camera,0,0,-1
	If KeyDown( 200 )=True Then TurnEntity camera,0,0,1
End Function


;keep track of mouse position relative to visable grid function
Function track_mouse(marker,camera)
	marker_X#=Int(PickedX#())
	marker_Z#=Int(PickedZ#())
	marker_Y#=Int(PickedY#())
	CameraPick(camera,MouseX(),MouseY())
End Function


Function update_player(player_mesh,marker,camera)
	If MouseDown(1) Then 
		FlushKeys 
		PositionEntity marker,marker_X#,marker_Y#,marker_Z#
		Playerwalking=1 
	Else Playerwalking=0 
	EndIf
	
	If EntityDistance(player_mesh,marker)>5
		PointEntity player_mesh,marker
		MoveEntity player_mesh,0,0,2
		PositionEntity camera,EntityX(player_mesh)-22.5,EntityY(player_mesh)+65,EntityZ(player_mesh)-22.5 
		PointEntity camera,player_mesh
		Playerwalking=1
		
	Else Playerwalking=0 
	EndIf
End Function


Function Get_NinjaAnima(anim)
	anim=LoadAnimMesh("bot/PMKninja.b3d")
	
    Walk=ExtractAnimSeq(anim,1,14)
	Stealth=ExtractAnimSeq(anim,15,30)
	PunchSwipe=ExtractAnimSeq(anim,32,44)
	Overhead=ExtractAnimSeq(anim,60,68)
	Block=ExtractAnimSeq(anim,69,72)
	ForwardKick=ExtractAnimSeq(anim,73,85)
	Pickup=ExtractAnimSeq(anim,84,93)
	Jump=ExtractAnimSeq(anim,94,102)
	JumpNoHeight=ExtractAnimSeq(anim,103,111)
	HightKill=ExtractAnimSeq(anim,112,125)
	SideKick=ExtractAnimSeq(anim,126,133)
	SpinAttack=ExtractAnimSeq(anim,134,145)
	BackFlip=ExtractAnimSeq(anim,146,158)
	Climb=ExtractAnimSeq(anim,159,165)
	Death1=ExtractAnimSeq(anim,166,173)
	Death2=ExtractAnimSeq(anim,174,182)
	Idle1=ExtractAnimSeq(anim,184,205)
	Idle2=ExtractAnimSeq(anim,206,250)
	Idle3=ExtractAnimSeq(anim,251,300)
	
	Return anim
End Function


Function check_animation(anim,walking)
	Select walking
		Case 0 
			If (Animating(anim) <> True) Or (AnimSeq (anim) =  Walk)
				Animate anim,3,.25,Idle2,4
			EndIf
		Case 1 
			If (Animating(anim) <> True) Or (AnimSeq (anim) = Idle2)
				Animate anim,3,1,Walk
			EndIf
		;Case 2 If (Animating(anim) <> True) Or (AnimSeq (anim) = Idle2)
		
		
	End Select
End Function

Function enemy_AI()
 

For B = 0 To 1
	If EntityDistance (blue_enemy_mesh(B),player_mesh) > 150 Then 
		HideEntity blue_enemy_mesh(B)
	Else ShowEntity blue_enemy_mesh(B)
	EndIf 
	

	If EntityDistance (blue_enemy_mesh(B),player_mesh) < 70 Then 
		

		PointEntity blue_enemy_mesh(B),marker
		If EntityDistance (blue_enemy_mesh(B),player_mesh) < 40 Then 
			PointEntity blue_enemy_mesh(B),player_mesh
		EndIf
		Enemywalking=True 
		
		MoveEntity blue_enemy_mesh(B),0,0,1.5
	EndIf
	check_animation(blue_enemy_mesh(B),Enemywalking)
	Enemywalking=False  
Next
For R = 0 To 1
	If EntityDistance (red_enemy_mesh(R),player_mesh) > 150 Then
 		HideEntity red_enemy_mesh(R)
	Else ShowEntity red_enemy_mesh(R) 
	EndIf 
	
	If EntityDistance (red_enemy_mesh(R),player_mesh) < 70 Then
		
 
		Enemywalking=True 
		PointEntity red_enemy_mesh(R),player_mesh
		MoveEntity red_enemy_mesh(R),0,0,1
	EndIf 
	check_animation(red_enemy_mesh(R),Enemywalking)
	Enemywalking=False 
Next

End Function

Function choose_fight_mode()
fight_mode=GetKey()
Select fight_mode
 	Case (49)
		If (Animating(player_mesh) <> True) Or (AnimSeq (player_mesh) <> PunchSwipe )
			Animate player_mesh,3,.5,PunchSwipe
		EndIf 
	Case (50)
		If (Animating(player_mesh) <> True) Or (AnimSeq (player_mesh) <> Overhead )
			Animate player_mesh,3,.5,Overhead
		EndIf 
	Case (51)
		If (Animating(player_mesh) <> True) Or (AnimSeq (player_mesh) <> Block )
			Animate player_mesh,3,.5,Block
		EndIf 
	Case (52)
		If (Animating(player_mesh) <> True) Or (AnimSeq (player_mesh) <> ForwardKick )
			Animate player_mesh,3,.5,ForwardKick
		EndIf 
	Case (53)
		If (Animating(player_mesh) <> True) Or (AnimSeq (player_mesh) <> Pickup )
			Animate player_mesh,3,.5,Pickup
		EndIf 
	Case (54)
		If (Animating(player_mesh) <> True) Or (AnimSeq (player_mesh) <>  Jump)
		Animate player_mesh,3,.25,Jump
		;TranslateEntity player_mesh,0,13,0
		EndIf 
		Playerjumping=True 
	Case (55)
		If (Animating(player_mesh) <> True) Or (AnimSeq (player_mesh) <> JumpNoHeight )
			Animate player_mesh,3,.5,JumpNoHeight
		EndIf 
	Case (56)
		If (Animating(player_mesh) <> True) Or (AnimSeq (player_mesh) <> HighKill )
			Animate player_mesh,3,.35,HightKill
		EndIf 
	Case (57)
		If (Animating(player_mesh) <> True) Or (AnimSeq (player_mesh) <> SideKick )
			Animate player_mesh,3,.5,SideKick
		EndIf 

End Select
If KeyDown(15)	
	Select fight_mode
	Case (49)
		If (Animating(player_mesh) <> True) Or (AnimSeq (player_mesh) <> SpinAttack )
			Animate player_mesh,3,.5,SpinAttack
		EndIf 
	Case (50)
		If (Animating(player_mesh) <> True) Or (AnimSeq (player_mesh) <> BackFlip )
			Animate player_mesh,3,.5,BackFlip
		EndIf 
	Case (51)
		If (Animating(player_mesh) <> True) Or (AnimSeq (player_mesh) <> Climb )
			Animate player_mesh,3,.5,Climb
		EndIf 
	Case (52)
		If (Animating(player_mesh) <> True) Or (AnimSeq (player_mesh) <> Death1 )
			Animate player_mesh,3,.5,Death1
		EndIf 

	Case (53)
		If (Animating(player_mesh) <> True) Or (AnimSeq (player_mesh) <> Death2 )
			Animate player_mesh,3,.5,Death2
		EndIf 
	End Select
EndIf  
End Function

Function GetFPS(JustChecking = False)
     If Not JustChecking Then frames = frames+1

     If MilliSecs() > timenext Then
          timenext = MilliSecs()+1000
          fps = frames
          frames = 0
     EndIf
     Return fps
End Function




Thanks for any help!

you may use translateentity for jumping, and right after pointentity you may use a

Rotateentity guy,0,entityyaw(guy),0

I now have 75-105 fps by using a lower graphics setting and by using vwait flip false. It looks about the same but twice the frame rate. I also have the player jumping to any place the mouse pointer is, including up onto boxes and stuff. He even walks on verticle surfaces. I think I want to build on that. The only problem is making it look right.
As is the player is pointing at the marker and is straight up if on leval ground, however on a verticle surface he will its angle is all haywire.

So my Idea to fix this is to use rotateentity like above, but how can I find the 90 degree angle to the surface he is jumping too?

I'm not sure that I understand what you're asking, but DeltaYaw() or DeltaPitch() might be what you're looking for.

What I am asking is a for a way to make the player stand on picked verticle surfaces. Imagine the player that follows the mouse (like in the 1st sample code I posted}. Then I have a large cube that is pickable, standing twenty or thirty feet tall, representing a wall of a building. Now when the player jumps onto that wall I want the player to ajust to the suface by standing 90 degrees to it and look the same as if he is standing on the ground. I'll post screen shots in a little while to show what I am talking about.

This picture demonstrates what I am talking about.
http://www.urbanposters.com/item~p~8320~pnid~847~nid~445.htm

Ow, a bit like in Ratchet & Clank where you can move up some buildings and stuff? I'm not sure how to do that, but I think you might be able to do it by always doing a linepick straight down from the player's location, and then use AlignToVector yourplayerentity,PickedNX(),PickedNY(),PickedNZ(),2
It won't work with 90° angles, because you pick straight down, but that could be easily solved by creating a small ramp.
So instead of sharp angles like this :
  |
__|


you'd make them softer like this :

  |
_/


You'd have to make sure you always move the player relative to the current angle.

That could work :)

Good Idea, I'll give that a shot.
Thanks

Oh, just one tip on using linepick : do it after you do updateworld. If you have some kind of gravity that is pulling down on the player every frame, your player could be a very little bit beneath the object you're trying to pick, but if you set up the collisions correclty, this won't be the case after updateworld.

I have a question:
If you have multiple UpdateWorlds in your main loop, which one should you place it after?

You shouldn't have multiple updateworlds in your main loop, because it would slow down everything. You'd best do something like this :
UpdatePlayers_Before() ; player movement etc
UpdateEnemies_Before() ; enemy movement etc

UpdateWorld()

UpdatePlayers_After() ; linepicks, position shadow at linepick coordinates, etc
UpdateEnemies_After() ; linepicks, position shadow at linepick coordinates, etc

Renderworld()
You can store the results of the linepick in the player's type if you need to use it in UpdatePlayers function.

In the UpdatePlayers_After() function, you can also compare the LinePick with the player's height to know if he's floating somewhere or not - I use this for jumping and gravity... When the player jumps, set player\jumping to true, and use this to make sure he can't keep jumping even when in mid-air like you can do in the castle demo. When the height of the player minus the linepickheight is very small, set it to false.
In your UpdatePlayers_Before(), you can check player/jumping - if it is true, increase player\dy# which is the amount you make him move down each frame. If it is false, set player\dy to a very small value (or 0, but I found a small value worked better).
This is all a bit off topic, but I think you might find it usefull :)

But if you do need multiple updateworlds, put it either after the last one, or after the one that comes after your player movement routines (where you apply gravity).

It's a nice start for point and click code... the real mastery happens when you have objects and things in the pathways... Assuming the play surface isnt always flat.

I've been working on such a plotter for sometime now but with little results i'm afraid. I got the best results by using a node system but this isnt the best way of doing it as maps can become large and node chking can become tidious on the resources..

If you happen along a method please share! :) as will I.

So far with no collisions set up there are two things that happen with objects in the way. If the object is pickable the player steps on it and the height is adjusted becouse the player is set like this
If MouseDown(1) Then 
		FlushKeys 
		PositionEntity marker,marker_X#,marker_Y#,marker_Z#
		Playerwalking=1 
	Else Playerwalking=0 
	EndIf
	
	If EntityDistance(player_mesh,marker)>5
		PointEntity player_mesh,marker
		MoveEntity player_mesh,0,0,2
		PositionEntity camera,EntityX(player_mesh)-22.5,EntityY(player_mesh)+65,EntityZ(player_mesh)-22.5 
		PointEntity camera,player_mesh
		Playerwalking=1
		
	Else Playerwalking=0 
	EndIf
End Function



the result is, if its just like some steps or a ramp he walks up them and looks ok but the players height is ajusted as soon as that point is picked rather that when he reaches the step.
The second is that when the object is tall like a building and is pickable, but the player walks up it taking the shortest path posible.(ninjas are so lazy) The good thing about this is that usualy becouse of the camera veiw you end up picking a side of the tall object and the player walks up it verticly, but on his side which looks goofy.


I guess, in a way thats how this code works, but only one node. You klick a point on the grid and the player moves to that point. I could see it being expanded on to be able to click several points and get the player to move to each point. Then expanded further to use a pathfinding algorithm
to make the point automatic. Thats a ways off though.