버블 랜덤하게 생성해서 움직이고 클릭하면 터져서 작은 버블이 나옴
bubble
package com.example.myapplication;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.PointF;
import java.util.Random;
public class Bubble {
private int scrW, scrH;
public boolean isDead;
private Context context;
private int speed;
private PointF dir = new PointF();
private Random rnd = new Random();
private Long currentTime;
private float deltaTime;
public float x,y;
public int r;
public Bitmap bubble;
public Bubble(Context context, int width, int height){
this.context = context;
scrW = width;
scrH = height;
r = rnd.nextInt(71) + 50;
bubble = BitmapFactory.decodeResource(context.getResources(), R.drawable.bubble);
bubble = Bitmap.createScaledBitmap(bubble, r * 2, r * 2, true);
initBubble();
}
private void initBubble(){
speed = rnd.nextInt(51) + 150;
double rad = Math.toRadians(rnd.nextInt(360));
dir.x = (float) Math.cos(rad) * speed;
dir.y = (float) -Math.sin(rad) * speed;
x = rnd.nextInt(scrW - r* 4) + r * 2;
y = rnd.nextInt(scrH - r* 4) + r * 2;
currentTime = System.nanoTime();
}
public void update(){
x += dir.x * Time.deltaTime; // 이동
y += dir.y * Time.deltaTime;
//화면의 경계에서 반사
if (x < r || x > scrW - r) {
dir.x = -dir.x;
x += dir.x * Time.deltaTime;
}
if (y < r || y > scrH - r) {
dir.y = -dir.y;
y += dir.y * Time.deltaTime;
}
}
public boolean hitTest(float px, float py) {
boolean hit = false;
isDead = (x - px) * (x - px) + (y - py) * (y - py) < r * r;
float dist = (x - px) * (x - px) + (y - py) * (y - py);
if (dist < r * r){
int cnt = rnd.nextInt(6) + 25; // 25~30 (파편의 수)
for (int i = 1; i <= cnt; i++) {
GameView.mSmall.add(new SmallBubble(context, scrW, scrH, x, y));
}
isDead = true;
}
return isDead;
}
}
smallbubble
package com.example.myapplication;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.PointF;
import java.util.Random;
public class SmallBubble {
// 화면 크기
private int scrW, scrH;
// 이동 방향, 속도, 수명
private PointF dir = new PointF();
private int speed;
private float life;
// 현재 위치, 반지름
public float x, y;
public int r;
// 투명도, 소멸, 비트맵
public int alpha = 255;
public boolean isDead;
public Bitmap bubble;
public SmallBubble(Context context, int sw, int sh, float px, float py){
scrW = sw; // 화면 크기
scrH = sh;
x = px; // 초기 위치
y = py;
Random rnd = new Random();
//speed = 300;
speed = rnd.nextInt(201) + 300; // 300~500
life = (rnd.nextInt(6) + 10) / 10f; // 1~1.5초
// 이동 방향
double rad = Math.toRadians(rnd.nextInt(360));
dir.x = (float) Math.cos(rad) * speed;
dir.y = (float) -Math.sin(rad) * speed;
// 반지름, 이미지 번호
r = rnd.nextInt(11) + 10; // 10~20
int n = rnd.nextInt(6); // 이미지 번호 (0~5)
bubble = BitmapFactory.decodeResource(context.getResources(), R.drawable.b0 + n);
bubble = Bitmap.createScaledBitmap(bubble, r * 2, r * 2, true);
}
public void update() {
x += dir.x * Time.deltaTime; // 이동
y += dir.y * Time.deltaTime;
life -= Time.deltaTime;
if (life < 0) {
alpha -= 5;
if (alpha < 0) alpha = 0;
}
if (alpha == 0 || x < -r || x > scrW + r || y < -r || y > scrH + r) {
isDead = true;
}
}
}
gameview
package com.example.myapplication;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.os.Handler;
import android.os.Message;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import java.util.ArrayList;
import java.util.Random;
public class GameView extends View {
private Context context; // Context 저장용
// 배경과 화면 크기
private Bitmap imgBack;
private int w, h;
// Random. 비눗방울 저장용
private Random rnd = new Random();
private ArrayList<Bubble> mBubble = new ArrayList<Bubble>();
static public ArrayList<SmallBubble> mSmall = new ArrayList<SmallBubble>();
private Paint paint = new Paint();
public GameView(Context context, AttributeSet attrs) {
super(context, attrs);
// Context 저장
this.context = context;
}
// View의 크기가 바뀔 때마다 호출. ( e.g. View 가 만들어질때, 타이틀바가 추가
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
this.w = w;
this.h = h;
// 배경 이미지
imgBack = BitmapFactory.decodeResource(getResources(), R.drawable.sky);
imgBack = Bitmap.createScaledBitmap(imgBack, w, h, true);
mHandler.sendEmptyMessageDelayed(0, 10); // Handler 기동
}
// 화면 그리기
@Override
protected void onDraw(Canvas canvas) {
canvas.drawBitmap(imgBack, 0, 0, null);
// 비눗방울 그리기
for (Bubble tmp : mBubble) {
canvas.drawBitmap(tmp.bubble, tmp.x - tmp.r, tmp.y - tmp.r, null);
}
for (SmallBubble tmp : mSmall){
paint.setAlpha(tmp.alpha);
canvas.drawBitmap(tmp.bubble, tmp.x - tmp.r, tmp.y - tmp.r, paint);
}
}
// 비눗방울 만들기. Handler가 호출
private void makeBubble() {
if (mBubble.size() < 20 && rnd.nextInt(1000) < 8) {
mBubble.add( new Bubble(context, w, h) );
}
}
// 비눗방울 이동. Handler가 호출
private void moveBubble() {
for (Bubble tmp : mBubble) {
tmp.update();
}
}
private void removeDead() {
for (int i = mBubble.size() - 1; i >= 0; i--) {
if (mBubble.get(i).isDead) mBubble.remove(i);
}
}
private void hitTest(float x, float y) {
for (Bubble tmp : mBubble) {
if (tmp.hitTest(x, y)) break;
}
}
// Touch Event
@Override
public boolean onTouchEvent(MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_DOWN) {
hitTest(event.getX(), event.getY());
}
return true;
}
// Handler
Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
Time.update();
makeBubble();
moveBubble();
removeDead();
invalidate();
mHandler.sendEmptyMessageDelayed(0, 10);
}
};
}
time
package com.example.myapplication;
public class Time {
static private long currentTime = System.nanoTime();
static public float deltaTime;
// deltaTime 계산
static public void update() {
deltaTime = (System.nanoTime() - currentTime) / 1000000000f;
currentTime = System.nanoTime();
}
}
mainactivity
package com.example.myapplication;
import static android.graphics.BlendMode.COLOR;
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.widget.Toolbar;
import android.graphics.Color;
import android.os.Bundle;
import android.view.View;
import android.view.WindowManager;
import com.google.android.material.floatingactionbutton.FloatingActionButton;
public class MainActivity extends AppCompatActivity {
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
// getSupportActionBar().hide();
setTitle("2019026380 이찬호");
FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab);
fab.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
finish();
}
});
}
}
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<com.google.android.material.appbar.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:theme="@style/ThemeOverlay.AppCompat.Dark">
<androidx.appcompat.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="?attr/colorPrimary"
app:popupTheme="@style/Theme.AppCompat" />
</com.google.android.material.appbar.AppBarLayout>
<include layout="@layout/content_main" />
<com.google.android.material.floatingactionbutton.FloatingActionButton
android:id="@+id/fab"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|end"
android:layout_marginEnd="@dimen/fab_margin"
android:layout_marginBottom="16dp"
app:srcCompat="@android:drawable/ic_dialog_email" />
</androidx.coordinatorlayout.widget.CoordinatorLayout>
contentmain.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="@string/appbar_scrolling_view_behavior"
tools:context=".MainActivity"
tools:showIn="@layout/activity_main">
<com.example.myapplication.GameView
android:id="@+id/gameView"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
실행화면