2015年11月17日 星期二

[Corona SDK] How to support multiple Ads networks - AdMob, iAds, Vungle

InHow to add advertisement in my APP - using AdMob V2, we learn how to add AdMob Ads.
For iAds and Vungle, we can use the similar way to add them.
We just consider how to support multiple networks here.
That it, we want to select AdMobiAds or Vungle dynamically, no matter it is for Fill Rate, eCPM or any other reasons.

Add plugin
First, we need add plug-in in build.settings:
settings =
{
 plugins =
    {
       ["plugin.google.play.services"] =
        {
            publisherId = "com.coronalabs"
        },
        ["CoronaProvider.ads.iads"] =
        {
            publisherId = "com.coronalabs",
            supportedPlatforms = { iphone=true, ["iphone-sim"]=true },
        },
        ["CoronaProvider.ads.vungle"] =
        {
            publisherId = "com.vungle",
        },      
    },
 android =
    {

        usesPermissions =
        {
            "android.permission.INTERNET",
            "android.permission.ACCESS_NETWORK_STATE",
        },
    },
}


Init the Ads
local adsProvider = {"adMob1","adMob2","vungle","iAds"} 
local ads = require( "ads" )
local adMobAdProvider = "admob"
local iAdsAdProvider = "iads"
local vungleAdProvider = "vungle"
local vungleAppId = "55e4xxxxxx"
local bannerAppID = "ca-app-pub-xxxxxx"
local interstitialAppID = "ca-app-pub-xxxxxx"
local appID = "com.gmail.MyCompany.App"
if ( isAndroid ) then
    bannerAppID = "ca-app-pub-xxxxx"
    interstitialAppID = "ca-app-xxxxxx"
    vungleAppId = "com.gmail.My_Company.App"
end
local lastAdsTypeShown = "none"
local currentAds = 1

local function adMobListener( event )
    local msg = event.response
    -- Quick debug message regarding the response from the library
    print( "Message from the adMob library: ", msg )
 if (event.type == "banner") then
     if ( event.isError ) then
         changeToNextAds()
     else
     end
 elseif(event.type == "interstitial") then
        if ( event.isError ) then
            changeToNextAds()
        elseif ( event.phase == "loaded" ) then
        elseif ( event.phase == "shown" ) then
        end
 end  
end

local function iAdsListener( event )
 local msg = event.response
 print("Message received from the iAds library: ", msg)
 if event.isError then
  changeToNextAds() 
 else
 end  
end

local function vungleListener( event )
   print("Message received from the vungleListener library: ", event.type)

   if ( event.type == "adStart" and event.isError ) then
     changeToNextAds()
   elseif ( event.type == "adEnd" ) then
      -- Ad was successfully shown and ended; hide the overlay so the app can resume.
   else
      print( "Received event", event.type )
   end
   return true
end

function adsInit()
 ads.init( adMobAdProvider, bannerAppID, adMobListener )
 if(isAndroid == false) then
   ads.init( iAdsAdProvider, appID, iAdsListener )    
 end
 ads.init( vungleAdProvider, vungleAppId, vungleListener )
end
We have to call ads.init() for AdMob,iAds and Vungle separately.
The parameters in their callback functions are different.
In above codes, we change to next Ads network when we get error.

Change Ads Network
We set new Ads network by function ads:setCurrentProvider().
local function changeToNextAds()
 currentAds = currentAds + 1
 if(currentAds > 3) then
  currentAds = 1
 end
 if(adsProvider[currentAds] == "iAds") then
  ads:setCurrentProvider(iAdsAdProvider)
 elseif(adsProvider[currentAds] == "vungle") then
  ads:setCurrentProvider(vungleAdProvider)
 else
  ads:setCurrentProvider(adMobAdProvider)
 end
end


Show Ads
function showAds(type,px,py)
 if(adsProvider[currentAds] == "adMob") then
  if(type == "banner") then
   ads.show( type, { x=px, y=py, appId=bannerAppID} )
   return true
  elseif(type == "interstitial") then    
   if(ads.isLoaded(type))then
    ads.show( type, { x=px, y=py, appId=interstitialAppID } )
    return true
   else
    return false
   end 
  end 
 elseif(adsProvider[currentAds] == "vungle") then
  if (type == "interstitial" and ads.isAdAvailable() ) then
      ads.show( "interstitial" )
      return true
  else
   return false
  end   
 elseif(adsProvider[currentAds] == "iAds") then
  ads.show( type, { x=px, y=py} )
  return true
 end
 return false  
