Adobe Director Online
 
Sridevi Aishwariya

Sridevi Aishwariya .G
Director Developer

Developing a Simple 3D Game

 
Download the source file here.
 

This article outlines the steps in creating a simple Ping Pong game in Director. The first step is the creation of a 3D cast member. Click on Windows in the Main Menu and select Shockwave 3D, a 3D cast would be created in the cast Window, rename the cast member as “3D World” and place it on sprite1. And then you can start adding script to the 3D cast.  

The beginSprite method is mainly used for initializing the 3D environment such as, model creation, positioning the model in the 3D environment, adding skin to the model, adding collision modifiers to the model etc.

 

-- Initializing the 3D cast member

mySprite = sprite(me.spriteNum)
tMember  = mySprite.member
tMember.resetWorld()  

-- Create a ball model

ballResource          = tMember.newModelResource("Ball", #sphere)
ballResource.radius   = 7
ballModel             = tMember.newModel("Ball", ballResource)  

-- positioning the ball model

ballModel.transform.identity()
ballModel.transform.translate(0,-75,0)

-- add new shader and texture to the ball model

tMember.newTexture("Texture02",#fromImageObject,member("Image1").image)
newShader01 = tMember.newShader("newPainter",#standard)
newShader01.texture = tMember.texture("Texture02")
ballModel.shader = newShader01

-- Add collision modifier

 .addModifier(#collision)    -- enabled by default
ballModel.collision.mode    = #sphere
ballModel.collision.resolve = FALSE -- resolved on an individual basis
ballModel.collision.setCollisionCallback(#ballCollide, me)  

Any number of models can be created from a modelResource. The model is the actual object that is visible in the 3D World. A model can be repositioned, cloned and made to respond to user event.

In order to give a realistic appearance to the Model, Shader is added to the Model. A Shader is the "skin" which is wrapped around the model resource used by the model. The visible component of a shader is created with up to eight layers of textures. These eight texture layers are either created from bitmap cast members or image objects within Director or imported with models from 3D modeling programs. A texture can be used by any number of shaders. Changes to a texture will appear in all shaders which use that texture.  

The collision modifier is added to the Model, it allows the model to detect and respond to collision. The setCollisionCallback() method is used to register a method, that is called when the collision is detected. In a game, we require the ball to bounce of the wall except when it collides against the bottom wall. Hence, we set the collision enabled property to TRUE and set the resolve property to FALSE since the collision is not resolved on an individual basis, but according to the rules of the game.  

on ballCollide me, collisionData
  case collisionData.modelB of
    leftwallModel:
      xDirection = 1
   otherwise:
    .
    .
    .
    .
  end case
end

The collisionData object has four properties, modelA and modelB are the models involved in the collision, pointOfContact is the world position of the collision and collisionNormal is the direction of the collision.

The code is broken as follows.  To stimulate the motion of the ball, we use the enterframe method to reposition the object in each frame.  

on enterframe 
  LocX = ballModel.transform.position.x + (3 * xDirection)
  LocY = ballModel.transform.position.y + (3 * yDirection)
  ballModel.transform.position = vector(LocX, LocY,0)
end  

To move the pinpong bat, we use the keyDown method, the keyPressed method tests whether the last key that was pressed on the keyboard is equal to the given keycode.  

on keyDown()
  --123: Left
  --126: up
  --125: down
  --124: Right
  .
  .
  . 
  if _key.keyPressed(123) and gameOver<>1 then -- left button clicked
     
      LocX = max (LocX-20,-70)
      batModel.transform.position = vector(LocX,-65,0)
  end if
  .
  .
  . 
end  

To create text in the 3D world, create a text cast member and edit it using the text editor. Create a TextModelResource using the Text Member. Inorder to apply shader to the Text, the shaderList (The number of entries in this list equals the number of meshes in the model resource used by the model. Each mesh can be shaded by only one shader) of the Text must be initialized to the new shader.  

-- create a text

textResource = member("normal_text").extrude3d(tMember)
textResource.tunnelDepth = 18
textResource.smoothness = 50
textModel = tMember.newModel("3DText",textResource)
textModel.transform.position = vector(-95,-20,0)
textModel.visibility = #none  

-- add texture to text

tMember.newTexture("Texture03",#fromImageObject,member("Image2").image)
newShader02 = tMember.newShader("newPainter01",#standard)
newShader02.texture = tMember.texture("Texture03")

count_shader = tMember.model("3DText").shaderList.count
i = 0
repeat while i < count_shader
  i = i + 1
  tMember.model("3DText").shaderlist[i] = newShader02
end repeat  

I have used the Particle system to draw a line across the screen. You can play around with the particle system to get a wide variety of effects like smoke, fire etc.  

-- create a particle model

particleResource = tMember.newModelResource("particle01", #particle,#both)
particleResource.colorRange.start=rgb(255,0,0)
particleResource.colorRange.end=rgb(0,0,255)
particleResource.sizeRange.start= 2
particleResource.sizeRange.end= 0
particleResource.blendRange.start=100.0
particleResource.blendRange.end=0.0
particleResource.emitter.numParticles=1000
particleResource.emitter.minSpeed=30
particleResource.emitter.maxSpeed=50
particleResource.emitter.angle=3
particleModel = tMember.newModel("particle01", particleResource)
particleModel.visibility = #none
particleModel.transform.position = vector(-95,-15,0)  

The code for the complete ping pong game is as follows. You can play around with the code and add buttons to restart the game and more.  

Create a field member and label it “score_field” to enter score, import two images to the cast library and name it “Image1” and “Image2” to create the textures for the objects. Create a Text member and name it “normal_text” , open the text editor and type “Game Over”.  

---------- Define the property and global variables

property mySprite
property tMember
property leftwallModel
property rightwallModel
property bottomwallModel
property topwallModel
property batModel
property ballModel
property textModel
property brickModel
property particleModel
property brickResource
property newShader03
property Texture01

global xDirection
global yDirection
global gameOver
global gScore
global seti

-----------------------------------------------------------------------

  on beginSprite(me)
    mySprite = sprite(me.spriteNum)
  tMember  = mySprite.member
  tMember.resetWorld()
  cameraModel = mySprite.camera

  gameOver = 0
  xDirection = 1
  yDirection = 1
  brickModel = [40]
  gScore = 0
  seti = 1  

  member("score_field").text = gScore & " "

  -- Create the batModel model 

  batResource          = tMember.newModelResource("Bat", #box)
  batResource.height   = 4
  batResource.width    = 30
  batResource.length   = 5
  batModel                = tMember.newModel("Bat", batResource)
  batModel.transform.identity()
  batModel.transform.translate(0,-65,0)

    -- Add collision modifier

  batModel.addModifier(#collision)   
  batModel.collision.mode    = #box
  batModel.collision.resolve = FALSE

  -- Create the left wall model

  lwallResource          = tMember.newModelResource("lwall", #box)
  lwallResource.height   = 140
  lwallResource.width    = 3
  lwallResource.length   = 5
  leftwallModel               = tMember.newModel("lwall", lwallResource)   

  leftwallModel.transform.identity()
  leftwallModel.transform.translate(-90,0,0)

  -- Add collision modifier

  leftwallModel.addModifier(#collision)   

  leftwallModel.collision.mode    = #box

  leftwallModel.collision.resolve = FALSE

 

  -- Create the right wall model

  rwallResource          = tMember.newModelResource("rwall", #box)

  rwallResource.height   = 140

  rwallResource.width    = 3

  rwallResource.length   = 5

  rightwallModel              = tMember.newModel("rwall", rwallResource)

 

  rightwallModel.transform.identity()

  rightwallModel.transform.translate(90,0,0)

 

  -- Add collision modifier

  rightwallModel.addModifier(#collision)   

  rightwallModel.collision.mode    = #box

  rightwallModel.collision.resolve = FALSE

 

  -- Create the top wall model

  twallResource          = tMember.newModelResource("twall", #box)

  twallResource.height   = 3

  twallResource.width    = 180

  twallResource.length   = 5

  topwallModel                = tMember.newModel("twall", twallResource)

 

  topwallModel.transform.identity()

  topwallModel.transform.translate(0,70,0)

 

  -- Add collision modifier

  topwallModel.addModifier(#collision)   

  topwallModel.collision.mode    = #box

  topwallModel.collision.resolve = FALSE

 

  -- Create the bottom wall model

  bwallResource          = tMember.newModelResource("bwall", #box)

  bwallResource.height   = 3

  bwallResource.width    = 180

  bwallResource.length   = 5

  bottomwallModel             = tMember.newModel("bwall", twallResource)

 

  bottomwallModel.transform.identity()

  bottomwallModel.transform.translate(0,-75,0)

 

  -- Add collision modifier

  bottomwallModel.addModifier(#collision)   

  bottomwallModel.collision.mode    = #box

  bottomwallModel.collision.resolve = FALSE

 

  -- Add texture to the wall and the bat  

 

  tMember.newTexture("Texture01",#fromImageObject,member("Image2").image)

  tMember.model("Bat").shader.texture=tMember.texture("Texture01")

 

  -- Create a ball model

  ballResource          = tMember.newModelResource("Ball", #sphere)

  ballResource.radius   = 7

  ballModel            = tMember.newModel("Ball", ballResource)

 

  -- Add collision modifier

  ballModel.addModifier(#collision)    -- enabled by default

  ballModel.collision.mode    = #sphere

  ballModel.collision.resolve = FALSE -- resolved on an individual basis

  ballModel.collision.setCollisionCallback(#ballCollide, me)

 

  -- add new shader and texture to the ball model

 

  tMember.newTexture("Texture02",#fromImageObject,member("Image1").image)

  newShader01 = tMember.newShader("newPainter",#standard)

  newShader01.texture = tMember.texture("Texture02")

  ballModel.shader = newShader01

 

  -- add new shader and texture to the brick model

 

  tMember.newTexture("Texture04",#fromImageObject,member("Image1").image)

  newShader03 = tMember.newShader("newPainter02",#standard)

  newShader03.texture = tMember.texture("Texture04")

 

  -- Create a brick

  brickResource          = tMember.newModelResource("Brick", #box)

  brickResource.height   = 10

  brickResource.width    = 10

  brickResource.length   = 5

 

  i=0

  k=0

  j=0

  x = -80

  y = 60

  repeat while i<2

    repeat while j<17

      j=j+1

      k = k+1

     

      brick_model_label = "Brick" & k

      brickModel[k]         = tMember.newModel(brick_model_label,brickResource)

      brickModel[k].transform.position = vector (x,y,0)

      x = x + 10

      brickModel[k].shader = newShader03

      

      -- add collision modifier

      brickModel[k].addModifier(#collision)    -- enabled by default

      brickModel[k].collision.mode    = #box

      brickModel[k].collision.resolve = FALSE

    end repeat

    i=i+1

    j=0

    y = y - 10

    x = -80

  end repeat

 

  -- create a text

  textResource = member("normal_text").extrude3d(tMember)

  textResource.tunnelDepth = 18

  textResource.smoothness = 50

  textModel = tMember.newModel("3DText",textResource)

  textModel.transform.position = vector(-95,-20,0)

  textModel.visibility = #none

 

  -- add texture to text

  tMember.newTexture("Texture03",#fromImageObject,member("Image2").image)

  newShader02 = tMember.newShader("newPainter01",#standard)

  newShader02.texture = tMember.texture("Texture03")

 

  count_shader = tMember.model("3DText").shaderList.count

  i = 0

  repeat while i < count_shader

    i = i + 1

    tMember.model("3DText").shaderlist[i] = newShader02

  end repeat

 

  -- create a particle model

  particleResource = tMember.newModelResource("particle01", #particle,#both)

  particleResource.colorRange.start=rgb(255,0,0)

  particleResource.colorRange.end=rgb(0,0,255)

  particleResource.sizeRange.start= 2

  particleResource.sizeRange.end= 0

  particleResource.blendRange.start=100.0

  particleResource.blendRange.end=0.0

  particleResource.emitter.numParticles=1000

  particleResource.emitter.minSpeed=30

  particleResource.emitter.maxSpeed=50

  particleResource.emitter.angle=3

  particleModel = tMember.newModel("particle01", particleResource)

  particleModel.visibility = #none

  particleModel.transform.position = vector(-95,-15,0)

end beginSprite

 

----------------------------------------------------------------------

 

on keyDown()

  --123: Left