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