end

function loadAds()
 if(adsProvider[currentAds] == "adMob") then
  ads.load( "interstitial", { appId=interstitialAppID} )
 end
end 
Vungle does not have Banner Ads and it will pre-load interstitial Ads itself.
iAds cannot pre-load interstitial Ads,
The codes shown above are very completed. 
You can just copy them directly and make it work.

[Corona SDK] 如何支援多個廣告系統 - AdMob, iAds, Vungle

如何加入廣告 - AdMob V2裡,
我們知道要如何加入AdMob Ads,
要加入iAdsVungle的話,作法很類似,
在這裡我們討論如果要同時支援的話該如何處理,
也就是說,我們可以動態選擇 AdMob, iAds, Vungle,
不管是因為Fill Rate, eCPM或者其它原因...

Add plugin
首先,我們需要在build.settings加入plug-in:
settings =
{
 plugins =
    {
       ["plugin.google.play.services"] =
        {
            publisherId = "com.coronalabs"
        },
        ["CoronaProvider.ads.iads"] =
        {
            publisherId = "com.coronalabs",
            supportedPlatforms = { iphone=true, ["iphone-sim"]=true },
        },
        ["CoronaProvider.ads.vungle"] =
        {
            publisherId = "com.vungle",
        },      
    },
 android =
    {

        usesPermissions =
        {
            "android.permission.INTERNET",
            "android.permission.ACCESS_NETWORK_STATE",
        },
    },
}
另外,Android需要增加網路存取的權限

Init the Ads
local adsProvider = {"adMob1","adMob2","vungle","iAds"} 
local ads = require( "ads" )
local adMobAdProvider = "admob"
local iAdsAdProvider = "iads"
local vungleAdProvider = "vungle"
local vungleAppId = "55e4xxxxxx"
local bannerAppID = "ca-app-pub-xxxxxx"
local interstitialAppID = "ca-app-pub-xxxxxx"
local appID = "com.gmail.MyCompany.App"
if ( isAndroid ) then
    bannerAppID = "ca-app-pub-xxxxx"
    interstitialAppID = "ca-app-xxxxxx"
    vungleAppId = "com.gmail.My_Company.App"
end
local lastAdsTypeShown = "none"
local currentAds = 1

local function adMobListener( event )
    local msg = event.response
    -- Quick debug message regarding the response from the library
    print( "Message from the adMob library: ", msg )
 if (event.type == "banner") then
     if ( event.isError ) then
         changeToNextAds()
     else
     end
 elseif(event.type == "interstitial") then
        if ( event.isError ) then
            changeToNextAds()
        elseif ( event.phase == "loaded" ) then
        elseif ( event.phase == "shown" ) then
        end
 end  
end

local function iAdsListener( event )
 local msg = event.response
 print("Message received from the iAds library: ", msg)
 if event.isError then
  changeToNextAds() 
 else
 end  
end

local function vungleListener( event )
   print("Message received from the vungleListener library: ", event.type)

   if ( event.type == "adStart" and event.isError ) then
     changeToNextAds()
   elseif ( event.type == "adEnd" ) then
      -- Ad was successfully shown and ended; hide the overlay so the app can resume.
   else
      print( "Received event", event.type )
   end
   return true
end

function adsInit()
 ads.init( adMobAdProvider, bannerAppID, adMobListener )
 if(isAndroid == false) then
   ads.init( iAdsAdProvider, appID, iAdsListener )    
 end
 ads.init( vungleAdProvider, vungleAppId, vungleListener )
end
我們需要針對AdMob,iAdsVungle各自呼叫ads.init()
因為callback回傳的參數不同,所以各自傳入不同callback function,
上面的程式裡,我們在callback function裡發現有錯誤時就換下一個Ads,
至於changeToNextAds()是什麼,看下一段

Change Ads Network
local function changeToNextAds()
 currentAds = currentAds + 1
 if(currentAds > 3) then
  currentAds = 1
 end
 if(adsProvider[currentAds] == "iAds") then
  ads:setCurrentProvider(iAdsAdProvider)
 elseif(adsProvider[currentAds] == "vungle") then
  ads:setCurrentProvider(vungleAdProvider)
 else
  ads:setCurrentProvider(adMobAdProvider)
 end
end
我們透過呼叫ads:setCurrentProvider()來設定新的Ads Network,

