Skip to content

Commit

Permalink
feat: 🎸 Add splash screen, easy menu and game starting
Browse files Browse the repository at this point in the history
✅ Closes: #13
  • Loading branch information
MadejaMaciej committed Mar 8, 2024
1 parent e13e687 commit 148034a
Show file tree
Hide file tree
Showing 26 changed files with 343 additions and 20 deletions.
6 changes: 5 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
Lost Dutchman Mine Change Log
=============================

0.0.1 February 28 - March 12, 2024
0.0.2 March 24, 2024
-------------------

0.0.1 March 10, 2024
-------------------

- Enh #13: Loading the game + starting new game (MadejaMaciej)
- Enh #24: Import map assets (MadejaMaciej)
- Enh #25: Crop and import player animations + sort images to proper directories (MadejaMaciej)
- Enh #26: Crop and import city assets images (MadejaMaciej)
Expand Down
1 change: 1 addition & 0 deletions code-desktop/.env.dev
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
MODE=development
1 change: 1 addition & 0 deletions code-desktop/.env.live
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
MODE=live
4 changes: 3 additions & 1 deletion code-desktop/package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "california-49er-desktop-v1",
"productName": "california-49er-desktop-v1",
"version": "0.0.1",
"version": "0.0.2",
"description": "Lost dutchman mine game for desktop.",
"main": ".webpack/main",
"scripts": {
Expand Down Expand Up @@ -35,6 +35,7 @@
"electron": "^29.1.0",
"eslint": "^8.0.1",
"eslint-plugin-import": "^2.25.0",
"file-loader": "^6.2.0",
"fork-ts-checker-webpack-plugin": "^7.2.13",
"git-cz": "4.9.0",
"jest": "29.7.0",
Expand All @@ -53,6 +54,7 @@
},
"license": "MIT",
"dependencies": {
"dotenv": "^16.4.5",
"electron-squirrel-startup": "^1.0.0",
"react": "^18.2.0",
"react-dom": "^18.2.0"
Expand Down
11 changes: 9 additions & 2 deletions code-desktop/src/app.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
import { createRoot } from 'react-dom/client';
import Main from './components/Main';

const root = createRoot(document.body);
root.render(<Main />);
const el = document.getElementById('root');

if (el) {
const root = createRoot(el);
root.render(<Main />);
} else {
const root = createRoot(document.body);
root.render(<Main />);
}
100 changes: 94 additions & 6 deletions code-desktop/src/components/Main.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,99 @@
import React from "react";
import React, { useState, useEffect, useCallback } from "react";
import Menu from "./ui/Menu";
import Game from "./game/Game";
import splash from "../images/ui/cover.jpg";

function getWindowDimensions() {
const { innerWidth: width, innerHeight: height } = window;
return {
width,
height
};
}

let timeoutId: NodeJS.Timeout = null;

function Main() {
return (
<>
<h2>Hello from React!</h2>
</>
);
const [splashScreenOpacity, setSplashScreenOpacity] = useState(0.5);
const [lastUpdate, setLastUpdate] = useState(new Date().getTime());
const [windowDimensions, setWindowDimensions] = useState({
height: window.innerHeight,
width: window.innerWidth,
});
const [screen, setScreen] = useState('menu');
const [gameState, setGameState] = useState({
location: 'town',
backgroundAlt: 'Town background',
playerPosition: {
x: 0.5,
y: 0,
direction: 'down',
currentAnimation: 'idle'
}
});
const [language, setLanguage] = useState('en');

const loadGame = useCallback(() => {

}, []);

const setSplashInterval = useCallback(() => {
setInterval(() => {
const now = new Date().getTime();
const delta = now - lastUpdate;
const deltaModifier = delta / 100
setLastUpdate(now);
setSplashScreenOpacity(splashScreenOpacity + (0.02 * deltaModifier));
}, 20)
}, [])

useEffect(() => {
setSplashInterval();

function handleResize() {
if (timeoutId) {
clearTimeout(timeoutId);
timeoutId = null;
}

const id = setTimeout(() => {
setWindowDimensions(getWindowDimensions());
}, 100);

timeoutId = id;
}

window.addEventListener('resize', handleResize);
return () => window.removeEventListener('resize', handleResize);
});

useEffect(() => {
if (splashScreenOpacity >= 1) {
const interval_id = setInterval(function(){}, Number.MAX_SAFE_INTEGER);

for (let i = 1; i < Number(interval_id); i += 1) {
clearInterval(i);
}
}
}, [splashScreenOpacity])

if (splashScreenOpacity < 1) {
return (
<img
src={splash}
alt="Background splash screen"
width={windowDimensions.width}
height={windowDimensions.height}
style={{ opacity: splashScreenOpacity, transition: 'linear' }}
/>
)
}

if (screen === 'game') {
return <Game savedGame={gameState} setGameState={setGameState} windowDimensions={windowDimensions} />;
}

return <Menu loadGame={loadGame} setScreen={setScreen} language={language} setLanguage={setLanguage} />;
}

export default Main;
9 changes: 9 additions & 0 deletions code-desktop/src/components/common/MenuButton.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import React from "react";
import { MenuButtonProps } from "../../types/menu";

function MenuButton({ clickHandler, text, classes = '' }: MenuButtonProps) {

return <button className={classes} onClick={clickHandler}>{text}</button>
}

export default MenuButton;
8 changes: 8 additions & 0 deletions code-desktop/src/components/common/Subtitle.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import React from "react";
import { TextProps } from "../../types/menu";

function Subtitle({ text, classes = '' }: TextProps) {
return <h4 className={classes}>{text}</h4>
}

export default Subtitle;
8 changes: 8 additions & 0 deletions code-desktop/src/components/common/Text.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import React from "react";
import { TextProps } from "../../types/menu";

function Text({ text, classes = '' }: TextProps) {
return <p className={classes}>{text}</p>
}

export default Text;
8 changes: 8 additions & 0 deletions code-desktop/src/components/common/Title.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import React from "react";
import { TextProps } from "../../types/menu";

function Title({ text, classes = '' }: TextProps) {
return <h2 className={classes}>{text}</h2>
}

export default Title;
21 changes: 21 additions & 0 deletions code-desktop/src/components/game/Background.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import React from "react";
import { BackgroundProps } from "../../types/game";

const ratio = 12.7675752773;

function Background({ image, savedGame, windowDimensions }: BackgroundProps) {
const canvasWidth = ratio * windowDimensions.height;

return <img
src={image}
alt={savedGame.backgroundAlt}
height={windowDimensions.height}
style={{
position: 'absolute',
transition: 'linear',
left: -(canvasWidth * savedGame.playerPosition.x),
}}
/>
}

export default Background;
22 changes: 22 additions & 0 deletions code-desktop/src/components/game/Game.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import React from "react";
import Player from "./Player";
import Background from "./Background";
import { GameProps } from "../../types/game";
import map from "../../images/map/map.png";
import town from "../../images/map/town.png";

function Game({ savedGame, setGameState, windowDimensions }: GameProps) {
return (
<>
{
savedGame.location === "town" ?
<Background image={town} savedGame={savedGame} windowDimensions={windowDimensions} /> :
<Background image={map} savedGame={savedGame} windowDimensions={windowDimensions} />
}

<Player />
</>
);
}

export default Game;
19 changes: 19 additions & 0 deletions code-desktop/src/components/game/Player.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import React from "react";
import idleDown from "../../animations/player/down/idle.png";

function Player() {

return <img
src={idleDown}
alt={"Player"}
style={{
position: 'absolute',
transition: 'linear',
top: '80%',
left: '50%',
transform: 'translate(-50%, -50%)',
}}
/>
}

export default Player;
16 changes: 16 additions & 0 deletions code-desktop/src/components/ui/Language.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import React from "react";
import { LanguageProps } from "../../types/menu";

function Language({ language, setLanguage }: LanguageProps) {

return (
<>
<label htmlFor="language">Language</label>
<select name="language">
<option></option>
</select>
</>
)
}

export default Language;
26 changes: 26 additions & 0 deletions code-desktop/src/components/ui/Menu.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import React, { useCallback } from "react";
import Language from "./Language";
import MenuButton from "../common/MenuButton";
import Title from "../common/Title";
import { MenuProps } from "../../types/menu";

function Menu({ loadGame, setScreen, language, setLanguage }: MenuProps) {
const quitGame = useCallback(() => {
window.close();
}, []);

const startNewGame = useCallback(() => {
setScreen('game')
}, [])

return (
<div>
<Title classes="center white" text="Main Menu" />
<Language language={language} setLanguage={setLanguage} />
<MenuButton clickHandler={startNewGame} text={'Start game'} />
<MenuButton clickHandler={quitGame} text={'Quit game'} />
</div>
)
}

export default Menu;
Binary file added code-desktop/src/images/map/town.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 2 additions & 2 deletions code-desktop/src/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@
<html>
<head>
<meta charset="UTF-8" />
<title>Hello World!</title>
<title>Lost Dutchman Mine</title>

</head>
<body>

<div id="root"></div>
</body>
</html>
10 changes: 8 additions & 2 deletions code-desktop/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import { app, BrowserWindow } from 'electron';
import { app, ipcMain, BrowserWindow } from 'electron';
import 'dotenv/config';

// This allows TypeScript to pick up the magic constants that's auto-generated by Forge's Webpack
// plugin that tells the Electron app where to look for the Webpack-bundled app code (depending on
// whether you're running in development or production).
Expand All @@ -20,11 +22,15 @@ const createWindow = (): void => {
},
});

mainWindow.setMenuBarVisibility(false);

// and load the index.html of the app.
mainWindow.loadURL(MAIN_WINDOW_WEBPACK_ENTRY);

// Open the DevTools.
mainWindow.webContents.openDevTools();
if (process.env.MODE === 'development') {
mainWindow.webContents.openDevTools();
}
};

// This method will be called when Electron has finished
Expand Down
17 changes: 14 additions & 3 deletions code-desktop/src/styles/index.css
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,18 @@

body {
font-family: 'handjet';
margin: auto;
max-width: 38rem;
padding: 2rem;
margin: 0;
padding: 0;
background-color: #000;
overflow-y: hidden;
overflow-x: hidden;
}

.center {
text-align: center;
margin: 0 auto;
}

.white {
color: #fff;
}
Loading

0 comments on commit 148034a

Please sign in to comment.