Android API DEMO:简单手绘游戏

来源:互联网 发布:霍去病的小说知乎 编辑:程序博客网 时间:2024/04/29 12:32
/** * 利用系统 UI flag特性模拟身临其境的game *  * @description: * @author ldm * @date 2016-5-26 下午4:13:04 */public class GameActivity extends Activity {    /**     * 自定义游戏视图,填充整个屏幕。     *      * @description:     * @author ldm     * @date 2016-5-26 下午4:16:17     */    public static class Content extends TouchPaint.PaintView implements            View.OnSystemUiVisibilityChangeListener, View.OnClickListener {        Activity mActivity;        Button mPlayButton;        boolean mPaused;        int mLastSystemUiVis;        boolean mUpdateSystemUi;        Runnable mFader = new Runnable() {            @Override            public void run() {                fade();                if (mUpdateSystemUi) {                    updateNavVisibility();                }                if (!mPaused) {                    getHandler().postDelayed(mFader, 1000 / 30);                }            }        };        public Content(Context context, AttributeSet attrs) {            super(context, attrs);            setOnSystemUiVisibilityChangeListener(this);        }        public void init(Activity activity, Button playButton) {            mActivity = activity;            mPlayButton = playButton;            mPlayButton.setOnClickListener(this);            setGamePaused(true);        }        @Override        public void onSystemUiVisibilityChange(int visibility) {            int diff = mLastSystemUiVis ^ visibility;            mLastSystemUiVis = visibility;            if (!mPaused && (diff & SYSTEM_UI_FLAG_HIDE_NAVIGATION) != 0                    && (visibility & SYSTEM_UI_FLAG_HIDE_NAVIGATION) == 0) {                mUpdateSystemUi = true;            }        }        @Override        protected void onWindowVisibilityChanged(int visibility) {            super.onWindowVisibilityChanged(visibility);            // 游戏暂停            setGamePaused(true);        }        // 窗口焦点发生变化时        @Override        public void onWindowFocusChanged(boolean hasWindowFocus) {            super.onWindowFocusChanged(hasWindowFocus);            if (!hasWindowFocus) {                setGamePaused(true);            }        }        @Override        public void onClick(View v) {            if (v == mPlayButton) {                // 开始与暂停按钮                setGamePaused(!mPaused);            }        }        void setGamePaused(boolean paused) {            mPaused = paused;            mPlayButton.setText(paused ? R.string.play : R.string.pause);// 设置按钮开关            setKeepScreenOn(!paused);            updateNavVisibility();            Handler h = getHandler();            if (h != null) {                getHandler().removeCallbacks(mFader);                if (!paused) {                    mFader.run();                    text("Draw!");// 在屏幕上绘制文字                }            }        }        // 更新系统UI的FLAG特性        void updateNavVisibility() {            int newVis = SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN                    | SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION                    | SYSTEM_UI_FLAG_LAYOUT_STABLE;            if (!mPaused) {                newVis |= SYSTEM_UI_FLAG_LOW_PROFILE                        | SYSTEM_UI_FLAG_FULLSCREEN                        | SYSTEM_UI_FLAG_HIDE_NAVIGATION                        | SYSTEM_UI_FLAG_IMMERSIVE_STICKY;            }            // 设备UI            setSystemUiVisibility(newVis);            mUpdateSystemUi = false;        }    }    Content mContent;    public GameActivity() {    }    @Override    public void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.game);        mContent = (Content) findViewById(R.id.content);        mContent.init(this, (Button) findViewById(R.id.play));    }    @Override    public void onAttachedToWindow() {        super.onAttachedToWindow();    }    @Override    protected void onPause() {        super.onPause();        // Pause game when its activity is paused.        mContent.setGamePaused(true);    }}

/**     * 自定义手绘View,处理所有的绘图及手势操作     *      * @description:     * @author ldm     * @date 2016-5-26 下午4:56:18     */    public static class PaintView extends View {        private static final int FADE_ALPHA = 0x06;        private static final int MAX_FADE_STEPS = 256 / (FADE_ALPHA / 2) + 4;        private static final int TRACKBALL_SCALE = 10;        private static final int SPLAT_VECTORS = 40;        private final Random mRandom = new Random();        private Bitmap mBitmap;        private Canvas mCanvas;        private final Paint mPaint = new Paint();        private final Paint mFadePaint = new Paint();        private float mCurX;        private float mCurY;        private int mOldButtonState;        private int mFadeSteps = MAX_FADE_STEPS;        /** 当前使用的颜色下标 */        int mColorIndex;        public PaintView(Context c) {            super(c);            init();        }        public PaintView(Context c, AttributeSet attrs) {            super(c, attrs);            init();        }        /**         * 初始化画笔         *          * @description:         * @author ldm         * @date 2016-5-26 下午4:58:26         */        private void init() {            setFocusable(true);            mPaint.setAntiAlias(true);            mFadePaint.setColor(BACKGROUND_COLOR);            mFadePaint.setAlpha(FADE_ALPHA);        }        /**         * 清屏操作         *          * @description:         * @author ldm         * @date 2016-5-26 下午5:01:54         */        public void clear() {            if (mCanvas != null) {                mPaint.setColor(BACKGROUND_COLOR);                mCanvas.drawPaint(mPaint);                invalidate();                mFadeSteps = MAX_FADE_STEPS;            }        }        /**         * 设置透明度变化         *          * @description:         * @author ldm         * @date 2016-5-26 下午5:02:12         */        public void fade() {            if (mCanvas != null && mFadeSteps < MAX_FADE_STEPS) {                mCanvas.drawPaint(mFadePaint);                invalidate();                mFadeSteps++;            }        }        /**         * 绘制文字         *          * @description:         * @author ldm         * @date 2016-5-26 下午4:39:07         */        public void text(String text) {            if (mBitmap != null) {                // 图片大小                final int width = mBitmap.getWidth();                final int height = mBitmap.getHeight();                mPaint.setColor(COLORS[mColorIndex]);                mPaint.setAlpha(255);                int size = height;                // 设置文字 大小                mPaint.setTextSize(size);                Rect bounds = new Rect();                // 获取文字的边界范围                mPaint.getTextBounds(text, 0, text.length(), bounds);                int twidth = bounds.width();                twidth += (twidth / 4);                if (twidth > width) {                    size = (size * width) / twidth;                    mPaint.setTextSize(size);                    mPaint.getTextBounds(text, 0, text.length(), bounds);                }                Paint.FontMetrics fm = mPaint.getFontMetrics();                // 绘制文字                mCanvas.drawText(text, (width - bounds.width()) / 2,                        ((height - size) / 2) - fm.ascent, mPaint);                mFadeSteps = 0;                invalidate();            }        }        @Override        protected void onSizeChanged(int w, int h, int oldw, int oldh) {            int curW = mBitmap != null ? mBitmap.getWidth() : 0;            int curH = mBitmap != null ? mBitmap.getHeight() : 0;            if (curW >= w && curH >= h) {                return;            }            if (curW < w)                curW = w;            if (curH < h)                curH = h;            Bitmap newBitmap = Bitmap.createBitmap(curW, curH,                    Bitmap.Config.ARGB_8888);            Canvas newCanvas = new Canvas();            newCanvas.setBitmap(newBitmap);            if (mBitmap != null) {                newCanvas.drawBitmap(mBitmap, 0, 0, null);            }            mBitmap = newBitmap;            mCanvas = newCanvas;            mFadeSteps = MAX_FADE_STEPS;        }        @Override        protected void onDraw(Canvas canvas) {            if (mBitmap != null) {                canvas.drawBitmap(mBitmap, 0, 0, null);            }        }        @Override        public boolean onTrackballEvent(MotionEvent event) {            final int action = event.getActionMasked();            if (action == MotionEvent.ACTION_DOWN) {                // Advance color when the trackball button is pressed.                advanceColor();            }            if (action == MotionEvent.ACTION_DOWN                    || action == MotionEvent.ACTION_MOVE) {                final int N = event.getHistorySize();                final float scaleX = event.getXPrecision() * TRACKBALL_SCALE;                final float scaleY = event.getYPrecision() * TRACKBALL_SCALE;                for (int i = 0; i < N; i++) {                    moveTrackball(event.getHistoricalX(i) * scaleX,                            event.getHistoricalY(i) * scaleY);                }                moveTrackball(event.getX() * scaleX, event.getY() * scaleY);            }            return true;        }        private void moveTrackball(float deltaX, float deltaY) {            final int curW = mBitmap != null ? mBitmap.getWidth() : 0;            final int curH = mBitmap != null ? mBitmap.getHeight() : 0;            mCurX = Math.max(Math.min(mCurX + deltaX, curW - 1), 0);            mCurY = Math.max(Math.min(mCurY + deltaY, curH - 1), 0);            paint(PaintMode.Draw, mCurX, mCurY);        }        @Override        public boolean onTouchEvent(MotionEvent event) {            return onTouchOrHoverEvent(event, true /* isTouch */);        }        @Override        public boolean onHoverEvent(MotionEvent event) {            return onTouchOrHoverEvent(event, false /* isTouch */);        }        private boolean onTouchOrHoverEvent(MotionEvent event, boolean isTouch) {            final int buttonState = event.getButtonState();            int pressedButtons = buttonState & ~mOldButtonState;            mOldButtonState = buttonState;            if ((pressedButtons & MotionEvent.BUTTON_SECONDARY) != 0) {                // Advance color when the right mouse button or first stylus                // button                // is pressed.                advanceColor();            }            PaintMode mode;            if ((buttonState & MotionEvent.BUTTON_TERTIARY) != 0) {                // Splat paint when the middle mouse button or second stylus                // button is pressed.                mode = PaintMode.Splat;            } else if (isTouch                    || (buttonState & MotionEvent.BUTTON_PRIMARY) != 0) {                // Draw paint when touching or if the primary button is pressed.                mode = PaintMode.Draw;            } else {                // Otherwise, do not paint anything.                return false;            }            final int action = event.getActionMasked();            if (action == MotionEvent.ACTION_DOWN                    || action == MotionEvent.ACTION_MOVE                    || action == MotionEvent.ACTION_HOVER_MOVE) {                final int N = event.getHistorySize();                final int P = event.getPointerCount();                for (int i = 0; i < N; i++) {                    for (int j = 0; j < P; j++) {                        paint(getPaintModeForTool(event.getToolType(j), mode),                                event.getHistoricalX(j, i),                                event.getHistoricalY(j, i),                                event.getHistoricalPressure(j, i),                                event.getHistoricalTouchMajor(j, i),                                event.getHistoricalTouchMinor(j, i),                                event.getHistoricalOrientation(j, i),                                event.getHistoricalAxisValue(                                        MotionEvent.AXIS_DISTANCE, j, i),                                event.getHistoricalAxisValue(                                        MotionEvent.AXIS_TILT, j, i));                    }                }                for (int j = 0; j < P; j++) {                    paint(getPaintModeForTool(event.getToolType(j), mode),                            event.getX(j), event.getY(j), event.getPressure(j),                            event.getTouchMajor(j), event.getTouchMinor(j),                            event.getOrientation(j),                            event.getAxisValue(MotionEvent.AXIS_DISTANCE, j),                            event.getAxisValue(MotionEvent.AXIS_TILT, j));                }                mCurX = event.getX();                mCurY = event.getY();            }            return true;        }        private PaintMode getPaintModeForTool(int toolType,                PaintMode defaultMode) {            if (toolType == MotionEvent.TOOL_TYPE_ERASER) {                return PaintMode.Erase;            }            return defaultMode;        }        private void advanceColor() {            mColorIndex = (mColorIndex + 1) % COLORS.length;        }        private void paint(PaintMode mode, float x, float y) {            paint(mode, x, y, 1.0f, 0, 0, 0, 0, 0);        }        private void paint(PaintMode mode, float x, float y, float pressure,                float major, float minor, float orientation, float distance,                float tilt) {            if (mBitmap != null) {                if (major <= 0 || minor <= 0) {                    // If size is not available, use a default value.                    major = minor = 16;                }                switch (mode) {                case Draw:                    mPaint.setColor(COLORS[mColorIndex]);                    mPaint.setAlpha(Math.min((int) (pressure * 128), 255));                    drawOval(mCanvas, x, y, major, minor, orientation, mPaint);                    break;                case Erase:                    mPaint.setColor(BACKGROUND_COLOR);                    mPaint.setAlpha(Math.min((int) (pressure * 128), 255));                    drawOval(mCanvas, x, y, major, minor, orientation, mPaint);                    break;                case Splat:                    mPaint.setColor(COLORS[mColorIndex]);                    mPaint.setAlpha(64);                    drawSplat(mCanvas, x, y, orientation, distance, tilt,                            mPaint);                    break;                }            }            mFadeSteps = 0;            invalidate();        }        /**         * Draw an oval.         *          * When the orienation is 0 radians, orients the major axis vertically,         * angles less than or greater than 0 radians rotate the major axis left         * or right.         */        private final RectF mReusableOvalRect = new RectF();        private void drawOval(Canvas canvas, float x, float y, float major,                float minor, float orientation, Paint paint) {            canvas.save(Canvas.MATRIX_SAVE_FLAG);            canvas.rotate((float) (orientation * 180 / Math.PI), x, y);            mReusableOvalRect.left = x - minor / 2;            mReusableOvalRect.right = x + minor / 2;            mReusableOvalRect.top = y - major / 2;            mReusableOvalRect.bottom = y + major / 2;            canvas.drawOval(mReusableOvalRect, paint);            canvas.restore();        }        /**         * Splatter paint in an area.         *          * Chooses random vectors describing the flow of paint from a round         * nozzle across a range of a few degrees. Then adds this vector to the         * direction indicated by the orientation and tilt of the tool and         * throws paint at the canvas along that vector.         *          * Repeats the process until a masterpiece is born.         */        private void drawSplat(Canvas canvas, float x, float y,                float orientation, float distance, float tilt, Paint paint) {            float z = distance * 2 + 10;            // Calculate the center of the spray.            float nx = (float) (Math.sin(orientation) * Math.sin(tilt));            float ny = (float) (-Math.cos(orientation) * Math.sin(tilt));            float nz = (float) Math.cos(tilt);            if (nz < 0.05) {                return;            }            float cd = z / nz;            float cx = nx * cd;            float cy = ny * cd;            for (int i = 0; i < SPLAT_VECTORS; i++) {                // Make a random 2D vector that describes the direction of a                // speck of paint                // ejected by the nozzle in the nozzle's plane, assuming the                // tool is                // perpendicular to the surface.                double direction = mRandom.nextDouble() * Math.PI * 2;                double dispersion = mRandom.nextGaussian() * 0.2;                double vx = Math.cos(direction) * dispersion;                double vy = Math.sin(direction) * dispersion;                double vz = 1;                // Apply the nozzle tilt angle.                double temp = vy;                vy = temp * Math.cos(tilt) - vz * Math.sin(tilt);                vz = temp * Math.sin(tilt) + vz * Math.cos(tilt);                // Apply the nozzle orientation angle.                temp = vx;                vx = temp * Math.cos(orientation) - vy * Math.sin(orientation);                vy = temp * Math.sin(orientation) + vy * Math.cos(orientation);                // Determine where the paint will hit the surface.                if (vz < 0.05) {                    continue;                }                float pd = (float) (z / vz);                float px = (float) (vx * pd);                float py = (float) (vy * pd);                // Throw some paint at this location, relative to the center of                // the spray.                mCanvas.drawCircle(x + px - cx, y + py - cy, 1.0f, paint);            }        }    }

https://github.com/ldm520/ANDROID_API_DEMOS等Android官方API开源代码。

0 0
原创粉丝点击