Created
October 19, 2018 10:36
-
-
Save Rukia3d/92dd31ed8e7dc18cc2b3b2add25afa6a to your computer and use it in GitHub Desktop.
Electron Fiddle Gist
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!DOCTYPE html> | |
<html> | |
<head> | |
<meta charset="UTF-8"> | |
<title>CARD CRAWL CLONE</title> | |
<style> | |
body { | |
text-align: center; | |
} | |
table { | |
margin: 0 auto; | |
} | |
td { | |
width: 100px; | |
height: 150px; | |
border: 1, solid, black; | |
background-color: grey; | |
} | |
.filled { | |
background-color: blue; | |
} | |
.target { | |
background-color: red; | |
} | |
.hover { | |
background-color: green; | |
} | |
</style> | |
</head> | |
<body> | |
<h1>Card Crawl Clone!</h1> | |
<div id="print"></div> | |
<div id="container"> | |
<table> | |
<tr id="enemyHand"> | |
<td data-index="0"></td> | |
<td data-index="1"></td> | |
<td data-index="2"></td> | |
<td data-index="3"></td> | |
</tr> | |
<tr id="playerHand"> | |
<td data-index="0"></td> | |
<td data-index="1"></td> | |
<td data-index="2"></td> | |
<td data-index="3"></td> | |
</tr> | |
</table> | |
</div> | |
<script> | |
// You can also require other files to run in this process | |
require('./renderer.js') | |
</script> | |
</body> | |
</html> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
THIS IS BACKEND FOR THE WORKSHOP FIDDLING WITH ELECTEON FIDLE | |
CREATED FOR NODEGIRLS SYDNEY | |
CLONE OF THE GAME MECHANICS FROM "CARD CRAWL" | |
*/ | |
// Modules to control application life and create native browser window | |
const {app, ipcMain, BrowserWindow} = require('electron') | |
// Keep a global reference of the window object, if you don't, the window will | |
// be closed automatically when the JavaScript object is garbage collected. | |
let mainWindow | |
// Global Game State Object and cards that we're going to use in the game. | |
let heroIndex = 1; | |
let heroCard = { name: "hero", health: 10, type: "hero" }; | |
let gso = { | |
deck: [], | |
enemyHand: [null, null, null, null], | |
playerHand: [null, null, null, null], | |
state: "PLAY" | |
} | |
let cardsArray = [ | |
{ name: "sword", power: 3, type: "attack" }, | |
{ name: "sword", power: 3, type: "attack" }, | |
{ name: "sword", power: 3, type: "attack" }, | |
{ name: "shield", power: 3, type: "shield" }, | |
{ name: "shield", power: 3, type: "shield" }, | |
{ name: "shield", power: 3, type: "shield" }, | |
{ name: "heal", power: 3, type: "heal" }, | |
{ name: "heal", power: 3, type: "heal" }, | |
{ name: "heal", power: 3, type: "heal" }, | |
{ name: "troll", health: 3, power: 3, type: "enemy" }, | |
{ name: "troll", health: 3, power: 3, type: "enemy" }, | |
{ name: "troll", health: 3, power: 3, type: "enemy" }, | |
{ name: "ghost", health: 3, power: 3, type: "enemy" }, | |
{ name: "ghost", health: 3, power: 3, type: "enemy" }, | |
{ name: "ghost", health: 3, power: 3, type: "enemy" }, | |
{ name: "witch", health: 3, power: 3, type: "enemy" }, | |
{ name: "witch", health: 3, power: 3, type: "enemy" }, | |
{ name: "witch", health: 3, power: 3, type: "enemy" }, | |
] | |
function createWindow () { | |
// Create the browser window. | |
mainWindow = new BrowserWindow({width: 800, height: 600}) | |
// and load the index.html of the app. | |
mainWindow.loadFile('index.html') | |
// Open the DevTools. | |
mainWindow.webContents.openDevTools() | |
// Emitted when the window is closed. | |
mainWindow.on('closed', function () { | |
// Dereference the window object, usually you would store windows | |
// in an array if your app supports multi windows, this is the time | |
// when you should delete the corresponding element. | |
mainWindow = null | |
}) | |
} | |
// This method will be called when Electron has finished | |
// initialization and is ready to create browser windows. | |
// Some APIs can only be used after this event occurs. | |
app.on('ready', createWindow) | |
// Quit when all windows are closed. | |
app.on('window-all-closed', function () { | |
// On OS X it is common for applications and their menu bar | |
// to stay active until the user quits explicitly with Cmd + Q | |
if (process.platform !== 'darwin') { | |
app.quit() | |
} | |
}) | |
app.on('activate', function () { | |
// On OS X it's common to re-create a window in the app when the | |
// dock icon is clicked and there are no other windows open. | |
if (mainWindow === null) { | |
createWindow() | |
} | |
}) | |
// In this file you can include the rest of your app's specific main process | |
// code. You can also put them in separate files and require them here. | |
ipcMain.on('MSG', (event, arg) => { | |
// Save changed object | |
let received = msgReceived(arg); | |
// Send back the answer with the object | |
mainWindow.webContents.send("GSO", received); | |
}); | |
// Parse the message to call a relevant function | |
function msgReceived(arg){ | |
console.log("Received message "+arg.id); | |
switch(arg.id){ | |
case "START": | |
return createGso(); | |
case "ACT": | |
return actParsed(arg.active, arg.target); | |
default: | |
console.log("Unknown message "+ arg); | |
return gso; | |
} | |
} | |
// Function to give cards if the number of empty cards is >= 3 | |
function giveCards(){ | |
// Check the number of empty cards in enemy hand | |
const cardsEmpty = gso.enemyHand.filter(function(e){ | |
return !e; | |
}).length; | |
if(cardsEmpty < 3) { | |
return; | |
} | |
for(var i=0; i<gso.enemyHand.length; i++){ | |
if(!gso.enemyHand[i]){ | |
gso.enemyHand[i] = gso.deck.pop() | |
} | |
} | |
} | |
// Based on the game logic check if the player won or lost or game continues | |
function checkGameState(){ | |
if(gso.playerHand[heroIndex].health <=0 ){ | |
gso.state = "LOST"; | |
} else if(gso.deck.length == 0){ | |
gso.state = "WON"; | |
} else { | |
giveCards(); | |
gso.state = "PLAY"; | |
} | |
} | |
// Remove used card only if it's not hero card | |
function removeCard(card, position){ | |
if(card.type=="hero"){ | |
return; | |
} | |
gso[position.row][position.index] = null; | |
} | |
// The initial GSP creation | |
function createGso(){ | |
let newDeck = cardsArray.sort(() => Math.random() - 0.5); | |
gso.deck = newDeck; | |
gso.playerHand[heroIndex] = heroCard; | |
giveCards(); | |
return gso; | |
} | |
// Analyse the player's action and based on the 2 cards from message | |
// Determine the act result | |
function actParsed(active, target){ | |
console.log(active, target); | |
let card1 = gso[active.row][active.index]; | |
let card2 = gso[target.row][target.index]; | |
console.log(card1, card2); | |
if(card2==null){ | |
console.log("Got an empty space"); | |
gso[target.row][target.index] = card1; | |
} else { | |
if(card2.type=="hero"){ | |
console.log("got an attack against hero"); | |
gso.playerHand[heroIndex].health = gso.playerHand[heroIndex].health - card1.power; | |
removeCard(card2, target); | |
} | |
if(card2.type=="shield"){ | |
console.log("got an attack against shield"); | |
removeCard(card2, target); | |
} | |
if(card1.type=="attack"){ | |
console.log("hero attacks enemy"); | |
removeCard(card2, target); | |
} | |
} | |
removeCard(card1, active); | |
if(card1.type=="heal" && target.index!=3){ | |
gso.playerHand[heroIndex].health = gso.playerHand[heroIndex].health + card1.power; | |
gso.playerHand[target.index] = null; | |
} | |
checkGameState(); | |
return gso; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
THIS IS FRONTED FOR THE WORKSHOP FIDDLING WITH ELECTEON FIDLE | |
CREATED FOR NODEGIRLS SYDNEY | |
CLONE OF THE GAME MECHANICS FROM "CARD CRAWL" | |
*/ | |
const { ipcRenderer } = require('electron') | |
// We need to keep selected card to reference it | |
// And a global GSO that comes from the backend | |
let selectedCard = null //{ row: null, index: null }; | |
let gso; | |
// Grab the selected card from the event target | |
function findSelectedCard(target){ | |
return { row: target.parentElement.id, index: target.dataset.index }; | |
} | |
// Communcation function that sends messages to backend | |
function sendMessage(obj){ | |
//console.log("Sending a message with", obj); | |
ipcRenderer.send('MSG', obj); | |
} | |
// When we start dragging - save the card that we use and redraw the table | |
function onDragStart(event){ | |
//console.log("Drag started ", event); | |
selectedCard = findSelectedCard(event.target); | |
renderTable(); | |
} | |
// When we finish dragging the card around, remove the selected card and redraw the table | |
function onDragEnd(event){ | |
//console.log("Drag ended ", event); | |
selectedCard = null; | |
renderTable(); | |
} | |
// When the drag is over - remove styled from the available targets | |
function onDragOver(event){ | |
//console.log("Drag Over ", event); | |
if(event.target.classList.contains("target")){ | |
event.target.classList.add("hover"); | |
event.preventDefault(); | |
} | |
} | |
// When we leave the card, remove the style from the selected target | |
function onDragLeave(event){ | |
//console.log("Drag Leave ", event); | |
event.target.classList.remove("hover"); | |
} | |
// When we drop the card, send message to the backend | |
function onDrop(event){ | |
//console.log("Drop Event ", event); | |
event.preventDefault(); | |
sendMessage({id: "ACT", active: selectedCard, target: findSelectedCard(event.target)}); | |
selectedCard = null; | |
} | |
// Check if this action satisfies all the game logic conditions | |
function isDropTarget(targetCard, targetRow){ | |
console.log("Selected card ", selectedCard); | |
const selectedType = selectedCard ? gso[selectedCard.row][selectedCard.index].type : null; | |
//console.log("Selected type ", selectedType); | |
if(!selectedType){ | |
return false; | |
} | |
if(targetCard==null){ | |
// we're dragging a card to an empty slot | |
if(targetRow=="playerHand" && selectedType != 'enemy') { | |
// we can only put into empty spot in a hand a shield, potion or sword | |
if(selectedCard.row=="playerHand" && selectedCard.index!=3){ | |
// we can move card from pocket to hand, but not back to the pocket | |
return false; | |
} | |
return true; | |
} | |
} else { | |
console.log(targetRow, selectedType); | |
// the slot is taken | |
if(targetRow=="playerHand" && selectedType == 'enemy'){ | |
// enemy card can only attack hero and shields | |
if(targetCard.type=="hero" || targetCard.type=="shield"){ | |
return true; | |
} | |
} | |
// sword can only attack if it's in player's hand and the enemy is in the enemy's hand | |
if(targetRow=="enemyHand" && selectedType=="attack" && selectedCard.row=="playerHand" && selectedCard.index!=3 && targetCard.type=="enemy"){ | |
console.log("Here we are") | |
return true; | |
} | |
} | |
return false; | |
} | |
function renderCell(card, cell, row){ | |
cell.className = ""; | |
cell.innerHTML = ""; | |
cell.draggable = false; | |
if(isDropTarget(card, row)){ | |
cell.classList.add("target"); | |
} | |
if(card){ | |
let description = "Card:"+card.name+"</br>"; | |
if(card.type=="hero"){ | |
description = description+"Health: "+card.health; | |
} else if(card.type=="enemy"){ | |
description = description+"Attack: "+card.power+"</br>Health: "+card.health; | |
} else { | |
description = description+"Power: "+card.power; | |
} | |
cell.classList.add("filled"); | |
cell.innerHTML = description; | |
cell.draggable = card.type != "hero"; | |
} | |
} | |
function renderRow(hand, selector){ | |
const cells = document.getElementById(selector).children; | |
for(let i=0; i<hand.length; i++){ | |
renderCell(hand[i], cells[i], selector); | |
} | |
} | |
function renderTable(){ | |
renderRow(gso.enemyHand, "enemyHand"); | |
renderRow(gso.playerHand, "playerHand"); | |
} | |
function startGame(){ | |
ipcRenderer.on("GSO", (event, arg) => { | |
renderGame(arg); | |
}); | |
let container = document.getElementById("container"); | |
container.addEventListener("dragstart", onDragStart); | |
container.addEventListener("dragend", onDragEnd); | |
container.addEventListener("dragover", onDragOver); | |
container.addEventListener("dragleave", onDragLeave); | |
container.addEventListener("drop", onDrop); | |
sendMessage({id: "START"}); | |
} | |
function renderGame(newGso){ | |
gso = newGso; | |
console.log(gso); | |
switch(gso.state){ | |
case "PLAY": | |
renderTable(); | |
console.log("Playing") | |
break; | |
case "LOST": | |
window.alert("You lost!"); | |
break; | |
case "WON": | |
window.alert("You won!"); | |
break; | |
} | |
} | |
startGame(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment