This commit is contained in:
lanxu 2024-09-28 10:50:10 +03:00
parent 1a9a28e191
commit d96fc2b077
25 changed files with 434 additions and 120 deletions

View File

@ -1,84 +1,11 @@
<div align="center">
# Silver Fang mini game
<h1><code>wasm-pack-template</code></h1>
<strong>A template for kick starting a Rust and WebAssembly project using <a href="https://github.com/rustwasm/wasm-pack">wasm-pack</a>.</strong>
<p>
<a href="https://travis-ci.org/rustwasm/wasm-pack-template"><img src="https://img.shields.io/travis/rustwasm/wasm-pack-template.svg?style=flat-square" alt="Build Status" /></a>
</p>
<h3>
<a href="https://rustwasm.github.io/docs/wasm-pack/tutorials/npm-browser-packages/index.html">Tutorial</a>
<span> | </span>
<a href="https://discordapp.com/channels/442252698964721669/443151097398296587">Chat</a>
</h3>
<sub>Built with 🦀🕸 by <a href="https://rustwasm.github.io/">The Rust and WebAssembly Working Group</a></sub>
</div>
## About
[**📚 Read this template tutorial! 📚**][template-docs]
This template is designed for compiling Rust libraries into WebAssembly and
publishing the resulting package to NPM.
Be sure to check out [other `wasm-pack` tutorials online][tutorials] for other
templates and usages of `wasm-pack`.
[tutorials]: https://rustwasm.github.io/docs/wasm-pack/tutorials/index.html
[template-docs]: https://rustwasm.github.io/docs/wasm-pack/tutorials/npm-browser-packages/index.html
## 🚴 Usage
### 🐑 Use `cargo generate` to Clone this Template
[Learn more about `cargo generate` here.](https://github.com/ashleygwilliams/cargo-generate)
```
cargo generate --git https://github.com/rustwasm/wasm-pack-template.git --name my-project
cd my-project
```sh
wargo watch -i .gitignore -i "pkg/*" -s "wasm-pack build --target=bundler --dev --out-name index"
```
### 🛠️ Build with `wasm-pack build`
And run in www
```
wasm-pack build
```
### 🔬 Test in Headless Browsers with `wasm-pack test`
```
wasm-pack test --headless --firefox
```
### 🎁 Publish to NPM with `wasm-pack publish`
```
wasm-pack publish
```
## 🔋 Batteries Included
* [`wasm-bindgen`](https://github.com/rustwasm/wasm-bindgen) for communicating
between WebAssembly and JavaScript.
* [`console_error_panic_hook`](https://github.com/rustwasm/console_error_panic_hook)
for logging panic messages to the developer console.
* `LICENSE-APACHE` and `LICENSE-MIT`: most Rust projects are licensed this way, so these are included for you
## License
Licensed under either of
* Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0)
* MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT)
at your option.
### Contribution
Unless you explicitly state otherwise, any contribution intentionally
submitted for inclusion in the work by you, as defined in the Apache-2.0
license, shall be dual licensed as above, without any additional terms or
conditions.
```sh
npm start
```

14
assets.json Normal file
View File

@ -0,0 +1,14 @@
{
"frames": [],
"meta": {
"app": "libgdx",
"version": "latest",
"image": "atlas.png",
"format": "png",
"size": {
"w": 10,
"h": 10
},
"scale": 1
}
}

98
create-phaser-atlas.py Executable file
View File

@ -0,0 +1,98 @@
#!/usr/bin/env python
"""
Archive extract script with sub-directory creation
"""
# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4
import io
import re
import sys
import json
from os import walk
import PIL
from PIL import Image
class AtlasFrame:
filename = None
xy = None
size = None
rotate = False
orig = None
offset = None
class Atlas:
image = None
format = None
size = None
frames = []
def serialize(obj):
return (obj.__class__, obj.__dict__)
def create_atlas(path):
f = []
for (dirpath, dirnames, filenames) in walk(path):
f.extend(filenames)
break
for filename in f:
print(filename)
print(f)
atlas = Atlas()
atlas.image = 'atlas.png'
atlas.format = 'png'
atlas.size = [10, 10]
return atlas
def main(dir):
print(dir)
atlas = create_atlas(dir)
json_str = createPhaserJson(atlas)
json_filename= 'assets.json'
with io.open(json_filename, 'w', encoding='utf8') as outfile:
outfile.write(str(json_str))
outfile.closed
print('wrote '+ json_filename )
def createPhaserJson(atlas):
data = {
'frames': [],
'meta': {
'app': 'libgdx',
'version': 'latest',
'image': atlas.image,
'format': atlas.format,
'size': { 'w': atlas.size[0], 'h': atlas.size[1] },
'scale': 1
}
}
for frame in atlas.frames:
framedata = {
'filename': frame.filename,
'frame': { 'x': frame.xy[0], 'y': frame.xy[1], 'w': frame.size[0], 'h': frame.size[1] },
'rotated': frame.rotate == 'true',
'trimmed': False,
'spriteSourceSize': { 'x': frame.offset[0], 'y': frame.offset[1], 'w': frame.orig[0], 'h': frame.orig[1] },
'sourceSize': { 'w': frame.orig[0], 'h': frame.orig[1] }
}
data['frames'].append(framedata)
json_str = json.dumps(data, indent=4, sort_keys=False, separators=(',', ': '), ensure_ascii=False)
return json_str
if __name__ == "__main__":
main(sys.argv[1])

1
src/game.rs Normal file
View File

@ -0,0 +1 @@

27
src/game/game_object.rs Normal file
View File

@ -0,0 +1,27 @@
use wasm_bindgen::prelude::*;
#[wasm_bindgen(getter_with_clone)] // Either do this or make text private and implement getter and setter (String!)
#[derive(Clone, Copy)]
pub struct GameState {
pub x: f64,
pub y: f64,
pub a: f64,
pub width: u32,
pub height: u32,
pub scale: f64,
}
#[wasm_bindgen]
impl GameObject {
pub fn new() -> GameObject {
GameObject {
x: 0.,
y: 0.,
a: 0.,
width: 0,
height: 0,
scale: 0.,
}
}
}

17
src/game/game_state.rs Normal file
View File

@ -0,0 +1,17 @@
use crate::game::game_object::GameObject;
pub enum State {
Menu,
InGame,
GameOver,
}
#[wasm_bindgen(getter_with_clone)]
pub struct GameState {
pub width: u32,
pub height: u32,
pub time: u64,
pub score: u64,
pub state: State(Menu),
objects: Vec<GameObject>,
}

View File

@ -1,3 +1,4 @@
mod game;
mod utils;
use wasm_bindgen::prelude::*;

BIN
www/assets/01.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 172 KiB

BIN
www/assets/02.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 135 KiB

BIN
www/assets/atlas.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 161 KiB

BIN
www/assets/card.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

BIN
www/assets/panel-000.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 173 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 159 B

View File

@ -1,5 +1,5 @@
// A dependency graph that contains any wasm must all be imported
// asynchronously. This `bootstrap.js` file does the single async import, so
// that no one else needs to worry about it again.
import("./index.js")
.catch(e => console.error("Error importing `index.js`:", e));
import("./index")
.catch(e => console.error("Error importing `index.ts`:", e));

View File

@ -1,11 +1,15 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Hello wasm-pack!</title>
</head>
<body>
<noscript>This page contains webassembly and javascript content, please enable javascript in your browser.</noscript>
<script src="./bootstrap.js"></script>
</body>
</html>
<head>
<meta charset="utf-8">
<title>Hello wasm-pack!</title>
</head>
<body>
<div id="silver-fang-mini-game"></div>
<noscript>This page contains webassembly and javascript content, please enable javascript in your browser.</noscript>
<script src="./bootstrap.js"></script>
</body>
</html>

View File

@ -1,3 +0,0 @@
import * as wasm from "mini-game";
wasm.greet();

6
www/index.ts Normal file
View File

@ -0,0 +1,6 @@
//wasm.greet();
import Game from "./src/game-base";
const game = new Game('silver-fang-minigame');
game.start();

135
www/package-lock.json generated
View File

@ -1,27 +1,31 @@
{
"name": "create-wasm-app",
"name": "silver-fang-mini-game",
"version": "0.1.0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "create-wasm-app",
"name": "silver-fang-mini-game",
"version": "0.1.0",
"license": "(MIT OR Apache-2.0)",
"dependencies": {
"mini-game": "file:../pkg",
"phaser": "^3.80.1"
},
"bin": {
"create-wasm-app": ".bin/create-wasm-app.js"
},
"devDependencies": {
"copy-webpack-plugin": "^12.0.2",
"mini-game": "file:../pkg",
"ts-loader": "^9.5.1",
"typescript": "^5.4.5",
"webpack": "^5.x.x",
"webpack-cli": "^5.1.4",
"webpack-dev-server": "^5.0.4"
}
},
"../pkg": {
"version": "0.1.0",
"dev": true
"name": "mini-game",
"version": "0.1.0"
},
"node_modules/@discoveryjs/json-ext": {
"version": "0.5.7",
@ -922,6 +926,52 @@
}
]
},
"node_modules/chalk": {
"version": "4.1.2",
"resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
"integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
"dev": true,
"license": "MIT",
"dependencies": {
"ansi-styles": "^4.1.0",
"supports-color": "^7.1.0"
},
"engines": {
"node": ">=10"
},
"funding": {
"url": "https://github.com/chalk/chalk?sponsor=1"
}
},
"node_modules/chalk/node_modules/ansi-styles": {
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
"integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
"dev": true,
"license": "MIT",
"dependencies": {
"color-convert": "^2.0.1"
},
"engines": {
"node": ">=8"
},
"funding": {
"url": "https://github.com/chalk/ansi-styles?sponsor=1"
}
},
"node_modules/chalk/node_modules/supports-color": {
"version": "7.2.0",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
"integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
"dev": true,
"license": "MIT",
"dependencies": {
"has-flag": "^4.0.0"
},
"engines": {
"node": ">=8"
}
},
"node_modules/chokidar": {
"version": "3.6.0",
"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz",
@ -2925,6 +2975,21 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/phaser": {
"version": "3.80.1",
"resolved": "https://registry.npmjs.org/phaser/-/phaser-3.80.1.tgz",
"integrity": "sha512-VQGAWoDOkEpAWYkI+PUADv5Ql+SM0xpLuAMBJHz9tBcOLqjJ2wd8bUhxJgOqclQlLTg97NmMd9MhS75w16x1Cw==",
"license": "MIT",
"dependencies": {
"eventemitter3": "^5.0.1"
}
},
"node_modules/phaser/node_modules/eventemitter3": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.1.tgz",
"integrity": "sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==",
"license": "MIT"
},
"node_modules/picocolors": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz",
@ -3287,6 +3352,19 @@
"node": ">=10"
}
},
"node_modules/semver": {
"version": "7.6.2",
"resolved": "https://registry.npmjs.org/semver/-/semver-7.6.2.tgz",
"integrity": "sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w==",
"dev": true,
"license": "ISC",
"bin": {
"semver": "bin/semver.js"
},
"engines": {
"node": ">=10"
}
},
"node_modules/send": {
"version": "0.18.0",
"resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz",
@ -3862,6 +3940,37 @@
"node": ">=0.6"
}
},
"node_modules/ts-loader": {
"version": "9.5.1",
"resolved": "https://registry.npmjs.org/ts-loader/-/ts-loader-9.5.1.tgz",
"integrity": "sha512-rNH3sK9kGZcH9dYzC7CewQm4NtxJTjSEVRJ2DyBZR7f8/wcta+iV44UPCXc5+nzDzivKtlzV6c9P4e+oFhDLYg==",
"dev": true,
"license": "MIT",
"dependencies": {
"chalk": "^4.1.0",
"enhanced-resolve": "^5.0.0",
"micromatch": "^4.0.0",
"semver": "^7.3.4",
"source-map": "^0.7.4"
},
"engines": {
"node": ">=12.0.0"
},
"peerDependencies": {
"typescript": "*",
"webpack": "^5.0.0"
}
},
"node_modules/ts-loader/node_modules/source-map": {
"version": "0.7.4",
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.4.tgz",
"integrity": "sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA==",
"dev": true,
"license": "BSD-3-Clause",
"engines": {
"node": ">= 8"
}
},
"node_modules/tslib": {
"version": "1.11.1",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-1.11.1.tgz",
@ -3881,6 +3990,20 @@
"node": ">= 0.6"
}
},
"node_modules/typescript": {
"version": "5.4.5",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.4.5.tgz",
"integrity": "sha512-vcI4UpRgg81oIRUFwR0WSIHKt11nJ7SAVlYNIu+QpqeyXP+gpQJy/Z4+F0aGxSE4MqwjyXvW/TzgkLAx2AGHwQ==",
"dev": true,
"license": "Apache-2.0",
"bin": {
"tsc": "bin/tsc",
"tsserver": "bin/tsserver"
},
"engines": {
"node": ">=14.17"
}
},
"node_modules/undici-types": {
"version": "5.26.5",
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz",

View File

@ -1,7 +1,7 @@
{
"name": "create-wasm-app",
"name": "silver-fang-mini-game",
"version": "0.1.0",
"description": "create an app to consume rust-generated wasm packages",
"description": "Silver Fang Mini Game",
"main": "index.js",
"bin": {
"create-wasm-app": ".bin/create-wasm-app.js"
@ -10,27 +10,17 @@
"build": "webpack --config webpack.config.js",
"start": "webpack-dev-server"
},
"repository": {
"type": "git",
"url": "git+https://github.com/rustwasm/create-wasm-app.git"
},
"keywords": [
"webassembly",
"wasm",
"rust",
"webpack"
],
"author": "Ashley Williams <ashley666ashley@gmail.com>",
"license": "(MIT OR Apache-2.0)",
"bugs": {
"url": "https://github.com/rustwasm/create-wasm-app/issues"
},
"homepage": "https://github.com/rustwasm/create-wasm-app#readme",
"devDependencies": {
"mini-game": "file:../pkg",
"copy-webpack-plugin": "^12.0.2",
"ts-loader": "^9.5.1",
"typescript": "^5.4.5",
"webpack": "^5.x.x",
"webpack-cli": "^5.1.4",
"webpack-dev-server": "^5.0.4"
},
"dependencies": {
"mini-game": "file:../pkg",
"phaser": "^3.80.1"
}
}
}

24
www/src/game-base.ts Normal file
View File

@ -0,0 +1,24 @@
import * as MiniGame from "mini-game";
import * as Phaser from "phaser";
import MainMenuScene from "./scenes/main-menu-scene";
class Game {
parent: string = ''
phaserGame: Phaser.Game = null
constructor(parent: string) {
this.parent = parent ?? 'game'
}
start() {
this.phaserGame = new Phaser.Game({
type: Phaser.AUTO,
parent: this.parent,
width: 800,
height: 600,
backgroundColor: 'rgba(80, 80, 80, 0)',
scene: [MainMenuScene],
});
}
}
export default Game;

View File

@ -0,0 +1,11 @@
class ButtonSprite extends Phaser.GameObjects.Sprite {
constructor(scene: Phaser.Scene, x: number, y: number) {
const texture = 'button_bg';
super(scene, x, y, texture, 0);
// this.setInteractive(true);
scene.add.existing(this);
}
}
export default ButtonSprite;

33
www/src/objects/button.ts Normal file
View File

@ -0,0 +1,33 @@
import * as Phaser from "phaser";
class GameButton {
group: Phaser.GameObjects.Group | null = null;
constructor(scene: Phaser.Scene, x: number, y: number, text: string) {
const textObject = new Phaser.GameObjects.Text(scene, x, y, text, {
color: 'black',
})
textObject.setOrigin(.5, .5)
const bgObject = new Phaser.GameObjects.Sprite(scene, x, y, 'button-bg-inactive')
bgObject.setScale(((textObject.width + 40) / 48), ((textObject.height + 40) / 48))
bgObject.setInteractive();
bgObject.on('pointerover', () => {
})
const buttonGroup = new Phaser.GameObjects.Group(scene)
buttonGroup.add(textObject)
buttonGroup.add(bgObject)
this.group = buttonGroup
scene.add.existing(bgObject)
scene.add.existing(textObject)
scene.add.existing(buttonGroup)
console.log(textObject.width, textObject.height)
}
moveTo(x: number, y: number) {
this.group.setXY(x, y)
}
}
export default GameButton;

View File

@ -0,0 +1,18 @@
import * as Phaser from "phaser";
import ButtonSprite from "../objects/button-sprite";
import GameButton from "../objects/button";
class MainMenuScene extends Phaser.Scene {
preload() {
this.load.image('button-bg', 'assets/panel-000.png');
}
create() {
const button = new GameButton(this, 0, 0, 'LOL');
button.moveTo(100, 100)
}
}
export default MainMenuScene;

10
www/tsconfig.json Normal file
View File

@ -0,0 +1,10 @@
{
"compilerOptions": {
"outDir": "./dist/",
"noImplicitAny": true,
"module": "es2022",
"target": "es5",
"allowJs": true,
"moduleResolution": "node"
}
}

View File

@ -2,7 +2,20 @@ const CopyWebpackPlugin = require("copy-webpack-plugin");
const path = require('path');
module.exports = {
entry: "./bootstrap.js",
entry: "./bootstrap.ts",
devtool: 'inline-source-map',
module: {
rules: [
{
test: /\.ts$/,
use: 'ts-loader',
exclude: /node_modules/,
},
],
},
resolve: {
extensions: ['.ts', '.js'],
},
output: {
path: path.resolve(__dirname, "dist"),
filename: "bootstrap.js",