2014년 9월 12일 금요일

2014년 7월 31일 목요일

ios에서 cocos2d-x(3.x)의 game view를 특정 뷰의 child view에 붙이기

cocos2d-x의 게임뷰를 특정 뷰의 child뷰로 가져오기 위한 방법입니다.
(cocos2d-x 3.2 버전 기준)


1. cocos2d-x기반의 빈 프로젝트(hello world)를 만듭니다.

2. AppController.mm의 didFinishLaunchingWithOptions 함수 안에
GLView를 생성하고 싱글톤 객체인 cocos2d::Director를 구동하는 코드가 있는데
여기서 이것들을 하면 안되니 모두 지워버립니다. ㅎㅎ

나머지 applicationDidEnterBackground, applicationWillEnterForeground 등의 함수안의 코드는 그냥 그대로 둡니다.


3. 새로운 컨트롤러(이하 CustomViewController)를 만들고 게임뷰를 담을 UIVIew(이하 viewGLViewContainter)객체를 하나 만들어 놓습니다.


4. CustomViewController 소스에서 아래 두 함수를 통해 게임뷰를 생성하여 viewGLViewContainter붙이고 정리하는 코드를 추가합니다.
- (void)viewWillAppear:(BOOL)animated
- (void)viewWillDisappear:(BOOL)animated

소스파일(CustomViewController.mm 소스 파일)에 아래 2개의 헤더를 import합니다.
- cocos2dx의 cpp코드를 사용해야 하니 mm 파일로 만들어야 합니다.

#import "cocos2d.h"
#import "CCEAGLView.h"


viewWillAppear함수에 아래 코드를 추가합니다.
- (void)viewWillAppear:(BOOL)animated
{
    [super viewWillAppear:animated];
    
    // Init the CCEAGLView
    CCEAGLView *eaglView = [CCEAGLView viewWithFrame: self.viewGLViewContainter.bounds
                             pixelFormat: kEAGLColorFormatRGBA8
                             depthFormat: GL_DEPTH24_STENCIL8_OES
                      preserveBackbuffer: NO
                              sharegroup: nil
                           multiSampling: NO
                         numberOfSamples: 0];
    
   
    [self.viewGLViewContainter addSubview:eaglView];

    cocos2d::GLView *glview = cocos2d::GLView::createWithEAGLView(eaglView);
    cocos2d::Director::getInstance()->setOpenGLView(glview);
    
    cocos2d::Application::getInstance()->run();
}

viewWillDisappear함수에 아래 코드를 추가합니다.
- (void)viewWillDisappear:(BOOL)animated
{
    cocos2d::Director::getInstance()->end();

    cocos2d::Director::getInstance()->mainLoop();

    [super viewWillDisappear:animated];
}


정상적이라면 아래와 유사한 화면을 볼 수 있겠습니다.


2014년 7월 30일 수요일

Genymotion Google Play 스토어 설치하기

Genymotion는 구글 플레이스토어를 제공하지 않습니다.
아래와 같은 절차로 스토어 앱을 설치할 수 있습니다.
  1. genymotion 과 VirtualBox을 최신버전으로 업그레이드 합니다.
  2. 두개의 파일을 다운로드 합니다.
    ARM Translation Installer v1.1  http://filetrip.net/dl?4SUOrdcMRv
      arm기반 프로그램을 x86으로 변환해주기 위해 필요합니다.
    -
    Google Apps for Android 4.4 - http://wiki.cyanogenmod.org/w/Google_Apps#gappsCM11  
  3. genymotion 에뮬레이터를 열고 홈스크린으로 이동합니다.Genymotion-ARM-Translation_v1.1.zip 홈파일을 홈스크린에 드레그&드롭합니다.
    파일 작업을 위한 다이알로그가 나타나고 작업진행을 묻는 다이알로그가 나타납니다.
    OK를 누르고 genymotion을 재구동합니다.(adb reboot명령을 쓰거나 아예 다시 띄우거나...)
  4. 다음으로 스토어앱 파일인  gapps-kk-signed.zip 을 위(3)와 같은 방법으로 설치합니다.
  5. 'Google Apps Services'의 크래쉬가 반복적으로 나타나는데  스토어 앱을 열어 계정을 설정하고 구글 스토어앱을 상위버전으로 업데이트 하면 더이상 크래쉬 오류가 발생하지 않습니다.