Show Ads
function showAds(type,px,py)
 if(adsProvider[currentAds] == "adMob") then
  if(type == "banner") then
   ads.show( type, { x=px, y=py, appId=bannerAppID} )
   return true
  elseif(type == "interstitial") then    
   if(ads.isLoaded(type))then
    ads.show( type, { x=px, y=py, appId=interstitialAppID } )
    return true
   else
    return false
   end 
  end 
 elseif(adsProvider[currentAds] == "vungle") then
  if (type == "interstitial" and ads.isAdAvailable() ) then
      ads.show( "interstitial" )
      return true
  else
   return false
  end   
 elseif(adsProvider[currentAds] == "iAds") then
  ads.show( type, { x=px, y=py} )
  return true
 end
 return false  
end

function loadAds()
 if(adsProvider[currentAds] == "adMob") then
  ads.load( "interstitial", { appId=interstitialAppID} )
 end
end 
Vungle沒有Banner Ads, 它自己會pre-load interstitial Ads,
iAds無法pre-load interstitial Ads,
上面的說明應該很完整,
基本上只要照抄就可以了

2015年11月16日 星期一

[Corona SDK] How to add Apple Game Center and Android Google Play Game Service

For Apple Game Center or Android Google Play Game Service, 
we just need to utilize the function of gameNetwork.
It is not difficulty to implement them.
To consider Apple and Google at the same time, 
let's check the codes first and see how them work:
local gameNetwork = require( "gameNetwork" )
local playerName
local playerId

local leaderboardsListId=
{
 ["HighestScore"]=
 {
  ["Description"] = "Highest Score",
  ["Identifier"] = "com.gmail.mycom.demo.Leaderboards.HighestScore"
 }
}

local achievementsListId = 
{
 ["FinishLevel1"]=
 {
  ["Description"] = "Finish Level 1",
  ["Identifier"] = "com.gmail.mycom.demo.Achievements.FinishLevel1"
 },
 ["FinishLevel2"]=
 {
  ["Description"] = "Finish Level 2",
  ["Identifier"] = "com.gmail.mycom.demo.Achievements.FinishLevel2"
 }
}

if(isAndroid) then
 leaderboardsListId=
 {
  ["HighestScore"]=
  {
   ["Description"] = "Highest Score",
   ["Identifier"] = "Cgkxxxxxxxx"
  }
 }

 achievementsListId = 
 {
  ["FinishLevel1"]=
  {
   ["Description"] = "Finish Level 1",
   ["Identifier"] = "Cgkxxxxxxx"
  },
  ["FinishLevel2"]=
  {
   ["Description"] = "Finish Level 2",
   ["Identifier"] = "Cgkxxxxxxxx"
  }
 }
end



function showLeaderboards( event )
 print("showLeaderboards()")
 if (playerId ~= nil) then
    if ( isAndroid ) then
       gameNetwork.show( "leaderboards" )
    else
       gameNetwork.show( "leaderboards", { leaderboard = {timeScope="AllTime"} } )
    end
 else
  gameNetworkSetup()
 end
    return true
end

local function postScoreSubmit( event )
   --whatever code you need following a score submission...
   return true
end

local function updateLeaderBoards(type, myScore)
 if (playerId == nil) then
  return
 end

 gameNetwork.request( "setHighScore",
 {
    localPlayerScore = { category=leaderboardsListId[type]["Identifier"], value=tonumber(myScore) },
    listener = postScoreSubmit
 } )
 print("gameNetwork.request( setHighScore) finished")
end

function showAchievements( event )
 print("showAchievements()")
 if (playerId ~= nil) then
    gameNetwork.show( "achievements" )
 else
  gameNetworkSetup()
 end
    return
end

local function achievementRequestCallback( event )
   
   return true
end

local function updateAchievement(type)
 if (playerId == nil) then
  return
 end
 gameNetwork.request( "unlockAchievement",
 {
    achievement = { identifier=achievementsListId[type]["Identifier"], percentComplete=100, showsCompletionBanner=true },
    listener = achievementRequestCallback
 } )
end

local function loadScoresCallback( event ) 
 if(event.data == nil) then
  print("event.data is nil")
  return
 end
 for i=1,25 do
  if(event.data[i] == nil) then
   break
  end
  print("event.data[",i,"].playerID:",event.data[i].playerID)
  print("event.data[",i,"].category:",event.data[i].category)
  if(event.data[i].playerID == playerId) then
   print("matched playID...........")
   break
  end
 end
