トップページ -> 最新情報技術の実習と研究ツール -> 3次元コンピュータグラフィックスのゲームエンジン -> 3次元のゲームエンジン Panda 3d を使ってみる
[サイトマップへ]  

3次元のゲームエンジン Panda 3d を使ってみる

Panda3d は,3次元のゲームエンジン.Unity や Unreal Engine よりも気軽に使えて,機能にそん色はない.

3次元のオブジェクトを使って,ダイナミックな何か(マウスやキーボード操作で何か)をしたいときには,Panda3d や Unreal Engine 4 などのゲームエンジンを使うのが便利

目次

  1. 前もって準備しておくこと
  2. Python3d を用いて画面を開く
  3. マウス操作
  4. シーンへの egg 形式ファイルの3次元モデルの読み込み
  5. 3次元モデルの配置
  6. キーボードイベントのイベントハンドラ
  7. マウスイベントのイベントハンドラ
  8. getX(), setX() などでオブジェクトを動かす
  9. オブジェクトを自動で動かす
  10. オブジェクトの速度

サイト内の関連Webページ

先人に感謝.


1. 前もって準備しておくこと

前準備として, Panda3d のインストールが終わっていること.

Windows でのインストールと動作確認の手順は,別の Web ページで説明しています


2. Python3d を用いて画面を開く

  1. テキストファイルの中身を次のように書く

    Windows のときは,ワードパッドを使うか,自分の好きなテキストエディタを使う

    ※ 参考のため,Visual Studio Code で Panda3d を使う手順を別の Web ページで説明しています.

    from direct.showbase.ShowBase import ShowBase
     
    class HelloWorld(ShowBase):
     
        def __init__(self):
            ShowBase.__init__(self)
     
    app = HelloWorld()
    app.run()
    

  2. テキストファイルを,保存する.

    ファイル名は何でもよいが、日本語などの全角文字は避ける.拡張子は「.py」にする.

  3. 実行する.

    ※ 参考のため,Visual Studio Code で Panda3d を使う手順を別の Web ページで説明しています.

    Windowsのコマンドプロンプトを使いたい場合には, 次のコマンドを実行.

    cd <先ほど保存したディレクトリppython hoge.py 
    

  4. 何も無い、黒めの灰色の画面が表示されるので確認する.

    結果を確認したら,右上の「x」をクリックして終了. 

演習問題:上の手順で画面を開きなさい

※ 実行手順については、 「Visual Studio Code で,Panda 3d プログラムを動かしてみる」を参考にしなさい


3. マウス操作

プログラムでは「scene」という名前のオブジェクトを作成

  1. テキストファイルの中身を次のように書き替える 
    from direct.showbase.ShowBase import ShowBase
    from direct.showbase.Loader import Loader
     
    class HelloWorld(ShowBase):
     
        def __init__(self):
            ShowBase.__init__(self)
     
            self.scene = self.loader.loadModel("models/environment")
            self.scene.reparentTo(self.render)
            self.scene.setScale(1, 1, 1)
            self.scene.setPos(0, 0, 0)
      
    app = HelloWorld()
    app.run()
    

  2. テキストファイルを,保存する.

    ファイル名は何でもよいが、日本語などの全角文字は避ける.拡張子は「.py」にする.

  3. 実行する.

    Windowsのコマンドプロンプトを使いたい場合には, 次のコマンドを実行.

    cd <先ほど保存したディレクトリppython hoge.py 
    

  4. 3次元モデルが表示されるので確認する.

  5. マウス操作

    結果を確認したら,右上の「x」をクリックして終了. 

演習問題:上の手順で3次元モデルを表示しなさい.マウス操作も行いなさい.


4. シーンへの egg 形式ファイルの3次元モデルの読み込み

