2015年11月20日 星期五

樹梅派

最近開始玩樹梅派,滿有趣的,從露天買了2片UK製樹梅派2開發板,一個7吋官方touch screen,重慶南路天瓏書局也有在賣,也有賣零件感應器,也跑去電子材料行買了一堆電阻和LED,準備好好玩樹梅派,我對電子硬體是白痴,不過不用擔心,網路上有很多教學,或者買些樹梅派的書.


  買的官方7吋touch screen螢幕,裝好畫面上下顛倒,在網路找到方法config.txt加入
    lcd_roate=2

  父母有小孩的,樹梅派對小孩子很有用,可學程式又可認識簡單電子硬體 ,我目前只會接LED,原理很簡單,1端接地,另一端串電阻到GPIO腳位,讓GPIO腳位HIGH(3.3V)或LOW(0V),然後用程式去控制HIGH或LOW,很多程式都能使用GPIO(shell,java,c,python...),官方網站映像安裝,python就能直接使用GPIO了,剛好上次學了python,GPIO用python對我而言,沒甚難的,網路上GPIO LED教學都只是開開關關,我是用thread去點亮LED,讓每個LED都有自己的生命,各自亂閃,很有趣.(原碼下載)








  編輯python和UI部份的IDE,我喜歡用 Anjuta超好用,本來樹梅派OS是裝debian版本,因為Anjuta裝不上,就改用最新ubuntu mate,不過Anjuta有些bug,不能直接樹入中文,只能用貼的.

連接電視畫面




看到網路上有很多高手DIY樹梅派的作品(手機,氣象站,遙控攝影車...),真的很佩服,哈哈

read more...

2015年3月9日 星期一

pygtk cairo動畫(續),使用元件類別,讓各元件做出獨特動作


原碼下載:




在遊戲中飛碟王是用sub_picture.py模組來建立,讓各部元件有自己影像和移動方式,生命低於200,會伸出手臂,攻擊玩家,有教學文件,也有範例


move_object還提使用sub_picture.py模組來建立,讓各部元件有自己影像和移動方式,A和B其實用C都可取代掉的

  1.先import sub_image_fly如下
    from sub_fly_king import sub_image_fly
  2.建立主影像list,這裡只用一元素,可幾個都沒關係,在用move_object建立移動物這樣就OK,0,0是相對座標,如下:
    p=[sub_image("src/png/f1.png",0,0)]
    move_fly_king=move_object(self,self.darea,p,None,None,"RECEVER_collision_fly","SEND_move_fly",self.king2_life)#生命50
  3.隨時可用add_sub_image()來加入sub_image,如下:
                p1=[sub_image_fly1("src/png/fp.png",80,10),sub_image_fly1("src/png/fp.png",20,10),sub_image_fly1("src/png/fp.png",140,10)]#旋轉燈
                p2=[sub_image_fly("src/png/f2.png",-10,0,move_fly_king),sub_image_fly("src/png/f2.png",170,0,move_fly_king)]#攻擊手臂
                move_fly_king.add_sub_image(p1)#加入旋轉燈
                move_fly_king.add_sub_image(p2)#加入攻擊手臂
                move_fly_king.set_move_type("直線X")   
                move_fly_king.set_y(20)
  4.預設sub_image移動是跟move_object是一致,只是多相對座標,預設方法move_update,給主移動物x,y,又傳回去,沒改變甚,如下:
        def move_update(self,x,y):#想成移動物的x,y就可,要如何更新
        return x,y
         
    def get_surface_cr(self,cr,x,y):#給參考點回傳一個cr surface,會被move_object執行續一直呼叫
        self.x,self.y=self.move_update(x,y)[0]+self.x_r,self.move_update(x,y)[1]+self.y_r
        return cr.set_source_surface(self.p,self.x,self.y)
  5.假設我們要讓各部元件有自己移動方式,只要繼承sub_image,然後覆寫move_update這樣就OK,舉個例子上面第3點中sub_image_fly1("src/png/fp.png",80,10),
    就是繼承sub_image如下, 下面move_update,給主移動物x,y,然後每次角度多1度,造成這個部件,繞著主移動物的相對座標(80,10),以半徑10繞圈圈

     from sub_picture import sub_image
     import math,cairo
     class sub_image_fly1(sub_image):
         def __init__(self,image_path,x,y):
             #呼叫了父類別建構式
        super(sub_image_fly1,self).__init__(image_path,x,y)
        self.scale=0
         #super(sub_image_fly,self).__init__(image_path,x,y)
     #複寫父類別move_update
         def move_update(self,x,y):#想成移動物的x,y就可,要如何更新

            self.scale=self.scale+1
            if(self.scale>=360):self.scale=0
            offset_value=(float(self.scale))/180.0*math.pi
            x=x+10*math.cos(float(offset_value))
            y=y+10*math.sin(float(offset_value))
            return x,y

