请查看 README.md
Inspired by react-tetris, cause I prefer Vue to React, so I use Vue to code it, my idea is to think of components and methods as functions, to ensure that an input (props/params) gets a determined output (view/return value), and use Vuex instead of Redux.
Open http://binaryify.github.io/vue-tetris/ to play!

Not only refers to the screen adaptation, but the change of input depending on your platform, use of the keyboard in the PC and in the phone using the touch as input:

What's the worst can happen when you're playing stand-alone games? Power outage. The state is stored in the localStorage by subscribing to store.subscribe, which records exactly all the state. Web page refreshes, the program crashes, the phone is dead, just re-open the connection and you can continue playing.

Vuex manages all the state that should be stored, which is a guarantee to be persisted as mentioned above.
The Game framework is the use of Vue + Vuex, together with Immutable.js.
Immutable is data that can not be changed once it is created. Any modification or addition to or deletion of an Immutable object returns a new Immutable object.
Let's look at the following code:
function keyLog(touchFn) {
let data = { key: 'value' };
f(data);
console.log(data.key); // Guess what will be printed?
}
If we do not look at f, and do not know what it did to data, we can not confirm what will be printed. But if data is Immutable, you can be sure that data haven't changed and value is printed:
function keyLog(touchFn) {
let data = Immutable.Map({ key: 'value' });
f(data);
console.log(data.get('key')); // value
}
JavaScript uses a reference assignment, meaning that the new object simply refers to the original object, changing the new will also affect the old:
foo = {a: 1}; bar = foo; bar.a = 2;
foo.a // 2
Although this can save memory, when the application is complex, it can result in the state not being controllable, posing a big risk. The advantages of saving memory, in this case, become more harm than good.
With Immutable.js the same doesn't happen:
foo = Immutable.Map({ a: 1 }); bar = foo.set('a', 2);
foo.get('a') // 1
We know that === operator for the Object and Array compares the reference to the address of the object rather than its "value comparison", such as:
{a:1, b:2, c:3} === {a:1, b:2, c:3}; // false
[1, 2, [3, 4]] === [1, 2, [3, 4]]; // false
To achieve the above we could only deepCopy and deepCompare to traverse the objects, but this is not only cumbersome it also harms performance.
Let's check Immutable.js approach!
map1 = Immutable.Map({a:1, b:2, c:3});
map2 = Immutable.Map({a:1, b:2, c:3});
Immutable.is(map1, map2); // true
// List1 = Immutable.List([1, 2, Immutable.List[3, 4]]);
List1 = Immutable.fromJS([1, 2, [3, 4]]);
List2 = Immutable.fromJS([1, 2, [3, 4]]);
Immutable.is(List1, List2); // true
Immutable learning materials: * Immutable.js
There are many different sound effects in the game, but in fact we keep only a reference to a sound file: /build/music.mp3. With the help of Web Audio Api, you can play audio in millisecond precision, with a high frequency, which is not possible with the <audio> tag. Press the arrow keys to move the box while the game is in progress, you can hear high-frequency sound.

WAA is a new set of relatively independent interface system, the audio file has a higher processing power and more professional built-in audio effects, is the W3C recommended interface, can deal with professional "sound speed, volume, environment, sound visualization, High-frequency, sound to " and other needs. The following figure describes the use of WAA process.

Where Source represents an audio source, Destination represents the final output. Multiple Sources compose the Destination.
Source Code:/src/unit/music.js. To achieve ajax loading mp3, and to WAA, control the playback process.
WAA is supported in the latest 2 versions of each browser(CanIUse)

IE and Android lack support though.
Web Audio Api learning materials: * Web audio concepts and usage| MDN * Getting Started with Web Audio API
touchstart and mousedown events are also registered for the button for responsive games. When touchstart occurs, mousedown is not triggered, and when mousedown occurs, the mouseup simulator mouseup will also be listened to as mouseup, since the mouse-removed event element can not fire. Source Code:/src/components/keyboard/index.js;visibilitychange event, when the page is hidden\switch, the game will not proceed, switch back and it will continue, the focus state has also been written into the Redux. So when playing with the phone and the phone has a call, the progress of the game will be saved; PC open the game do not hear any other gameover, which is a bit like ios application switch;any time you refresh the page, (such as the closing the tab or the end of the game) can restore the current state;
, all the rest is CSS;The Vue version and the React version of the core code are essentially the same, but there are a few problems when writing components, such as:
React version store uses the immutable data structure, the store on the vuex if you use the immutable structure, not use to monitor data changes, so all the data in the store to use the common data, in the place where need these data provided by immutable fromJS conversion, where need common data is converted to common data, through the immutable toJS in the process of actual refactoring, I try to stay away from the core game logic, actually I didn't understand the game implementation logic is in the reconstruction of the complete, just ensure the consistency of input and output method, just be patience
How to rewrite the React components into the Vue, my train of thought is to put the components as a function, ensure that an input (props) can get a certain output (view), and then do the same with different methods is also, React setState would trigger the render method, so can be defined in the methods from the render method to manually trigger the render method after the state change
Life cycle, in simple terms, the React of corresponding Vue componentWillMount beforeMount, React componentDidMount corresponding Vue mounted, React to optimize the performance of shouldComponentUpdate in Vue does not need, does not need manual optimization is one of the reason that I like the Vue
Vue does not have the React component of componentWillReceiveProps' life cycle, and my solution is to use watch to work with deep: true to listen for changes in props such as:
watch: {
$props: {
deep: true,
handler(nextProps) {
//xxx
}
}
}
Redux of the state of the data flow is through the store 'mapStateToProps' into props and then through the 'connect' function into the root component, the root component put these props into different components, when the state of the store, the root component will render again, update the props on the subcomponents, child components according to the new props render again
And Vuex train of thought, on the other hand, any component can at any time through this. $store. State. XXX access to the data on the store, more freedom, from store example reads the state of the simplest method is to return to a state in computational attributes:
computed: {
keyboard () {
return this.store.state.keyboard
}
}
Call 'store.commit' submit payload to modify the data store or dispatch submit mutation indirectly modify the data on the store, commit and dispatch the difference between the commit for synchronous modifying state, dispatch for asynchronous modifying state, asynchronous completion need to invoke the commit, generally simple demand only need to commit a payload, as long as the data on the store changed, component automatically render again
npm install
npm run dev
The browser will go to http://localhost:8080
In the i18n.jsonis the configuration for the multi-language environment. You can change the language by passing the url parameter lan like this: https://Binaryify.github.io/vue-tetris/?lan=en
npm run build
Will build the application in the 'dist' folder.
$ claude mcp add vue-tetris \
-- python -m otcore.mcp_server <graph>