How to optimize (lower gas) random ERC721 NFT mint?

I am creating an NFT that on-chain generates random body parts which off-chain is being combined and made into images and such. I am doing it on-chain to keep it true to the purpose of NFTs, but also because I have another function where I can combine tokens and choose which parts to keep on a new one.

Anyways, this minting of NFTs costs way too much eth atm, I am benchmarking it by minting 5 at a time, which with this current setup costs about 0.26 eth with a gas price of 150, so it uses about 1 151 894 gas. This won't really work since that almost equals the cost I've been thinking of charging for one NFT. I was wondering if anyone might have a good idea of how I could optimize my code to make it cost less, or another method to do this entirely.

These are the relevant functions:

``````//Generate random large number
function randomNumber() private view returns(uint) {
return uint(keccak256(abi.encodePacked(block.difficulty, block.timestamp, nonce)));
}

//Generate a random biased category
function generateRandomCategory() private returns(uint8) {
nonce++;
uint randNumber = randomNumber();

//Each rarity has their own chance of being picked, common has 20/36, uncommon has 10/36, rare 6/36 etc
//After choosing a rarity it will pick which category of that rarity by doing % the amount of categories
//of that rarity + the combined amount of all previous rarities, this will give the id of that category

uint rarityChoice = randNumber % 32;
if(rarityChoice <= 15) { return uint8(randNumber%2);     }   //Common has 2 categories, ids start at 0
if(rarityChoice <= 28) { return uint8(randNumber%2)+2;   }   //Uncommon has 2 categories, ids start at 2
return uint8(randNumber%2)+4;  //Rare has 2 categories, ids start at 4
}

event NewBot(uint16 indexed _id, uint8 level, uint8 head, uint8 body, uint8 l_arm, uint8 r_arm, uint8 l_leg, uint8 r_leg);

//Mint new bot
function mintBot(uint amount) public payable {
require(amount > 0, "You must mint atleast one bot.");
//require((totalSupply() + amount) < maxAmount, "Not enough inventory to fulfill your request.");
//require(msg.value == (50000000000000000 * amount), "Wrong ether amount!");
for(uint i = 0; i < amount; i++) {
uint8 body = generateRandomCategory();
uint8 l_arm = generateRandomCategory();
uint8 r_arm = generateRandomCategory();
uint8 l_leg = generateRandomCategory();
uint8 r_leg = generateRandomCategory();
uint16 _id = uint16(mint(msg.sender));
bitsMapping[_id] = [head, body, l_arm, r_arm, l_leg, r_leg, uint8(1)];
emit NewBot(_id, uint8(1), head, body, l_arm, r_arm, l_leg, r_leg);
}
}
``````

ALSO: I did some tests to find out what was actually using up the most gas when calling the mint function (all passing the number 5 to mint 5 bots).

• Current code used: 1 151 894 gas
• Commenting out all the generateRandomCategory() used: 1 016 806 gas
• Commenting out generateRandomCategory() AND bitsMapping[_id] used: 633 817 gas