read more...

2015年3月1日 星期日

pygtk cairo動畫(續),增加播放wav聲音檔,播放圖片list,修改鍵盤事件........

原碼下載






我用自己寫的move_object.py動畫引擎模組,很簡單的就寫出了滿複雜的射擊遊戲,當然move_object.py可作很多的動畫,有時間會在嘗試其他遊戲,並增加move_object.py的功能
move_object.py新增了播放圖片list,和預設動作,背景上寫更多文字,圖片list移動物可顯示life,在遊戲中,你會看到大隻飛碟的燈號會閃來閃去,飛碟會向下或朝玩家丟子彈

並增加播放wav聲音檔模組soundwave.py,只是用os.popen,來執行LINUX指令paplay播放wav,目前LINUX音效都是pulseaudio

os.popen('paplay '+self.file)

讓機台很順的左右移動
主程式增加鬆開鍵盤事件connect,鬆開右或左鍵,停止移動
改寫鍵盤壓下事件,壓下左鍵時物件自動一直向,壓下右鍵時物件自動一直向右
............
self.window.connect("key-release-event", self.on_key_up)#鬆開

..............................
move_list_signal.py增加鬆開鍵盤事件


    #鍵盤事件,鬆開
    def on_key_up(self, event,list):
        key = event.keyval
        if key == gtk.keysyms.Right:self.main.move_stop()
        if key == gtk.keysyms.Left:self.main.move_stop()

之前移動物,只單張圖片,現在可用圖片list,會輪流播放圖片,下面是畫出一隻特大飛碟,飛碟燈會閃來閃去

              p=["fly1.png","fly2.png","fly3.png"]
              move_fly_king=move_object.move_object(self,self.framme1,self.darea,p,None,None,"RECEVER_collision_fly","SEND_move_fly",50)#生命50
              move_fly_king.set_move_type("直線X")
              move_fly_king.set_y(70)
              move_fly_king.set_life(100)#設生命
              self.move_list_fly_king.append(move_fly_king)

背景上可用set_text_list,寫更多文字,如下
         list1=["分數:"+str(self.score),self.get_frame_w_h()[0]-180,25,30,"紅色"]
         list2=["射擊遊戲V1.0",12,18,20,"黃色"]
         self.move_obj_b.set_text_list([list1,list2])

預設移動方式,增加2種set_move_foward(x,y),朝x,y方向前進

move_ufo_bullet.set_move_foward(self.move_body.get_xy()[0],self.move_body.get_xy()[1])#朝

角度直線可帶旋轉,第一參數angle=-90直線向上,第2參數5是移動量,若0原地不動,第3參數旋轉半徑,第4參數是旋轉半徑增幅

move_bullet.set_move_angle(angle,5,20,0)

若要讓移動物,繞半徑50,原地旋轉set_move_angle(90,0,50,0)
若要讓移動物,直線向上set_move_angle(-90,5)
.....................

read more...

2015年2月23日 星期一

pygtk cairo動畫(續) 修正 一些BUG,執行效果變好了,穩定版原碼下載

 穩定版原碼下載
