Register  |  FAQ  |  Search  |  Memberlist  |  Usergroups  |  Log in 
Reply to topic
 A Simple FPS Game 
Vincent


Joined: 25 Dec 2006
Posts: 296
Reply with quote
In this tutorial, we'll create a simple FPS game base the "Hall" demo.
View user's profile Send private message
 Part 1 : Game Menu 
Vincent


Joined: 25 Dec 2006
Posts: 296
Reply with quote
In this section, we create a game menu.

1. Open the "Hall" scene (...\scenes\demos\Hall.sce) in Awakening
2. Create a Text2D, edit it's text to "Begin Game". You can adjust it's appearance as you please, my scheme is:

set it's color to blue; set it's font to "Arial", size is 37; set Width & Height scale all to 2

3. In the Command Target rollout, uncheck the Transparent style. This let the overlay can receive mouse input and do command.

4. Create a Script named "begin game" (View > Scripts List... > New String); and edit it's code to:
Code:
StopShot()
GameMode(true)


5. Select the "Begin Game" overlay, in the Command Target rollout, click "Add Action" button.

6. In the Action Define dialog that appears, set Message to "Release", Function to "DoScript", Object to "begin game", click OK button. We've just defined a action for overlay, let it do a script when mouse released on it.

7. Ok, press F5 to run the scene, you can start walk around by clicking the overlay.


But we want to hide the menu when walking around:

1. Select the "Begin Game" overlay and right-click on it, click "Define Script Variable..." on the context menu.
2. In the Script Variables List dialog, rename the selected variable to "menu_begingame" (click on the name to start edit).
3. Add a line to the codes of "begin game" script:
Code:
menu_begingame.hide(true)

so this code will hide the overlay when run the script.


[section end]


Last edited by Vincent on Wed Jul 18, 2007 10:50 am; edited 1 time in total
View user's profile Send private message
 Part 2 : Cursor and Movement 
Vincent


Joined: 25 Dec 2006
Posts: 296
Reply with quote
In this section, we deal with cursor and input.

I. Draw Cross Cursor

1. Download QinEmperor, unpack it, find the "cross.tga" in the "textures" folder.

2. Load the "cross.tga" to scene ( right-click in Texture Browse Window, select "Add Texture").

3. You should see a small blue cross in Textures Browse Window, select it and right-click, select "Define Script Variable..." on
the popup menu; you should see a variable named "cross_tga" in the Script Variables List dialog that appears.

4. In Awakening's main menu, select View > Edit User Script File... , the User Script File of the scene will appears in Windows Notepad; you can edit it in other program too, the usr file locates with same folder to scene file.

5. Add two lines in OnSize() function:
Code:
wincx=cx
wincy=cy


6. Add below codes in Render2D() function:
Code:
   if (IsGameMode()) then
      draw.setbkcolor(COLOR_WHITE)
      local cp=point.new(wincx/2,wincy/2)
      local halfsize=16
      local r=rect.new(cp.x-halfsize,cp.y-halfsize,cp.x+halfsize,cp.y+halfsize)
      draw.stretchblt(r,cross_tga)   
   end


run the scene, click Begin Game, a blue cross will appears on the center of window.

II. Rotate Camera by Mouse Move

1. Add below lines BEFORE OnMouseMove() function:
Code:
local cameraMoveStep,cameraRotateStep=CameraMoveRotateStep(1,1) -- get
CameraMoveRotateStep(cameraMoveStep,cameraRotateStep) -- restore


2. Add below codes in OnMouseMove() function:
Code:
local xcenter=wincx/2
local ycenter=wincy/2
local xoffset=x-xcenter
local yoffset=y-ycenter
if (xoffset==0 and yoffset==0) then return end

if (IsGameMode() and not IsPause()) then
   local rot=camera.getRotation()
   rot.x=rot.x+yoffset*cameraRotateStep*0.1
   rot.y=rot.y+xoffset*cameraRotateStep*0.1
   if (rot.x>80) then rot.x=80 end
   if (rot.x<-80) then rot.x=-80 end
   camera.setRotation(rot)

   local x=xcenter
   local y=ycenter
   x,y=wnd.ClientToScreen(GetMainWnd(),x,y)
   wnd.SetCursorPos(x,y)
end



III. Hide & Show default arrow cursor
we want to hide the arrow cursor when playing game, also need a method to show the cursor again.

1. Add a line to the ""begin game" script:
Code:
wnd.ShowCursor(false)


