BbaDdo :: 'Android' 카테고리의 글 목록


'Android'에 해당되는 글 9건

  1. 2014.01.08 SoundPoool - maxStreams 설정
  2. 2013.11.08 cocos2d-x 안드로이드 진동기능 설정 cocos2d-x android vibration definition
  3. 2013.11.08 cocos2d-x 안드로이드 웹페이지 호출 cocos2d-x loading a wep page in Android
  4. 2013.07.12 cocos2d-x 1.01 ripple, wave, liquid 응용
  5. 2013.03.07 Bresenham 브레센함 알고리듬 : 원 그리기
  6. 2012.10.05 Conway's Game Of Life Java code
  7. 2012.09.19 Android image crop
  8. 2012.08.20 java.lang.reflect.Method.invoke 메서드 활용
  9. 2012.07.19 Android Screen Capture
크리에이티브 커먼즈 라이선스
Creative Commons License

 

 

 

 

SoundPoool -  MaxStreams 설정

 

In addition to low-latency playback, SoundPool can also manage the number of audio streams being rendered at once. When the SoundPool object is constructed, the maxStreams parameter sets the maximum number of streams that can be played at a time from this single SoundPool. SoundPool tracks the number of active streams. If the maximum number of streams is exceeded, SoundPool will automatically stop a previously playing stream based first on priority and then by age within that priority. Limiting the maximum number of streams helps to cap CPU loading and reducing the likelihood that audio mixing will impact visuals or UI performance.

 

 

사운드 풀의 스트림 최대수는 동시에 출력되는 음악파일의 숫자인데

만일 플레이되려는 스트림수가 최대수 보다 클 경우에는 자동적으로

최초순위에 있는 스트림을 정지시키고 새로운 스트림을 플레이 하게 만든다.

스트림 최대수를 정하는 이유는 cpu 로딩 부담을 줄이고 플레이화면의 포퍼먼스를

해치지 않도록 하기 위함이다.

 

즉, 스트림 최대수는 가능한 최소로 줄이고

maxStreams 값을 초과한 상태에서 SoundPool.play() 메서드에 의한 에러 메서지는

무시해도 된다는 이야기인가?

 

surfaceview 상에서 막대한 양의 소리가 동시에 출력되는 경우라면 에러메서지가

넘쳐나게 된다. 최대한 줄이고 무시하라는 이야기?... 그러나 결국 다운된다.

차라리 현재 플레이되는 스트림갯수를 리턴하는 메서드가 있으면

제어할 수 있을텐데... 없다. 현재로서는 모름.

 

가장 좋은 방법은 maxStreams 값을 최소화 하고

충돌되는 반복 횟수를 로직으로 가능한 줄여나가는 것.

 

Cocos2d-x 의 경우에는 Cocos2dxSound.java 파일에서 이 값을 설정할 수 있다.

 

출처 : http://developer.android.com/reference/android/media/SoundPool.html

저작자 표시 비영리 변경 금지
신고
크리에이티브 커먼즈 라이선스
Creative Commons License

 

 

 

cocos2d-x 안드로이드 진동기능 설정

cocos2d-x android vibration definition

 

1.     (사용자 project name)\android\src\org\cocos2dx\lib

è폴더내의 Cocos2dxSound.java,  Cocos2dxActivity.java 두 클래스 파일에 메서드 추가

빨간색 코드

 

================

Cocos2dxSound.java

================

package org.cocos2dx.lib;

 

import java.util.HashMap;

import java.util.Iterator;

import java.util.Map;

 

import android.content.Context;

import android.media.AudioManager;

import android.media.SoundPool;

import android.util.Log;

import android.os.Vibrator;

 

/**

 *

 * This class is used for controlling effect

 *

 */

 

public class Cocos2dxSound {

             private Context mContext;

             private SoundPool mSoundPool;

             private float mLeftVolume;

             private float mRightVolume;

            

             // sound id and stream id map

             private HashMap<Integer,Integer> mSoundIdStreamIdMap;

             // sound path and sound id map

             private HashMap<String,Integer> mPathSoundIDMap;

            

             private static final String TAG = "Cocos2dxSound";

             private static final int MAX_SIMULTANEOUS_STREAMS_DEFAULT = 5;

             private static final float SOUND_RATE = 1.0f;

             private static final int SOUND_PRIORITY = 1;

             private static final int SOUND_QUALITY = 5;

            

             private final int INVALID_SOUND_ID = -1;

             private final int INVALID_STREAM_ID = -1;

            

            

             public Cocos2dxSound(Context context){

                           this.mContext = context;        

                           initData();

             }

            

             public int preloadEffect(String path){

                           int soundId = INVALID_SOUND_ID;

                          

                           // if the sound is preloaded, pass it

                           if (this.mPathSoundIDMap.get(path) != null){

                                        soundId =  this.mPathSoundIDMap.get(path).intValue();

                           } else {

                                        soundId = createSoundIdFromAsset(path);

                                       

                                        if (soundId != INVALID_SOUND_ID){

                                                     // the sound is loaded but has not been played

                                                     this.mSoundIdStreamIdMap.put(soundId, INVALID_STREAM_ID);

                                                    

                                                     // record path and sound id map

                                                     this.mPathSoundIDMap.put(path, soundId);

                                        }

                           }

                                       

                           return soundId;

             }

. . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . .

 

            

             @SuppressWarnings("unchecked")

             private void pauseOrResumeAllEffects(boolean isPause){

                           Iterator<?> iter = this.mSoundIdStreamIdMap.entrySet().iterator();

                           while (iter.hasNext()){

                                        Map.Entry<Integer, Integer> entry = (Map.Entry<Integer, Integer>)iter.next();

                                        int soundId = entry.getKey();

                                        if (isPause) {

                                                     this.pauseEffect(soundId);

                                        } else {

                                                     this.resumeEffect(soundId);

                                        }

                           }

             }

            

             public void vibrate(long time){

                           Vibrator v = (Vibrator) mContext.getSystemService(Context.VIBRATOR_SERVICE);

                           v.vibrate(time);

             }

            

             public void vibrateWithPattern(long[] pattern, int repeat){

                           Vibrator v = (Vibrator) mContext.getSystemService(Context.VIBRATOR_SERVICE);

                           v.vibrate(pattern, repeat);

             }

            

             public void cancelVibrate(){

                           Vibrator v = (Vibrator) mContext.getSystemService(Context.VIBRATOR_SERVICE);

                           v.cancel();

             }

}

 

 

 

          ==============

           Cocos2dxActivity.java

           ==============

          

package org.cocos2dx.lib;

 

import android.app.Activity;

import android.app.AlertDialog;

import android.app.Dialog;

import android.content.DialogInterface;

import android.content.Intent;

import android.content.pm.ApplicationInfo;

import android.content.pm.PackageManager;

import android.content.pm.PackageManager.NameNotFoundException;

import android.net.Uri;

import android.os.Bundle;

import android.os.Handler;

import android.os.Message;

import android.util.DisplayMetrics;

import android.util.Log;

 

public class Cocos2dxActivity extends Activity{

    private static Cocos2dxMusic backgroundMusicPlayer;

    private static Cocos2dxSound soundPlayer;

    private static Cocos2dxAccelerometer accelerometer;

    private static boolean accelerometerEnabled = false;

    private static Handler handler;

    private final static int HANDLER_SHOW_DIALOG = 1;

    private static String packageName;

 

    private static native void nativeSetPaths(String apkPath);

 

          //===============

          //add url member

          //===============

          private static Activity meUrl = null;

 

 

    @Override

    protected void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);

       

 

                       //===============

                       //add url member

                       //===============

                       meUrl = this;

 

        // get frame size

        DisplayMetrics dm = new DisplayMetrics();

        getWindowManager().getDefaultDisplay().getMetrics(dm);

        accelerometer = new Cocos2dxAccelerometer(this);

 

        // init media player and sound player

        backgroundMusicPlayer = new Cocos2dxMusic(this);

        soundPlayer = new Cocos2dxSound(this);

       

        // init bitmap context

        Cocos2dxBitmap.setContext(this);

       

        handler = new Handler(){

                     public void handleMessage(Message msg){

                          switch(msg.what){

                           case HANDLER_SHOW_DIALOG:

                                  showDialog(((DialogMessage)msg.obj).title, ((DialogMessage)msg.obj).message);

                                  break;

                           }

                     }

        };

    }

 

. . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . .

 

    public static void terminateProcess(){

         android.os.Process.killProcess(android.os.Process.myPid());

    }

 

    public static void vibrate(long time){

                      soundPlayer.vibrate(time);

    }

         

