Whack-A-Mole(もぐらたたき) 第二回
フロントエンジニアの、YAMATAKUです。
前回、ベースUIの実装まで行いました。今回は、ゲームの核である「もぐら」の実装をしていきます。
もぐらクラス作成
Mole.js
import React, { Component } from 'react';
import {
View,
StyleSheet,
Button,
Image,
TouchableWithoutFeedback
} from 'react-native';
import Images from './assets/Images';
import SpriteSheet from 'rn-sprite-sheet';
import Constants from './Constants';
export default class Mole extends Component {
constructor(props) {
super(props);
this.mole = null;
}
pop = () => {
this.isPopping = true;
this.mole.play({
type: "appear",
fps: 24,
onFinish: () => {
this.actionTimeout = setTimeout(() => {
this.mole.play({
type: "hide",
fps: 24,
onFinish: () => {
this.isPopping= false;
this.props.onFinishPopping(this.props.index);
}
})
}, 1000);
}
})
}
whack = () => {
}
render() {
return (
<View style={{flex: 1}}>
<SpriteSheet
ref={ref => (this.mole = ref)}
source={Images.sprites}
columns={6}
rows={8}
width={100}
animations={{
idle: [0],
appear: [1, 2, 3, 4],
hide: [4, 3, 2, 1, 0],
dizzy: [36, 37, 38],
faint: [42, 43, 44, 0],
attack: [11, 12, 13, 14, 15, 16],
heal: [24, 25, 26, 27, 28, 29, 30, 31, 32, 33],å
}}
/>
<TouchableWithoutFeedback onPress={this.whack} style={{ position: 'absolute', top: 0, left: 0, right: 0, bottom: 0}}>
<View style={{ position: 'absolute', top: 0, left: 0, right: 0, bottom: 0}} />
</TouchableWithoutFeedback>
</View>
)
}
}
App.js修正
App.js
/**
* Sample React Native App
* https://github.com/facebook/react-native
*
* @format
* @flow strict-local
*/
import React, { Component } from "react";
// 省略 //
import Mole from './Mole';
const DEFAULT_TIME = 20;
const DEFAULT_STATE = {
// 省略 //
}
export default class MainScreen extends Component {
constructor(props){
super(props);
this.state = DEFAULT_STATE;
this.moles = [];
this.molesPopping = 0;
this.interval = null;
this.timeInterval = null;
}
componentDidMount = () => {
//setStateで状態更新、第2引数はcallback関数
this.setState(DEFAULT_STATE, this.setupTicks);
}
setupTicks = () => {
//もぐらの更新スピード決定
let speed = 750 - (this.state.level * 50);
if (speed < 350) {
speed = 350;
}
//もぐら更新スタート
this.interval = setInterval(this.popRanndomMole, speed);
//時間カウントスタート
this.timeInterval = setInterval(this.timerTick, 1000);
}
//もぐら位置抽選
randomBetween = (min, max) => {
return Math.floor(Math.random() * (max - min + 1) + min);
}
//もぐらアクション終了で表示もぐらカウントをマイナス
onFinishPopping = (index) => {
this.molesPopping -= 1;
}
//表示するもぐら抽選して表示
popRanndomMole = () => {
//12匹の準備ができているかチェック
if (this.moles.length != 12) {
return;
}
let randomIndex = this.randomBetween(0, 11); //表示もぐら抽選
//当選したもぐら位置が非表示かつ、表示中のもぐらが3匹以下なら表示する
if (!this.moles[randomIndex].isPopping && this.molesPopping < 3) {
this.molesPopping += 1;
this.moles[randomIndex].pop();
}
}
//時間更新
timerTick = () => {
if (this.state.time === 0) {
clearInterval(this.interval);
clearInterval(this.timeInterval);
this.setState({
cleared: true
})
}
else {
this.setState({
time: this.state.time - 1
})
}
}
render() {
let healthBarWidth = (Constants.MAX_WIDTH - Constants.XR * 100 - Constants.XR * 60 - Constants.XR * 6) * this.state.health / 100;
return (
<View style={styles.container}>
<Image style={styles.backgroundImage} resizeMode="stretch" source={Images.background} />
<View style={styles.topPanel}>
<SafeAreaView >
// 省略 //
</SafeAreaView>
</View>
<View style={styles.playArea}>
{//縦に4段
Array.apply(null, Array(4)).map((el, rowIdx) => {
return (
<View style={styles.playRow} key={rowIdx}>
{//横に3列
Array.apply(null, Array(3)).map((el, colIdx) => {
let moleIdx = (rowIdx * 3) + colIdx;
return (
<View style={styles.playCell} key={colIdx}>
<Mole
index={moleIdx}
ref={(ref) => { this.moles[moleIdx] = ref }}
onFinishPopping={this.onFinishPopping}
/>
</View>
)
})}
</View>
)
})}
</View>
</View>
)
}
}
const styles = StyleSheet.create({
// 省略 //
playArea: {
width: Constants.MAX_WIDTH,
marginTop: Constants.YR * 250,
height: Constants.MAX_HEIGHT - Constants.YR * 250 - Constants.YR * 112,
flexDirection: 'column',
},
playRow: {
height: (Constants.MAX_HEIGHT - Constants.YR * 250 - Constants.YR * 112) / 4,
width: Constants.MAX_WIDTH,
flexDirection: 'row',
},
playCell: {
width: Constants.MAX_WIDTH / 3,
height: (Constants.MAX_HEIGHT - Constants.YR * 250 - Constants.YR * 112) / 4,
alignItems: 'center'
}
})
確認
$ react-native run-android
もぐらがアニメーションして現れます。
次回の記事で、もぐらを叩く機能を実装してゲーム完成させようと思います。
おまけ
今回、TEAM用に新しくGitHubアカウントを開設しましたが、自分のMacで作成した鍵が、別のGitHubと衝突したため、以下の様な設定を行いましたので、メモとして残します。
以下、Macの場合
1. 鍵作成(hogeは適宜置き換え)
$ ssh-keygen -f ~/.ssh/hoge_key
2. Gitにhoge_keyを登録
3. 設定ファイル修正
$ vi ~/.ssh/config
host github.hogehoge.com
HostName github.com
IdentityFile ~/.ssh/hoge_key
User git
TCPKeepAlive yes
IdentitiesOnly yes
//保存
:wq + Enter
//適用
$ source ~/.ssh/config
[設定完了]
・remote addの場合
$ git remote add origin git@github.hogehoge.com:******/******.git
・cloneの場合
$ git clone git@github.hogehoge.com:******/******.git
これで、複数のGitHubの設定が有効になり、リモート操作も可能になります
すいません、Windowの場合も基本は同じだと思われます。