2. New a Script named "pause game", and edit it's code as below:
Code:
if (gGamePause) then -- pause game
  wnd.ShowCursor(false)
  Pause(false)
else -- resume game
  wnd.ShowCursor(true)
  Pause(true)
end
gGamePause=not gGamePause


3. Add below codes in OnKeyDown() function:
Code:
if (VK_TAB==nChar or VK_ESCAPE==nChar) then
      DoScript('pause game')
end


so we can pause game by pressing the Tab key; the Esc Key is a accelerator key by default, so it's unusable temporarily.

4. Also we want to release the cursor when we switch to other application, so add below lines in OnActivate() function:
Code:
   if (0==nActive) then -- deactivated
      Pause(true)
   else   -- actived
      Pause(false)
   end



IV. Keyboard Input

By default, the Winds3D Player have some accelerator keys like Esc, Space, etc; these keys may conflict with your game input setting, so there is a function for disabling accelerator: EnableAccel(). Another problem is the default player movement keys, like F,C,W,S,A,D etc, also may not accord with your wish; so the SetInputStyle() function let you disable/enable all or some of these controls.

1. Disable accelerator keys
New a Script named "_SCENE_BEGIN", and edit it's code as below:
Code:
EnableAccel(false)


Scene Player will do the "_SCENE_BEGIN" script when scene begin.

2. Enable W,S,A,D controls
Add a line to the "begin game" script:
Code:
SetInputStyle( ModifyStyle(GetInputStyle(),0,INPUT_STYLE_WSAD) )


the default movement keys also can be changed int the standalone Winds3D Player (File > Configure Input...), but fixed in web3d player.


[section end]


Last edited by Vincent on Fri Jul 20, 2007 5:19 am; edited 5 times in total
View user's profile Send private message
 thx 
liverol


Joined: 29 Jun 2007
Posts: 45
Reply with quote
code in mousemove() function is helpful,wait for next section.
View user's profile Send private message
  
nigec


Joined: 04 Jul 2007
Posts: 212
Reply with quote
thanks Vincent, that was really helpful.. Cool
View user's profile Send private message
 Part 3: Shoot 
Vincent


Joined: 25 Dec 2006
Posts: 296
Reply with quote
In this section, we'll simulate gun shooting, bullet flying and colliding in game.

Before the next step, create a new folder (assume named "simplefps" below) in your disk; and save the scene to the folder with name "fps.sce".

I. Temporary Object

Let's consider such sort of objects in game, they appear sometime, and exist just for a period of time, when the life time out, they should disappear; for example, a bullet will appear when shooting, and it should disappear once hit something. So we write a class for this sort of temporary objects - "tempobj" :

In the "simplefps" folder, create a text file with name "tempobj.lua", and edit it's content as below:
Code:
-- temporary object

local function _new(t)

   local fLifeTime=5;
   
   local getLifeTime   =   function() return fLifeTime; end
   local setLifeTime   =   function(lt) fLifeTime=lt; end

   local frameMove   =   function(timed)
               fLifeTime=fLifeTime-timed
               if (fLifeTime<=0) then
                  return true;
               end
               return false;
            end
   local deleteThis =   function()
               error('this function must be overloaded!')
            end


   if (type(t)~='table') then t={} end
   t.getLifeTime=getLifeTime
   t.setLifeTime=setLifeTime
   t.frameMove=frameMove
   t.deleteThis=deleteThis


   return t
end

-- export ----
tempobj   =   {
   new   = _new
}



II. Bullet

The bullet class is derived from tempobj, create a text file and save with name "bullet.lua" in same folder, codes is here:
Code:
require 'tempobj'

local function _new()
   local bul=tempobj.new(scene.createMovTar())

   bul.setNoBounce(true) -- no bounce
   bul.pointed(true)   -- is point

   bul.deleteThis   =   function()
               scene.deleteMovTar(bul)
            end

   return bul
end

-- export ----
bullet   =   {
   new   = _new
}


we use a pointed movtar as bullet's physics figure, and delete it when bullet die.


III. My Player

We need append functions to the predefined "player" class.

In the "simplefps" folder, create a text file with name "myplayer.lua", and edit it's content as below:
Code:
require 'bullet'

