Pen Settings

HTML

CSS

CSS Base

Vendor Prefixing

Add External Stylesheets/Pens

Any URL's added here will be added as <link>s in order, and before the CSS in the editor. You can use the CSS from another Pen by using it's URL and the proper URL extention.

+ add another resource

JavaScript

Babel includes JSX processing.

Add External Scripts/Pens

Any URL's added here will be added as <script>s in order, and run before the JavaScript in the editor. You can use the URL of any other Pen and it will include the JavaScript from that Pen.

+ add another resource

Packages

Add Packages

Search for and use JavaScript packages from npm here. By selecting a package, an import statement will be added to the top of the JavaScript editor for this package.

Behavior

Save Automatically?

If active, Pens will autosave every 30 seconds after being saved once.

Auto-Updating Preview

If enabled, the preview panel updates automatically as you code. If disabled, use the "Run" button to update.

Format on Save

If enabled, your code will be formatted when you actively save your Pen. Note: your code becomes un-folded during formatting.

Editor Settings

Code Indentation

Want to change your Syntax Highlighting theme, Fonts and more?

Visit your global Editor Settings.

HTML

              
                <div id="app"></div>
              
            
!

CSS

              
                @import url('https://fonts.googleapis.com/css?family=Luckiest+Guy');
@import url('https://fonts.googleapis.com/css?family=Architects+Daughter');
@import url('https://fonts.googleapis.com/css?family=Kranky');
@import url('https://fonts.googleapis.com/css?family=Permanent+Marker');

$cell-size : 27px;
$boss-enemy-size: 50px;

body {
	text-align: center;
	background-color: black;
	color: white;
}

.title{
	font-family: 'Luckiest Guy', cursive;
}