egg 形式ファイルの3次元モデルである次の2つのファイルを読み込み

  1. C:\Panda3D-1.9.4-x64\models\ を開くと、「.egg.gz」のファイルがあることを確認

    これらは 3次元モデルのファイル

  2. 今度は、C:\Panda3D-1.9.4-x64\models\misc\ を開くと、ここにも「.egg.gz」のファイルがあることを確認

  3. テキストファイルの中身を次のように書き替える 

    2つの3次元モデルのファイルを読み込むようにする

    from direct.showbase.ShowBase import ShowBase
    from direct.showbase.Loader import Loader
     
    class HelloWorld(ShowBase):
     
        def __init__(self):
            ShowBase.__init__(self)
     
            self.scene = self.loader.loadModel("models/environment")
            self.scene.reparentTo(self.render)
            self.scene.setScale(1, 1, 1)
            self.scene.setPos(0, 0, 0)
      
            self.cube = self.loader.loadModel("models/misc/rgbCube")
            self.cube.reparentTo(self.render)
            self.cube.setScale(1, 1, 1)
            self.cube.setPos(0, 20, 0)
    
    app = HelloWorld()
    app.run()
    

  4. テキストファイルを,保存する.

    ファイル名は何でもよいが、日本語などの全角文字は避ける.拡張子は「.py」にする.

  5. 実行する.

    Windowsのコマンドプロンプトを使いたい場合には, 次のコマンドを実行.

    cd <先ほど保存したディレクトリppython hoge.py 
    

  6. 2つの3次元モデル(竹林と立方体)が表示されるので確認する.

    立方体は、画面中央に緑色で現れる

  7. マウス操作

    結果を確認したら,右上の「x」をクリックして終了. 

演習問題:上の手順で3次元モデルを表示しなさい.マウス操作も行いなさい.

演習問題:次のように書き換えて、実行結果を確認しなさい。今度は、真っ白の球が表示される

        self.cube = self.loader.loadModel("models/misc/sphere")
        self.cube.reparentTo(self.render)
        self.cube.setScale(1, 1, 1)
        self.cube.setPos(0, 20, 0)

h2> 5. 3次元モデルの配置

位置を変えて配置

  1. テキストファイルの中身を次のように書き替える
    from direct.showbase.ShowBase import ShowBase
    from direct.showbase.Loader import Loader
     
    class HelloWorld(ShowBase):
     
        def __init__(self):
            ShowBase.__init__(self)
     
            self.scene = self.loader.loadModel("models/environment")
            self.scene.reparentTo(self.render)
            self.scene.setScale(1, 1, 1)
            self.scene.setPos(0, 0, 0)
    
            self.cube1 = self.loader.loadModel("models/misc/rgbCube")
            self.cube1.reparentTo(self.render)
            self.cube1.setScale(1, 1, 1)
            self.cube1.setPos(0, 20, 0)
    
            self.cube2 = self.loader.loadModel("models/misc/rgbCube")
            self.cube2.reparentTo(self.render)
            self.cube2.setScale(1, 1, 1)
            self.cube2.setPos(5, 20, 0)
      
    app = HelloWorld()
    app.run()
    

  2. テキストファイルを,保存する.

    ファイル名は何でもよいが、日本語などの全角文字は避ける.拡張子は「.py」にする.

  3. 実行する.

    Windowsのコマンドプロンプトを使いたい場合には, 次のコマンドを実行.

    cd <先ほど保存したディレクトリppython hoge.py 
    

  4. 立方体は 2つ表示されるので確認する.

  5. マウス操作

    結果を確認したら,右上の「x」をクリックして終了. 

演習問題:上の手順で2つの立方体を表示しなさい.マウス操作も行いなさい.

setScale() で拡大縮小

  1. テキストファイルの中身を次のように書き替える
    from direct.showbase.ShowBase import ShowBase
    from direct.showbase.Loader import Loader
     
    class HelloWorld(ShowBase):
     
        def __init__(self):
            ShowBase.__init__(self)
     
            self.scene = self.loader.loadModel("models/environment")
            self.scene.reparentTo(self.render)
            self.scene.setScale(1, 1, 1)
            self.scene.setPos(0, 0, 0)
    
            self.cube1 = self.loader.loadModel("models/misc/rgbCube")
            self.cube1.reparentTo(self.render)
            self.cube1.setScale(1, 1, 1)
            self.cube1.setPos(0, 20, 0)
    
            self.cube2 = self.loader.loadModel("models/misc/rgbCube")
            self.cube2.reparentTo(self.render)
            self.cube2.setScale(1, 1, 1)
            self.cube2.setPos(5, 20, 0)
            self.cube2.setScale(2.4)
      
    app = HelloWorld()
    app.run()
    

  2. テキストファイルを,保存する.

    ファイル名は何でもよいが、日本語などの全角文字は避ける.拡張子は「.py」にする.

  3. 実行する.

    Windowsのコマンドプロンプトを使いたい場合には, 次のコマンドを実行.

    cd <先ほど保存したディレクトリppython hoge.py 
    

  4. 右側の立方体は 2.4 倍に拡大されるので確認する.

  5. マウス操作

    結果を確認したら,右上の「x」をクリックして終了. 