local function _new()
   local movtar=player.getMovTar()

   local bulletlist=array.new()

   local fire = function()
      local bul=bullet.new()
      bul.setLifeTime(3)
      bul.setPosition(camera.getPosition())
      bul.setVelocity(camera.getFront()*9000)
      bulletlist.add(bul)
   end

   local frameMove = function(timed)
      for i,v in ipairs(bulletlist) do
         if (v.frameMove(timed)) then
            bulletlist.remove(i)
            v.deleteThis()
         end
      end
   end

   player.fire=fire
   player.frameMove=frameMove

   return player
end

-- export ----
myplayer   =   {
   new   = _new
}



IV. Triggering the "fire" function

In the "fps.sce.usr" file:

1. Add two lines at the beginning:
Code:
require 'myplayer'
player=myplayer.new()


2. Add below codes in the OnLButtonDown() function:
Code:
   if (IsGameMode() and not IsPause()) then
      player.fire()
   end


3. Add a line BEFORE the FrameMove() function:
Code:
local lastAppTime=0


4. Add below codes in the FrameMove() function:
Code:
   local nowAppTime=GetAppTime()
   local AppTimeD=nowAppTime-lastAppTime
   lastAppTime=nowAppTime

   player.frameMove(AppTimeD)



Now, the shoot utility works, but we can't see anything happen when click to fire. You can add a function to the bullet class:
Code:
local _frameMove = bul.frameMove
bul.frameMove =   function(timed)
   print(string.format("hi, i'm a happy bullet, i've still %d seconds to life!",bul.getLifeTime()))
   return _frameMove(timed)
end


when you click to fire, you can open the console to trace bullets.


Last edited by Vincent on Sat Jul 21, 2007 3:25 am; edited 1 time in total
View user's profile Send private message
 Part 4: Shoot continued 
Vincent


Joined: 25 Dec 2006
Posts: 296
Reply with quote
I. Spot

When a bullet hitting a wall, it should produce a spot on the wall.

1. Find the "bspot.tga" in the QinEmperor's textures and copy it to Awakening's textures folder.

2. In the "bullet.lua" , add a line to the beginning of the "_new()" function:
Code:
   local nSpotTexture=texturelist.addTexture("\\bspot.tga")

this code load the "bspot.tga" file to scene, and save the texture id to a local variable - nSpotTexture. it's a good practice to declare variables as "local" as possible, keep the global namespace clean!

3. Add a function to the bullet class (in the "_new()" function, add below codes before the "return bul" line) :
Code:
bul.OnCollide = function(ptrace)
   local t=trace.new(ptrace)

   local blockobj=t.getBlockObject()
   if (blockobj) then
      if (UD_SURFACE==blockobj.getClassID()) then
         -- spot
         local spot=scene.buildSpot(blockobj,t.getStop()-blockobj.getLmOrg(),5,COLOR_WHITE,true)
         if (spot) then
            spot.setTexture(nSpotTexture)
            spot.setLifeTime(16)
         end

         -- add spark codes here --

      end
   end

   bul.setLifeTime(0)
end


The bullet class's hierarchy tree is movtar < tempobj < bullet, the movtar class has a callback function "OnCollide", when a movable target colliding with other objects, it'll call this function to do a notice. So by writing codes in this function, we can do something when a bullet hitting something.

The first line "local t=trace.new(ptrace)" constructs a "trace" instance by passed handle - "ptrace"; then we use the trace instance to get the touched object; if the object is a surface, then build a spot on it.

The last line "bul.setLifeTime(0)" kill the bullet object, so the bullet will disappear.

Now, try to fire in game again, do you find those pretty spots?


II. Spark

When a bullet colliding with hard object it should emit sparks; we use particle system to simulate that.

1. Find the "spark.bmp" in the QinEmperor's textures and copy it to Awakening's textures folder.

2. In the "bullet.lua" , add a line to the beginning of the "_new()" function:
Code:
   local nSparkTexture=texturelist.addTexture('\\spark.bmp')


3. In the "OnCollide" function of bullet.lua, add below codes after forementioned spot codes:
Code:
-- spark
local par=scene.createParticles()
if (par) then
   par.setPosition(t.getStop())
   par.setType(PARTICLES_TYPE_EXPLODE)
   par.setStyle( andDWORD(par.getStyle(), notDWORD(PARS_CYCLE)) )
   par.setVelocity(vec.new(25,0,0))
   par.setTexture(nSparkTexture)
   par.setSize(4)
   par.setAmount(10)
   par.setLifeTime(3)
end



ok, we have achieved the shoot utility, not too hard is it?



[section end]
View user's profile Send private message
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum
All times are GMT  
Page 1 of 1  

  
  
 Reply to topic