用我寫的move_object.py 這模組,已可做出一些想要的動畫,目前我很滿意這模組,修正一些bug,不合程式邏輯(try全拿掉了),並增加一些爆炸畫面抖動效果,哈哈,寫這模組,是純好玩的,和專業的pygame比,當然差很多,不過我這,不用裝其他套件,就可在liux gnome桌面下執行

再來在說一下cairo,我完全弄懂cairo的運作原理了,當初開始寫這模組,清除畫面是用一個透明40x40像素,就算del掉,這surface是不會消失的,時間久,畫圖區充滿了透明40x40像素,queue_draw()就會更新一次,畫面會教lag,我試著用self.p_boom=self.p1=cairo.ImageSurface(cairo.FORMAT_ARGB32,0,0)#無像素png,清除畫面,改善很多,後來我再試著用self.cr=None也可以清除畫面,這更好讓memory也連帶淨空,終於是我要的效果了.
我認為cairo的原理真的很棒,程式稍用亂數改一下座標位置,就讓碰撞物或爆炸畫面產生抖動效果,如下
             offset= random.randint(-self.move_offset,self.move_offset)
             self.cr.set_source_surface(self.p1, self.x+offset, self.y+offset)
真的很棒,實際可看 一下move_object.py原碼,其實程式很短,大部分都在寫一些預設的移動,都只是在處理座標位置self.x,self.y,座標變,queue_draw()更新畫布,物體就會移動,很簡單的,新的畫面


read more...

2015年2月22日 星期日

pygtk cairo動畫(續)執行續,不同物件中信號傳遞

這是一個用move_object.py就完成的,一個不起眼的小遊戲,當然有興趣改一改,可做成其他遊戲,按這下載原碼
執行速度尚可,再來是想讓move_object.py這模組執行更順,才會具續下一步,寫這只是純好玩的,有興趣可拿來修改,參考都很歡迎




move_object.py,用選擇性參數,初始化物件,x=None,y=None,_RECEVER_COLLISION_=None,_RECEVER_MOVE_=None,這4參數可給,可不給,跟java多重建構子功能一樣
,最後_RECEVER_COLLISION_=None,_RECEVER_MOVE_=None,這2參數採用不具方式,用來設定方法,讓使用者在主程式實做,前面是碰撞發送,後者是移動發送,若2者都不給,就是非碰撞物,不做信號實做
    #建構式,用來初始化物件
    def __init__(self,main_obj,frame,darea,image_path,x=None,y=None,_RECEVER_COLLISION_=None,_RECEVER_MOVE_=None):

來看這2參數實際運作,下面getattr(self.main_obj,self.RECEVER_MOVE)(self),呼叫主程式self.main_obj的不具名方法,把本身當參數(self)
主程式,產生move_object物件時把"SEND_move_bullet"當參數,因此_RECEVER_MOVE_就是SEND_move_bullet,此時move_object.py不具名方法就是SEND_move_bullet,就變成self.main_obj.SEND_move_bullet(self),所以主程式就必須實做SEND_move_bullet這個方法(如下面狀況)
主程式
...............................
move_bullet=move_object.move_object(self,self.framme1,self.darea,p,x,y,None,"SEND_move_bullet")

...................
def SEND_move_bullet(self,move_object):
...........................

move_object.py程式


##############################碰撞時透過thread發送信號,把本身和碰撞物當參數,否則送出本身##        
    def SEND_MOVE_SIGNAL(self):
        d="RECEVER"
        if(self.check_yes):
            if(self.is_check_move):#判斷是否要實作移動發送
             #self.main_obj.RECEVER_MOVE(self)
             getattr(self.main_obj,self.RECEVER_MOVE)(self)

###############和其他是否碰撞,若碰撞回傳True,否則False###################################
    def check_collision(self,other_obj):
                  ...................................

          if(self.check_collision_p(xo,yo,xo1,yo1,xs,ys,xs1,ys1)):
              if(self.is_collision_check):
               #在這實作碰撞發送,若碰撞,送出本身和被撞物
               getattr(self.main_obj,self.RECEVER_COLLISION)(self,other_obj)
                           .............................