演習問題:上の手順で2つの立方体を表示しなさい.マウス操作も行いなさい.

演習問題の2倍率の違う 5つの立方体を表示する次のプログラムを実行し、結果を確認しなさい

from direct.showbase.ShowBase import ShowBase
from direct.showbase.Loader import Loader
 
class HelloWorld(ShowBase):
 
    def __init__(self):
        ShowBase.__init__(self)
 
        self.scene = self.loader.loadModel("models/environment")
        self.scene.reparentTo(self.render)
        self.scene.setScale(1, 1, 1)
        self.scene.setPos(0, 0, 0)

        self.cube1 = self.loader.loadModel("models/misc/rgbCube")
        self.cube1.reparentTo(self.render)
        self.cube1.setScale(1, 1, 1)
        self.cube1.setPos(-6, 20, 0)
        self.cube1.setScale(0.2)

        self.cube1 = self.loader.loadModel("models/misc/rgbCube")
        self.cube1.reparentTo(self.render)
        self.cube1.setScale(1, 1, 1)
        self.cube1.setPos(-3, 20, 0)
        self.cube1.setScale(0.6)

        self.cube1 = self.loader.loadModel("models/misc/rgbCube")
        self.cube1.reparentTo(self.render)
        self.cube1.setScale(1, 1, 1)
        self.cube1.setPos(0, 20, 0)
        self.cube1.setScale(1.0)

        self.cube1 = self.loader.loadModel("models/misc/rgbCube")
        self.cube1.reparentTo(self.render)
        self.cube1.setScale(1, 1, 1)
        self.cube1.setPos(3, 20, 0)
        self.cube1.setScale(1.4)

        self.cube1 = self.loader.loadModel("models/misc/rgbCube")
        self.cube1.reparentTo(self.render)
        self.cube1.setScale(1, 1, 1)
        self.cube1.setPos(6, 20, 0)
        self.cube1.setScale(1.8)
  
app = HelloWorld()
app.run()

setQuat() で回転

egg 形式ファイルの3次元モデルである C:\Panda3D-1.9.4-x64\models\misc\rgbCube.egg も読み込む

  1. テキストファイルの中身を次のように書き替える
    from direct.showbase.ShowBase import ShowBase
    from direct.showbase.Loader import Loader
    from panda3d.core import Quat 
    
    class HelloWorld(ShowBase):
     
        def __init__(self):
            ShowBase.__init__(self)
     
            self.scene = self.loader.loadModel("models/environment")
            self.scene.reparentTo(self.render)
            self.scene.setScale(1, 1, 1)
            self.scene.setPos(0, 0, 0)
    
            self.cube1 = self.loader.loadModel("models/misc/rgbCube")
            self.cube1.reparentTo(self.render)
            self.cube1.setScale(1, 1, 1)
            self.cube1.setPos(0, 20, 0)
    
            self.cube2 = self.loader.loadModel("models/misc/rgbCube")
            self.cube2.reparentTo(self.render)
            self.cube2.setScale(1, 1, 1)
            self.cube2.setPos(5, 20, 0)
            self.cube2.setQuat( Quat( 0, 1, 1, 1 ) )
      
    app = HelloWorld()
    app.run()
    

  2. テキストファイルを,保存する.

    ファイル名は何でもよいが、日本語などの全角文字は避ける.拡張子は「.py」にする.

  3. 実行する.

    Windowsのコマンドプロンプトを使いたい場合には, 次のコマンドを実行.

    cd <先ほど保存したディレクトリppython hoge.py 
    

  4. 右側の立方体は回転しているので確認する.

  5. マウス操作

    結果を確認したら,右上の「x」をクリックして終了. 

演習問題:上の手順で2つの立方体を表示しなさい.マウス操作も行いなさい.

演習問題の2setQuat に設定した値の違う 5つの立方体を表示する次のプログラムを実行し、結果を確認しなさい