2014년 7월 5일 토요일

xcode script build phase를 이용해서 build-date 앱에 기록하기

xcode프로젝트 셋팅에 들어가서
Build Phase를 선택합니다.

좌상단의 + 버튼을 눌러 'New Run Script Build Phase' 선택합니다.

shell  /bin/sh 아래 입력창에 다음 내용을 추가합니다.

builddate=`date "+%Y-%m-%d %H:%M:%S"`
if [[ -n "$builddate" ]]; then
# if BuildDateString doesn't exist, add it
/usr/libexec/PlistBuddy -c "Add :BuildDateString $builddate" "${PROJECT_DIR}/${INFOPLIST_FILE}"
# and if BuildDateString already existed, update it
/usr/libexec/PlistBuddy -c "Set :BuildDateString $builddate" "${PROJECT_DIR}/${INFOPLIST_FILE}"

fi;

빌드 타임에 해당 스크립트가 수행되면서 현재 날자를
'1999-01-01 12:00:00'과 같은 형식으로 info.plist파일에 추가하게 됩니다.
이때 추가되는 키는 BuildDataString입니다.

앱 코드에서는 다음과 같이 간단히 빌드날자를 얻어올 수 있습니다.

buildDate = [[[NSBundle mainBundle] infoDictionary] objectForKey:@"BuildDateString"];


* 위 내용은 xcode 5.1.1 버전에서 검토한 내용입니다.

2014년 5월 27일 화요일

Blender를 이용해서 2D Image를 3D Object로 만들기..

대상이 되는 이미지를 SVG(Scalable Vector Graphics) 이미지로 변환
 - 각종 툴이나 웹상에서 바로 바꿔주는 다양한 방법이 있음(검색 검색~)
 - 찾은거 하나 : http://image.online-convert.com/convert-to-svg

아래 블렌더에서 svg를 3D object로 바꾸는 훌륭한 유투브 동영상이 있음.
 - http://www.youtube.com/watch?v=ows2QTiMRPg


2014년 5월 20일 화요일

chromecast : 개발을 위한 준비물...

크롬캐스트는 TV따위의 HDMI단자에 꽂아서 사용하게 됩니다.
명령을 전달하는 디바이스(폰이나 PC)와 명령을 받아 수행하는 크롬캐스트는 같은 WIFI망에 존재해야 합니다.

개발 대상 어플은 Sender와 Receiver로 구분됩니다.


1. chromecast 사야함 : 49900원 ㅡㅡ;
- 셋업하기 : https://cast.google.com/chromecast/setup/

2. sender application 선택
폰 및 PC쪽에서 크롬캐스트에 명령을 던지는 역할
- ios, android, chrome API중 하나

3. receiver application
Sender에서 보내온 명령을 받아 처리(미디어 출력)하는 역할
개발 방식에 따라 아래와 같이 3가지 타입을 제공하고 있습니다.
- Default Media Receiver : 기본으로 제공하는 리시버로 정해진 틀을 사용 / 별도 구현이 필요 없음
- Styled Media Receiver : 기본 제공되는 layout안에서 CSS파일에 의한 모양새? 정도 바꿀 수 있는 기능 제공
- Custom receiver : HTML전체 영역(html+css+javascript)을 전반적으로 수정가능하도록 해주시는 기능 제공
   (Custom receiver는 https를 사용하는 보안서버를 사용해야 합니다.)

4. 개발자 계정 생성
 - https://developers.google.com/cast/docs/registration
 - https://cast.google.com/publish
 - 등록비 : 5$
 - chromecast device를 등록하는데 기다리는 시간이 좀.. ~;~

5. 개발자 가이드 보고 따라 만들기. ㅡㅡ;
 - https://developers.google.com/cast/docs/developers

* 디바이스의 시리얼 등록이후 연결이 잘 안되면 크롬캐스트를 리부팅하라는 stackoverflow의 글이 존재함.
실제로 잘 안되서 리부팅 하니 바로 됨. ㅡㅡ;;;


2014년 5월 15일 목요일

unity3d script : 적절한 Input작업 방법

메뉴의 edit>project setting>time에 Fixed Timestep값을 조정하면
FixedUpdate함수가 불리는 주기를 설정합니다.
기본이 0.02로 셋팅되어 있고 이는 50fps로 호출됨을 의미합니다.