本遊戲中機台,子彈,飛碟,是碰撞物,因此要實做碰撞或移動發送,也可2者皆做,這裡我才用機台,和子彈是作移動發送,飛碟是作碰撞發送,如下,只要使用move_object這模組,就可完成不同動畫了


    #畫出機台
    def draw_body(self):
          if(len(self.move_list_body)<1 br="">            p="body.png"
            w,h=self.get_frame_w_h()
            #最後2個參數不給,給None代表不作碰撞接收,但作移動發送SEND_move_body,0,0是要產生的位置,也可用set_move_to_xy放到想要位置
            self.move_body=move_object.move_object(self,self.framme1,self.darea,p,w/2-20,h-60,None,"SEND_move_body")
            self.move_list_body.append(self.move_body)
    #畫出子彈
    def draw_bullet(self):        #if key == gtk.keysyms.Right:self.generate()
     if(len(self.move_list_bullet)<6 and="" len="" self.move_list_body="">0):
          p="bullet.png"
          #最後2個參數實作接收移動發送,收移動發送後碰撞檢查
          w,h=self.move_body.get_width_height()[0]/2,self.move_body.get_width_height()[1]
          x,y=self.move_body.get_xy()[0]+w,self.move_body.get_xy()[1]-h
          move_bullet=move_object.move_object(self,self.framme1,self.darea,p,x,y,None,"SEND_move_bullet")
          move_bullet.set_move_type("直線向上")
          move_bullet.set_move_speed(0.005)
          move_bullet.set_explosion_png("boom2.png")
          self.move_list_bullet.append(move_bullet)
          #加到列表list      
  


    #畫出隨機飛碟
    def generate(self):
          p="logo"+str(random.randint(1,5))+".png"
          #最後2個參數實作接收移動發送後碰撞檢查RECEVER_collision和None不作移動發送,代表check碰撞,不給座標None,None,位置會隨機產生
          move_fly=move_object.move_object(self,self.framme1,self.darea,p,None,None,"RECEVER_collision_fly",None)
          speed=float(random.randint(1,100))/100
          move_fly.set_move_speed(speed)
          if(random.randint(1,100) >50 ):
              move_fly.set_move_type("亂數")
          else:
              move_fly.set_move_type("直線X")
          #加到列表list
          self.move_list_fly.append(move_fly)


然後下面實做SEND_move_body,SEND_move_body移動發送,RECEVER_collision_fly碰撞接收,機台單純發送移動,送給move_list_signal做逐一送給飛碟做碰撞檢查,子彈打到最上方就從list移走並爆炸,否則送給move_list_signal做逐一送給飛碟做碰撞檢查,當飛碟檢查到碰撞發生時,RECEVER_collision_fly會收到信號,做碰撞後的後續處理,讓它爆炸,從list移走,增加分數,等等後續處理


##########################################移動發送,碰撞接收實作######################################################
    #接收移動動畫信號,移動物移動時會收到信號,送到move_list_signal作檢查,參數為移動物
    def SEND_move_body(self,move_object):

        #接到移動物,送過來信號,送給move_list_signal逐一檢查碰撞
      
        self.move_list_signal.check_collision(move_object,self.move_list_fly)
    #接收移動動畫信號,移動物移動時會收到信號,送到move_list_signal作檢查,參數為移動物
    def SEND_move_bullet(self,move_object):
        #print(move_object.get_xy()[1])
        #接到移動物,送過來信號,超過視窗上方就移走bullet,否則,送給move_list_signal逐一檢查碰撞
        if(move_object.get_xy()[1]<0-move_object .get_xy="" br="">            #True打到最上面會爆炸,設False到最上面不會爆炸
            if(move_object in self.move_list_bullet):self.move_list_signal.kill_move_obj(move_object,True,self.move_list_bullet)
        else:          
            self.move_list_signal.check_collision(move_object,self.move_list_fly)
    #接收移動物和碰撞物,碰撞時會收到信號,參數為移動物和碰撞物送給move_list_signal移走移動物,和碰撞物
    #飛碟是作碰撞,第一個參數傳本身,第2個參數傳實作移動,發送的是機台或子彈
    def RECEVER_collision_fly(self,c_object,move_object):
        #print(c_object.get_name())
        #更改了爆炸圖片,大隻飛碟爆炸不同
        if(c_object.get_name()=="logo4.png"):c_object.set_explosion_png("boom1.png")
      
        #self.move_body=None
        #從list中移走移動物,和碰撞物,True代表產生爆炸畫面,若不要爆炸畫面設False,注意是那個list移走,否則不會爆炸
        self.move_list_signal.kill_move_obj(c_object,True,self.move_list_fly)
        if(move_object in self.move_list_body):
            self.move_list_signal.kill_move_obj(move_object,True,self.move_list_body)
            self.GAME_OVER()
            self.score=0
        if(move_object in self.move_list_bullet):
            #設子彈爆炸不一樣,畫面較逼真
            #move_object.set_explosion_png("boom2.png")
            self.move_list_signal.kill_move_obj(move_object,True,self.move_list_bullet)
            self.score=self.score+1
            self.show_score()
            if(self.score>self.score_high):self.score_high=self.score#不要在執行續中呼叫
read more...

2015年2月19日 星期四

pygtk Cairo動畫(續)碰撞信號處理實做

程式原碼下載



我寫的move_object.py這模組,算蠻強大的,後續會應用這模組,製造更多動畫,主程式下面以move_object.py我製造一張會抖動的太空背景,因ubuntu1410,我先關掉抖動,後續在改,若是debian可把
          #self.move_obj_b.set_move_speed(.5)
          #self.move_obj_b.set_move_type("背景")
打開,就會有抖動效果,按方向建右鍵增加移動飛碟,若飛碟相撞會產生爆炸,並從視窗消失,按方向建左鍵移走飛碟

    #畫出背景
    def draw_background(self):
          p="background.png"
          #ubuntu1410 bug座標不能0,0
          self.move_obj_b=move_object.move_object(self,self.framme1,self.darea,p,1,1)
          #self.move_obj_b.set_move_to_xy(0,0) ubuntu1410 don't work跑到0,0會X error
          #若不要背景移動,下面不要設定
          #self.move_obj_b.set_move_speed(.5)
          #self.move_obj_b.set_move_type("背景")

    #畫出隨機飛碟
    def generate(self):
          p="logo"+str(random.randint(1,3))+".png"
          move_obj=move_object.move_object(self,self.framme1,self.darea,p)
          speed=float(random.randint(1,100))/100
          move_obj.set_move_speed(speed)
          if(random.randint(1,100) >50 ):
              move_obj.set_move_type("亂數")
          else:
              move_obj.set_move_type("直線X")
          #加到列表list
          self.move_list_signal.move_list_append(move_obj)


再來重要的動畫碰撞信號實做,來看看如何實做,到目前程式很少就做出了很複雜動作,其實在於邏輯是否夠好,可行,程式就會簡潔有力,在move_object.py修改了SEND_MOVE_SIGNAL方法,碰撞時呼叫self.main_obj.RECEVER否則呼叫self.main_obj.RECEVER_MOVE

    #碰撞時透過thread發送信號,把本身和碰撞物當參數,否則送出本身       
    def SEND_MOVE_SIGNAL(self):
        if(self.is_check_collision):
            self.main_obj.RECEVER(self,self.c_obj)
        else:
            self.main_obj.RECEVER_MOVE(self)


在move_object.py增加了碰撞方法,碰撞產生時self.is_check_collision=True,此時SEND_MOVE_SIGNAL改成呼叫self.main_obj.RECEVER,一開始self.is_check_collision=False

    def check_collision(self,other_obj):

         

          xo,yo=other_obj.get_xy()
          xo_w,yo_h=other_obj.get_width_height()
          xo1=xo+xo_w
          yo1=yo+yo_h
          #本身座標和寬高
          xs,ys=self.get_xy()
          xs_w,ys_h=self.get_width_height()
          xs1=xs+xs_w
          ys1=ys+ys_h
          #print(xo,yo,xo1,yo1,xs,ys,xs1,ys1)
          if(self.is_collision(xo,yo,xo1,yo1,xs,ys,xs1,ys1)):
              self.is_check_collision=True
              self.c_obj=other_obj
              self.set_move_type=None#碰撞後不要在移動了

在來看主程式,如何接收信號,非碰撞時接收RECEVER_MOVE,然後將移動物參數送給move_list_signal(類似界面),move_list_signal這個類,會將移動物送給各個移動物,做碰撞判斷,若主程式收到碰撞信號RECEVER,會透過move_list_signal這個類,會將移動物和被碰撞物刪除,並產生爆炸畫面,簡單邏輯,就能造成強大效果,做出複雜的動作,很神奇吧!


    #接收移動動畫信號,移動物移動時會收到信號,送到move_list_signal作檢查,參數為移動物
    def RECEVER_MOVE(self,move_object):

        #檢查碰撞,若不要檢查,忽略
        self.move_list_signal.check_collision(move_object)

    #接收移動動畫信號,移動物,和碰撞物碰撞時會收到信號,參數為移動物和碰撞物
    def RECEVER(self,move_object,c_object):
        #print(move_object.get_name())
        #從list中移走移動物,和碰撞物,True代表產生爆炸畫面,若不要爆炸畫面設False
        self.move_list_signal.kill_move_obj(move_object,True)
        self.move_list_signal.kill_move_obj(c_object,True)
  其餘看程式註解,下面是執行畫面


read more...

2015年2月18日 星期三

pygtk cairo動畫(續) BUG修正(debian 7.7 memory增加的問題),增加鍵盤事件

程式原碼下載


修正在debian7.7下,memory一直增加問題,以及所有OS,執行會漰潰的問題.


memory增加是deb7.7 pygtk3.0的問題,改用gtk2.0正常

執行會漰潰的問題是gtk button元件的問題(使用者一直按button可能crash),改用鍵盤正常

避開BUG,就可好好來使用pygtk cairo製作想要的動畫


鍵盤事件,如下,把key-press-event事件跟 self.window連結,指定處理方法on_key_down
這裡實做是放到move_list_singal模組中,當使用者按下方向鍵右鍵,增加一隻移動物,每支
移動物都有自己特徵,按下方向鍵左鍵,刪除一隻移動物,移動物速度都不一樣,移動方式目前有2種,亂移,跟水平亂移,要怎移動,只是在加上去


main.py
...................................................................................................................
        self.window.connect("key-press-event", self.on_key_down)
....................................................................................................................

    #處理鍵盤,由move_list_signal物件來實作,呼叫self.move_list_signal.on_key_down(event)
    def on_key_down(self, widget, event):
        key = event.keyval
        self.move_list_signal.on_key_down(event)
        #if key == gtk.keysyms.Right:self.generate()




move_list_signal.py
.................................
    #鍵盤事件,若想不同動作,可繼承複寫
    def on_key_down(self, event):
        key = event.keyval
        if key == gtk.keysyms.Right:
            self.main.generate()
        if key == gtk.keysyms.Left:
            self.kill_move_first()




要增加移動方式 ,self.move_type是設定type給begin_move方法來判斷,程式碼,都有詳細註解


    #移動方式
    def set_move_type(self, mtype):
        self.move_type=mtype


    def begin_move(self,):#不給type為靜止
        if(self.move_type=="亂數"):self.set_move_random()
        if(self.move_type=="直線X"):self.set_move_line_x_radom()
   

執行畫面



read more...