from direct.showbase.ShowBase import ShowBase
from direct.showbase.Loader import Loader
from panda3d.core import Quat 

class HelloWorld(ShowBase):
 
    def __init__(self):
        ShowBase.__init__(self)
 
        self.scene = self.loader.loadModel("models/environment")
        self.scene.reparentTo(self.render)
        self.scene.setScale(1, 1, 1)
        self.scene.setPos(0, 0, 0)

        self.cube1 = self.loader.loadModel("models/misc/rgbCube")
        self.cube1.reparentTo(self.render)
        self.cube1.setScale(1, 1, 1)
        self.cube1.setPos(-6, 20, 0)
        self.cube1.setQuat( Quat( 0, 1, 1, 0 ) )

        self.cube2 = self.loader.loadModel("models/misc/rgbCube")
        self.cube2.reparentTo(self.render)
        self.cube2.setScale(1, 1, 1)
        self.cube2.setPos(-3, 20, 0)
        self.cube2.setQuat( Quat( 0, 1, 1, 0.2 ) )

        self.cube3 = self.loader.loadModel("models/misc/rgbCube")
        self.cube3.reparentTo(self.render)
        self.cube3.setScale(1, 1, 1)
        self.cube3.setPos(0, 20, 0)
        self.cube3.setQuat( Quat( 0, 1, 1, 0.4 ) )

        self.cube4 = self.loader.loadModel("models/misc/rgbCube")
        self.cube4.reparentTo(self.render)
        self.cube4.setScale(1, 1, 1)
        self.cube4.setPos(3, 20, 0)
        self.cube4.setQuat( Quat( 0, 1, 1, 0.6 ) )

        self.cube5 = self.loader.loadModel("models/misc/rgbCube")
        self.cube5.reparentTo(self.render)
        self.cube5.setScale(1, 1, 1)
        self.cube5.setPos(6, 20, 0)
        self.cube5.setQuat( Quat( 0, 1, 1, 0.8 ) )
  
app = HelloWorld()
app.run()


キーボードイベントのイベントハンドラ

キーコードの種類 "A", "space", "enter", "arrow_left", "arrow_up", "arrow_down", "arrow_right" など

  1. テキストファイルの中身を次のように書き替える
    from direct.showbase.ShowBase import ShowBase
    from direct.showbase.Loader import Loader
    from panda3d.core import Quat
     
    class HelloWorld(ShowBase):
     
        def __init__(self):
            ShowBase.__init__(self)
     
            self.scene = self.loader.loadModel("models/environment")
            self.scene.reparentTo(self.render)
            self.scene.setScale(1, 1, 1)
            self.scene.setPos(0, 0, 0)
    
            self.cube = self.loader.loadModel("models/misc/rgbCube")
            self.cube.reparentTo(self.render)
            self.cube.setScale(1, 1, 1)
            self.cube.setPos(0, 20, 0)
            self.cube.setQuat( Quat( 0, 1, 1, 1 ) )
    
            self.accept( "a", self.a_key )    
     
        def a_key(self): 
            self.cube.setScale(2)
    
    
    app = HelloWorld()
    app.run()
    

  2. テキストファイルを,保存する.

    ファイル名は何でもよいが、日本語などの全角文字は避ける.拡張子は「.py」にする.

  3. 実行する.

    Windowsのコマンドプロンプトを使いたい場合には, 次のコマンドを実行.

    cd <先ほど保存したディレクトリppython hoge.py 
    

  4. 立方体が表示されるので確認する

  5. キーボードの「A」キーを押すと、大きな立方体に変わるので確認する

    結果を確認したら,右上の「x」をクリックして終了. 

演習問題:上の手順で立方体を表示しなさい.キーボードの「A」キーを押す操作も行いなさい.

演習問題の2: スペースキーに反応するように、プログラムを次のように書き換えて実行しなさい


        self.accept( "space", self.space_key )    
 
    def space_key(self): 
        self.cube.setScale(5)


マウスイベントのイベントハンドラ

