init
14
.babelrc
Normal file
@ -0,0 +1,14 @@
|
||||
{
|
||||
"presets": [
|
||||
["@babel/env", {
|
||||
"targets": {
|
||||
"browsers": [
|
||||
">0.25%",
|
||||
"not ie 11",
|
||||
"not op_mini all"
|
||||
]
|
||||
},
|
||||
"modules": false
|
||||
}]
|
||||
],
|
||||
}
|
||||
36
.gitignore
vendored
Normal file
@ -0,0 +1,36 @@
|
||||
#MIT License
|
||||
|
||||
#Copyright (c) 2017 Richard Davey
|
||||
|
||||
#Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
#of this software and associated documentation files (the "Software"), to deal
|
||||
#in the Software without restriction, including without limitation the rights
|
||||
#to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
#copies of the Software, and to permit persons to whom the Software is
|
||||
#furnished to do so, subject to the following conditions:
|
||||
|
||||
#The above copyright notice and this permission notice shall be included in all
|
||||
#copies or substantial portions of the Software.
|
||||
|
||||
#THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
#IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
#FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
#AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
#LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
#OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
#SOFTWARE.
|
||||
|
||||
# System and IDE files
|
||||
Thumbs.db
|
||||
.DS_Store
|
||||
.idea
|
||||
*.suo
|
||||
*.sublime-project
|
||||
*.sublime-workspace
|
||||
|
||||
# Vendors
|
||||
node_modules/
|
||||
|
||||
# Build
|
||||
dist/
|
||||
/npm-debug.log
|
||||
5
.prettierrc
Normal file
@ -0,0 +1,5 @@
|
||||
{
|
||||
"trailingComma": "none",
|
||||
"tabWidth": 2,
|
||||
"useTabs": false
|
||||
}
|
||||
71
README.md
Normal file
@ -0,0 +1,71 @@
|
||||
/*MIT License
|
||||
|
||||
Copyright (c) 2017 Richard Davey
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.*/
|
||||
|
||||
# Phaser 3 Webpack Project Template
|
||||
|
||||
A Phaser 3 project template with ES6 support via [Babel 7](https://babeljs.io/) and [Webpack 4](https://webpack.js.org/) that includes hot-reloading for development and production-ready builds.
|
||||
|
||||
This has been updated for Phaser 3.50.0 version and above.
|
||||
|
||||
Loading images via JavaScript module `import` is also supported, although not recommended.
|
||||
|
||||
## Requirements
|
||||
|
||||
[Node.js](https://nodejs.org) is required to install dependencies and run scripts via `npm`.
|
||||
|
||||
## Available Commands
|
||||
|
||||
| Command | Description |
|
||||
|---------|-------------|
|
||||
| `npm install` | Install project dependencies |
|
||||
| `npm start` | Build project and open web server running project |
|
||||
| `npm run build` | Builds code bundle with production settings (minification, uglification, etc..) |
|
||||
|
||||
## Writing Code
|
||||
|
||||
After cloning the repo, run `npm install` from your project directory. Then, you can start the local development server by running `npm start`.
|
||||
|
||||
After starting the development server with `npm start`, you can edit any files in the `src` folder and webpack will automatically recompile and reload your server (available at `http://localhost:8080` by default).
|
||||
|
||||
## Customizing the Template
|
||||
|
||||
### Babel
|
||||
|
||||
You can write modern ES6+ JavaScript and Babel will transpile it to a version of JavaScript that you want your project to support. The targeted browsers are set in the `.babelrc` file and the default currently targets all browsers with total usage over "0.25%" but excludes IE11 and Opera Mini.
|
||||
|
||||
```
|
||||
"browsers": [
|
||||
">0.25%",
|
||||
"not ie 11",
|
||||
"not op_mini all"
|
||||
]
|
||||
```
|
||||
|
||||
### Webpack
|
||||
|
||||
If you want to customize your build, such as adding a new webpack loader or plugin (i.e. for loading CSS or fonts), you can modify the `webpack/base.js` file for cross-project changes, or you can modify and/or create new configuration files and target them in specific npm tasks inside of `package.json'.
|
||||
|
||||
## Deploying Code
|
||||
|
||||
After you run the `npm run build` command, your code will be built into a single bundle located at `dist/bundle.min.js` along with any other assets you project depended.
|
||||
|
||||
If you put the contents of the `dist` folder in a publicly-accessible location (say something like `http://mycoolserver.com`), you should be able to open `http://mycoolserver.com/index.html` and play your game.
|
||||
17
index.html
Normal file
@ -0,0 +1,17 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta
|
||||
name="viewport"
|
||||
content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no"
|
||||
/>
|
||||
<style>
|
||||
body {
|
||||
margin: 0;
|
||||
height: 100%;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body></body>
|
||||
</html>
|
||||
9357
package-lock.json
generated
Normal file
39
package.json
Normal file
@ -0,0 +1,39 @@
|
||||
{
|
||||
"name": "phaser3-project-template",
|
||||
"version": "1.1.2",
|
||||
"description": "A Phaser 3 Project Template",
|
||||
"main": "src/index.js",
|
||||
"scripts": {
|
||||
"build": "export NODE_OPTIONS=--openssl-legacy-provider && webpack --config webpack/prod.js ",
|
||||
"dev-build": "export NODE_OPTIONS=--openssl-legacy-provider && webpack --config webpack/base.js ",
|
||||
"start": "export NODE_OPTIONS=--openssl-legacy-provider && webpack-dev-server --config webpack/base.js --open"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/photonstorm/phaser3-project-template.git"
|
||||
},
|
||||
"author": "Richard Davey <rdavey@gmail.com> (http://www.photonstorm.com)",
|
||||
"license": "MIT",
|
||||
"licenseUrl": "http://www.opensource.org/licenses/mit-license.php",
|
||||
"bugs": {
|
||||
"url": "https://github.com/photonstorm/phaser3-project-template/issues"
|
||||
},
|
||||
"homepage": "https://github.com/photonstorm/phaser3-project-template#readme",
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.7.2",
|
||||
"@babel/preset-env": "^7.7.1",
|
||||
"babel-loader": "^8.0.6",
|
||||
"clean-webpack-plugin": "^3.0.0",
|
||||
"file-loader": "^4.2.0",
|
||||
"html-webpack-plugin": "^3.2.0",
|
||||
"raw-loader": "^3.1.0",
|
||||
"terser-webpack-plugin": "^2.2.1",
|
||||
"webpack": "^4.41.2",
|
||||
"webpack-cli": "^3.3.10",
|
||||
"webpack-dev-server": "^3.9.0",
|
||||
"webpack-merge": "^4.2.2"
|
||||
},
|
||||
"dependencies": {
|
||||
"phaser": "^3.50.0"
|
||||
}
|
||||
}
|
||||
BIN
src/assets/chico-bald.png
Normal file
|
After Width: | Height: | Size: 300 KiB |
BIN
src/assets/chico-carpet.png
Normal file
|
After Width: | Height: | Size: 238 KiB |
BIN
src/assets/chico-corner.png
Normal file
|
After Width: | Height: | Size: 304 KiB |
BIN
src/assets/chico-couch.png
Normal file
|
After Width: | Height: | Size: 275 KiB |
BIN
src/assets/chico-ears.png
Normal file
|
After Width: | Height: | Size: 430 KiB |
BIN
src/assets/chico-eating.png
Normal file
|
After Width: | Height: | Size: 346 KiB |
BIN
src/assets/chico-house.png
Normal file
|
After Width: | Height: | Size: 328 KiB |
BIN
src/assets/chico-loaf.png
Normal file
|
After Width: | Height: | Size: 209 KiB |
BIN
src/assets/chico-nose.png
Normal file
|
After Width: | Height: | Size: 341 KiB |
BIN
src/assets/chico-sleep.png
Normal file
|
After Width: | Height: | Size: 396 KiB |
BIN
src/assets/chico-vent.png
Normal file
|
After Width: | Height: | Size: 173 KiB |
BIN
src/assets/chico-withears.png
Normal file
|
After Width: | Height: | Size: 264 KiB |
BIN
src/assets/full-bald.jpg
Normal file
|
After Width: | Height: | Size: 414 KiB |
BIN
src/assets/full-carpet.jpg
Normal file
|
After Width: | Height: | Size: 328 KiB |
BIN
src/assets/full-corner.jpg
Normal file
|
After Width: | Height: | Size: 554 KiB |
BIN
src/assets/full-couch.jpg
Normal file
|
After Width: | Height: | Size: 411 KiB |
BIN
src/assets/full-ears.jpg
Executable file
|
After Width: | Height: | Size: 3.2 MiB |
BIN
src/assets/full-eating.jpg
Normal file
|
After Width: | Height: | Size: 443 KiB |
BIN
src/assets/full-house.jpg
Normal file
|
After Width: | Height: | Size: 510 KiB |
BIN
src/assets/full-loaf.jpg
Normal file
|
After Width: | Height: | Size: 193 KiB |
BIN
src/assets/full-nose.jpg
Normal file
|
After Width: | Height: | Size: 539 KiB |
BIN
src/assets/full-sleep.jpg
Normal file
|
After Width: | Height: | Size: 451 KiB |
BIN
src/assets/full-vent.jpg
Normal file
|
After Width: | Height: | Size: 116 KiB |
BIN
src/assets/full-withears.jpg
Normal file
|
After Width: | Height: | Size: 78 KiB |
BIN
src/assets/lapi.png
Normal file
|
After Width: | Height: | Size: 196 KiB |
BIN
src/assets/question.jpg
Normal file
|
After Width: | Height: | Size: 2.1 KiB |
74
src/components/Button.js
Normal file
@ -0,0 +1,74 @@
|
||||
import Phaser from "phaser";
|
||||
|
||||
const WHITE = 0xffffff;
|
||||
const OFFWHITE = 0xeeeeee;
|
||||
|
||||
export default class Button extends Phaser.GameObjects.Graphics {
|
||||
constructor(
|
||||
scene,
|
||||
x,
|
||||
y,
|
||||
width,
|
||||
height,
|
||||
radius = 16,
|
||||
label = "",
|
||||
labelSize = 20,
|
||||
color = OFFWHITE
|
||||
) {
|
||||
super(scene);
|
||||
|
||||
this.fillStyle(color);
|
||||
this.fillRoundedRect(x, y, width, height, radius); // avoid redraw later
|
||||
|
||||
this.hitRect = scene.add.rectangle(x, y, width, height);
|
||||
this.setInteractive(this.hitRect, Phaser.Geom.Rectangle.Contains)
|
||||
.on("pointerup", this.handleUp, this)
|
||||
.on("pointerout", this.handleOut, this)
|
||||
.on("pointerdown", this.handleDown, this)
|
||||
.on("pointerover", this.handleOver, this);
|
||||
|
||||
this.pressedRect = scene.add.rectangle(
|
||||
x + width * (1 / 2),
|
||||
y + height * (1 / 2),
|
||||
width * (4 / 5),
|
||||
height * (4 / 5),
|
||||
0x000000,
|
||||
1
|
||||
); // add a rectangle to show when the button is pressed
|
||||
this.pressedRect.setAlpha(0); // needed for it to show at all
|
||||
this.pressedRect.setDepth(1); // bring to front
|
||||
|
||||
this.label = scene.add
|
||||
.text(x, y, label, {
|
||||
fontFamily: "sans-serif",
|
||||
fontSize: labelSize,
|
||||
color: "#000000",
|
||||
align: "center",
|
||||
wordWrap: { width: width + 4, useAdvancedWrap: true }
|
||||
})
|
||||
.setDepth(1);
|
||||
this.setLabel(label);
|
||||
}
|
||||
|
||||
handleUp(pointer) {
|
||||
this.handleOut(pointer);
|
||||
}
|
||||
|
||||
handleOut(pointer) {
|
||||
this.pressedRect.setAlpha(0);
|
||||
}
|
||||
|
||||
handleDown(pointer) {
|
||||
this.pressedRect.setAlpha(0.25);
|
||||
}
|
||||
|
||||
handleOver(pointer) {
|
||||
if (pointer.wasTouch) this.pressedRect.setAlpha(0.25);
|
||||
}
|
||||
|
||||
setLabel(label) {
|
||||
this.label.setText(label);
|
||||
this.label.setX(this.hitRect.x + (this.hitRect.width - this.label.width) / 2); // (bWidth - tWidth) / 2 = margin
|
||||
this.label.setY(this.hitRect.y + (this.hitRect.height - this.label.height) / 2); // (bHeight - tHeight) / 2 = margin
|
||||
}
|
||||
}
|
||||
241
src/components/ShopItem.js
Normal file
@ -0,0 +1,241 @@
|
||||
import Phaser from "phaser";
|
||||
|
||||
import Button from "../components/Button";
|
||||
|
||||
export default class ShopItem extends Phaser.GameObjects.Container {
|
||||
constructor(
|
||||
scene,
|
||||
x,
|
||||
y,
|
||||
width,
|
||||
height = width,
|
||||
children,
|
||||
label = "Sample Chico",
|
||||
imgKey = "",
|
||||
startCost = 1,
|
||||
production = 0,
|
||||
description = "",
|
||||
ears = false
|
||||
) {
|
||||
super(scene, x, y, children);
|
||||
this.locked = true;
|
||||
this.startCost = startCost;
|
||||
this.imgKey = imgKey;
|
||||
this.nextCost = startCost;
|
||||
this.count = 0;
|
||||
|
||||
this.label = scene.add.text(0, 0, label, {
|
||||
fontFamily: "sans-serif",
|
||||
fontSize: 22,
|
||||
color: "#000000",
|
||||
})
|
||||
|
||||
this.label.visible = false;
|
||||
|
||||
this.img = scene.add
|
||||
.image(0, this.label.height + 2, imgKey)
|
||||
.setScale(0.25)
|
||||
.setOrigin(0, 0);
|
||||
|
||||
this.lockedImg = scene.add
|
||||
.image(0, this.label.height + 2, "locked")
|
||||
.setScale(0.71)
|
||||
.setOrigin(-0.05, 0.01);
|
||||
|
||||
this.description = scene.add
|
||||
.text(width / 2, this.label.height + 8, description, {
|
||||
fontFamily: "sans-serif",
|
||||
fontSize: 17,
|
||||
color: "#ffffff",
|
||||
stroke: "#000000",
|
||||
strokeThickness: 1,
|
||||
align: "left",
|
||||
fixedWidth: this.img.displayWidth,
|
||||
wordWrap: { width: this.img.displayWidth, useAdvancedWrap: true }
|
||||
})
|
||||
.setOrigin(0.475, 0.1);
|
||||
this.description.visible = false;
|
||||
|
||||
this.costLabel = scene.add
|
||||
.text(
|
||||
width / 2,
|
||||
this.label.height + this.img.displayHeight - 20,
|
||||
`Cost: ${this.nextCost}`,
|
||||
{
|
||||
fontFamily: "sans-serif",
|
||||
fontSize: 18,
|
||||
color: "#ffffff",
|
||||
stroke: "#000000",
|
||||
strokeThickness: 1,
|
||||
align: "left",
|
||||
fixedWidth: this.img.displayWidth,
|
||||
wordWrap: { width: this.img.displayWidth, useAdvancedWrap: true }
|
||||
}
|
||||
)
|
||||
.setOrigin(0.475, 0.1);
|
||||
this.costLabel.visible = false;
|
||||
|
||||
this.countLabel = scene.add
|
||||
.text(width / 2, this.costLabel.y - 18, `Count: ${this.count}`, {
|
||||
fontFamily: "sans-serif",
|
||||
fontSize: 18,
|
||||
color: "#ffffff",
|
||||
stroke: "#000000",
|
||||
strokeThickness: 1,
|
||||
align: "left",
|
||||
fixedWidth: this.img.displayWidth,
|
||||
wordWrap: { width: this.img.displayWidth, useAdvancedWrap: true }
|
||||
})
|
||||
.setOrigin(0.475, 0.1);
|
||||
this.countLabel.visible = false;
|
||||
|
||||
this.label.setX(width / 2).setOrigin(0.5, 0);
|
||||
this.img.setX((width - this.img.displayWidth) / 2);
|
||||
|
||||
const setStatsVisible = (visible) => {
|
||||
this.description.visible = visible;
|
||||
this.costLabel.visible = visible;
|
||||
this.countLabel.visible = visible;
|
||||
};
|
||||
|
||||
scene.input.on("pointerdown", (pointer) => {
|
||||
if (pointer.wasTouch) {
|
||||
setStatsVisible(false); // pointerout doesn't work on mobile
|
||||
}
|
||||
});
|
||||
|
||||
this.img.setInteractive();
|
||||
this.img.on("pointerover", () => setStatsVisible(true));
|
||||
this.img.on("pointerout", (pointer) => {
|
||||
if (!pointer.wasTouch) {
|
||||
setStatsVisible(false);
|
||||
}
|
||||
});
|
||||
|
||||
let items = [
|
||||
this.label,
|
||||
this.img,
|
||||
this.description,
|
||||
this.countLabel,
|
||||
this.lockedImg,
|
||||
this.costLabel,
|
||||
];
|
||||
|
||||
if (ears) {
|
||||
this.buyEars = new Button(
|
||||
scene,
|
||||
8,
|
||||
height - 25,
|
||||
width - 16,
|
||||
24,
|
||||
8,
|
||||
"Buy Chico Ears",
|
||||
16
|
||||
);
|
||||
this.buyEars.on("pointerup", () => {
|
||||
if (this.nextCost <= scene.chicos) {
|
||||
scene.chicos -= this.nextCost;
|
||||
this.count++;
|
||||
this.countLabel.setText(`Count: ${this.count}`);
|
||||
} else {
|
||||
this.buyEars.setLabel("No Chicos");
|
||||
setTimeout(() => {
|
||||
this.buyEars.setLabel("Buy Chico Ears");
|
||||
}, 2000);
|
||||
}
|
||||
});
|
||||
scene.add.existing(this.buyEars);
|
||||
items = [
|
||||
...items,
|
||||
this.buyEars,
|
||||
this.buyEars.pressedRect,
|
||||
this.buyEars.label
|
||||
];
|
||||
} else {
|
||||
this.buyOne = new Button(
|
||||
scene,
|
||||
4,
|
||||
height - 24,
|
||||
width / 2 - 8,
|
||||
24,
|
||||
8,
|
||||
"Buy One",
|
||||
14
|
||||
);
|
||||
scene.add.existing(this.buyOne);
|
||||
this.buyOne.on("pointerup", () => {
|
||||
if (this.nextCost <= scene.chicos) {
|
||||
scene.chicos -= this.nextCost;
|
||||
scene.perSecond += production;
|
||||
this.count++;
|
||||
this.countLabel.setText(`Count: ${this.count}`);
|
||||
this.nextCost = Math.round(startCost * Math.pow(1.05, this.count + 1) + 1); this.costLabel.setText(`Cost: ${this.nextCost}`);
|
||||
} else {
|
||||
this.buyOne.setLabel("No Chicos");
|
||||
setTimeout(() => {
|
||||
this.buyOne.setLabel("Buy One");
|
||||
}, 2000);
|
||||
}
|
||||
});
|
||||
this.buyOne.on("pointerover", (pointer) => {
|
||||
setStatsVisible(true);
|
||||
});
|
||||
this.buyOne.on("pointerout", (pointer) => {
|
||||
if (!pointer.wasTouch) {
|
||||
setStatsVisible(false);
|
||||
}
|
||||
});
|
||||
|
||||
this.buyMax = new Button(
|
||||
scene,
|
||||
width / 2 + 4,
|
||||
height - 24,
|
||||
width / 2 - 8,
|
||||
24,
|
||||
8,
|
||||
"Buy Max",
|
||||
14
|
||||
);
|
||||
scene.add.existing(this.buyMax);
|
||||
|
||||
this.buyMax.on("pointerup", () => {
|
||||
let bought = 0;
|
||||
while (this.nextCost <= scene.chicos) {
|
||||
bought++;
|
||||
scene.chicos -= this.nextCost;
|
||||
scene.perSecond += production;
|
||||
this.count++;
|
||||
this.countLabel.setText(`Count: ${this.count}`);
|
||||
this.nextCost = Math.round((this.nextCost + 1) * 1.4);
|
||||
this.costLabel.setText(`Cost: ${this.nextCost}`);
|
||||
}
|
||||
this.buyMax.setLabel(`Bought ${bought}`);
|
||||
setTimeout(() => {
|
||||
this.buyMax.setLabel("Buy Max");
|
||||
}, 2000);
|
||||
});
|
||||
this.buyMax.on("pointerover", () => {
|
||||
setStatsVisible(true);
|
||||
});
|
||||
this.buyMax.on("pointerout", (pointer) => {
|
||||
if (!pointer.wasTouch) {
|
||||
setStatsVisible(false);
|
||||
}
|
||||
});
|
||||
|
||||
items = [
|
||||
...items,
|
||||
this.buyOne,
|
||||
this.buyOne.pressedRect,
|
||||
this.buyOne.label,
|
||||
this.buyMax,
|
||||
this.buyMax.pressedRect,
|
||||
this.buyMax.label
|
||||
];
|
||||
}
|
||||
|
||||
this.add(items);
|
||||
|
||||
scene.add.existing(this);
|
||||
}
|
||||
}
|
||||
47
src/index.js
Normal file
@ -0,0 +1,47 @@
|
||||
import Phaser from "phaser";
|
||||
import Handler from "./scenes/handler.js";
|
||||
import Game from "./scenes/game.js";
|
||||
|
||||
// 9:16 portrait
|
||||
const MAX_SIZE_WIDTH_SCREEN = 1920
|
||||
const MAX_SIZE_HEIGHT_SCREEN = 1080
|
||||
const MIN_SIZE_WIDTH_SCREEN = 150
|
||||
const MIN_SIZE_HEIGHT_SCREEN = 270
|
||||
const SIZE_WIDTH_SCREEN = 450
|
||||
const SIZE_HEIGHT_SCREEN = 800
|
||||
|
||||
const config = {
|
||||
type: Phaser.CANVAS,
|
||||
parent: "phaser-example",
|
||||
scale: {
|
||||
mode: Phaser.Scale.RESIZE,
|
||||
autoCenter: Phaser.Scale.CENTER_VERTICALLY,
|
||||
width: SIZE_WIDTH_SCREEN,
|
||||
height: SIZE_HEIGHT_SCREEN,
|
||||
min: {
|
||||
width: MIN_SIZE_WIDTH_SCREEN,
|
||||
height: MIN_SIZE_HEIGHT_SCREEN
|
||||
},
|
||||
max: {
|
||||
width: MAX_SIZE_WIDTH_SCREEN,
|
||||
height: MAX_SIZE_HEIGHT_SCREEN
|
||||
}
|
||||
},
|
||||
scene: [Handler, Game],
|
||||
canvasStyle: "display: block;"
|
||||
};
|
||||
|
||||
const game = new Phaser.Game(config);
|
||||
|
||||
game.screenBaseSize = {
|
||||
maxWidth: MAX_SIZE_WIDTH_SCREEN,
|
||||
maxHeight: MAX_SIZE_HEIGHT_SCREEN,
|
||||
minWidth: MIN_SIZE_WIDTH_SCREEN,
|
||||
minHeight: MIN_SIZE_HEIGHT_SCREEN,
|
||||
width: SIZE_WIDTH_SCREEN,
|
||||
height: SIZE_HEIGHT_SCREEN
|
||||
};
|
||||
|
||||
/*game.scale.on('resize', (gameSize, baseSize, displaySize, previousWidth, previousHeight) => {
|
||||
console.log("resize", gameSize, baseSize, displaySize, previousWidth, previousHeight);
|
||||
});*/
|
||||
401
src/scenes/game.js
Normal file
@ -0,0 +1,401 @@
|
||||
import Phaser from "phaser";
|
||||
import img from "../assets/lapi.png";
|
||||
|
||||
import Button from "../components/Button";
|
||||
import ShopItem from "../components/ShopItem";
|
||||
|
||||
import CHICO_BALD from "../assets/chico-bald.png";
|
||||
import CHICO_CARPET from "../assets/chico-carpet.png";
|
||||
import CHICO_CORNER from "../assets/chico-corner.png";
|
||||
import CHICO_EARS from "../assets/chico-ears.png";
|
||||
import CHICO_EATING from "../assets/chico-eating.png";
|
||||
import CHICO_HOUSE from "../assets/chico-house.png";
|
||||
import CHICO_LOAF from "../assets/chico-loaf.png";
|
||||
import CHICO_NOSE from "../assets/chico-nose.png";
|
||||
import CHICO_SLEEP from "../assets/chico-sleep.png";
|
||||
import CHICO_VENT from "../assets/chico-vent.png";
|
||||
import CHICO_WITH_EARS from "../assets/chico-withears.png";
|
||||
import LOCKED from "../assets/question.jpg";
|
||||
|
||||
export default class Game extends Phaser.Scene {
|
||||
handlerScene = null;
|
||||
sceneStopped = false;
|
||||
chicos = 0;
|
||||
perSecond = 0;
|
||||
win = false;
|
||||
spinRemaining = 360;
|
||||
|
||||
constructor() {
|
||||
super({ key: "game" });
|
||||
}
|
||||
|
||||
preload() {
|
||||
this.load.image("img", img);
|
||||
this.load.image("chico-bald", CHICO_BALD);
|
||||
this.load.image("chico-carpet", CHICO_CARPET);
|
||||
this.load.image("chico-corner", CHICO_CORNER);
|
||||
this.load.image("chico-ears", CHICO_EARS);
|
||||
this.load.image("chico-eating", CHICO_EATING);
|
||||
this.load.image("chico-house", CHICO_HOUSE);
|
||||
this.load.image("chico-loaf", CHICO_LOAF);
|
||||
this.load.image("chico-nose", CHICO_NOSE);
|
||||
this.load.image("chico-sleep", CHICO_SLEEP);
|
||||
this.load.image("chico-vent", CHICO_VENT);
|
||||
this.load.image("chico-with-ears", CHICO_WITH_EARS);
|
||||
this.load.image("locked", LOCKED);
|
||||
|
||||
this.width = this.game.screenBaseSize.width;
|
||||
this.height = this.game.screenBaseSize.height;
|
||||
|
||||
this.handlerScene = this.scene.get("handler");
|
||||
this.handlerScene.sceneRunning = "game";
|
||||
this.sceneStopped = false;
|
||||
}
|
||||
|
||||
create() {
|
||||
const { width, height } = this;
|
||||
// scene config
|
||||
this.handlerScene.updateResize(this);
|
||||
|
||||
const title = this.add
|
||||
.text(width / 2, 0, "BALD CHICO TYCOON", {
|
||||
fontFamily: "sans-serif",
|
||||
fontSize: "32px",
|
||||
fontStyle: "bold",
|
||||
color: "#000000"
|
||||
})
|
||||
.setOrigin(0.5, 0);
|
||||
|
||||
// game objects
|
||||
this.buttonContainer = this.add.container(0, 0);
|
||||
this.chicoButton = this.add
|
||||
.image(width / 4 + 8, title.height + height / 8, "chico-bald")
|
||||
.setScale(0.4)
|
||||
.setDepth(1);
|
||||
|
||||
console.log(title.height, height, height / 8);
|
||||
|
||||
this.chicoButton.firstClick = true;
|
||||
this.chicoButton.setInteractive({ useHandCursor: true });
|
||||
|
||||
const infoButton = new Button(
|
||||
this,
|
||||
this.width - this.chicoButton.displayWidth - 8,
|
||||
title.height,
|
||||
this.chicoButton.displayWidth,
|
||||
this.chicoButton.displayHeight,
|
||||
16,
|
||||
"I have lost my ears. Please help me buy new ears. I do not want to be bald anymore.",
|
||||
19
|
||||
);
|
||||
this.add.existing(infoButton);
|
||||
const startText = this.add.text(
|
||||
this.width - this.chicoButton.displayWidth - 8,
|
||||
title.height + this.chicoButton.displayHeight - 36,
|
||||
"Press to start",
|
||||
{
|
||||
fontFamily: "sans-serif",
|
||||
fontSize: 20,
|
||||
fontStyle: "bold",
|
||||
color: "#000000",
|
||||
align: "center",
|
||||
fixedWidth: this.chicoButton.displayWidth
|
||||
}
|
||||
);
|
||||
|
||||
this.numberWithCommas = (x) => {
|
||||
return x.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",");
|
||||
};
|
||||
|
||||
const handleChicoDown = () => {
|
||||
this.chicoButton.setScale(0.375);
|
||||
};
|
||||
|
||||
const handleChicoUp = () => {
|
||||
this.chicos++;
|
||||
if (this.chicoButton.firstClick) {
|
||||
this.chicoButton.firstClick = false;
|
||||
infoButton.label.destroy();
|
||||
infoButton.destroy();
|
||||
startText.destroy();
|
||||
}
|
||||
this.chicoButton.setScale(0.4);
|
||||
};
|
||||
|
||||
this.chicoButton.on("pointerdown", handleChicoDown);
|
||||
this.chicoButton.on("pointerup", handleChicoUp);
|
||||
infoButton.on("pointerdown", handleChicoDown);
|
||||
infoButton.on("pointerup", handleChicoUp);
|
||||
|
||||
this.chicoLabel = this.add
|
||||
.text(width * (2 / 3), title.height + 36, "Chicos:", {
|
||||
fontFamily: "sans-serif",
|
||||
fontSize: 24,
|
||||
color: "#000000"
|
||||
})
|
||||
.setDepth(-1);
|
||||
|
||||
this.chicoValue = this.add
|
||||
.text(
|
||||
width * (2 / 3) - this.chicoLabel.width * 1.5,
|
||||
this.chicoLabel.y + 24,
|
||||
this.chicos,
|
||||
{
|
||||
fontFamily: "sans-serif",
|
||||
fontSize: 36,
|
||||
color: "#000000",
|
||||
align: "center",
|
||||
fixedWidth: this.chicoLabel.width * 4,
|
||||
wordWrap: { width: this.chicoLabel.width * 4, useAdvancedWrap: true }
|
||||
}
|
||||
)
|
||||
.setDepth(-1);
|
||||
|
||||
this.productionLabel = this.add
|
||||
.text(
|
||||
width * (2 / 3) - this.chicoLabel.width * 0.5,
|
||||
this.chicoValue.y + 40,
|
||||
"Production:",
|
||||
{
|
||||
fontFamily: "sans-serif",
|
||||
fontSize: 24,
|
||||
color: "#000000",
|
||||
align: "center",
|
||||
fixedWidth: this.chicoLabel.width * 2
|
||||
}
|
||||
)
|
||||
.setDepth(-1);
|
||||
|
||||
this.productionValue = this.add
|
||||
.text(
|
||||
width * (2 / 3) - this.chicoLabel.width * 0.5,
|
||||
this.productionLabel.y + 24,
|
||||
this.perSecond,
|
||||
{
|
||||
fontFamily: "sans-serif",
|
||||
fontSize: 36,
|
||||
color: "#000000",
|
||||
align: "center",
|
||||
fixedWidth: this.chicoLabel.width * 2,
|
||||
wordWrap: { width: this.chicoLabel.width * 2, useAdvancedWrap: true }
|
||||
}
|
||||
)
|
||||
.setDepth(-1);
|
||||
|
||||
this.thanksForEarsTop = this.add
|
||||
.text(
|
||||
width * (4 / 7),
|
||||
title.height - 4,
|
||||
"Thank you for buying\n me some new ears!",
|
||||
{
|
||||
fontFamily: "sans-serif",
|
||||
fontSize: 18,
|
||||
color: "#000000",
|
||||
align: "center"
|
||||
}
|
||||
)
|
||||
.setDepth(-1)
|
||||
.setVisible(false);
|
||||
|
||||
this.thanksForEarsBottom = this.add
|
||||
.text(
|
||||
width * (3 / 5),
|
||||
this.productionValue.y + 40,
|
||||
"This is better than\n a bowlful of kale!",
|
||||
{
|
||||
fontFamily: "sans-serif",
|
||||
fontSize: 18,
|
||||
color: "#000000",
|
||||
align: "center"
|
||||
}
|
||||
)
|
||||
.setDepth(-1)
|
||||
.setVisible(false);
|
||||
|
||||
const frameWidth = width;
|
||||
const frameHeight = height - this.chicoButton.displayHeight;
|
||||
const itemWidth = frameWidth / 3 - 8;
|
||||
const itemHeight = frameHeight / 3 - 16;
|
||||
|
||||
const itemCarpet = new ShopItem(
|
||||
this,
|
||||
4,
|
||||
0,
|
||||
itemWidth,
|
||||
itemHeight,
|
||||
[],
|
||||
"Carpet Chico",
|
||||
"chico-carpet",
|
||||
1,
|
||||
0.2,
|
||||
"I'm Chico"
|
||||
);
|
||||
|
||||
const itemEating = new ShopItem(
|
||||
this,
|
||||
frameWidth / 3 + 4,
|
||||
itemCarpet.y,
|
||||
itemWidth,
|
||||
itemHeight,
|
||||
[],
|
||||
"Eating Chico",
|
||||
"chico-eating",
|
||||
25,
|
||||
0.6,
|
||||
"Favorite time of the day"
|
||||
);
|
||||
|
||||
const itemNose = new ShopItem(
|
||||
this,
|
||||
(frameWidth / 3) * 2 + 4,
|
||||
itemCarpet.y,
|
||||
itemWidth,
|
||||
itemHeight,
|
||||
[],
|
||||
"Big Nose Chico",
|
||||
"chico-nose",
|
||||
100,
|
||||
2,
|
||||
"I can smell you from here"
|
||||
);
|
||||
|
||||
const itemHouse = new ShopItem(
|
||||
this,
|
||||
itemCarpet.x,
|
||||
itemHeight,
|
||||
itemWidth,
|
||||
itemHeight,
|
||||
[],
|
||||
"House Chico",
|
||||
"chico-house",
|
||||
200,
|
||||
5.5,
|
||||
"My lovely estate"
|
||||
);
|
||||
|
||||
const itemLoaf = new ShopItem(
|
||||
this,
|
||||
itemEating.x,
|
||||
itemHouse.y,
|
||||
itemWidth,
|
||||
itemHeight,
|
||||
[],
|
||||
"Loaf Chico",
|
||||
"chico-loaf",
|
||||
400,
|
||||
12,
|
||||
"I'm Chico"
|
||||
);
|
||||
|
||||
const itemVent = new ShopItem(
|
||||
this,
|
||||
itemNose.x,
|
||||
itemHouse.y,
|
||||
itemWidth,
|
||||
itemHeight,
|
||||
[],
|
||||
"Suspect Chico",
|
||||
"chico-vent",
|
||||
800,
|
||||
28,
|
||||
"Love good ventilation"
|
||||
);
|
||||
|
||||
const itemCorner = new ShopItem(
|
||||
this,
|
||||
itemCarpet.x,
|
||||
(itemHeight + 4) * 2,
|
||||
itemWidth,
|
||||
itemHeight,
|
||||
[],
|
||||
"Corner Chico",
|
||||
"chico-corner",
|
||||
1600,
|
||||
64,
|
||||
"Where have I found myself now?"
|
||||
);
|
||||
|
||||
const itemSleep = new ShopItem(
|
||||
this,
|
||||
itemEating.x,
|
||||
itemCorner.y,
|
||||
itemWidth,
|
||||
itemHeight,
|
||||
[],
|
||||
"Sleeping Chico",
|
||||
"chico-sleep",
|
||||
3200,
|
||||
144,
|
||||
"Long day of being a Chico"
|
||||
);
|
||||
|
||||
const itemEars = new ShopItem(
|
||||
this,
|
||||
itemNose.x,
|
||||
itemCorner.y,
|
||||
itemWidth,
|
||||
itemHeight,
|
||||
[],
|
||||
"Chico Ears",
|
||||
"chico-ears",
|
||||
100000,
|
||||
0,
|
||||
"",
|
||||
true
|
||||
);
|
||||
|
||||
this.shopItems = [
|
||||
itemCarpet,
|
||||
itemEating,
|
||||
itemNose,
|
||||
itemVent,
|
||||
itemHouse,
|
||||
itemLoaf,
|
||||
itemCorner,
|
||||
itemSleep,
|
||||
itemEars
|
||||
];
|
||||
|
||||
const shopFrame = new Phaser.GameObjects.Container(
|
||||
this,
|
||||
0,
|
||||
this.chicoButton.displayHeight + 36,
|
||||
this.shopItems
|
||||
);
|
||||
|
||||
this.add.existing(shopFrame);
|
||||
}
|
||||
|
||||
update(time, delta) {
|
||||
this.chicos += this.perSecond * (delta / 1000);
|
||||
this.chicoValue.setText(this.numberWithCommas(Math.floor(this.chicos)));
|
||||
this.productionValue.setText(
|
||||
this.numberWithCommas(Math.round(this.perSecond * 10) / 10) + "/s"
|
||||
);
|
||||
for (let i = 0; i < this.shopItems.length; i++) {
|
||||
const item = this.shopItems[i];
|
||||
if (item.locked && item.startCost <= this.chicos) {
|
||||
item.locked = false;
|
||||
item.lockedImg.destroy();
|
||||
item.label.visible = true;
|
||||
}
|
||||
}
|
||||
if (this.shopItems[this.shopItems.length - 1].count > 0 && !this.win) {
|
||||
this.win = true;
|
||||
this.chicoButton.setTexture("chico-with-ears");
|
||||
this.thanksForEarsTop.setVisible(true);
|
||||
this.thanksForEarsBottom.setVisible(true);
|
||||
this.time.addEvent({
|
||||
delay: 30000,
|
||||
callback: () => {
|
||||
this.thanksForEarsTop.setVisible(false);
|
||||
this.thanksForEarsBottom.setVisible(false);
|
||||
}
|
||||
});
|
||||
}
|
||||
if (this.win && this.spinRemaining > 0) {
|
||||
this.spinRemaining--;
|
||||
this.chicoButton.angle += 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
72
src/scenes/handler.js
Normal file
@ -0,0 +1,72 @@
|
||||
import Phaser from "phaser";
|
||||
|
||||
export default class Handler extends Phaser.Scene {
|
||||
sceneRunning = null;
|
||||
|
||||
constructor() {
|
||||
super("handler");
|
||||
}
|
||||
|
||||
create() {
|
||||
this.cameras.main.setBackgroundColor("#D4D4D4");
|
||||
this.launchScene("game");
|
||||
}
|
||||
|
||||
launchScene(scene, data) {
|
||||
this.scene.launch(scene, data);
|
||||
this.gameScene = this.scene.get(scene);
|
||||
}
|
||||
|
||||
updateResize(scene) {
|
||||
scene.scale.on("resize", this.resize, scene);
|
||||
|
||||
const scaleWidth = scene.scale.gameSize.width;
|
||||
const scaleHeight = scene.scale.gameSize.height;
|
||||
|
||||
scene.parent = new Phaser.Structs.Size(scaleWidth, scaleHeight);
|
||||
scene.sizer = new Phaser.Structs.Size(
|
||||
scene.width,
|
||||
scene.height,
|
||||
Phaser.Structs.Size.FIT,
|
||||
scene.parent
|
||||
);
|
||||
|
||||
scene.parent.setSize(scaleWidth, scaleHeight);
|
||||
scene.sizer.setSize(scaleWidth, scaleHeight);
|
||||
|
||||
this.updateCamera(scene);
|
||||
}
|
||||
|
||||
resize(gameSize) {
|
||||
// 'this' means to the current scene that is running
|
||||
if (!this.sceneStopped) {
|
||||
const width = gameSize.width;
|
||||
const height = gameSize.height;
|
||||
|
||||
this.parent.setSize(width, height);
|
||||
this.sizer.setSize(width, height);
|
||||
|
||||
const camera = this.cameras.main;
|
||||
const scaleX = this.sizer.width / this.game.screenBaseSize.width;
|
||||
const scaleY = this.sizer.height / this.game.screenBaseSize.height;
|
||||
|
||||
camera.setZoom(Math.max(scaleX, scaleY));
|
||||
camera.centerOn(
|
||||
this.game.screenBaseSize.width / 2,
|
||||
this.game.screenBaseSize.height / 2
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
updateCamera(scene) {
|
||||
const camera = scene.cameras.main;
|
||||
const scaleX = scene.sizer.width / this.game.screenBaseSize.width;
|
||||
const scaleY = scene.sizer.height / this.game.screenBaseSize.height;
|
||||
|
||||
camera.setZoom(Math.max(scaleX, scaleY));
|
||||
camera.centerOn(
|
||||
this.game.screenBaseSize.width / 2,
|
||||
this.game.screenBaseSize.height / 2
|
||||
);
|
||||
}
|
||||
}
|
||||
62
webpack/base.js
Normal file
@ -0,0 +1,62 @@
|
||||
/*MIT License
|
||||
|
||||
Copyright (c) 2017 Richard Davey
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.*/
|
||||
|
||||
const webpack = require("webpack");
|
||||
const path = require("path");
|
||||
const HtmlWebpackPlugin = require("html-webpack-plugin");
|
||||
const { CleanWebpackPlugin } = require("clean-webpack-plugin");
|
||||
|
||||
module.exports = {
|
||||
mode: "development",
|
||||
devtool: "eval-source-map",
|
||||
module: {
|
||||
rules: [
|
||||
{
|
||||
test: /\.js$/,
|
||||
exclude: /node_modules/,
|
||||
use: {
|
||||
loader: "babel-loader"
|
||||
}
|
||||
},
|
||||
{
|
||||
test: [/\.vert$/, /\.frag$/],
|
||||
use: "raw-loader"
|
||||
},
|
||||
{
|
||||
test: /\.(gif|png|jpe?g|svg|xml)$/i,
|
||||
use: "file-loader"
|
||||
}
|
||||
]
|
||||
},
|
||||
plugins: [
|
||||
new CleanWebpackPlugin({
|
||||
root: path.resolve(__dirname, "../")
|
||||
}),
|
||||
new webpack.DefinePlugin({
|
||||
CANVAS_RENDERER: JSON.stringify(true),
|
||||
WEBGL_RENDERER: JSON.stringify(true)
|
||||
}),
|
||||
new HtmlWebpackPlugin({
|
||||
template: "./index.html"
|
||||
})
|
||||
]
|
||||
};
|
||||
49
webpack/prod.js
Normal file
@ -0,0 +1,49 @@
|
||||
/*MIT License
|
||||
|
||||
Copyright (c) 2017 Richard Davey
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.*/
|
||||
|
||||
const merge = require("webpack-merge");
|
||||
const path = require("path");
|
||||
const base = require("./base");
|
||||
const TerserPlugin = require("terser-webpack-plugin");
|
||||
|
||||
module.exports = merge(base, {
|
||||
mode: "production",
|
||||
output: {
|
||||
filename: "bundle.min.js"
|
||||
},
|
||||
devtool: false,
|
||||
performance: {
|
||||
maxEntrypointSize: 900000,
|
||||
maxAssetSize: 900000
|
||||
},
|
||||
optimization: {
|
||||
minimizer: [
|
||||
new TerserPlugin({
|
||||
terserOptions: {
|
||||
output: {
|
||||
comments: false
|
||||
}
|
||||
}
|
||||
})
|
||||
]
|
||||
}
|
||||
});
|
||||