public static void vibrateWithPattern(long pattern[], int repeat){

                       soundPlayer.vibrateWithPattern(pattern, repeat);

}

         

public static void cancelVibrate(){

                       soundPlayer.cancelVibrate();

}

 

   

   

   

    @Override

    protected void onResume() {

         super.onResume();

         if (accelerometerEnabled) {

             accelerometer.enable();

         }

    }

 

    @Override

    protected void onPause() {

         super.onPause();

         if (accelerometerEnabled) {

             accelerometer.disable();

         }

    }

. . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . .

 

 

2.     (사용자 cocos2d-x folder name)\ CocosDenshion\include

è폴더내 SimpleAudioEngine.h 함수 추가, 빨간색 코드 줄

 

================

SimpleAudioEngine.h

================

 

#ifndef _SIMPLE_AUDIO_ENGINE_H_

#define _SIMPLE_AUDIO_ENGINE_H_

 

#include "Export.h"

#include <stddef.h>

 

namespace CocosDenshion {

 

/**

@class          SimpleAudioEngine

@brief                  offer a VERY simple interface to play background music & sound effect

*/

class EXPORT_DLL SimpleAudioEngine

{

public:

    SimpleAudioEngine();

    ~SimpleAudioEngine();

 

    /**

    @brief Get the shared Engine object,it will new one when first time be called

    */

    static SimpleAudioEngine* sharedEngine();

 

    /**

    @brief Release the shared Engine object

    @warning It must be called before the application exit, or a memroy leak will be casued.

    */

static void end();

 

    /**

    @brief  Set the zip file name

    @param pszZipFileName The relative path of the .zip file

    */

    static void setResource(const char* pszZipFileName);

 

. . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . .

 

/**

    @brief                          preload a compressed audio file

    @details               the compressed audio will be decode to wave, then write into an

    internal buffer in SimpleaudioEngine

    */

    void preloadEffect(const char* pszFilePath);

 

    /**

    @brief                          unload the preloaded effect from internal buffer

    @param[in]                     pszFilePath                          The path of the effect file,or the FileName of T_SoundResInfo

    */

    void unloadEffect(const char* pszFilePath);

 

    /**

   @brief                  vibration setting

   */

   void vibrate(long long time);

   void vibrateWithPattern(long long pattern[], int repeat);

   void cancelVibrate();

};

 

} // end of namespace CocosDenshion

 

#endif // _SIMPLE_AUDIO_ENGINE_H_

 

 

 

3.     (사용자 cocos2d-x folder name)\CocosDenshion\CocosDenshion\android

è폴더 내의 SimpleAudioEngine.cpp

 

================

SimpleAudioEngine.cpp

================

#include "SimpleAudioEngine.h"

#include "jni/SimpleAudioEngineJni.h"

 

namespace CocosDenshion

{

             static SimpleAudioEngine *s_pEngine = 0;

 

             SimpleAudioEngine::SimpleAudioEngine()

             {

 

             }

 

             SimpleAudioEngine::~SimpleAudioEngine()

             {

 

             }

 

             SimpleAudioEngine* SimpleAudioEngine::sharedEngine()

             {

                           if (! s_pEngine)

                           {

                                        s_pEngine = new SimpleAudioEngine();

                           }

       

                           return s_pEngine;

             }

 

             void SimpleAudioEngine::end()

             {

                           endJNI();

             }

 

             void SimpleAudioEngine::setResource(const char* pszZipFileName)

             {

 

             }

 

            void SimpleAudioEngine::preloadBackgroundMusic(const char* pszFilePath)

             {

                         preloadBackgroundMusicJNI(pszFilePath);

             }

 

             void SimpleAudioEngine::playBackgroundMusic(const char* pszFilePath, bool bLoop)

             {

                         playBackgroundMusicJNI(pszFilePath, bLoop);

             }

. . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . .

 

             void SimpleAudioEngine::resumeAllEffects()

             {

                           resumeAllEffectsJNI();

             }

 

             void SimpleAudioEngine::stopAllEffects()

             {

                           stopAllEffectsJNI();

             }

 

             void SimpleAudioEngine::vibrate(long long time)

             {

                           vibrateJNI(time);

             }

            

             void SimpleAudioEngine::vibrateWithPattern(long long pattern[], int repeat)

             {

                           vibrateWithPatternJNI(pattern, repeat);

                          

             }

            

             void SimpleAudioEngine::cancelVibrate()

             {

                           cancelVibrateJNI();

             }

}

 

 

 

 

4.     (사용자 cocos2d-x folder name)\ CocosDenshion\android\jni

è폴더 내의 SimpleAudioEngineJni.h, SimpleAudioEngineJni.cpp JNI 등록

 

           ==================

SimpleAudioEngineJni.h

==================

#ifndef __SIMPLE_AUDIO_ENGINE_JNI__

#define __SIMPLE_AUDIO_ENGINE_JNI__

 

#include <jni.h>

 

extern "C"

{

      extern void preloadBackgroundMusicJNI(const char *path);

      extern void playBackgroundMusicJNI(const char *path, bool isLoop);

             extern void stopBackgroundMusicJNI();

             extern void pauseBackgroundMusicJNI();

             extern void resumeBackgroundMusicJNI();

             extern void rewindBackgroundMusicJNI();

             extern bool isBackgroundMusicPlayingJNI();

             extern float getBackgroundMusicVolumeJNI();

             extern void setBackgroundMusicVolumeJNI(float volume);

             extern unsigned int playEffectJNI(const char* path, bool bLoop);

             extern void stopEffectJNI(unsigned int nSoundId);

             extern void endJNI();

             extern float getEffectsVolumeJNI();

             extern void setEffectsVolumeJNI(float volume);

             extern void preloadEffectJNI(const char *path);

             extern void unloadEffectJNI(const char* path);

             extern void pauseEffectJNI(unsigned int nSoundId);

             extern void pauseAllEffectsJNI();

             extern void resumeEffectJNI(unsigned int nSoundId);

             extern void resumeAllEffectsJNI();

             extern void stopAllEffectsJNI();

             extern void vibrateJNI(long long time);

             extern void vibrateWithPatternJNI(long long pattern[], int repeat);

             extern void cancelVibrateJNI();

}

 

#endif // __SIMPLE_AUDIO_ENGINE_JNI__

 

 

           ==================

SimpleAudioEngineJni.h

==================

#include "SimpleAudioEngineJni.h"

#include <android/log.h>

 

#define  LOG_TAG    "libSimpleAudioEngine"

#define  LOGD(...)  __android_log_print(ANDROID_LOG_DEBUG,LOG_TAG,__VA_ARGS__)

#define  CLASS_NAME "org/cocos2dx/lib/Cocos2dxActivity"

 

typedef struct JniMethodInfo_

                  {

                                   JNIEnv *    env;

                                   jclass      classID;

                                   jmethodID   methodID;

                  } JniMethodInfo;

 

 

extern "C"

