I have a suggestion for a possible improvement to the ThirdPerson.pb demo.
This change will make the robot animation stop when it stops moving.
It was one thing that really bothered me about an otherwise excellent demo program.
IMO this small amount of code change will make the demo much more elegant.
It is totally up to you of course if you choose to implement this modification or not.
I will take no offense if you don't.
Also, you may invent a more elegant way to code it. Your option.
I use the AnimateEntity() to affect the change.
There is one thing though, using the "Stop" string with AnimateEntity() was a pure guess.
It seems to work though.
I added two new variables in 'HandleEntity()' procedure.
Action.s and LastAction.s
Here are the line by line details of what I have done.
Code:
Modifications to 'ThirdPerson.pb' demo.
Line 13 #PlayerSpeed = 26 ;IMO a better choice
Line 113 AnimateEntity(0, "Stop") ;changed "Walk" to "Stop"
Line 228 Protected.f Speed, Speed2, x, y, MouseX, MouseY, Action.s ;added Action.s
Line 229 Static Jump.f, MemJump.i, Rot.Vector3, Trans.Vector3, Clic, LastAction.s ;Added LastAction.s
Line 263 Action = "Stop" ;a new line
Line 268 Action = "Walk" ;a new line
Line 272 Action = "Walk" ;a new line
Line 284 Action = "Walk" ;a new line
Line 288 Action = "Walk" ;a new line
;a new if block
Line 291 If Action <> LastAction
Line 292 LastAction = Action
Line 293 AnimateEntity(0, Action)
Line 294 EndIf
Here is the complete modified code.
Code:
;
; ------------------------------------------------------------
;
; PureBasic - Third Person
;
; (c) 2011 - Fantaisie Software
;
; ------------------------------------------------------------
;
IncludeFile "Screen3DRequester.pb"
#PlayerSpeed = 26
#CameraSpeed = 10
Structure Vector3
x.f
y.f
z.f
EndStructure
Structure s_Key
Up.i
Down.i
Left.i
Right.i
StrafeLeft.i
StrafeRight.i
Jump.i
EndStructure
Structure s_Entity
Entity.i
EntityBody.i
BodyOffsetY.f
elapsedTime.f
Key.s_Key
MainNode.i
SightNode.i
CameraNode.i
ForwardNode.i
StrafeNode.i
EndStructure
Structure s_Camera
Camera.i
Tightness.f
CameraNode.i
TargetNode.i
EndStructure
Macro GetNodePosition(Position, Node)
Position\x = NodeX(Node)
Position\y = NodeY(Node)
Position\z = NodeZ(Node)
EndMacro
Macro SubVector3(V, V1, V2)
V\x = V1\x - V2\x
V\y = V1\y - V2\y
V\z = V1\z - V2\z
EndMacro
;-Declare
Declare HandleEntity(*Entity.s_Entity)
Declare CameraTrack(*Camera.s_Camera, *Entity.s_Entity)
Declare OnGround(*Entity.s_Entity)
Declare MakeColimacon(PX.f, PY.f, PZ.f, Length.i, Height.i, Width.i, Stair.i)
Declare MakeStair(PX.f, PY.f, PZ.f, Length.i, Height.i, Width.i, Stair.i)
Declare AddObjects()
Define Robot.s_Entity
Define Camera.s_Camera
If InitEngine3D()
InitSprite()
InitKeyboard()
InitMouse()
If Screen3DRequester()
KeyboardMode(#PB_Keyboard_International)
Add3DArchive("../Data/Textures" , #PB_3DArchive_FileSystem)
Add3DArchive("../Data/Models" , #PB_3DArchive_FileSystem)
Add3DArchive("../Data/Scripts" , #PB_3DArchive_FileSystem)
Add3DArchive("../Data/GUI" , #PB_3DArchive_FileSystem)
Add3DArchive("../Data/Packs/desert.zip", #PB_3DArchive_Zip)
Parse3DScripts()
WorldShadows(#PB_Shadow_Modulative, 500)
;Texture
CreateTexture(1, 256, 256)
StartDrawing(TextureOutput(1))
Box(0, 0, 256, 256, $002255)
DrawingMode(#PB_2DDrawing_Outlined)
Box(0, 0, 256, 256, $FFFFFF)
Box(10, 10, 236, 236, $FFFF)
StopDrawing()
;Material
CreateMaterial(0, LoadTexture(0, "r2skin.jpg"))
CreateMaterial(1, TextureID(1))
CreateMaterial(2, LoadTexture(2, "Dirt.jpg"))
CreateMaterial(3, LoadTexture(3, "Wood.jpg"))
GetScriptMaterial(4, "Scene/GroundBlend")
;Robot
LoadMesh (0, "robot.mesh")
CreateEntity (0, MeshID(0), #PB_Material_None);
AnimateEntity(0, "Stop")
;Robot Body
CreateEntity(1, MeshID(0), #PB_Material_None, 0, 26, 0)
HideEntity(1, 1)
;Ground
CreatePlane(2, 5000, 5000, 100, 100, 100, 100)
CreateEntity(2, MeshID(2), MaterialID(1), 0, 0, 0)
;Body
EntityPhysicBody(1, #PB_Entity_CapsuleBody, 1, 0, 0)
EntityPhysicBody(2, #PB_Entity_StaticBody)
;Add some statics and dynamics objects
CreateCube(3, 1)
AddObjects()
;Add some stairs
MakeColimacon(120, 0, 120, 130, 7, 48, 15)
MakeStair(360, 0, 220, 130, 11, 48, 15)
;-Light
CreateLight(0,RGB(155,155,155),700,500,0)
AmbientColor(RGB(85,85,85))
; Skybox
SkyBox("desert07.jpg")
;
With Robot
\Entity = 0
\EntityBody = 1
\BodyOffsetY = 43
\Key\Down = #PB_Key_Down
\Key\Left = #PB_Key_Left
\Key\Right = #PB_Key_Right
\Key\Up = #PB_Key_Up
\Key\StrafeLeft = #PB_Key_X
\Key\StrafeRight = #PB_Key_C
\Key\Jump = #PB_Key_Space
\MainNode = CreateNode(#PB_Any) ; Entity position
\SightNode = CreateNode(#PB_Any, 120, 20, 0) ; For cameraLookAt
\CameraNode = CreateNode(#PB_Any, -140, 100, 0) ; Camera position
\ForwardNode = CreateNode(#PB_Any, 1, 0, 0) ; Direction normalized
\StrafeNode = CreateNode(#PB_Any, 0, 0, -1) ; Direction normalized
AttachNodeObject(\MainNode, NodeID(\SightNode) , #PB_Node_Node)
AttachNodeObject(\MainNode, NodeID(\CameraNode) , #PB_Node_Node)
AttachNodeObject(\MainNode, NodeID(\ForwardNode), #PB_Node_Node)
AttachNodeObject(\MainNode, NodeID(\StrafeNode) , #PB_Node_Node)
AttachNodeObject(\MainNode, EntityID(\Entity) , #PB_Node_Entity)
EndWith
;-Camera
CreateCamera(0, 0, 0, 100, 100)
With Camera
\Camera = 0
\Tightness = 0.035
; Camera use 2 nodes
\CameraNode = CreateNode(#PB_Any, -3000, 700, 0) ; Camera position
\TargetNode = CreateNode(#PB_Any) ; For cameraLookAt
AttachNodeObject(\CameraNode, CameraID(\Camera), #PB_Node_Camera)
EndWith
;-Main loop
;
Repeat
Screen3DEvents()
If Engine3DFrameRate(#PB_Engine3D_Current)
Robot\elapsedTime = 40/Engine3DFrameRate(#PB_Engine3D_Current)
EndIf
HandleEntity(@Robot)
CameraTrack(@Camera, @Robot)
RenderWorld(50)
FlipBuffers()
Until KeyboardPushed(#PB_Key_Escape) Or Quit = 1
EndIf
Else
MessageRequester("Error", "The 3D Engine can't be initialized",0)
EndIf
End
Procedure OnGround(*Entity.s_Entity)
With *Entity
ProcedureReturn RayCollide(NodeX(\MainNode), NodeY(\MainNode)+3, NodeZ(\MainNode), NodeX(\MainNode), NodeY(\MainNode), NodeZ(\MainNode))
EndWith
EndProcedure
Procedure IsStair(*Entity.s_Entity)
Protected.f x, y, z
With *Entity
x = (NodeX(\ForwardNode) - NodeX(\MainNode))*30
y = (NodeY(\ForwardNode) - NodeY(\MainNode))*30
z = (NodeZ(\ForwardNode) - NodeZ(\MainNode))*30
;CreateLine3D(20, NodeX(\MainNode), NodeY(\MainNode)+20, NodeZ(\MainNode), $FFFF, NodeX(\MainNode)+V\x, NodeY(\MainNode)+V\y+20, NodeZ(\MainNode)+V\z, $FFFF)
Ray1 = RayCollide(NodeX(\MainNode), NodeY(\MainNode)+10, NodeZ(\MainNode), NodeX(\MainNode)+x, NodeY(\MainNode)+y+10, NodeZ(\MainNode)+z)
Ray2 = RayCollide(NodeX(\MainNode), NodeY(\MainNode)+20, NodeZ(\MainNode), NodeX(\MainNode)+x, NodeY(\MainNode)+y+20, NodeZ(\MainNode)+z)
If Ray1 And Ray2=0
ProcedureReturn 1
EndIf
ProcedureReturn 0
EndWith
EndProcedure
Procedure HandleEntity(*Entity.s_Entity)
Protected.Vector3 Forward, Strafe, PosMain, PosDir, PosStrafe
Protected.f Speed, Speed2, x, y, MouseX, MouseY, Action.s
Static Jump.f, MemJump.i, Rot.Vector3, Trans.Vector3, Clic, LastAction.s
With *Entity
GetNodePosition(PosMain, \MainNode)
GetNodePosition(PosDir, \ForwardNode)
GetNodePosition(PosStrafe, \StrafeNode)
SubVector3(Forward, PosDir, PosMain)
SubVector3(Strafe, PosStrafe, PosMain)
Speed = #PlayerSpeed * \elapsedTime
Speed2 = Speed / 2
If ExamineKeyboard()
If KeyboardReleased(#PB_Key_F5)
WorldDebug(#PB_World_DebugBody)
ElseIf KeyboardReleased(#PB_Key_F6)
WorldDebug(#PB_World_DebugEntity)
ElseIf KeyboardReleased(#PB_Key_F7)
WorldDebug(#PB_World_DebugNone)
EndIf
If KeyboardPushed(\Key\Jump) And OnGround(*Entity)
Jump = 4
MemJump = 1
EndIf
Rot\x * 0.30
Rot\y * 0.30
Rot\z * 0.30
Trans\x * 0.20
Trans\y = Jump
Trans\z * 0.20
Action = "Stop"
If KeyboardPushed(\Key\Up)
Trans\x + Forward\x * Speed
Trans\z + Forward\z * Speed
Action = "Walk"
ElseIf KeyboardPushed(\Key\Down)
Trans\x + Forward\x * -Speed2
Trans\z + Forward\z * -Speed2
Action = "Walk"
EndIf
If KeyboardPushed(\Key\Left)
Rot\y + 2 * \elapsedTime
ElseIf KeyboardPushed(\Key\Right)
Rot\y - 2 * \elapsedTime
EndIf
If KeyboardPushed(\Key\StrafeLeft)
Trans\x + Strafe\x * Speed2
Trans\z + Strafe\z * Speed2
Action = "Walk"
ElseIf KeyboardPushed(\Key\StrafeRight)
Trans\x + Strafe\x * -Speed2
Trans\z + Strafe\z * -Speed2
Action = "Walk"
EndIf
If Action <> LastAction
LastAction = Action
AnimateEntity(0, Action)
EndIf
If OnGround(*Entity)
Jump = 0
ElseIf MemJump
Jump + 20
If Jump > 80
MemJump = 0
EndIf
Else
Jump - 9
EndIf
If IsStair(*Entity) And Jump = 0 And ( Abs(Trans\x)>=Speed / 2 Or Abs(Trans\z)>=Speed / 2)
Jump = 22 ; Or more
EndIf
EndIf
MoveEntity (\EntityBody, Trans\x, Trans\y, Trans\z)
RotateEntity(\EntityBody, 0, Rot\y, 0, #PB_Relative)
NodeLocate(\MainNode, EntityX(\EntityBody), EntityY(\EntityBody)-\BodyOffsetY, EntityZ(\EntityBody))
RotateNode(\MainNode, 0, EntityYaw(\EntityBody), 0)
EndWith
EndProcedure
Procedure CameraTrack(*Camera.s_Camera, *Entity.s_Entity)
Protected CameraPosition.Vector3, TargetPosition.Vector3, Temp.Vector3
Protected V1.Vector3, V2.Vector3, x.f, y.f, z.f
GetNodePosition(CameraPosition, *Entity\CameraNode)
GetNodePosition(TargetPosition, *Entity\SightNode)
x = NodeX(*Camera\CameraNode)
y = NodeY(*Camera\CameraNode)
z = NodeZ(*Camera\CameraNode)
x = (CameraPosition\x - x) * *Camera\Tightness
y = (CameraPosition\y - y) * *Camera\Tightness
z = (CameraPosition\z - z) * *Camera\Tightness
MoveNode(*Camera\CameraNode, x, y, z)
x = NodeX(*Camera\TargetNode)
y = NodeY(*Camera\TargetNode)
z = NodeZ(*Camera\TargetNode)
x = (TargetPosition\x - x) * *Camera\Tightness
y = (TargetPosition\y - y) * *Camera\Tightness
z = (TargetPosition\z - z) * *Camera\Tightness
MoveNode(*Camera\TargetNode, x, y, z)
CameraLookAt(*Camera\Camera, NodeX(*Camera\TargetNode), NodeY(*Camera\TargetNode), NodeZ(*Camera\TargetNode))
EndProcedure
Procedure MakeColimacon(PX.f, PY.f, PZ.f, Length.i, Height.i, Width.i, Stair.i)
Protected.f Angle
Protected.i a, Ent
For a = 1 To Stair
Ent = CreateEntity(#PB_Any, MeshID(3), MaterialID(2))
ScaleEntity(Ent, Length, Height, Width)
EntityLocate(Ent, PX + Cos(Radian(Angle)) * Width * 5, PY + (a-1) * Height * 4, PZ -Sin(Radian(Angle)) * Width * 5)
RotateEntity(Ent, 0, Angle, 0)
EntityPhysicBody(Ent, #PB_Entity_StaticBody)
Angle = Mod(Angle + 30, 360)
Next
EndProcedure
Procedure MakeStair(PX.f, PY.f, PZ.f, Length.i, Height.i, Width.i, Stair.i)
Protected.i a, Ent, Nb
Protected.f Size, Delta, H
For a = 1 To Stair
Ent = CreateEntity(#PB_Any, MeshID(3), MaterialID(2))
ScaleEntity(Ent, Length, Height, Width)
EntityLocate(Ent, PX, PY + (a-1) * Height, PZ + (a-1) * Width * 0.8)
EntityPhysicBody(Ent, #PB_Entity_StaticBody)
Next a
;Add a plateform
Ent = CreateEntity(#PB_Any, MeshID(3), MaterialID(2))
ScaleEntity(Ent, Length*5, Height, Width*5)
EntityLocate(Ent, PX, PY + (a-1) * Height, PZ + (a-1) * Width)
EntityPhysicBody(Ent, #PB_Entity_StaticBody)
;Add Pyramid
Nb = 7
Delta = 0.01
Size = 20
H = EntityY(Ent) + Height/2
For j = 0 To Nb
For i= 0 To Nb-j
Ent = CreateEntity(#PB_Any, MeshID(3), MaterialID(4))
ScaleEntity(Ent, Size, Size, Size)
EntityPhysicBody(Ent, #PB_Entity_BoxBody, 0.5)
EntityLocate(Ent, 340 + j * ((Size) / 2) + i * Size, H + ((Size) / 2) + (j * (Size)), 890)
Next
Next
EndProcedure
Procedure AddObjects()
Protected Size.Vector3
Protected.f x, z
Protected.i Ent, i
For i = 0 To 100
If Random(1)
Size\x = Random(60) + 30
Size\y = Random(60) + 30
Size\z = Random(60) + 30
Volume.f = Size\x * Size\y * Size\z
Ent=CreateEntity(#PB_Any, MeshID(3), MaterialID(3), Random(5000)-2600, 100, Random(5000)-2500)
RotateEntity(Ent, 0, Random(360), 0)
ScaleEntity(ent, Size\x, Size\y, Size\z)
EntityPhysicBody(Ent, #PB_Entity_BoxBody, (Volume / 7000), 0, 2)
Else
Size\x = Random( 60) + 30
Size\y = Random(160) + 30
Size\z = Random( 60) + 30
Repeat
x = Random(5000)-2500
Until x < -400 Or x > 400
Repeat
z = Random(5000)-2500
Until z < -400 Or z > 400
Ent=CreateEntity(#PB_Any, MeshID(3), MaterialID(2), x, Size\y/2 + Random(90) , z)
RotateEntity(Ent, 0, Random(360), 0)
ScaleEntity(Ent, Size\x, Size\y, Size\z)
EntityPhysicBody(Ent, #PB_Entity_StaticBody)
EndIf
Next
EndProcedure