Update함수는 구동되는 기기에 dependent하기에 framerate가 달라질 수 있습니다.
이는 physics처리에 적절하지 않습니다.
rigidbody를 움직이고자 할 경우 반드시 FixedUpdate함수에서 처리 하도록 합니다.

FixedUpdate함수는 설정된 값으로 주기마다 실행되어 기기의 영향을 받지 않습니다.
단, 반드시 호출된다는 의미는 성능에 따라 한번에 여러번 호출될 수 있다는 의미를 가지고 있기도 합니다.
* LateUpdate는 Update함수이후에 호출됩니다. 



*** Input입력은 Update에서
physics처리는 FixedUpdate 에서!!


FixedUpdate함수에서 Input처리를 수행하고자 할 경우
아래 예시와 같이 case1 방법 보다는 case2방법을 추천함.


case1
——————————————————————————————————————
using UnityEngine;
public class Test:MonoBehaviour{
    void FixedUpdate(){
        if(Input.GetKeyDown(KeyCode.Space)){
           //Action
        }
    }
}
——————————————————————————————————————


case2
——————————————————————————————————————
using UnityEngine;
public class Test:MonoBehaviour{
    bool action = false;
    void Update(){
         if(Input.GetKeyDown(KeyCode.Space)){
             action = true;
         }
    }
    void FixedUpdate(){
       if(action){
           //Action
           action = false;
        }
    }
}
——————————————————————————————————————

unity3d script : Destroy를 호출하기 전에 Corouotine를 정리해야 함

Coroutine은 yield구문을 만다면 곧바로 실행이 됩니다.
스크립트를 중지하거나 제거하면 yield이후의 구문은 실행되지 않습니다.


아래는 잘못된 코드입니다.

void Update()
{
    if(health < 0)
    {
           StartCoroutine(Die());
           Destroy(gameObject); //or enabled = false;
    }
}

IEnumerator Die()
{
       animation.Play("wobble");
       yield return new WaitForSeconds(3);
       //This will never be called
       animation.Play("die");
}

아래와 같이 수정해야 정상동작을 수행합니다.

bool dying;
void Update()
{
     if(dying) return;
     if(health < 0)
     {
         StartCoroutine(Die());
     }
}

IEnumerator Die()
{
      dying = true;
      animation.Play("wobble");
      yield return new WaitForSeconds(3);
      animation.Play("die");
      yield return new WaitForSeconds(3);
      Destroy(gameObject);
}

unity3d script : 데이터 저장하기

1. PlayerPrefs을 사용한 방법

//Setting value
PlayerPrefs.SetInt("Score", currentScore);
PlayerPrefs.SetInt("HighScore1", currentScore);
PlayerPrefs.SetString("HighScore1Name", currentPlayerName);

//Getting values
highScore1 = PlayerPrefs.GetInt("HighScore1");
highScore1Name = PlayerPrefs.GetString("HighScore1Name", "N/A");

2. 파일을 이용한 저장(Serializer/Deserializer)
유니티는 Application.persistentDataPath 경로를 이용해서 사용자 데이터를
저장하고 불러올 수 있습니다.


    void SaveScores()
    {
        //Get a binary formatter
        var b = new BinaryFormatter();

        //Create a file
        var f = File.Create(Application.persistentDataPath + "/highscores.dat");

        //Save the scores
        b.Serialize(f, highScores);
        f.Close();
    }

    void Start()
    {
        //If not blank then load it
        if(File.Exists(Application.persistentDataPath + "/highscores.dat"))
        {
            //Binary formatter for loading back
            var b = new BinaryFormatter();

            //Get the file
            var f = File.Open(Application.persistentDataPath + "/highscores.dat", FileMode.Open);

            //Load back the scores
            highScores = (List<ScoreEntry>)b.Deserialize(f);
            f.Close();
        }
    }

unity3d script : 스크립트 최적화


감소된 고정 델타 타임