{

                  static JavaVM *gJavaVM = 0;

 

                  jint JNI_OnLoad(JavaVM *vm, void *reserved)

                  {

                                   gJavaVM = vm;

 

                                   return JNI_VERSION_1_4;

                  }

 

                  // get env and cache it

                  static JNIEnv* getJNIEnv(void)

                  {

                                   JNIEnv *env = 0;

 

                                   // get jni environment

                                   if (gJavaVM->GetEnv((void**)&env, JNI_VERSION_1_4) != JNI_OK)

                                   {

                                                     LOGD("Failed to get the environment using GetEnv()");

                                   }

 

                                   if (gJavaVM->AttachCurrentThread(&env, 0) < 0)

                                   {

                                                     LOGD("Failed to get the environment using AttachCurrentThread()");

                                   }

 

                                   return env;

                  }

 

                  // get class and make it a global reference, release it at endJni().

                  static jclass getClassID(JNIEnv *pEnv)

                  {

                                   jclass ret = pEnv->FindClass(CLASS_NAME);

                                   if (! ret)

                                   {

                                                     LOGD("Failed to find class of %s", CLASS_NAME);

                                   }

 

                                   return ret;

                  }

 

static bool getStaticMethodInfo(JniMethodInfo &methodinfo, const char *methodName, const char *paramCode)

    {

                                   jmethodID methodID = 0;

                                   JNIEnv *pEnv = 0;

                                   bool bRet = false;

 

        do

        {

                                                     pEnv = getJNIEnv();

                                                     if (! pEnv)

                                                     {

                                                                       break;

                                                     }

 

            jclass classID = getClassID(pEnv);

 

            methodID = pEnv->GetStaticMethodID(classID, methodName, paramCode);

            if (! methodID)

            {

                LOGD("Failed to find static method id of %s", methodName);

                break;

            }

 

                                                     methodinfo.classID = classID;

                                                     methodinfo.env = pEnv;

                                                     methodinfo.methodID = methodID;

 

                                                     bRet = true;

        } while (0);

 

        return bRet;

    }

 

                  void preloadBackgroundMusicJNI(const char *path)

                  {

                                   // void playBackgroundMusic(String,boolean)

                                   JniMethodInfo methodInfo;

 

                                   if (! getStaticMethodInfo(methodInfo, "preloadBackgroundMusic", "(Ljava/lang/String;)V"))

                                   {                                                   

                                                     return;

                                   }

 

                                   jstring stringArg = methodInfo.env->NewStringUTF(path);

                                   methodInfo.env->CallStaticVoidMethod(methodInfo.classID, methodInfo.methodID, stringArg);

                                   methodInfo.env->DeleteLocalRef(stringArg);

                                   methodInfo.env->DeleteLocalRef(methodInfo.classID);

                  }

 

. . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . .

 

 

                  void resumeAllEffectsJNI()

                  {

                                   // void resumeAllEffects()

 

                                   JniMethodInfo methodInfo;

 

                                   if (! getStaticMethodInfo(methodInfo, "resumeAllEffects", "()V"))

                                   {

                                                     return ;

                                   }

 

                                   methodInfo.env->CallStaticVoidMethod(methodInfo.classID, methodInfo.methodID);

                                   methodInfo.env->DeleteLocalRef(methodInfo.classID);

                  }

 

                  void stopAllEffectsJNI()

                  {

                                   // void stopAllEffects()

 

                                   JniMethodInfo methodInfo;

 

                                   if (! getStaticMethodInfo(methodInfo, "stopAllEffects", "()V"))

                                   {

                                                     return ;

                                   }

 

                                   methodInfo.env->CallStaticVoidMethod(methodInfo.classID, methodInfo.methodID);

                                   methodInfo.env->DeleteLocalRef(methodInfo.classID);

                  }

 

                  void vibrateJNI(long long time)

                  {

                                   JniMethodInfo methodInfo;

                                  

                                   if (! getStaticMethodInfo(methodInfo, "vibrate", "(J)V"))

                                   {

                                                     return;

                                   }

                                  

                                   methodInfo.env->CallStaticVoidMethod(methodInfo.classID, methodInfo.methodID, time);

                                   methodInfo.env->DeleteLocalRef(methodInfo.classID);

                  }

                 

                  void vibrateWithPatternJNI(long long pattern[], int repeat)

                  {

                                   JniMethodInfo methodInfo;

                                  

                                   if (! getStaticMethodInfo(methodInfo, "vibrateWithPattern", "([JI)V"))

                                   {

                                                     return;

                                   }

                                  

                                   int elements = sizeof(pattern);

                                   jlongArray jLongArray = methodInfo.env->NewLongArray(elements);

                                   methodInfo.env->SetLongArrayRegion(jLongArray, 0, elements, (jlong*) pattern);

                                  

                                   methodInfo.env->CallStaticVoidMethod(methodInfo.classID, methodInfo.methodID, jLongArray, repeat);

                                   methodInfo.env->DeleteLocalRef(methodInfo.classID);

                  }

                 

                  void cancelVibrateJNI()

                  {

                 

                                   JniMethodInfo methodInfo;

                                  

                                   if (! getStaticMethodInfo(methodInfo, "cancelVibrate", "()V"))

                                   {

                                                     return;

                                   }

 

                                   methodInfo.env->CallStaticVoidMethod(methodInfo.classID, methodInfo.methodID);

                                   methodInfo.env->DeleteLocalRef(methodInfo.classID);

                  }

 

}

 

5.     AndroidManifest.xml 파일에

è<uses-permission android:name="android.permission.VIBRATE" /> 추가

 

6.     원하는 곳에서 실행 코드 예

//진동 ===================================================

#if (CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID)       

        SimpleAudioEngine::sharedEngine()->vibrate(100);

#endif

//========================================================

 

           è당연히 심플오디오엔진에 추가했기 때문에  위와 같이 정의함

 

           vibrate(long long time)  : 매개변수 밀리초 동안 진동

           vibrateWithPattern(long long pattern[], int repeat)  : 일정 패턴대로 반복

                     pattern è 밀리초 배열,  repeatè 반복횟수 

           cancelVibrate() : 진동끄기

 

 

출처 : http://www.cocos2d-x.org/forums/6/topics/8179

저작자 표시 비영리 변경 금지
신고
크리에이티브 커먼즈 라이선스
Creative Commons License

 

 

cocos2d-x 안드로이드 웹페이지 호출

cocos2d-x  loading a wep page in Android

 

1.   JNI 등록할    UrlJni.h ,   UrlJni.cpp  클래스파일 작성

ð  2개 파일들을

(사용자폴더이름)\cocos2dx\platform\android\jni 폴더에 저장

 

======

UrlJni.h

======

#ifndef __ANDROID_URL_JNI_H__

#define __ANDROID_URL_JNI_H__

 

extern "C"

{

    extern void openURLJNI(const char* url);

}

 

#endif

 

 

========

UrlJni.cpp

========

#include "UrlJni.h"

#include "JniHelper.h"

 

#include <jni.h>

 

using namespace cocos2d;

 

extern "C"

{

    void openURLJNI(const char* url)

    {

        JniMethodInfo t;

        if (JniHelper::getStaticMethodInfo(t, "org/cocos2dx/lib/Cocos2dxActivity"

                        ,"openURL"

                        ,"(Ljava/lang/String;)V"))

        {

            jstring StringArg1 = t.env->NewStringUTF(url);

            t.env->CallStaticVoidMethod(t.classID,t.methodID, StringArg1);

        }

 

    }

}

 

 

2.    (사용자폴더이름)\cocos2dx\Android.mk  에 등록

è 아래 빨간색 코드 한줄

========

Android.mk

========

LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)

LOCAL_MODULE := cocos2dx_static

LOCAL_MODULE_FILENAME := libcocos2d

LOCAL_SRC_FILES := \

CCConfiguration.cpp \

CCDrawingPrimitives.cpp \

CCScheduler.cpp \

CCCamera.cpp \

actions/CCAction.cpp \

. . . . . . . . . . . . .

. . . . . . . . . . . . . 

. . . . . . . . . . . . .

. . . . . . . . . . . . . 

platform/android/jni/JniHelper.cpp \

platform/android/jni/IMEJni.cpp \

platform/android/jni/MessageJni.cpp \

platform/android/jni/SensorJni.cpp \

platform/android/jni/SystemInfoJni.cpp \

platform/android/jni/TouchesJni.cpp \

platform/android/jni/UrlJni.cpp \

script_support/CCScriptSupport.cpp \

sprite_nodes/CCAnimation.cpp \

sprite_nodes/CCAnimationCache.cpp \

sprite_nodes/CCSprite.cpp \

. . . . . . . . . . . . .

. . . . . . . . . . . . . 

 

3.     Cocos2dxActivity.java 에 멤버변수와 메서드를 추가한다.

(사용자프로젝트이름)\ android\src\org\cocos2dx\lib 폴더에 있음

ð  아래 코드 빨간색 코드

 

================

Cocos2dxActivity.java

================

package org.cocos2dx.lib;