end

local function loadLocalPlayerCallback( event ) 
 if(event.data == nil) then
  print("event.data is nil")
  return
 end

 playerId = event.data.playerID
 playerName = event.data.alias
 print("loadLocalPlayerCallback(),playerName:",playerName,",playerId:",playerId)
 if(playerId == nil) then
  return
 end
 myGameSettings.gameCerterHasEverLoggedIn = true
 saveData()   

 gameNetwork.request( "loadScores",
            {
                leaderboard =
                {
                    category = leaderboardsListId["HighestScore"]["Identifier"], 
                    playerScope = "Global",   -- Global, FriendsOnly
                    timeScope = "AllTime",    -- AllTime, Week, Today
                    --range = {1,5},
                    playerCentered = true,
                },
                listener = loadScoresCallback
            }) 
end

local function loadAchievementCallback( event )    
 if(event.data == nil) then
  print("event.data is nil")
  return
 end

 for i=1,#event.data do
  if(event.data[i] ~= nil) then
   print("event.data[",i,"].identifier:",event.data[i].identifier)
   print("event.data[",i,"].title:",event.data[i].title)
   print("event.data[",i,"].isCompleted:",event.data[i].isCompleted)
  end
 end 
end

local function gameNetworkLoginCallback( event )
 if(isAndroid==false) then
  if(event.data) then
   print("User has logged into iOS Game Center")
  else
   print("User has NOT logged into iOS Game Center")
   return 
  end
 end
 gameNetwork.request( "loadLocalPlayer", { listener=loadLocalPlayerCallback } )
 gameNetwork.request( "loadAchievements", { listener=loadAchievementCallback } )
 return true
end

local function gpgsInitCallback( event )
 if(event.data) then
  print("User has logged into Google App Play Center")
     gameNetwork.request( "login", { userInitiated=true, listener=gameNetworkLoginCallback } )
 else
  print("User has NOT logged into Google App Play Center")
 end
end

function gameNetworkSetup()
 if ( isAndroid ) then
  myGameSettings.gameCerterHasEverLoggedIn = false
  gameNetwork.init( "google", gpgsInitCallback )
 else
  gameNetwork.init( "gamecenter", gameNetworkLoginCallback )
 end
end
}
Init
In general, we can call gameNetworkSetup() in main.lua
For Android, we need to check if we have logged in successfully in gpgsInitCallback().
For iOS, we need to check if we have logged in successfully in gameNetworkLoginCallback().
The code gameNetwork.request( "loadLocalPlayer", { listener=loadLocalPlayerCallback } ) is to confirm the user who logs in.
You can go without it.
The code gameNetwork.request( "loadAchievements", { listener=loadAchievementCallback } ) is to recover the users's records.
For example, users may have ever installed this APP, remove this APP, and re-install it again.
If you think that you don't need to recover the records for them, you can go with it.

Show leaderboard
To show the leaderboard, we just need to call function showLeaderboards().
In general, we do it when user press some button

Show achievement
To show the leaderboard, we just need to call function showAchievements().
In general, we do it when user press some button.

Update leaderboard

To update leaderboard, we just need to call function updateLeaderBoards().
In general, wwe do it when user finish the game.

Update achievements 

To update leaderboard, we just need to call function updateAchievement().
In general, wwe do it when user finish some round.


Below are what differ between Apple Game Center and Android Google Play Game Service:
Apple Game Center
The data in leaderboardsListId{} and achievementsListId{}:
e.g. "com.gmail.mycom.demo.Leaderboards.HighestScore".
They are user defined, as long as they are  not duplicated.

Google Play Game Service
The data in leaderboardsListId{} and achievementsListId{}:
e.g. "Cgkxxxxxxxx".
They are defined by play store publish when you finished the setting in game center.
For Google Play Game Service, we also need to add the googlePlayGamesAppId in build.settings:
android =
    {
        usesPermissions =
        {
            "android.permission.INTERNET",
            "android.permission.ACCESS_NETWORK_STATE",
            "com.android.vending.BILLING",
        },
        googlePlayGamesAppId = "123456789012" 
    },
usesPermissions are not concerned for game service,
googlePlayGamesAppId is what you get when you link the APP in play store publish game center.

[Corona SDK] 如何加入Apple Game Center 和 Android Google Play Game Service

