I don't have time to correct your code but here is code for my own game with a ball that can bounce properly off surfaces, and is afftected by gravity and air friction. I haven't incldued the include files, but the physics code is all there, so you can just copy that and modify it to suit your needs.
Include "..\functions\scancodes.bb"
Include "..\shadow system\Swift Shadow System - 053.bb"
Include "..\particle system\Swift_Particle_System-036.bb"
Include "..\functions\mesh_optimizer.bb"
Include "..\functions\media.bb"
Include "..\functions\level-tiled.bb"
Include "..\functions\calculate_normals.bb"
Include "..\functions\removetagfromstring.bb"
Include "..\functions\cel_shade.bb"
Include "..\functions\fstr-float2string.bb"
Include "..\functions\addmeshtosurface.bb"
Include "..\functions\savescreenshot.bb"
Include "..\functions\createquad.bb"
Include "tag_system-002.bb"
Global info1$="Boing!"
Global info2$=""
Global info3$=""
Global info4$="Press TAB in game for instructions."
Include "start.bb"
; -------------------------------------------------------------------------------------------------------------------
.Constants
Const SHAREWARE = False
Const FPS=72
Const GRAVITY# = 9.8*2
Const AIR_FRICTION_CONSTANT# = 0.1 ; 0.2
Const GROUND_FRICTION_CONSTANT# = 0.5 ;3.0
; This is the number of times to run the physics each frame.
; Increasing this value will make the physics more stable... ie, when you're in a corner you won't bounce all
; over the place... you'll just sit against it properly.
Const PHYSICS_DIVIDER = 4
Const X = 0
Const Y = 1
Const Z = 2
Const XYZ = 3
Const R = 0
Const G = 1
Const B = 2
Const RGB = 3
Const TEX_COLOR = 1
Const TEX_ALPHA = 2
Const TEX_MASK = 4
Const TEX_MIPMAP = 8
Const TEX_UCLAMP = 16
Const TEX_VCLAMP = 32
Const TEX_UVCLAMP = TEX_UCLAMP + TEX_VCLAMP
Const LEVEL_WIDTH = 64
Const LEVEL_HEIGHT = 64
Const COLLIDE_GameGrid = 1
Const COLLIDE_Level = 2
Const COLLIDE_Ball = 3
Const BALL_START_HEIGHT# = 0.25
; Font stuff:
; Maximum number of fonts the game can utilize.
Const MAX_FONTS = 4
; Spacing distance between the characters, assuming character width of 1.0
Const FONT3D_KERNING# = 0.25
; -------------------------------------------------------------------------------------------------------------------
.Types
;Type Actor
; Field Mesh
; Field Velocity#[XYZ]
; Field Collision_Radius#
; Field Health
;End Type
Type Player
Field Name$
Field Avatar
Field Input_Up
Field Input_Down
Field Input_Left
Field Input_Right
Field Input_Fire1
Field Input_Fire2
Field Score
End Type
; -------------------------------------------------------------------------------------------------------------------
.Variables
Show_Debug_Data = 1 ; Defines whether to show the FPS and other information such as the current number of polygons in the world. 0 = no data, 1 = fps only, 2 = all data
; These are the default keyboard definitions.
KEY_Up = KEY_UPARROW
KEY_Down = KEY_DOWNARROW
KEY_Left = KEY_LEFTARROW
KEY_Right = KEY_RIGHTARROW
KEY_Fire1 = KEY_LEFTCTRL
KEY_ToggleDebugData = KEY_TAB
KEY_ExitGame = KEY_ESC
KEY_Screenshot = KEY_F8
KEY_NextBlock = KEY_PGDN
KEY_PreviousBlock = KEY_PGUP
KEY_EditSavelevel = KEY_S
KEY_EditLoadlevel = KEY_L
KEY_EditResetLevel = KEY_R
KEY_ResetBall = KEY_ENTER
KEY_ToggleShadows = KEY_F5
KEY_RecalculateLevelNormals = KEY_F4
KEY_ToggleMotionBlur = KEY_SPACE
Dim Cam(TOTAL_CAMERAS) ; This is a list of entity handles for all the cameras in the world.
Camera_Active = 0 ; This is the currently active camera's entity handle.
Camera_Target = 0 ; This is the object which the currently active camera should point at.
; These are all the valid characters which are in the game's fonts. Space MUST be last, because it does not actually have a mesh file associated with it.
Global CHARACTER_SET$ = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!?.()[]/\:,'+-@" + Chr$(34) + Chr$(32)
Global Fonts_Loaded = 0 ; Dunno why you'd ever need to know this in the game, but here it is.
Dim Font_Mesh(MAX_FONTS, 128) ; This is the mesh for each ascii character in the fonts. Only the lower 128 ascii characters are supported.
Dim Font_Mesh_Width#(MAX_FONTS, 128) ; This is one half the width of each character in the font.
Player_Thrust# = 16.0
Player_Friction_Stick_Time = 100 ; This is the amount of time (in milliseconds) which the player will be considered to be sticking to the level after it initally collides with it. This is to avoid issues where tiny bounces of the non-deforming ball constantly bring it into and out of contact with the ground every other frame or two. A real ball would stay in contact with the ground when rolling because it deforms when touching the ground.
; A more realistic physics system would define an amount which the ball deforms when it hits, and thus how much energy it stores and returns when it rebounds, as well as how long it stays in contact with the ground when doing so. A harder hit or greater gravity would mean more stick.
Edit_Mode = False ; Edit mode is off by default.
; Stuff for generating the shadows:
;Global ShadowTris = 0
; -------------------------------------------------------------------------------------------------------------------
.Main
Gosub Initialize_Game
Frame_Period = Ceil(1000.0/Float(FPS))
Time_Now = MilliSecs()
Repeat
; Update the game's timer.
Time_Old = Time_Now ; Save the time at which the last frame began.
; Repeat until the time since the last frame is greater than the minimum time allowed between frames.
; This is how we limit the framerate to 60fps or less to keep the game smooth.
Repeat
Time_Now = MilliSecs()
Time_Delta = Time_Now - Time_Old
Until Time_Delta >= Frame_Period
; Calculate the time the last frame took, in fractions of a second, and divide by
; the number of times we run the physics each frame.
Time_Delta_Sec# = (Float(Time_Delta) / 1000.0) / Float(PHYSICS_DIVIDER)
Gosub Gather_Input ; Gather input from all sources, keyboard, joystick, net, etc.
; Do physics several times per frame to make them smoother.
For Loop_Physics = 1 To PHYSICS_DIVIDER
Gosub Animate_World ; Move entities, perform AI, etc.
UpdateWorld ; Check for collisions.
Next
SPS_Update(Time_Delta) ; Update the particles.
Update_Shadows(Camera_Active) ; Update the shadows.
RenderWorld ; Render 3D scene.
Gosub Render_2D_Overlay ; Render 2D graphics over finished 3D scene.
Flip ; Swap the front and back buffers.
Until KeyHit(1)
End
; -------------------------------------------------------------------------------------------------------------------
; This subroutime initializes the game.
; -------------------------------------------------------------------------------------------------------------------
.Initialize_Game
; Turn off hardware multitexturing because it causes problems on some systems.
HWMultiTex False
WBuffer True
; Show the pointer when the mouse is over the game window. Only works in windowed mode.
ShowPointer
; Set ambient light level.
Shadow_Ambient_Light_R = 35*3
Shadow_Ambient_Light_G = 35*3
Shadow_Ambient_Light_B = 40*3
AmbientLight Shadow_Ambient_Light_R, Shadow_Ambient_Light_G, Shadow_Ambient_Light_B
LIGHT_Sun_Down = CreateLight(1)
LightColor LIGHT_Sun_Down, 250, 250, 220
RotateEntity LIGHT_Sun_Down, 90, 0, 0
LIGHT_Sun_Left = CreateLight(1)
LightColor LIGHT_Sun_Left, 50, 50, 44
RotateEntity LIGHT_Sun_Left, 0, 90, 0
LIGHT_Shadow = CreateLight(1)
LightColor LIGHT_Shadow, -23, -23, -23
RotateEntity LIGHT_Shadow, -90, 0, 0
; Specify the lights which cast shadows, and set their range.
FakeLight = CreatePivot()
PositionEntity FakeLight, 0, 10000, 0, True
Cast_Light(FakeLight, 200000)
; Create the primary local player.
Local_Player.Player = New Player
Gosub Initialize_Cameras
Gosub Load_Media
Gosub Initialize_Particle_System
; Set up collision between the level and the ball:
EntityRadius ballpos, BallRadius#
EntityType ballpos, COLLIDE_Ball
Collisions COLLIDE_Ball, COLLIDE_Level, 2, 2
; Load and construct the level:
Load_Level(255, False)
Receive_Shadow(Level_Avatar)
;Cel_Shade(Level_Avatar)
Return
; -------------------------------------------------------------------------------------------------------------------
; This subroutine loads and/or creates all objects and textures required to play the game.
; -------------------------------------------------------------------------------------------------------------------
.Load_Media
Load_Textures()
Load_Brushes()
Load_Meshes()
Load_Blocks()
;Font3D_Load(1)
; Create a plane for the level editor to use to determine which coordinates the mouse is pointing at.
; Make the plane invisible by adjusting the alpha rather than hiding it so that collision still works on it.
MESH_GameGrid = CreateQuad(0, 0, LEVEL_HEIGHT, 0, 0, LEVEL_WIDTH, 0, LEVEL_HEIGHT, 1, 0, LEVEL_WIDTH, 0, 0, 1, 1, 0, 0, 0, 0, 1)
EntityType MESH_GameGrid, COLLIDE_GameGrid
EntityPickMode MESH_GameGrid, 2
EntityAlpha MESH_GameGrid, 0
PositionEntity MESH_GameGrid, 0, 0.5, 0
TEX_Edit_Cube = LoadTexture("gfx\tex-009.bmp")
MESH_Edit_Cube = CreateCube()
ScaleEntity MESH_Edit_Cube, 0.6, 0.6, 0.6
EntityTexture MESH_Edit_Cube, TEX_Edit_Cube
EntityAlpha MESH_Edit_Cube, 0.75
EntityBlend MESH_Edit_Cube, 3
;EntityFX MESH_Edit_Cube, 16
; Create the editing grid and cursor cube:
MESH_Edit_Cube2 = CreateCube()
ScaleEntity MESH_Edit_Cube2, 0.56, 0.56, 0.56
EntityColor MESH_Edit_Cube2, 0, 0, 0
EntityAlpha MESH_Edit_Cube2, 0.25
EntityBlend MESH_Edit_Cube2, 1
EntityParent MESH_Edit_Cube2, MESH_Edit_Cube
EntityFX MESH_Edit_Cube2, 16
MESH_Grid = CreateQuad(0, 0, LEVEL_HEIGHT, 0, 0, LEVEL_WIDTH, 0, LEVEL_HEIGHT, LEVEL_WIDTH, 0, LEVEL_WIDTH, 0, 0, LEVEL_WIDTH, LEVEL_HEIGHT, 0, 0, 0, 0, LEVEL_HEIGHT)
PositionEntity MESH_Grid, 0, -0.025, 0
TEX_Edit_Grid = TEX_Edit_Cube
EntityTexture MESH_Grid, TEX_Edit_Grid
EntityFX MESH_Grid, 1+8
EntityAlpha MESH_Grid, 0.5
EntityBlend MESH_Grid, 3
; If edit mode is off by default, hide the editing entities initially.
If Edit_Mode = False
HideEntity MESH_Edit_Cube
HideEntity MESH_Grid
EndIf
; Set up the ball:
BallRadius# = 0.25
ballpos=CreatePivot()
ball=CreateSphere(16,ballpos)
ScaleMesh ball,BallRadius#,BallRadius#,BallRadius#
Local_Player\Avatar = ballpos
Camera_Target = Local_Player\Avatar
TARGET_CameraPivot = CreatePivot()
EntityParent TARGET_CameraPivot, Local_Player\Avatar
TranslateEntity TARGET_CameraPivot, 0, 0, -4
PositionEntity ballpos, 0.5, BALL_START_HEIGHT#, 0.5
TEX_Ball = LoadTexture("gfx\sphere.bmp")
;TEX_Ball = LoadTexture("tex-035.bmp")
;TEX_Ball = LoadTexture("cell-001.tga", 1+2+8+64)
EntityTexture ball,TEX_Ball
; Set the ball's initial location for the code which rotates the ball only when it's actually moving.
NewX# = EntityX#(ballpos, True)
NewY# = EntityY#(ballpos, True)
NewZ# = EntityZ#(ballpos, True)
; Set up the ball's shadow:
TEX_Ball_Shadow = LoadTexture("gfx\tex-020.bmp", TEX_UVCLAMP)
TextureBlend TEX_Ball_Shadow, 3
; Create a mesh for the shadow. We delete it each frame before creating a new one. This prevents a crash.
;MESH_Shadow = CreateMesh()
;Cast_Shadow(ball)
Cast_Textured_Shadow(ball, TEX_Ball_Shadow)
;Cel_Shade(ball)
; Set up the backdrop:
; MESH_Backdrop = CreateSprite2(Camera_Active)
; Center the sprite in the screen.
; Sprite2D MESH_Backdrop,320,240,1
; Scale the sprite to fill the screen.
; ScaleSprite2 MESH_Backdrop, 640, 480
; Draw background behind everything else.
; EntityOrder MESH_Backdrop,1
; Set up the sky:
; MESH_Sky = MESH_Backdrop
; TEX_Sky = LoadTexture("flatsky03.bmp")
; EntityTexture MESH_Sky, TEX_Sky
; EntityFX MESH_Sky, 1+8
Return
; -------------------------------------------------------------------------------------------------------------------
; This subroutine gathers local and remote user input.
; -------------------------------------------------------------------------------------------------------------------
.Gather_Input
; Check for non-gameplay related local input which we can deal with immediately.
; Take a screenshot.
If KeyHit(KEY_Screenshot)
SaveScreenshot()
EndIf
; Toggle through various styles of displaying debug data
If KeyHit(KEY_ToggleDebugData)
Show_Debug_Data = Show_Debug_Data + 1
If (Show_Debug_Data > 3) Then Show_Debug_Data = 0
If (Show_Debug_Data = 2)
ShowEntity MESH_Grid
;EntityAlpha MESH_Grid, 1
ShowEntity MESH_Edit_Cube
;EntityAlpha MESH_Edit_Cube, 1
Edit_Mode = True
Else
;EntityAlpha MESH_Grid, 0
HideEntity MESH_Grid
;EntityAlpha MESH_Edit_Cube, 0
HideEntity MESH_Edit_Cube
Edit_Mode = False
EndIf
EndIf
;Toggle the polygons which are shadowed beign visible or not.
If KeyHit(KEY_ToggleShadows)
Shadow_Mode = (Shadow_Mode+1) Mod 3
EndIf
; Toggle motion blur on the ball.
If KeyHit(KEY_ToggleMotionBlur)
; If motion blur has not already been applied,
If Motion_Blur = False
; Activate motion blur.
SPS_CREATE_EMITTER(BallEmitter.EmitterBrush, ballpos)
Motion_Blur = True
EndIf
; Increase the ball's velocity.
Velocity# = Sqr(Vx#^2 + Vy#^2 + Vz#^2)
If Velocity# > 0
; Calculate the direction vector. The direction vector is a normal and has a length of 1.
Direction_X# = Vx# / Velocity#
Direction_Y# = Vy# / Velocity#
Direction_Z# = Vz# / Velocity#
; Set the ball's velocity to a specific amount.
Velocity# = 20
Vx# = Direction_X# * Velocity#
Vy# = Direction_Y# * Velocity#
Vz# = Direction_Z# * Velocity#
EndIf
EndIf
; If the game is currently in edit mode...
If Edit_Mode
; Check to see which tile the mouse is pointing at.
Temp = CameraPick(Camera_Active, MouseX(), MouseY())
Picked_X# = PickedX#()
Picked_Y# = PickedY#()
Picked_Z# = PickedZ#()
Grid_Picked_X = Floor(Picked_X#)
Grid_Picked_Y = Floor(Picked_Y#)
Grid_Picked_Z = Floor(Picked_Z#)
PositionEntity MESH_Edit_Cube, Grid_Picked_X+0.5, Grid_Picked_Y+0.5, Grid_Picked_Z+0.5
; Switch the current block for drawing.
If KeyHit(KEY_NextBlock)
Current_Drawing_Block = Current_Drawing_Block+1
If Current_Drawing_Block >= Blocks_Loaded Then Current_Drawing_Block = 0
EndIf
If KeyHit(KEY_PreviousBlock)
Current_Drawing_Block = Current_Drawing_Block-1
If Current_Drawing_Block < 0 Then Current_Drawing_Block = Blocks_Loaded-1
EndIf
; Draw with the current drawing block and update the level if the left mouse button is pressed.
If MouseDown(1)
If (Grid_Picked_X >= 0) And (Grid_Picked_X < LEVEL_WIDTH) And (Grid_Picked_Y >= 0) And (Grid_Picked_Y < LEVEL_HEIGHT)
; If the block below the current location is diffrent than the block we want to draw with...
If Level_Block(Grid_Picked_X, Grid_Picked_Z) <> Current_Drawing_Block
; Replace the block with the new block and reconstruct the level.
Level_Block(Grid_Picked_X, Grid_Picked_Z) = Current_Drawing_Block
ResetEntity Level_Avatar
FreeEntity Level_Avatar
Construct_Level()
; The level has changed so reset the save check.
Level_Save_Sucess = False
EndIf
EndIf
EndIf
; Grab the block below the cursor if the right mouse button is pressed.
If MouseDown(2)
If (Grid_Picked_X >= 0) And (Grid_Picked_X < LEVEL_WIDTH) And (Grid_Picked_Y >= 0) And (Grid_Picked_Y < LEVEL_HEIGHT)
Current_Drawing_Block = Level_Block(Grid_Picked_X, Grid_Picked_Z)
EndIf
EndIf
; Save the level.
If KeyHit(KEY_EditSavelevel)
Level_Save_Sucess = Save_Level()
EndIf
; Load the last edited level.
If KeyHit(KEY_EditLoadlevel)
Load_Sucessful = Load_Level(255)
ResetEntity Level_Avatar
FreeEntity Level_Avatar
Level_Avatar = Construct_Level()
; The level has changed so reset the save check.
Level_Save_Sucess = False
EndIf
; Reset the level.
If KeyHit(KEY_EditResetLevel)
ResetEntity Level_Avatar
FreeEntity Level_Avatar
For LoopZ = 0 To LEVEL_WIDTH-1
For LoopX = 0 To LEVEL_HEIGHT-1
Level_Block(LoopX, LoopZ) = 0
Next
Next
Level_Avatar = Construct_Level()
; The level has changed so reset the save check.
Level_Save_Sucess = False
EndIf
EndIf
; Reset the ball back to it's original location.
If (KeyHit(KEY_ResetBall) = True) Or (EntityY#(ballpos) < -5)
; Rset the ball's collisions so it will move to w
ResetEntity ballpos
; PositionEntity ballpos, 0.5, BallRadius#+0.01, 0.5
PositionEntity ballpos, 0.5, BALL_START_HEIGHT#, 0.5
EntityRadius ballpos, BallRadius#
EntityType ballpos, COLLIDE_Ball
Discard = EntityCollided(ballpos, COLLIDE_Level)
Vx# = 0
Vy# = 0
Vz# = 0
Vr# = 0
; Delete all particles and emitters in the world.
SPS_OFF()
EndIf
Thrust_Z# = 0
If KeyDown(208)=True Then Thrust_Z# = -Player_Thrust#
If KeyDown(200)=True Then Thrust_Z# = Player_Thrust#
Thrust_X# = 0
If KeyDown(203)=True Then Thrust_X# = -Player_Thrust#
If KeyDown(205)=True Then Thrust_X# = Player_Thrust#
; Check for local gameplay input which we will deal with later.
; Local_Player\Input_Up = KeyDown(KEY_Up)
; Local_Player\Input_Down = KeyDown(KEY_Down)
; Local_Player\Input_Left = KeyDown(KEY_Left)
; Local_Player\Input_Right = KeyDown(KEY_Right)
; Local_Player\Input_Fire1 = KeyDown(KEY_Fire1)
; If MouseDown(1)
; BallRadius# = BallRadius# + 0.5
; PositionEntity ballpos,EntityX(ballpos),BallRadius#,EntityZ(ballpos)
; ScaleEntity ball,BallRadius#,BallRadius#,BallRadius#
; EndIf
; If MouseDown(2)
; BallRadius# = BallRadius# - 0.5
; If (BallRadius# < 1.0) Then BallRadius# = 1.0
; PositionEntity ballpos,EntityX(ballpos),BallRadius#,EntityZ(ballpos)
; ScaleEntity ball,BallRadius#,BallRadius#,BallRadius#
; EndIf
Return
; -------------------------------------------------------------------------------------------------------------------
; This subroutine parses local and remote user input and modifys certain variables accordingly.
; -------------------------------------------------------------------------------------------------------------------
.Parse_Input
Return
; -------------------------------------------------------------------------------------------------------------------
; This subroutine animates everything in the world according to the rules of the game and the given input.
; -------------------------------------------------------------------------------------------------------------------
.Animate_World
Gosub Animate_Sphere
Gosub Animate_Cameras
; Lock sky to camera.
;PositionEntity MESH_Sky, EntityX#(Camera_Active), EntityY#(Camera_Active), EntityZ#(Camera_Active)
Return
; -------------------------------------------------------------------------------------------------------------------
; This subroutine animates the sphere.
; -------------------------------------------------------------------------------------------------------------------
.Animate_Sphere
; Check to see if the entity collided with the level last frame.
Entity_Hit = EntityCollided(ballpos, COLLIDE_Level)
; If the entity collided with the level, then store the time of the last collision.
If Entity_Hit Then Last_Collide_Time = Time_Now
; Calculate motion friction:
; Calculate the entity's current velocity.
Velocity# = Sqr(Vx#^2 + Vy#^2 + Vz#^2)
; If the entity is not traveling fast enough to be motion blurred:
If Velocity# < 6.0
; If motion blur is on, turn it off:
If Motion_Blur = True
SPS_DELETE_CHILD_EMITTERS(ballpos)
Motion_Blur = False
EndIf
EndIf
; If the entity is moving, adjust it's velocity:
If Velocity# > 0
; Calculate the direction vector.
; The direction vector has a length of 1.
Direction_X# = Vx# / Velocity#
Direction_Y# = Vy# / Velocity#
Direction_Z# = Vz# / Velocity#
; Compute air friction.
; Air friction is dependent on the speed of the entity, and will prevent it from accelerting forever.
Air_Friction_Force# = AIR_FRICTION_CONSTANT# * Velocity#^2.0
Velocity# = Velocity# - (Air_Friction_Force# * Time_Delta_Sec#)
; If the entity is colliding with the level this frame, or still sticking to the level from it's last
; collision, then apply ground friction.
If (Time_Now - Last_Collide_Time) <= Player_Friction_Stick_Time
; Compute ground friction. Ground friction is not dependent on the speed of the entity.
Velocity# = Velocity# - (GROUND_FRICTION_CONSTANT# * Time_Delta_Sec#)
EndIf
; Make sure the entity's velocity doesn't go below 0.
; It is impossible to have a negative velocity in physics and "bad things" happen if you try to.
If (Velocity# < 0) Then Velocity# = 0
; Convert the entity's velocity and direction back into a motion vector.
Vx# = Direction_X# * Velocity#
Vy# = Direction_Y# * Velocity#
Vz# = Direction_Z# * Velocity#
; If the entity collided with the level, make it bounce.
If Entity_Hit > 0
; Calculate bounce:
; Get the normal of the surface which the entity collided with.
Nx# = CollisionNX(ballpos, 1)
Ny# = CollisionNY(ballpos, 1)
Nz# = CollisionNZ(ballpos, 1)
; Multiply the entity's motion vector by the surface normal.
; This gives us the part of the vector which points in the same direction as the surface the object collided with.
Elasticity# = 0.5
Vx# = Vx# - Vx#*Abs(Nx#)*(1.0 - Elasticity#)
Vy# = Vy# - Vy#*Abs(Ny#)*(1.0 - Elasticity#)
Vz# = Vz# - Vz#*Abs(Nz#)*(1.0 - Elasticity#)
; Compute the dot product of the entity's motion vector and the normal of the surface collided with.
VdotN# = Vx#*Nx# + Vy#*Ny# + Vz#*Nz#
; Calculate the normal force.
NFx# = -2.0 * Nx# * VdotN#
NFy# = -2.0 * Ny# * VdotN#
NFz# = -2.0 * Nz# * VdotN#
; Add the normal force to the direction vector.
Vx# = Vx# + NFx#
Vy# = Vy# + NFy#
Vz# = Vz# + NFz#
; Do not allow the entity to move vertically.
; If Vy# > 0 Then Vy# = 0
EndIf
EndIf
; Apply directional thrust:
; If the entity collided with the level, apply directional thrust.
;If Entity_Hit > 0
; Take thrust in object space, and translates it to an XYZ vector in world space.
;TFormVector 0, 0, Thrust#, ballpos, 0
; Add any thrust being applied this frame.
; There's a very good reason why this is done AFTER the friction is calculated.
; It involves inequalities in force cause by variable framerates.
Vx# = Vx# + (Thrust_X# * Time_Delta_Sec#)
Vz# = Vz# + (Thrust_Z# * Time_Delta_Sec#)
;EndIf
; Apply gravity:
Vy# = Vy# - (GRAVITY# * Time_Delta_Sec#)
; Move and rotate the entity:
; We rotate the entity by the actual distance moved and not by the velocity because if we rotate according
; to the velocity then the entity will roll when it's up against a wall and not moving.
OldX# = NewX#
OldZ# = NewZ#
TranslateEntity ballpos, Vx#*Time_Delta_Sec#, Vy#*Time_Delta_Sec#, Vz#*Time_Delta_Sec#, True
NewX# = EntityX#(ballpos, True)
NewZ# = EntityZ#(ballpos, True)
Mx# = (NewX# - OldX#)
Mz# = (NewZ# - OldZ#)
; Rotate the entity the right amount for it's radius and the distance it has moved along the X and Z axis.
; This is kinda a hack and only designed for rolling on planes but you won't notice the diffrence.
XAngleAdjust# = (Mx# / BallRadius#) * (180.0/Pi)
ZAngleAdjust# = (Mz# / BallRadius#) * (180.0/Pi)
TurnEntity ball,ZAngleAdjust#,0,-XAngleAdjust#,True
Return
; -------------------------------------------------------------------------------------------------------------------
; This subroutine animates the cameras.
; -------------------------------------------------------------------------------------------------------------------
.Animate_Cameras
; Point the active camera at the currently specified target.
;Px# = EntityX#(TARGET_CameraPivot, True)
;Py# = EntityY#(TARGET_CameraPivot, True)
;Pz# = EntityZ#(TARGET_CameraPivot, True)
;PositionEntity Camera_Active, Px#, 2, Pz#
PositionEntity Camera_Active, EntityX#(Camera_Target, True), 2, EntityZ#(Camera_Target, True) - 4
;PointEntity Camera_Active, Camera_Target
;RotateEntity Camera_Active, 0, EntityYaw#(Camera_Active), 0, True
Return
; -------------------------------------------------------------------------------------------------------------------
; This subroutine draws any 2D status information over the 3D scene after the 3D scene has been rendered.
; -------------------------------------------------------------------------------------------------------------------
.Render_2D_Overlay
Color 255, 255, 255
Select Show_Debug_Data
Case 1
If (Time_Delta > 0)
Frames_Per_Second = Int(Floor(1000.0/Float(Time_Delta)))
Text 0, 16*0, " FPS = " + Str$(Frames_Per_Second)
;If (FPS_Text > 0) Then FreeEntity FPS_Text
;FPS_Text = Font3D_Text(Str$(Frames_Per_Second), 1, 64, 1)
;RotateEntity FPS_Text, -90, 0, 0
;EntityParent FPS_Text, Camera_Active, 1
;Sprite2D(FPS_Text, 320, 60, 1)
EndIf
Case 2
Text 0, 16*1, " Polygons = " + Str$(TrisRendered())
Text 0, 16*2, " Camera Mode = " + Str$(CameraMode)
Text 0, 16*3, " Grid_X: " + Str$(Grid_Picked_X)
Text 0, 16*4, " Grid_Z: " + Str$(Grid_Picked_Z)
Text 0, 16*5, " Pick Block: " + Str$(Level_Block(Grid_Picked_X, Grid_Picked_Z))
Text 0, 16*6, " Draw Block: " + Str$(Current_Drawing_Block)
Text 0, 16*8, " F8 = Screenshot"
Text 0, 16*9, " S = Save level"
Text 0, 16*10, " L = Load level"
Text 0, 16*11, " R = Reset Level"
Text 0, 16*12, " PGUP/PGDN = Change block"
Text 0, 16*13, " LEFTMOUSE = Paste block"
Text 0, 16*14, " RIGHTMOUSE = Copy block"
If Level_Save_Sucess = True Then Text 0, 16*16, " Level Saved!"
;Text 0, 16*4, " Camera_Active Location = " + RSet$(FStr$(EntityX#(Camera_Active)), 8) + "," + RSet$(FStr$(EntityY#(Camera_Active)), 8) + "," + RSet$(FStr$(EntityZ#(Camera_Active)), 8)
;Text 0, 16*5, " Local_Player Location = " + RSet$(FStr$(EntityX#(Local_Player\Avatar)), 8) + "," + RSet$(FStr$(EntityY#(Local_Player\Avatar)), 8) + "," + RSet$(FStr$(EntityZ#(Local_Player\Avatar)), 8)
;Text 0, 16*7, " Local_Player Speed = " + RSet$(FStr$(Local_Player\Speed#), 8) + " m/s"
Case 3
Text 0, 16*1, " Vx = " + Str$(Vx#)
Text 0, 16*2, " Vy = " + Str$(Vy#)
Text 0, 16*3, " Vz = " + Str$(Vz#)
Text 0, 16*5, " Velocity = " + Str$(Velocity#)
Text 0, 16*6, " Rotational_Velocity = " + Str$(Rotational_Velocity#)
Text 0, 16*8, " Textures_Loaded = " + Str$(Textures_Loaded)
Text 0, 16*9, " Meshes_Loaded = " + Str$(Meshes_Loaded)
Text 0, 16*10, " Brushes_Loaded = " + Str$(Brushes_Loaded)
Text 0, 16*11, " Blocks_Loaded = " + Str$(Blocks_Loaded)
Text 0, 16*13, " Shadow polygons = " + Str$(Shadow_Poly_Count)
End Select
Return
; -------------------------------------------------------------------------------------------------------------------
; This subroutine sets up the cameras.
; -------------------------------------------------------------------------------------------------------------------
.Initialize_Cameras
Cam(0) = CreateCamera()
CameraRange Cam(0), 1.0, 1024.0
CameraZoom Cam(0), 1.0
CameraFogMode Cam(0), 0
;CameraFogRange Cam(0), 0, 127.0
;CameraFogColor Cam(0), 127, 255, 255
;CameraClsMode Cam(0), False, True
;Purple haze
;CameraFogColor Cam(0), 198, 200, 255
;Pink haze
;CameraFogColor Cam(0), 255, 217, 214
Camera_Active = Cam(0)
Camera_Target = Local_Player\Avatar
Return
; -------------------------------------------------------------------------------------------------------------------
; This subroutine frees up memory and shuts down stuff before exiting.
; -------------------------------------------------------------------------------------------------------------------
.Quit_Game
; Fade to black, shut down.
Exit_Game = True
Return
; -------------------------------------------------------------------------------------------------------------------
; This subroutine sets up the various kinds of particles we want to use and initializes certain variables in the
; particle system.
; -------------------------------------------------------------------------------------------------------------------
.Initialize_Particle_System
; Load and/or create the meshes used to represent the particles.
; Rememeber that any changes to these meshes at any time will affect ALL particles in the world which use
; them as their template, even particles which have already been created!
; This creates a small 1x1 plane mesh which we can use as a template and then hides it.
ParticleMesh = CreateQuad(0.5, 0.5, 0, 0, 0, -0.5, 0.5, 0, 1, 0, -0.5, -0.5, 0, 1, 1, 0.5, -0.5, 0, 0, 1)
HideEntity ParticleMesh
; Load the textures required for the particles:
;FireTexture = LoadAnimTexture("fire.bmp", TEX_Color + TEX_Mipmap + TEX_UVClamp, 64, 64, 0, 16)
;SmokeTexture = LoadAnimTexture("smoke.bmp", TEX_Color + TEX_Mipmap + TEX_UVClamp, 64, 64, 0, 16)
; Create the particle brushes.
; Particle brushes define how each type of particle behaves - how long it lives, if it changes size, etc.
BallParticle.ParticleBrush = New ParticleBrush
BallParticle\Speed_Min# = 0
BallParticle\Speed_Max# = 0
BallParticle\Heading_Min# = 0
BallParticle\Heading_Max# = 0
BallParticle\Inclination_Min# = 0
BallParticle\Inclination_Max# = 0
BallParticle\Wind_Min# = 0
BallParticle\Wind_Max# = 0
BallParticle\Gravity_Min# = 0
BallParticle\Gravity_Max# = 0
BallParticle\Lifespan_Min = 200
BallParticle\Lifespan_Max = 200
BallParticle\XRot_Speed_Min# = 0
BallParticle\YRot_Speed_Min# = 0
BallParticle\ZRot_Speed_Min# = 0
BallParticle\XRot_Speed_Max# = 0
BallParticle\YRot_Speed_Max# = 0
BallParticle\ZRot_Speed_Max# = 0
BallParticle\BrushMesh = ball
BallParticle\TextureHandle = TEX_Ball
BallParticle\TextureFrames = 1
BallParticle\Alpha_Start# = 0.5
BallParticle\Alpha_End# = 0.0
BallParticle\Scale_Start# = 0.98
BallParticle\Scale_End# = 0.98
BallParticle\FaceDirection = 0
BallParticle\Blend = 3
BallParticle\Shininess = 0
BallParticle\FX = 0
BallParticle\AutoFade_Near# = 1000
BallParticle\AutoFade_Far# = 1000
BallParticle\OnExpireSpawnEmitter = Null
; Create the emitter brushes.
; Emitter brushes define the properties of the emitters, including their lifespan and the kind and number of
; particles they emit.
; Create a smoke particle emitter which emits from a single point.
BallEmitter.EmitterBrush = New EmitterBrush
BallEmitter\Shape = 1
BallEmitter\OuterRadius# = 0
BallEmitter\InnerRadius# = 0
BallEmitter\EmissionRate = 35
BallEmitter\EmissionOdds = 100
BallEmitter\Lifespan = -1
BallEmitter\ParticleType = BallParticle
BallEmitter\RotateWithParent = 1
; Set the particle system's world scale and gravity to match the game.
SPS_Units_Per_Meter# = 1.0
SPS_Gravity# = GRAVITY#
; Tell the particle system which camera to point billboarded particles at.
;
; You can change this anytime you want if you want to change cameras. Just remmember the particle's won't point
; at the new camera until SPS_Update() is called.
SPS_CurrentCameraHandle = Cam(0)
Return
; -------------------------------------------------------------------------------------------------------------------
; fov is the same as your camerazoom.
; -------------------------------------------------------------------------------------------------------------------
Function Sprite2D(sprite,x#,y#,fov#)
PositionEntity sprite,2*(x-320),-2*(y-240),fov#*640
End Function
; -------------------------------------------------------------------------------------------------------------------
; scale sprite in screen pixels relative to a 640x480 res when used with Sprite2D
; -------------------------------------------------------------------------------------------------------------------
Function ScaleSprite2(sprite,x,y)
ScaleEntity sprite,x,y,1
End Function
; -------------------------------------------------------------------------------------------------------------------
; please pass camera to this function or 0 for a billboard type with mesh.
; -------------------------------------------------------------------------------------------------------------------
Function CreateSprite2(parent)
If parent<>0
m=CreateMesh(parent)
Else
m=CreateMesh()
EndIf
s=CreateSurface(m)
AddVertex s,-1,+1,-1,0,0:AddVertex s,+1,+1,-1,1,0
AddVertex s,+1,-1,-1,1,1:AddVertex s,-1,-1,-1,0,1
AddTriangle s,0,1,2:AddTriangle s,0,2,3
ScaleEntity m,100,100,1
Return m
End Function