15-25fps(0.04 ~ 0.067)의 고정 델타 타임을 사용하세요. 사용자는 Edit->Project Settings->Time에서 이것을 바꿀수 있습니다. 이것은 FixedUpdate가 불리고 물리 엔진이 충돌감지(collision detection)와 rigidbody 엡데이트하는 빈도수를 줄여줍니다. 주요 캐릭터에 rigidbody를 사용한다면 Rigidbody컴포넌트에서 낮은 고정 델타 타임 스텝을 부드럽게하기 위해 interpolation을 활성화 할 수 있습니다.
Interpolate렌더링 프레임의 현재 시점에서 이전 물리 프레임과 다음 물리 프레임(예측)의 사이 값을 찾아서 선형보간을 수행합니다.  이를 위해 이전 물리 프레임의 값을 계속해서 어딘가에 저장해두어야 합니다. 엔진은 선형 보간된 위치와 회전 값으로 Transform정보를 강제로 설정합니다. Extrapolate 렌더링 프레임의 현재 시간과 이전 물리 프레임시간을 뺀 델타시간을 구한뒤에 현재 리지드바디가 가지고 있는 속력에 이를 곱하여 최종 위치를 예측합니다. ( 회전은 각속도를 사용합니다. ) 마찬가지로 엔진은 예측된 위치와 회전 값으로 Transform정보를 강제로 설정합니다. 

GetComponent콜수 줄이기

GetComponent나 BuiltIn 컴포넌트를 액세서를 사용하는 것은 주목할만한 오버헤드를 생기가 할 수 있습니다. 이것은 컴포넌트의 직접적인 참조를 캐슁하여 줄일수 있습니다.
예를 들어:
function Update () {
    transform.Translate(0, 1, 0);
}

> 위 코드는 실제 아래와 같이 처리됩니다.
GetComponent<Transform>().Translate(0, 1, 0);

대신 아래와 같이 최적화 할수 있습니다:
myTransform : Transform;
function Awake () {
   myTransform = transform;
}
function Update () {
    myTransform.Translate(0, 1, 0);
}

 

메모리 할당을 피하세요

  • 스크립트에서 할당을 최소화하세요.
  • Structs를 사용하세요. Structs는 메모리를 할당하지 않습니다. 대신 스택에 놓이게되며 값으로 전달을하며 이것이 더 빠릅니다.

struct로 생성가능한 걸 class를 생성하면 힙에 할당될 시점에서의 메모리 할당, 제거할떄의 GC처리는 성능 비용이 비싼편입니다.

   

GUI 를 줄이세요

  • GUILayout대신 GUI functions을 사용하고 화면에서 GUI의 양을 최소화 하세요
  • GUI 오버헤드를 줄이기 위해MonoBehaviour.useGUILayout = false를 사용하세요
function Awake () {
    useGUILayout = false;
}

GUI는 NGUI나 앞으로 유니티에 포함될 UGUI를 사용하는것이 좋겠음.

iOS 스크립트 콜 최적화를 사용하세요

UnityEngine 내임스페이스에 있는 대부분의 함수는 C/C++로 구현되어 있습니다. 그런 함수를 스크립트에서 부르는 것은 성능에 추가적인 오버헤드가 있습니다. 프레임당 추가의 몇 밀리세컨드를 얻기 위해서는 Edit->Project Settings->Player 에 있는 iOS스크립트 콜 최적화를 사용하세요:
  • Slow and Safe - 기본적인 단일의 내부 콜 핸들링 (익셉션 지원함) .
  • Fast and Exceptions Unsupported - 빠른 단일 내부 콜 구현, 그러나 익셉션이 지원되지 않으므로 조심히 사용하세요. 이것이 유용한 전형적인 경우:프로그램이 유니티엔진을 많이 사용하면서 익셉션이 생기지 않을때 입니다. 이 옵션은 1-4ms/frame을 줄일 수 있습니다.