不管是AppleGame Center,還是AndroidGoogle Play Game Service
基本上都是利用gameNetwork的功能即可,
實作不難,考慮同時支援AppleGoogle
先將程式碼貼上再來講解:
local gameNetwork = require( "gameNetwork" )
local playerName
local playerId

local leaderboardsListId=
{
 ["HighestScore"]=
 {
  ["Description"] = "Highest Score",
  ["Identifier"] = "com.gmail.mycom.demo.Leaderboards.HighestScore"
 }
}

local achievementsListId = 
{
 ["FinishLevel1"]=
 {
  ["Description"] = "Finish Level 1",
  ["Identifier"] = "com.gmail.mycom.demo.Achievements.FinishLevel1"
 },
 ["FinishLevel2"]=
 {
  ["Description"] = "Finish Level 2",
  ["Identifier"] = "com.gmail.mycom.demo.Achievements.FinishLevel2"
 }
}

if(isAndroid) then
 leaderboardsListId=
 {
  ["HighestScore"]=
  {
   ["Description"] = "Highest Score",
   ["Identifier"] = "Cgkxxxxxxxx"
  }
 }

 achievementsListId = 
 {
  ["FinishLevel1"]=
  {
   ["Description"] = "Finish Level 1",
   ["Identifier"] = "Cgkxxxxxxx"
  },
  ["FinishLevel2"]=
  {
   ["Description"] = "Finish Level 2",
   ["Identifier"] = "Cgkxxxxxxxx"
  }
 }
end



function showLeaderboards( event )
 print("showLeaderboards()")
 if (playerId ~= nil) then
    if ( isAndroid ) then
       gameNetwork.show( "leaderboards" )
    else
       gameNetwork.show( "leaderboards", { leaderboard = {timeScope="AllTime"} } )
    end
 else
  gameNetworkSetup()
 end
    return true
end

local function postScoreSubmit( event )
   --whatever code you need following a score submission...
   return true
end

local function updateLeaderBoards(type, myScore)
 if (playerId == nil) then
  return
 end

 gameNetwork.request( "setHighScore",
 {
    localPlayerScore = { category=leaderboardsListId[type]["Identifier"], value=tonumber(myScore) },
    listener = postScoreSubmit
 } )
 print("gameNetwork.request( setHighScore) finished")
end

function showAchievements( event )
 print("showAchievements()")
 if (playerId ~= nil) then
    gameNetwork.show( "achievements" )
 else
  gameNetworkSetup()
 end
    return
end

local function achievementRequestCallback( event )
   
   return true
end

local function updateAchievement(type)
 if (playerId == nil) then
  return
 end
 gameNetwork.request( "unlockAchievement",
 {
    achievement = { identifier=achievementsListId[type]["Identifier"], percentComplete=100, showsCompletionBanner=true },
    listener = achievementRequestCallback
 } )
end

local function loadScoresCallback( event ) 
 if(event.data == nil) then
  print("event.data is nil")
  return
 end
 for i=1,25 do
  if(event.data[i] == nil) then
   break
  end
  print("event.data[",i,"].playerID:",event.data[i].playerID)
  print("event.data[",i,"].category:",event.data[i].category)
  if(event.data[i].playerID == playerId) then
   print("matched playID...........")
   break
  end
 end
end

local function loadLocalPlayerCallback( event ) 
 if(event.data == nil) then
  print("event.data is nil")
  return
 end

 playerId = event.data.playerID
 playerName = event.data.alias
 print("loadLocalPlayerCallback(),playerName:",playerName,",playerId:",playerId)
 if(playerId == nil) then
  return
 end
 myGameSettings.gameCerterHasEverLoggedIn = true
 saveData()   

 gameNetwork.request( "loadScores",
            {
                leaderboard =
                {
                    category = leaderboardsListId["HighestScore"]["Identifier"], 
                    playerScope = "Global",   -- Global, FriendsOnly
                    timeScope = "AllTime",    -- AllTime, Week, Today
                    --range = {1,5},
                    playerCentered = true,
                },
                listener = loadScoresCallback
            }) 
end

local function loadAchievementCallback( event )    
 if(event.data == nil) then
  print("event.data is nil")
  return
 end

 for i=1,#event.data do
  if(event.data[i] ~= nil) then
   print("event.data[",i,"].identifier:",event.data[i].identifier)
   print("event.data[",i,"].title:",event.data[i].title)
   print("event.data[",i,"].isCompleted:",event.data[i].isCompleted)
  end
 end 
end

