js实现一款升级益智类小游戏代码
代码语言:html
所属分类:游戏
代码描述:js实现一款升级益智类小游戏代码,玩法:将鼠标拖拽转动把小熊方到星星上即可升级。
下面为部分代码预览,完整代码请点击下载或在bfwstudio webide中打开
<!DOCTYPE html> <html lang="en" > <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1"> <style> * { box-sizing: border-box; } body { margin: 0; padding: 0; overflow-x: hidden; font-family: 'Avenir Next', Avenir, sans-serif; font-weight: 500; font-size: 20px; color: #555; background-color: #1B1B1B; } canvas { cursor: move; display: block; position: absolute; max-width: 100%; left: 0; top: 0; } .is-cub-hovered, .is-cub-hovered canvas { cursor: -webkit-grab; cursor: grab; } .is-cub-dragging, .is-cub-dragging canvas { cursor: -webkit-grabbing; cursor: grabbing; } .instruction { padding: 0 10px; text-align: center; position: absolute; width: 100%; padding-bottom: 40px; } .button { font-family: 'Avenir Next', Avenir, sans-serif; font-weight: 500; font-size: 20px; padding: 5px 15px; margin: 10px; background: #BBB; color: white; border-radius: 5px; border: none; cursor: pointer; } .button:hover { background: #09F; } .top-bar { position: absolute; left: 0; top: 0; } .level-select-button { position: relative; z-index: 2; /* above canvas */ } .next-level-button { position: absolute; left: 50%; -webkit-transform: translateX(-110px) scale(0.5); transform: translateX(-110px) scale(0.5); opacity: 0; background: #09F; width: 200px; height: 80px; pointer-events: none; -webkit-transition: -webkit-transform 0.2s, opacity 0.2s; transition: transform 0.2s, opacity 0.2s; } .next-level-button:hover { background: #2BF; } .next-level-button.is-open { display: inline-block; pointer-events: auto; -webkit-transform: translateX(-110px) scale(1); transform: translate(-110px) scale(1); opacity: 1; } /* ---- level list ---- */ .level-list { position: absolute; background: #EEE; width: 100%; min-height: 100%; left: 0; top: 0; margin: 0; list-style: none; padding: 10px; z-index: 3; /* above canvas, level select button */ left: -100%; transition: left 0.2s; } .level-list.is-open { left: 0; } .level-list__item { display: inline-block; background: #DDD; margin: 5px; padding: 10px; width: 80px; height: 80px; text-align: center; border-radius: 10px; position: relative; } .level-list__item:hover { color: #09F; cursor: pointer; background: white; } .level-list__item.is-playing { background: #09F; color: white; } .level-list__item__number { display: block; font-size: 30px; line-height: 35px; } .level-list__item__blurb { display: block; font-size: 16px; } .level-list__item__check { position: absolute; right: -10px; top: -10px; width: 30px; line-height: 30px; background: #555; border-radius: 15px; color: white; display: none; } .level-list__item.did-complete .level-list__item__check { display: block; } /* ---- level pres ---- */ .levels { display: none; } </style> </head> <body> <div class="top-bar"> <button class="button level-select-button">Levels</button> </div> <ol class="level-list"></ol> <canvas></canvas> <p class="instruction"></p> <button class="button next-level-button">Next level</button> <div class="levels"> <pre id="intro-fixed1" data-blurb="Tutorial"> blurb: Tutorial instruction: Drag cub to star --- *=.=. ! . . . ! @=.=. </pre> <pre id="intro-fixed2" data-blurb="Tutorial"> blurb: Tutorial instruction: Drag grid to rotate. Cub and star moves with grid. Orange links stay in place. --- * . . ! . . . ! @=.=. </pre> <pre id="intro-fixed3" data-blurb="★"> blurb: ★ --- @=. . . . . ! *=. . </pre> <pre id="intro-free1" data-blurb="Tutorial"> blurb: Tutorial instruction: Blue links move with grid. Rotate grid to connect blue and orange links in different ways. --- @-. . ! | . . . | *-.-. </pre> <pre id="m3x3-2-med" data-blurb="★"> blurb: ★ --- . . * | | | . . . | | | @ .=. </pre> <pre id="m3x3-fixed-switch" data-blurb="★"> blurb: ★ --- *=.-. . . . | @-. . </pre> <pre id="m4x4-2" data-blurb="★"> blurb: ★ --- . .=. . | ! . . .-* | . . . . . @-. . </pre> <pre id="m4x4-1" data-blurb="★"> blurb: ★ --- . . . . * . . @ | ! | . . . . ! . . . . </pre> <pre id="m4x4-3" data-blurb="★"> blurb: ★ --- . @ . . ! | . . . . | .=.=.-. | . * . . </pre> <pre id="m4x4-4" data-blurb="★"> blurb: ★ --- . . . . * . . . ! . . .-. ! .=.=. @ </pre> <pre id="m4x4-5" data-blurb="★"> blurb: ★ --- .-.-.-. | @ .-.-. * .=. . ! | .-.-. . </pre> <pre id="m4x4-6-med" data-blurb="★"> blurb: ★ --- . * . . .-.=. . | . . . . ! | .=. @ . </pre> <pre id="m4x4-7-hard1" data-blurb="★★"> blurb: ★★ --- . . *-. .-.=. . | .=. . . | | @-.-.=. </pre> <pre id="m4x4-8-hard2" data-blurb="★★"> blurb: ★★ --- .-@ .=. . . . . | .-. .-* | . .=.-. </pre> <pre id="m4x4-9-hard1" data-blurb="★★"> blurb: ★★ --- . . .=. ! @-. .-. . .=. . . . * . </pre> <pre id="m4x4-10-hard1" data-blurb="★★"> blurb: ★★ --- . @=. . | . .-.-. .-.-.-. ! ! . * . . </pre> <pre id="m5x5-3" data-blurb="★"> . . . . . | ! . . .-. . | . . . . * | . . .=. . | . @ . . . </pre> <pre id="m5x5-1" data-blurb="★"> @-.-. .-. | . . . . . . . .=. . . . . .=. | . .=.-* . </pre> <pre id="m5x5-2" data-blurb="★★"> . . . . . . .=.-. @ | ! . . . .-. .=. . .=. ! * . . . . </pre> <pre id="m5x5-4" data-blurb="★★"> . . . .-. ! . .-. . . ! | .=. . . . | . . . . * | .-@=. .=. </pre> <pre id="m5x5-5" data-blurb="★★"> . . . . . . . .-. * ! . . .-. . .=. . . . | . @-. . . </pre> <pre id="m5x5-6" data-blurb="★★"> . . .-.-. ! ! . .=.-. . | . .-. .-@ ! * .=. . . | .=. .-.=. </pre> <pre id="m5x5-7" data-blurb="★★★"> .=* . @=. | . .=. . . | | | .=. . .-. | . . . .=. ! . .-.-. . </pre> <pre id="m5x5-8" data-blurb="★★★"> . * . .-. | . . .=.-. ! | . . . . . . .-. .=. | . . .=.-@ </pre> <pre id="m5x5-9" data-blurb="★★★"> .-.-. . . | . . . .-@ ! * . .-. . | ! .-. . .=. | ! . . .=. . </pre> <pre id="m5x5-10" data-blurb="★★"> . . . . . . . . .-@ ! * . .=. . | ! .-. . . . . . . . . </pre> <pre id="m5x5-11" data-blurb="★★★"> . . . .=. | . . . .=. | . . .-. . ! | . .=. . . | ! ! .-@ . * . </pre> <pre id="m5x5-12" data-blurb="★★"> . . .=.=. . . . . . . . . . @ . . . . . * . .=.=. </pre> <pre id="m6x6-1-hard1" data-blurb="★★★"> . . * . . . ! | | . .-. .-. . | . . . . .-. | ! | . . .=. . . | @-.-. .-. . | . .=. . .-. </pre> <pre id="m6x6-2" data-blurb="★★★"> @ .=. . .=. | | ! . . . .=. . | | . . . .-. . | ! . . . . . * | | .=. .-. . . | | | .-. . . .=. </pre> <pre id="m6x6-3" data-blurb="★★★"> .=. .=.-.-* | .-. . . . . | ! . . .-.-. . ! .-. .=.=. . @ .=. . . . | ! . .-. .-. . </pre> <pre id="pivot-4x4-intro" data-blurb="Tutorial"> instruction: Green links pivot with grid, but point in the same direction --- . .-* . | . . . . . .>. . . @ . . </pre> <pre id="pivot-5x5-2" data-blurb="★★"> . . .-.-@ . .<. . . .>. . . . | ! .-.-. . * ! . . . . . </pre> <pre id="pivot-5x5-swirly" data-blurb="★★★"> . . . . . ^ .<. . . * . . . . . @ . . .>. v . . . . . </pre> <pre id="pivot-5x5-1" data-blurb="★★★"> . .-. . . ^ . .<.=.=. .>. . .-@ * . . .=. . . . . . </pre> <pre id="pivot-5x5-3" data-blurb="★★"> .=. . .-* v . . . . . . . .-.J. @-. . . . v .<. . . . </pre> <pre id="pivot-5x5-4" data-blurb="★★★"> .-.-. @>. ! ^ . . . . . | . . . . . | . . . .=* ^ . . .-. .> </pre> <pre id="pivot-5x5-5" data-blurb="★★★"> .-. . . * . .>. . . | v .-. . . . ^ . . .-. . v @=.=. . . </pre> <pre id="pivot-5x5-6" data-blurb="★★★"> . . .>. . ! | @=. .-. . . . . .=.> . . . . . . *>.<. . </pre> <pre id="pivot-5x5-7" data-blurb="★★★"> * . @ . . v | . . . . . ! . . . . . ^ ! ! . .-. . . ! . . . . . v </pre> <pre id="pivot-6x6-1" data-blurb="★★★"> . . . . . . | v @ . . . . * | | . . . . . . | ! ^ | K . . . .-.=. | . .-. . . . v .>. . . . . </pre> <pre id="pivot-6x6-3" data-blurb="★★★"> . @-. .>.-. . . . . . . | * .>. .=. . ! . . . . . .> | ^ . . . .=. . . .=. . .=.> </pre> <pre id="pivot-6x6-2" data-blurb="★★★"> . .-.-. .=. v . . . . . . | ! v .>. . . . * ^ . . . . . . | . .-.<. . . ! | | . . . .>.-@ </pre> <pre id="m44" data-blurb="★★"> . .=. *-. . . .=. . ! . . . . . | ! . . . . . | | . @ . .=. </pre> <pre id="m45" data-blurb="★★"> @ * .>. . . .=.=. . | | .>. . . . . . . .>. | .=. . .-. </pre> <pre id="m46" data-blurb="★★★"> .-. . . ^ . . . . .L. . . ! @ . .-* </pre> <pre id="m47" data-blurb="★★"> @ . . . . . v v v v v v . . . . . . . . . . . . . . . . . . v v v v v . . . . . . . . . .=. * v v v v v </pre> <pre id="m48" data-blurb="★"> .-.<.>.=. . W ! | . . .A. . * | | . .=. . . . ^ ! . .D.-.=.=@ | . . .-.-. . | .#.=. .<. . v v </pre> <pre id="m49" data-blurb="★★★"> . . .-@ . | . . . .J. * . . . . | ! ! . . . . . v ! . . . .-. </pre> <pre id="m50" data-blurb="★★★"> *=. . . v . . . . ^ | . . . . ^ | @ .>. . </pre> <pre id="rotate-tut" data-blurb="Tutorial"> instruction: Red links are fixed in place, but rotate with grid --- . . . . @ .4. . | . . .-* . . . . </pre> <pre id="rotate1" data-blurb="★"> . . .-* | . . . . 5 .4. . . | @ . . . </pre> <pre id="rotate2" data-blurb="★★"> @ .-.=. | . . .4. | * . . . | | . . . . </pre> <pre id="rotate3" data-blurb="★★"> . . * . ! 5 v . . . @ | . .4. . ! . . . . </pre> <pre id="rotate3b" data-blurb="★★"> * . . . ! 5 . . . @ | . .4. . ! . . . . </pre> <pre id="rotate-5x5-1" data-blurb="★★"> . . . .-@ 8 . .=. . . *=. . . . . .-. . . . . . . . </pre> <pre id="rotate-5x5-2" data-blurb="★★"> . . . . . . . . .6* | . . . .=. | .4. . . . | . . . .-@ </pre> <pre id="rotate-5x5-2b" data-blurb="★★★"> . . . . . ! | .-.-. . . v | . . .-. . @ . . . . 5 . . .=* . </pre> <pre id="rotate-6x6-1" data-blurb="★★★"> @4.=. . . . . . . . . . v 8 | .-.-. . . . ! ! ^ . . . . . . . .>. . . . ! * . .4. . . </pre> <pre id="rotate-6x6-2" data-blurb="★★★"> . . *<. . . .=. .-. . . 5 . . . .-. . | . . . . . . . . . . . . 5 | . .=. . @-. </pre> <pre id="rotate-6x6-3" data-blurb="★★★"> .4. . . . @ ! .-. . .=. . ! . . . . . . ! .>.6. . . . ! . . . .=.-. ^ . . . . * . </pre> </div> <script type="text/javascript" src="//repo.bfw.wiki/bfwrepo/js/EvEmitter.1.0.2.js"></script> <script > /*! * Unipointer v2.1.0 * base class for doing one thing with pointer event * MIT license */ /*jshint browser: true, undef: true, unused: true, strict: true */ ( function( window, factory ) { // universal module definition /* jshint strict: false */ /*global define, module, require */ if ( typeof define == 'function' && define.amd ) { // AMD define( [ 'ev-emitter/ev-emitter' ], function( EvEmitter ) { return factory( window, EvEmitter ); }); } else if ( typeof module == 'object' && module.exports ) { // CommonJS module.exports = factory( window, require('ev-emitter') ); } else { // browser global window.Unipointer = factory( window, window.EvEmitter ); } }( window, function factory( window, EvEmitter ) { 'use strict'; function noop() {} function Unipointer() {} // inherit EvEmitter var proto = Unipointer.prototype = Object.create( EvEmitter.prototype ); proto.bindStartEvent = function( elem ) { this._bindStartEvent( elem, true ); }; proto.unbindStartEvent = function( elem ) { this._bindStartEvent( elem, false ); }; /** * works as unbinder, as you can ._bindStart( false ) to unbind * @param {Boolean} isBind - will unbind if falsey */ proto._bindStartEvent = function( elem, isBind ) { // munge isBind, default to true isBind = isBind === undefined ? true : !!isBind; var bindMethod = isBind ? 'addEventListener' : 'removeEventListener'; if ( window.navigator.pointerEnabled ) { // W3C Pointer Events, IE11. See https://coderwall.com/p/mfreca elem[ bindMethod ]( 'pointerdown', this ); } else if ( window.navigator.msPointerEnabled ) { // IE10 Pointer Events elem[ bindMethod ]( 'MSPointerDown', this ); } else { // listen for both, for devices like Chrome Pixel elem[ bindMethod ]( 'mousedown', this ); elem[ bindMethod ]( 'touchstart', this ); } }; // trigger handler methods for events proto.handleEvent = function( event ) { var method = 'on' + event.type; if ( this[ method ] ) { this[ method ]( event ); } }; // returns the touch that we're keeping track of proto.getTouch = function( touches ) { for ( var i=0; i < touches.length; i++ ) { var touch = touches[i]; if ( touch.identifier == this.pointerIdentifier ) { return touch; } } }; // ----- start event ----- // proto.onmousedown = function( event ) { // dismiss clicks from right or middle buttons var button = event.button; if ( button && ( button !== 0 && button !== 1 ) ) { return; } this._pointerDown( event, event ); }; proto.ontouchstart = function( event ) { this._pointerDown( event, event.changedTouches[0] ); }; proto.onMSPointerDown = proto.onpointerdown = function( event ) { this._pointerDown( event, event ); }; /** * pointer start * @param {Event} event * @param {Event or Touch} pointer */ proto._pointerDown = function( event, pointer ) { // dismiss other pointers if ( this.isPointerDown ) { return; } this.isPointerDown = true; // save pointer identifier to match up touch events this.pointerIdentifier = pointer.pointerId !== undefined ? // pointerId for pointer events, touch.indentifier for touch events pointer.pointerId : pointer.identifier; this.pointerDown( event, pointer ); }; proto.pointerDown = function( event, pointer ) { this._bindPostStartEvents( event ); this.emitEvent( 'pointerDown', [ event, pointer ] ); }; // hash of events to be bound after start event var postStartEvents = { mousedown: [ 'mousemove', 'mouseup' ], touchstart: [ 'touchmove', 'touchend', 'touchcancel' ], pointerdown: [ 'pointermove', 'pointerup', 'pointercancel' ], MSPointerDown: [ 'MSPointerMove', 'MSPointerUp', 'MSPointerCancel' ] }; proto._bindPostStartEvents = function( event ) { if ( !event ) { return; } // get proper events to match start event var events = postStartEvents[ event.type ]; // bind events to node events.forEach( function( eventName ) { window.addEventListener( eventName, this ); }, this ); // save these arguments this._boundPointerEvents = events; }; proto._unbindPostStartEvents = function() { // check for _boundEvents, in case dragEnd triggered twice (old IE8 bug) if ( !this._boundPointerEvents ) { return; } this._boundPointerEvents.forEach( function( eventName ) { window.removeEventListener( eventName, this ); }, this ); delete this._boundPointerEvents; }; // ----- move event ----- // proto.onmousemove = function( event ) { this._pointerMove( event, event ); }; proto.onMSPointerMove = proto.onpointermove = function( event ) { if ( event.pointerId == this.pointerIdentifier ) { this._pointerMove( event, event ); } }; proto.ontouchmove = function( event ) { var touch = this.getTouch( event.changedTouches ); if ( touch ) { this._pointerMove( event, touch ); } }; /** * pointer move * @param {Event} event * @param {Event or Touch} pointer * @private */ proto._pointerMove = function( event, pointer ) { this.pointerMove( event, pointer ); }; // public proto.pointerMove = function( event, pointer ) { this.emitEvent( 'pointerMove', [ event, pointer ] ); }; // ----- end event ----- // proto.onmouseup = function( event ) { this._pointerUp( event, event ); }; proto.onMSPointerUp = proto.onpointerup = function( event ) { if ( event.pointerId == this.pointerIdentifier ) { this._pointerUp( event, event ); } }; proto.ontouchend = function( event ) { var touch = this.getTouch( event.changedTouches ); if ( touch ) { this._pointerUp( event, touch ); } }; /** * pointer up * @param {Event} event * @param {Event or Touch} pointer * @private */ proto._pointerUp = function( event, pointer ) { this._pointerDone(); this.pointerUp( event, pointer ); }; // public proto.pointerUp = function( event, pointer ) { this.emitEvent( 'pointerUp', [ event, pointer ] ); }; // ----- pointer done ----- // // triggered on pointer up & pointer cancel proto._pointerDone = function() { // reset properties this.isPointerDown = false; delete this.pointerIdentifier; // remove events this._unbindPostStartEvents(); this.pointerDone(); }; proto.pointerDone = noop; // ----- pointer cancel ----- // proto.onMSPointerCancel = proto.onpointercancel = function( event ) { if ( event.pointerId == this.pointerIdentifier ) { this._pointerCancel( event, event ); } }; proto.ontouchcancel = function( event ) { var touch = this.getTouch( event.changedTouches ); if ( touch ) { this._pointerCancel( event, touch ); } }; /** * pointer cancel * @param {Event} event * @param {Event or Touch} pointer * @private */ proto._pointerCancel = function( event, pointer ) { this._pointerDone(); this.pointerCancel( event, pointer ); }; // public proto.pointerCancel = function( event, pointer ) { this.emitEvent( 'pointerCancel', [ event, pointer ] ); }; // ----- ----- // // utility function for getting x/y coords from event Unipointer.getPointerPoint = function( pointer ) { return { x: pointer.pageX, y: pointer.pageY }; }; // ----- ----- // return Unipointer; })); function FreeSegment( a, b ) { this.type = 'FreeSegment'; this.a = a; this.b = b; // orientations this.noon = { a: a, b: b }; this.three = { a: { x: -a.y, y: a.x }, b: { x: -b.y, y: b.x } }; this.six = { a: { x: -a.x, y: -a.y }, b: { x: -b.x, y: -b.y } }; this.nine = { a: { x: a.y, y: -a.x }, b: { x: b.y, y: -b.x } }; } var proto = FreeSegment.prototype; proto.render = function( ctx, center, gridSize ) { var ax = this.a.x * gridSize; var ay = this.a.y * gridSize; var bx = this.b.x * gridSize; var by = this.b.y * gridSize; ctx.strokeStyle = 'hsla(200, 80%, 50%, 0.7)'; ctx.lineWidth = gridSize * 0.6; ctx.lineCap = 'round'; ctx.beginPath(); ctx.moveTo( ax, ay ); ctx.lineTo( bx, by ); ctx.stroke(); ctx.closePath(); }; function FixedSegment( a, b ) { this.type = 'FixedSegment'; this.a = a; this.b = b; // orientations this.noon = { a: a, b: b }; this.three = { a: a, b: b }; this.six = { a: a, b: b }; this.nine = { a: a, b: b }; } var proto = FixedSegment.prototype; proto.render = function( ctx, center, gridSize ) { var ax = this.a.x * gridSize; var ay = this.a.y * gridSize; var bx = this.b.x * gridSize; var by = this.b.y * gridSize; ctx.strokeStyle = 'hsla(30, 100%, 40%, 0.6)'; ctx.lineWidth = gridSize * 0.8; ctx.lineCap = 'round'; ctx.beginPath(); ctx.moveTo( ax, ay ); ctx.lineTo( bx, by ); ctx.stroke(); ctx.closePath(); }; function PivotSegment( a, b ) { this.type = 'FreeSegment'; this.a = a; this.b = b; var dx = b.x - a.x; var dy = b.y - a.y; this.delta = { x: dx, y: dy }; // orientations this.noon = { a: a, b: b }; this.three = { a: { x: -a.y, y: a.x }, b: { x: -a.y + dx, y: a.x + dy } }; this.six = { a: { x: -a.x, y: -a.y }, b: { x: -a.x + dx, y: -a.y + dy } }; this.nine = { a: { x: a.y, y: -a.x }, b: { x: a.y + dx, y: -a.x + dy } }; } var proto = PivotSegment.prototype; proto.render = function( ctx, center, gridSize, mazeAngle ) { var ax = this.a.x * gridSize; var ay = this.a.y * gridSize; var bx = this.delta.x * gridSize; var by = this.delta.y * gridSize; ctx.save(); ctx.translate( ax, ay ); ctx.rotate( -mazeAngle ); var color = 'hsla(150, 100%, 35%, 0.7)' // line ctx.strokeStyle = color; ctx.lineWidth = gridSize * 0.4; ctx.lineCap = 'round'; ctx.beginPath(); ctx.moveTo( 0, 0 ); ctx.lineTo( bx, by ); ctx.stroke(); ctx.closePath(); // circle ctx.fillStyle = color; ctx.beginPath(); ctx.arc( 0, 0, gridSize * 0.4, 0, Math.PI * 2 ); ctx.fill(); ctx.closePath(); ctx.restore(); }; var TAU = Math.PI * 2; function RotateSegment( a, b ) { this.type = 'RotateSegment'; this.a = a; this.b = b; // orientations var dx = b.x - a.x; var dy = b.y - a.y; this.delta = { x: dx, y: dy }; this.theta = Math.atan2( dy, dx ); this.noon = { a: a, b: b }; this.three = { a: a, b: this.getB( TAU/4 ) }; this.six = { a: a, b: this.getB( TAU/2 ) }; this.nine = { a: a, b: this.getB( TAU*3/4 ) }; } var proto = RotateSegment.prototype; proto.getB = function( angle ) { return { x: Math.round( this.a.x + Math.cos( this.theta + angle ) * 2 ), y: Math.round( this.a.y + Math.sin( this.theta + angle ) * 2 ), }; }; proto.render = function( ctx, center, gridSize, mazeAngle ) { var ax = this.a.x * gridSize; var ay = this.a.y * gridSize; ctx.save(); ctx.translate( ax, ay ); ctx.rotate( mazeAngle ); var color = 'hsla(0, 100%, 50%, 0.6)'; ctx.strokeStyle = color; ctx.fillStyle = color; // axle ctx.lineWidth = gridSize* 0.8; ctx.lineJoin = 'round'; ctx.rotate(TAU/8); ctx.strokeRect( -gridSize*0.2, -gridSize*0.2, gridSize*0.4, gridSize*0.4 ); ctx.rotate(-TAU/8); // line ctx.lineWidth = gridSize * 0.8; ctx.lineCap = 'round'; ctx.beginPath(); ctx.moveTo( 0, 0 ); var bx = this.delta.x * gridSize; var by = this.delta.y * gridSize; ctx.lineTo( bx, by ); ctx.stroke(); ctx.closePath(); ctx.restore(); }; // rotational physics model var TAU = Math.PI * 2; function FlyWheel( props ) { this.angle = 0; this.friction = 0.95; this.velocity = 0; for ( var prop in props ) { this[ prop ] = props[ prop ]; } } var proto = FlyWheel.prototype; proto.integrate = function() { this.velocity *= this.friction; this.angle += this.velocity; this.normalizeAngle(); }; proto.applyForce = function( force ) { this.velocity += force; }; proto.normalizeAngle = function() { this.angle = ( ( this.angle % TAU ) + TAU ) % TAU; }; proto.setAngle = function( theta ) { var velo = theta - this.angle; if ( velo > TAU/2 ) { velo -= TAU; } else if ( velo < -TAU/2 ) { velo += TAU; } var force = velo - this.velocity; this.applyForce( force ); }; var cub = { offset: { x: 0, y: 0 }, }; var pegOrienter = { noon: function( peg ) { return peg; }, three: function( peg ) { return { x: peg.y, y: -peg.x }; }, six: function( peg ) { return { x: -peg.x, y: -peg.y }; }, nine: function( peg ) { return { x: -peg.y, y: peg.x }; }, }; cub.setPeg = function( peg, orientation ) { peg = pegOrienter[ orientation ]( peg ); this.peg = peg; this.noon = { x: peg.x, y: peg.y }; this.three = { x: -peg.y, y: peg.x }; this.six = { x: -peg.x, y: -peg.y }; this.nine = { x: peg.y, y: -peg.x }; }; var offsetOrienter = { noon: function( offset ) { return offset; }, three: function( offset ) { // flip y because its rendering return { x: offset.y, y: -offset.x }; }, six: function( offset ) { return { x: -offset.x, y: -offset.y }; }, nine: function( offset ) { // flip y because its rendering return { x: -offset.y, y: offset.x }; }, }; cub.setOffset = function( offset, orientation ) { this.offset = offsetOrienter[ orientation ]( offset ); }; // ----- render ----- // cub.render = function( ctx, mazeCenter, gridSize, angle, isHovered ) { function circle( x, y, radius ) { ctx.beginPath(); ctx.arc( x, y, radius, 0, Math.PI * 2 ); ctx.fill(); ctx.closePath(); } var x = this.peg.x * gridSize + this.offset.x; var y = this.peg.y * gridSize + this.offset.y; ctx.save(); ctx.translate( mazeCenter.x, mazeCenter.y ); ctx.rotate( angle ); ctx.translate( x, y ); ctx.rotate( -angle ); ctx.fillStyle = 'hsla(330, 100%, 40%, 1)'; var scale = isHovered ? 1.15 : 1; ctx.scale( scale, scale ); circle( 0, 0, gridSize * 0.6 ); circle( gridSize * -0.45, gridSize * -0.35, gridSize * 0.3 ); circle( gridSize * 0.45, gridSize * -0.35, gridSize * 0.3 ); ctx.restore(); }; /* globals FlyWheel, FreeSegment, FixedSegment, PivotSegment, RotateSegment, cub */ function Maze() { this.freeSegments = []; this.fixedSegments = []; this.pivotSegments = [.........完整代码请登录后点击上方下载按钮下载查看
网友评论0