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
- Android API DEMO:简单手绘游戏
- Android Api Demo简单分类整理
- HandDraw(手绘)~demo
- Oc HandDraw(手绘)-demo
- 一个简单的入门的android游戏demo
- Android 2.2 API demo
- android api demo 解析
- Android API Demo structure
- Android编程之手绘
- Android自由轨迹手绘
- Android手绘效果实现
- Android天气预报 简单Demo
- Android Media 简单 Demo
- android MediaRecorder简单Demo
- Android API Demo程序框架
- Android API Demo实例解析
- android api 测试demo地址
- 基于mAppWidget实现手绘地图--索引&DEMO
- Mybaits之逆向工程
- 四、MyBatis主配置文件
- RA, 寄存器分配
- WineBottler:让苹果Mac OS照样用IE浏览器
- p96验证
- Android API DEMO:简单手绘游戏
- ArrayList在for循环中使用remove方法移除元素
- 免费馅饼
- leetcode 349:两个数组的交集I
- Linux进程学习---基本概念
- Java开发和运行环境的搭建
- allowBackup
- 在Android运行cocos Demo游戏
- Win7 outlook2010无法启动问题