local function gameNetworkLoginCallback( event )
 if(isAndroid==false) then
  if(event.data) then
   print("User has logged into iOS Game Center")
  else
   print("User has NOT logged into iOS Game Center")
   return 
  end
 end
 gameNetwork.request( "loadLocalPlayer", { listener=loadLocalPlayerCallback } )
 gameNetwork.request( "loadAchievements", { listener=loadAchievementCallback } )
 return true
end

local function gpgsInitCallback( event )
 if(event.data) then
  print("User has logged into Google App Play Center")
     gameNetwork.request( "login", { userInitiated=true, listener=gameNetworkLoginCallback } )
 else
  print("User has NOT logged into Google App Play Center")
 end
end

function gameNetworkSetup()
 if ( isAndroid ) then
  myGameSettings.gameCerterHasEverLoggedIn = false
  gameNetwork.init( "google", gpgsInitCallback )
 else
  gameNetwork.init( "gamecenter", gameNetworkLoginCallback )
 end
end
}
初始化
一般來說,我們可以在main.lua裡呼叫gameNetworkSetup(),
對於Android系統,在gpgsInitCallback()裡可以確認是否登錄成功
對於iOS系統,在gameNetworkLoginCallback()裡可以確認是否登錄成功,
至於後面的gameNetwork.request( "loadLocalPlayer", { listener=loadLocalPlayerCallback } )
是用來確認目前登錄遊戲中心的使用者,有沒有呼叫它都可以,
gameNetwork.request( "loadAchievements", { listener=loadAchievementCallback } )則是用來回復使用者的紀錄, 例如使用曾經安裝過這個APP,移除它後又重新下載, 如果不想幫使用者回復紀錄,不執行也可以

顯示排行榜(leaderboard)
想要顯示排行榜,只要呼叫showLeaderboards()即可, 通常這個動作是在使用者按下某個按鈕時

顯示任務(achievement)
想要顯示排行榜,只要呼叫showAchievements()即可, 通常這個動作是在使用者按下某個按鈕時

更新排行榜 想要更新排行榜,只要呼叫updateLeaderBoards()即可, 通常這個動作是在使用者完成遊戲時

更新任務 想要更新排行榜,只要呼叫updateAchievement()即可, 通常這個動作是在使用者完成某個關卡時


以下是AppleGame Center,和AndroidGoogle Play Game Service稍有不同的地方
Apple Game Center
leaderboardsListId{}achievementsListId{}裡的資料, 例如"com.gmail.mycom.demo.Leaderboards.HighestScore", 這是使用者自己決定的編碼,然後在iTunes Connect裡設定即可, 不重覆就行

Google Play Game Service
leaderboardsListId{}和achievementsListId{}裡的資料,
例如"Cgkxxxxxxxx", 這是使用者在play store publish的遊戲中心設定後系統給的編碼, 另外,對於Google Play Game Service, 我們還需要在build.settings增加:
android =
    {
        usesPermissions =
        {
            "android.permission.INTERNET",
            "android.permission.ACCESS_NETWORK_STATE",
            "com.android.vending.BILLING",
        },
        googlePlayGamesAppId = "123456789012" 
    },
usesPermissions無所謂,
googlePlayGamesAppId是在play store publish的遊戲中心連結應用程式後系統給的編碼

[ 遊戲 ] 空戰 - 火力全開


https://www.facebook.com/Air-Fight-Infinite-Power-189988404668625/

你有無盡的火力來消滅敵人戰機。
小心接踵而來的敵機和巨量的子彈攻擊,
當你有危險時,不要遲疑,趕快發射炸彈來保護你自己。

如果你喜歡射擊遊戲,那你一定會喜歡這個APP。

[ Game ] Air Fight - Infinite Power



https://www.facebook.com/Air-Fight-Infinite-Power-189988404668625/


You have infinite power to clear the enemies.

Be careful of consecutive enemy fighters and massive bullets.
Don't hesitate to shoot the bomb when you are in danger.

If you like shooting game, you will love this app.

[ 遊戲 ] 桌上撞盤


https://www.facebook.com/Table-Discs-1477277249248292


這是一個有趣的新型態遊戲。

第一眼看起有點像撞球中的開侖,
但是它其實更為簡單且好玩。

你不需要有什麼開超的撞球技巧,
只要將白盤射出,讓它撞到紅盤即可。

當然,這中間一定會有許多的障礙來阻撓你...

[ Game ] Table Discs


https://www.facebook.com/Table-Discs-1477277249248292