マウスボタンのコード "mouse1", "mouse2", "mouse3"

  1. テキストファイルの中身を次のように書き替える
    from direct.showbase.ShowBase import ShowBase
    from direct.showbase.Loader import Loader
    from panda3d.core import Quat
     
    class HelloWorld(ShowBase):
     
        def __init__(self):
            ShowBase.__init__(self)
     
            self.scene = self.loader.loadModel("models/environment")
            self.scene.reparentTo(self.render)
            self.scene.setScale(1, 1, 1)
            self.scene.setPos(0, 0, 0)
    
            self.cube = self.loader.loadModel("models/misc/rgbCube")
            self.cube.reparentTo(self.render)
            self.cube.setScale(1, 1, 1)
            self.cube.setPos(0, 20, 0)
            self.cube.setQuat( Quat( 0, 1, 1, 1 ) )
    
            self.accept( "mouse1", self.mouse1 )
            self.accept( "mouse3", self.mouse3 )
     
        def mouse1(self): 
            self.cube.setScale(2)
    
        def mouse3(self): 
            self.cube.setScale(0.5)
    
    
    app = HelloWorld()
    app.run()
    

  2. テキストファイルを,保存する.

    ファイル名は何でもよいが、日本語などの全角文字は避ける.拡張子は「.py」にする.

  3. 実行する.

    Windowsのコマンドプロンプトを使いたい場合には, 次のコマンドを実行.

    cd <先ほど保存したディレクトリppython hoge.py 
    

  4. 立方体が表示されるので確認する

  5. マウスの右ボタンをクリックすると、小さな立方体に変わるので確認する

  6. マウスの左ボタンをクリックすると、大きな立方体に変わるので確認する

    結果を確認したら,右上の「x」をクリックして終了. 

演習問題:上の手順で立方体を表示しなさい.右と左のマウスボタンを押す操作も行いなさい.


getX(), setX() などでオブジェクトを動かす

  1. テキストファイルの中身を次のように書き替える
    from direct.showbase.ShowBase import ShowBase
    from direct.showbase.Loader import Loader
    from panda3d.core import Quat
     
    class HelloWorld(ShowBase):
     
        def __init__(self):
            ShowBase.__init__(self)
     
            self.scene = self.loader.loadModel("models/environment")
            self.scene.reparentTo(self.render)
            self.scene.setScale(1, 1, 1)
            self.scene.setPos(0, 0, 0)
    
            self.cube = self.loader.loadModel("models/misc/rgbCube")
            self.cube.reparentTo(self.render)
            self.cube.setScale(1, 1, 1)
            self.cube.setPos(0, 20, 0)
            self.cube.setQuat( Quat( 0, 1, 1, 1 ) )
    
    
            self.accept( "arrow_up", self.up_key )    
            self.accept( "arrow_down", self.down_key )    
            self.accept( "arrow_right", self.right_key )    
            self.accept( "arrow_left", self.left_key )    
    
        def up_key(self): 
            self.cube.setZ( self.cube.getZ() + 1 )
        def down_key(self): 
            self.cube.setZ( self.cube.getZ() - 1 )
        def right_key(self): 
            self.cube.setX( self.cube.getX() + 1 )
        def left_key(self): 
            self.cube.setX( self.cube.getX() - 1 )
    
    
    app = HelloWorld()
    app.run()
    

  2. テキストファイルを,保存する.

    ファイル名は何でもよいが、日本語などの全角文字は避ける.拡張子は「.py」にする.

  3. 実行する.

    Windowsのコマンドプロンプトを使いたい場合には, 次のコマンドを実行.

    cd <先ほど保存したディレクトリppython hoge.py 
    

  4. 立方体が表示されるので確認する

  5. キーボードの矢印キー(上、下、右、左)でオブジェクトが移動するので確認する.

    結果を確認したら,右上の「x」をクリックして終了. 

演習問題:上の手順で立方体を表示しなさい. キーボードの矢印キー(上、下、右、左)でオブジェクトが移動するので確認しなさい


