' ________________________________________________________________________ ' TrueVision3D (web: http://www.truevision3d.com) ' ???????????????????????????????????? ' Tutorial 14 : Give a destination to a mesh ' ?????? ' Description : In this 14th tutorial, we will load a landscape, put five ' ?????? tanks on it and use the last "mouse picking" tutorials ' to be able to select a tank and give it a destination.
' Force explicit declarations Option Explicit
' We declare TVEngine. Private TV3D As TVEngine
' No so new : we declare the tank as an mesh8 object Private Tank(1 To 5) As TVMesh
' We declare the landscape Private Land As TVLandscape
' We declare the texture factory Private TextureFactory As TVTextureFactory
' We the declare the scene Private Scene As TVScene
' New : we have to declare the screen obect to be able to render 3d lines ' from 2 vectors in the world Private ScreenTV As TVScreen2DImmediate
' We declare the input engine. Private InputEngine As TVInputEngine
' We declare the collision object Private CollisionResult As TVCollisionResult
' The loop. Private DoLoop As Boolean
' We need a position for the tanks Private TankPosition(1 To 5) As D3DVECTOR
' New : we need a destination for the tanks Private TankDestination(1 To 5) As D3DVECTOR
' New : we need a direction for the tank to make them point in the ' right direction. Private TankDirection(1 To 5) As D3DVECTOR
' We need angles for the tanks Private TankAngleY(1 To 5) As Single
' We need a variable that will hold the index of the tank selected '保存当前所选择的坦克 Private intTankSelected As Integer
' We declare the WinApi function (MouseCursor) Private Declare Function GetCursorPos Lib "user32" (lpPoint As POINTAPI) As Long
Private Sub cmdQuit_Click()
' We have clicked on the "Quit" button, so we change the DoLoop. DoLoop = False
End Sub
Private Sub Form_Load()
' We have to create the TV3D object before anything else. Set TV3D = New TVEngine
' Set search directory of Textures, Objects, ... TV3D.SetSearchDirectory App.Path ' We initialize TV3D in the picture box of the form. TV3D.Init3DWindowedMode Picture1.hWnd
' We want to see the FPS. TV3D.DisplayFPS = True 'We set the anglesystem to degree TV3D.SetAngleSystem TV_ANGLE_DEGREE
' We create the input object. Set InputEngine = New TVInputEngine
' We create the screen object. Note that we can't use "Screen" as ' the name of our object because it's allready an object name ' reserved for VisualBasic and also the Windows API. Set ScreenTV = New TVScreen2DImmediate
' We create the scene (the world). Set Scene = New TVScene
' We set a mouse pointer Scene.LoadCursor "..\..\..\Media\pointer.bmp", TV_COLORKEY_BLACK, 16, 16
' We set background color. Scene.SetSceneBackGround 0, 0.3, 0.9
' We need to create a new texture factory Set TextureFactory = New TVTextureFactory
' The land generation Set Land = New TVLandscape ' Generate the height of the land from the grayscale of the image. Land.GenerateHugeTerrain "..\..\..\Media\Heightmaps\Track.jpg", TV_PRECISION_LOW, 8, 8, -700, -1024, True ' Then, we load the land texture. TextureFactory.LoadTexture "..\..\..\Media\sand.jpg", "LandTexture" ' Load the tank texture TextureFactory.LoadTexture "..\..\..\Media\tank.bmp", "TankTexture", , , TV_COLORKEY_NO ' We assign a texture to that land. Land.SetTexture GetTex("LandTexture") Dim i As Integer For i = 1 To 5 ' We ceate the tank Set Tank(i) = Scene.CreateMeshBuilder ' Now, load our model. Tank(i).Load3DSMesh "..\..\..\Media\tank.3ds", False ' We assign the texture Tank(i).SetTexture GetTex("TankTexture") ' Set the tank's vertex color to red ' Warning, don't call this too often, it creates a new material :) Tank(i).SetColor RGBA(1, 0, 0, 1) ' Let set the initial position of the tank TankPosition(i).x = (100 * i) - 300 TankPosition(i).z = 200 TankPosition(i).y = Land.GetHeight(TankPosition(i).x, TankPosition(i).z) + 10 Tank(i).SetPosition TankPosition(i).x, TankPosition(i).y, TankPosition(i).z Next i ' Lets select the tank(1) by default intTankSelected = 1 ' Set the tank's vertex color to green Tank(intTankSelected).SetColor RGBA(0, 1, 0, 1) ' We pop the form over everything else. Form1.Show ' We start the main loop. DoLoop = True Main_Loop
End Sub
Private Sub Form_Unload(Cancel As Integer)
' The user asked to quit but clicked on the 'X' button at up right. DoLoop = False ' And ask to quit. Main_Quit
End Sub
Private Sub Main_Loop()
' The main loop Do ' Let us the capacity to use buttons of the form. DoEvents ' We check the input Check_Input ' We check and update the movement Check_Movement
' We update the camera to point on the tank selected '将场景视角转向选择的坦克 Scene.SetCamera 0, 200, 0, TankPosition(intTankSelected).x, TankPosition(intTankSelected).y, TankPosition(intTankSelected).z
' Clear the the last frame. TV3D.Clear ' We render the landscape. Land.Render True ' Render the mesh Scene.RenderAllMeshes ' For each tank, we draw a line from the tank's position ' to the tank's destination. Note that you have to ' "begin" the 2d part calling the begin action of the screen class ' Yes, Line3D is in the 2D screen immediate :) it's easier to optimize ' for the engine this way. ScreenTV.ACTION_Begin2D Dim i As Integer For i = 1 To 5 '在屏幕上绘制3d线段 ScreenTV.DRAW_Line3D TankPosition(i).x, TankPosition(i).y, TankPosition(i).z, TankDestination(i).x, TankDestination(i).y, TankDestination(i).z, RGBA(0, 1, 0, 1), RGBA(0, 1, 0, 1) Next i ScreenTV.ACTION_End2D ' We display everything that we have rendered TV3D.RenderToScreen 'We loop all of this until the DoLoop isn't True. Loop Until DoLoop = False ' We ask to quit. Main_Quit
End Sub
Private Sub Check_Input() ' We position the TrueVision3D mouse under the Windows mouse cursor. ' You must do that if you want TV to uses the Windows cursor ' instead of the internal DirectInput cursor, that is not always ' synchronized with the windows one. Dim tmpWindowsMousePosition As POINTAPI GetCursorPos tmpWindowsMousePosition InputEngine.SetMousePosition tmpWindowsMousePosition.x - ((Form1.Left / 15) + 12), tmpWindowsMousePosition.y - ((Form1.Top / 15) + 30)
' Now, for the mouse input... Dim tmpMouseX As Long, tmpMouseY As Long Dim tmpMouseB1 As Integer, tmpMouseB2 As Integer
' Get the movement of the mouse. InputEngine.GetAbsMouseState tmpMouseX, tmpMouseY, tmpMouseB1, tmpMouseB2
' If we clicked on the mouse button1, we wanted to select a tank... ' 鼠标左键选择坦克 If tmpMouseB1 <> 0 Then '...check if the mouse pointer has collided with a Tank. Set CollisionResult = Scene.MousePicking(tmpMouseX, tmpMouseY, TV_COLLIDE_MESH, TV_TESTTYPE_BOUNDINGBOX) ' Check if we did have a collision with a tank If CollisionResult.IsCollision Then ' Yes, we did have a collision with a tank, but which one ' is it? We can know this by comparing the positions. Dim FoundTheTank As Boolean Dim i As Integer While Not FoundTheTank i = i + 1 If Tank(i).GetPosition.x = CollisionResult.GetCollisionMesh.GetPosition.x _ And Tank(i).GetPosition.z = CollisionResult.GetCollisionMesh.GetPosition.z Then intTankSelected = i ' Change the color of the tank selected Dim j As Integer For j = 1 To 5 Tank(j).SetColor RGBA(1, 0, 0, 1) Next j Tank(i).SetColor RGBA(0, 1, 0, 1) FoundTheTank = True End If Wend End If
End If
' If we clicked on the mouse button2, we wanted to give a destination ' to the selected tank. '按下鼠标右键,给定坦克的目标位置 If tmpMouseB2 <> 0 Then '...check if the mouse pointer has collided with a Tank. Set CollisionResult = Scene.MousePicking(tmpMouseX, tmpMouseY, TV_COLLIDE_LANDSCAPE, TV_TESTTYPE_ACCURATETESTING) ' Check if we did have a collision with the landscape If CollisionResult.IsCollision Then TankDestination(intTankSelected) = CollisionResult.GetImpactPoint ' Direction of the tank is the unit vector ' of the difference between end point and start point of the tank ' We use VNormalize to get a vector of length 1 (unit vector) '方向 TankDirection(intTankSelected) = VNormalize(VSubtract(TankDestination(intTankSelected), TankPosition(intTankSelected))) ' Update the tank's angle, according ot the direction ' it uses a useful 2D function that gets the angle from a direction. (on x and z) '角度 TankAngleY(intTankSelected) = Direction2Ang(TankDirection(intTankSelected).x, TankDirection(intTankSelected).z)
' Set the tank's mesh rotation '旋转 Tank(intTankSelected).SetRotation 0, TankAngleY(intTankSelected), 0 End If
End If
End Sub
Private Sub Check_Movement()
Dim i As Integer For i = 1 To 5 ' Check if tank has reached destination, if not, update the tank ' position by adding a scale of the vector destination. '检测坦克是否抵达目的地,如果没有,通过添加矢量值的方式来更新坦克的位置 If GetDistance3D(TankPosition(i).x, 0, TankPosition(i).z, TankDestination(i).x, 0, TankDestination(i).z) > 2 Then ' Update all the tank's position TankPosition(i) = VAdd(TankPosition(i), VScale(TankDirection(i), TV3D.TimeElapsed * 0.1)) TankPosition(i).y = Land.GetHeight(TankPosition(i).x, TankPosition(i).z) + 10 ' Update the tank's mesh position Tank(i).SetPosition TankPosition(i).x, TankPosition(i).y, TankPosition(i).z End If Next i End Sub
Private Sub Main_Quit() ' We want to quit the project, so we start by desroyng ' the texture factory. Set TextureFactory = Nothing ' We destroy the screen object Set ScreenTV = Nothing ' We destroy the tank object Set Tank(1) = Nothing Set Tank(2) = Nothing ' We destroy the land object. Set Land = Nothing ' Don't forget to destroy the inputengine object... Set InputEngine = Nothing ' Then, we destroy the scene object. Set Scene = Nothing ' We finish the frenetic destroy with the TV3D object. Set TV3D = Nothing ' We end the application. End
End Sub
|