├── .gitignore ├── .idea ├── .name ├── compiler.xml ├── copyright │ └── profiles_settings.xml ├── gradle.xml ├── misc.xml ├── modules.xml └── vcs.xml ├── Demos.iml ├── app ├── .gitignore ├── app.iml ├── build.gradle ├── proguard-rules.pro └── src │ └── main │ ├── AndroidManifest.xml │ ├── java │ └── com │ │ └── infinut │ │ └── anar │ │ └── demos │ │ ├── MainActivity.java │ │ ├── PageTurnActivity.java │ │ ├── PageTurnRenderView.java │ │ ├── PageTurnScreen.java │ │ ├── RocketActivity.java │ │ ├── RocketRenderView.java │ │ ├── RocketScreen.java │ │ ├── Star.java │ │ └── framework │ │ ├── ImageUtil.java │ │ ├── PixelUtil.java │ │ ├── Pool.java │ │ ├── RenderView.java │ │ ├── Screen.java │ │ ├── Touch.java │ │ └── TouchHandler.java │ └── res │ ├── drawable │ ├── rocket_effect.png │ ├── star_blue.png │ ├── star_green.png │ ├── star_orange.png │ ├── star_pink.png │ ├── star_purple.png │ ├── star_red.png │ └── star_yellow.png │ ├── layout │ ├── activity_main.xml │ ├── activity_page_turn.xml │ └── activity_rocket.xml │ ├── mipmap-hdpi │ └── ic_launcher.png │ ├── mipmap-mdpi │ └── ic_launcher.png │ ├── mipmap-xhdpi │ └── ic_launcher.png │ ├── mipmap-xxhdpi │ └── ic_launcher.png │ └── values │ ├── attrs.xml │ ├── colors.xml │ └── strings.xml ├── build.gradle ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat └── settings.gradle /.gitignore: -------------------------------------------------------------------------------- 1 | .gradle 2 | /local.properties 3 | /.idea/workspace.xml 4 | /.idea/libraries 5 | .DS_Store 6 | /build 7 | /captures 8 | -------------------------------------------------------------------------------- /.idea/.name: -------------------------------------------------------------------------------- 1 | Demos -------------------------------------------------------------------------------- /.idea/compiler.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /.idea/copyright/profiles_settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /.idea/gradle.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 18 | 19 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 19 | -------------------------------------------------------------------------------- /.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /Demos.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /app/app.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 8 | 9 | 10 | 11 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | 3 | android { 4 | compileSdkVersion 22 5 | buildToolsVersion "23.0.0 rc3" 6 | 7 | defaultConfig { 8 | applicationId "com.infinut.anar.demos" 9 | minSdkVersion 15 10 | targetSdkVersion 22 11 | versionCode 1 12 | versionName "1.0" 13 | } 14 | buildTypes { 15 | release { 16 | minifyEnabled false 17 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 18 | } 19 | } 20 | } 21 | 22 | dependencies { 23 | compile fileTree(dir: 'libs', include: ['*.jar']) 24 | } 25 | -------------------------------------------------------------------------------- /app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in C:\Users\anar\AppData\Local\Android\sdk/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | 12 | # If your project uses WebView with JS, uncomment the following 13 | # and specify the fully qualified class name to the JavaScript interface 14 | # class: 15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 16 | # public *; 17 | #} 18 | -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 11 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 29 | 30 | 36 | 37 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /app/src/main/java/com/infinut/anar/demos/MainActivity.java: -------------------------------------------------------------------------------- 1 | package com.infinut.anar.demos; 2 | 3 | import android.app.Activity; 4 | import android.content.Intent; 5 | import android.os.Bundle; 6 | import android.view.View; 7 | import android.widget.Button; 8 | 9 | import com.infinut.anar.demos.framework.RenderView; 10 | 11 | /** 12 | * Main page to launch the samples 13 | */ 14 | public class MainActivity extends Activity { 15 | protected void onCreate(Bundle savedInstanceState) { 16 | super.onCreate(savedInstanceState); 17 | 18 | setContentView(R.layout.activity_main); 19 | 20 | Button rocket = (Button) findViewById(R.id.rocket); 21 | rocket.setOnClickListener(new View.OnClickListener() { 22 | @Override 23 | public void onClick(View v) { 24 | startActivity(new Intent(MainActivity.this, RocketActivity.class)); 25 | } 26 | }); 27 | 28 | Button pageturn = (Button) findViewById(R.id.pageturn); 29 | pageturn.setOnClickListener(new View.OnClickListener() { 30 | @Override 31 | public void onClick(View v) { 32 | startActivity(new Intent(MainActivity.this, PageTurnActivity.class)); 33 | } 34 | }); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /app/src/main/java/com/infinut/anar/demos/PageTurnActivity.java: -------------------------------------------------------------------------------- 1 | package com.infinut.anar.demos; 2 | 3 | import android.app.Activity; 4 | import android.os.Bundle; 5 | 6 | import com.infinut.anar.demos.framework.RenderView; 7 | 8 | /** 9 | * A sample Activity showing the launch of a Surface View for a page turn animation. 10 | */ 11 | public class PageTurnActivity extends Activity { 12 | RenderView view; 13 | 14 | @Override 15 | protected void onCreate(Bundle savedInstanceState) { 16 | super.onCreate(savedInstanceState); 17 | 18 | setContentView(R.layout.activity_page_turn); 19 | view = (RenderView) findViewById(R.id.mainview); 20 | } 21 | 22 | protected void onPause() { 23 | super.onPause(); 24 | view.pause(); 25 | } 26 | 27 | protected void onResume() { 28 | super.onResume(); 29 | view.resume(); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /app/src/main/java/com/infinut/anar/demos/PageTurnRenderView.java: -------------------------------------------------------------------------------- 1 | package com.infinut.anar.demos; 2 | 3 | import android.content.Context; 4 | import android.util.AttributeSet; 5 | 6 | import com.infinut.anar.demos.framework.RenderView; 7 | 8 | /** 9 | * Launches the thread for rendering page turn animation 10 | */ 11 | public class PageTurnRenderView extends RenderView { 12 | public PageTurnRenderView(Context context, AttributeSet attrs) { 13 | super(context, attrs); 14 | screen = new PageTurnScreen(context, touchHandler); 15 | } 16 | } -------------------------------------------------------------------------------- /app/src/main/java/com/infinut/anar/demos/PageTurnScreen.java: -------------------------------------------------------------------------------- 1 | package com.infinut.anar.demos; 2 | 3 | import android.content.Context; 4 | import android.content.res.Resources; 5 | import android.graphics.Canvas; 6 | import android.graphics.DashPathEffect; 7 | import android.graphics.Matrix; 8 | import android.graphics.Paint; 9 | import android.graphics.Path; 10 | import android.graphics.PointF; 11 | import android.graphics.RectF; 12 | import android.util.DisplayMetrics; 13 | 14 | import com.infinut.anar.demos.framework.PixelUtil; 15 | import com.infinut.anar.demos.framework.Screen; 16 | import com.infinut.anar.demos.framework.TouchHandler; 17 | 18 | /** 19 | * Page Turn animation present / update 20 | */ 21 | public class PageTurnScreen extends Screen { 22 | public PageTurnScreen(Context context, TouchHandler touchHandler) { 23 | super(context, touchHandler); 24 | } 25 | 26 | private float scale; 27 | private float screenWidth; 28 | private float screenHeight; 29 | 30 | Matrix matrix; 31 | RectF location; 32 | 33 | //draw paper 34 | Paint paperbg; 35 | Paint outlinebg; 36 | Paint dashedbg; 37 | Paint curlEdgePaint; 38 | 39 | //curl transition 40 | PointF mA, mB, mC, mD, mE, mF; 41 | float mMovement, mVelocity; 42 | Path bgPath, curlPath; 43 | 44 | @Override 45 | public void init() { 46 | if (initialized.compareAndSet(false, true)) { 47 | Resources res = context.getResources(); 48 | DisplayMetrics dm = res.getDisplayMetrics(); 49 | 50 | //init variables 51 | scale = PixelUtil.getScale(dm); 52 | screenWidth = dm.widthPixels; 53 | screenHeight = dm.heightPixels; 54 | 55 | paperbg = new Paint(); 56 | paperbg.setStyle(Paint.Style.FILL); 57 | paperbg.setColor(0xffffcc00); 58 | paperbg.setAntiAlias(true); 59 | paperbg.setDither(true); 60 | 61 | outlinebg = new Paint(); 62 | outlinebg.setStyle(Paint.Style.STROKE); 63 | outlinebg.setColor(0xff555555); 64 | outlinebg.setStrokeCap(Paint.Cap.ROUND); 65 | outlinebg.setStrokeWidth(1 * scale); 66 | 67 | dashedbg = new Paint(); 68 | dashedbg.setStyle(Paint.Style.STROKE); 69 | dashedbg.setColor(0xff555555); 70 | dashedbg.setStrokeCap(Paint.Cap.ROUND); 71 | dashedbg.setStrokeWidth(1 * scale); 72 | dashedbg.setPathEffect(new DashPathEffect(new float[]{4 * scale, 2 * scale}, 0)); 73 | 74 | curlEdgePaint = new Paint(); 75 | curlEdgePaint.setColor(0xffffe6d5); 76 | curlEdgePaint.setAntiAlias(true); 77 | curlEdgePaint.setStyle(Paint.Style.FILL); 78 | curlEdgePaint.setShadowLayer(5*scale, 5*scale, -5*scale, 0x66000000); 79 | 80 | bgPath = new Path(); 81 | curlPath = new Path(); 82 | matrix = new Matrix(); 83 | 84 | //square page in center of screen 85 | float padx = (screenWidth - screenHeight) / 2; 86 | location = new RectF(padx, 0, padx + screenHeight, screenHeight); 87 | } 88 | startCurl(); 89 | } 90 | 91 | @Override 92 | public void update(float deltaTime) { 93 | mVelocity += 5 * scale * deltaTime; 94 | mMovement += deltaTime * mVelocity * scale; 95 | doCurl(); 96 | } 97 | 98 | @Override 99 | public void present(float deltaTime, Canvas canvas) { 100 | matrix.reset(); 101 | Path mask = createBackgroundPath(); 102 | // Save current canvas so we do not mess it up 103 | canvas.save(); 104 | canvas.clipPath(mask); 105 | 106 | matrix.setTranslate(location.left, location.top); 107 | canvas.drawRect(location, paperbg); 108 | canvas.drawRect(location, outlinebg); 109 | 110 | for (int i = 1; i < 4; i++) { 111 | float bgy = (location.height() * i) / 4; 112 | canvas.drawLine(location.left, bgy, location.right, bgy, dashedbg); 113 | } 114 | 115 | canvas.restore(); 116 | 117 | //draw edge 118 | Path path = createCurlEdgePath(); 119 | canvas.drawPath(path, curlEdgePaint); 120 | } 121 | 122 | private Path createBackgroundPath() { 123 | bgPath.reset(); 124 | bgPath.moveTo(mA.x, mA.y); 125 | bgPath.lineTo(mB.x, mB.y); 126 | bgPath.lineTo(mC.x, mC.y); 127 | bgPath.lineTo(mD.x, mD.y); 128 | bgPath.lineTo(mA.x, mA.y); 129 | return bgPath; 130 | } 131 | 132 | private Path createCurlEdgePath() { 133 | curlPath.reset(); 134 | curlPath.moveTo(mA.x, mA.y); 135 | curlPath.lineTo(mF.x, mF.y); 136 | curlPath.lineTo(mE.x, mE.y); 137 | curlPath.lineTo(mD.x, mD.y); 138 | curlPath.lineTo(mA.x, mA.y); 139 | return curlPath; 140 | } 141 | 142 | private void startCurl() { 143 | float width = location.right - location.left; 144 | float height = location.bottom - location.top; 145 | mMovement = 0; 146 | mVelocity = 5 * scale; 147 | 148 | mA = new PointF(0, 0); 149 | mB = new PointF(0, 0); 150 | mC = new PointF(0, 0); 151 | mD = new PointF(0, 0); 152 | mE = new PointF(0, 0); 153 | mF = new PointF(0, 0); 154 | mA.x = location.left + width; 155 | mA.y = location.top + height; 156 | mC.x = location.left + 0.0f; 157 | mC.y = location.top + 0.0f; 158 | mB.x = location.left + width; 159 | mB.y = location.top + 0.0f; 160 | mD.x = location.left + 0; 161 | mD.y = location.top + height; 162 | mE.x = mD.x; 163 | mE.y = mD.y; 164 | mF.x = mA.x; 165 | mF.y = mA.y; 166 | } 167 | 168 | private void doCurl() { 169 | float width = location.right - location.left; 170 | float height = location.bottom - location.top; 171 | 172 | if (mMovement > 0.0f) { 173 | // Calculate point A 174 | mA.y = height - mMovement; 175 | mA.x = width; 176 | 177 | // Calculate point D 178 | mD.x = 0; 179 | mD.y = height - mMovement / 2; 180 | 181 | mE.x = mD.x; 182 | mE.y = mD.y; 183 | mF.x = mA.x; 184 | mF.y = mA.y; 185 | 186 | // Now calculate E and F. B and C are fixed points. 187 | double angle = Math.PI - 2*Math.atan(width*2 / mMovement); 188 | double _cos = Math.cos(angle); 189 | double _sin = Math.sin(angle); 190 | 191 | // And get F 192 | mF.x = (float) (mA.x - _sin * mMovement); 193 | mF.y = (float) (height - mMovement - _cos * mMovement); 194 | 195 | // So get E 196 | mE.x = (float) (mD.x - _sin * mMovement / 2); 197 | mE.y = (float) (height - mMovement / 2 - _cos * mMovement / 2); 198 | 199 | 200 | //adjust for location 201 | mA.x += location.left; 202 | mA.y += location.top; 203 | mD.x += location.left; 204 | mD.y += location.top; 205 | mE.x += location.left; 206 | mE.y += location.top; 207 | mF.x += location.left; 208 | mF.y += location.top; 209 | } 210 | } 211 | } 212 | -------------------------------------------------------------------------------- /app/src/main/java/com/infinut/anar/demos/RocketActivity.java: -------------------------------------------------------------------------------- 1 | package com.infinut.anar.demos; 2 | 3 | import android.app.Activity; 4 | import android.os.Bundle; 5 | 6 | import com.infinut.anar.demos.framework.RenderView; 7 | 8 | 9 | /** 10 | * A sample Activity showing the launch of a Surface View. 11 | * 12 | */ 13 | public class RocketActivity extends Activity { 14 | RenderView view; 15 | 16 | @Override 17 | protected void onCreate(Bundle savedInstanceState) { 18 | super.onCreate(savedInstanceState); 19 | 20 | setContentView(R.layout.activity_rocket); 21 | view = (RenderView) findViewById(R.id.mainview); 22 | } 23 | 24 | protected void onPause() { 25 | super.onPause(); 26 | view.pause(); 27 | } 28 | 29 | protected void onResume() { 30 | super.onResume(); 31 | view.resume(); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /app/src/main/java/com/infinut/anar/demos/RocketRenderView.java: -------------------------------------------------------------------------------- 1 | package com.infinut.anar.demos; 2 | 3 | import android.content.Context; 4 | import android.util.AttributeSet; 5 | 6 | import com.infinut.anar.demos.framework.RenderView; 7 | 8 | /** 9 | * Renders a rocket and rocket-burst. 10 | */ 11 | public class RocketRenderView extends RenderView { 12 | public RocketRenderView(Context context, AttributeSet attrs) { 13 | super(context, attrs); 14 | screen = new RocketScreen(context, touchHandler); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /app/src/main/java/com/infinut/anar/demos/RocketScreen.java: -------------------------------------------------------------------------------- 1 | package com.infinut.anar.demos; 2 | 3 | import android.content.Context; 4 | import android.content.res.Resources; 5 | import android.graphics.Bitmap; 6 | import android.graphics.Canvas; 7 | import android.graphics.Matrix; 8 | import android.graphics.RectF; 9 | import android.util.DisplayMetrics; 10 | 11 | import com.infinut.anar.demos.framework.ImageUtil; 12 | import com.infinut.anar.demos.framework.PixelUtil; 13 | import com.infinut.anar.demos.framework.Screen; 14 | import com.infinut.anar.demos.framework.Touch; 15 | import com.infinut.anar.demos.framework.TouchHandler; 16 | 17 | import java.util.ArrayList; 18 | import java.util.List; 19 | import java.util.Random; 20 | 21 | /** 22 | * Is where the work happens. Update and Present(draw) methods. 23 | */ 24 | public class RocketScreen extends Screen { 25 | 26 | private float scale; 27 | private float screenWidth; 28 | private float screenHeight; 29 | private Matrix matrix; 30 | 31 | private Bitmap rocket; 32 | //rocket location 33 | private float speedX; 34 | private float speedY; 35 | private float accelX; 36 | private float accelY; 37 | private float rotate; 38 | private RectF bounds; 39 | private boolean burst; 40 | 41 | //burst 42 | Random random; 43 | List stars; 44 | Bitmap[] starBitmaps; 45 | 46 | public RocketScreen(Context context, TouchHandler touchHandler) { 47 | super(context, touchHandler); 48 | } 49 | 50 | public void init() { 51 | if (initialized.compareAndSet(false, true)) { 52 | Resources res = context.getResources(); 53 | DisplayMetrics dm = res.getDisplayMetrics(); 54 | 55 | //init variables 56 | scale = PixelUtil.getScale(dm); 57 | screenWidth = dm.widthPixels; 58 | screenHeight = dm.heightPixels; 59 | matrix = new Matrix(); 60 | 61 | //load image 62 | int imageSize = (int) (80 * scale); 63 | rocket = ImageUtil.loadImage(res, R.drawable.rocket_effect, imageSize, imageSize); 64 | bounds = new RectF(); 65 | startRocket(); 66 | 67 | //init burst 68 | random = new Random(); 69 | stars = new ArrayList(); 70 | loadStars(res); 71 | } 72 | if (restartAnimation()) { 73 | startRocket(); 74 | } 75 | } 76 | 77 | private void loadStars(Resources res) { 78 | starBitmaps = new Bitmap[7]; 79 | int bs = Math.round(40 * scale); 80 | 81 | starBitmaps[0] = ImageUtil.loadImage(res, R.drawable.star_blue, bs, bs); 82 | starBitmaps[1] = ImageUtil.loadImage(res, R.drawable.star_green, bs, bs); 83 | starBitmaps[2] = ImageUtil.loadImage(res, R.drawable.star_orange, bs, bs); 84 | starBitmaps[3] = ImageUtil.loadImage(res, R.drawable.star_pink, bs, bs); 85 | starBitmaps[4] = ImageUtil.loadImage(res, R.drawable.star_purple, bs, bs); 86 | starBitmaps[5] = ImageUtil.loadImage(res, R.drawable.star_red, bs, bs); 87 | starBitmaps[6] = ImageUtil.loadImage(res, R.drawable.star_yellow, bs, bs); 88 | } 89 | 90 | private boolean restartAnimation() { 91 | //rocket out of screen 92 | if (!burst) { 93 | if (bounds.right < 0 || bounds.left > screenWidth || bounds.top > screenHeight || bounds.bottom < 0) { 94 | return true; 95 | } 96 | } 97 | //all stars out of screen 98 | if(burst) { 99 | for (Star star : stars) { 100 | if (star.isVisible(screenWidth, screenHeight)) { 101 | return false; 102 | } 103 | } 104 | return true; 105 | } 106 | 107 | return false; 108 | } 109 | 110 | private void startRocket() { 111 | float radians = (float) Math.toRadians(60); 112 | float speed = 100 * scale; 113 | speedX = (float) (Math.cos(radians) * speed); 114 | speedY = (float) (Math.sin(radians) * speed * -1); 115 | accelX = 0; 116 | accelY = 20 * scale; //accelY is gravity 117 | 118 | float imageSize = rocket.getHeight(); 119 | bounds.set(0, screenHeight - imageSize, imageSize, screenHeight); 120 | burst = false; 121 | } 122 | 123 | public void update(float deltaTime) { 124 | List events = touchHandler.getTouchEvents(); 125 | for (Touch event : events) { 126 | if (bounds.contains(event.x, event.y)) { 127 | startBurst(); 128 | break; 129 | } 130 | } 131 | 132 | if (!burst) { 133 | speedX += accelX * deltaTime; 134 | speedY += accelY * deltaTime; 135 | bounds.offset(speedX * deltaTime, speedY * deltaTime); 136 | 137 | //rotate on tangent to path 138 | rotate = (float) Math.toDegrees(Math.atan2(speedY, speedX)); 139 | } else { 140 | for(Star star: stars) { 141 | star.update(deltaTime); 142 | } 143 | } 144 | } 145 | 146 | private void startBurst() { 147 | stars.clear(); 148 | for (int i = 0; i < 10; i++) { 149 | Star star = new Star(); 150 | Bitmap bitmap = starBitmaps[i % starBitmaps.length]; 151 | int size = bitmap.getWidth(); 152 | star.bounds = new RectF(bounds.centerX() - (size) / 2, bounds.centerY() - (size) / 2, bounds.centerX() + (size) / 2, bounds.centerY() + (size) / 2); 153 | star.bitmap = bitmap; 154 | 155 | star.dirX = (random.nextInt(200) - 100) * scale; //between -50 and 50 156 | star.dirY = -(random.nextInt(200) - 100) * scale; //between -50 and 50 157 | star.accelX = 0.0f; 158 | star.accelY = 20 * scale; //accelY is gravity 159 | stars.add(star); 160 | } 161 | burst = true; 162 | } 163 | 164 | public void present(float deltaTime, Canvas canvas) { 165 | canvas.drawColor(0xFFC6E9AF); 166 | if (!burst) { 167 | matrix.setTranslate(bounds.left, bounds.top); 168 | matrix.postRotate(rotate, bounds.centerX(), bounds.centerY()); 169 | 170 | canvas.drawBitmap(rocket, matrix, null); 171 | } else { 172 | for (Star star : stars) { 173 | star.draw(canvas, matrix); 174 | } 175 | } 176 | } 177 | } 178 | -------------------------------------------------------------------------------- /app/src/main/java/com/infinut/anar/demos/Star.java: -------------------------------------------------------------------------------- 1 | package com.infinut.anar.demos; 2 | 3 | import android.graphics.Bitmap; 4 | import android.graphics.Canvas; 5 | import android.graphics.Matrix; 6 | import android.graphics.RectF; 7 | 8 | /** 9 | * Wrapper for a star shown when rocket bursts. 10 | */ 11 | public class Star { 12 | Bitmap bitmap; 13 | RectF bounds; 14 | 15 | //initial values 16 | float dirX, dirY; //velocity x, y 17 | float accelX, accelY; //acceleration x, y 18 | 19 | public void draw(Canvas canvas, Matrix matrix) { 20 | matrix.setTranslate(bounds.left, bounds.top); 21 | canvas.drawBitmap(bitmap, matrix, null); 22 | } 23 | public void update(float deltaTime) { 24 | dirX = dirX + accelX * deltaTime; 25 | dirY = dirY + accelY * deltaTime; 26 | 27 | bounds.offset(dirX * deltaTime, dirY * deltaTime); 28 | } 29 | public boolean isVisible(float screenWidth, float screenHeight) { 30 | if (bounds.right < 0 || bounds.left > screenWidth || bounds.top > screenHeight || bounds.bottom < 0) { 31 | return false; 32 | } 33 | return true; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /app/src/main/java/com/infinut/anar/demos/framework/ImageUtil.java: -------------------------------------------------------------------------------- 1 | package com.infinut.anar.demos.framework; 2 | 3 | import android.content.res.Resources; 4 | import android.graphics.Bitmap; 5 | import android.graphics.BitmapFactory; 6 | 7 | /** 8 | * Loads up images with the right sampling interval based on device resolution and size. 9 | */ 10 | public class ImageUtil { 11 | public static Bitmap loadImage(Resources res, int resourceId, int width, 12 | int height) { 13 | Bitmap bitmap = decodeSampledBitmapFromResource(res, resourceId, width, 14 | height); 15 | return Bitmap.createScaledBitmap(bitmap, width, height, true); 16 | } 17 | 18 | private static Bitmap decodeSampledBitmapFromResource(Resources res, 19 | int resId, int reqWidth, int reqHeight) { 20 | 21 | // First decode with inJustDecodeBounds=true to check dimensions 22 | final BitmapFactory.Options options = new BitmapFactory.Options(); 23 | options.inJustDecodeBounds = true; 24 | BitmapFactory.decodeResource(res, resId, options); 25 | 26 | // Calculate inSampleSize 27 | options.inSampleSize = calculateInSampleSize(options, reqWidth, 28 | reqHeight); 29 | 30 | // Decode bitmap with inSampleSize set 31 | options.inJustDecodeBounds = false; 32 | return BitmapFactory.decodeResource(res, resId, options); 33 | } 34 | 35 | private static int calculateInSampleSize(BitmapFactory.Options options, 36 | int reqWidth, int reqHeight) { 37 | // Raw height and width of image 38 | final int height = options.outHeight; 39 | final int width = options.outWidth; 40 | int inSampleSize = 1; 41 | 42 | if (height > reqHeight || width > reqWidth) { 43 | 44 | // Calculate ratios of height and width to requested height and 45 | // width 46 | final int heightRatio = (int) ((float) height 47 | / (float) reqHeight); 48 | final int widthRatio = (int) ((float) width / (float) reqWidth); 49 | 50 | // Choose the smallest ratio as inSampleSize value, this will 51 | // guarantee 52 | // a final image with both dimensions larger than or equal to the 53 | // requested height and width. 54 | inSampleSize = heightRatio < widthRatio ? heightRatio : widthRatio; 55 | } 56 | 57 | return inSampleSize; 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /app/src/main/java/com/infinut/anar/demos/framework/PixelUtil.java: -------------------------------------------------------------------------------- 1 | package com.infinut.anar.demos.framework; 2 | 3 | import android.util.DisplayMetrics; 4 | 5 | /** 6 | * Defines a scale factor to use for scaling what's displayed 7 | */ 8 | public class PixelUtil { 9 | public static float getScale(DisplayMetrics dm) { 10 | int x = dm.widthPixels; 11 | int y = dm.heightPixels; 12 | if (x < y) { 13 | float xr = dm.widthPixels / 320.0f; 14 | float yr = dm.heightPixels / 480.0f; 15 | return Math.min(xr, yr); 16 | } else {//landscape 17 | float xr = dm.widthPixels / 480.0f; 18 | float yr = dm.heightPixels / 320.0f; 19 | return Math.min(xr, yr); 20 | } 21 | } 22 | 23 | } 24 | -------------------------------------------------------------------------------- /app/src/main/java/com/infinut/anar/demos/framework/Pool.java: -------------------------------------------------------------------------------- 1 | package com.infinut.anar.demos.framework; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | 6 | /** 7 | * Pool reusable objects to reduce garbage collection 8 | */ 9 | public class Pool { 10 | 11 | private final List freeObjects; 12 | private final PoolObjectFactory factory; 13 | private final int maxSize; 14 | 15 | public interface PoolObjectFactory { 16 | public T createObject(); 17 | } 18 | 19 | public Pool(PoolObjectFactory factory, int maxSize) { 20 | this.factory = factory; 21 | this.maxSize = maxSize; 22 | this.freeObjects = new ArrayList(maxSize); 23 | } 24 | 25 | public T newObject() { 26 | T object = null; 27 | 28 | if (freeObjects.size() == 0) 29 | object = factory.createObject(); 30 | else 31 | object = freeObjects.remove(freeObjects.size() - 1); 32 | 33 | return object; 34 | } 35 | 36 | public void free(T object) { 37 | if (freeObjects.size() < maxSize) 38 | freeObjects.add(object); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /app/src/main/java/com/infinut/anar/demos/framework/RenderView.java: -------------------------------------------------------------------------------- 1 | package com.infinut.anar.demos.framework; 2 | 3 | import android.content.Context; 4 | import android.graphics.Canvas; 5 | import android.util.AttributeSet; 6 | import android.view.MotionEvent; 7 | import android.view.SurfaceHolder; 8 | import android.view.SurfaceView; 9 | 10 | import java.util.concurrent.atomic.AtomicBoolean; 11 | 12 | /** 13 | * Manages a rendering thread. 14 | */ 15 | public abstract class RenderView extends SurfaceView implements SurfaceHolder.Callback, Runnable { 16 | 17 | Thread renderThread = null; 18 | SurfaceHolder holder; 19 | protected Screen screen; 20 | protected TouchHandler touchHandler; 21 | AtomicBoolean running = new AtomicBoolean(); 22 | AtomicBoolean render = new AtomicBoolean(); 23 | 24 | public RenderView(Context context, AttributeSet attrs) { 25 | super(context, attrs); 26 | holder = getHolder(); 27 | holder.addCallback(this); 28 | touchHandler = new TouchHandler(); 29 | running.set(false); 30 | render.set(false); 31 | } 32 | 33 | public void resume() { 34 | if (renderThread == null) { 35 | running.set(true); 36 | renderThread = new Thread(this); 37 | renderThread.start(); 38 | } 39 | } 40 | 41 | public void run() { 42 | while(!render.get()) //check can render first. 43 | continue; 44 | //surface has been initialized 45 | screen.init(); 46 | long startTime = System.nanoTime(); 47 | while (running.get()) { 48 | if(!render.get()) 49 | continue; 50 | float deltaTime = (System.nanoTime() - startTime) / 1000000000.0f; 51 | startTime = System.nanoTime(); 52 | 53 | screen.update(deltaTime); 54 | 55 | Canvas canvas = holder.lockCanvas(); 56 | canvas.drawRGB(0, 0, 0); 57 | screen.present(deltaTime, canvas); 58 | holder.unlockCanvasAndPost(canvas); 59 | } 60 | } 61 | 62 | public void pause() { 63 | running.set(false); 64 | if (renderThread != null) { 65 | boolean retry = true; 66 | while (retry) { 67 | try { 68 | renderThread.join(); 69 | renderThread = null; 70 | retry = false; 71 | } catch (InterruptedException e) { 72 | //retry 73 | } 74 | } 75 | } 76 | } 77 | 78 | @Override 79 | public boolean onTouchEvent(MotionEvent event) { 80 | 81 | return touchHandler.onTouch(this, event); 82 | } 83 | 84 | @Override 85 | public void surfaceCreated(SurfaceHolder holder) { 86 | render.set(false); 87 | } 88 | 89 | @Override 90 | public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { 91 | render.compareAndSet(false, true); 92 | } 93 | 94 | @Override 95 | public void surfaceDestroyed(SurfaceHolder holder) { 96 | render.set(false); 97 | } 98 | } -------------------------------------------------------------------------------- /app/src/main/java/com/infinut/anar/demos/framework/Screen.java: -------------------------------------------------------------------------------- 1 | package com.infinut.anar.demos.framework; 2 | 3 | import android.content.Context; 4 | import android.graphics.Canvas; 5 | 6 | import java.util.concurrent.atomic.AtomicBoolean; 7 | 8 | /** 9 | * Screens (derived from this class) do the work of showing the animation(s) 10 | */ 11 | public abstract class Screen { 12 | protected AtomicBoolean initialized; 13 | protected TouchHandler touchHandler; 14 | protected Context context; 15 | 16 | public Screen(Context context, TouchHandler touchHandler) { 17 | this.touchHandler = touchHandler; 18 | this.context = context; 19 | initialized = new AtomicBoolean(false); 20 | } 21 | public abstract void init(); 22 | 23 | public abstract void update(float deltaTime); 24 | 25 | public abstract void present(float deltaTime, Canvas canvas); 26 | 27 | public void draw() { 28 | 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /app/src/main/java/com/infinut/anar/demos/framework/Touch.java: -------------------------------------------------------------------------------- 1 | package com.infinut.anar.demos.framework; 2 | 3 | /** 4 | * Store and pass the touch event from the render thread to the screen responsible for handling it. 5 | */ 6 | public class Touch { 7 | public static final int TOUCH_DOWN = 0; 8 | public static final int TOUCH_UP = 1; 9 | public static final int TOUCH_MOVE = 2; 10 | 11 | public volatile int type; 12 | public volatile float x, y; 13 | public volatile int pointer; 14 | 15 | } 16 | -------------------------------------------------------------------------------- /app/src/main/java/com/infinut/anar/demos/framework/TouchHandler.java: -------------------------------------------------------------------------------- 1 | package com.infinut.anar.demos.framework; 2 | 3 | import android.view.MotionEvent; 4 | import android.view.View; 5 | 6 | import java.util.ArrayList; 7 | import java.util.List; 8 | 9 | /** 10 | * Handles touch input using a Pooled object queue. 11 | */ 12 | public class TouchHandler { 13 | 14 | Pool touchEventPool; 15 | List touchEvents = new ArrayList(); 16 | List touchEventsBuffer = new ArrayList(); 17 | 18 | public TouchHandler() { 19 | Pool.PoolObjectFactory factory = new Pool.PoolObjectFactory() { 20 | 21 | public Touch createObject() { 22 | return new Touch(); 23 | } 24 | }; 25 | touchEventPool = new Pool(factory, 100); 26 | } 27 | 28 | public boolean onTouch(View v, MotionEvent event) { 29 | //add touch events to the buffer 30 | int action = event.getAction() & MotionEvent.ACTION_MASK; 31 | int pointerIndex = event.getActionIndex(); 32 | int pointerId = event.getPointerId(pointerIndex); 33 | 34 | switch (action) { 35 | case MotionEvent.ACTION_DOWN: 36 | case MotionEvent.ACTION_POINTER_DOWN: 37 | addEvent(Touch.TOUCH_DOWN, pointerId, event.getX(pointerIndex), event.getY(pointerIndex)); 38 | break; 39 | 40 | case MotionEvent.ACTION_UP: 41 | case MotionEvent.ACTION_POINTER_UP: 42 | case MotionEvent.ACTION_CANCEL: 43 | addEvent(Touch.TOUCH_UP, pointerId, event.getX(pointerIndex), event.getY(pointerIndex)); 44 | break; 45 | 46 | case MotionEvent.ACTION_MOVE: 47 | int pointerCount = event.getPointerCount(); 48 | for (int i = 0; i < pointerCount; i++) { 49 | pointerIndex = i; 50 | pointerId = event.getPointerId(pointerIndex); 51 | addEvent(Touch.TOUCH_MOVE, pointerId, event.getX(pointerIndex), event.getY(pointerIndex)); 52 | } 53 | break; 54 | } 55 | return true; 56 | 57 | } 58 | 59 | private void addEvent(int type, int pointerId, float x, float y) { 60 | synchronized (this) { 61 | Touch touchEvent; 62 | touchEvent = touchEventPool.newObject(); 63 | touchEvent.type = type; 64 | touchEvent.pointer = pointerId; 65 | touchEvent.x = x; 66 | touchEvent.y = y; 67 | touchEventsBuffer.add(touchEvent); 68 | } 69 | } 70 | 71 | public List getTouchEvents() { 72 | synchronized (this) { 73 | int len = touchEvents.size(); 74 | for (int i = 0; i < len; i++) 75 | touchEventPool.free(touchEvents.get(i)); 76 | touchEvents.clear(); 77 | touchEvents.addAll(touchEventsBuffer); 78 | touchEventsBuffer.clear(); 79 | return touchEvents; 80 | } 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/rocket_effect.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/anaredmond/surfaceviewdemo/6de7790174bafb201165d5720336c7e45f72ca18/app/src/main/res/drawable/rocket_effect.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/star_blue.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/anaredmond/surfaceviewdemo/6de7790174bafb201165d5720336c7e45f72ca18/app/src/main/res/drawable/star_blue.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/star_green.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/anaredmond/surfaceviewdemo/6de7790174bafb201165d5720336c7e45f72ca18/app/src/main/res/drawable/star_green.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/star_orange.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/anaredmond/surfaceviewdemo/6de7790174bafb201165d5720336c7e45f72ca18/app/src/main/res/drawable/star_orange.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/star_pink.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/anaredmond/surfaceviewdemo/6de7790174bafb201165d5720336c7e45f72ca18/app/src/main/res/drawable/star_pink.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/star_purple.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/anaredmond/surfaceviewdemo/6de7790174bafb201165d5720336c7e45f72ca18/app/src/main/res/drawable/star_purple.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/star_red.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/anaredmond/surfaceviewdemo/6de7790174bafb201165d5720336c7e45f72ca18/app/src/main/res/drawable/star_red.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/star_yellow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/anaredmond/surfaceviewdemo/6de7790174bafb201165d5720336c7e45f72ca18/app/src/main/res/drawable/star_yellow.png -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 5 | 6 |