オブジェクトを自動で動かす

  1. テキストファイルの中身を次のように書き替える
    from direct.showbase.ShowBase import ShowBase
    from direct.showbase.Loader import Loader
    from panda3d.core import Quat
    from direct.task import Task
     
    class HelloWorld(ShowBase):
     
        def __init__(self):
            ShowBase.__init__(self)
     
            self.scene = self.loader.loadModel("models/environment")
            self.scene.reparentTo(self.render)
            self.scene.setScale(1, 1, 1)
            self.scene.setPos(0, 0, 0)
    
            self.cube = self.loader.loadModel("models/misc/rgbCube")
            self.cube.reparentTo(self.render)
            self.cube.setScale(1, 1, 1)
            self.cube.setPos(0, 20, 0)
            self.cube.setQuat( Quat( 0, 1, 1, 1 ) )
    
            self.taskMgr.add(self.cubeMotionTask, "CubeMotionTask")
    
        def cubeMotionTask(self, task):
            self.cube.setPos(0, 20, task.time * 0.2)
            return Task.cont
      
    app = HelloWorld()
    app.run()
    

  2. テキストファイルを,保存する.

    ファイル名は何でもよいが、日本語などの全角文字は避ける.拡張子は「.py」にする.

  3. 実行する.

    Windowsのコマンドプロンプトを使いたい場合には, 次のコマンドを実行.

    cd <先ほど保存したディレクトリppython hoge.py 
    

  4. オブジェクトが自動で移動するので確認する.

    結果を確認したら,右上の「x」をクリックして終了. 

演習問題:上の手順で立方体を表示しなさい. 動くことを確認しなさい


オブジェクトの速度

  1. テキストファイルの中身を次のように書き替える
    from direct.showbase.ShowBase import ShowBase
    from direct.showbase.Loader import Loader
    from panda3d.core import Quat
    from direct.task import Task
     
    class HelloWorld(ShowBase):
     
        def __init__(self):
            ShowBase.__init__(self)
     
            self.scene = self.loader.loadModel("models/environment")
            self.scene.reparentTo(self.render)
            self.scene.setScale(1, 1, 1)
            self.scene.setPos(0, 0, 0)
    
            self.cube = self.loader.loadModel("models/misc/rgbCube")
            self.cube.reparentTo(self.render)
            self.cube.setScale(1, 1, 1)
            self.cube.setPos(0, 20, 0)
            self.cube.setQuat( Quat( 0, 1, 1, 1 ) )
            self.previous_time = 0
            self.x = 0
            self.y = 20
            self.z = 0
            self.vx = 0
            self.vy = 0
            self.vz = 0
    
            self.accept( "arrow_up", self.up_key )    
            self.accept( "arrow_down", self.down_key )    
            self.accept( "arrow_right", self.right_key )    
            self.accept( "arrow_left", self.left_key )    
            self.taskMgr.add(self.cubeMotionTask, "CubeMotionTask")
    
    
        def cubeMotionTask(self, task):
            self.x += self.vx * (task.time - self.previous_time) 
            self.y += self.vy * (task.time - self.previous_time) 
            self.z += self.vz * (task.time - self.previous_time) 
            self.cube.setPos(self.x, self.y, self.z)
            self.previous_time = task.time	
            return Task.cont
    
    
        def up_key(self): 
            self.vz = self.vz + 1
        def down_key(self): 
            self.vz = self.vz - 1
        def right_key(self): 
            self.vx = self.vx + 1
        def left_key(self): 
            self.vx = self.vx - 1
    
    
    app = HelloWorld()
    app.run()
    

  2. テキストファイルを,保存する.

    ファイル名は何でもよいが、日本語などの全角文字は避ける.拡張子は「.py」にする.

  3. 実行する.

    Windowsのコマンドプロンプトを使いたい場合には, 次のコマンドを実行.

    cd <先ほど保存したディレクトリppython hoge.py 
    

  4. 立方体が表示されるので確認する

  5. キーボードの矢印キー(上、下、右、左)でオブジェクトが移動するので確認する.

    結果を確認したら,右上の「x」をクリックして終了. 

演習問題:上の手順で立方体を表示しなさい. キーボードの矢印キー(上、下、右、左)でオブジェクトが移動するので確認しなさい


衝突判定

from direct.showbase.ShowBase import ShowBase
from direct.showbase.Loader import Loader
from panda3d.core import Quat
from pandac.PandaModules import CollisionTraverser, CollisionHandlerPusher
from pandac.PandaModules import CollisionNode, CollisionSphere 