This is an interesting game in new type.
It look like Carom at first sight.
However, it is easier and has more fun.

You don't need to have good skills for billiards game.
Just shoot the white disc and let it collide with red disc.

Of course, there will have some obstacles to interfere with your movement.

[ 遊戲 ] 推推樂



https://www.facebook.com/pages/Push-Discs/1632278527059052

想要運動您的手指嗎?
"推推樂"是一個簡單好玩但又充滿挑戰性的遊戲。
它支援Google遊戲中心。
快邀請您的朋友一同來挑戰它。

[ Game ] Push Discs


https://www.facebook.com/pages/Push-Discs/1632278527059052

Want to exercise your finger?
"Push Discs" is a simple but full of challenging game.
It supports Google Play Game Services.
Invite your friends to challenge it together.

[ 遊戲 ] 單字矩陣無限玩



https://www.facebook.com/Infinite-Word-Matrix-3-letters-874519139268720/

你認識很多3個字母的單字嗎?

這太簡單了吧?要拼出3個字的單字實在沒什麼難度,
不過,其實這會比你想像中的困難,
因為3個字的單字比你想像中的少,
再者,有些字又很相似,
例如 "ria","rib","rid","rif","rig","rim","rip"....
我們可能會認為 "rie", "rit"等等也都是有意義的單字,
但...其實不然。

這個APP不只是個好玩的拼字遊戲,也是一個幫助你練習和覆習拼字的工具。

[ Game ] Infinite Word Matrix


https://www.facebook.com/Infinite-Word-Matrix-3-letters-874519139268720/


How many words in 3 letters do you know?

You may think that it is easy to spell out the words in 3 letters.
However, the number of words in 3 letters is less than you expect.
Furthermore, many words are similar except for one letter difference.
For example, "ria","rib","rid","rif","rig","rim","rip"....
We may think that there should have words such as "rie", "rit".
But...you get the wrong answers.


This APP is not only a game for fun, it is also a tester, reminder for you to improve your spell skill.

[ 遊戲 ] 撲克陣列



https://www.facebook.com/Infinite-Poker-Matrix-1591171817815298

一個玩不停的撲克遊戲。
你只要點選任何5張牌即可。

牌面越大,你得到的金幣就會越多。
不過,當你在選擇牌時,你必須同時考慮下一次的5張牌應該是什麼。
這是一個完全免費的遊戲。

[ Game ] Infinite Poker Matrix


https://www.facebook.com/Infinite-Poker-Matrix-1591171817815298

An endless poker game.
Just pick any five cards.
The better combination, the more coins you get.
However, when you pick current 5 cards, you should also consider that what will the next 5 cards be.
This is a totally free game.

[ 遊戲 ] 快樂兔遊隧道


https://www.facebook.com/Happy-Bunny-Tunnel-Surf-1477746165886686


快樂兔正在隧道內快樂的遊玩。
胡蘿蔔仍然是她的最愛。

快樂兔正在隧道內快樂的遊玩。
胡蘿蔔仍然是她的最愛。

[ Game ] Happy Bunny - Tunnel Surf


https://www.facebook.com/Happy-Bunny-Tunnel-Surf-1477746165886686


Happy Bunny is playing in the tunnel.
Carrot is still her favorite.

She can jump...
She can change tunnel...
She can also do these two thing at the same time.

The is a brand new type game.
We believe that you can enjoy playing it for a long time.

[ 遊戲 ] 快樂兔動動腦


https://www.facebook.com/pages/Happy-Bunny-Rack-Brain/1482173925439162


你曾經擠破腦袋也記不住某些事?

它真是一個惡夢啊...
老是記了就忘,
再記...還是忘...
有什麼簡單的方法可以改善嗎?

當然可以,
我們可以藉由這個遊戲來活絡我們的大腦,
它會加強所謂的右腦圖像記憶。

記住,不要把它當成訓練,
用玩遊戲的輕鬆心情去完成它,
無形中,你會發現你的瞬間記憶變強了,
讓我們一起試試吧!

[ Game ] Happy Bunny - Rack Brain


https://www.facebook.com/pages/Happy-Bunny-Rack-Brain/1482173925439162

Have you ever racked your brain for trying to remember something?

It's a nightmare for most of us.
Can we improve our memory skill in easy way?

Yes, we can.
Let's activate our brain just by playing this game.
It can strengthen your ability of brain imaging memory.
Try it now!

