• 在介绍本文动画效果实现之前,先来介绍属性...在Android3.0之前,系统提供了两种动画效果实现方式,帧动画frame-by-frame animation和补间动画tweened animation。帧动画就是类似电影播放一样,将整部影片拆分成一片片

    在介绍本文动画效果实现之前,先来介绍属性动画相关的几个知识点。

    1. ValueAnimator与ObjectAnimator。
    2. Interpolator插值器与TypeEvaluator估值器。

    在Android3.0之前,系统提供了两种动画效果实现方式,帧动画frame-by-frame animation和补间动画tweened animation。帧动画就是类似电影播放一样,将整部影片拆分成一片片的然后连贯起来播放。补间动画则可以实现对view的缩放、平移、旋转等操作。在3.0之后,出现了一种新的动画模式称为属性动画property animation。

    属性动画产生的原因

    属性动画的出现不是用来替代补间动画的,而是用来解决补间动画所不能够完成的事件的。如果我们的需求超出了操控view的旋转、缩放、平移等操作范围,那么我们就需选择属性动画去实现了。那么属性动画可以做到哪些补间动画做不到的事情呢?下面列举几点,当然属性动画的功能很强大,不仅限于我列举的几点。

    1. 属性动画可以做到对一个非view类进行动画操作。
    2. 属性动画可以做到真正的改变view对象的属性值。而补间动画只是改变了view的动画效果。

    ValueAnimator与ObjectAnimator

    ObjectAnimator是属性动画中最总要的执行类,ObjectAnimator可以操作某个对象的属性值,但是这个属性值必须要有get和set方法,同时也可以设置view的执行线路,通过插值器来控制。
    举个简单的例子:

    ObjectAnimator
    .ofFloat(view, "rotationY", 0.0F, 360.0F)
    .setDuration(500)
    .start();
    

    其可操作的属性有x/y;scaleX/scaleY;rotationX/ rotationY;transitionX/ transitionY等。
    上面的例子是修改view的单个属性值,同样也可以同时修改多个属性,下面介绍两种

    1. PropertyValuesHolder属性值持有者

      PropertyValuesHolder pvhLeft = PropertyValuesHolder.ofInt("left", 0, 1);
      
      PropertyValuesHolder pvhTop = PropertyValuesHolder.ofInt("top", 0, 1);
      
      ObjectAnimator.ofPropertyValuesHolder( this, pvhLeft, pvhTop).
      
    2. 提供一个不存在的属性值

      ObjectAnimator anim = ObjectAnimator.ofFloat(view, "long", 1.0F, 0.0F).setDuration(500);
      anim.start();
      anim.UpdateListener(new AnimatorUpdateListener() {
          @Override
          public void onAnimationUpdate(ValueAnimator animation) {
              float cVal = (Float) animation.getAnimatedValue();
              view.setAlpha(cVal);
              view.setScaleX(cVal);
              view.setScaleY(cVal);
          }
      });
      

    上面提到的都是修改对象已有的setter和getter方法的属性值。那么如果对象没有为某个属性提供提供setter和getter方法呢,我们也可以做到修改这些属性值,下面提供两种实现方式:

    1. 通过valueAnimation来实现,这个下面会讲解。
    2. 通过自己写一个包装类来实现。然后为该属性提供setter和getter方法。

      class ViewWrapper{
          private View mView;
          public int getWidth(){
              return mView.getLayoutParams().width;
          }
      }
      

    ValueAnimator包含Property Animation动画的所有核心功能,如动画时间,开始、结束属性值,相应时间属性值计算方法等。
    属性动画的应用有两个步骤:
    1、计算属性的值。2、根据属性值执行相应的动作。
    ValueAnimator只是完成了第一步骤,而要完成第二步还要借助于ValueAnimator.onUpdateListener接口,在此方法中可以通过ValueAnimator对象的getAnimatedValue()函数可以得到当前的属性值。

    ValueAnimator animation = ValueAnimator.ofFloat(0f, 1f);
    animation.setDuration(1000);
    animation.addUpdateListener(new AnimatorUpdateListener  () {
        @Override
         public void onAnimationUpdate(ValueAnimator animation) {
             Log.i("update", ((Float)animation.getAnimatedValue()).toString());
             // 此处可以根据getAnimatedValue获取到的属性值改变view相关的属性从而执行某些动作
         }
    });
    animation.setInterpolator(new CycleInterpolator(3));
    animation.start();
    

    Time Interpolator插值器与TypeEvaluator估值器

    Time interplator:定义了属性值变化的方式,如线性均匀改变,开始慢然后逐渐快等。在Property Animation中是TimeInterplator,在View Animation中是Interplator,这两个是一样的,在3.0之前只有Interplator,3.0之后实现代码转移至了TimeInterplator。Interplator继承自TimeInterplator,内部没有任何其他代码。

    1. AccelerateInterpolator 加速,开始时慢中间加速
    2. DecelerateInterpolator 减速,开始时快然后减速
    3. AccelerateDecelerateInterolator 先加速后减速,开始结束时慢,中间加速
    4. AnticipateInterpolator 反向 ,先向相反方向改变一段再加速播放
    5. AnticipateOvershootInterpolator 反向加回弹,先向相反方向改变,再加速播放,会超出目的值然后缓慢移动至目的值
    6. BounceInterpolator 跳跃,快到目的值时值会跳跃,如目的值100,后面的值可能依次为85,77,70,80,90,100
    7. CycleIinterpolator 循环,动画循环一定次数,值的改变为一正弦函数:Math.sin(2 * mCycles * Math.PI * input)
    8. LinearInterpolator 线性,线性均匀改变
    9. OvershottInterpolator 回弹,最后超出目的值然后缓慢改变到目的值
    10. TimeInterpolator 一个接口,允许你自定义interpolator,以上几个都是实现了这个接口

    TypeEvaluator:根据属性的开始、结束值与TimeInterpolation计算出的因子计算出当前时间的属性值,android提供了以下几个evalutor:

    1. IntEvaluator:属性的值类型为int。
    2. FloatEvaluator:属性的值类型为float。
    3. ArgbEvaluator:属性的值类型为十六进制颜色值。
    4. TypeEvaluator:一个接口,可以通过实现该接口自定义Evaluator。

    当然我们也可以自己定义估值器,如下:

    public class FloatEvaluator implements TypeEvaluator {
         public Object evaluate(float fraction, Object startValue, Object endValue) {
                float startFloat = ((Number) startValue).floatValue();
                return startFloat + fraction * (((Number) endValue).floatValue() - startFloat);
         }
    }
    

    实例
    接下来我们要实现的就是如下的 效果图:
    这里写图片描述
    在本例的实现中我们的重点也是在ValueAnimator和ObjectAnimator中读者可以结合上述知识内容来消化本例的动画技术。附上代码:

    package com.example.custom.animation;
    
    import java.util.ArrayList;
    
    import com.example.custom.R;
    import android.animation.Animator;
    import android.animation.AnimatorListenerAdapter;
    import android.animation.AnimatorSet;
    import android.animation.ArgbEvaluator;
    import android.animation.ObjectAnimator;
    import android.animation.ValueAnimator;
    import android.app.Activity;
    import android.content.Context;
    import android.graphics.Canvas;
    import android.graphics.Paint;
    import android.graphics.RadialGradient;
    import android.graphics.Shader;
    import android.graphics.drawable.ShapeDrawable;
    import android.graphics.drawable.shapes.OvalShape;
    import android.os.Bundle;
    import android.view.MotionEvent;
    import android.view.View;
    import android.view.animation.AccelerateInterpolator;
    import android.view.animation.DecelerateInterpolator;
    import android.widget.LinearLayout;
    
    public class BouncingBalls extends Activity {
    
        @Override
        public void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.bouncing_balls);
            LinearLayout container = (LinearLayout) findViewById(R.id.container);
            container.addView(new MyAnimationView(this));
        }
    
        public class MyAnimationView extends View {
    
            private static final int RED = 0xffFF8080;
            private static final int BLUE = 0xff8080FF;
    
            public final ArrayList<ShapeHolder> balls = new ArrayList<ShapeHolder>();
            AnimatorSet animation = null;
    
    
            public MyAnimationView(Context context) {
                super(context);
                ValueAnimator colorAnim = ObjectAnimator.ofInt(this, "backgroundColor", RED, BLUE);
                colorAnim.setDuration(3000);
                colorAnim.setEvaluator(new ArgbEvaluator());
                colorAnim.setRepeatCount(ValueAnimator.INFINITE);
                colorAnim.setRepeatMode(ValueAnimator.REVERSE);
                colorAnim.start();
            }
    
            @Override
            public boolean onTouchEvent(MotionEvent event) {
    
                if (event.getAction() != MotionEvent.ACTION_DOWN &&
                        event.getAction() != MotionEvent.ACTION_MOVE) {
                    return false;
                }
    
                // 初始化一个跳跳球
                ShapeHolder newBall = initBouncingBall(event.getX(), event.getY());
    
                float startY = newBall.getY();
                float endY = getHeight() - 50;
                float h = (float)getHeight();
                float eventY = event.getY();
                int duration = (int)(500 * ((h - eventY)/h));
    
                // 操作newBall的Y属性值
                ValueAnimator bounceAnim = ObjectAnimator.ofFloat(newBall, "y", startY, endY);
                bounceAnim.setDuration(duration);
                bounceAnim.setInterpolator(new AccelerateInterpolator());
    
                ValueAnimator squashAnim1 = ObjectAnimator.ofFloat(newBall, "x", newBall.getX(),newBall.getX() - 25f);
                squashAnim1.setDuration(duration/4);
                squashAnim1.setRepeatCount(1);
                squashAnim1.setRepeatMode(ValueAnimator.REVERSE);
                squashAnim1.setInterpolator(new DecelerateInterpolator());
    
                ValueAnimator squashAnim2 = ObjectAnimator.ofFloat(newBall, "width", newBall.getWidth(),newBall.getWidth() + 50);
                squashAnim2.setDuration(duration/4);
                squashAnim2.setRepeatCount(1);
                squashAnim2.setRepeatMode(ValueAnimator.REVERSE);
                squashAnim2.setInterpolator(new DecelerateInterpolator());
    
                ValueAnimator stretchAnim1 = ObjectAnimator.ofFloat(newBall, "y", endY, endY + 25f);
                stretchAnim1.setDuration(duration/4);
                stretchAnim1.setRepeatCount(1);
                stretchAnim1.setInterpolator(new DecelerateInterpolator());
                stretchAnim1.setRepeatMode(ValueAnimator.REVERSE);
    
                ValueAnimator stretchAnim2 = ObjectAnimator.ofFloat(newBall, "height",newBall.getHeight(), newBall.getHeight() - 25);
                stretchAnim2.setDuration(duration/4);
                stretchAnim2.setRepeatCount(1);
                stretchAnim2.setInterpolator(new DecelerateInterpolator());
                stretchAnim2.setRepeatMode(ValueAnimator.REVERSE);
    
                ValueAnimator bounceBackAnim = ObjectAnimator.ofFloat(newBall, "y", endY, startY);
                bounceBackAnim.setDuration(duration);
                bounceBackAnim.setInterpolator(new DecelerateInterpolator());
    
                AnimatorSet bouncer = new AnimatorSet();
                bouncer.play(bounceAnim).before(squashAnim1);
                bouncer.play(squashAnim1).with(squashAnim2);
                bouncer.play(squashAnim1).with(stretchAnim1);
                bouncer.play(squashAnim1).with(stretchAnim2);
                bouncer.play(bounceBackAnim).after(stretchAnim2);
    
                ValueAnimator fadeAnim = ObjectAnimator.ofFloat(newBall, "alpha", 1f, 0f);
                fadeAnim.setDuration(250);
                fadeAnim.addListener(new AnimatorListenerAdapter() {
                    @Override
                    public void onAnimationEnd(Animator animation) {
                        balls.remove(((ObjectAnimator)animation).getTarget());
                    }
                });
    
                AnimatorSet animatorSet = new AnimatorSet();
                animatorSet.play(bouncer).before(fadeAnim);
    
                animatorSet.start();
    
                return true;
            }
    
            private ShapeHolder initBouncingBall(float x, float y) {
    
                int red = (int)(Math.random() * 255);
                int green = (int)(Math.random() * 255);
                int blue = (int)(Math.random() * 255);
                int color = 0xff000000 | red << 16 | green << 8 | blue;
                int darkColor = 0xff000000 | red/4 << 16 | green/4 << 8 | blue/4;
    
                // 实例化一个圆形
                OvalShape circle = new OvalShape();
                circle.resize(50f, 50f);
    
                // 设置画笔的形状
                ShapeDrawable drawable = new ShapeDrawable(circle);
                Paint paint = drawable.getPaint(); 
    
                // 第一个,第二个参数表示渐变圆中心坐标,半径,圆心颜色,圆边缘颜色,渲染器平铺模式
                RadialGradient gradient = new RadialGradient(37.5f, 12.5f, 50f, color, darkColor, Shader.TileMode.CLAMP);
                // 给画笔设置著色器
                paint.setShader(gradient);
    
                ShapeHolder shapeHolder = new ShapeHolder(drawable);
                shapeHolder.setX(x - 25f);
                shapeHolder.setY(y - 25f);
                shapeHolder.setPaint(paint);
                balls.add(shapeHolder);
    
                return shapeHolder;
            }
    
            @Override
            protected void onDraw(Canvas canvas) {
                for (int i = 0; i < balls.size(); ++i) {
                    ShapeHolder shapeHolder = balls.get(i);
                    canvas.save();
                    canvas.translate(shapeHolder.getX(), shapeHolder.getY());
                    shapeHolder.getShape().draw(canvas);
                    canvas.restore();
                }
            }
        }
    }
    package com.example.custom.animation;
    
    import android.graphics.Paint;
    import android.graphics.RadialGradient;
    import android.graphics.drawable.ShapeDrawable;
    import android.graphics.drawable.shapes.Shape;
    import android.view.View;
    
    
    public class ShapeHolder {
        private float x = 0, y = 0;
        private int color;
        private float alpha = 1f;
        private Paint paint;
        private ShapeDrawable shape;
        private RadialGradient gradient;
        public void setPaint(Paint value) {
            paint = value;
        }
        public Paint getPaint() {
            return paint;
        }
    
        public void setX(float value) {
            x = value;
        }
        public float getX() {
            return x;
        }
        public void setY(float value) {
            y = value;
        }
        public float getY() {
            return y;
        }
        public void setShape(ShapeDrawable value) {
            shape = value;
        }
        public ShapeDrawable getShape() {
            return shape;
        }
        public int getColor() {
            return color;
        }
        public void setColor(int value) {
            shape.getPaint().setColor(value);
            color = value;
        }
        public void setGradient(RadialGradient value) {
            gradient = value;
        }
        public RadialGradient getGradient() {
            return gradient;
        }
    
        public void setAlpha(float alpha) {
            this.alpha = alpha;
            shape.setAlpha((int)((alpha * 255f) + .5f));
        }
    
        public float getWidth() {
            return shape.getShape().getWidth();
        }
    
        public void setWidth(float width) {
            Shape s = shape.getShape();
            s.resize(width, s.getHeight());
        }
    
        public float getHeight() {
            return shape.getShape().getHeight();
        }
        public void setHeight(float height) {
            Shape s = shape.getShape();
            s.resize(s.getWidth(), height);
        }
    
        public ShapeHolder(ShapeDrawable s) {
            shape = s;
        }
    }
    展开全文
  • 跳跳游戏

    2018-07-13 21:27:13
    好疲惫呀,感觉做不动了,需要一些鼓励题目描述Given an array of non-negative integers, you are initially positioned at the first index of the array.Each element in the array represents your maximum jump...

    好疲惫呀,感觉做不动了,需要一些鼓励奋斗

    题目描述

    Given an array of non-negative integers, you are initially positioned at the first index of the array.
    Each element in the array represents your maximum jump length at that position.
    Determine if you are able to reach the last index.
    For example:
    A =[2,3,1,1,4], returntrue.

    A =[3,2,1,0,4], returnfalse.

    解题思路

    记录节点可达最远位置,最后比较最远位置与最后一节点位置的大小

    代码示例

    class Solution {
    public:

        bool canJump(int A[], int n) {

    //标记能跳到的最远处

            int maxjump = 0;    

    //i <= maxjump表示此时能跳到i处,0<=i<n表示扫描所有能到达的点,在改点处能跳到的最远处。

            for (int i = 0; i < n && i <= maxjump; i++) {

                maxjump = max(maxjump, i + A[i]);

            }

    //如果最后跳的最远的结果大于等于n-1,那么满足能跳到最后。

            return maxjump >= n - 1 ? true : false;
        }
    };
    展开全文
  • 1.小球类   package com.android.ballmove;...import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.Canvas; import android.graphics.Paint; public class Ball {

    1.小球类

     

    package com.android.ballmove;

    import android.graphics.Bitmap;
    import android.graphics.BitmapFactory;
    import android.graphics.Canvas;
    import android.graphics.Paint;

    public class Ball {
     /** 
     18.          * 球的高 
     19.          */ 
              public static final int HEIGHT = 93;  
              /** 
     22.          * 球的宽 
     23.          */ 
              public static final int WIDTH = 93;  
              private static final int STEPLENGTH = 10;//每次运动的间距  
              private static final float REDUCEPERCENTAGE =  0.35F;//递减系数  
              private int stepReduce ;//每次反向运动的缩短的距离  
               
              private float runX ;//球的位置  
              private float runY ;//球的位置  
             private BallSurfaceView bsv ;  
              private boolean upDirection = false;//if true,up direction,or is down direction  
              private float maxHeight ;//当前运动最高的高度  
              private Paint paint ;  
               
              Bitmap ballBitmap ;//球的图片  
              SportActivity sa ;  
              public Ball(float initX , float initY , BallSurfaceView bsv){  
                        this.runX  = initX;  
                        this.runY = initY ;  
                        maxHeight = initY;  
                        this.bsv = bsv;  
                        ballBitmap = BitmapFactory.decodeResource(bsv.getResources(), R.drawable.ball);//加载图片  
                        paint = new Paint();  
                        sa = bsv.sportActivity;  
              }  
               
              public void onDraw(Canvas canvas) {  
                        int c = paint.getColor();//保存颜色,之后还原为之前颜色  
                        boundaryTest();  
                        if(canvas != null) canvas.drawBitmap(ballBitmap,runX,runY,paint);  
                        paint.setColor(c);  
                        move();  
             }  
             /** 
     56.          * 运动 
     57.          */ 
              private void move() {  
                        if(maxHeight >= (sa.screenHeight - HEIGHT)) {  
                                 return;  
                       }  
                       if(upDirection){//向上  
                                 runY = runY + STEPLENGTH ;  
                        }else{  
                                 runY = runY - STEPLENGTH ;  
                        }  
              }  
        
              /** 
     70.          * 边界检测,使球不会飞出边界 
     71.          */ 
              private void boundaryTest(){  
        
                        if(runY > sa.screenHeight - HEIGHT){//向下运动到头  
                               upDirection = !upDirection;//方向置反  
                                 runY = sa.screenHeight - HEIGHT;  
                                 stepReduce = (int) (maxHeight * REDUCEPERCENTAGE);  
                                 maxHeight = maxHeight + stepReduce ;//最大高度递减  
                                  
                       }  
                        if(runY < maxHeight ){//向上运动到头  
                                upDirection = !upDirection;//方向置反  
                                if(maxHeight >= (sa.screenHeight - HEIGHT)) return;  
                                 runY = maxHeight ;  
                                  
                       }  
             }  
     } 

     

    2.小球弹跳的过程

     

    package com.android.ballmove;

    import android.content.Context;
    import android.graphics.Canvas;
    import android.graphics.Color;
    import android.graphics.Paint;
    import android.view.SurfaceHolder;
    import android.view.SurfaceView;

    public class BallSurfaceView extends SurfaceView implements SurfaceHolder.Callback{  
             SportActivity sportActivity ;//调用该SurfaceView的上下文引用  
             private Ball ball ;//小球  
             SurfaceHolder holder ;  
              
            public BallSurfaceView(Context context) {  
                       super(context);  
                       this.sportActivity = (SportActivity)context ;  
                       ball = new Ball(100, 100, this);  
                       holder = this.getHolder();  
                       holder.addCallback(this);  
             }  
       
             @Override 
             protected void onDraw(Canvas canvas) {  
                       super.onDraw(canvas);  
                        
                       if(canvas == null) canvas = holder.lockCanvas();//锁定画布  
                       Paint p = new Paint();  
                       int c = p.getColor();  
                       p.setColor(Color.GRAY);//设置背景白色  
                       if(canvas != null)  
                       canvas.drawRect(0, 0, sportActivity.screenWidth, sportActivity.screenHeight, p);  
                       p.setColor(c);  
                       ball.onDraw(canvas);  
                       holder.unlockCanvasAndPost(canvas);//释放锁  
             }  
       
             @Override 
             public void surfaceChanged(SurfaceHolder holder, int format, int width,                               int height) {  
                        
             }      
             @Override 
             public void surfaceCreated(SurfaceHolder holder) {  
                       new RefreshThread().start();  
             }  
       
             @Override 
             public void surfaceDestroyed(SurfaceHolder holder) {  
                        
            }  
              
             private class RefreshThread extends Thread{  
       
                       @Override 
                       public void run() {  
       
                               while(true){  
                                         Canvas canvas = null;  
                                         try{  
                                                  onDraw(canvas);  
                                         }catch(Exception e){  
                                                   e.printStackTrace();  
                                         }                                        
                                        try {  
                                                  Thread.sleep(40);  
                                         } catch (InterruptedException e) {  
                                                   e.printStackTrace();  
                                         }  
                                }  
                       }  
                        
            }  
       


     

    3.Activity

     

    package com.android.ballmove;

    import android.app.Activity;
    import android.os.Bundle;
    import android.util.DisplayMetrics;
    import android.view.Window;
    import android.view.WindowManager;

    public class SportActivity extends Activity {
      public int screenWidth ;  
               public int screenHeight ;  
               BallSurfaceView bsv ;  
          /** Called when the activity is first created. */ 
          @Override 
          public void onCreate(Bundle savedInstanceState) {  
              super.onCreate(savedInstanceState);  
              bsv = new BallSurfaceView(this);  
             //获得屏幕尺寸  
             DisplayMetrics dm = new DisplayMetrics();  
          dm = this.getApplicationContext().getResources().getDisplayMetrics();  
                   screenWidth = dm.widthPixels;  
                    screenHeight = dm.heightPixels;  
                 //下两句为设置全屏  
              requestWindowFeature(Window.FEATURE_NO_TITLE);  
                         getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN ,   
                                      WindowManager.LayoutParams.FLAG_FULLSCREEN);  
              
            setContentView(bsv);  
          }  

    }

     

    展开全文
  • Android如何从外部跳进App 这个问题解决了两天时间,因为网上没有完整的解决方案,解决后分享一下给大家! 这个话题可以分两方面来讲,一方面是从微信进入App,另一方面是从网页进入App。 咱们拿...


    博客出自:http://blog.csdn.net/liuxian13183,转载注明出处! All Rights Reserved !


    这个问题解决了两天时间,因为网上没有完整的解决方案,解决后分享一下给大家!

    原理:路由。

    通过配置scheme、host和path等信息即Filter,告诉项目自己可以处理哪些信息,并且将参数带过去处理的一种思路。

    解决这个问题有两个作用:

    1、不用打开App直接进入某页面

    2、实现App分享到外部,同时由外部进入App的闭环。

    这个话题可以分两方面来讲,一方面是从微信进入App,另一方面是从网页进入App。

    咱们拿http://my.oschina.net/liucundong/blog/354029当例子来讲一下

    主要通过scheme、host、path、pathPrefix等data信息来区分

    两个方案都需要给跳转到的Activity加入intent-filter信息,例如

    <intent-filter>

    <action android:name="android.intent.action.VIEW" />

    <category android:name="android.intent.category.DEFAULT" />

    <category android:name="android.intent.category.BROWSABLE" />

    <data android:scheme="cundong" android:host="splash"/>

    </intent-filter>

    首先我们来讲微信端进入App,场景:从App分享内容到微信,再从微信直接打开App。

    第一步,注册微信公众平台,相关企业信息,下载链接,Logo等 都填写完毕

    第二步,分享时使用WXAppExtendObject,把链接url赋值给extInfo

    第三步,在IWXAPIEventHandler接口的onReq方法的req.getType()=ConstantsAPI.COMMAND_SHOWMESSAGE_FROM_WX时,发起你的跳转

    第四步,跳转时需要数据,数据从哪里来,从WXEntryActivity类中onCreate方法的getIntent对象里来

    从微信进入App就这样结束了。

    -------------------我是分割线------------------------

    接着来讲网页端,由于webView的限制,如微信、微博等都采用这个控件,所以只能分享到网页,再进入App。

    原理如下:

    <div>
                <a id="J-call-app" href="javascript:;" class="label">立即打开&gt;&gt;</a>
                <input id="J-download-app" type="hidden" name="storeurl" value="http://apk.hiapk.com/appinfo/com.tmall.wireless">
            </div>
     
            <script>
                (function(){
                    var ua = navigator.userAgent.toLowerCase();
               
                    var t;
                    var url=document.location;
                    var config = {
                        /*scheme:必须*/
                        scheme_IOS: 'cundong://',
                        scheme_Adr: 'cundong://splash',
                        download_url: document.getElementById('J-download-app').value,
                        timeout: 600
                    };
     
                    function openclient() {
                        var startTime = Date.now();
     
                        var ifr = document.createElement('iframe');
     
                        //alert(config.scheme_Adr);
                        ifr.src = ua.indexOf('os') > 0 ? config.scheme_IOS : config.scheme_Adr;
                        ifr.style.display = 'none';
                        document.body.appendChild(ifr);
     
                        var t = setTimeout(function() {
                            var endTime = Date.now();
     
                            if (!startTime || endTime - startTime < config.timeout -200) { 
                                window.location = config.download_url;
                            } else {
                                       window.location.href=ifr.src.replace("http://","cundong://");;
                            }
                        }, config.timeout);


     
                        window.onblur = function() {
                            clearTimeout(t);
                        }
                    }
                    window.addEventListener("DOMContentLoaded", function(){
                        document.getElementById("J-call-app").addEventListener('click',openclient,false);
     
                    }, false);
                })()
            </script>

    点击打开四个字后,执行一个js,在限制时间内,如果可以打开App则打开,否则进入下载页

    解决这个问题的基本思路就是这样,欢迎大家交流探讨!



    展开全文
  • 跳跳涂鸦跳跳涂鸦——向上跳动游戏(学习笔记) 一、需求分析 (一)、游戏的主要玩法 1、是一款2D向上跳动游戏 主要玩法:player向上跳动,然后有五种类型的砖块,每个砖块有不同的属性、砖块上面有怪物,也有相应...

    跳跳涂鸦跳跳涂鸦——向上跳动游戏(学习笔记)

    一、需求分析

    (一)、游戏的主要玩法

    1、是一款2D向上跳动游戏

    • 主要玩法:player向上跳动,然后有五种类型的砖块,每个砖块有不同的属性、砖块上面有怪物,也有相应的道具,吃了道具有不同的效果。
    • 附加玩法:通过吃金币来购买皮肤
    • 拓展玩法:死亡后花钱复活,可以花钱买道具、总之可以在核心晚上的基础上加上其他的类型。还可以添加双人模式等…

    2、 五种砖块的属性

    • 第一种:普通的,就是站上去向上跳
    • 第二种、跳不上去
    • 第三种:跳上去之后让主角向上跳一次,然后就下落
    • 第四种:跳上去之后高度是第一种的1.5倍
    • 第五种:在第一种的基础之上添加左右移动,和上下移动。

    3、游戏物体

    • 砖块、敌人、主角、各类UI面板

    二、知识点

    (一)、原理知识

    1、添加专门的背景相机

    • 因为游戏人物要向上移动,所以背景会离开相机的照射范围
    • 解决方案有两个,一、添加两个相机。二、背景跟随相机移动
    • 使用添加两个相机来解决,先让背景能正常的在主相机上面显示,然后新建一个相机,位置信息跟主摄像机位置保持一直,然后设置背景的渲染层级(layer)为water,然后背景相机的culling Mask 只勾选water照射层级跟背景一样,然后再设置主相机的模式为Depth only。Culling Mask 不勾选water.

    2、设置底部图片跟随相机的变动而变动长度

    • 原理:图片的宽高能转化成相机照射的宽高,然后窗口的宽高跟相机照射宽高一样,在图片不能适应屏幕比例或者相机照射窗口的时候,可以通过比例调节图片的宽高以达到跟相机照射宽高一样。

    • 这里实际上是固定了屏幕比例,然后让图片适应相机照射范围。让相机照射范围的比例,跟图片转化到屏幕比例的大小一致。通过改变图片的宽高来达到一致。

      
      

    (二)、插件知识

    1、使用了iTween来控制MainUI中的player跳动

    • 换装界面的动画也是使用iTween来设置的

    • GameOver面板的弹出也是通过iTween来设置的

      iTween.MoveBy(gameObject, iTween.Hash(
                  "y", offsetY,
                  "easeType", iTween.EaseType.easeInOutQuad,
                  "loopType", iTween.LoopType.pingPong,
                  "time", time
                  ));
      

    (三)、操作知识

    1、UI面板的搭建

    • 根据需求来制定游戏面板
    • UI面板主要有Main、InGame、Pause、GameOver、Skin五个
    • 五个之间的切换有两种方式
      • 第一种:通过删除在穿件的方式来确定,和通过setactive来设置
      • 第二种:通过CanvasGroup里面的alpha来设置

    2、通过简单的UI框架来控制UI之间的切换

    • 设置GUIManager来控制,通过一个List和Stack来装UI面板。
    • 通过出栈和如栈来控制显示。

    (四)、代码相关

    1、设置Player的弹跳跟左右移动

    • 跳弹的原理主要是用刚体里面的方法来实现,需要注意的是每次跳完之后要从小设置加速度为0

    • 通过Tag来判断是不是Player进入,是Player进入才进行弹跳

      private void OnTriggerEnter2D(Collider2D collision)
          {
              if(collision.tag == "Platform")
                  Jump(1);     
          }
          public void Jump(float x)
          {
              GetComponent<Rigidbody2D>().velocity = Vector2.zero;
              GetComponent<Rigidbody2D>().AddForce(new Vector2(0, 12 * x), ForceMode2D.Impulse);
             
      
          }
      
    • 左右移动:主要是通过按键的按下来控制位移来解决,通过Player身上的位置信息来进行移动

    • 移动的时候要注意Player转向的问题,通过一个三维值来转向

      Vector3 acc = Vector3.zero;
                  Vector3 diff;
                  if (Input.GetKey(KeyCode.LeftArrow))
                  {
                      acc.x = -0.1f;
                      transform.localScale = new Vector3(-1, 1, 1);
                  }
                  if (Input.GetKey(KeyCode.RightArrow))
                  {
                      transform.localScale = new Vector3(1, 1, 1);
                      acc.x = 0.1f;
                  }
      
                  diff = Vector3.MoveTowards(transform.localPosition, transform.localPosition + acc, 0.5f * Time.time);
                  diff.y = transform.localPosition.y;
                  diff.z = 0;
      

    2、控制Player移动到边界的问题

    • Player跳到左边界的时候让其回到右边界,同理右边也一样
    • 设置两个标志位来记录左边和右边,两个标志位的位置获得通过相机的世界坐标来确定
    • 通过跳到位置信息和两个表示为来进行判断得到是否越界
    	float rightBorder;
        float leftBorder;
    void Start () {
    
            leftBorder = Camera.main.ViewportToWorldPoint(new Vector3(0, 0)).x;
            rightBorder = Camera.main.ViewportToWorldPoint(new Vector3(1, 0)).x;       
        }
     if (diff.x < leftBorder)
                {
                    diff.x = rightBorder;
                }
                if (diff.x > rightBorder)
                {
                    diff.x = leftBorder;
                }
                transform.localPosition = diff;
    

    3、设置Tile的类型和参数

    • 设置砖块类型的变换,碰撞效果等。需要添加刚体和碰撞体。
    • 通过Sprite数组来进行图片的变化,然后每个图片都是一样的效果。
    • 通过switch来进行不同砖块属性的变换

    4、 控制相机跟随主角

    • 正常情况下主角移动相机跟随,但是这样个人的感觉不太好,所以设置为主角超过屏幕中间的之后相机才跟随移动

      	//当前位置
          public Transform target;
          //目标位置的初始位置
          private Vector3 velocity = Vector3.zero;
          private float dampTime = 0.5f;
          public void Update()
          {
              if (target)
              {
                  //使用pos来标记相机当前查看的位置为主角的当前位置
                  Vector3 pos = Camera.main.WorldToScreenPoint(target.position);
                  //需要移动的位置
                  Vector3 delta = target.position - Camera.main.ViewportToWorldPoint(new Vector3(0.5f, 0.5f, pos.z));
                  //设置目标位置的初始位置
                  Vector3 destination = transform.position + delta;
                  destination.x = 0;  //默认x为0
                  if (destination.y > transform.position.y)
                  {
                      //SmoothDown方法 参数一:当前位置,参数二:移动距离,参数三:目标的初始位置,参数四:时间间隔
                      transform.position = Vector3.SmoothDamp(transform.position, destination, ref velocity, dampTime);
                  }
              }
          }
      

    5、单例模板

    • 使用单例模板来控制所以代码的单例模式
    public abstract  class MonoSingleton<T> : MonoBehaviour 
        where T  : MonoBehaviour
    {
        private static T m_instance;
        public static T Instance
        {
            get { return m_instance; }
        }
        protected virtual void Awake()
        {
            m_instance = this as T;
        }
    }
    

    6、随机生成砖块(GameSetting类)

    • 使用一个类来控制砖块的各种高宽属性,用编辑器拓展来进行手动赋值设置,值根据需求来变动
    • 使用对象池来管理所以的砖块生成和回收。
    • 使用权值来控制不同砖块生成的比例问题。

    7、砖块的左右移动和上下移动

    • 使用一个变量来统一控制,当左右移动和上下移动的砖块达到一定位置的时候就向反方向移动。
    • 然后通过OnTriggerOnenter来设置移动。

    8、对象池的设置

    • 所以的游戏物体都用对象池来生成,这里没有用到对象池模板,而是简单的设置了一下生成和回收

    • 所以游戏物体都一个自己的随机生成方法和对象池

    • 生成参数有,最大高度、最小高度、生成数量、和其他不同东西之间需要的参数

       /// <summary>
          /// 从池子取物体
          /// </summary>
          /// <param name="type">类型</param>
          /// <returns></returns>
          public GameObject GetInactiveObject(ObjectType type)
          {
              switch (type)
              {
                  case ObjectType.Tile:
                      return tilePool.Dequeue();           
                  case ObjectType.Item:
                      return itemPool.Dequeue();         
                  case ObjectType.Coin:
                      return coinPool.Dequeue();                
                  case ObjectType.Enemy:
                      return enemyPool.Dequeue();                
                  case ObjectType.Bullet:
                      GameObject go = bulletPool.Dequeue();
                      go.transform.position = bulletSpawnPos.position;
                      go.SetActive(true);
                      return go;            
                  default:
                      return null;
              }
          }
          /// <summary>
          /// 回收物体
          /// </summary>
          /// <param name="go">游戏物体</param>
          /// <param name="type">游戏物体类型</param>
          public void AddInActiveObjectToPool(GameObject go, ObjectType type)
          {
              go.SetActive(false);
              switch (type)
              {
                  case ObjectType.Tile:
                      tilePool.Enqueue(go);
                      CreateTile();
                      break;
                  case ObjectType.Item:
                      itemPool.Enqueue(go);
                      break;
                  case ObjectType.Coin:
                      coinPool.Enqueue(go);
                      break;
                  case ObjectType.Enemy:
                      enemyPool.Enqueue(go);
                      break;
                  case ObjectType.Bullet:
                      bulletPool.Enqueue(go);
                      break;
                  default:
                      break;
              }
          }
      
      

    9、物体的生成和单个物体的对象池

    • 比较多,而且都类似,所以只放一个上来

       void GenerateTilePool()
          {
              for (int i = 0; i < initialSize; i++)
              {
                  GameObject go = Instantiate(tilePrefab, transform);
                  go.SetActive(false);
                  go.name = i.ToString();
                  tilePool.Enqueue(go);
              }
          }
      
      GameObject go = GetInactiveObject(ObjectType.Tile);
              float rand = Random.Range(0, totalsum);
              int randNumber = SetTileByRandomNumber(rand);       
              Vector2 pos = new Vector2(Random.Range(-3.5f,3.5f),currentY);
      
    • 根据不同游戏物体的需求来具体生成,如果同一个游戏物体有几个类型就用枚举类型加witch来解决

    • 生成主要通过随机数的位置。

    10、难度曲线的变化

    • 主要是增加怪物的生成数量,当然达到一定程度之后就一直保持一个参数不变化了。

    11、游戏物体权值的设置

    • 游戏不同之间物体的生成比例不一样,所以使用权值来确定哪些物体生成的多哪些少
    • 每个物体都有一个权值,然后加起来是总权值,生成多的个数就多设置一些。

    12、换装

    • 通过改变player身上的Sprite Renderer来控制
    • 在开始界面保存游戏物体身上的sprite Renderer信息,购买了相应的皮肤之后把购买的信息赋值给开始界面。主要通过给每一个皮肤设置一个ID来控制,然后保存该ID值来进行改变。

    13、游戏音乐和音效

    • 通过两个脚本来控制。
    • 背景音乐(music manager),获取游戏物体身上的AudioScenes来进行控制
    • 游戏音效(soundManager)通过一个列表装好所有的音效,在不同的点击效果来设置播放效果。

    三、遇到的问题

    (一)、老师错误

    1、具体的

    (二)、自己的错误

    1、设置相机错误

    • 描述:设置两个相机是时候不能实现效果,原本主相机和背景相机相互不干扰的,但是没有该效果,背景相机移动主相机还是能看到,但是自己设置的不行
    • 原因:是从主摄像机复制一个出来进行拍摄背景的,但是自己是新建的一个相机,所以不能达到背景相机移动不影响主相机的效果。刚开设置的时候背景相机的位置跟主相机的位置不一样,所以设置了跟随以后没有跟上。如果是新建一个相机的位置跟主相机一样的话,还是能正常显示该效果的。
    • 解决:从主相机复制来制作背景相机
    • 注意:可能是位置的问题,因为位置不一样所以不能拍摄

    2、测试不同的砖块的时候没有出现图片的替换

    • 描述:同上
    • 原因:设计的时候代码多了一行,但是后面没有执行,所以没有执行数组的索引替换
    • 解决:注释多写的代码
    • 注意:有时候有些参数设置了,但是后面没有处理,于是带代码上面也使用了后面没有处理的转换,于是不能达到自己想要的效果,

    3、对象池生成物体的时候转换名字的时候报错,提示类型不能转换

    • 描述:同上
    • 原因:对象池回收的时候要设置为不可见状态,而代码设置了可见状态,所以不能进行同时转换
    • 解决:把代码改回来
    • 注意:写逻辑的时候对待什么时候是false什么时候是true要判断清楚。

    4、砖块上下移动的时候一直向下移动

    • 描述:同上
    • 原因:在设置参数的时候,一个是y方向的移动,变成了x方向,所以砖块一直向下移动
    • 解决:把参数改回来
    • 注意:一个是在设置的时候仔细查看值,第二个是发现错误的时候定位要准确,知道是不能向上移动,肯定是x或者y的值不对。

    5、floor不能跟player发生碰撞

    • 描述:
    • 原因:使用boxcollider的时候用错了,本来要使用boxcollide2D的,自己用了boxCollider
    • 解决:修改boxCollider
    • 注意:发生碰撞检测的时候,如果达不到想要的结果,先查看rigidbody,和Collider的状态,比如Collider的is Trigger勾选等。

    四、最后总结

    1、总结概括

    • 该游戏主要是一款2D向上跳跃游戏,主要运用技术有对象池、使用不同的对象池和随机生成方法来控制游戏物体的产生和回收、通过简单的UI框架来控制UI的显示、通过一个UI控制类添加List和栈来控制显示和隐藏,主要是给每个面板一个ID值,需要的时候出栈不需要的时候出栈、开发过程中还有很多地方运用到了List比如不同主角、方块之间的变化也是通过改变sprite Renderer来改变的。还学习了简单的换装原理。和声音管理组件的使用。

    2、制作思路扩展

    • 其实不同之间的方块也可以通过面向对象的思维来制作,给方块添加一个父类。
    • 在对象池的使用过程中,也可以使用面向对象的思想,来进行写一个对象池和生成模板来进行不同的生成。

    3、反思

    • 虽然看完和制作完之后,基本原理都弄清楚了,知识点也知道了,扩展思路也有,但是如果是自己写代码的话还是写不出来。
    • 一些内置方法自己也不是很清楚用法。看来编程能力还有待提高。
    • 还有就是开发的时候,有些错误可以避免的但是还是粗心没有看清楚。
    • 还有一些知识点有点懒也没有具体的写笔记,知识笼统的概括了一下而已。代码也没有贴上来。
    展开全文
  • 一般情况下,在android系统中获取手机的方位信息azimuth似乎是很简单的事情,在api中有TYPE_ORIENTATION常量,可以像得到加速度传感器那样得到方向传感器sm.getDefaultSensor(Sensor.TYPE_ORIENTATION);ranh
  • 一款很不错的安卓僵尸跳跳游戏源码下载,该android游戏的源码比较完整,值得大家的学习。 类似驴子跳的玩法.丰富的道具!可爱的画面! 玩家需要左右摇晃手机保证小僵尸不要掉下跳板,在完成关卡的前提下找到任务...
  • 说起这个问题,真是头疼。我的项目布局时候突然就不提示属性的输入了,全要手敲,我原以为是因为设置了限制,查看了as的设置,并没有,关键是在代码输入的Activity或者Fragment中输入代码是有提示的,我重新打开其他...
  • 尊重开发者的劳动成果,未经允许请勿转载 游戏简介: 贱鸟跳跳,贱贱的小鸟这次遇上大问题了,被它整蛊过的同类都在找它的麻烦,现在我们赶紧到游戏中帮帮它吧!左右手互撸,合理操控,获得高分,打败其它玩家,获得...
  • Kotlin开发Android实现模块间跳转需进行如下配置: 1、主Module apply plugin: 'kotlin-kapt' dependencies { kapt "com.alibaba:arouter-compiler:1.1.4" } 2、库Module apply plugin: '...
  • 简单介绍: 用安卓实现的一个黑色全屏上,红色的小球的随机跳动,加速度越来越快。 采用surfaceview实现,在activity中设置为全屏,并将小球弹跳的surfaceview设置为显示的view,主要代码都在surfaceview中实现...
  • 目录:src\com.android.email.activity 一. Welcome.java 根据AndroidManifest.xml可知该文件为程序入口文件: 加载该文件时,查询数据库账户列表信息。如果查询出没有账户信息,则跳转到设置账户界面:...
  • 动画的基本原理是从开始时间到结束时间一帧一帧的播放静态图像。Interpolator插值器来...Android系统的插值器有9种: Interpolators的使用方式有两种:一种是通过xml文件来设置,另一种在代码中设置 xml中的使用 &...
  • 简介Python 是否可以开发简单的游戏?明显是可以的。在 Python 中可以利用 pygame 来开发一款游戏,有了 pygame,就不需要我们自己...
  • 所示,这是一款android的跳格子游戏(名字叫小鸟跳跳中的游戏为第二版)——红色的格子只能跳一次,黄色的格子可以跳2次,控制小鸟从起点跳到终点。 我 们的目的是使小鸟可以到达终点,注意,这里的到达也许...
  • android Email总结文档

    2019-01-05 22:24:20
    目录:src\com.android.email.activity 一. Welcome.java 根据AndroidManifest.xml可知该文件为程序入口文件:加载该文件时,查询数据库账户列表信息。如果查询出没有账户信息,则跳转到设置账户界面:...
  • Intent 是Android中各种交互,
  • Android中支持表情

    2019-07-04 19:21:23
    最近项目需要支持表情,表情的添加和解析实现基本上是参照Android自身的SmileyParser,具体就不多讲了,直接贴上代码: public class SmileyParser {private static SmileyParser sInstance = null;private Context...
  • 乒乓球游戏源码 ...人气:3592运行环境:/android/ipad 软件大小:3.12 MB 更新日期:2013-09-09 共享源码 吃金币游戏源码 一款很不错的吃金币游戏源码,该游戏现在的用户...
1 2 3 4 5 6
收藏数 120
精华内容 48
热门标签