.game-container {
	height:auto;
	width: auto;
	margin: 25px auto;

	div.score{
		overflow: hidden;
		.score-item {
			background-color: white;
			color: black;
			padding: 7px;
			margin-left:5px;
			display: inline-block;
			font-size: 16px;
			font-weight: bold;
			vertical-align: middle;
			font-family: 'Architects Daughter', cursive;
		}	
		.health-symbol {
			height:15px; width: 15px;
			background-color: green;
			margin-right:3px;
			border: none;
		}	
		.weapon-symbol {
			height:22px; width: 22px;
			background : url("https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcQf6UaRVK33LHUjCyiQqXH9Ihu9Ec2FQPyjxruQfG1F7gCPdFFA8g") no-repeat center;
			background-size: 22px 22px;			
			margin-right:5px;
			border: none;
		}
		.toggle-darkness-btn {
			padding: 5px;
			margin: 5px;
			color: white; 
			background: rgba(0,0,0,0.5);
			float: right;
			font-weight: bold;
			font-family: 'Architects Daughter', cursive;
			border: 2px solid white; 
			&:hover{
				background: white;
				color: black;			
			}			
		}
	}
	
	p.tips{
		font-size: 17px;
		padding: 5px;
		font-family: 'Permanent Marker', cursive;
	}
	
	.game-screen{
		position: relative;
		table {
			max-width: 90%;
			margin: 10px auto;
			td {
				height: $cell-size; width: $cell-size;
			}
			.cell-wall { 
				background-color: #4d3319 ;  
				border: 2px solid #392613 ; 
				box-shadow: 1px 1px 1px 2px #261a0d inset;
			}	
			.cell-floor { 
				background-color:white; 
			}
			.player { 
				background-color: blue;
				background : url("https://vignette1.wikia.nocookie.net/kungfupanda/images/7/73/KFP3-promo-po4.jpg/revision/latest/scale-to-width-down/350?cb=20150726165358")  no-repeat center;
				background-size: 100% 100%;
			}
			.health { 
				background-color: green;
			}			
			.weapon { 
				//background-color: black;
				background : url("https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcQf6UaRVK33LHUjCyiQqXH9Ihu9Ec2FQPyjxruQfG1F7gCPdFFA8g") no-repeat center;
				background-size: 70% 70%;
				background-color: white;
			}
			.enemy { 			
				background: url("http://images.clipartpanda.com/lizard-clipart-lizard-clip-art-mascot.jpg") no-repeat center;
				background-size: 90% 90%;
				background-color: white;
			}
			.boss { 
				//background-color: pink; 
				//border: 4px dotted red;
				background: url("http://vignette2.wikia.nocookie.net/kungfupanda/images/8/85/KFP3-promo-kai.jpg/revision/latest?cb=20160314161848") no-repeat center center;
				background-size: $boss-enemy-size $boss-enemy-size;
				border: 3px solid grey;
			}
			.door {
				//background-color: #996633;
				//border: 4px dotted black;
				background : url("https://lh3.ggpht.com/HRQFs2zD9ym23JwJEjshYhZNGobW7M6e1Yq1wJf0mzVi-kkplx_Ss25fEzBqBfQyqS8=w300") no-repeat center;					
				background-size: 45px 45px;
			}
			.out-of-screen { display: none ; }
			.out-of-camera {
				background-image: url("");
				background-color: black; 
				border: none !important ;
				box-shadow: none !important;
			}
			.enemy.attack-effect { background-size: 60% 60%; }
			.boss.attack-effect {
				background-size: $cell-size $cell-size;
				background-color: white;
			}
		}	
	}
	
	.endscreen-inactive {
		display: none;
	}
	.endscreen-active {
		position: absolute;
		display: block;
		background-color: rgba(0,0,0,0.5);
		height:100%;
		width:100%;
		bottom: 0;	left:0;
		p{
			text-align: center;
			color: white;
			font-size: 55px; font-weight: bold;
			position: absolute;
			left:50%; top:50%;
			transform: translate(-50%,-50%);
			font-family: 'Kranky', cursive;
			padding: 20px;
			border: 20px solid transparent;
-moz-border-image: url(http://www.w3.org/TR/css3-background/border.png) 30% round;
-webkit-border-image: url(http://www.w3.org/TR/css3-background/border.png) 30% round;
-o-border-image: url(http://www.w3.org/TR/css3-background/border.png) 30% round;
border-image: url(http://www.w3.org/TR/css3-background/border.png) 30% round;
			
			.player{
				display: inline-block;
				height: 50px; width:50px;
				border: none;
				background: url("https://vignette1.wikia.nocookie.net/kungfupanda/images/7/73/KFP3-promo-po4.jpg/revision/latest/scale-to-width-down/350?cb=20150726165358") no-repeat center;
				background-size: 50px 50px;
			}
			.play-again{
				font-size: 29px;
				display: block;
				margin: 10px auto;
				background-color: rgb(169, 16, 33);
				padding: 5px 14px;
			}
		}	
	}
}


              
            
!

JS

              
                
var ROWS = 50;
var COLS = 50;

var CELL_SIZE_IN_PX = 27;
var GAMESCREEN_WIDTH_IN_PERCENTAGE = 80/100; // in %
var GAMESCREEN_HEIGHT_OFFSET_IN_PERCENTAGE= 25/100 ;// in %

var gameElements = {
	WALL				: { codeValue: 0, className: "cell-wall" },
	EMPTY_FLOOR	: { codeValue: 1, className: "cell-floor" },
	PLAYER			: { codeValue: 2, className: "player" },
	BOSS_ENEMY	: { codeValue: 3, className: "boss" },
	HEALTH			: { codeValue: 4, className: "health", totalCount: 5 },
	WEAPON			: { codeValue: 5, className: "weapon", totalCount: 7 },
	ENEMY				: { codeValue: 6, className: "enemy", totalCount: 10 },
	DOOR				: { codeValue: 7, className: "door" },
	totalDungeon: 4,
	weaponTypes	: [
		{ name	: "Axe", damage: 30 },
		{ name	: "Oath Keeper", damage: 25 },
		{ name	: "Needle", damage: 20 },
		{ name	: "Long Claw", damage: 35 }
	]
};

function getRandomIntInclusive(min, max) {
	min = Math.ceil(min);
	max = Math.floor(max);
	return Math.floor(Math.random() * (max - min + 1)) + min;
}

class ScorePanel extends React.Component {
	constructor(props) {
		super(props);
	}

	render() {
		return (
			<div className="score">
				<div className="score-item">
					<button className="health-symbol"></button> 
					Health {this.props.health} 
				</div>
				<div className="score-item">Dungeon Level {this.props.dungeon_no}</div>
				<div className="score-item">XP {this.props.xp}</div>
				<div className="score-item">
					<button className="weapon-symbol"></button>
					Weapon Name: {this.props.weapon.name} Damage: {this.props.weapon.damage}
				</div>
				<button type="button" className="toggle-darkness-btn" onClick={this.props.toggleDarkness}>TOGGLE DARKNESS</button>
			</div>	
		);	
	}	
}

class Cell extends React.Component {
	constructor(props){
		super(props);
		this.state = {
			fightingEnemy : false
		}; 
	}
		
	componentWillReceiveProps(nextProps){
		if(nextProps.applyAttackEffect) {
			this.setState({ fightingEnemy : true});
		}	
	}
	
	render() {
		var cellClass = [];		
		if ( this.props.value === gameElements["WALL"].codeValue)
			cellClass.push(gameElements["WALL"].className);
		else 
			cellClass.push(gameElements["EMPTY_FLOOR"].className);

		var specialCategory = ["PLAYER", "HEALTH", "ENEMY", "WEAPON", "BOSS_ENEMY", "DOOR"]
		.find( (name) => {	return gameElements[name].codeValue ===  this.props.value;});
		if(specialCategory)
			cellClass.push(gameElements[specialCategory].className) ;

		if(! this.props.visible)
			cellClass.push("out-of-camera");

		if(! this.props.show)
			cellClass.push("out-of-screen");
		
		if(this.state.fightingEnemy)
		{
			cellClass.push("attack-effect");
			setTimeout(()=>{
				this.setState({fightingEnemy: false});
			},200);			
		}	
		return (
			<td className={cellClass.join(" ")} 
					style={{height: CELL_SIZE_IN_PX,width:CELL_SIZE_IN_PX}} />	
		);	
	}
}

class Game extends React.Component {
	constructor(props) {
		super(props);
		this.map = this.createMap();
		this.state = {
			playerPos	: { x: 0,y: 0},
			scores		: this.getDefaultScoreValues(),
			darkMode : false,
			windowSize: { height:0,width:0}
		};

		this.enemyPositions = []; // enemyObject = {x , y, damage, health}
		this.weaponPositions = []; // weaponObject = {x , y, damage}
		this.healthPositions = []; // healthObject = {x, y, bonusHealth}
		this.cameraRadius = 5;
		
		this.handleWindowResize = this.handleWindowResize.bind(this);
		this.handleUserInput = this.handleUserInput.bind(this);
	}
	
	getDefaultScoreValues() {
		var defaultscore = {
				health		: 100,
				weapon		: { name: "Sword", damage: 50 },
				dungeon_no: 1,
				xp				: 0
			}
		return defaultscore; 
	}
	
	componentWillMount() {
		window.addEventListener("resize", this.handleWindowResize);
		window.addEventListener("keydown",this.handleUserInput);
		
		var windowHeight = $(window).height();
		var windowWidth = $(window).width();		
		this.gameScreenHeight =  (windowHeight - GAMESCREEN_HEIGHT_OFFSET_IN_PERCENTAGE * windowHeight) / CELL_SIZE_IN_PX ;
		this.gameScreenWidth = ( windowWidth * GAMESCREEN_WIDTH_IN_PERCENTAGE) / CELL_SIZE_IN_PX ;
		this.generateDungeonMap();
		if (this.map.length > 0) {
			// check for empty array
			this.fixPlayerPosition();			
			this.placeGameElementsOnBoard(this.state.scores.dungeon_no);
		}
	}

	componentWillUnmount() {
		window.removeEventListener("resize", this.handleWindowResize);	
		window.removeEventListener("keydown", this.handleUserInput);	
	}
	
	componentDidMount() {
		$(this.container).focus();	// not working
	}
	
	componentDidUpdate() {
		this.fightingEnemy = false;
	}
	
	handleWindowResize() {
		var newSize = {
			height	:	$(window).height(),
			width		:	$(window).width()
		};
				
		this.gameScreenHeight =  (newSize.height - GAMESCREEN_HEIGHT_OFFSET_IN_PERCENTAGE * newSize.height) / CELL_SIZE_IN_PX ;
		this.gameScreenWidth = 	 (newSize.width * GAMESCREEN_WIDTH_IN_PERCENTAGE) / CELL_SIZE_IN_PX ;
	
		this.setState({windowSize : newSize});
	}
	
	isVisibleCell(cell){	
		var playerX = this.state.playerPos.x;	
		var playerY = this.state.playerPos.y;
		var cameraCenter = {			
			x: Math.min(Math.max(playerX,this.cameraRadius),COLS-1-this.cameraRadius ),	
			y: Math.min(Math.max(playerY,this.cameraRadius),ROWS-1-this.cameraRadius )
		};
		var cameraRight = cameraCenter.x + this.cameraRadius;
		var cameraLeft= cameraCenter.x - this.cameraRadius;
		var cameraBottom= cameraCenter.y + this.cameraRadius;
		var cameraTop= cameraCenter.y - this.cameraRadius;
		
		if( cell.x >= cameraLeft && cell.x <= cameraRight && cell.y >= cameraTop && cell.y <= cameraBottom)
			return true;
		else 
			return false;
	}
	
	canshowCell(cell) {
		var playerX = this.state.playerPos.x;	
		var playerY = this.state.playerPos.y;
		
		var halfScreenWidth = (this.gameScreenWidth - this.gameScreenWidth % 2) / 2;
		var halfScreenHeight = (this.gameScreenHeight - this.gameScreenHeight % 2) / 2;
		
		var screenCenter = {			
			x: Math.min(Math.max(playerX,halfScreenWidth),COLS-1-halfScreenWidth ),	
			y: Math.min(Math.max(playerY,halfScreenHeight),ROWS-1-halfScreenHeight )
		};
			
		var screenRight = screenCenter.x + halfScreenWidth;
		var screenLeft= screenCenter.x - halfScreenWidth;
		var screenBottom= screenCenter.y + halfScreenHeight;
		var screenTop= screenCenter.y - halfScreenHeight;
			
		if( cell.x >= screenLeft && cell.x <= screenRight && cell.y >= screenTop && cell.y <= screenBottom)
			return true;
		else 
			return false;
	}

	createMap() {
		var map = [];
		for (var x = 0; x < COLS; x++) {
			map.push([]);
			for (var y = 0; y < ROWS; y++) {
				map[x].push(0);
			}
		}
		return map;
	}

	generateDungeonMap() {
		if(ROWS < 25 || COLS < 25)
		{
			alert("Configure Minimum 25 rows and 25 columns ");
			return;
		}
		
		var generator = new ROT.Map.Uniform(COLS, ROWS, {
			timeLimit: 5000,
			roomDugPercentage: 0.2
		});
		generator.create((x, y, v) => {
			if (v === 0) {
				// 0 represents floor In Uniform generator
				this.map[x][y] = 1;
			} else {
				this.map[x][y] = 0;
			}
		});
	}

	getRandomEmptyCell() {
		var randomX = 0,
				randomY = 0;
		do {
			randomX = Math.floor(Math.random() * COLS);
			randomY = Math.floor(Math.random() * ROWS);
		} while (this.map[randomX][randomY] !== gameElements["EMPTY_FLOOR"].codeValue); //  floor CHECK

		return { x: randomX, y: randomY };
	}

	fixPlayerPosition() {
		var initialPlayerPos = this.getRandomEmptyCell();
		this.map[initialPlayerPos.x][initialPlayerPos.y] = gameElements["PLAYER"].codeValue;
		this.setState({ playerPos: initialPlayerPos });
	}

	isLastDungeon(level) {
		return level === gameElements.totalDungeon;
	}

	getAllSideEmptyCell() {		
		var x = 0,
				y = 0,
				cells = [];
		
		do {
			x = Math.floor(Math.random() * COLS);
			y = Math.floor(Math.random() * ROWS);
			
			cells = [
				[x-1 , y-1],
				[x , y-1],
				[x+1 , y-1],
				[x-1 , y],
				[x , y],
				[x+1 , y],
				[x-1 , y+1],
				[x , y+1],
				[x+1 , y+1]
			]	;		
			var allSideEmpty =  
				cells.every((arr)=>{
						var col = Math.max( 0, Math.min(arr[0],COLS-1)),
								row = Math.max( 0, Math.min(arr[1],ROWS-1));
						return this.map[col][row] === gameElements["EMPTY_FLOOR"].codeValue;
				});	
		} while (allSideEmpty === false); //  floor CHECK
		
		return { x: x, y: y };
	}
	
	placeGameElementsOnBoard(dungeonLevel) {
		var entity = gameElements["HEALTH"];
		var totalCount = entity.totalCount;
		while (totalCount--) {
			var cell = this.getRandomEmptyCell();
			this.map[cell.x][cell.y] = entity.codeValue;
			this.healthPositions.push({
				x: cell.x,
				y: cell.y,
				bonusHealth: getRandomIntInclusive(3, 5) * dungeonLevel * 5
			});
		}

		entity = gameElements["WEAPON"];
		totalCount = entity.totalCount;
		while (totalCount--) {
			var cell = this.getRandomEmptyCell();
			this.map[cell.x][cell.y] = entity.codeValue;
			this.weaponPositions.push({
				x: cell.x,
				y: cell.y,
				weaponType:
					gameElements.weaponTypes[
						Math.floor(Math.random() * gameElements.weaponTypes.length)
					]
			});
		}

		entity = gameElements["ENEMY"];
		totalCount = entity.totalCount;
		while (totalCount--) {
			var cell = this.getRandomEmptyCell();
			this.map[cell.x][cell.y] = entity.codeValue;
			this.enemyPositions.push({
				x: cell.x,
				y: cell.y,
				damage: getRandomIntInclusive(3, 4) * dungeonLevel * 5,
				health: getRandomIntInclusive(3, 4) * dungeonLevel * 5
			});
		}

		entity = gameElements["BOSS_ENEMY"];
		if (this.isLastDungeon(dungeonLevel)) {
			var cell = this.getAllSideEmptyCell();
			this.map[cell.x][cell.y] = entity.codeValue;
			this.enemyPositions.push({
				x: cell.x,
				y: cell.y,
				damage: 30,
				health: 550
			});
		}

		entity = gameElements["DOOR"];
		if (!this.isLastDungeon(dungeonLevel)) {
			var cell = this.getAllSideEmptyCell();
			this.map[cell.x][cell.y] = entity.codeValue;
		}
	}

	handleUserInput(e) {
		if (e.which === ROT.VK_LEFT) this.movePlayer(-1, 0);
		else if (e.which === ROT.VK_RIGHT) this.movePlayer(1, 0);
		else if (e.which === ROT.VK_UP) this.movePlayer(0, -1);
		else if (e.which === ROT.VK_DOWN) this.movePlayer(0, 1);
	}

	isValidMove(newx, newy) {
		if (newx >= 0 && newx <= COLS - 1 && (newy >= 0 && newy <= ROWS - 1))
			return true;
	}

	movePlayer(dx, dy) {
		var currX = this.state.playerPos.x;
		var currY = this.state.playerPos.y;
		var newPos = { 
		x: currX + dx, 
		y: currY + dy 
		};
		var player = this.state.scores;
		var newscore = this.state.scores;
		var nextCellCode = this.map[newPos.x][newPos.y];
		
		if (!this.isValidMove(newPos.x, newPos.y)) {
			return;
		}

		if (nextCellCode === gameElements["DOOR"].codeValue) 
		{
			this.map[currX][currY] = gameElements["EMPTY_FLOOR"].codeValue;
			this.goNextLevel();
			newscore["xp"] = 0;
			newscore["dungeon_no"] = this.state.scores.dungeon_no + 1;
			this.setState({ "scores":newscore });	
		} 
		else if (nextCellCode === gameElements["EMPTY_FLOOR"].codeValue) 
		{
			this.map[currX][currY] = gameElements["EMPTY_FLOOR"].codeValue;
			this.map[newPos.x][newPos.y] = gameElements["PLAYER"].codeValue;
			this.setState({ "playerPos":{x:newPos.x, y:newPos.y} });		
		}
		else if (nextCellCode === gameElements["HEALTH"].codeValue) 
		{
			var healthIndex = this.healthPositions.findIndex(cell => {
				return cell.x === newPos.x && cell.y === newPos.y;
			});			
			this.map[currX][currY] = gameElements["EMPTY_FLOOR"].codeValue;
			this.map[newPos.x][newPos.y] = gameElements["PLAYER"].codeValue;
			//alert(" player.health: " + player.health + " healthIndex:" + healthIndex + " value: " + this.healthPositions[healthIndex].bonusHealth);
			newscore["health"] =  player.health + this.healthPositions[healthIndex].bonusHealth;
			this.setState({
				"scores":newscore,
				"playerPos":{x:newPos.x, y:newPos.y}
			});
		} 
		else if (nextCellCode === gameElements["WEAPON"].codeValue) 
		{
			var weaponIndex = this.weaponPositions.findIndex(cell => {
				return cell.x === newPos.x && cell.y === newPos.y;
			});
			
			this.map[currX][currY] = gameElements["EMPTY_FLOOR"].codeValue;
			this.map[newPos.x][newPos.y] = gameElements["PLAYER"].codeValue;
			newscore["weapon"] =  this.weaponPositions[weaponIndex].weaponType;
			this.setState({
				"scores":newscore,
				"playerPos":{x:newPos.x, y:newPos.y}
			});
		} 
		else if (
			nextCellCode === gameElements["ENEMY"].codeValue ||
			nextCellCode === gameElements["BOSS_ENEMY"].codeValue
		) {
			this.fightEnemy(newPos.x, newPos.y);
		}
	}

	fightEnemy(newx, newy) {
		//var player = this.state.scores;
		var player = {
			health : this.state.scores.health,
			weapon : this.state.scores.weapon,
			dungeon_no : this.state.scores.dungeon_no ,
			xp : this.state.scores.xp
		};
		var newscore = this.state.scores;
		var isBoss = false;

		if (this.map[newx][newy] === gameElements["BOSS_ENEMY"].codeValue) {
			isBoss = true;
		}

		var enemyIndex = this.enemyPositions.findIndex(cell => {
			return cell.x === newx && cell.y === newy;
		});
		var enemyCell = this.enemyPositions[enemyIndex];

		var playerHealthAfterAttack = Math.max(0, player.health - enemyCell.damage);
		var enemyHealthAfterAttack = Math.max(0, enemyCell.health - player.weapon.damage );
				
		//console.log("Player CurrHealth: " + player.health + " Enemy Damage: " + enemyCell.damage + " afterAttackPlayerHealth: " + playerHealthAfterAttack);

		if (playerHealthAfterAttack === 0) {			
			this.enemyPositions[enemyIndex].health = enemyHealthAfterAttack;
			newscore["health"] =  playerHealthAfterAttack;
			this.setState({"scores":newscore});
			this.endGame("player lost");
		} 
		else if (playerHealthAfterAttack && enemyHealthAfterAttack === 0) {
			// player destroyed enemy
			this.enemyPositions.splice(enemyIndex, 1); // remove enemyPosition from array
			this.map[this.state.playerPos.x][this.state.playerPos.y] =
				gameElements["EMPTY_FLOOR"].codeValue;
			this.map[newx][newy] = gameElements["PLAYER"].codeValue;
					
			newscore["health"] =  playerHealthAfterAttack;
			newscore["xp"] =  player.xp + 10;
				this.setState({
				"scores" :newscore,
				"playerPos":{x:newx, y:newy}
			});		
			
			if (isBoss) {
				this.endGame("player won");
			}	
			else {
				if( (this.state.scores.xp ) % 100 === 0 ) {
					this.goNextLevel();
					newscore["dungeon_no"] = this.state.scores.dungeon_no + 1;
					newscore["xp"] = 0;
					this.setState({"scores": newscore});
				}	
			}			
		} 
		else if (playerHealthAfterAttack && enemyHealthAfterAttack) {			
			this.enemyPositions[enemyIndex].health = enemyHealthAfterAttack;
			this.fightingEnemy = true;
			this.cellUnderAttack = {x	: enemyCell.x, y : enemyCell.y};		
			newscore["health"] = playerHealthAfterAttack;
			this.setState({"scores": newscore});
		}
	}

	endGame(result) {
		if(result === "player lost")
			this.playerStatus = "LOST";
		else if(result === "player won")
			this.playerStatus = "WON";
		
		var newPos = this.state.playerPos;
		newPos.x = -1; newPos.y = -1;
		this.setState({playerPos: newPos});
	}

	clearGameBoard() {
		this.map.forEach((arr, index) => {
			this.map[index] = arr.fill(0);
		});

		this.enemyPositions = []; // enemyObject = {x , y, damage, health}
		this.weaponPositions = []; // weaponObject = {x , y, damage}
		this.healthPositions = []; // healthObject = {x, y, bonusHealth}
	}

	goNextLevel() {
		this.clearGameBoard();
		this.generateDungeonMap();
		if (this.map.length > 0) {
			// check for empty array
			this.fixPlayerPosition();
			this.placeGameElementsOnBoard(this.state.scores.dungeon_no + 1);
		}
	}

	handleToggleBtnClick() {
		this.setState({ darkMode: !this.state.darkMode});
	}
	
	playAgain(){
		this.clearGameBoard();
		this.generateDungeonMap();
		if (this.map.length > 0) {
			// check for empty array			
			this.fixPlayerPosition();
			this.placeGameElementsOnBoard(1);
			this.setState({ scores: this.getDefaultScoreValues() });
		}
	}
	
	render() {		
		var showEndScreen = (this.state.playerPos.x === -1 && this.state.playerPos.y === -1) ? true : false;
		
		var boardRows = [];

		for (var row = 0; row < ROWS; row++) {
			var boardCells = [];
			for (var column = 0; column < COLS; column++) {
				var currCell = {x:column,y:row};
				var applyAttackEffect = false;
				if(this.fightingEnemy)
				{
					if(this.cellUnderAttack.x === column && this.cellUnderAttack.y === row) 	
						applyAttackEffect =  true;
				}	
				
				boardCells.push(
					<Cell 
						key={column} value={this.map[column][row]} 
						visible={this.state.darkMode ? this.isVisibleCell(currCell) : true} 
						show={this.canshowCell(currCell)}
						applyAttackEffect = {applyAttackEffect} 
					/>
				);
			}
			boardRows.push(<tr key={row}> {boardCells} </tr>);
		}		
				
		return (
			<div className="game-container">
				<ScorePanel {...this.state.scores} 
										toggleDarkness={()=>this.handleToggleBtnClick()}/>
				<p className="tips"> Defeat Super Villain Kai in Dungeon 4 </p>
				<div className="game-screen">
					<table
						name="table"
						ref={node => {this.container = node;}}>
							{boardRows}
					</table>
				</div>	
				
				<EndScreen 
					showEndScreen={showEndScreen} 
					result={this.playerStatus}
					handlePlayAgain={()=>this.playAgain()}
					/>
			</div>
		);
	}
}

function EndScreen(props){	
	return (
		<div className={props.showEndScreen ? "endscreen-active" : "endscreen-inactive"}>
			<p>
				<button className="player"></button> {props.result} THE GAME 
				<button className="play-again" onClick={props.handlePlayAgain}>Play Again</button>
			</p> 
		</div>
	);	
}

function Title(props) {
	return <h2 className="title">{props.children}</h2>;
}

class App extends React.Component {
	constructor(props) {
		super(props);
	}

	render() {
		return (
			<div className="container-fluid app">
				<Title> Kung-Fu Panda In Dungeon Crawler </Title>
				<Game />
			</div>
		);
	}
}

ReactDOM.render(<App />, document.getElementById("app"));

              
            
!
999px

Console