I'm making a card game and I have a parent component which holds all my methods. The methods are my "logic" and it determines how to set the randomly generated hand according to 'house-way'. Think of house-way as a set of rules on how to play a certain hand.
I'm having a problem with how to structure my components. I've heard that you should keep your components small and my component is already 300 lines long.
Any advice on how to restructure this? I've tried putting methods on a different file and importing them, but I had trouble when it comes to setting state. In other words, 'this.setState()' throws an error unless it is a method of a class.
the code is a mess, but I basically need help with how to make my component less bloated.
export default class Layout extends Component {
constructor(props) {
console.log("starting up");
super(props);
//each hand holds a randomly generated tile object from { tilesSet }
this.state = {
//needs empty spots for when (mounting) <Hands hand1={this.state.hand[0].img} /> else error since hand[0] doesnt exist.
hand: ["", "", "", ""],
cards: false,
pairName: '',
rule: '',
show: false,
history: [],
test: 'test'
};
//binding in the constructor is recommended for performance.
this.handleToggle = this.handleToggle.bind(this);
this.handleClick = this.handleClick.bind(this);
this.handleHW = this.handleHW.bind(this);
this.assignHands = this.assignHands.bind(this);
this.checkPair = this.checkPair.bind(this);
this.checkTeenDey = this.checkTeenDey.bind(this);
this.hiLowMiddle = this.hiLowMiddle.bind(this);
this.compare = this.compare.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
}
//n = pairTL, n2 = otherTL
split(n, n2){
//Gee Joon
if (n[0].pair === 1) {
let combo1 = baccaratCount(n2[0], n[0]);
let combo2 = baccaratCount(n2[1], n[1]);
//if it meets the split requirements...
if((combo1 >= 7 && combo2 >= 9) || (combo1 >= 9 && combo2 >= 7)){
console.log('got em', combo1, combo2);
return true;
}
else {
return true;
}
//Teen/Dey
// } else if(high[0].val === 2) {
// var combo1 = baccaratCount(high[0].val, low[0].val);
// var combo2 = baccaratCount(high[0].val, low[1].val);
// //checks if any of the tiles are 7,8, or 9. for 9 gong and wong.
// var check7_9 = low[0].val >= 7 && low[0].val <= 9;
// var check7_9_2 = low[1].val >= 7 && low[1].val <= 9;
// //regular 6-8 split rule.
// if((combo1 >= 6 && combo2 >= 8) || (combo1 >= 8 && combo2 >= 6)){
// moveTiles("split");
// return true;
// //we might have 7,8,9 with T/D. (with 8 and 9, it turns to 0 and 1, so we need this part.)
// } else if (check7_9 === true || check7_9_2 === true){
// //if both are 7,8, or 9
// if (check7_9 === check7_9_2){
// moveTiles("split");
// return true;
// //only if 1..
// } else if (check7_9 === true && check7_9_2 === false){
// if (low[1].val >= 3 && low[1].val <=6){
// moveTiles("split");
// return true;
// } else {
// moveTiles();
// return true;
// }
// //if other one...
// } else{
// if (low[0].val >= 3 && low[0].val <=6){
// moveTiles("split");
// return true;
// } else {
// moveTiles();
// return true;
// }
// }
// //does not split.
// } else {
// moveTiles();
// return;
// }
// } else {
// // all other pairs. split pairs are in one array with a length of 2. ex: [7, 9]
// var combo1 = baccaratCount(high[0].val, low[0].val);
// var combo2 = baccaratCount(high[0].val, low[1].val);
// if(combo1 >= high[0].split[0] && combo2 >= high[0].split[0]){
// moveTiles("split");
// } else {
// moveTiles();
// }
// return true;
// }
}
}
//checks for pairs. takes an array as arg
checkPair(hand){
for(let i = 0; i < hand.length; i++) {
for (let ii = 0; ii < hand.length; ii++) {
// if there is a pair and it is not comparing to itself.
if (hand[i].pair === hand[ii].pair && i !== ii) {
let pairTL = hand.filter((x) => x.rank === hand[i].rank); //array of the pair tiles
let otherTL = hand.filter((x) => x.rank !== hand[i].rank); // array of the other 2 tiles. use these two to move tiles accordingly
//if we split this pair...
if (hand[i].split !== false) {
//returns true if it split..
if(this.split(pairTL, otherTL)) {
let copyArr = [pairTL[0], otherTL[0], pairTL[1], otherTL[1]];
this.setState(() => ({hand: copyArr}));
}
else {
let copyArr = otherTL.concat(pairTL);
this.setState(() => ({hand: copyArr}));
return true;
}
}
//don't split
else {
let copyArr = otherTL.concat(pairTL); //concats the two small arrays together and renders.
this.setState(() => ({hand: copyArr, pairName: pairTL[0].name, rule: 'Don\'t Split'}))
return true;
}
}
}
}
return false; // no pairs
}
//will not execute if there is a pair...(checkPair returns true)
checkTeenDey(hand){
//true if we have teen or dey
let teenDey = hand.find((el) => el.val === 2) !== undefined;
//if true...
if(teenDey){
let tile = hand.find((el) => el.val === 2); // teen/ dey object
let tempArr = hand.filter((el) => el.name !== tile.name); //new arr without marked teen/dey. arr.length = 3
let secondTeenDey = tempArr.find((el) => el.val === 2); //second teen/dey (not pair)
let seven = tempArr.find((el) => el.val === 7);
let eight = tempArr.find((el) => el.val === 8);
let nine = tempArr.find((el) => el.val === 9);
//if there is a second teen/dey
if (secondTeenDey){
let twoArr = tempArr.filter((el) => el.name !== secondTeenDey.name);
console.log(tile, secondTeenDey, twoArr);
return true;
}
//look for 7,8,9
else if (seven){
console.log (seven);
return true;
}
else if(eight){
return true;
}
else if(nine){
return true;
}
}
// no teen or dey...
else{
return false;
}
}
//point system used for sort()
compare(a,b){
let comparison = 0;//no change
if(a.realValue < b.realValue){
comparison = -1;//a comes before b
}
else if(a.realValue > b.realValue){
comparison = 1;//b comes before a
}
return comparison;
}
//will not execute if there is a teen dey...
hiLowMiddle(hand){
//makes a new copy of hand and sorts it using sort()'s point system.
let sortedArr = hand.slice().sort(this.compare); //slice used, else mutates hand.
let tempHair = [sortedArr[0], sortedArr[3]];
let tempBack = [sortedArr[1], sortedArr[2]];
let hiLow = tempHair.concat(tempBack); //newly sorted arr
this.setState(() => ({hand: hiLow, rule: 'Hi-Low-Middle'}));
}
//generates new hand and updates them to state.
assignHands() {
let tempArr = [0, 0, 0, 0]; //filler array
let testArr = tilesSet.slice(); //filler array. tilesSet is untouched
//loops through and assigns random tile from deck
let newArr = tempArr.map((x) => {
let counter = Math.floor(Math.random()* (testArr.length - 1));
//used to hold the selected obj. needed since splice changes arr.length and we splice/display the different indexes.
let dummyArr = testArr[counter];
testArr.splice(counter, 1);
return dummyArr;
})
//updates state
this.setState({hand: [newArr[0], newArr[1], newArr[2], newArr[3]], show: true, history: [...this.state.history, [...newArr]]})
}
handleSubmit = (e) => {
e.preventDefault();
}
//toggle effect.
handleToggle = () => {
this.setState(() => ({cards: !this.state.cards}));
}
handleClick = () => {
assignHands(tilesSet);
//works, but not 100% properly. the changes are one step behind. fix async.
//check to see the history length. max set # 20
if(this.state.history.length >= 10){
let temp = this.state.history.slice();
temp.shift();
this.setState(() => ({history: temp}))
}
}
//House Way
handleHW(){
if(!this.checkPair(this.state.hand)){
if(!this.checkTeenDey(this.state.hand)){
this.hiLowMiddle(this.state.hand);
}
}
}
render() {
return (
<div>
{this.state.show ? <h1>{baccaratCount(this.state.hand[0], this.state.hand[1]) + '/' + baccaratCount(this.state.hand[2], this.state.hand[3])}</h1> : <h1>Press New Hand to Start</h1>}
<form onSubmit={this.handleSubmit}>
<label>
<input type='text'/>
</label>
<button>submit</button>
</form>
<Input test={this.state.test}/>
<Hands
cards={this.state.cards}
hand1={this.state.hand[0].img}
hand2={this.state.hand[1].img}
hand3={this.state.hand[2].img}
hand4={this.state.hand[3].img}
/>
<Buttons
type="button"
className="btn btn-dark"
handleClick={this.handleClick}
handleHW={this.handleHW}
hand={this.state.hand}
/>
<h2>Value of tiles: {this.state.hand[0].val ? this.state.hand[0].val : "0"} - {this.state.hand[1].val ? this.state.hand[1].val : "0"} - {this.state.hand[2].val ? this.state.hand[2].val : "0"} - {this.state.hand[3].val ? this.state.hand[3].val : "0"}</h2>
<h2>Pair Name: {this.state.pairName}</h2>
<h2>Rule: {this.state.rule}</h2>
<h2>
History: <div>{this.state.history.map((el) => <li key={Math.random()}>{el.map((ele) => ele.name+ '--')}</li>)}</div>
</h2>
</div>
);
}
}
Related
I have two drawer components and inside those drawer user can select maximum 3 rows. Each row has a Accessory Qty property which cannot be greater than Max Qty.
Two Drawers, each with clickHandler which triggers inner row sections
Each row has Accessory Qty and Max Qty. as mentioned above.
Selecting all the rows and clicking Associate to all which adds the selected rows in the other drawers. You can see in the breadcrumbs that currently I'm in SET F. Now after going back to Image one, when I click the 2nd drawer which is SET H I can see that the selected Items are added here.
Now if I change any value in any of the rows of SET H the same change is reflected in the SET F
This is the whole problem, I want the changes not to reflect in other drawers.
For this data is getting fetched from the API. I'm setting a copy of the data in the backupdata. Then with the index and values I'm changing the values in the corresponding rows.
handleQtyChange
const handleQtyChange = (event, i) => {
console.log("Set Index QTY", index, i);
const backupdata = [...billOfMaterials];
var data = event.target.value;
if (backupdata[index].accessory_details[i].accessory[0].code !== "") {
var accesory_code =
backupdata[index].accessory_details[i].accessory[0].code;
var max_qty = backupdata[index].accessory_details[i].max_qty;
var updated_qty = event.target.value;
if (parseFloat(updated_qty) > parseFloat(max_qty)) {
setMessageDialog({
isOpen: true,
message: "Qty must be less than or equal to Max qty",
severity: "error",
});
} else {
if (data == "" || (!isNaN(+data) && parseFloat(data) >= 0)) {
console.log("AccessoryChildIndex", i);
console.log("Max qty", accessoryListWithMaxQty);
console.log("Set Index", index);
setMessageDialog({
isOpen: false,
message: "",
severity: "error",
});
var accessory_total_qty_index = backupdata[
index
].accessory_total_qty.findIndex(
(x) =>
x.code == backupdata[index].accessory_details[i].accessory[0].code
);
console.log("accessory_total_qty Index", accessory_total_qty_index);
backupdata[index].accessory_total_qty[accessory_total_qty_index].qty =
updated_qty;
backupdata[index].accessory_details[i].accessory_qty = updated_qty;
backupdata[index].accessory_details[i].total = (
parseFloat(
event.target.value == undefined || event.target.value == ""
? 0
: event.target.value
) * parseFloat(backupdata[index].accessory_details[i].rate)
).toFixed(2);
backupdata[index].grand_total = grandTotal();
setBillOfMaterials(backupdata);
if (!checkBomAccessoryWiseTotalQty(accesory_code, max_qty)) {
setMessageDialog({
isOpen: true,
message: "Qty limit exceed max qty would be " + max_qty,
severity: "error",
});
backupdata[index].accessory_total_qty[
accessory_total_qty_index
].qty = 0;
backupdata[index].accessory_details[i].accessory_qty = 0;
backupdata[index].accessory_details[i].total = 0;
backupdata[index].grand_total = grandTotal();
setBillOfMaterials(backupdata);
}
console.log("Change BOM", billOfMaterials);
}
}
}
};
handleAssociateToAll
const handleAssociateToAll = () => {
//var data = [...billOfMaterials];
var backupdata = [...billOfMaterials];
//var backupdata = JSON.parse(JSON.stringify([...billOfMaterials]));
var selectedData = backupdata[index].accessory_details.filter((el) => {
return el.is_selected == true;
});
console.log(selectedData);
console.log(index);
backupdata.map((el, i) => {
if (index != i) {
console.log(selectedData);
selectedData.map((dt) => {
dt.accessory_qty = "0";
dt.is_selected = false;
let checkAccessory = backupdata[i].accessory_details.find((data) => {
return (
data.accessory[0].code != "" &&
data.accessory[0].code == dt.accessory[0].code
);
});
console.log("Check", checkAccessory);
if (checkAccessory == undefined) {
backupdata[i].accessory_details = [
dt,
...backupdata[i].accessory_details,
];
}
});
backupdata[index].accessory_total_qty &&
backupdata[index].accessory_total_qty.map((qty) => {
qty.qty = "0";
let checkTotalQty = backupdata[i].accessory_total_qty.find(
(data) => {
return data.code == qty.code;
}
);
if (checkTotalQty == undefined) {
backupdata[i].accessory_total_qty = [
...backupdata[i].accessory_total_qty,
qty,
];
}
});
}
});
setBillOfMaterials(backupdata);
checkAllSelected();
};
console.log("bill", billOfMaterials);
I guess I've explained well. So how do I keep the other drawer's data unchanged and change only the selected drawers rows.
The api response
After clicking Associate to all:
The overall bill, the selected rows are added in accessory_total_qty:
This question already has an answer here:
Discord.js v12 code breaks when upgrading to v13
(1 answer)
Closed 1 year ago.
So basically I had this blackjack command that worked fine with v12 discord.js but as soon as I updated to discord v13. Bugs starting to appear like:
node:5932) DeprecationWarning: The message event is deprecated. Use messageCreate instead
(Use node --trace-deprecation ... to show where the warning was created)
(Only error showing up)
So I made some research and figured out that what happens to embed, but this command does not content an embed.. I came here to ask help. I would appreciate it :)
Blackjack.js
const { stripIndents } = require('common-tags');
const { shuffle, verify } = require('../../functions');
const db = require('quick.db');
const suits = ['♣', '♥', '♦', '♠'];
const faces = ['Jack', 'Queen', 'King'];
const hitWords = ['hit', 'hit me'];
const standWords = ['stand'];
module.exports = {
config: {
name: 'blackjack',
aliases: ['bj'],
category: 'games',
usage: '[deck] <bet>',
description: 'Play A Game Of Blackjack!',
accessableby: 'everyone'
},
run: async (bot, message, args, ops) => {
if (!args[0]) return message.channel.send('**Please Enter Your Deck Amount!**')
let deckCount = parseInt(args[0])
if (isNaN(args[0])) return message.channel.send('**Please Enter A Number!**')
if (deckCount <= 0 || deckCount >= 9) return message.channel.send("**Please Enter A Number Between 1 - 8!**")
let user = message.author;
let bal = db.fetch(`money_${user.id}`)
if (!bal === null) bal = 0;
if (!args[1]) return message.channel.send("**Please Enter Your Bet!**")
let amount = parseInt(args[1])
if (isNaN(args[1])) return message.channel.send("**Please Enter A Number**")
if (amount > 10000) return message.channel.send("**Cannot Place Bet More Than \`10000\`**")
if (bal < amount) return message.channel.send("**You Are Betting More Than You Have!**")
const current = ops.games.get(message.channel.id);
if (current) return message.channel.send(`**Please Wait Until The Current Game Of \`${current.name}\` Is Finished!**`);
try {
ops.games.set(message.channel.id, { name: 'blackjack', data: generateDeck(deckCount) });
const dealerHand = [];
draw(message.channel, dealerHand);
draw(message.channel, dealerHand);
const playerHand = [];
draw(message.channel, playerHand);
draw(message.channel, playerHand);
const dealerInitialTotal = calculate(dealerHand);
const playerInitialTotal = calculate(playerHand);
if (dealerInitialTotal === 21 && playerInitialTotal === 21) {
ops.games.delete(message.channel.id);
return message.channel.send('**Both Of You Just Hit Blackjack!**');
} else if (dealerInitialTotal === 21) {
ops.games.delete(message.channel.id);
db.subtract(`money_${user.id}`, amount);
return message.channel.send(`**The Dealer Hit Blackjack Right Away!\nNew Balance - **\` ${bal - amount}\``);
} else if (playerInitialTotal === 21) {
ops.games.delete(message.channel.id);
db.add(`money_${user.id}`, amount)
return message.channel.send(`**You Hit Blackjack Right Away!\nNew Balance -**\`${bal + amount}\``);
}
let playerTurn = true;
let win = false;
let reason;
while (!win) {
if (playerTurn) {
await message.channel.send(stripIndents`
**First Dealer Card -** ${dealerHand[0].display}
**You [${calculate(playerHand)}] -**
**${playerHand.map(card => card.display).join('\n')}**
\`[Hit / Stand]\`
`);
const hit = await verify(message.channel, message.author, { extraYes: hitWords, extraNo: standWords });
if (hit) {
const card = draw(message.channel, playerHand);
const total = calculate(playerHand);
if (total > 21) {
reason = `You Drew ${card.display}, Total Of ${total}! Bust`;
break;
} else if (total === 21) {
reason = `You Drew ${card.display} And Hit 21!`;
win = true;
}
} else {
const dealerTotal = calculate(dealerHand);
await message.channel.send(`**Second Dealer Card Is ${dealerHand[1].display}, Total Of ${dealerTotal}!**`);
playerTurn = false;
}
} else {
const inital = calculate(dealerHand);
let card;
if (inital < 17) card = draw(message.channel, dealerHand);
const total = calculate(dealerHand);
if (total > 21) {
reason = `Dealer Drew ${card.display}, Total Of ${total}! Dealer Bust`;
win = true;
} else if (total >= 17) {
const playerTotal = calculate(playerHand);
if (total === playerTotal) {
reason = `${card ? `Dealer Drew ${card.display}, Making It ` : ''}${playerTotal}-${total}`;
break;
} else if (total > playerTotal) {
reason = `${card ? `Dealer Drew ${card.display}, Making It ` : ''}${playerTotal}-\`${total}\``;
break;
} else {
reason = `${card ? `Dealer Drew ${card.display}, Making It ` : ''}\`${playerTotal}\`-${total}`;
win = true;
}
} else {
await message.channel.send(`**Dealer Drew ${card.display}, Total Of ${total}!**`);
}
}
}
db.add(`games_${user.id}`, 1)
ops.games.delete(message.channel.id);
if (win) {
db.add(`money_${user.id}`, amount);
return message.channel.send(`**${reason}, You Won ${amount}!**`);
} else {
db.subtract(`money_${user.id}`, amount);
return message.channel.send(`**${reason}, You Lost ${amount}!**`);
}
} catch (err) {
ops.games.delete(message.channel.id);
throw err;
}
function generateDeck(deckCount) {
const deck = [];
for (let i = 0; i < deckCount; i++) {
for (const suit of suits) {
deck.push({
value: 11,
display: `${suit} Ace!`
});
for (let j = 2; j <= 10; j++) {
deck.push({
value: j,
display: `${suit} ${j}`
});
}
for (const face of faces) {
deck.push({
value: 10,
display: `${suit} ${face}`
});
}
}
}
return shuffle(deck);
}
function draw(channel, hand) {
const deck = ops.games.get(channel.id).data;
const card = deck[0];
deck.shift();
hand.push(card);
return card;
}
function calculate(hand) {
return hand.sort((a, b) => a.value - b.value).reduce((a, b) => {
let { value } = b;
if (value === 11 && a + value > 21) value = 1;
return a + value;
}, 0);
}
}
};
Event Handler:
const { readdirSync } = require("fs")
module.exports = (bot) => {
const load = dirs => {
const events = readdirSync(`./events/${dirs}/`).filter(d => d.endsWith('.js'));
for (let file of events) {
const evt = require(`../events/${dirs}/${file}`);
let eName = file.split('.')[0];
bot.on(eName, evt.bind(null, bot));
};
};
["client", "guild"].forEach(x => load(x));
};
message is an event. you have an event handler, which fires, when a message event is triggered by a user. (they send a message).
What this error is saying is that the message event is deprecated. messageCreate (or messageUpdate) are the new events, and your event handlers need to use that syntax to address the message events (accordingly to creation or update).
I've written the code below (please be noted that some unrelated functions have been removed).
I'm trying to make a Player-vs-Computer TicTacToe game. But every time I try to run the code on Android Studio, Uncaught error: Maximum call stack size exceeded will be shown, specifically when it's Computer's turn to make a move. I think the error is in the onTilePress function, but I'm not sure how to solve it. Does anyone have an idea what is wrong there? Any suggestion will be much appreciated. Thank you in advance.
/* eslint-disable prettier/prettier */
...
export default class TicTacToe2 extends React.Component {
constructor(props){
super(props);
this.state = {
gameState: [
[0, 0, 0],
[0, 0, 0],
[0, 0, 0]
] ,
currentPlayer: 1,
}
//tilesSelected : 0;
}
componentDidMount(){ //To start the first render... I guess
this.initializeGame();
}
//Reset the gameboard
initializeGame = () => {
this.setState({gameState:
[
[0, 0, 0],
[0, 0, 0],
[0, 0, 0]
],
currentPlayer: 1,
});
}
checkTie = () => {
...
}
//To check if the tile selected is owned
checkTilesOwner = (row, col) => {
var arr = this.state.gameState;
if (arr[row][col] == 1){ //Tile owned by Player 1
//Alert.alert("Owned by player 1!"); //remove comment for trial-and-error
this.BotMove();
}
else if (arr[row][col] == -1) { //Tile owned by Bot
//Alert.alert("Owned by Bot!"); //remove comment for trial-and-error
this.BotMove();
}
else { //Empty tile
this.onTilePress(row, col); //Select the tile
}
}
//Return 1 if player 1 won, -1 if player 2 / bot won, or 0 if no one has won
getWinner = () => {
...
}
BotMove = () => {
var RandRow = Math.floor(Math.random() * 3) + 0; //Generate random number for Row
var RandCol = Math.floor(Math.random() * 3) + 0; //Generate random number for Col
this.checkTilesOwner(RandRow, RandCol);
}
onTilePress = (row, col) => {
//Dont allow tiles to change
var value = this.state.gameState[row][col];
if (value !== 0) { return;}
//Identify and grab current player
var currentPlayer = this.state.currentPlayer;
//Set the correct tile...
var arr = this.state.gameState.slice();
arr[row][col] = currentPlayer;
this.setState({gameState: arr});
//Switch to other player
var nextPlayer = (currentPlayer == 1) ? -1 : 1; //if yes, then change to -1; else, then change to 1
this.setState({currentPlayer: nextPlayer});
//Alert.alert(nextPlayer);
//Check if the match is tie
var checkDraw = this.checkTie();
//check winner
var winner = this.getWinner(); //get the winner update
if (winner == 1) {
Alert.alert("Player 1 has won!");
this.initializeGame();
}
else if (winner == -1){
Alert.alert("Bot has won!");
this.initializeGame();
}
else if (checkDraw == 9){
Alert.alert("It's a draw!");
this.initializeGame();
}
//Identify the current player: 1 is human, -1 is bot
var takePlayer = '' + nextPlayer;
if (takePlayer == 1) {
Alert.alert("Player 1's turn!");
}
else if (takePlayer == -1) { //If it is Bot's turn to nmake a move, then trigger BotMove
Alert.alert("Bot's turn!");
this.BotMove(); //Uncaught error: Maximum call stack size exceeded //possible cause: endless loop
}
}
onNewGamePress = () => {
this.initializeGame();
}
renderIcon = (row, col) => {
var value = this.state.gameState[row][col];
switch(value) {
case 1:
return <TouchableOpacity><Text style={styles.tileX}>X</Text></TouchableOpacity>;
case -1:
return <TouchableOpacity><Text style={styles.tileO}>O</Text></TouchableOpacity>;
default:
return <View />
}
}
render() {
return (
//Container for Gameboard
...
);
}
}
Yes, your BotMove and checkTilesOwner are circular.
Try to simplify your logic into
onTilePress(...) {
// think what needs to be done
// get only stuff you need without moving it
this.BotMove(...)
}
Don't blend the thinking code (logic) with the action itself. Because otherwise you will end up with lots of this.setState call. Not only this could cause lots of circular problem, but only it won't help you understand your business logic, in your case, your game logic :)
Separate your logic from your rendering.
I have this redux reducer case, which has multiple conditions to work with. I am getting issue in changing value of state properties.
//code explaination:
In the second condition I am checking if action.hoverIndex > action.dragIndex, and if the condition is true then it creates "td" variable to hold the new state. After state change I have to make some changes in the properties of the state.
In the else part of the 2nd condition when I change the properties of "td" by assigning new value in for loop, it works as expected, but same thing when I try in "nestedConditionHandler" it does not work. not sure what is causing this issue.
const cmdArray = [
"ECommand",
"BCommand",
"CCommand",
"DCommand",
];
const cmdPair = {
ECommand: "EndE",
BCommand: "EndB",
CCommand: "EndC",
DCommand: "EndD",
};
const notFirstCommand = [
"PCommand",
"QCommand",
"XCommand"
];
case actionTypes.UPDATE_COMMAND_WORKFLOW:
// Deep clone of current state
const temp = cloneDeep(state);
// Draged command state
const dragCard = temp[action.dragIndex];
const tempDragCard = cloneDeep(dragCard);
// hovered command state
const hoverCard = temp[action.hoverIndex];
const tempHoverCard = cloneDeep(hoverCard);
//condition one
if (
action.hoverIndex === 0 &&
notFirstCommand.includes(dragCard.class_name)
) {
return temp;
}
//condition 2
// command drag from top to bottom
if (action.hoverIndex > action.dragIndex) {
const td = update(temp, {
$splice: [
[action.dragIndex, 1],
[action.hoverIndex, 0, tempDragCard],
],
});
let startIndex;
let endconditionIndex;
// for nested commands
const nestedConditionHandler = (i, currState) => {
startIndex = i + 1;
endconditionIndex = td.indexOf(
td.find((cur) => cmdPair[currState.class_name] === cur.class_name)
);
while (startIndex < endconditionIndex) {
const tempTd = td[startIndex];
console.log(tempTd);
console.log(currState.indent + 1);
td[startIndex].indent = currState.indent +1
td[startIndex].parentId = currState.parentId
if (cmdArray.includes(td[startIndex].class_name)) {
nestedConditionHandler(startIndex, td[startIndex]);
}
startIndex += 1;
}
};
if (
dragCard.class_name === "ECommand" ||
dragCard.class_name === "EfCommand"
) {
for (let i = action.dragIndex; i < action.hoverIndex; i++) {
td[i].indent = dragCard.indent + 1;
td[i].parentId = dragCard.parentId;
}
} else {
for (let i = action.dragIndex; i < action.hoverIndex; i++) {
td[i].indent = dragCard.indent;
td[i].parentId = dragCard.parentId;
if (cmdArray.includes(td[i].class_name)) {
nestedConditionHandler(i, td[i]);
}
}
}
return td;
}
// command drag from bottom to top , next condition
I have a bad problem to solve in an application react-based written with typescript that should manage 3D shapes.
The problem is that the reflections don't look good at all. I tried everything I can to better the code but nothing was successful.
The workflow is to create a material holder in a blender, export it and to apply to an empty shape imported from another gltf.
For all the materials I tried (paper, with normal map structure) everything works fine.
with simple paper material
In case the material is reflective (roughness 0.2 and metalness 0.8) this is the result:
with reflective material
As you can see the portion of the environment reflected is dramatically wrong if you think that the cube is a placeholder so done:
one of the six images of the cube map
The code is very simple, here I create the cube Map:
const loader = new THREE.CubeTextureLoader();
const path = `${this.props.baseUrl}backgrounds/${background.value}`;
const ext = background.value === "test" ? "jpg" : "png";
const bkcg = [
`${path}/py.${ext}`,
`${path}/nz.${ext}`,
`${path}/px.${ext}`,
`${path}/ny.${ext}`,
`${path}/pz.${ext}`,
`${path}/nx.${ext}`,
];
// const loader = new THREE.TextureLoader();
// const bkcg = `${this.props.baseUrl}backgrounds/test_texture.jpg`;
loader.load(bkcg, async (t) => {
t.minFilter = THREE.LinearFilter;
t.magFilter = THREE.LinearFilter;
t.encoding = THREE.sRGBEncoding;
t.format = THREE.RGBFormat;
this.setState({
background: t,
bckgLoaded: true,
});
Here I assign the material to the different meshes:
public editMeshes = (
item: THREE.Mesh,
isOrderPage: boolean,
design: IDesign,
materials: {[name: string]: THREE.MeshStandardMaterial | string},
textures: ITextures,
renderer: THREE.WebGLRenderer,
scene: THREE.Scene,
) => {
if (item.name === "Ground" || item.name === "X_Ground_Freigabe") {
const color = isOrderPage ? new THREE.Color("#ffffff") : new THREE.Color("#aaaaaa"); // #8f8f8f
const groundMaterial = new THREE.MeshBasicMaterial({ color });
item.material = groundMaterial;
} else {
item.scale.x = item.scale.x + 0;
item.scale.y = item.scale.y + 0;
item.scale.z = item.scale.z + 0;
if (Object.keys(design).indexOf(item.name) !== -1 || Object.keys(materials).indexOf(item.name) !== -1) {
if (Object.keys(design).indexOf(item.name) === -1 && Object.keys(materials).indexOf(item.name) !== -1) {
if (item.material instanceof THREE.MeshStandardMaterial) {
item.material.color = new THREE.Color(`${materials[item.name]}`);
}
} else {
if (typeof(materials[item.name]) !== "string") {
item.material = materials[item.name] as THREE.MeshStandardMaterial;
if (item.material instanceof THREE.MeshStandardMaterial) {
if (shinyMaterials.indexOf((item.material as THREE.MeshStandardMaterial).name) !== -1) {
this.createCubeCamera(item, textures, scene, renderer);
item.material.needsUpdate = true;
} else {
(item.material as THREE.MeshStandardMaterial).map = textures ? textures[item.name] :
(item.material as THREE.MeshStandardMaterial).map;
(item.material as THREE.MeshStandardMaterial).envMapIntensity = 4;
(item.material as THREE.MeshStandardMaterial).needsUpdate = true;
item.material.flatShading = false;
}
}
}
}
} else {
if (shinyMaterials.indexOf((item.material as THREE.MeshStandardMaterial).name) !== -1) {
this.createCubeCamera(item, textures, scene, renderer);
}
}
}
}
}
here I create the camera for the reflections:
public createCubeCamera = (
item: THREE.Mesh,
textures: ITextures,
scene: THREE.Scene,
renderer: THREE.WebGLRenderer) => {
const cubeCamera = new THREE.CubeCamera(0.001, 10000, 2048);
scene.add(cubeCamera);
cubeCamera.name = `cubeCamera_${item.name}`;
cubeCamera.position.set(item.position.x, item.position.y, item.position.z);
item.visible = false;
cubeCamera.update(renderer, scene);
item.visible = true;
const renderCamera = cubeCamera.renderTarget.texture as THREE.CubeTexture; // scene.background as THREE.CubeTexture
(item.material as THREE.MeshStandardMaterial).map =
textures ? textures[item.name] : (item.material as THREE.MeshStandardMaterial).map;
(item.material as THREE.MeshStandardMaterial).envMap = renderCamera;
(item.material as THREE.MeshStandardMaterial).envMapIntensity = 1;
(item.material as THREE.MeshStandardMaterial).flatShading = false;
(item.material as THREE.MeshStandardMaterial).needsUpdate = true;
}
and here I render the scene:
if (this.props.background) {
scene.background = this.props.background;
const camera = this.props.mainScene.cameras[0];
scene.children[0].children.map((item: THREE.Object3D) => {
if (item instanceof THREE.Light) {
this.props.mockUtils.editLights(
item as THREE.SpotLight | THREE.DirectionalLight,
this.props.scene.lights_intensity,
scene,
);
}
if (item instanceof THREE.Mesh) {
this.props.mockUtils.editMeshes(
item,
this.props.isOrderPage,
this.props.design,
this.props.materials,
this.props.textures,
// this.props.background,
renderer,
scene,
);
}
});
this.props.mockUtils.addAmbientLight(scene, this.props.scene.ambient_light);
scene.children.map((obj: THREE.Object3D) => {
if (obj instanceof THREE.CubeCamera) {
obj.update(renderer, scene);
}
});
renderer.render(scene, camera);
if (this.design.current) {
this.props.mockUtils.finish(
renderer,
FinalImage,
id,
`${this.props.baseUrl}products/${this.props.scene.product_name}.jpg`,
this.props.isOrderPage,
this.props.scene.zoomFactor,
this.design.current,
this.assetsLoaderCallback,
);
}
}
}
Can anyone help me to understand how to receive a normal reflection of the cube map that is applied to the scene background?
Thank you
Michael Moretti