Garbage Collection 최적화

  • 위에 서 말한 것처럼 어떤 할당도 피하도록 하세요
  • 만약 피할수 없다면 두가지 할당/수집 방법이 있습니다:
    • 작은 힙 빠르고 자주 일어나는 가비지 콜렉션 전략
      이 방법은 아주 긴 액션 게임플레이가 있고 부드러움 framerate가 필요한 게임에서 잘 작동합니다.
      짧은 시간동안 작은 블락을 할당하는 유니티 iOS게임에서 힙은 보통 ~5ms(iPhone 3G에서)걸립니다. 1MB힙에서는 가비지 컬력션은 ~7ms정도 더 걸립니다.
      가끔은 매 N번 프레임마다 강제 가비지 콜렉션을 하는것도 유용합니다:
      if (Time.frameCount % 30 == 0)
      {
         System.GC.Collect();
      }
      
      그러나 유의해서 사용하세요. 내부 프로파일러 통계를 보고 그것을 바탕으로 결정을 내리세요.
    • 큰 힙 느리고 빈도수가 낮은 가비지 콜렉션
      이 방법은 게임이 요구하는 부드러운 프레임 속도가 짧은 것과 중간 사이의 길이일 때 사용을 합니다. 아이디어는 게임이 실행될때는 가비지 컬렉션을 피하고 게임이 중단 되었을 때하는 것입니다. 게임 시작에 힙에 어느 정도의 공간을 미리 할당하는 것도 좋은 생각인데 그 공간은 게임 플레이 세션이 잘 돌아갈수 있을 만큼 크고 OS의 낮은 메모리 시스템으로 인해 프로그램이 멈추지 않을 만큼의 작은 공간을 말합니다. 모노는 필요할 때문 힙을 늘리기 때문에 가끔 시작시에 강제적으로 확장하는 것도 좋은 생각입니다:
      function Start() {
       var tmp = new System.Object[1024];
       // 할당은 작은 블락에해서 큰 블락은 위하 특별한 처리 방법을 피하도록 합니다
              for (var i : int = 0; i < 1024; i++)
        tmp[i] = new byte[1024];
       // 참조를 풀어 줍니다
              tmp = null;
      }
      
      나중에 게임 플레이가 중단 되었을때 강제적으로 가비지 콜렉션을 할 수 있습니다:
      System.GC.Collect();
      
      주의해서 사용하셔야 합니다. 내주 프로파일러 통계에 주목하시고 실제 숫자를 바탕으로 결정을 내리세요.

string '+' operator는 많은 가비지를 생성합니다. 가급적 StringBuilder()를 사용하는 것이 좋겠음.
StringBuilder sb = new StringBuilder();
sb.AppendFormat("[{0}] {1}", index, name.ToString());

.Net의 gerneric collections 을 사용하여 타입의 boxing, unboxing 부하를 없앱니다.

의심가는 코드 블럭에 Profiler.BeginSample, Profiler.EndSample를 사용하여 프로파일러 하이라키에서 확인하자.

using UnityEngine;
using System.Collections;

public class Example : MonoBehaviour {
    void Example() {
        Profiler.BeginSample("MyPieceOfCode");
        Profiler.EndSample();
    }
}





unity3d script : 시간 경과에 따른 로직 처리

1. 특정 시간 경과 이후 특정 작업 반복 실행하기

Coroutines으로 작업이 가능하지만 단순한 지연 이벤트를 처리하기는
Coroutines의 처리로직이 복잡해질 수 있다...
Time.deltaTime을 사용하는 방법

float timer;
int waitingTime;

void Start()
{
    timer = 0.0;
    waitingTime = 2;
    inside = false;
}

void Update()
{
    timer += Time.deltaTime;
    if(timer > waitingTime)
    {
        //Action
        timer = 0;
    }
}



2. 오브젝트가 생성된 이후 특정 시간이 경과한 뒤에 destroy시키기

화면에 오브젝트가 나타난뒤 몇초 이후 제거하려 한다면 다음과 같은 코드를 사용하면 됩니다.

function Start()
{
    //Destroy the game object in 5 seconds
    Destroy(gameObject, 5);
}



3. Coroutine을 이용한 Action 지연 처리

using UnityEngine;
using System.Collections;

public class Wait : MonoBehaviour
{
    public bool check =true;
    int i 0;

    void Update ()
    {
        if(Input.GetKeyDown(KeyCode.A)&&check)
        {
            check = false;
            print("Inside" + i++);
            StartCoroutine(WaitForIt());
        }
    }

    IEnumerator WaitForIt()
    {
        yield return new WaitForSeconds(2.0f);
        check=true;
    }
}



4. 함수 지연 호출

public Rigidbody projectile;
void LaunchProjectile()
{
    Rigidbody instance = Instantiate(projectile);
    instance.velocity = Random.insideUnitSphere * 5;

    // CancelInvoke(“LaunchProjectile”); // 필요할 경루 Invoke 취소처리
}

void Start()
{
    Invoke("LaunchProjectile", 2); // 2초뒤 LaunchProjectile함수 호출
    Invoke("LaunchProjectile", 2, 0.3f); // 2초뒤 0.3초주기로 LaunchProjectile함수 반복 호출
}



