今回はHiyokoクラス、Ballクラスの説明をします。
この2つのクラスを同時に扱うのには理由があります。カジュアルゲームを作ろう!3では画面に描くためにHiyokoクラス、Ballクラス、Kagoクラスの3つ必要と説明しました。 ひよこも玉も画面上は奥行きがあるように見えます。上の方に表示されている方が奥で、下の方に表示されている方が手前です。Androidでは画面の描画をした順で上に絵を重ねてます。つまり、ひよこと玉の表示する順番は座標によって動的に変えなければなりません。
そのためHiyokoクラスもBallクラスもViewを継承していましたが中間にもう一つのViewを継承したTamaireCharacterクラスを作ります。
public class TamaireCharacter extends View {
protected double positionX,positionY,positionZ;
protected Bitmap image;
TamaireCharacter(Context context){
super(context);
this.positionZ = 0;
}
public void drawTamaireCharacter(Canvas canvas){};
}
positionX,positionYはそれぞれのX,Y座標です。positionZは仮想的な高さで表示はpositionY+positionZが実際のY座標です。
全てのキャラクタは初期状態で地面にあるのでpositionZ=0とします。
Hiyokoクラスは以下のようにしました。
<pre>public class Hiyoko extends TamaireCharacter {
public Bitmap imageHiyoko[] = new Bitmap[4];
private enum Direction{LEFT,RIGHT};
private Direction direction = Direction.LEFT;
private int ballLockOn;
private double vX,vY;
private int hiyokoCounter;
final private int HIYOKOCOUNTMAX = 20;
private int feedoutCounter;
private int rotateCounter;
Hiyoko(Context context){
super(context);
this.direction = Direction.LEFT;
this.positionX = Math.random()*80.0f + 10.0f;
this.positionY = Math.random()*25.0f + 75.0f;
this.vX = 0.0f;
this.vY = 0.0f;
this.ballLockOn = -1;
this.hiyokoCounter = HIYOKOCOUNTMAX;
this.feedoutCounter = -1;
this.rotateCounter = -1;
}
@Override
public void drawTamaireCharacter(Canvas canvas){
this.positionX+= this.vX;
this.positionY+= this.vY;
this.hiyokoCounter--;
if(this.hiyokoCounter <0 )
{
this.hiyokoCounter = HIYOKOCOUNTMAX;
}
if(this.direction == Direction.LEFT){
if(this.hiyokoCounter > HIYOKOCOUNTMAX/2){
canvas.drawBitmap(this.imageHiyoko[0], (int)(canvas.getWidth() * this.positionX /100.0f - this.imageHiyoko[0].getWidth()/2 ),
(int)(canvas.getHeight() * this.positionY/100.0f - this.imageHiyoko[0].getHeight()),null );
}else{
canvas.drawBitmap(this.imageHiyoko[1], (int)(canvas.getWidth() * this.positionX /100.0f - this.imageHiyoko[1].getWidth()/2 ),
(int)(canvas.getHeight() * this.positionY/100.0f - this.imageHiyoko[1].getHeight()),null );
}
}else{
if(this.hiyokoCounter > HIYOKOCOUNTMAX/2){
canvas.drawBitmap(this.imageHiyoko[2], (int)(canvas.getWidth() * this.positionX /100.0f - this.imageHiyoko[2].getWidth()/2 ),
(int)(canvas.getHeight() * this.positionY/100.0f - this.imageHiyoko[2].getHeight()),null );
}else{
canvas.drawBitmap(this.imageHiyoko[3], (int)(canvas.getWidth() * this.positionX /100.0f - this.imageHiyoko[3].getWidth()/2 ),
(int)(canvas.getHeight() * this.positionY/100.0f - this.imageHiyoko[3].getHeight()),null );
}
}
if(this.vX>0){
this.setDirection(1);
}else{
this.setDirection(0);
}
}
public void drawTamaireCharacter2(Canvas canvas){
Bitmap tempBitmap;
double rate;
Paint paint = new Paint();
this.hiyokoCounter--;
if(this.hiyokoCounter <0 )
{
this.hiyokoCounter = HIYOKOCOUNTMAX;
}
if(this.feedoutCounter == -1){
paint.setAlpha(255);
}else if(this.feedoutCounter >0){
paint.setAlpha(this.feedoutCounter);
this.feedoutCounter -=5;
if(this.feedoutCounter<=0){
this.feedoutCounter = 0;
}
}else{
paint.setAlpha(0);
}
rate = (double)this.imageHiyoko[0].getHeight()/(double)this.imageHiyoko[0].getWidth();
if(this.direction == Direction.LEFT){
if(this.hiyokoCounter > HIYOKOCOUNTMAX/2){
tempBitmap = Bitmap.createScaledBitmap(this.imageHiyoko[0],(int)((double)canvas.getWidth()*0.5f) ,(int)((double)canvas.getWidth()*0.5f * rate),false);
}else{
tempBitmap = Bitmap.createScaledBitmap(this.imageHiyoko[1],(int)((double)canvas.getWidth()*0.5f) ,(int)((double)canvas.getWidth()*0.5f * rate) ,false);
}
}else{
if(this.hiyokoCounter > HIYOKOCOUNTMAX/2){
tempBitmap = Bitmap.createScaledBitmap(this.imageHiyoko[2],(int)((double)canvas.getWidth()*0.5f) ,(int)((double)canvas.getWidth()*0.5f * rate) ,false);
}else{
tempBitmap = Bitmap.createScaledBitmap(this.imageHiyoko[3],(int)((double)canvas.getWidth()*0.5f) ,(int)((double)canvas.getWidth()*0.5f * rate),false);
}
}
canvas.drawBitmap(tempBitmap, (int)(canvas.getWidth() * this.positionX /100.0f - tempBitmap.getWidth()/2 ),
(int)(canvas.getHeight() * this.positionY/100.0f - tempBitmap.getHeight()),paint );
}
public void drawTamaireCharacter3(Canvas canvas){
Bitmap tempBitmap;
double rate;
Paint paint = new Paint();
double widthRate;
this.hiyokoCounter--;
if(this.hiyokoCounter <0 )
{
this.hiyokoCounter = HIYOKOCOUNTMAX;
}
if(this.feedoutCounter == -1){
paint.setAlpha(255);
}else if(this.feedoutCounter >0){
paint.setAlpha(this.feedoutCounter);
this.feedoutCounter -=5;
if(this.feedoutCounter<=0){
this.feedoutCounter = 0;
}
}else{
paint.setAlpha(0);
}
if(this.rotateCounter == -1){
widthRate = 1.0f;
}else {
this.rotateCounter -=5;
if(this.rotateCounter<=0){
this.rotateCounter = 0;
}
widthRate = Math.cos((double)this.rotateCounter/12.0);
}
rate = (double)this.imageHiyoko[0].getHeight()/(double)this.imageHiyoko[0].getWidth();
if(this.direction == Direction.LEFT){
if(this.hiyokoCounter > HIYOKOCOUNTMAX/2){
tempBitmap = Bitmap.createScaledBitmap(this.imageHiyoko[0],(int)((double)canvas.getWidth()*0.5f * widthRate ),(int)((double)canvas.getWidth()*0.5f * rate),false);
}else{
tempBitmap = Bitmap.createScaledBitmap(this.imageHiyoko[1],(int)((double)canvas.getWidth()*0.5f * widthRate) ,(int)((double)canvas.getWidth()*0.5f * rate) ,false);
}
}else{
if(this.hiyokoCounter > HIYOKOCOUNTMAX/2){
tempBitmap = Bitmap.createScaledBitmap(this.imageHiyoko[2],(int)((double)canvas.getWidth()*0.5f * widthRate) ,(int)((double)canvas.getWidth()*0.5f * rate) ,false);
}else{
tempBitmap = Bitmap.createScaledBitmap(this.imageHiyoko[3],(int)((double)canvas.getWidth()*0.5f*widthRate) ,(int)((double)canvas.getWidth()*0.5f * rate),false);
}
}
canvas.drawBitmap(tempBitmap, (int)(canvas.getWidth() * this.positionX /100.0f - tempBitmap.getWidth()/2 ),
(int)(canvas.getHeight() * this.positionY/100.0f - tempBitmap.getHeight()),paint );
}
public void setDirection(int d){
if(d==0){
this.direction = Direction.LEFT;
}else{
this.direction = Direction.RIGHT;
}
}
public int getDirection(){
if(this.direction == Direction.RIGHT){
return 1;
}else{
return 0;
}
}
public int getBallLockOn(){
return this.ballLockOn;
}
public void setBallLockOn(int target){
this.ballLockOn = target;
}
public void setVelocity(double deltaX,double deltaY){
double theta;
theta = Math.atan2(deltaY,deltaX);
this.vX = 1.0f * Math.cos(theta);
this.vY = 1.0f * Math.sin(theta);
}
public void clearVelocity()
{
this.vX = 0.0f;
this.vY = 0.0f;
}
public float calcDistance(TamaireCharacter ball){
return (float)Math.sqrt (Math.pow( (double)(ball.positionX - this.positionX) ,2)
+ Math.pow( (double)(ball.positionY - this.positionY) ,2)) ;
}
public Point getHiyokoLocation(){
Point location = new Point();
location.x = (int)this.positionX;
location.y = (int)this.positionY;
return location;
}
public void startFeedout(){
this.feedoutCounter = 255;
}
public void resetFeedout(){
this.feedoutCounter = -1;
}
public void startRotate(){
this.rotateCounter = 255;
}
public void resetRotate(){
this.rotateCounter = -1;
}
}
次にBallクラスです。
<pre>public class Ball extends TamaireCharacter {
enum BallColor{RED,WHITE};
private BallColor ballColor;
private double vX,vZ;
enum BallStatus{FIELD,MOVING,KAGO,CHATCH};
private BallStatus ballStatus;
static final private double GRAVITY = 0.25;
private boolean isOverBasket;
public BallThrow ballThrow;
static public int xJudgement1,xJudgement2,yJudgement;
Ball(Context context,BallColor color){
super(context);
Resources res = this.getContext().getResources();
this.ballColor = color;
switch(color){
case RED:
this.image = BitmapFactory.decodeResource(res,R.drawable.red_ball);
break;
case WHITE:
this.image = BitmapFactory.decodeResource(res,R.drawable.white_ball);
break;
}
this.positionX = Math.random()*90.0f + 5 ;
this.positionY = Math.random()*25.0f + 75;
this.positionZ = 0.0f;
this.vX = 0.0f;
this.vZ = 0.0f;
this.ballStatus = BallStatus.FIELD;
this.isOverBasket = false;
}
@Override
public void drawTamaireCharacter(Canvas canvas){
if(this.ballStatus != BallStatus.CHATCH) {
canvas.drawBitmap(this.image,(int)(canvas.getWidth() * this.positionX /100.0f- this.image.getWidth()/2),
(int)(canvas.getHeight() * (this.positionY + this.positionZ) /100.0f- this.image.getHeight()),null);
}
if(this.ballStatus == BallStatus.MOVING){
this.positionX += this.vX;
if(this.positionX < 2 || this.positionX>98){
this.vX = 0;
}
this.vZ += GRAVITY;
this.positionZ += this.vZ;
if(this.positionZ > 0){
this.ballStatus = BallStatus.FIELD;
this.positionZ = 0.0f;
}
if(canvas.getHeight()*(this.positionY+ this.positionZ)/100 > yJudgement
&& canvas.getWidth()* this.positionX/100 > xJudgement1
&& canvas.getWidth()* this.positionX/100 < xJudgement2
&& this.vZ >0
&& this.isOverBasket ){
this.ballStatus = BallStatus.KAGO;
this.vX = 0;
if(this.ballColor == BallColor.RED){
TamaireView.scoreRed ++;
}else{
TamaireView.scoreWhite ++;
}
}else{
isOverBasket = false;
}
if((int)((double)canvas.getHeight() * (double)(this.positionY+ this.positionZ)/100.0f) < yJudgement
&& (int)((double)canvas.getWidth()* (double)this.positionX/100.0f) > xJudgement1
&& (int)((double)canvas.getWidth()* (double)this.positionX/100.0f) < xJudgement2
&& this.vZ > 0.0f ){
this.isOverBasket = true;
}else{
this.isOverBasket = false;
}
}else if(this.ballStatus == BallStatus.KAGO){
if( canvas.getHeight() * (this.positionY+this.positionZ)/100.0f < yJudgement + Kago.imageKago.getHeight()*0.18f){
this.vZ += GRAVITY;
this.positionZ += this.vZ;
}
}
}
public void setPositionX(int _positionX) {
this.positionX = _positionX;
}
public void setPositionY(int _positionY) {
this.positionY = _positionY;
}
public BallStatus getBallStatus(){
return this.ballStatus;
}
public void setBallStatus(BallStatus bStatus){
this.ballStatus = bStatus;
}
public void setVZ(double _vZ){
this.vZ = _vZ;
}
public void setVX(double _vX){
this.vX = _vX;
}
public void throwBall(){
this.ballThrow.ballThrow(this);
}
public void initBallPosition(){
this.positionX = Math.random()*90.0f + 5 ;
this.positionY = Math.random()*25.0f + 75;
this.positionZ = 0.0f;
this.vX = 0.0f;
this.vZ = 0.0f;
this.ballStatus = BallStatus.FIELD;
this.isOverBasket = false;
}
public void initBallPositionDemoB(){
this.positionX = 1001;
this.positionY = 1001;
this.positionZ = 0.0f;
this.vX = 0.0f;
this.vZ = 0.0f;
this.ballStatus = BallStatus.FIELD;
this.isOverBasket = false;
}
}
実際の表示の仕組みは以下です。
public class TamaireView extends View {
//ひよこ2種類、玉2種類の配列を宣言
private Hiyoko hiyokoRed,hiyokoWhite;
private Ball[] ballRed;
private Ball[] ballWhite;
//表示するもの(tamaireCharacter)の配列定義 ひよこ2羽と紅白の玉各10個で合計22個 + 入れ替えのときに使う一時保管の場所1個->23個の箱を用意
private TamaireCharacter[] tamaireCharacter = new TamaireCharacter[23] ;
TamaireView(Context context){
super(context);
//ひよこと玉のインスタンス化
hiyokoRed = new Hiyoko(context);
hiyokoWhite = new Hiyoko(context);
ballRed = new Ball[10];
ballWhite = new Ball[10];
for(int i = 0;i < 10;i++){
ballRed[i] = new Ball(context,Ball.BallColor.RED);
ballWhite[i] = new Ball(context,Ball.BallColor.WHITE);
}
//tamaireCharacterとひよこ、玉の紐づけ 同じものを指すのでtamaireCharacterのインスタンス化はしない
for(int i=0;i<10;i++){
tamaireCharacter[i] = ballRed[i];
tamaireCharacter[i+10] = ballWhite[i];
}
tamaireCharacter[20] = hiyokoRed;
tamaireCharacter[21] = hiyokoWhite;
}
@Override
public void onDraw(Canvas canvas) {
sortCharacter(canvas);//各キャラクタのY座標でソーティング
//並び替えられたtaamireCharacterを表示、何番目に何が入っているかはわからない。
for( int i = 0 ; i < 22 ; i++ ){
tamaireCharacter[i].drawTamaireCharacter(canvas);
}
}
}
//Y座標の小さい順にtamaireCharacterを並び替え
public void sortCharacter(Canvas canvas){
for(int minNum = 0;minNum < 21;minNum++){
for(int compNum = minNum + 1;compNum < 22;compNum++){
if(tamaireCharacter[minNum].getViewPosition(canvas) > tamaireCharacter[compNum].getViewPosition(canvas)){
tamaireCharacter[22] = tamaireCharacter[minNum];
tamaireCharacter[minNum] = tamaireCharacter[compNum];
tamaireCharacter[compNum] = tamaireCharacter[22];
}
}
}
}
}

