Skip to content

Instantly share code, notes, and snippets.

@greaneym
Last active November 23, 2017 01:20
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save greaneym/fad9cbdb56af9d9b48467d22a7e587e0 to your computer and use it in GitHub Desktop.
Save greaneym/fad9cbdb56af9d9b48467d22a7e587e0 to your computer and use it in GitHub Desktop.
rogue react game for FCC zipline
.button {
position: absolute;
left: 20px;
margin: 5px;
top: 5px;
background-color: #f9fcfd;
height: 45px;
width: 55px;
font-family: normal 20px/1.5 "Open Sans", sans-serif;
font-color: "black"; }
"use strict";
/*
used Hexi (pixi) to build a simple game prototype
used RinCon web log for example of react container for pixi
*/
/* future enhancements,
. make messages DRY with function
. figure out how to solve CORS problem when loading remote assets
like tilesets and sounds
. add more react.js Reset button and container are React.js rest is pixi.js
. add more rooms and levels, just one level here for prototype
*/
var g,score;
//Create a new Hexi instance, and start it
// this was started in html
// not all assets work yet.
/*
//var chimeSound = "/hexi/hexi-master/tutorials/sounds/chimes.wav";
// g = hexi(512, 512, setup);
//Set the background color and scale the canvas
g.backgroundColor = "white";
g.scaleToWindow();
//Start Hexi
g.start();
count = 0;
*/
// create something to be masked..
//var mySprite = PIXI.Sprite.fromImage("testImage.png");
// this takes the place of rogue-like fov where mask is on top
// of cursor and blocks vision but still can see things if move around
var myS1 = PIXI.Sprite.fromImage("https://gist.githubusercontent.com/greaneym/15d8e91b19474f03fc6e2da00c567c5f/raw/630ad277ebbf08892416bf53bfde9e88ad45758d/perlinsnap.png");
myS1.width = 400;
myS1.height = 400;
myS1.x = 50;
myS1.y = 50;
//Declare your global variables (global to this game, which means you
//want to use them in more than one function)
// health = obtaining treasure and finding the door
// XP gained with exiting door and/or killing the boss
// The boss can kill player if unarmed and collision occurs.
// Player's health goes down if collides with enemies.
// Player can kill boss if obtains sticks.
// sticks have sidedness, one side does not kill.
// Player must hit boss multiple (4x) times to reduce alpha (kill) the boss.
// Player must have health and XP to win, score can be negative.
var dungeon = undefined,
player = undefined,
boss = undefined,
treasure = undefined,
enemies = undefined,
stick1 = undefined,
stick2= undefined,
chimes = undefined,
exit = undefined,
healthBar = undefined,
message = undefined,
message2 = undefined,
message3 = undefined,
message4 = undefined,
message5 = undefined,
message6 = undefined,
gameScene = undefined,
outerCover = undefined,
gameMiddleScene = undefined,
gameMiddleScene2 = undefined,
gameOverScene = undefined,
gameXPScene = undefined,
score = undefined,
xp = undefined,
scoreDisplay = undefined,
scoreDisplayTitle = undefined,
xpDisplay = undefined,
xpDisplayTitle = undefined,
scoreNeededToWin = undefined,
xpNeededToWin = undefined,
gameBossScene = undefined,
gamePlayerScene = undefined,
darkbulb = undefined;
//The `setup` function runs once and is used to initializes your game
function setup() {
//Create the `chimes` sound object
// chimes = g.sound("chimeSound");
//Create the `gameScene` group
gameScene = g.group();
// gameScene.addChild(myMask);
// gameScene.addChild(lighting);
function randomRange(myMin, myMax) {
var result = Math.floor(Math.random() * (myMax - myMin + 1)) + myMin;
return result; // Change this line
}
//The exit door
exit = g.rectangle(48, 48, "green");
//not moving this very much but you could change the values for more
//randomness in location
exit.x = 22 + randomRange(2,3);
exit.y = 22 - randomRange(1,4);
console.log("exit.xy", exit.x,exit.y);
gameScene.addChild(exit);
//The player sprite
// The player moves with the cursor
player = g.rectangle(32, 32, "blue");
player.x = 68;
player.y = g.canvas.height / 2 - player.halfHeight;
gameScene.addChild(player);
var covering = new PIXI.Graphics();
var rr = Math.random() * 0x10 | 0;
var rg = Math.random() * 0x10 | 0;
var rb = Math.random() * 0x10 | 0;
var rad = 80 + Math.random() * 20;
covering.beginFill((rr << 0) + (rg << 0) + rb, 10);
covering.drawRect(0, 0, 200,200);
covering.endFill();
var darkbulb = new PIXI.Graphics();
var rr = 0x99999;
var rg = 0x99999;
var rb = 0x99999;
var rad = 180 + Math.random() * 20;
darkbulb.beginFill((rr ) + (rg) + rb, 0.7);
darkbulb.drawCircle(0, 0, rad);
darkbulb.endFill();
//The boss sprite
boss = g.rectangle(32, 52, "black");
g.stage.putCenter(boss, (28 + randomRange(1,20)), (100 + randomRange(1,20)));
//boss.x = 28 + randomRange(1,5);
//boss.y = 100 + randomRange(-3, 3);
boss.alpha = 900; //if hit, this goes down and color changes
gameScene.addChild(boss);
// console.log("boss", boss);
//Create the score message
//`text` arguments: stringContent, font, color, x, y.
scoreDisplayTitle = g.text("Score: ", "20px helvetica", "#00FF00", 375, 30);
scoreDisplay = g.text(" ", "20px helvetica", "#00FF00", 455, 30);
xpDisplayTitle = g.text("XP: ", "20px helvetica", "#00FF00", 395, 55);
xpDisplay = g.text(" ", "20px helvetica", "#00FF00", 455, 55);
//Game variables
score = 0;
scoreNeededToWin = 80;
xp = 0;
xpNeededToWin = 2000;
//Create the treasure
//w, h, color
treasure = g.rectangle(16, 16, "gold");
//Create the stick weapons
//w, h, color
stick1 = g.rectangle(34, 8, "orange"); // this stick has to be pushed
// below to move it
stick2 = g.rectangle(34, 10, "purple");
/*
// Here are two ways to move things around but here used put.center
//Position it next to the left edge of the canvas
treasure.x = 20 * Math.random(2);
treasure.y = 10; // + 6* Math.random();
//Position it next to the left edge of the canvas
stick1.x = 400 + (10 * Math.random());
stick1.y = 400 - (10 * Math.random());
stick2.x = g.canvas.width - stick2.width - (6 * Math.random());
stick2.y = g.canvas.height / (2 * Math.random()) - stick2.halfHeight;
*/
//Alternatively, you could use Ga's built in convenience method
//called `putCenter` to postion the sprite like this:
// I purposely made the calculations so that they are random but
// still in relatively the same starting position. Use this
// to make a bigger variety of locations
g.stage.putCenter(treasure, (208 + randomRange(1,3)), (10 + randomRange(1,2)));
g.stage.putCenter(stick1, (228 + randomRange(1,5)), (30 + randomRange(1,15)));
g.stage.putCenter(stick2, (228 + randomRange(0,7)), (26 + randomRange(1,20)));
//Create a `pickedUp` property on the treasure to help us Figure
//out whether or not the treasure has been picked up by the player
treasure.pickedUp = false;
stick1.pickedUp = false;
stick2.pickedUp = false;
//Add the treasure to the `gameScene`
gameScene.addChild(treasure);
gameScene.addChild(stick1);
gameScene.addChild(stick2);
//Make the enemies
var numberOfEnemies = 6,
spacing = 48,
xOffset = 150,
speed = 2,
direction = 1;
//An array to store all the enemies
enemies = [];
//Make as many enemies as there are `numberOfEnemies`
for (var i = 0; i < numberOfEnemies; i++) {
//Each enemy is a red rectangle
var enemy = g.rectangle(32, 32, "red");
//Space each enemey horizontally according to the `spacing` value.
//`xOffset` determines the point from the left of the screen
//at which the first enemy should be added.
var x = spacing * i + xOffset;
//Give the enemy a random y position
var y = g.randomInt(0, g.canvas.height - enemy.height);
//Set the enemy's direction
enemy.x = x;
enemy.y = y;
//Set the enemy's vertical velocity. `direction` will be either `1` or
//`-1`. `1` means the enemy will move down and `-1` means the enemy will
//move up. Multiplying `direction` by `speed` determines the enemy's
//vertical direction
enemy.vy = speed * direction;
//Reverse the direction for the next enemy
direction *= -1;
//Push the enemy into the `enemies` array
enemies.push(enemy);
//Add the enemy to the `gameScene`
gameScene.addChild(enemy);
}
//Create the health bar
var outerBar = g.rectangle(128, 16, "black"),
innerBar = g.rectangle(128, 16, "yellowGreen");
//Group the inner and outer bars
healthBar = g.group(outerBar, innerBar);
//Set the `innerBar` as a property of the `healthBar`
healthBar.inner = innerBar;
//Position the health bar
healthBar.x = g.canvas.width - 148;
healthBar.y = 16;
//Add the health bar to the `gameScene`
gameScene.addChild(healthBar);
//Add some text for the game over message
message = g.text("Game Over!", "64px Futura", "black", 20, 20);
message.x = 120;
message.y = g.canvas.height / 2 - 64;
//Add some sidetext for the capture treasure message
message2 = g.text("Won Treasure!", "20px Futura", "black", 20, 20);
message2.x = 20;
message2.y = g.canvas.height / 2 - 64;
//Add some sidetext for the stick message
message3 = g.text("Enemies Fear the Stick!", "20px Futura", "black", 21, 23);
//Add some sidetext for the boss message
message4 = g.text("You killed the Boss!", "20px Futura", "black", 20, 23);
message5 = g.text("The Boss killed You!", "20px Futura", "red", 20, 35);
message6 = g.text("XP Treasure for You!", "20px Futura", "black", 24, 40);
//Create a `gameMiddleScene` group and add the message sprite to it
gameMiddleScene = g.group(message2);
gameMiddleScene.visible = false;
gameMiddleScene2 = g.group(message3);
gameMiddleScene2.visible = false;
gameBossScene = g.group(message4);
gameBossScene.visible = false;
gamePlayerScene = g.group(message5);
gamePlayerScene.visible = false;
gameXPScene = g.group(message6);
gameXPScene.visible = false;
gameOverScene = g.group(message);
//Make the `gameOverScene` invisible for now
gameOverScene.visible = false;
gameScene.addChild(myS1);
myS1.mask = darkbulb; // has interesting effect
player.addChild(darkbulb);
// near the end
//Let the user control the player character using the keyboard.
//Hexi's `arrowControl` method lets you do this easily. Supply the
//sprite you want to move as the first argument, and the number of
//pixels per frame that it should move as the second argument
// g.arrowControl(player, 5);
//The `arrowControl` method is great for prototyping a game
//but for more flexibility you can also program the arrow keys
//manually, like this:
//Create some keyboard objects using Hexi's `keyboard` method.
//You would usually use this code in the `setup` function
//Supply the ASCII key code value as the single argument
let leftArrow = g.keyboard(37),
upArrow = g.keyboard(38),
rightArrow = g.keyboard(39),
downArrow = g.keyboard(40);
//Left arrow key `press` method
leftArrow.press = () => {
//Change the player's velocity when the key is pressed
player.vx = -5;
player.vy = 0;
};
//Left arrow key `release` method
leftArrow.release = () => {
//If the left arrow has been released, and the right arrow isn't down,
//and the player isn't moving vertically:
//Stop the player
if (!rightArrow.isDown && player.vy === 0) {
player.vx = 0;
}
};
upArrow.press = () => {
player.vy = -5;
player.vx = 0;
};
upArrow.release = () => {
if (!downArrow.isDown && player.vx === 0) {
player.vy = 0;
}
};
rightArrow.press = () => {
player.vx = 5;
player.vy = 0;
};
rightArrow.release = () => {
if (!leftArrow.isDown && player.vy === 0) {
player.vx = 0;
}
};
downArrow.press = () => {
player.vy = 5;
player.vx = 0;
};
downArrow.release = () => {
if (!upArrow.isDown && player.vx === 0) {
player.vy = 0;
}
};
//set the game state to `play`
g.state = play;
}
g = hexi(512, 512, setup);
//Set the background color and scale the canvas
g.backgroundColor = "white";
g.scaleToWindow();
//Start Hexi
g.start();
//The `play` function contains all the game logic and runs in a loop
function play() {
//Move the player
g.move(player);
//Keep the player contained inside the stage's area
g.contain(player, g.stage);
//Move the enemies and check for a collision
//Set `playerHit` to `false` before checking for a collision
var playerHit = false;
var stick1Hit = false;
var stick2Hit = false;
var bossHit = false;
//Loop through all the sprites in the `enemies` array
enemies.forEach(function (enemy) {
//Move the enemy
g.move(enemy);
//Check the enemy's screen boundaries
var enemyHitsEdges = g.contain(enemy, g.stage);
//If the enemy hits the top or bottom of the stage, reverse
//its direction
if (enemyHitsEdges) {
if (enemyHitsEdges.has("top") || enemyHitsEdges.has("bottom")) {
enemy.vy *= -1;
}
}
//Test for a collision. If any of the enemies are touching
//the player, set `playerHit` to `true`
if (g.hitTestRectangle(player, enemy)) {
playerHit = true;
//console.log("playerHit?", playerHit);
}
//Test for a collision w weapon. If any of the enemies are touching
//the player, set `stickHit` to `true`
if (g.hitTestRectangle(stick1, enemy)) {
stick1Hit = true;
score += 2;
}
if (g.hitTestRectangle(stick2, enemy)) {
stick2Hit = true;
xp +=10;
enemy.alpha -=1;
}
if (g.hitTestRectangle(stick2, boss)) {
bossHit = true;
xp +=20;
boss.alpha = boss.alpha -1;
if (boss.alpha < 0) {
gameBossScene.visible = true;
g.wait(1000, function () {
return (gameBossScene.visible = false)
});
if (xp > 2000) { xp = 2000; } //why is xp going over 2000?
g.wait(2000, function () {
return (g.state = end)
});
}
}
});
//If the player is hit...
if (playerHit) {
//Make the player semi-transparent
player.alpha = 0.5;
score -= 3;
//Reduce the width of the health bar's inner rectangle by 1 pixel
healthBar.inner.width -= 1;
} else {
//Make the player fully opaque (non-transparent) if it hasn't been hit
player.alpha = 1;
}
if ((stick1Hit) || (stick2Hit)){
//Make the player semi-transparent
player.alpha = 1;
//Reduce the width of the health bar's inner rectangle by 1 pixel
healthBar.inner.width += 1;
}
//Check for a collision between the player and the treasure
if (g.hitTestRectangle(player, treasure)) {
//If the treasure is touching the player, center it over the player
treasure.x = player.x + 8;
treasure.y = player.y + 8;
if (!treasure.pickedUp) {
//If the treasure hasn't already been picked up,
treasure.pickedUp = true;
gameMiddleScene.visible = true;
//Wait for 1 second (1000 milliseconds) then
//remove the message
g.wait(1000, function () {
return (gameMiddleScene.visible = false)
});
};
}
//Check for a collision between the player and the stick weapon
if (g.hitTestRectangle(player, stick1)) {
//If the stick is touching the player, center it over the player
stick1.x = player.x - 5;
stick1.y = player.y - 5;
if (!stick1.pickedUp) {
stick1.pickedUp = true;
gameMiddleScene2.visible = true;
//Wait for 1 second (1000 milliseconds) then
//remove the message
g.wait(1000, function () {
return (gameMiddleScene2.visible = false)
});
};
}
//Check for a collision between the player and the stick weapon
if (g.hitTestRectangle(player, stick2)) {
//If the stick is touching the player, center it over the player
stick2.x = player.x + 6;
stick2.y = player.y + 6;
if (!stick2.pickedUp) {
stick2.pickedUp = true;
gameMiddleScene2.visible = true;
//Wait for 1 second (1000 milliseconds) then
//remove the message
g.wait(1000, function () {
return (gameMiddleScene2.visible = false)
});
};
}
if (g.hitTestRectangle(player, boss)) {
//If the player hits boss without stick,game over
if (!stick2.pickedUp) {
gamePlayerScene.visible = true;
//Wait for 1 second (1000 milliseconds) then
//remove the message
g.wait(1000, function () {
return (gamePlayerScene.visible = false)
});
g.wait(2000, function () {
return (g.state = end)
});
};
};
/* Display the score */
scoreDisplay.content = score;
xpDisplay.content = xp;
//Check for the end of the game
//Does the player have enough health? If the width of the `innerBar`
//is less than zero, end the game and display "You lost!"
if (healthBar.inner.width < 0) {
g.state = end;
message.content = "You lost!";
}
//If the player has brought the treasure to the exit,
//you get more XP!"
if (g.hitTestRectangle(treasure, exit) || (score === scoreNeededToWin)) {
xp += 50;
gameXPScene.visible = true;
g.wait(1000, function () {
return (gameXPScene.visible = false)
});
}
//The player wins if the score matches the value
//of `scoreNeededToWin`, which is 60
if (score === scoreNeededToWin) {
gameOverScene.visible = true;
g.wait(1000, function () {
return (ogameXPScene.visible = false)
});
g.state = end;
}
if (xp === xpNeededToWin) {
gameXPScene.visible = true;
g.wait(1000, function () {
return (gameXPScene.visible = false)
});
g.state = end;
}
} //end play don't remove
function end() {
//Hide the `gameScene` and display the `gameOverScene`
gameScene.visible = false;
gameOverScene.visible = true;
}
function reset() {
//remove assets
g.remove(enemies);
g.remove(stick1);
g.remove(stick2);
g.remove(treasure);
g.remove(healthBar);
g.remove(message);
g.remove(message2);
g.remove(message3);
g.remove(message4);
g.remove(message5);
g.remove(message6);
g.remove(exit);
g.remove(player);
g.remove(boss);
g.remove(scoreDisplay);
g.remove(xpDisplay);
//score = 0;
//xp = 0;
gameScene.visible = true;
gameOverScene.visible = false;
setup();
//this.renderer.render(stage);
scoreDisplay = g.text(" ", "20px helvetica", "#00FF00", 470, 30);
xpDisplay = g.text(" ", "20px helvetica", "#00FF00", 470, 55);
g.state = play;
}
class Canvas extends React.Component {
constructor( props ) {
super(props);
//bind our animate function
this.animate = this.animate.bind(this);
}
/**
* Animation loop for updating Pixi Canvas
**/
animate() {
this.frame = requestAnimationFrame(this.animate);
}
componentDidMount() {
var g = hexi(512, 512, setup);
}
/**
* shouldComponentUpdate is used to check our new props against the current
* and only update if needed
**/
shouldComponentUpdate(nextProps, nextState) {
console.log("no props");
}
/**
* When we get new props, run the appropriate imperative functions
**/
componentWillReceiveProps(nextProps) {
console.log("no props");
}
updateCount(props) {
console.log("no props updated");
}
componentWillUnmount() {
this.refs.gameCanvas.removeChild(this.renderer.view);
this.renderer.destroy( true );
this.renderer = null;
this.frame = null;
cancelAnimationFrame(this.frame);
}
render() {
return (
<div className="game-canvas-container" ref="gameCanvas">
</div>
);
}
}
class Application extends React.Component {
constructor(props) {
super(props);
//store our zoom level in state
this.onResetGame = this.onResetGame.bind(this);
}
/**
* Event handler for resetting. Increments the count
**/
onResetGame() {
console.log("in canvas, clicked reset");
g.state = play;
g.count = 0;
g.state = reset;
g.state();
}
render() {
return (
<div>
<button className='button' onClick={this.onResetGame}>Reset Game</button>
<Canvas />
</div>
);
}
}
ReactDOM.render(<Application />, document.getElementById("appContainer"));
<!DOCTYPE html>
<html>
<head>
<title>Rogue Hexi.js and React.js Game for FCC</title>
<meta charset="utf-8">
<!--
/*
$bgcolor: rgb(249,252,253);
$buttonfont: normal 20px/1.5 'Open Sans', sans-serif;
$whitish: #F44336;
.button {
position: absolute;
left:20px;
margin: 5px;
top: 5px;
background-color:$bgcolor;
height: 45px;
width: 55px;
font-family: $buttonfont;
font-color: "black";
}
compiled to css with node-sass-chokidar
*/
-->
<link rel="stylesheet" type="text/css" href="game.css">
</head>
<body>
<div id="outerMask">
<div class="app-container" id="appContainer"></div>
</div>
<script src="https://cdn.rawgit.com/kittykatattack/hexi/835464c9/bin/hexi.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.0.2/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/15.0.2/react-dom.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/babel-core/5.8.23/browser.min.js"></script>
<script type="text/javascript" src="game.js"></script>
<script type="text/babel" src="gamereact.js"></script>
</script>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment