游戏斗兽棋,童年的回忆
最近在某游戏平台上面玩了一款经典的游戏,《斗兽棋》,就是象、狮、虎、豹、狼、狗、猫、鼠八种棋子组成,分为红方和蓝方,童年时代经常玩的游戏,俗称“洋火皮”,哈哈。现在用 react-native 进行实现一下。下面是代码,代码里面有详细的注释。
import React, { Component } from 'react'
import { View, Text, TouchableOpacity, Button } from 'react-native';
import { navigationOptions } from './../../utils/navigationOptions';
import { createStackNavigator, createAppContainer } from "react-navigation";
import Utils from './../../utils/Utils';
class Game extends Component {
constructor(props){
super(props)
this.state = {
/**
* 二维数组
* 0 代表空白(没有棋子), 9 代表未翻开的棋子,
* 1 ~ 8 分别代表 红色 { 象,狮,虎,豹,狼,狗,猫,鼠 }
* 9 ~ 16 分别代表 蓝色 { 象,狮,虎,豹,狼,狗,猫,鼠 }
*/
walls: [
// [ 1, 1, 1, 1 ],
// [ 1, 1, 1, 1 ],
// [ 1, 1, 1, 1 ],
// [ 1, 1, 1, 1 ]
],
chesses: [
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16
],
map: {
1: '象',
2: '狮',
3: '虎',
4: '豹',
5: '狼',
6: '狗',
7: '猫',
8: '鼠'
},
colorMap: {}, //0 代表未翻开的棋子, 1 代表翻开的棋子
selectChess: 0, // 棋子被翻开后,再次点击被选中的棋子,0 代表都未选中,1-16 代表被选中的序号
index: -1, // 上一次选中的棋子的一维下标,-1 代表未选中,
index2: -1, // 上一次选中的棋子的二维下标,-1 代表未选中,
// currentChess: 0, // 当前可走的棋子 0 代表红色方, 1 代表蓝色方 暂时没用
// surplusChessMap: { // 剩余的棋子,双方开始各有八颗
// red: 8,
// blue: 8
// }
}
}
static navigationOptions = navigationOptions({ headerTitle: 'Game' })
componentDidMount() {
this.initWalls()
}
render() {
const { walls } = this.state
return (
<View style={{flex:1, backgroundColor: '#000'}}>
<View style={{height: '20%', justifyContent: 'space-around', alignItems: 'center'}}>
<Text style={{color: '#fff', textAlign: 'center'}}>斗兽棋</Text>
<Button title='重新开始' onPress={e => this.initWalls()}></Button>
</View>
<View style={{ flex: 1, justifyContent: 'space-around', alignItems: 'center' }}>
{ this.init(walls) }
</View>
</View>
)
}
/**
* 初始化
*/
init() {
const { chesses, walls, map, colorMap, selectChess } = this.state
return walls.map((item, index) => (
<View style={{ width: '100%', height: 100, display: 'flex', flexDirection: 'row', justifyContent: 'space-around', alignItems: 'center', backgroundColor: 'pink' }} key={'item'+index}>
{
item.map((item2,index2) => (
<View style={{width: 80, height: 80, backgroundColor: 'yellow', justifyContent: 'space-around', alignItems: 'center', ...Utils.setPadding(5)}} key={'item2'+index2}>
<TouchableOpacity onPress={e => this.touchHandle(item2,index,index2)} activeOpacity={0.7} style={{ width: selectChess == item2 ? '109%' : '90%', height: selectChess == item2 ? '108%' : '90%', backgroundColor: item2 === 0 ? 'yellow' : (colorMap[item2] ? '#adc' : '#ccc'), justifyContent: 'space-around', alignItems: 'center' }}>
<View>
<Text style={{ color: item2 <= 8 ? 'red' : 'blue', fontSize: selectChess == item2 ? 40 : 20 }}>{ colorMap[item2] ? (map[item2 <= 8 ? item2 : item2 - 8]) : '' }</Text>
</View>
</TouchableOpacity>
</View>
))
}
</View>
))
}
/**
* 初始化棋子,初始化背景颜色
*/
initWalls(){
const { chesses, walls, colorMap } = this.state
let arr = []
chesses.sort(this.randomSort)
for(let i = 0, len = chesses.length; i < len; i+=4){
arr.push(chesses.slice(i, i + 4))
}
chesses.map(item=>{
colorMap[item] = 0
})
this.setState({
walls: arr,
colorMap
})
}
/**
* 随机排序
*/
randomSort(){
return Math.random() > 0.5 ? 1 : -1
}
/**
* 点击每一项触发的函数
* @param {*} item 当前项的值
* @param {*} i1 当前项的一维下标
* @param {*} i2 当前项的二维下表
*/
touchHandle(item, i1, i2) {
const { colorMap, selectChess, walls, index, index2 } = this.state
// 如果当前未选中任何棋子,纯粹的点击空白处,直接返回
if(item === 0 && index === -1) return;
if(colorMap[item] == 1 || item === 0){ // 判断是否是已经被翻开的棋子或者空白格
if(selectChess == item){
this.setState({
selectChess: 0,
index: -1,
index2: -1
})
}else if(selectChess == 0){
this.setState({
selectChess: item,
index: i1,
index2: i2
})
}else{
let pre1 = walls[index][index2]
let now1 = walls[i1][i2]
// 判断是否是同类型棋子
let isSameType = ((pre1 > 8 && now1 > 8) || (pre1 <= 8 && now1 <= 8)) && !(pre1 === 0 || now1 === 0)
if(isSameType){
this.setState({
selectChess: item
})
return
}
// 判断两次点击是否是在同一行或者同一列
if(i1 === index || i2 === index2){
const diff = i1 === index ? i2 - index2 : i1 - index
// 判断两次点击是否相邻
if(Math.abs(diff) === 1){
let arr = JSON.parse(JSON.stringify(walls))
let pre = walls[index][index2] > 8 ? walls[index][index2] - 8 : walls[index][index2]
let now = walls[i1][i2] > 8 ? walls[i1][i2] - 8 : walls[i1][i2]
if(now === 0){ // 如果当前值为0,那么上一个值直接与当前值交换位置
arr[index][index2] = walls[i1][i2]
arr[i1][i2] = walls[index][index2]
this.setState({
walls: arr,
selectChess: 0
})
}else{
// 如果上一个值大于当前值,那么保留当前值,当前值位置不变,上一个值变为0
if(pre > now){
if(pre1 === 8 && now1 === 9 || (pre1 === 16 && now1 === 1)){ // 如果第一次点击的是老鼠,第二次点击的是大象,那么保留老鼠pre1,并将第二次位置设置为0
arr[i1][i2] = walls[index][index2]
arr[index][index2] = 0
}else{
arr[index][index2] = 0
}
}else if(pre === now){ // 如果两者相等,那么两者都设置为0
arr[index][index2] = 0
arr[i1][i2] = 0
}else{ // 如果当前值大于上一个值,那么保留上一个值,将当前值的位置设置为上一个值,并将上一个值的位置设置为0
if(pre1 === 1 && now1 === 16 || (pre1 === 9 && now1 === 8)){ // 如果第一次点击的是大象,第二次点击的是老鼠,那么保留老鼠now1,并将第一次位置设置为0
arr[index][index2] = 0
}else{
arr[index][index2] = 0
arr[i1][i2] = walls[index][index2]
}
}
this.setState({
walls: arr,
selectChess: 0
})
}
}
}
}
}else{
this.setState({
colorMap: { ...colorMap, [item]: 1 },
selectChess: 0
})
}
}
}
const AppNavigator = createStackNavigator(
{
Game:{screen:Game}
},
{
initialRouteName:"Game"
}
);
export default createAppContainer(AppNavigator)
样式就不在此贴了,因为没有美化,比较难看,只是实现了功能,而且没有进行输赢判定。后期有时间再补充吧。使用的方法可能比较绕。