First Commit
This commit is contained in:
commit
517fb6537d
1
.browserslistrc
Normal file
1
.browserslistrc
Normal file
@ -0,0 +1 @@
|
|||||||
|
last 2 versions
|
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
node_modules
|
817
dist/bundle.js
vendored
Normal file
817
dist/bundle.js
vendored
Normal file
@ -0,0 +1,817 @@
|
|||||||
|
/******/ (function() { // webpackBootstrap
|
||||||
|
/******/ "use strict";
|
||||||
|
/******/ var __webpack_modules__ = ([
|
||||||
|
/* 0 */,
|
||||||
|
/* 1 */
|
||||||
|
/***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) {
|
||||||
|
|
||||||
|
__webpack_require__.r(__webpack_exports__);
|
||||||
|
/* harmony import */ var _node_modules_style_loader_dist_runtime_injectStylesIntoStyleTag_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(2);
|
||||||
|
/* harmony import */ var _node_modules_style_loader_dist_runtime_injectStylesIntoStyleTag_js__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(_node_modules_style_loader_dist_runtime_injectStylesIntoStyleTag_js__WEBPACK_IMPORTED_MODULE_0__);
|
||||||
|
/* harmony import */ var _node_modules_css_loader_dist_cjs_js_node_modules_postcss_loader_dist_cjs_js_ruleSet_1_rules_1_use_2_node_modules_less_loader_dist_cjs_js_index_less__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(3);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
var options = {};
|
||||||
|
|
||||||
|
options.insert = "head";
|
||||||
|
options.singleton = false;
|
||||||
|
|
||||||
|
var update = _node_modules_style_loader_dist_runtime_injectStylesIntoStyleTag_js__WEBPACK_IMPORTED_MODULE_0___default()(_node_modules_css_loader_dist_cjs_js_node_modules_postcss_loader_dist_cjs_js_ruleSet_1_rules_1_use_2_node_modules_less_loader_dist_cjs_js_index_less__WEBPACK_IMPORTED_MODULE_1__.default, options);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* harmony default export */ __webpack_exports__["default"] = (_node_modules_css_loader_dist_cjs_js_node_modules_postcss_loader_dist_cjs_js_ruleSet_1_rules_1_use_2_node_modules_less_loader_dist_cjs_js_index_less__WEBPACK_IMPORTED_MODULE_1__.default.locals || {});
|
||||||
|
|
||||||
|
/***/ }),
|
||||||
|
/* 2 */
|
||||||
|
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
var isOldIE = function isOldIE() {
|
||||||
|
var memo;
|
||||||
|
return function memorize() {
|
||||||
|
if (typeof memo === 'undefined') {
|
||||||
|
// Test for IE <= 9 as proposed by Browserhacks
|
||||||
|
// @see http://browserhacks.com/#hack-e71d8692f65334173fee715c222cb805
|
||||||
|
// Tests for existence of standard globals is to allow style-loader
|
||||||
|
// to operate correctly into non-standard environments
|
||||||
|
// @see https://github.com/webpack-contrib/style-loader/issues/177
|
||||||
|
memo = Boolean(window && document && document.all && !window.atob);
|
||||||
|
}
|
||||||
|
|
||||||
|
return memo;
|
||||||
|
};
|
||||||
|
}();
|
||||||
|
|
||||||
|
var getTarget = function getTarget() {
|
||||||
|
var memo = {};
|
||||||
|
return function memorize(target) {
|
||||||
|
if (typeof memo[target] === 'undefined') {
|
||||||
|
var styleTarget = document.querySelector(target); // Special case to return head of iframe instead of iframe itself
|
||||||
|
|
||||||
|
if (window.HTMLIFrameElement && styleTarget instanceof window.HTMLIFrameElement) {
|
||||||
|
try {
|
||||||
|
// This will throw an exception if access to iframe is blocked
|
||||||
|
// due to cross-origin restrictions
|
||||||
|
styleTarget = styleTarget.contentDocument.head;
|
||||||
|
} catch (e) {
|
||||||
|
// istanbul ignore next
|
||||||
|
styleTarget = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
memo[target] = styleTarget;
|
||||||
|
}
|
||||||
|
|
||||||
|
return memo[target];
|
||||||
|
};
|
||||||
|
}();
|
||||||
|
|
||||||
|
var stylesInDom = [];
|
||||||
|
|
||||||
|
function getIndexByIdentifier(identifier) {
|
||||||
|
var result = -1;
|
||||||
|
|
||||||
|
for (var i = 0; i < stylesInDom.length; i++) {
|
||||||
|
if (stylesInDom[i].identifier === identifier) {
|
||||||
|
result = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
function modulesToDom(list, options) {
|
||||||
|
var idCountMap = {};
|
||||||
|
var identifiers = [];
|
||||||
|
|
||||||
|
for (var i = 0; i < list.length; i++) {
|
||||||
|
var item = list[i];
|
||||||
|
var id = options.base ? item[0] + options.base : item[0];
|
||||||
|
var count = idCountMap[id] || 0;
|
||||||
|
var identifier = "".concat(id, " ").concat(count);
|
||||||
|
idCountMap[id] = count + 1;
|
||||||
|
var index = getIndexByIdentifier(identifier);
|
||||||
|
var obj = {
|
||||||
|
css: item[1],
|
||||||
|
media: item[2],
|
||||||
|
sourceMap: item[3]
|
||||||
|
};
|
||||||
|
|
||||||
|
if (index !== -1) {
|
||||||
|
stylesInDom[index].references++;
|
||||||
|
stylesInDom[index].updater(obj);
|
||||||
|
} else {
|
||||||
|
stylesInDom.push({
|
||||||
|
identifier: identifier,
|
||||||
|
updater: addStyle(obj, options),
|
||||||
|
references: 1
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
identifiers.push(identifier);
|
||||||
|
}
|
||||||
|
|
||||||
|
return identifiers;
|
||||||
|
}
|
||||||
|
|
||||||
|
function insertStyleElement(options) {
|
||||||
|
var style = document.createElement('style');
|
||||||
|
var attributes = options.attributes || {};
|
||||||
|
|
||||||
|
if (typeof attributes.nonce === 'undefined') {
|
||||||
|
var nonce = true ? __webpack_require__.nc : 0;
|
||||||
|
|
||||||
|
if (nonce) {
|
||||||
|
attributes.nonce = nonce;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Object.keys(attributes).forEach(function (key) {
|
||||||
|
style.setAttribute(key, attributes[key]);
|
||||||
|
});
|
||||||
|
|
||||||
|
if (typeof options.insert === 'function') {
|
||||||
|
options.insert(style);
|
||||||
|
} else {
|
||||||
|
var target = getTarget(options.insert || 'head');
|
||||||
|
|
||||||
|
if (!target) {
|
||||||
|
throw new Error("Couldn't find a style target. This probably means that the value for the 'insert' parameter is invalid.");
|
||||||
|
}
|
||||||
|
|
||||||
|
target.appendChild(style);
|
||||||
|
}
|
||||||
|
|
||||||
|
return style;
|
||||||
|
}
|
||||||
|
|
||||||
|
function removeStyleElement(style) {
|
||||||
|
// istanbul ignore if
|
||||||
|
if (style.parentNode === null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
style.parentNode.removeChild(style);
|
||||||
|
}
|
||||||
|
/* istanbul ignore next */
|
||||||
|
|
||||||
|
|
||||||
|
var replaceText = function replaceText() {
|
||||||
|
var textStore = [];
|
||||||
|
return function replace(index, replacement) {
|
||||||
|
textStore[index] = replacement;
|
||||||
|
return textStore.filter(Boolean).join('\n');
|
||||||
|
};
|
||||||
|
}();
|
||||||
|
|
||||||
|
function applyToSingletonTag(style, index, remove, obj) {
|
||||||
|
var css = remove ? '' : obj.media ? "@media ".concat(obj.media, " {").concat(obj.css, "}") : obj.css; // For old IE
|
||||||
|
|
||||||
|
/* istanbul ignore if */
|
||||||
|
|
||||||
|
if (style.styleSheet) {
|
||||||
|
style.styleSheet.cssText = replaceText(index, css);
|
||||||
|
} else {
|
||||||
|
var cssNode = document.createTextNode(css);
|
||||||
|
var childNodes = style.childNodes;
|
||||||
|
|
||||||
|
if (childNodes[index]) {
|
||||||
|
style.removeChild(childNodes[index]);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (childNodes.length) {
|
||||||
|
style.insertBefore(cssNode, childNodes[index]);
|
||||||
|
} else {
|
||||||
|
style.appendChild(cssNode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function applyToTag(style, options, obj) {
|
||||||
|
var css = obj.css;
|
||||||
|
var media = obj.media;
|
||||||
|
var sourceMap = obj.sourceMap;
|
||||||
|
|
||||||
|
if (media) {
|
||||||
|
style.setAttribute('media', media);
|
||||||
|
} else {
|
||||||
|
style.removeAttribute('media');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sourceMap && typeof btoa !== 'undefined') {
|
||||||
|
css += "\n/*# sourceMappingURL=data:application/json;base64,".concat(btoa(unescape(encodeURIComponent(JSON.stringify(sourceMap)))), " */");
|
||||||
|
} // For old IE
|
||||||
|
|
||||||
|
/* istanbul ignore if */
|
||||||
|
|
||||||
|
|
||||||
|
if (style.styleSheet) {
|
||||||
|
style.styleSheet.cssText = css;
|
||||||
|
} else {
|
||||||
|
while (style.firstChild) {
|
||||||
|
style.removeChild(style.firstChild);
|
||||||
|
}
|
||||||
|
|
||||||
|
style.appendChild(document.createTextNode(css));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var singleton = null;
|
||||||
|
var singletonCounter = 0;
|
||||||
|
|
||||||
|
function addStyle(obj, options) {
|
||||||
|
var style;
|
||||||
|
var update;
|
||||||
|
var remove;
|
||||||
|
|
||||||
|
if (options.singleton) {
|
||||||
|
var styleIndex = singletonCounter++;
|
||||||
|
style = singleton || (singleton = insertStyleElement(options));
|
||||||
|
update = applyToSingletonTag.bind(null, style, styleIndex, false);
|
||||||
|
remove = applyToSingletonTag.bind(null, style, styleIndex, true);
|
||||||
|
} else {
|
||||||
|
style = insertStyleElement(options);
|
||||||
|
update = applyToTag.bind(null, style, options);
|
||||||
|
|
||||||
|
remove = function remove() {
|
||||||
|
removeStyleElement(style);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
update(obj);
|
||||||
|
return function updateStyle(newObj) {
|
||||||
|
if (newObj) {
|
||||||
|
if (newObj.css === obj.css && newObj.media === obj.media && newObj.sourceMap === obj.sourceMap) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
update(obj = newObj);
|
||||||
|
} else {
|
||||||
|
remove();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = function (list, options) {
|
||||||
|
options = options || {}; // Force single-tag solution on IE6-9, which has a hard limit on the # of <style>
|
||||||
|
// tags it will allow on a page
|
||||||
|
|
||||||
|
if (!options.singleton && typeof options.singleton !== 'boolean') {
|
||||||
|
options.singleton = isOldIE();
|
||||||
|
}
|
||||||
|
|
||||||
|
list = list || [];
|
||||||
|
var lastIdentifiers = modulesToDom(list, options);
|
||||||
|
return function update(newList) {
|
||||||
|
newList = newList || [];
|
||||||
|
|
||||||
|
if (Object.prototype.toString.call(newList) !== '[object Array]') {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (var i = 0; i < lastIdentifiers.length; i++) {
|
||||||
|
var identifier = lastIdentifiers[i];
|
||||||
|
var index = getIndexByIdentifier(identifier);
|
||||||
|
stylesInDom[index].references--;
|
||||||
|
}
|
||||||
|
|
||||||
|
var newLastIdentifiers = modulesToDom(newList, options);
|
||||||
|
|
||||||
|
for (var _i = 0; _i < lastIdentifiers.length; _i++) {
|
||||||
|
var _identifier = lastIdentifiers[_i];
|
||||||
|
|
||||||
|
var _index = getIndexByIdentifier(_identifier);
|
||||||
|
|
||||||
|
if (stylesInDom[_index].references === 0) {
|
||||||
|
stylesInDom[_index].updater();
|
||||||
|
|
||||||
|
stylesInDom.splice(_index, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
lastIdentifiers = newLastIdentifiers;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
/***/ }),
|
||||||
|
/* 3 */
|
||||||
|
/***/ (function(module, __webpack_exports__, __webpack_require__) {
|
||||||
|
|
||||||
|
__webpack_require__.r(__webpack_exports__);
|
||||||
|
/* harmony import */ var _node_modules_css_loader_dist_runtime_api_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(4);
|
||||||
|
/* harmony import */ var _node_modules_css_loader_dist_runtime_api_js__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(_node_modules_css_loader_dist_runtime_api_js__WEBPACK_IMPORTED_MODULE_0__);
|
||||||
|
// Imports
|
||||||
|
|
||||||
|
var ___CSS_LOADER_EXPORT___ = _node_modules_css_loader_dist_runtime_api_js__WEBPACK_IMPORTED_MODULE_0___default()(function(i){return i[1]});
|
||||||
|
// Module
|
||||||
|
___CSS_LOADER_EXPORT___.push([module.id, "* {\n margin: 0;\n padding: 0;\n -webkit-box-sizing: border-box;\n box-sizing: border-box;\n}\nbody {\n width: 100vw;\n height: 100vh;\n display: -webkit-box;\n display: -ms-flexbox;\n display: flex;\n -webkit-box-pack: center;\n -ms-flex-pack: center;\n justify-content: center;\n -webkit-box-align: center;\n -ms-flex-align: center;\n align-items: center;\n}\n.main {\n display: -webkit-box;\n display: -ms-flexbox;\n display: flex;\n -webkit-box-orient: vertical;\n -webkit-box-direction: normal;\n -ms-flex-direction: column;\n flex-direction: column;\n -webkit-box-align: center;\n -ms-flex-align: center;\n align-items: center;\n -ms-flex-pack: distribute;\n justify-content: space-around;\n width: 360px;\n height: 420px;\n background-color: #ccc;\n border: 10px solid black;\n border-radius: 40px;\n}\n.stage {\n position: relative;\n width: 304px;\n height: 304px;\n border: 2px solid black;\n}\n.stage .snake > div {\n position: absolute;\n width: 10px;\n height: 10px;\n background-color: #000;\n border: 1px solid #ccc;\n}\n.stage .food {\n position: absolute;\n top: 0;\n left: 20px;\n width: 10px;\n height: 10px;\n background-color: yellow;\n border: 1px solid #ccc;\n border-radius: 50%;\n}\n.point {\n display: -webkit-box;\n display: -ms-flexbox;\n display: flex;\n -ms-flex-pack: distribute;\n justify-content: space-around;\n width: 100%;\n}\n", ""]);
|
||||||
|
// Exports
|
||||||
|
/* harmony default export */ __webpack_exports__["default"] = (___CSS_LOADER_EXPORT___);
|
||||||
|
|
||||||
|
|
||||||
|
/***/ }),
|
||||||
|
/* 4 */
|
||||||
|
/***/ (function(module) {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
MIT License http://www.opensource.org/licenses/mit-license.php
|
||||||
|
Author Tobias Koppers @sokra
|
||||||
|
*/
|
||||||
|
// css base code, injected by the css-loader
|
||||||
|
// eslint-disable-next-line func-names
|
||||||
|
module.exports = function (cssWithMappingToString) {
|
||||||
|
var list = []; // return the list of modules as css string
|
||||||
|
|
||||||
|
list.toString = function toString() {
|
||||||
|
return this.map(function (item) {
|
||||||
|
var content = cssWithMappingToString(item);
|
||||||
|
|
||||||
|
if (item[2]) {
|
||||||
|
return "@media ".concat(item[2], " {").concat(content, "}");
|
||||||
|
}
|
||||||
|
|
||||||
|
return content;
|
||||||
|
}).join("");
|
||||||
|
}; // import a list of modules into the list
|
||||||
|
// eslint-disable-next-line func-names
|
||||||
|
|
||||||
|
|
||||||
|
list.i = function (modules, mediaQuery, dedupe) {
|
||||||
|
if (typeof modules === "string") {
|
||||||
|
// eslint-disable-next-line no-param-reassign
|
||||||
|
modules = [[null, modules, ""]];
|
||||||
|
}
|
||||||
|
|
||||||
|
var alreadyImportedModules = {};
|
||||||
|
|
||||||
|
if (dedupe) {
|
||||||
|
for (var i = 0; i < this.length; i++) {
|
||||||
|
// eslint-disable-next-line prefer-destructuring
|
||||||
|
var id = this[i][0];
|
||||||
|
|
||||||
|
if (id != null) {
|
||||||
|
alreadyImportedModules[id] = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (var _i = 0; _i < modules.length; _i++) {
|
||||||
|
var item = [].concat(modules[_i]);
|
||||||
|
|
||||||
|
if (dedupe && alreadyImportedModules[item[0]]) {
|
||||||
|
// eslint-disable-next-line no-continue
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mediaQuery) {
|
||||||
|
if (!item[2]) {
|
||||||
|
item[2] = mediaQuery;
|
||||||
|
} else {
|
||||||
|
item[2] = "".concat(mediaQuery, " and ").concat(item[2]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
list.push(item);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return list;
|
||||||
|
};
|
||||||
|
|
||||||
|
/***/ }),
|
||||||
|
/* 5 */
|
||||||
|
/***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) {
|
||||||
|
|
||||||
|
__webpack_require__.r(__webpack_exports__);
|
||||||
|
/* harmony import */ var _snake__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(6);
|
||||||
|
/* harmony import */ var _food__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(7);
|
||||||
|
/* harmony import */ var _point__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(8);
|
||||||
|
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
|
||||||
|
|
||||||
|
function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }
|
||||||
|
|
||||||
|
function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }
|
||||||
|
|
||||||
|
//游戏控制器
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
var GameControl = /*#__PURE__*/function () {
|
||||||
|
function GameControl() {
|
||||||
|
_classCallCheck(this, GameControl);
|
||||||
|
|
||||||
|
// 存储移动的方向
|
||||||
|
this.direction = ''; // 游戏是否继续
|
||||||
|
|
||||||
|
this.isLive = true;
|
||||||
|
this.snake = new _snake__WEBPACK_IMPORTED_MODULE_0__.default();
|
||||||
|
this.food = new _food__WEBPACK_IMPORTED_MODULE_1__.default();
|
||||||
|
this.point = new _point__WEBPACK_IMPORTED_MODULE_2__.default(10, 3);
|
||||||
|
this.init();
|
||||||
|
} // 游戏初始化的方法
|
||||||
|
|
||||||
|
|
||||||
|
_createClass(GameControl, [{
|
||||||
|
key: "init",
|
||||||
|
value: function init() {
|
||||||
|
// 绑定键盘事件
|
||||||
|
document.addEventListener('keydown', this.keydownHandle.bind(this)); // document调用这个函数, 这里的this是document, 所以要么改成箭头函数,要么用bind
|
||||||
|
|
||||||
|
this.run();
|
||||||
|
} // 按键按下事件
|
||||||
|
|
||||||
|
}, {
|
||||||
|
key: "keydownHandle",
|
||||||
|
value: function keydownHandle(e) {
|
||||||
|
// console.log(this)
|
||||||
|
// console.log(e.key);
|
||||||
|
this.direction = e.key;
|
||||||
|
} // 蛇移动的方法
|
||||||
|
|
||||||
|
}, {
|
||||||
|
key: "run",
|
||||||
|
value: function run() {
|
||||||
|
var X = this.snake.X;
|
||||||
|
var Y = this.snake.Y; // 检查有没有吃到食物
|
||||||
|
|
||||||
|
this.checkEat(X, Y); // 控制移动
|
||||||
|
|
||||||
|
switch (this.direction) {
|
||||||
|
// 上
|
||||||
|
case "ArrowUp":
|
||||||
|
case "Up":
|
||||||
|
Y -= 10;
|
||||||
|
break;
|
||||||
|
//下
|
||||||
|
|
||||||
|
case "ArrowDown":
|
||||||
|
case "Down":
|
||||||
|
Y += 10;
|
||||||
|
break;
|
||||||
|
// 左
|
||||||
|
|
||||||
|
case "ArrowLeft":
|
||||||
|
case "Left":
|
||||||
|
X -= 10;
|
||||||
|
break;
|
||||||
|
// 右
|
||||||
|
|
||||||
|
case "ArrowRight":
|
||||||
|
case "Right":
|
||||||
|
X += 10;
|
||||||
|
break;
|
||||||
|
} // 先检查有没有撞墙
|
||||||
|
|
||||||
|
|
||||||
|
try {
|
||||||
|
this.snake.X = X;
|
||||||
|
this.snake.Y = Y;
|
||||||
|
} catch (e) {
|
||||||
|
// 捕获到异常, 结束运行
|
||||||
|
alert(e.message);
|
||||||
|
clearTimeout(this.timeID);
|
||||||
|
this.isLive = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.timeID && clearTimeout(this.timeID); // 短路运算
|
||||||
|
|
||||||
|
if (this.isLive) {
|
||||||
|
this.timeID = setTimeout(this.run.bind(this), 300 - (this.point.level - 1) * 30);
|
||||||
|
}
|
||||||
|
} // 检查是否吃到食物
|
||||||
|
|
||||||
|
}, {
|
||||||
|
key: "checkEat",
|
||||||
|
value: function checkEat(X, Y) {
|
||||||
|
if (X === this.food.X && Y === this.food.Y) {
|
||||||
|
console.log('吃到食物');
|
||||||
|
this.food.change();
|
||||||
|
this.point.addScore();
|
||||||
|
this.snake.addBody();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}]);
|
||||||
|
|
||||||
|
return GameControl;
|
||||||
|
}();
|
||||||
|
|
||||||
|
/* harmony default export */ __webpack_exports__["default"] = (GameControl);
|
||||||
|
|
||||||
|
/***/ }),
|
||||||
|
/* 6 */
|
||||||
|
/***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) {
|
||||||
|
|
||||||
|
__webpack_require__.r(__webpack_exports__);
|
||||||
|
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
|
||||||
|
|
||||||
|
function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }
|
||||||
|
|
||||||
|
function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }
|
||||||
|
|
||||||
|
var Snake = /*#__PURE__*/function () {
|
||||||
|
function Snake() {
|
||||||
|
_classCallCheck(this, Snake);
|
||||||
|
|
||||||
|
this.element = document.getElementById('snake');
|
||||||
|
this.head = document.querySelector('#snake>div'); // 提示类型不匹配,断言
|
||||||
|
|
||||||
|
this.bodies = document.getElementById('snake').getElementsByTagName('div'); //query选择符选出来的元素及元素数组是静态的,而getElement这种方法选出的元素是动态的。静态的就是说选出的所有元素的数组,不会随着文档操作而改变.
|
||||||
|
// 在使用的时候getElement这种方法性能比较好,query选择符则比较方便
|
||||||
|
} // 蛇头的坐标
|
||||||
|
|
||||||
|
|
||||||
|
_createClass(Snake, [{
|
||||||
|
key: "X",
|
||||||
|
get: function get() {
|
||||||
|
return this.head.offsetLeft;
|
||||||
|
},
|
||||||
|
set: // 设置蛇头的坐标
|
||||||
|
function set(value) {
|
||||||
|
if (this.X == value) return; // 蛇撞墙
|
||||||
|
|
||||||
|
if (value < 0 || value > 290) {
|
||||||
|
throw new Error('蛇撞墙了');
|
||||||
|
} // 没撞墙
|
||||||
|
// 长度大于1时,禁止掉头
|
||||||
|
|
||||||
|
|
||||||
|
if (this.bodies[1] && this.bodies[1].offsetLeft === value) {
|
||||||
|
console.log("发生了掉头");
|
||||||
|
|
||||||
|
if (value > this.X) {
|
||||||
|
// 向右掉头, 则要往左修正value
|
||||||
|
value = this.X - 10;
|
||||||
|
} else {
|
||||||
|
value = this.X + 10;
|
||||||
|
}
|
||||||
|
} // 移动身体
|
||||||
|
|
||||||
|
|
||||||
|
this.moveBody(); // 这里同样要先移动身体, 再移动头
|
||||||
|
// 移动头
|
||||||
|
|
||||||
|
this.head.style.left = value + 'px'; // 检查头是否撞到了身体
|
||||||
|
|
||||||
|
if (this.bodies.length > 4) {
|
||||||
|
this.checkBreak();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
key: "Y",
|
||||||
|
get: function get() {
|
||||||
|
return this.head.offsetTop;
|
||||||
|
},
|
||||||
|
set: function set(value) {
|
||||||
|
if (this.Y == value) return; // 蛇撞墙
|
||||||
|
|
||||||
|
if (value < 0 || value > 290) {
|
||||||
|
throw new Error('蛇撞墙了');
|
||||||
|
} // 没撞墙
|
||||||
|
// 长度大于1 , 禁止掉头
|
||||||
|
|
||||||
|
|
||||||
|
if (this.bodies[1] && this.bodies[1].offsetTop === value) {
|
||||||
|
console.log("发生了掉头");
|
||||||
|
|
||||||
|
if (value > this.Y) {
|
||||||
|
// 向下掉头, 则要往上修正value
|
||||||
|
value = this.Y - 10;
|
||||||
|
} else {
|
||||||
|
value = this.Y + 10;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.moveBody();
|
||||||
|
this.head.style.top = value + 'px'; // 检查头是否撞到了身体
|
||||||
|
|
||||||
|
this.checkBreak();
|
||||||
|
} // 增加身体
|
||||||
|
|
||||||
|
}, {
|
||||||
|
key: "addBody",
|
||||||
|
value: function addBody() {
|
||||||
|
this.element.insertAdjacentHTML("beforeend", "<div></div>");
|
||||||
|
} // 移动身体
|
||||||
|
// 最后一节移到倒数第二节, 把倒数第二节移到倒数第三节 ... 从后开始移动
|
||||||
|
// 蛇头不用管
|
||||||
|
|
||||||
|
}, {
|
||||||
|
key: "moveBody",
|
||||||
|
value: function moveBody() {
|
||||||
|
for (var i = this.bodies.length - 1; i > 0; i--) {
|
||||||
|
// 前一截的位置
|
||||||
|
var x = this.bodies[i - 1].offsetLeft;
|
||||||
|
var y = this.bodies[i - 1].offsetTop; // HTMLElement 对象表示 HTML 中的一个元素。
|
||||||
|
// HTMLElement 对象继承了Element 对象的标准属性,也实现了一些非标准属性
|
||||||
|
// HTMLElement 简单的看成Element的子类
|
||||||
|
// 给当前的一截赋值
|
||||||
|
|
||||||
|
this.bodies[i].style.left = x + 'px';
|
||||||
|
this.bodies[i].style.top = y + 'px';
|
||||||
|
}
|
||||||
|
} // 检查撞身体
|
||||||
|
|
||||||
|
}, {
|
||||||
|
key: "checkBreak",
|
||||||
|
value: function checkBreak() {
|
||||||
|
for (var i = 4; i < this.bodies.length; i++) {
|
||||||
|
var bd = this.bodies[i];
|
||||||
|
|
||||||
|
if (bd.offsetLeft === this.X && bd.offsetTop === this.Y) {
|
||||||
|
throw new Error('蛇撞到自己了');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}]);
|
||||||
|
|
||||||
|
return Snake;
|
||||||
|
}();
|
||||||
|
|
||||||
|
/* harmony default export */ __webpack_exports__["default"] = (Snake);
|
||||||
|
|
||||||
|
/***/ }),
|
||||||
|
/* 7 */
|
||||||
|
/***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) {
|
||||||
|
|
||||||
|
__webpack_require__.r(__webpack_exports__);
|
||||||
|
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
|
||||||
|
|
||||||
|
function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }
|
||||||
|
|
||||||
|
function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }
|
||||||
|
|
||||||
|
// 定义食物类
|
||||||
|
var Food = /*#__PURE__*/function () {
|
||||||
|
function Food() {
|
||||||
|
_classCallCheck(this, Food);
|
||||||
|
|
||||||
|
this.element = document.getElementById('food'); // 这里的感叹号是非null和非undefined的类型断言
|
||||||
|
|
||||||
|
this.change();
|
||||||
|
} // 获取食物的坐标
|
||||||
|
|
||||||
|
|
||||||
|
_createClass(Food, [{
|
||||||
|
key: "X",
|
||||||
|
get: function get() {
|
||||||
|
return this.element.offsetLeft;
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
key: "Y",
|
||||||
|
get: function get() {
|
||||||
|
return this.element.offsetTop;
|
||||||
|
} // 修改食物的坐标
|
||||||
|
|
||||||
|
}, {
|
||||||
|
key: "change",
|
||||||
|
value: function change() {
|
||||||
|
this.element.style.left = Math.round(Math.random() * 29) * 10 + 'px';
|
||||||
|
this.element.style.top = Math.round(Math.random() * 29) * 10 + 'px';
|
||||||
|
}
|
||||||
|
}]);
|
||||||
|
|
||||||
|
return Food;
|
||||||
|
}();
|
||||||
|
|
||||||
|
/* harmony default export */ __webpack_exports__["default"] = (Food);
|
||||||
|
|
||||||
|
/***/ }),
|
||||||
|
/* 8 */
|
||||||
|
/***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) {
|
||||||
|
|
||||||
|
__webpack_require__.r(__webpack_exports__);
|
||||||
|
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
|
||||||
|
|
||||||
|
function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }
|
||||||
|
|
||||||
|
function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }
|
||||||
|
|
||||||
|
//定义统计类
|
||||||
|
var Point = /*#__PURE__*/function () {
|
||||||
|
function Point() {
|
||||||
|
var maxLevel = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 10;
|
||||||
|
var upScore = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 10;
|
||||||
|
|
||||||
|
_classCallCheck(this, Point);
|
||||||
|
|
||||||
|
this.score = 0;
|
||||||
|
this.level = 1;
|
||||||
|
this.maxLevel = maxLevel;
|
||||||
|
this.upScore = upScore;
|
||||||
|
this.scoreEle = document.getElementById('score');
|
||||||
|
this.levelEle = document.getElementById('level');
|
||||||
|
} // 增加积分
|
||||||
|
|
||||||
|
|
||||||
|
_createClass(Point, [{
|
||||||
|
key: "addScore",
|
||||||
|
value: function addScore() {
|
||||||
|
this.scoreEle.innerHTML = ++this.score + ''; // 整除时升级
|
||||||
|
|
||||||
|
if (this.score % this.upScore === 0) {
|
||||||
|
this.levelUp();
|
||||||
|
}
|
||||||
|
} // 增加等级
|
||||||
|
|
||||||
|
}, {
|
||||||
|
key: "levelUp",
|
||||||
|
value: function levelUp() {
|
||||||
|
if (this.level < this.maxLevel) {
|
||||||
|
this.levelEle.innerHTML = ++this.level + '';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}]);
|
||||||
|
|
||||||
|
return Point;
|
||||||
|
}();
|
||||||
|
|
||||||
|
/* harmony default export */ __webpack_exports__["default"] = (Point);
|
||||||
|
|
||||||
|
/***/ })
|
||||||
|
/******/ ]);
|
||||||
|
/************************************************************************/
|
||||||
|
/******/ // The module cache
|
||||||
|
/******/ var __webpack_module_cache__ = {};
|
||||||
|
/******/
|
||||||
|
/******/ // The require function
|
||||||
|
/******/ function __webpack_require__(moduleId) {
|
||||||
|
/******/ // Check if module is in cache
|
||||||
|
/******/ var cachedModule = __webpack_module_cache__[moduleId];
|
||||||
|
/******/ if (cachedModule !== undefined) {
|
||||||
|
/******/ return cachedModule.exports;
|
||||||
|
/******/ }
|
||||||
|
/******/ // Create a new module (and put it into the cache)
|
||||||
|
/******/ var module = __webpack_module_cache__[moduleId] = {
|
||||||
|
/******/ id: moduleId,
|
||||||
|
/******/ // no module.loaded needed
|
||||||
|
/******/ exports: {}
|
||||||
|
/******/ };
|
||||||
|
/******/
|
||||||
|
/******/ // Execute the module function
|
||||||
|
/******/ __webpack_modules__[moduleId](module, module.exports, __webpack_require__);
|
||||||
|
/******/
|
||||||
|
/******/ // Return the exports of the module
|
||||||
|
/******/ return module.exports;
|
||||||
|
/******/ }
|
||||||
|
/******/
|
||||||
|
/************************************************************************/
|
||||||
|
/******/ /* webpack/runtime/compat get default export */
|
||||||
|
/******/ !function() {
|
||||||
|
/******/ // getDefaultExport function for compatibility with non-harmony modules
|
||||||
|
/******/ __webpack_require__.n = function(module) {
|
||||||
|
/******/ var getter = module && module.__esModule ?
|
||||||
|
/******/ function() { return module['default']; } :
|
||||||
|
/******/ function() { return module; };
|
||||||
|
/******/ __webpack_require__.d(getter, { a: getter });
|
||||||
|
/******/ return getter;
|
||||||
|
/******/ };
|
||||||
|
/******/ }();
|
||||||
|
/******/
|
||||||
|
/******/ /* webpack/runtime/define property getters */
|
||||||
|
/******/ !function() {
|
||||||
|
/******/ // define getter functions for harmony exports
|
||||||
|
/******/ __webpack_require__.d = function(exports, definition) {
|
||||||
|
/******/ for(var key in definition) {
|
||||||
|
/******/ if(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {
|
||||||
|
/******/ Object.defineProperty(exports, key, { enumerable: true, get: definition[key] });
|
||||||
|
/******/ }
|
||||||
|
/******/ }
|
||||||
|
/******/ };
|
||||||
|
/******/ }();
|
||||||
|
/******/
|
||||||
|
/******/ /* webpack/runtime/hasOwnProperty shorthand */
|
||||||
|
/******/ !function() {
|
||||||
|
/******/ __webpack_require__.o = function(obj, prop) { return Object.prototype.hasOwnProperty.call(obj, prop); }
|
||||||
|
/******/ }();
|
||||||
|
/******/
|
||||||
|
/******/ /* webpack/runtime/make namespace object */
|
||||||
|
/******/ !function() {
|
||||||
|
/******/ // define __esModule on exports
|
||||||
|
/******/ __webpack_require__.r = function(exports) {
|
||||||
|
/******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) {
|
||||||
|
/******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
||||||
|
/******/ }
|
||||||
|
/******/ Object.defineProperty(exports, '__esModule', { value: true });
|
||||||
|
/******/ };
|
||||||
|
/******/ }();
|
||||||
|
/******/
|
||||||
|
/************************************************************************/
|
||||||
|
var __webpack_exports__ = {};
|
||||||
|
// This entry need to be wrapped in an IIFE because it need to be isolated against other modules in the chunk.
|
||||||
|
!function() {
|
||||||
|
__webpack_require__.r(__webpack_exports__);
|
||||||
|
/* harmony import */ var _index_less__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(1);
|
||||||
|
/* harmony import */ var _modules_gameControl__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(5);
|
||||||
|
|
||||||
|
|
||||||
|
new _modules_gameControl__WEBPACK_IMPORTED_MODULE_1__.default(); // 调试
|
||||||
|
}();
|
||||||
|
/******/ })()
|
||||||
|
;
|
30
dist/index.html
vendored
Normal file
30
dist/index.html
vendored
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
|
<title>贪食蛇</title>
|
||||||
|
<script defer src="bundle.js"></script></head>
|
||||||
|
<body>
|
||||||
|
<!-- 主容器 -->
|
||||||
|
<div class="main">
|
||||||
|
<!-- 游戏区域 -->
|
||||||
|
<div class="stage">
|
||||||
|
<!-- 蛇 -->
|
||||||
|
<div class="snake" id="snake">
|
||||||
|
<div></div>
|
||||||
|
</div>
|
||||||
|
<!-- 食物 -->
|
||||||
|
<div class="food" id="food">
|
||||||
|
<div></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 统计区域 -->
|
||||||
|
<div class="point">
|
||||||
|
<div class="score">Score: <span id="score">0</span></div>
|
||||||
|
<div class="level">Level: <span id="level">1</span></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
8538
package-lock.json
generated
Normal file
8538
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
34
package.json
Normal file
34
package.json
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
{
|
||||||
|
"name": "demo",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"description": "",
|
||||||
|
"main": "index.js",
|
||||||
|
"scripts": {
|
||||||
|
"test": "echo \"Error: no test specified\" && exit 1",
|
||||||
|
"build": "webpack",
|
||||||
|
"start": "webpack serve --open chrome.exe"
|
||||||
|
},
|
||||||
|
"keywords": [],
|
||||||
|
"author": "",
|
||||||
|
"license": "ISC",
|
||||||
|
"devDependencies": {
|
||||||
|
"@babel/core": "^7.13.10",
|
||||||
|
"@babel/preset-env": "^7.13.10",
|
||||||
|
"babel-loader": "^8.2.2",
|
||||||
|
"clean-webpack-plugin": "^3.0.0",
|
||||||
|
"core-js": "^3.9.1",
|
||||||
|
"css-loader": "^5.1.3",
|
||||||
|
"html-webpack-plugin": "^5.3.1",
|
||||||
|
"less": "^4.1.1",
|
||||||
|
"less-loader": "^8.0.0",
|
||||||
|
"postcss": "^8.2.8",
|
||||||
|
"postcss-loader": "^5.2.0",
|
||||||
|
"postcss-preset-env": "^6.7.0",
|
||||||
|
"style-loader": "^2.0.0",
|
||||||
|
"ts-loader": "^8.0.18",
|
||||||
|
"typescript": "^4.2.3",
|
||||||
|
"webpack": "^5.26.0",
|
||||||
|
"webpack-cli": "^4.5.0",
|
||||||
|
"webpack-dev-server": "^3.11.2"
|
||||||
|
}
|
||||||
|
}
|
30
src/index.html
Normal file
30
src/index.html
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
|
<title>贪食蛇</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<!-- 主容器 -->
|
||||||
|
<div class="main">
|
||||||
|
<!-- 游戏区域 -->
|
||||||
|
<div class="stage">
|
||||||
|
<!-- 蛇 -->
|
||||||
|
<div class="snake" id="snake">
|
||||||
|
<div></div>
|
||||||
|
</div>
|
||||||
|
<!-- 食物 -->
|
||||||
|
<div class="food" id="food">
|
||||||
|
<div></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 统计区域 -->
|
||||||
|
<div class="point">
|
||||||
|
<div class="score">Score: <span id="score">0</span></div>
|
||||||
|
<div class="level">Level: <span id="level">1</span></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
59
src/index.less
Normal file
59
src/index.less
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
@bgColor: #ccc;
|
||||||
|
|
||||||
|
* {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
body {
|
||||||
|
width: 100vw;
|
||||||
|
height: 100vh;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
.main {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-around;
|
||||||
|
width: 360px;
|
||||||
|
height: 420px;
|
||||||
|
background-color: @bgColor;
|
||||||
|
border: 10px solid black;
|
||||||
|
border-radius: 40px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.stage{
|
||||||
|
position: relative;
|
||||||
|
width: 304px;
|
||||||
|
height: 304px;
|
||||||
|
border: 2px solid black;
|
||||||
|
|
||||||
|
.snake{
|
||||||
|
&>div{
|
||||||
|
position: absolute;
|
||||||
|
width: 10px;
|
||||||
|
height: 10px;
|
||||||
|
background-color: #000;
|
||||||
|
border: 1px solid @bgColor;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.food{
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 20px;
|
||||||
|
width: 10px;
|
||||||
|
height: 10px;
|
||||||
|
background-color: yellow;
|
||||||
|
border: 1px solid @bgColor;
|
||||||
|
border-radius: 50%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.point{
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-around;
|
||||||
|
width: 100%;
|
||||||
|
}
|
5
src/index.ts
Normal file
5
src/index.ts
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
import './index.less'
|
||||||
|
import gameControl from './modules/gameControl'
|
||||||
|
|
||||||
|
new gameControl()
|
||||||
|
// 调试
|
28
src/modules/food.ts
Normal file
28
src/modules/food.ts
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
// 定义食物类
|
||||||
|
class Food {
|
||||||
|
// 定义一个属性, 食物对应的元素
|
||||||
|
element: HTMLElement // HTMLElement为ts带的类型
|
||||||
|
|
||||||
|
constructor(){
|
||||||
|
this.element = document.getElementById('food')!; // 这里的感叹号是非null和非undefined的类型断言
|
||||||
|
|
||||||
|
this.change()
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取食物的坐标
|
||||||
|
get X(){
|
||||||
|
return this.element.offsetLeft
|
||||||
|
}
|
||||||
|
|
||||||
|
get Y(){
|
||||||
|
return this.element.offsetTop
|
||||||
|
}
|
||||||
|
|
||||||
|
// 修改食物的坐标
|
||||||
|
change(){
|
||||||
|
this.element.style.left = Math.round(Math.random() * 29 ) * 10 + 'px'
|
||||||
|
this.element.style.top = Math.round(Math.random() * 29 ) * 10 + 'px'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Food
|
95
src/modules/gameControl.ts
Normal file
95
src/modules/gameControl.ts
Normal file
@ -0,0 +1,95 @@
|
|||||||
|
//游戏控制器
|
||||||
|
import Snake from './snake'
|
||||||
|
import Food from './food'
|
||||||
|
import Point from './point'
|
||||||
|
|
||||||
|
class GameControl {
|
||||||
|
snake: Snake
|
||||||
|
food: Food
|
||||||
|
point: Point
|
||||||
|
timeID: any
|
||||||
|
|
||||||
|
// 存储移动的方向
|
||||||
|
direction: string = ''
|
||||||
|
|
||||||
|
// 游戏是否继续
|
||||||
|
isLive: boolean = true
|
||||||
|
|
||||||
|
constructor(){
|
||||||
|
this.snake = new Snake()
|
||||||
|
this.food = new Food()
|
||||||
|
this.point = new Point(10, 3)
|
||||||
|
this.init()
|
||||||
|
}
|
||||||
|
|
||||||
|
// 游戏初始化的方法
|
||||||
|
init (){
|
||||||
|
// 绑定键盘事件
|
||||||
|
document.addEventListener('keydown',this.keydownHandle.bind(this))
|
||||||
|
// document调用这个函数, 这里的this是document, 所以要么改成箭头函数,要么用bind
|
||||||
|
|
||||||
|
this.run()
|
||||||
|
}
|
||||||
|
|
||||||
|
// 按键按下事件
|
||||||
|
keydownHandle(e:KeyboardEvent){
|
||||||
|
// console.log(this)
|
||||||
|
// console.log(e.key);
|
||||||
|
this.direction = e.key
|
||||||
|
}
|
||||||
|
|
||||||
|
// 蛇移动的方法
|
||||||
|
run(){
|
||||||
|
let X = this.snake.X
|
||||||
|
let Y = this.snake.Y
|
||||||
|
// 检查有没有吃到食物
|
||||||
|
this.checkEat(X, Y)
|
||||||
|
// 控制移动
|
||||||
|
switch(this.direction) {
|
||||||
|
// 上
|
||||||
|
case "ArrowUp":
|
||||||
|
case "Up": Y -= 10
|
||||||
|
break
|
||||||
|
//下
|
||||||
|
case "ArrowDown":
|
||||||
|
case "Down": Y += 10
|
||||||
|
break
|
||||||
|
// 左
|
||||||
|
case "ArrowLeft":
|
||||||
|
case "Left": X -= 10
|
||||||
|
break
|
||||||
|
// 右
|
||||||
|
case "ArrowRight":
|
||||||
|
case "Right": X += 10
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
// 先检查有没有撞墙
|
||||||
|
try{
|
||||||
|
this.snake.X = X
|
||||||
|
this.snake.Y = Y
|
||||||
|
}catch(e){
|
||||||
|
// 捕获到异常, 结束运行
|
||||||
|
alert(e.message)
|
||||||
|
clearTimeout(this.timeID)
|
||||||
|
this.isLive = false
|
||||||
|
}
|
||||||
|
|
||||||
|
this.timeID && clearTimeout(this.timeID) // 短路运算
|
||||||
|
if(this.isLive){
|
||||||
|
this.timeID = setTimeout (this.run.bind(this), 300 - (this.point.level - 1) * 30)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查是否吃到食物
|
||||||
|
checkEat(X:number, Y:number){
|
||||||
|
if(X === this.food.X && Y === this.food.Y){
|
||||||
|
console.log('吃到食物');
|
||||||
|
this.food.change()
|
||||||
|
this.point.addScore()
|
||||||
|
this.snake.addBody()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default GameControl
|
38
src/modules/point.ts
Normal file
38
src/modules/point.ts
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
//定义统计类
|
||||||
|
class Point {
|
||||||
|
score = 0
|
||||||
|
level = 1
|
||||||
|
scoreEle:HTMLElement
|
||||||
|
levelEle:HTMLElement
|
||||||
|
|
||||||
|
// 最高等级限制
|
||||||
|
maxLevel: number
|
||||||
|
|
||||||
|
// 多少分升一级
|
||||||
|
upScore: number
|
||||||
|
|
||||||
|
constructor(maxLevel:number=10, upScore:number = 10){
|
||||||
|
this.maxLevel = maxLevel
|
||||||
|
this.upScore = upScore
|
||||||
|
this.scoreEle = document.getElementById('score')!
|
||||||
|
this.levelEle = document.getElementById('level')!
|
||||||
|
}
|
||||||
|
|
||||||
|
// 增加积分
|
||||||
|
addScore(){
|
||||||
|
this.scoreEle.innerHTML = ++this.score + ''
|
||||||
|
// 整除时升级
|
||||||
|
if(this.score % this.upScore === 0){
|
||||||
|
this.levelUp()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 增加等级
|
||||||
|
levelUp(){
|
||||||
|
if(this.level < this.maxLevel){
|
||||||
|
this.levelEle.innerHTML = ++this.level + ''
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Point
|
114
src/modules/snake.ts
Normal file
114
src/modules/snake.ts
Normal file
@ -0,0 +1,114 @@
|
|||||||
|
class Snake{
|
||||||
|
element: HTMLElement
|
||||||
|
// 蛇头
|
||||||
|
head:HTMLElement
|
||||||
|
// 蛇的身体(包括蛇头)
|
||||||
|
bodies: HTMLCollection
|
||||||
|
|
||||||
|
constructor(){
|
||||||
|
this.element = document.getElementById('snake')!
|
||||||
|
this.head = document.querySelector('#snake>div') as HTMLElement // 提示类型不匹配,断言
|
||||||
|
this.bodies = document.getElementById('snake')!.getElementsByTagName('div')
|
||||||
|
//query选择符选出来的元素及元素数组是静态的,而getElement这种方法选出的元素是动态的。静态的就是说选出的所有元素的数组,不会随着文档操作而改变.
|
||||||
|
// 在使用的时候getElement这种方法性能比较好,query选择符则比较方便
|
||||||
|
}
|
||||||
|
|
||||||
|
// 蛇头的坐标
|
||||||
|
get X(){
|
||||||
|
return this.head.offsetLeft
|
||||||
|
}
|
||||||
|
|
||||||
|
get Y(){
|
||||||
|
return this.head.offsetTop
|
||||||
|
}
|
||||||
|
|
||||||
|
// 设置蛇头的坐标
|
||||||
|
set X(value: number){
|
||||||
|
if(this.X == value) return
|
||||||
|
|
||||||
|
// 蛇撞墙
|
||||||
|
if(value < 0 || value > 290){
|
||||||
|
throw new Error('蛇撞墙了')
|
||||||
|
}
|
||||||
|
|
||||||
|
// 没撞墙
|
||||||
|
// 长度大于1时,禁止掉头
|
||||||
|
if(this.bodies[1] && (this.bodies[1] as HTMLElement).offsetLeft === value){
|
||||||
|
console.log("发生了掉头");
|
||||||
|
if(value > this.X){
|
||||||
|
// 向右掉头, 则要往左修正value
|
||||||
|
value = this.X - 10
|
||||||
|
} else {
|
||||||
|
value = this.X + 10
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 移动身体
|
||||||
|
this.moveBody() // 这里同样要先移动身体, 再移动头
|
||||||
|
// 移动头
|
||||||
|
this.head.style.left = value + 'px'
|
||||||
|
// 检查头是否撞到了身体
|
||||||
|
if(this.bodies.length > 4){
|
||||||
|
this.checkBreak()
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
set Y(value: number){
|
||||||
|
if(this.Y == value) return
|
||||||
|
// 蛇撞墙
|
||||||
|
if(value < 0 || value > 290){
|
||||||
|
throw new Error('蛇撞墙了')
|
||||||
|
}
|
||||||
|
// 没撞墙
|
||||||
|
// 长度大于1 , 禁止掉头
|
||||||
|
if(this.bodies[1] && (this.bodies[1] as HTMLElement).offsetTop === value){
|
||||||
|
console.log("发生了掉头");
|
||||||
|
if(value > this.Y){
|
||||||
|
// 向下掉头, 则要往上修正value
|
||||||
|
value = this.Y - 10
|
||||||
|
} else {
|
||||||
|
value = this.Y + 10
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.moveBody()
|
||||||
|
this.head.style.top = value + 'px'
|
||||||
|
// 检查头是否撞到了身体
|
||||||
|
this.checkBreak()
|
||||||
|
}
|
||||||
|
|
||||||
|
// 增加身体
|
||||||
|
addBody (){
|
||||||
|
this.element.insertAdjacentHTML("beforeend", "<div></div>")
|
||||||
|
}
|
||||||
|
|
||||||
|
// 移动身体
|
||||||
|
// 最后一节移到倒数第二节, 把倒数第二节移到倒数第三节 ... 从后开始移动
|
||||||
|
// 蛇头不用管
|
||||||
|
moveBody(){
|
||||||
|
for(let i = this.bodies.length - 1; i > 0; i--){
|
||||||
|
// 前一截的位置
|
||||||
|
let x = (this.bodies[i - 1] as HTMLElement).offsetLeft
|
||||||
|
let y = (this.bodies[i - 1] as HTMLElement).offsetTop;
|
||||||
|
|
||||||
|
// HTMLElement 对象表示 HTML 中的一个元素。
|
||||||
|
// HTMLElement 对象继承了Element 对象的标准属性,也实现了一些非标准属性
|
||||||
|
// HTMLElement 简单的看成Element的子类
|
||||||
|
|
||||||
|
// 给当前的一截赋值
|
||||||
|
(this.bodies[i] as HTMLElement).style.left = x + 'px';
|
||||||
|
(this.bodies[i] as HTMLElement).style.top = y + 'px';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查撞身体
|
||||||
|
checkBreak(){
|
||||||
|
for(let i = 4; i < this.bodies.length; i++){
|
||||||
|
let bd = this.bodies[i] as HTMLElement
|
||||||
|
if(bd.offsetLeft === this.X && bd.offsetTop === this.Y){
|
||||||
|
throw new Error('蛇撞到自己了')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Snake
|
9
tsconfig.json
Normal file
9
tsconfig.json
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
{
|
||||||
|
// 随便配置下
|
||||||
|
"compilerOptions": {
|
||||||
|
"module": "ES2015",
|
||||||
|
"target": "ES2015",
|
||||||
|
"strict": true,
|
||||||
|
"noEmitOnError": true
|
||||||
|
}
|
||||||
|
}
|
103
webpack.config.js
Normal file
103
webpack.config.js
Normal file
@ -0,0 +1,103 @@
|
|||||||
|
const path = require('path')
|
||||||
|
const htmlWebpackPlugin = require('html-webpack-plugin')
|
||||||
|
const { CleanWebpackPlugin } = require('clean-webpack-plugin')
|
||||||
|
|
||||||
|
// webpack中的所有信息都写在这里
|
||||||
|
module.exports = {
|
||||||
|
mode: 'none',
|
||||||
|
// 指定入口文件
|
||||||
|
entry: './src/index.ts',
|
||||||
|
|
||||||
|
//指定打包文件的左右目录
|
||||||
|
output: {
|
||||||
|
// 制定打包文件的目录
|
||||||
|
path: path.resolve(__dirname, 'dist'),
|
||||||
|
// 打包后文件的文件名
|
||||||
|
filename: 'bundle.js',
|
||||||
|
// 告诉webpack不使用箭头函数,const
|
||||||
|
environment: {
|
||||||
|
arrowFunction: false,
|
||||||
|
const:false
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
// 指定webpack打包时要使用的模块
|
||||||
|
module: {
|
||||||
|
// 指定要加载的规则
|
||||||
|
rules: [
|
||||||
|
{
|
||||||
|
// test指定的是规则生效的文件
|
||||||
|
test: /\.ts$/,
|
||||||
|
// 使用loader, loader的执行顺序是从下往上的
|
||||||
|
use: [
|
||||||
|
// 配置babel
|
||||||
|
{
|
||||||
|
// 指定加载器
|
||||||
|
loader: 'babel-loader',
|
||||||
|
// 配置项
|
||||||
|
options: {
|
||||||
|
// 设置预定义环境
|
||||||
|
presets: [
|
||||||
|
[
|
||||||
|
// 指定环境的插件
|
||||||
|
'@babel/preset-env',
|
||||||
|
// 配置信息
|
||||||
|
{
|
||||||
|
// 要兼容的浏览器
|
||||||
|
targets: {
|
||||||
|
chrome: '58',
|
||||||
|
ie: '11',
|
||||||
|
},
|
||||||
|
// 指定corejs的版本
|
||||||
|
corejs: '3',
|
||||||
|
// 使用corejs的方式, usage按需加载
|
||||||
|
useBuiltIns: 'usage',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
'ts-loader',
|
||||||
|
],
|
||||||
|
// 排除的文件
|
||||||
|
exclude: /node-modules/,
|
||||||
|
},
|
||||||
|
|
||||||
|
// less文件的处理
|
||||||
|
{
|
||||||
|
test: /\.less$/,
|
||||||
|
use: [
|
||||||
|
'style-loader',
|
||||||
|
'css-loader',
|
||||||
|
// postcss配置
|
||||||
|
{
|
||||||
|
loader: "postcss-loader",
|
||||||
|
options: {
|
||||||
|
postcssOptions: {
|
||||||
|
plugins: [
|
||||||
|
"postcss-preset-env"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
'less-loader'
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
|
||||||
|
// webpack插件配置
|
||||||
|
plugins: [
|
||||||
|
// 大包前先清空旧的文件
|
||||||
|
new CleanWebpackPlugin(),
|
||||||
|
new htmlWebpackPlugin({
|
||||||
|
// title: "自定义标题"
|
||||||
|
template: './src/index.html',
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
|
||||||
|
// 设置引用模块
|
||||||
|
resolve: {
|
||||||
|
extensions: ['.ts', '.js'],
|
||||||
|
},
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user