4. 언제 coroutine을 사용할까?
coroutine은 Update함수의 내용이 너무 복잡해지는걸 원치 않을때 유용하게 사용될 수 있습니다.
주의 : 여러개의 coroutine이 같은 변수를 수정하고자 하면 찾기 어려운 오류를 발생시킬 수 있습니다.






unity3d script : Object들을 담는 자료 구조(.Net Generic collections)

리스트를 사용하고자 할때 Array, ArrayList, HashTable은 사용하지 말도록…

대신, .Net의 gerneric collections 이나 단순 배열을 사용하도록 합니다.
 - 선언시 자료형을 지정하기 떄문에 명시적 형변환이 필요 없습니다.
 - ArrayList보다 빠릅니다.

리스트를 쓰고자 할 때는 List<Type>,
해쉬 테이블을 사용하고자 할 때는  Dictionary<KeyType,ValueType>


사용하기 전에 아래와 같은 선언이 필요합니다.
using System.Collections.Generic


리스트 사용 방법

//Define a list using C#
List<int> myList = new List<int>();
List<SomeClass> anotherList = new List<SomeClass>();

//Add element to a list
myList.Add(someValue);

//Add multiple elements to a list
myList.AddRange(someListOrArrayOfValues);

//Clear all elements
myList.Clear();

//Insert into a list
myList.Insert(1, someValue);

//Insert multiple elements
myList.InsertRange(1, someListOrArrayOfValues);

//Remove a specific value
myList.Remove(someValue);

//Remove at a specific index
myList.RemoveAt(1);

//Find an index of an element
var index = myList.IndexOf(someValue);

//Find an index of something using a function in Javascript
var index = anotherList.FindIndex(function(entry) entry.someValue == something);

//Turn a list into an array
var myArray = myList.ToArray();

//Find an index of something using a function in C#
var index = anotherList.FindIndex((entry) => entry.someValue == something)

//Get the number of items in the list
var itemCount = myList.Count


딕셔너리 사용 방법

//Define a string to int dictionary in C#
Dictionary<string, int> myDic = new Dictionary<string, int>();

//Define a dictionary of GameObject to a class in C#
Dictionary<GameObject, SomeClass> anotherDic = new Dictionary<GameObject, SomeClass>();

//Add an element to a dictionary
myDic["Something"] = someIntValue;

//Get a value from a dictionary
var someValue = myDic["Something"];

//Get a complex value and change one of its properties
anotherDic[gameObject].someProperty = someValue;

//Check if a value exists
if(myDic.ContainsKey("Something")) { }

//Remove an element from a dictionary
myDic.Remove("Something');

//Run through all of the keys in the dictionary JS
for(var key : String in myDic.Keys) { }

//Run through all of the values in the dictionary in C#
foreach(int value in myDic.Values) { }

//Clear all elements
myDic.Clear();

//Get the number of items in the dictionary
var count = myDic.Count;

unity3d script : 특정 script에 access하는 방법

자신의 오브젝트에 존재하는 스크립트를 찾아 access하는 방법

GetComponent<TargetScriptName>().someVariable = someValue;
GetComponent<TargetScriptName>().SomeMethod();


다른 오브젝트를 통해 access하는 방법
void OnTriggerEnter(Collider other)
{
      other.GetComponent<TargetScriptName>().someVariable = someValue;
}

void OnCollisionEnter(Collision collision)
{
      collision.GetComponent<TargetScriptName>().someVariable = someValue;
}


이름이나 태그를 통해 스크립트 찾아내는 방법
GameObject.FindWithTag 함수나 GameObject.Find 함수를 사용

targetScript = GameObject.Find("someObjectName").GetComponent<TargetScriptName>();


모든 child오브젝트에서의 특정 스크립트를 얻어내고자 할 경우...

for(var t : Transform in transform)
{
     target = t.GetComponent(TargetScriptName);
     target.DoSomething();
     target.someVariable = someValue;
}

unity3d script : 특정 범위에 포함되는 충돌체에 데미지 주기

float radius = 10.0F;
float power = 1000.0F;

Collider[] colliders = Physics.OverlapSphere (_transform.position, radius);

foreach(Collider col in colliders)
{
if(col.rigidbody)
{
  if(col.rigidbody != gameObject.rigidbody)
  {
       col.rigidbody.AddExplosionForce (power, _transform.position, radius);
  }
}
}