class HelloWorld(ShowBase):
 
    def __init__(self):
        ShowBase.__init__(self)
 
        base.cTrav = CollisionTraverser()
        self.pusher = CollisionHandlerPusher()

        self.scene = self.loader.loadModel("models/environment")
        self.scene.reparentTo(self.render)
        self.scene.setScale(1, 1, 1)
        self.scene.setPos(0, 0, -5)

        self.cube1 = self.loader.loadModel("models/misc/rgbCube")
        self.cube1.reparentTo(self.render)
        self.cube1.setScale(1, 1, 1)
        self.cube1.setPos(-6, 20, 0)
        self.cube1.setQuat( Quat( 0, 1, 1, 0 ) )
        c = CollisionNode('Cube1')
        c.addSolid(CollisionSphere(0, 0, 0, 0.6))
        cube1_c = self.cube1.attachNewNode(c)

        self.cube2 = self.loader.loadModel("models/misc/rgbCube")
        self.cube2.reparentTo(self.render)
        self.cube2.setScale(1, 1, 1)
        self.cube2.setPos(-3, 20, 0)
        self.cube2.setQuat( Quat( 0, 1, 1, 0.2 ) )
        c = CollisionNode('Cube2')
        c.addSolid(CollisionSphere(0, 0, 0, 0.6))
        cube2_c = self.cube2.attachNewNode(c)

        self.cube3 = self.loader.loadModel("models/misc/rgbCube")
        self.cube3.reparentTo(self.render)
        self.cube3.setScale(1, 1, 1)
        self.cube3.setPos(0, 20, 0)
        self.cube3.setQuat( Quat( 0, 1, 1, 0.4 ) )
        c = CollisionNode('Cube3')
        c.addSolid(CollisionSphere(0, 0, 0, 0.6))
        cube3_c = self.cube3.attachNewNode(c)

        self.cube4 = self.loader.loadModel("models/misc/rgbCube")
        self.cube4.reparentTo(self.render)
        self.cube4.setScale(1, 1, 1)
        self.cube4.setPos(3, 20, 0)
        self.cube4.setQuat( Quat( 0, 1, 1, 0.6 ) )
        c = CollisionNode('Cube4')
        c.addSolid(CollisionSphere(0, 0, 0, 0.6))
        cube4_c = self.cube4.attachNewNode(c)

        self.cube5 = self.loader.loadModel("models/misc/rgbCube")
        self.cube5.reparentTo(self.render)
        self.cube5.setScale(1, 1, 1)
        self.cube5.setPos(6, 20, 0)
        self.cube5.setQuat( Quat( 0, 1, 1, 0.8 ) )
        c = CollisionNode('Cube5')
        c.addSolid(CollisionSphere(0, 0, 0, 0.6))
        cube5_c = self.cube5.attachNewNode(c)
  
        self.player = self.loader.loadModel("models/misc/rgbCube")
        self.player.reparentTo(self.render)
        self.player.setScale(1, 1, 1)
        self.player.setPos(0, 15, 0)
        c = CollisionNode('Player')
        c.addSolid(CollisionSphere(0, 0, 0, 0.6))
        player_c = self.player.attachNewNode(c)


        self.accept( "arrow_up", self.up_key )    
        self.accept( "arrow_down", self.down_key )    
        self.accept( "arrow_right", self.right_key )    
        self.accept( "arrow_left", self.left_key )    

        base.cTrav.addCollider(cube1_c, self.pusher)
        base.cTrav.addCollider(cube2_c, self.pusher)
        base.cTrav.addCollider(cube3_c, self.pusher)
        base.cTrav.addCollider(cube4_c, self.pusher)
        base.cTrav.addCollider(cube5_c, self.pusher)
        base.cTrav.addCollider(player_c, self.pusher)
        self.pusher.addCollider(cube1_c, self.cube1, base.drive.node())
        self.pusher.addCollider(cube2_c, self.cube2, base.drive.node())
        self.pusher.addCollider(cube3_c, self.cube3, base.drive.node())
        self.pusher.addCollider(cube4_c, self.cube4, base.drive.node())
        self.pusher.addCollider(cube5_c, self.cube5, base.drive.node())
        self.pusher.addCollider(player_c, self.player, base.drive.node())

    def up_key(self): 
        self.player.setY( self.player.getY() + 1 )
    def down_key(self): 
        self.player.setY( self.player.getY() - 1 )
    def right_key(self): 
        self.player.setX( self.player.getX() + 1 )
    def left_key(self): 
        self.player.setX( self.player.getX() - 1 )


app = HelloWorld()
app.run()