import android.app.Activity;

      import android.app.AlertDialog;

      import android.app.Dialog;

      import android.content.DialogInterface;

      import android.content.Intent;

      import android.content.pm.ApplicationInfo;

      import android.content.pm.PackageManager;

      import android.content.pm.PackageManager.NameNotFoundException;

      import android.net.Uri;

      import android.os.Bundle;

      import android.os.Handler;

      import android.os.Message;

      import android.util.DisplayMetrics;

      import android.util.Log;

 

      public class Cocos2dxActivity extends Activity{

             private static Cocos2dxMusic backgroundMusicPlayer;

             private static Cocos2dxSound soundPlayer;

             private static Cocos2dxAccelerometer accelerometer;

             private static boolean accelerometerEnabled = false;

             private static Handler handler;

             private final static int HANDLER_SHOW_DIALOG = 1;

             private static String packageName;

private static native void nativeSetPaths(String apkPath);

 

             //===============

             //add url member

             //===============

             private static Activity meUrl = null;

 

 

    @Override

    protected void onCreate(Bundle savedInstanceState) {

   super.onCreate(savedInstanceState);

       

 

             //===============

             //add url member

             //===============

             meUrl = this;

 

    // get frame size

    DisplayMetrics dm = new DisplayMetrics();

              getWindowManager().getDefaultDisplay().getMetrics(dm);

              accelerometer = new Cocos2dxAccelerometer(this);

 

              // init media player and sound player

        backgroundMusicPlayer = new Cocos2dxMusic(this);

        soundPlayer = new Cocos2dxSound(this);

       

             // init bitmap context

        Cocos2dxBitmap.setContext(this);

       

        handler = new Handler(){

        public void handleMessage(Message msg){

                         switch(msg.what){

                         case HANDLER_SHOW_DIALOG:

                                      showDialog(((DialogMessage)msg.obj).title, ((DialogMessage)msg.obj).message);

                                      break;

                             }

 }

        };

    }

 

//===============

//add url method

//===============

public static void openURL(String url){

             Intent i = new Intent(Intent.ACTION_VIEW); 

             i.setData(Uri.parse(url));

             meUrl.startActivity(i);

   }

//===============

 

. . . . . . . . . . . . .

. . . . . . . . . . . . .

. . . . . . . . . . . . .

 

 

 

4.     사용하고자 하는 해당 클래스에서 코딩

 

//헤더파일 인클루드 코드

#if (CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID)        

#include "platform/android/jni/UrlJni.h"

#endif

 

//호출 코드

#if (CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID)       

             openURLJNI("http://bbaddoroid.tistory.com");

#endif

 

 

 끝.

 

저작자 표시 비영리 변경 금지
신고
크리에이티브 커먼즈 라이선스
Creative Commons License

 

 

 

 

 

cocos2d-x openGl10 엔진을 이용한 ripple, wave, liquid 효과 적용,

C++로 코딩 한번 해 봄.액션 시퀀스를 사용하지 않고 각 효과 클래스 객체가 릴리즈 될때의 초간격을 이용해 구현. 이유가 있음

초 간격을 잘못 주면 다운...폰 배터리 빼고 다시 켜야함.

이구.. 보니느 스맛뽄이 꾸질꾸질 구형이라

2.13 cocos2d-x는 visual studio 에서만 확인,

물론 안드로이드 자바 랩핑까지만 되는 것만 봄...

 

 

 

 

helloWorldScene.h

 

#ifndef __HELLOWORLD_SCENE_H__

#define __HELLOWORLD_SCENE_H__

 

#include "cocos2d.h"

#include "SimpleAudioEngine.h"

#include <platform.h>

 

using namespace cocos2d;

using namespace CocosDenshion;

 

class HelloWorld : public CCLayer

{

private:

         CCSize            m_size;

         ccTime            m_t; //float

         cc_timeval        m_start;          //구조체 (, 마이크로초) long, long

         cc_timeval        m_end;                     //터치무브 시간 구함

         cc_timeval        m_result;                  //시스템시간으로 계산

             CCLabelTTF*       m_pLabel;     

         CCLabelBMFont*    m_pLabel2;

         bool              m_touchOff;                        //wave effect activity off, 웨이브 실행시 터치 오프

         bool              m_changedWaveOff; //sellect wave button off, 웨이브 이펙트 변경시 에러방지

         int               m_caseEffect;              //case 순서

         int               m_nRipple;                         //리플의 경우 연속터치시 다른 이펙트와 충돌 방지용

         int               m_nCheck;                          //위와 동일

         CCSprite*         m_pTx;                             //텍스트 띄우기

         SimpleAudioEngine* m_soundRipples;          //효과음

         SimpleAudioEngine* m_soundWaves;            //효과음

         SimpleAudioEngine* m_soundLiquid;           //효과음

public:

         HelloWorld();

         ~HelloWorld();

 

         // Here's a difference. Method 'init' in cocos2d-x returns bool, instead of returning 'id' in cocos2d-iphone

         virtual bool init(); 

 

         // there's no 'id' in cpp, so we recommand to return the exactly class pointer

         static cocos2d::CCScene* scene();

        

         // a selector callback

         virtual void menuCloseCallback(CCObject* pSender);

 

         // for the subclass of CCLayer, each has to implement the "static node()" method manually

         LAYER_NODE_FUNC(HelloWorld);

 

         //터치이벤트

         virtual void ccTouchesBegan(CCSet *pTouch, CCEvent *pEvent);

         virtual void ccTouchesMoved(CCSet *pTouch, CCEvent *pEvent);

         virtual void ccTouchesEnded(CCSet *pTouch, CCEvent *pEvent);

         virtual void ccTouchesCancelled(CCSet *pTouch, CCEvent *pEvent);

         void UpdateLabel();

 

         // 리플, 웨이브 효과

         void MadeRipple(const CCPoint &p, const ccTime &t);

         void MadeWave(const ccTime &t);

         void MadeLiquid(const ccTime &t);

 

         // 리플 반복 터치 허용, 웨이브 반복 터치 불허

         void TouchOn();

 

         // 리플 -> 웨이브 변경 방지

         void waveChangeOn();

 

         // 텍스트 스크롤

         void ScrollTx(ccTime t);

};

 

#endif // __HELLOWORLD_SCENE_H__

 

 

 

 

helloWorldScene.cpp

 

#include "HelloWorldScene.h"

 

 

HelloWorld::HelloWorld()

{

        m_touchOff = false;

        m_changedWaveOff = false;

        m_caseEffect = 0;

        m_nRipple = 0;

        m_nCheck = 0;

}

 

HelloWorld::~HelloWorld()

{

}

 

CCScene* HelloWorld::scene()

{

        // 'scene' is an autorelease object

        CCScene *scene = CCScene::node();

        

         // 'layer' is an autorelease object

         HelloWorld *layer = HelloWorld::node();

 

         // add layer as a child to scene

         scene->addChild(layer);

 

         // return the scene

         return scene;

}

 

// on "init" you need to initialize your instance

bool HelloWorld::init()

{

         //////////////////////////////

         // 1. super init first

         if ( !CCLayer::init() )

         {

                  return false;

         }

 

         /////////////////////////////

         // 2. add a menu item with "X" image, which is clicked to quit the program

         //    you may modify it.

 

         // add a "close" icon to exit the progress. it's an autorelease object

         CCMenuItemImage *pCloseItem = CCMenuItemImage::itemFromNormalImage(

                       "CloseNormal.png", "CloseSelected.png", this, menu_selector(HelloWorld::menuCloseCallback) );

         pCloseItem->setPosition( ccp(CCDirector::sharedDirector()->getWinSize().width - 20, 20) );

         pCloseItem->setTag(1);

 

         CCMenuItemImage *pSelectedItem = CCMenuItemImage::itemFromNormalImage(

                        "Normal.png", "Selected.png", this, menu_selector(HelloWorld::menuCloseCallback) );

         pSelectedItem->setPosition( CCPointMake(20, 20));

         pSelectedItem->setTag(2);

                 

         // create menu, it's an autorelease object

         CCMenu* pMenu = CCMenu::menuWithItems(pCloseItem, pSelectedItem, NULL);

         pMenu->setPosition( CCPointZero );

         this->addChild(pMenu, 1);

 

         /////////////////////////////

         // 3. add your codes below...

 

         // add a label shows "Hello World"

         // create and initialize a label

         m_pLabel = CCLabelTTF::labelWithString("Hello World", "fonts/impact.ttf", 30);

         m_pLabel->setColor(ccc3(197,245,244));

 

         m_pLabel2 = CCLabelBMFont::labelWithString("Ripple", "fonts/futura-48.fnt");

        

         // ask director the window size

         m_size = CCDirector::sharedDirector()->getWinSize();

 

                  // position the label on the center of the screen

         m_pLabel->setPosition( CCPointMake(m_size.width / 2, m_size.height - 40) );

         m_pLabel2->setPosition( CCPointMake(m_size.width / 2, 40) );

 

         // add the label as a child to this layer

         this->addChild(m_pLabel, 1);

         this->addChild(m_pLabel2, 1);

 

         // add "HelloWorld" splash screen"

         CCSprite* pSprite = CCSprite::spriteWithFile("HelloWorld.png");

 

         // position the sprite on the center of the screen

         pSprite->setPosition( CCPointMake(m_size.width/2, m_size.height/2) );

 

         // add the sprite as a child to this layer

         this->addChild(pSprite, 0);

 

         // 설명

         m_pTx = CCSprite::spriteWithFile("method.png");  //외부파일 로딩

         m_pTx->setAnchorPoint(ccp(0, 0.5)); //앵커 좌측하단, ccp()코코스좌표함수

         m_pTx->setPosition(CCPointMake(m_size.width, m_size.height/2));      //이미지 좌측하단 위치

         this->addChild(m_pTx, 2);         

 

         //스케줄러 호출

         schedule(schedule_selector(HelloWorld::ScrollTx), 0.5f);    //텍스트 스크롤

 

         // 터치이벤트 활성화

         this->setIsTouchEnabled(true);

        

         // 효과음 프리로드

         m_soundRipples->sharedEngine();

         m_soundWaves->sharedEngine();

         m_soundLiquid->sharedEngine();

 

         m_soundRipples->preloadEffect("waterdrop.wav");

         m_soundWaves->preloadEffect("wave.wav");

         m_soundLiquid->preloadEffect("bubble.wav");

 

         m_soundRipples->setEffectsVolume(1);

         m_soundWaves->setEffectsVolume(1);

         m_soundLiquid->setEffectsVolume(1);

 

         return true;

}

 

 

//텍스트 스크롤

void HelloWorld::ScrollTx(ccTime t)

{

         if(m_pTx->getPositionX() < -m_pTx->boundingBox().size.width)

         {

                  m_pTx->setPosition(ccp(m_size.width, m_size.height/2));

         }

         CCActionInterval *move = CCMoveBy::actionWithDuration(5, CCPointMake(-m_pTx->boundingBox().size.width, 0));

         m_pTx->runAction(move);

}

 

 

 

//리플 효과 주기 터치지점

void HelloWorld::MadeRipple(const CCPoint &p, const ccTime &t)

{

         // 리플효과 연속터치 횟수

         ++m_nRipple;

 

        

         // CCPoint center중심점, float r 범위, int wav 발생웨이브수, float amp, ccGridSize &gridSize, ccTime t 실행시간

         this->runAction(CCRipple3D::actionWithPosition(p, 0, 0, 0, ccg(32,24), 2.83f));

         this->runAction(CCRipple3D::actionWithPosition(p, m_size.height, 8, 10.f+t, ccg(32,24), 2.8f));

 

         this->runAction(CCRipple3D::actionWithPosition(p, 0, 0, 0, ccg(32,24), 1.73f));

         this->runAction(CCRipple3D::actionWithPosition(p, 200, 4, 40.f+t, ccg(32,24), 1.7f));

        

         this->runAction(CCRipple3D::actionWithPosition(p, 0, 0, 0, ccg(32,24), 0.53f));

         this->runAction(CCRipple3D::actionWithPosition(p, 100, 2, 80.f+t, ccg(32,24), 0.5f));

 

 

         //시간지연

         CCDelayTime* wait = CCDelayTime::actionWithDuration(3); 

 

         //터치 활성화

         CCCallFunc* waveChangeAction = CCCallFunc::actionWithTarget(this, callfunc_selector(HelloWorld::waveChangeOn));

 

         //시퀀스 등록: 액션 시퀀스 뒤에 콜백함수 호출,   

  //일반적인 액션시퀀스는 CCActionInterval *seq = (CCActionInterval*)CCSequence::actions

         CCFiniteTimeAction *seq = CCSequence::actions(wait, waveChangeAction, NULL);

         this->runAction(seq); // 시퀀스를 실행

     

}

 

// 웨이브 효과 주기 t 동안

void HelloWorld::MadeWave(const ccTime &t)

{

         // int wav 발생웨이브수, float amp, ccGridSize &gridSize 간격단위, ccTime t 실행시간

         this->runAction(CCWaves3D::actionWithWaves(0, 0, ccg(15,10), t+1.1f));

         this->runAction(CCWaves3D::actionWithWaves(3, 30, ccg(15,10), t+1.0f));

        

         //시간지연

         CCDelayTime* wait = CCDelayTime::actionWithDuration(t+1.3f); 

 

         //터치 활성화

         CCCallFunc* touchAction = CCCallFunc::actionWithTarget(this, callfunc_selector(HelloWorld::TouchOn));

 

         //시퀀스 등록: 액션 시퀀스 뒤에 콜백함수 호출,   

         CCFiniteTimeAction *seq = CCSequence::actions(wait, touchAction, NULL);

         this->runAction(seq); // 시퀀스를 실행

}

 

 

// 물효과

void HelloWorld::MadeLiquid(const ccTime &t)

{

         // int wav 발생웨이브수, float amp, ccGridSize &gridSize 간격단위, ccTime t 실행시간

         this->runAction(CCLiquid::actionWithWaves(0, 0, ccg(16,12), t+2.6f));

         this->runAction(CCLiquid::actionWithWaves(8, 10, ccg(16,12), t+2.5f));

        

         //시간지연

         CCDelayTime* wait = CCDelayTime::actionWithDuration(t+2.8f); 

 

         //터치 활성화

         CCCallFunc* touchAction = CCCallFunc::actionWithTarget(this, callfunc_selector(HelloWorld::TouchOn));

 

         //시퀀스 등록: 액션 시퀀스 뒤에 콜백함수 호출, 

         CCFiniteTimeAction *seq = CCSequence::actions(wait, touchAction, NULL);

         this->runAction(seq); // 시퀀스를 실행

}

 

 

void HelloWorld::TouchOn()

{

         m_touchOff = false;

}

 

void HelloWorld::waveChangeOn()

{       

         ++m_nCheck;

         if(m_nRipple == m_nCheck)

         {

                  m_changedWaveOff = false;

                  m_nRipple = 0;

                  m_nCheck = 0;

         }

}

 

void HelloWorld::UpdateLabel()

{

         //현재 시간 저장  

         CCTime::gettimeofdayCocos2d(&m_end, NULL);  //cc_timeval 구조체 long, long

         CCTime::timersubCocos2d(&m_result, &m_start, &m_end);  // 인터발 구함

         m_t = m_result.tv_sec + m_result.tv_usec / 1000000.f;  // ccTime 형으로 계산, float

        

         char str[17] = {}; //13 + 4 : 10,000 단위까지, 이상은 에러발생

//       sprintf_s(str, "Interval : %.2f", m_t);  //문자열 만들기

         sprintf(str, "Value : %.2f", m_t);  //문자열 만들기

         m_pLabel->setString(str);  //라벨 변경

}

 

 

 

 

//==================================//

//터치 이벤트

//==================================//

 

void HelloWorld::ccTouchesBegan(CCSet *pTouch, CCEvent *pEvent)

{

         // 현재 시간 저장

         CCTime::gettimeofdayCocos2d(&m_start, NULL);

        

         if(m_touchOff) return;

 

         //라벨 바꾸기

         UpdateLabel();

}

 

 

void HelloWorld::ccTouchesMoved(CCSet *pTouch, CCEvent *pEvent)

{

         if(m_touchOff) return;

         UpdateLabel();

}

 

void HelloWorld::ccTouchesEnded(CCSet *pTouch, CCEvent *pEvent)

{

         if(m_touchOff) return;

         UpdateLabel();

 

         //좌표 추출

         CCTouch *touch = (CCTouch*)(pTouch->anyObject());

         CCPoint touchGlPoint = touch->locationInView(touch->view());

 

 

         switch(m_caseEffect)

         {

         case 0:

                  //파문 효과

                  m_changedWaveOff = true;

                  m_soundRipples->playEffect("waterdrop.wav", false); //: 재생할 사운드 파일이름

                                                     //UI 좌표를 GL좌표로 변경

                  MadeRipple(CCDirector::sharedDirector()->convertToGL(touchGlPoint), m_t);

                  break;

         case 1:

                  m_touchOff = true;        

                  //웨이브효과

                  m_soundWaves->playEffect("wave.wav", false); //: 재생할 사운드 파일이름

                  MadeWave(m_t);

                  break;

         case 2:

                  m_touchOff = true;

                  //물효과

                  m_soundLiquid->playEffect("bubble.wav", false); //: 재생할 사운드 파일이름

                  MadeLiquid(m_t);

                  break;

         }       

 

 

 

//       CCLog("t: %f", m_t);

}

 

void HelloWorld::ccTouchesCancelled(CCSet *pTouch, CCEvent *pEvent)

{

         // 디바이스 정지시

}

 

 

void HelloWorld::menuCloseCallback(CCObject* pSender)

{

         CCMenuItem* item = (CCMenuItem*)pSender;

         if(item->getTag() == 1)

         {

                  CCDirector::sharedDirector()->end();

         }

         else if(item->getTag() == 2)

         {

                  if(m_touchOff || m_changedWaveOff) return;

                 

                  if(m_caseEffect == 0)

                  {

                           m_caseEffect = 1;

                           m_pLabel2->setString("Wave");  //라벨 변경

                  }

                  else if(m_caseEffect == 1)

                  {

                           m_caseEffect = 2;

                           m_pLabel2->setString("Liquid");  //라벨 변경

                  }

                  else

                  {

                           m_caseEffect = 0;

                           m_pLabel2->setString("Ripple");  //라벨 변경

                  }

         }

#if (CC_TARGET_PLATFORM == CC_PLATFORM_IOS)

         exit(0);

#endif 

}

저작자 표시 비영리 변경 금지
신고
크리에이티브 커먼즈 라이선스
Creative Commons License

 

 

비트맵 형식으로 원을 그리는 알고리듬, 중심점에서 실제의 반지름에 해당하는 지점에서 가장 가까운 픽셀을 찍는 방식이다. 제곱근이나 삼각함수 없이 정수 연산으로 빠르게 처리할 있다.

찾으려는 다음 픽셀은 예를 들어, 시계의 12 지점에서 오른쪽으로 1픽셀 이동 또는 오른쪽 1픽셀이동 아래로 1픽셀 이동한 점이 된다. 쉽게 생각하면, 시계 12 지점에서 시계방향으로 원을 그리는데 있어 연필의 진행방향이 오른쪽 또는 오른쪽 아래가 된다는 . 프로그램 코딩상에서 실제로 식에 의해 그리게 되면 중심각 45도가 되는 지점까지의 원호를 그리게 된다.

 

>>>사용되는 수식 정의<<<

 

방정식 :  x²+ y²- r²= 0 (중심점 x, y 반지름 r)

 

해당 픽셀 : Pk = (xk, yk)

오차     : Ek = xk2 + yk2 - r²

 

Pk 다음 진행 지점 픽셀 : x 1픽셀 더한 지점 : xk + 1, y 1픽셀 지점 yk - 1

P1 = (xk + 1 , yk)

P2 = (xk + 1 , yk - 1)

 

오차  :  E1 = (xk + 1)2 + yk2 - r²   

  E2 = (xk + 1)2 + (yk – 1)2 - r²  

 

(단 E1 > E2)

 

여기서 오차가 0 실제 중심점에서 반지름에 해당하는 정확한 지점이 되는데 오차가 양수 때는 반지름 보다 지점이 되고 음수일 때는 반대가 된다.  

 

개의 다음 진행 픽셀 중에 오차가 작은 픽셀을 선택한다. 하지만 오차의 값이 양수 음수 경우가 생기게 되는데 오차가 양수일 때는 항상E2 E1 보다 작으므로 P2 픽셀을 선택한다. 다시 말해 정확한 반지름 위치에 접근한 픽셀이다.

그리고 음수일 때는 P1 선택한다. 다시 말해 정확한 반지름 위치보다 안쪽으로 들어오게 되므로 음수의 절대치가 쪽을 선택한다.

그러나 E1 양수 E2 음수일 경우(오른쪽 다음 픽셀은 원의 바깥쪽 오른쪽 아래 픽셀은 원의 안쪽에 위치할 ) 에는 오차의 절대치 값이 작은 쪽을 선택하면 된다.

그리고 E1 음수 E2 양수일 수는 없다.

      

E1 > 0, E2  > 0 : P2 선택

E1 < 0, E2  < 0 : P1 선택

E1 > 0 , E2 < 0 : P1, P2 중에 절대치가 작은 쪽을 선택절대치가 같은 경우 어느 쪽을 선택해도 상관없다.

 

결론적으로 수식으로 정의 하면, 오차의 합이 음수일 음수일 경우에는 물론 P1 선택하게 되고 E1양수, E2음수 E2 절대치가 크다는 사실이 되므로 오차가 작은 P1 선택해야 된다.

또한 오차의 합이 양수일 P2 선택, E1양수, E2음수 E1 절대치가 크다는 사실이 되므로 오차가 작은 P2 선택해야 된다.

마지막으로 오차의 합이 0 때는 오차의 절대치가 같다는 경우이므로 어느 쪽을 선택해도 상관없다.  

 

E1 + E2 < 0 : P1 선택

E1 + E2 > 0 : P2 선택

E1 + E2 = 0 : 아무거나 선택(자바 코딩상에서는 P2 선택)

 

판별식 :

F(k) = E1 + E2

       = (xk + 1)2 + yk2 - r² + (xk + 1)2 + (yk – 1)2 - r²     

       = 2(xk2 + 2xk + 1) + yk2 + (yk2 - 2yk + 1) - 2r²

       = 2xk2 + 4xk + 2 + 2yk2 - 2yk + 1 - 2r²

       = 2xk2 + 2yk2 + 4xk - 2yk - 2r² + 3

       = 2(xk2 + yk2 - r²) + 4xk - 2yk + 3

       = 2Ek + 4xk - 2yk + 3

 

 

P 최초 시작점(초기화, 12) : xk = 0, yk = r, p = -2r + 3

F(0) = 2Ek + 4xk - 2yk + 3

       = -2yk + 3

       = -2r + 3

 

 

다음 진행 픽셀 수식:

 

P1 경우 : P1 = (Xk + 1, yk)

     F(k + 1) = 2E1 + 4(xk + 1) - 2yk + 3 

             = 2(xk2 + 2xk + 1 + yk2 - r²) + 4xk + 4 - 2yk + 3

             = 2xk2 + 2yk2 - 2r² + 2 + 4xk + 4xk + 4 - 2yk + 3

             = 2(xk2 + yk2 - r²) + 4xk - 2yk + 3 + 4xk + 6

= 2Ek + 4xk - 2yk + 3 + 4xk + 6

             = F(k) + 4xk + 6

 

P2 경우 : P2 = (Xk + 1, yk – 1)

F(k + 1) = 2E2 + 4(xk + 1) – 2(yk – 1) + 3 

             = 2(xk2 + 2xk + 1 + yk2 - 2yk + 1 - r²) + 4xk + 4 - 2yk + 2 + 3

             = 2xk2 + 2yk2 - 2r² + 4xk + 2 - 4yk + 2  + 4xk + 4 - 2yk + 2 + 3

             = 2(xk2 + yk2 - r²) + 4xk - 2yk + 3 + 4xk - 4yk + 10

= F(k) + 4xk - 4yk + 10

= F(k) + 4(xk - yk) + 10

 

 

 

 

자바 코드안드로이드 SurfaceHoler 사용해 그리는 메서드

* 주의점은 drawRect() 그릴 Y축의 개념은 흔히 쓰는 그래프상의 위치와     

  상반된다는 것. 

   *  8부분으로 나누어 서로 상반되게 x축과 y축을 지정해서 그리게 된다.

 *  기본적으로 x 값을 1 픽셀씩 증가시키면서  판별식을 이용해서 Y 값을     

감소시키는 때를 선택하는 알고리듬이 된다.

 

//Canvas.drawRect() 이용한 원주 그리기, Bresenham 알고리즘

private void circle(Canvas canvas, int x, int y, int radius){

if(radius <= 0) return; //반지름 0 이하일때 실행 안함

             

//값 초기화

     int xK = 0; //x축 해당값 초기화

     int yK = radius;//y축 해당값 반지름 값으로 초기화  

     int pK = 3 - (radius + radius); //3 - 2 * r, 픽셀 초기 시작지점

 

     do{

  //

          paint.setColor(Color.LTGRAY);

//동, 회색          

canvas.drawRect(x + xK, y - yK, x + xK + 4, y - yK + 4, paint);

          paint.setColor(Color.BLUE);

//, 청색

          canvas.drawRect(x - xK, y - yK, x - xK + 4, y - yK + 4, paint); 

                      

          //

          paint.setColor(Color.WHITE);

//, 흰색

          canvas.drawRect(x + xK, y + yK, x + xK + 4, y + yK + 4, paint);

          paint.setColor(Color.RED);

//, 적색

          canvas.drawRect(x - xK, y + yK, x - xK + 4, y + yK + 4, paint);

                      

          //

          paint.setColor(Color.CYAN);

//, 하늘색

          canvas.drawRect(x + yK, y - xK, x + yK + 4, y - xK + 4, paint);

          paint.setColor(Color.MAGENTA);

//, 분홍색

          canvas.drawRect(x + yK, y + xK, x + yK + 4, y + xK + 4, paint);

 

          //

          paint.setColor(Color.YELLOW);

//

          anvas.drawRect(x - yK, y - xK, x - yK + 4, y - xK + 4, paint);

          paint.setColor(Color.GREEN);

//

          canvas.drawRect(x - yK, y + xK, x - yK + 4, y + xK + 4, paint);

 

          xK++; // x 다음 픽셀 1 증가

                      

          //P1 선택 : pK + xK * 4 + 6 판별식

          if(pK < 0) pK += (xK << 2) + 6;  //판별할 pK 갱신

                    /*

                     * 쉬프트 연산자 << : xK << n --> xK * 2 n   

                     * >> : xK >> n --> xK / 2^n(승), 쉬프트연산자가 '*',     

* '/' 연산속도 보다 빠르다.

                     */

                      

          //P2선택 : pK + (xK - yK) * 4 + 10 판별식, yK 감소                 

            

          else {

          --yK; // 다음 픽셀 y 1 감소

               pK += ((xK - yK) << 2) + 10; //판별할 pK 갱신

     }

}while(xK <= yK); //x 증가치가 y 감소치의 합이 반지름과 같을때 까지, 45

}

저작자 표시 비영리 변경 금지
신고
크리에이티브 커먼즈 라이선스
Creative Commons License

 

 

콘웨이 박사의 '게임오브라이프' 를 자바로 만들어 보았읍니다.

참고 사이트 :  http://en.wikipedia.org/wiki/Conway%27s_Game_of_Life

 

이 게임을 간략하게 설명하자면,  2차원 격자로 형성된 무한평면에서 하나의 격자(cell)를 생명단위로 설정하고

주변 8개 셀들에 의해 그 셀이 살아남거나 죽어버리거나 또는 탄생하거나 하는 규칙을 정해서

다음 세대로 전이되어가는 상태를 보여줍니다. 마치 세포들이 생성되고 소멸되는 모습을 보는 듯 하죠.

자바코드에서는 물론 무한평면이 아닙니다.

 

영국의 수학자인 John Horton Conway 박사가 1970년에 고안했다고 합니다.

룰은 4가지 입니다.

 

* Any live cell with fewer than two live neighbours dies, as if caused by under-population.
* Any live cell with two or three live neighbours lives on to the next generation.
* Any live cell with more than three live neighbours dies, as if by overcrowding.
* Any dead cell with exactly three live neighbours becomes a live cell, as if by reproduction.

 

 

 

 

1. 살아있는 셀 A의 주변 8개 셀 중에 2개 미만의 수(즉, 0 또는 1개)가 살아있을때 A셀은 죽어버립니다. 왜냐구요? 외로워서...

2. 살아있는 셀 A의 주변 8개 셀 중에 2개 또는 3개의 셀이 살아있을때 A셀은 살아남습니다.

3. 살아있는 셀 A의 주변 8개 셀 중에 4개 이상의 셀(4 ~ 8개)이 살아있을때 A셀의 죽어버립니다. 왜? 살기가 복잡해서...

4. 죽어있는 셀 A의 주변 8개 셀 중에 정확히 3개의 셀이 살아있을때 죽어있는 A셀이 살아납니다. 왜냐구요? 그냥 룰이니까...

 

이렇게 4가지 룰을 적용해서 마치 자동으로 세포가 생성되고 소멸되는 모습을 보여줍니다.

그리고 영원히 살아남는 셀무리도 생깁니다.

흥미롭죠? 규칙을 마음대로 정해서 만들어도 됩니다.

 

간단한 로직으로 간단하게 만들 수 있는 코드이지만 결과는 정말이지 흥미롭습니다.

지구에 최초의 생명체가 탄생하는 과정을 볼 수는 없지만 우주의 상수들이 생명탄생의 적합한 환경으로 만들고

오랜 세월에 걸쳐 생명이 탄생했을 것이라는 막연한 상상 같은 실생활에 전혀 쓸데 없는 생각을 하게 만드네요.

 

셀을 잘 디자인해서 실행하면  재미있는 모습을 볼 수도 있읍니다. 초기 데모화면중에 "New" 버튼을 누르면

게임 실행 준비가 됩니다. 마우스로 셀을 클릭하거나 드랙해서 "Start" 버튼누르면 실행됩니다.

마우스 오른쪽 버튼 클릭하면 도움말 나옵니다.

 

 

실행파일 다운로드

 

 

자바 실행파일 첨부했으나 자바가상머신이 컴퓨터에 깔려있어야 실행된다는 점...

최소한 JRE를 깔아도 아마도 될 겁니다. 자바 설치 방법은 검색하시면 나옵니다.

자바 다운로드  : http://www.oracle.com/technetwork/java/javase/downloads/index.html

끝.

 

 

 

<Result>

저작자 표시 비영리 변경 금지
신고
TAG Conway

Android image crop

Android 2012.09.19 17:18
크리에이티브 커먼즈 라이선스
Creative Commons License

 

퍼즐 게임에 들어가는 일부 코드 :

안드로이드 내장 갤러리를 띄워 스마트폰 sd카드에 있는 이미지나 카메라로 찍은 이미지를 불러와서 크롭(잘라내기)해서 새로운 비트맵파일을 생성하는 코드

간단한 로직이지만 스마트폰 내장 갤러리는 이미지가 새로 생성되거나 사용자가 임으로 파일을 삭제할때 그때 그때 스캔해서 이미지를 띄워주지 않는다. 

Cursor 클래스를 이용해서 Thumb nail 파일 데이터들을 같이 조작 거나 접근해서 파일들을 처리하는 로직도 있지만 일이 더 커진다... 사용자가 임으로 해당 이미지파일을 삭제하면...썸네일과 실제이미지가 꼬여버리는 일이 발생한다.  파일들을 함부로 건드리면...골치아프다는... 

하지만 한번에 이런 것들을 해결하는 코드가 미디어 재스캔

 android.content.ContextWrapper.sendBroadcast(Intent intent)
갤러리를 띄울때나 크롭할때 미디어 재스캔 요청하면 알아서 제대로 파일들을 띄워준다.

그래서 MediaStore.EXTRA_OUTPUT 를 마음 편하게 쓰면 된다.

초기화 파일 생성 및 로딩 코드도 있다. 차근 차근 보면 꽤 쓸만한 로직?

 

Main.java, main.xml, AndroidManifest.xml 세개 파일.

결과: sdcard/division 폴더속에 크롭한 이미지들이 생겨난다. 사용자가 만들어진 크롭파일들을 삭제해도 파일 이름 설정은 초기화 파일(bbaddoCrop.cfg)로 인해 계속 증가치로 저장된다. 재인스톨시 해당폴더 속에 같은 이름의 이미지가 있을시 초기화 파일이 없으므로  10000.png 로 부터 다시 덮어쓰게 됨... 파일들이 꼬여진다.. 다른 로직을 만들어 쓰면 간단히 해결된다. 아래 코드에서는 빠져있다. 

 

 

 

 

 

 

 

package pes.imagecrop;

 

 

/* 

 * Extra Options Table for image/* crop: Intent.putExtra("Options", Value of the data type);

 * 카메라 크롭을 이용해 오려진 이미지를 가져오기

 *

 * Options ""       DataType                   Description

 * =======================================================

 * crop            String                     Signals the crop feature

 * aspectX          int                        Aspect Ratio

 * aspectY          int                        Aspect Ratio

 * outputX          int                       width of output created from this Intent

 * outputY          int                       width of output created from this Intent

 * scale            boolean                    should it scale

 * return-data      boolean                 Return the bitmap with Action=inline-data by using the data

                                                crop 이미지를 intent 통해서 수신 받을 여부

 * data          Parcelable                 Bitmap to process, you may provide it a bitmap (not tested)

 * circleCrop      String                if this string is not null, it will provide some circular cr

 * output           URI              Set this URi to a File:/// , (==> MediaStore.EXTRA_OUTPUT)

                                           crop 이미지를 intent 통해서 파일로 저장. 기기마다 오류가 발생

 * noFaceDetection   boolean             camera.face

 *

 *

 */

 

import java.io.File;

import java.io.FileInputStream;

import java.io.FileNotFoundException;

import java.io.FileOutputStream;

import java.io.IOException;

import java.util.Properties;

import android.app.Activity;

import android.app.AlertDialog;

import android.content.Context;

import android.content.DialogInterface;

import android.content.Intent;

import android.graphics.Bitmap;

import android.graphics.BitmapFactory;

import android.net.Uri;

import android.os.Bundle;

import android.os.Environment;

import android.provider.MediaStore;

import android.view.KeyEvent;

import android.view.View;

import android.view.View.OnClickListener;

import android.widget.Button;

import android.widget.ImageView;

 

 

public class Main extends Activity{

       private static final int PICK_FROM_CAMERA;  //카메라

       private static final int PICK_FROM_GALLERY;   //갤러리

       private static final int AFTER_CROP;  //크롭 com.android.camera.action.CROP

       static {

PICK_FROM_CAMERA = 0

PICK_FROM_GALLERY = 1;

AFTER_CROP = 2;

 }

       private Uri captureUri;  //카메라, 갤러리 파일 경로

       private Uri cropUri; //크롭파일 경로

       private ImageView iv;

       private Button bt;

       private int name ; //크롭파일 이름 설정 상수

       private File tempFile; //카메라 캡쳐 임시 파일

       private boolean cameraFlag = false; //임시파일 지우기 플랙, 카메라일때만 적용

      

       @Override

       public void onCreate(Bundle savedInstanceState){

             super.onCreate(savedInstanceState);

             setContentView(R.layout.main);

            

             //이미지파일 저장할 폴더 만든다

             File f = new File(Environment.getExternalStorageDirectory().getAbsolutePath()+ "/division");

             if(!f.isDirectory()) f.mkdir();

 

             //미디어 재스캔 요청

             sendBroadcast(new Intent(Intent.ACTION_MEDIA_MOUNTED,

                                   Uri.parse("file://" + Environment.getExternalStorageDirectory())));

 

             if(!initialFileRead()){

                    name = 10000;

             }

             bt = (Button) findViewById(R.id.button);

             bt.setText("Load Images");

             iv = (ImageView) findViewById(R.id.image);

             bt.setOnClickListener(load);

       }

 

       //카메라에서 이미지 획득

       private void getCameraPhoto(){

             cameraFlag = true;

            

             //==MediaStore.ACTION_IMAGE_CAPTURE

             Intent cameraIntent = new Intent("android.media.action.IMAGE_CAPTURE");

 

             //카메라로 찍은 최초 이미지 임시파일 설정 저장

             tempFile = new File(Environment.getExternalStorageDirectory(), "tempo1234.jpg");

             captureUri = Uri.fromFile(tempFile);

            

             //==android.provider.MediaStore.EXTRA_OUTPUT == MediaStore.EXTRA_OUTPUT

             cameraIntent.putExtra("output", captureUri); //카메라 캡쳐 임시파일생성, 카메라 ok 버튼 눌렀을때

             startActivityForResult(cameraIntent, PICK_FROM_CAMERA); //0 : 카메라

       }

      

       //갤러리에서에서 이미지 획득

       private void getGalleryPhoto(){

             cameraFlag = false;

            

             //미디어 재스캔 요청

             sendBroadcast(new Intent(Intent.ACTION_MEDIA_MOUNTED,

                           Uri.parse("file://" + Environment.getExternalStorageDirectory())));

            

             // ACTION_PICK : 데이터 실제주소 이용, ACTION_GET_CONTENT : 데이터 유형 이용

             Intent galleryIntent = new Intent("android.intent.action.PICK"); // ==Intent.ACTION_PICK

            

             //==android.provider.MediaStore.Images.Media.CONTENT_TYPE

             galleryIntent.setType("vnd.android.cursor.dir/image");

            

             //이미지뷰의 이미지 선택, 두번째 파라메타가 resultCode

             startActivityForResult(galleryIntent, PICK_FROM_GALLERY);  //1 : 갤러리

       }

 

      

       //결과값 처리 : crop 해서 bitmap 생성, 원본카메라촬영 파일 제거

       @Override

       protected void onActivityResult(int requestCode, int resultCode, Intent intent) {

             //미디어 재스캔 요청

             sendBroadcast(new Intent(Intent.ACTION_MEDIA_MOUNTED,

                    Uri.parse("file://" + Environment.getExternalStorageDirectory()))); //미디어 새로 스캔

 

             //startActivityForResult(Intent, 상수)파라미터 두번째 상수값이 제대로 되었을때만 통과 -1 아닐때

             if(resultCode != RESULT_OK){  //RSULT_OK == -1

                    if (resultCode == RESULT_CANCELED){ //카메라 캔슬시 

                           if(cameraFlag){

                                 if(tempFile.exists()) tempFile.delete();

                           }

                    }

                    return;      

             }

            

             switch(requestCode) {

             case PICK_FROM_GALLERY:

                    captureUri = intent.getData();

                    crop();

                    break;

             case PICK_FROM_CAMERA:

                    crop();

                    break;

                   

             //크롭된 임시파일 제거와 View 처리를 위해 startActivityForResult 한번 호출  

             case AFTER_CROP:   

                    //저장된 크롭파일 이미지뷰에 보이기

                    try{

                        Bitmap cropPhoto = BitmapFactory.decodeFile(cropUri.getPath());

                           iv.setImageBitmap(cropPhoto);

                           iv.setScaleType(ImageView.ScaleType.FIT_XY);

                    } catch(Exception e){ return; }

 

                    //카메라 촬영 원본 임시파일 삭제

                    if(cameraFlag){

                           if(tempFile.exists()) tempFile.delete();

                    }

                    ++name;  //크롭저장파일 이름 설정

                    break;

             }

       }

 

       //이미지 크롭해서 비트맵 파일 생성

       public void crop(){

             Intent cropIntent = new Intent("com.android.camera.action.CROP"); //크롭 액티비티 실행

             //특정확장자 지정은  ex) setType("/image/jpg")

             cropIntent.setDataAndType(captureUri, "image/*"); //크롭할 파일들 경로 형식 설정

 

             //크롭파일 설정

             cropIntent.putExtra("outputX", 300);  //이미지 해상도

             cropIntent.putExtra("outputY", 300);

             cropIntent.putExtra("aspectX", 1);  //가로세로 비율

             cropIntent.putExtra("aspectY", 1);

             cropIntent.putExtra("scale", true); //꽉찬 비율로 저장

             cropIntent.putExtra("noFaceDetection", true); //camera.face

             cropIntent.putExtra("outputFormat", Bitmap.CompressFormat.PNG.toString()); //png_ 파일형식저장

          

           //생성될 크롭파일 경로 설정

           cropUri = Uri.fromFile(

                     new File(Environment.getExternalStorageDirectory().getAbsolutePath() + "/division",

                                        "c" + name + ".png"));

            

           //크롭파일 저장

           //==android.provider.MediaStore.EXTRA_OUTPUT == "output"

           cropIntent.putExtra(MediaStore.EXTRA_OUTPUT, cropUri); //크롭 파일저장

             startActivityForResult(cropIntent, AFTER_CROP);

       }

      

       //버튼 클릭이벤트

       private OnClickListener load = new OnClickListener(){

             @Override

             public void onClick(View v) {

                    new AlertDialog.Builder(Main.this)   //일단 이런식으로 얄궂게 클릭이벤트 설정

                    .setIcon(0)  //0 : 헤더아이콘 제거

                    .setTitle("Choose Image From...  ")

                    .setPositiveButton("Camera", new DialogInterface.OnClickListener(){

                           @Override

                           public void onClick(DialogInterface dialog, int which) {

                                 getCameraPhoto();

                           }

                    })

                    .setNeutralButton("Gallery", new DialogInterface.OnClickListener(){

 

                           @Override

                           public void onClick(DialogInterface dialog, int which) {

                                 getGalleryPhoto();

                           }

                    })

                    .setNegativeButton("Cancel", new DialogInterface.OnClickListener(){

 

                           @Override

                           public void onClick(DialogInterface dialog, int which) {

                                 dialog.dismiss();

                           }

                    }).show();                

             }

       };

      

      

       //===============================

       // 초기화 설정 파일 저장 불러오기

       //===============================

       public void initialFileWrite(){    //초기 설정 파일 만들기

             Properties pp = new Properties();

             pp.setProperty("name", "" + name);

      

             FileOutputStream out = null;

             try {

                    out = openFileOutput("bbaddoCrop.config", Context.MODE_PRIVATE);

                    pp.store(out,"BbaDdo Crop Config Setting");

                    out.close();

             }      catch (FileNotFoundException e) {}

                    catch (IOException e) {}

             }

                   

       public boolean initialFileRead(){  //초기 설정 파일 불러오기

             Properties pp = new Properties();

             FileInputStream in = null;

             try {

                    in = openFileInput("bbaddoCrop.config");

                    pp.load(in);

                    in.close();

             }      catch (FileNotFoundException e) {return false;}

              catch (IOException e) {return false;}

 

             name = Integer.parseInt(pp.getProperty("name"));

             return true;

       }

      

       //=========================================

       // 디바이스 BACK 이벤트 : 종료  

       //=========================================

       @Override

       public boolean onKeyUp(int keyCode, KeyEvent event) {

              if(keyCode == KeyEvent.KEYCODE_BACK){    //안드로이드 백스페이스 종료

                    new AlertDialog.Builder(this)  //프로세서 종료를 위한 얼러트다이얼로그

               .setIcon(android.R.drawable.ic_menu_close_clear_cancel)  //0 : 헤더아이콘 제거

               .setTitle("Quit")

               .setMessage("Are you sure?")

               .setPositiveButton("Yes", new DialogInterface.OnClickListener() {

                   @Override

                   public void onClick(DialogInterface dialog, int which) {

                       initialFileWrite();

                       moveTaskToBack(true);

                       finish();