Рисование на холсте с использованием пользовательского метода?

#java #android #resources #canvas #drawable

#java #Android #Ресурсы #холст #можно рисовать

Вопрос:

Я пишу для 2-D игры для Android, и у меня возникли некоторые проблемы.

В настоящее время в моем пакете у меня есть поток, который рисует на экземпляре холста. Я рисую растровые изображения, доступные для рисования, из ресурсов. Что я хотел бы сделать, так это сохранить поток, передающий рисунок фонового изображения. Но есть ли экземпляры пользовательских объектов, способных рисовать на том же холсте, используя drawable objects. Это кажется возможным логически, но я не могу заставить это работать. Каждый раз, когда я пытаюсь извлечь ресурсы из своего пользовательского класса, приложение вылетает при запуске.

Вот пара моих попыток: (пожалуйста, не смейтесь, если я сделал что-то глупое, я пытаюсь.)

 public class Worker{

//Get drawables
//  Resources res = getResources();
//  Drawable man1 = res.getDrawable(R.drawable.workertest);


//  Context mContext;
//  Resources res = mContext.getResources();

//  Drawable man1 = mContext.getResources().getDrawable(R.drawable.workertest);
//  Drawable man2 = mContext.getResources().getDrawable(R.drawable.workertest1);

//  Drawable man1 = res.getDrawable(R.drawable.workertest);
//  Drawable man2 = res.getDrawable(R.drawable.workertest1);

}
  

Как вы можете видеть, я попробовал пару разных методов, и я также попытался добавить (extends activity) в свой класс, но я не могу понять это.

Этот код не касается фактического рисования на холсте, мне еще предстоит пересечь этот мост

Редактировать: Вот действие. Как вы можете видеть, это вызывает поток в lunarview. Этот поток создает экземпляр объекта, который должен извлекать рисуемый объект. как, во имя всего святого, мне получить контекст приложения для объекта? или есть другой способ сделать это? И да, это код из примеров кодов Android.

 public class LunarLander extends Activity {
    private static final int MENU_EASY = 1;

    private static final int MENU_HARD = 2;

    private static final int MENU_MEDIUM = 3;

    private static final int MENU_PAUSE = 4;

    private static final int MENU_RESUME = 5;

    private static final int MENU_START = 6;

    private static final int MENU_STOP = 7;


    /** A handle to the thread that's actually running the animation. */
    public static LunarThread mLunarThread;

    /** A handle to the View in which the game is running. */
    public LunarView mLunarView;



    /**
     * Invoked during init to give the Activity a chance to set up its Menu.
     *
     * @param menu the Menu to which entries may be added
     * @return true
     */
    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        super.onCreateOptionsMenu(menu);

        menu.add(0, MENU_START, 0, R.string.menu_start);
        menu.add(0, MENU_STOP, 0, R.string.menu_stop);
        menu.add(0, MENU_PAUSE, 0, R.string.menu_pause);
        menu.add(0, MENU_RESUME, 0, R.string.menu_resume);
        menu.add(0, MENU_EASY, 0, R.string.menu_easy);
        menu.add(0, MENU_MEDIUM, 0, R.string.menu_medium);
        menu.add(0, MENU_HARD, 0, R.string.menu_hard);

        return true;
    }

    /**
     * Invoked when the user selects an item from the Menu.
     *
     * @param item the Menu entry which was selected
     * @return true if the Menu item was legit (and we consumed it), false
     *         otherwise
     */
    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        switch (item.getItemId()) {
            case MENU_START:
                mLunarThread.doStart();
                return true;
            case MENU_STOP:
                mLunarThread.setState(LunarThread.STATE_LOSE,
                        getText(R.string.message_stopped));
                return true;
            case MENU_PAUSE:
                mLunarThread.pause();
                return true;
            case MENU_RESUME:
                mLunarThread.unpause();
                return true;
            case MENU_EASY:
                mLunarThread.setDifficulty(LunarThread.DIFFICULTY_EASY);
                return true;
            case MENU_MEDIUM:
                mLunarThread.setDifficulty(LunarThread.DIFFICULTY_MEDIUM);
                return true;
            case MENU_HARD:
                mLunarThread.setDifficulty(LunarThread.DIFFICULTY_HARD);
                return true;
        }

        return false;
    }

    /**
     * Invoked when the Activity is created.
     *
     * @param savedInstanceState a Bundle containing state saved from a previous
     *        execution, or null if this is a new execution
     */
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        // tell system to use the layout defined in our XML file
        setContentView(R.layout.lunar_layout);

        // get handles to the LunarView from XML, and its LunarThread
        mLunarView = (LunarView) findViewById(R.id.lunar);
        mLunarThread = mLunarView.getThread();


        // give the LunarView a handle to the TextView used for messages
        mLunarView.setTextView((TextView) findViewById(R.id.text));




        if (savedInstanceState == null) {
            // we were just launched: set up a new game
            mLunarThread.setState(LunarThread.STATE_READY);
            Log.w(this.getClass().getName(), "SIS is null");
        } else {
            // we are being restored: resume a previous game
            mLunarThread.restoreState(savedInstanceState);
            Log.w(this.getClass().getName(), "SIS is nonnull");
        }
    }

    /**
     * Invoked when the Activity loses user focus.
     */
    @Override
    protected void onPause() {
        super.onPause();
        mLunarView.getThread().pause(); // pause game when Activity pauses
    }

    /**
     * Notification that something is about to happen, to give the Activity a
     * chance to save state.
     *
     * @param outState a Bundle into which this Activity should save its state
     */
    @Override
    protected void onSaveInstanceState(Bundle outState) {
        // just have the View's thread save its state into our Bundle
        super.onSaveInstanceState(outState);
        mLunarThread.saveState(outState);
        Log.w(this.getClass().getName(), "SIS called");
    }
    public boolean onTouchEvent(MotionEvent event){
        int clickX = Math.round(event.getX()/10)*10;
        int clickY = Math.round(event.getY()/10)*10;

        LunarView.xCo = clickX;
        LunarView.yCo = clickY;

        return true;

    }
  