[ 遊戲 ] https://www.facebook.com/Happy-Bunny-Dodge-Game-124867114526322


https://www.facebook.com/Happy-Bunny-Dodge-Game-124867114526322

好玩的快樂兔將會讓你一玩就停不下來。

當你玩這個遊戲時,你會很驚訝時間怎麼會過得這麼快。
它是一款無止盡的遊戲,
只能你能,你想玩多久就玩多久。
準備好了嗎?來和我們一起玩吧....

[ Game ] Happy Bunny - Dodge Game


https://www.facebook.com/Happy-Bunny-Dodge-Game-124867114526322

The interesting game "Happy Bunny Go" will let you never stop playing.
You will be surprised that time passes so fast when you play this game.
It is an endless game.
You can play as long as you can.
Ready? Come play with us...

[ 遊戲] 我是直升機駕駛高手 - 城市冒險

https://www.facebook.com/Fly-Helicopter-City-Adventure-1503841246594029

你可以駕駛直升機通過不同的地形?

就這樣嗎?
當然不止....
你需要盡可能避開敵人的直升機,為了您的安全。
與此同時,噴氣戰鬥機正以可怕的速度接近你。
隨時注意轟炸機,否則你會被空投的炸彈炸飛。
地上的高射砲會一直瞄準你,無論你如何移動。

請記住,盡可能收集硬幣,越多越好。
這些金幣可以換成續關鑰匙。

[ Game ] Fly Helicopter-City Adventure

 https://www.facebook.com/Fly-Helicopter-City-Adventure-1503841246594029

Can you fly the helicopter to pass different kinds of terrain?

Is that all?
Of course not ....
You need to avoid the enemy helicopters as far as possible, for your safety.
At the same time, the jet planes are approaching you in terrible speed.
Watch out the bomber any time, or you will be attacked by the air bomb.
The antiaircraft gun is always aiming at you no matter how you move.

Remember to collect the coins as more as possible.
They can be exchanged for key, which will save your life.

[遊戲] 圓盤保齡球


https://www.facebook.com/Discs-Bowling-879320752188039/


這是一個用圓盤來玩的保齡球遊戲

它的規則和一般的保齡球玩法一樣,
不過,你可以更簡單的控制它,包括方向,力道,移動的弧度等等。
有二種挑戰,標準賽和障礙賽。
找個休間時間,好好來享受這個遊戲的樂趣吧...

[Game] Discs Bowling


https://www.facebook.com/Discs-Bowling-879320752188039/


This is a bowling game played with discs.
The rule is the same as typical bowling game.
However, you can control it in easier method, including direction, strength, moving curve....and so on.
There have two types of challenges, Standard Race and Obstacle Race.
Take your time and enjoy this game....

[Game] Crazy Racing - Keep Speeding


https://www.facebook.com/Crazy-Racing-Keep-Speeding-1691066911114797


Crazy racing is coming again...
The is a racing game without speed limitation.
As the speed increasing, you will have less and less time to respond.
You will feel excited if you like the crazy speed.

Remember to collect the coins as more as possible.
They can be exchanged for key, which will save your life.

[遊戲] 瘋狂賽車 - 超越極速




瘋狂賽車又來了...
這是一個沒有速度極限的賽車遊戲。

隨著速度越來越快,你將需要更快的反應。
如果你喜歡這種瘋狂的速度感,本遊戲會讓你感到興奮。

請記住,盡可能收集硬幣,越多越好。
這些金幣可以換成續關鑰匙。

[遊戲] 瘋狂直昇機 - 城市戰爭





這一次,你的直昇機已裝上武器...

你有機關槍可以用極為強大的速度射出子彈,
只要你適時的補充,這些子彈是打不完的。

你有飛彈可以用來擊落轟炸機,或用來消滅地上的坦克車,
當然,你也可以用飛彈來清除任何擋在你前面的障礙物。

還有一個所謂的無敵模式,
在這模式下,你是不受任何敵方的武器所攻擊,也可穿越任何的障礙物..

讓我們一起來戰鬥吧,盡情享受殺敵的快感.....

[Game] Crazy Helicopter - City War





This time, your helicopter is armed.

You have machine gun to shoot the bullets in powerful speed.
The bullets will not run out of as long as you refill them in time.

You have missiles to shoot down the bomber or to destroy the tank.
Of course, you can also use missiles to clear any obstacles in front of you.

When you are in super mode, you are invincible and have endless bullets and missiles.
Let's fight together......