Skip to content

Commit

Permalink
🎌🛕 -> Add Arena component to #15 #16
Browse files Browse the repository at this point in the history
  • Loading branch information
Gizmotronn committed Feb 19, 2022
1 parent 47d608f commit 87e6146
Show file tree
Hide file tree
Showing 3 changed files with 138 additions and 1 deletion.
3 changes: 3 additions & 0 deletions frontend/src/App.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import LoadingIndicator from './Components/LoadingIndicator';
import SelectCharacter from './Components/SelectCharacter';
import { CONTRACT_ADDRESS, transformCharacterData } from './constants';
import GameContent from './utils/GameContent.json';
import Arena from './Components/Arena';
// Eth -> JS imports
import { ethers } from 'ethers';

Expand Down Expand Up @@ -158,6 +159,8 @@ const App = () => {
// If user is connected and does not have a character NFT - show SelectCharacter component
} else if (currentAccount && !characterNFT) {
return <SelectCharacter setCharacterNFT={setCharacterNFT} />;
} else if (currentAccount && characterNFT) { // If user is connected and has a character NFT - show Arena component
return <Arena characterNFT={characterNFT} setCharacterNFT={setCharacterNFT} />;
}
};

Expand Down
133 changes: 133 additions & 0 deletions frontend/src/Components/Arena/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
import React, { useEffect, useState } from 'react';
import { ethers } from 'ethers';
import { CONTRACT_ADDRESS, transformCharacterData } from '../../constants';
import gameContent from '../../utils/GameContent.json';
import './Arena.css'
import SelectCharacter from '../SelectCharacter';

// Parse in characterNFT metadata
const Arena = ({ characterNFT }) => {
// State
const [gameContract, setGameContract] = useState(null);
// Boss Metadata state
const [boss, setBoss] = useState(null);
const [attackState, setAttackState] = useState('');
const runAttackAction = async () => {
try {
if (gameContract) {
setAttackState('attacking...'); // Waiting for the attack transaction to finish
console.log('Attacking boss....')
const attackTxn = await gameContract.attackBoss();
await attackTxn.wait();
console.log('attackTxn:', attackTxn);
setAttackState('hit'); // When the character lands a hit on the boss
}
} catch (error) {
console.log('Error attacking boss:', error);
setAttackState(''); // Default state - nothing happens
}
};

// UseEffect
useEffect(() => {
const { ethereum } = window;

if (ethereum) {
const provider = new ethers.providers.Web3Provider(ethereum);
const signer = provider.getSigner();
const gameContract = new ethers.Contract(
CONTRACT_ADDRESS,
gameContent.abi,
signer
);

setGameContract(gameContract);
} else {
console.log('Ethereum object not found ');
}

// Async function that gets the boss from the contract and sets it in state
const fetchBoss = async () => {
const bossTxn = await gameContract.getBoss();
console.log('Boss:', bossTxn);
setBoss(transformCharacterData(bossTxn));
};

// Attack setup logic when event is fired
const onAttackComplete = (newBossHp, newPlayerHp) => {
const bossHp = newBossHp.toNumber();
const playerHp = newPlayerHp.toNumber();

console.log(`AttackComplete: Boss Hp: ${bossHp}, Player Hp: ${playerHp}`);
// Update player and boss hp
setBoss((prevState) => {
return { ...prevState, hp: bossHp };
});

SelectCharacter((prevState) => { // I think this is supposed to be `setCharacterNFT`
return { ...prevState, hp: playerHp };
});
}

if (gameContract) {
fetchBoss();
gameContract.on('AttackComplete', onAttackComplete);
}

return () => {
if (gameContract) {
gameContract.off('AttackComplete', onAttackComplete);
}
}
}, [gameContract]); // Is either `gameContent` or `gameContract`

return (
<div className="arena-container">
{boss && (
<div className="boss-container">
<div className={`boss-content ${attackState}`}>
<h2> {boss.name} </h2>
<div className="image-content">
<img src={boss.imageURI} alt={`boss.name`} />
<div className="health-bar">
<progress value={boss.hp} max={boss.maxHp} />
<p>{`${boss.hp} / ${boss.maxHp} HP`}</p>
</div>
</div>
</div>
<div className="attack-container">
<button className="cta-button" onClick={runAttackAction}>
{`Attack ${boss.name}`}
</button>
</div>
</div>
)}

{characterNFT && (
<div className="players-container">
<div className="player-container">
<h2>Your character</h2>
<div className="player">
<div className="image-content">
<h2>{characterNFT.name}</h2>
<img
src={characterNFT.imageURI}
alt={`Character ${characterNFT.name}`}
/>
<div className="health-bar">
<progress value={characterNFT.hp} max={characterNFT.maxHp} />
<p>{`${characterNFT.hp} / ${characterNFT.maxHp} HP`}</p>
</div>
</div>
<div className="stats">
<h4>{`⚔️ Attack Damage: ${characterNFT.attackDamage}`}</h4>
</div>
</div>
</div>
</div>
)}
</div>
);
};

export default Arena;
3 changes: 2 additions & 1 deletion frontend/src/Components/SelectCharacter/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ const SelectCharacter = ({ setCharacterNFT }) => {
const mintTxn = await gameContract.mintCharacterNFT(characterId);
await mintTxn.wait();
console.log('mintTxn:', mintTxn);
//alert(`Your NFT has minted - see it here: https://testnets.opensea.io/assets/${CONTRACT_ADDRESS}/${tokenId.toNumber()}`);
// hides loading indicator when done with Action
setMintingCharacter(false);
}
Expand Down Expand Up @@ -109,7 +110,7 @@ const SelectCharacter = ({ setCharacterNFT }) => {

return (
<div className="select-character-container">
<h2>Mint Your Hero. Save El Barrio.</h2>
<h2>Mint Your Hero.</h2>
{characters.length > 0 && (
<div className="character-grid">{renderCharacters()}</div>
)}
Expand Down

0 comments on commit 87e6146

Please sign in to comment.