Комментарии:

1. Итак … есть ли у вас основное действие в вашем приложении? Если бы вы могли опубликовать сбой, который вы получили, это помогло бы. Однако я предполагаю, что в вашем приложении нет действия, необходимого для запуска приложения для Android.

2. Также полезно получать выходные данные из logcat при сбое. Предполагая, что вы находитесь в Eclipse, вы можете получить это из представления DDMS.

3. Нет, я делаю, в приложении есть несколько классов. И основная активность заключается в другом. фактически, в указанном выше классе есть другие методы, которые работают отлично. единственный раз, когда я получаю сбой, это когда я пытаюсь использовать ресурсы для рисования в этом пользовательском классе. Когда я закомментировал приведенный выше код, приложение работает отлично, если не при запуске, я получаю сообщение «Извините, приложение неожиданно остановилось. Попробуйте еще раз. Ошибок компилятора нет.

4. @espertus, они длинные, но я опубликовал их выше

5. Я придумал временный обходной путь… Поскольку поток обрабатывает чертежи без ошибок. Я создал метод в потоке, который рисует изображение, а затем я создал метод в моем пользовательском классе, который вызывает метод рисования в потоке. кажется, это очень неэффективный способ сделать это, но, похоже, пока работает.

Ответ №1:

Как предположил Грег, проблема заключается в получении права Context на извлечение ресурсов. Простой способ решить эту проблему — передать main Activity в качестве аргумента в Worker конструкторе класса и сохранить его как private Context поле. Что-то вроде:

 public class Worker{
  private Context mContext;
  public Worker (Context context) {
    mContext = context;
    Resources res = mContext.getResources();
    // all the rest of your code
  }
}
  

Вы будете использовать его в своей основной деятельности как:

 Worker worker = new Worker(this);
  

Комментарии:

1. единственная проблема, которую я вижу, заключается в том, что код, в котором мне нужно реализовать класс worker, — это поток, созданный для рисования пользовательского интерфейса и обработки кликов и т.д. Поэтому моя трудность заключается в понимании того, как передать фактический контекст приложения конструктору. Другими словами, приведенный выше код, реализующий (new Worker(this)), не работает. «Это» читается как имя класса LunarView. Я не знаю, имеет ли это смысл.

2. Вам придется это выяснить. Если ваш класс LunarView является внутренним классом вашей Activity, то используйте MyActivity.this вместо этого. Если нет, то используйте ту же идею (передавая контекст в конструктор) при создании экземпляра класса LunarView из вашей Activity.

3. uuuuugggg это не работает, лол, Какой именно синтаксис мне нужен?

4. Я не вижу, где вы создаете экземпляр этого рабочего класса, поэтому трудно сказать вам точно, что делать. Но классы LunarView и LunarThread уже имеют поля, указывающие на правильный контекст: в LunarThread называется mContext. Используйте это для своего конструктора в рабочем классе.