Как передвигать персонажа на двух скоростях, не затрагивая при этом одну? - PullRequest
0 голосов
/ 24 мая 2018

ОК, так что это немного сложно объяснить.Я делаю основанную на холсте 2-мерную игру "укажи и нажми".Вы можете осмотреться (переместить окружение), перетаскивая мышь горизонтально по экрану.И перемещайте персонажа, нажимая, куда вы хотите, чтобы он пошел.Вроде как Эта Моя Война.Вот упрощенная версия того, что я получил ...

ДЕЙСТВИЯ МЫШИ:

var held, mouseX, mouseXInitial;
window.addEventListener('mousedown',function(e){
    held = true;
    mouseXInitial = mouseX; 
});
window.addEventListener('mouseup',function(e){
    held = false;
});
window.addEventListener('mousemove',function(e){
    mouseX = e.clientX;
});
mouseEvents();

СМОТРЕТЬ (перетаскивая по экрану, чтобы осмотреть окружающую среду):

var sharedParentObject = {
    scrolledAmount: null,
    scrolling: function(){
        if (held){
            this.scrolledAmount = mouseX - mouseXInitial;
            this.x = this.xInitial + this.scrolledAmount;
        }
    },
    inputShared: function(){
        var that = this;
        window.addEventListener('mousedown',function(e){
            that.xInitial = that.x;
        });
        window.addEventListener('mousemove',function(e){
            that.scrolling();
        });
    }
}

ПЕРЕМЕЩЕНИЕ ХАРАКТЕРА:

 function Character(){
    this.speed = 2;
    this.target = null;
    this.input = function(){
        var that = this;
        window.addEventListener('mouseup',function(e){
            that.target = that.mouseXInitial;
            that.target += that.scrolledAmount;
        });
    }
    this.update = function(){
        if (this.target){
            //moving right
            if (this.x + this.w/2 < this.target){
                this.x += this.speed;
            }
            //moving left
            if (this.x + this.w/2 > this.target){
                this.x -= this.speed;
            }
        }
    }
 }

 Character.prototype = Object.create(sharedParentObject);

Это работает, но проблема в том, что, как только я начинаю перетаскивать экран, чтобы осмотреться, пока персонаж уже гуляет, он становится все странным и нервным.Я понимаю, почему это происходит.Символ x изменяется одновременно как в классе символов, так и в родительском классе.Есть ли способ, чтобы персонаж мог идти к цели, продолжая двигаться, пока я прокручиваю окружение?Вроде делаю и то и другое, не влияя одно на другое ..

1 Ответ

0 голосов
/ 30 мая 2018

Все, что вам нужно сделать, это отслеживать расстояние, на которое мышь переместилась между событиями onmousedown и onmouseup.Если расстояние очень мало, то пользователь нажал на одну точку, если расстояние больше, чем он пытается панорамировать сцену.

<!doctype html>
<html>
	<head>
		<meta charset="utf-8">
		<style>
			body {
				background-color: black;
			}
			
			canvas {
				display: block;
				margin-top: 20px;
				margin-left: auto;
				margin-right: auto;
				border: solid 1px white;
				border-radius: 10px;
			}
		</style>
	</head>
	<body>
		<canvas id="canvas"></canvas>
		<script type="application/javascript">
		
		// ES5 Friendly class functions
		// (Supports overloading & single inheritance)
		var _class = (function() {
		
			"use strict";
			
			/*
				All a class is in JS is a function that
				acts as a constructor and an object (prototype)
				that holds the properties shared across all
				instances (static vars, constants & functions).
			*/
			
			function _class(constructor,prototype) {
				prototype.base = null;
				prototype.super = constructor;
				
				constructor.prototype = prototype;
				
				return constructor;
			}
			
			_class.extends = function(base,constructor,prototype) {
				for (var property in base.prototype) {
					if (!prototype[property]) {
						prototype[property] = base.prototype[property];
					}
				}
				
				function bundledConstructor() {
					base.apply(this,arguments);
					constructor.apply(this,arguments);
				}
				
				prototype.base = base;
				prototype.super = bundledConstructor;
				
				bundledConstructor.prototype = prototype;
				
				return bundledConstructor;
			}
			
			return _class;
		
		})();
		
		void function() {
			
			"use strict";
			
			// Classes
			
			// Encapsulate canvas element
			var Viewport = _class(
				function(canvasID,width,height,bgColour) {
					this.canvas = document.getElementById(canvasID) || null;
					this.width = width || 1.0;
					this.height = height || 1.0;
					this.bgColour = bgColour || "gray";
					this.hWidth = this.width >> 1;
					this.hHeight = this.height >> 1;
					this.canvas.width = this.width;
					this.canvas.height = this.height;
					this.ctx = this.canvas.getContext("2d");
					this.ctx.translate(this.hWidth,this.hHeight);
					
					var bounds = this.canvas.getBoundingClientRect();
					
					this.leftMargin = bounds.left;
					this.topMargin = bounds.top;
				},{
					clear: function() {
						var ctx = this.ctx;
						ctx.fillStyle = this.bgColour;
						ctx.fillRect(-this.hWidth,-this.hHeight,this.width,this.height);
					}
				}
			);
			
			// This is a class used to encapsulate
			// the scene's panning/zooming.
			var Camera = _class(
				// Constructor Function
				function(viewport,x,y) {
					this.viewport = viewport || null;
					this.x = x || 0.0;
					this.y = y || 0.0;
					this.scale = 1.0;
					this.invScale = 1.0 / this.scale;
					
					this.allowUserInput = false;
					this.mouseDown = false;
					this.mouseLastX = 0.0;
					this.mouseLastY = 0.0;
					
					viewport.canvas.addEventListener("wheel",this.onwheel.bind(this));
					viewport.canvas.addEventListener("mousedown",this.onmousedown.bind(this));
					viewport.canvas.addEventListener("mouseup",this.onmouseup.bind(this));
					viewport.canvas.addEventListener("mousemove",this.onmousemove.bind(this));
				},
				
				// Prototype (constant values & functions go here)
				{	
					scaleCoordinates: function(x,y) {
						return [
							(x - this.viewport.hWidth) * this.invScale + this.x,
							(y - this.viewport.hHeight) * this.invScale + this.y
						];
					},
					
					scaleDimensions: function(width,height) {
						return [
							width * this.invScale,
							height * this.invScale
						];
					},
					
					pan: function(deltaX,deltaY) {
						this.x += deltaX;
						this.y += deltaY;
					},
					
					zoom: function(deltaScale) {
						this.scale += deltaScale;
						this.scale = Math.max(0.0,this.scale);
						this.invScale = 1.0 / this.scale;
					},
					
					onwheel: function(e) {
						if (this.allowUserInput) {
							var deltaY = -Math.sign(e.deltaY) * (e.deltaY / e.deltaY) * 0.25;
							
							this.zoom(deltaY);
						}
					},
					
					onmousedown: function(e) {
						this.mouseDown = true;
						
						[
							this.mouseLastX,
							this.mouseLastY
						] = this.scaleCoordinates(
							e.clientX - this.viewport.leftMargin,
							e.clientY - this.viewport.topMargin
						);
					},
					
					onmouseup: function(e) {
						this.mouseDown = false;
					},
					
					onmousemove: function(e) {
						if (this.allowUserInput && this.mouseDown) {
							var [
								mouseX,
								mouseY
							] = this.scaleCoordinates(
								e.clientX - this.viewport.leftMargin,
								e.clientY - this.viewport.topMargin
							);
							
							this.pan(
								this.mouseLastX - mouseX,
								this.mouseLastY - mouseY
							);
						}
					}
				}
			);
			
			// Contains basic behaviour all game objects will have
			var GameObject = _class(
				function(x,y,width,height,colour) {
					this.x = x || 0.0;
					this.y = y || 0.0;
					this.width = width || 1.0;
					this.height = height || 1.0;
					this.colour = colour || "darkblue";
					this.dx = 0.0;
					this.dy = 0.0;					
					this._draw_x = 0.0;
					this._draw_y = 0.0;
					this._draw_width = 0.0;
					this._draw_height = 0.0;
				},{
					updateDrawParameters: function(camera) {
						this._draw_width = this.width * camera.scale;
						this._draw_height = this.height * camera.scale;
						this._draw_x = ((this.x - camera.x) * camera.scale) - this._draw_width * 0.5;
						this._draw_y = ((this.y - camera.y) * camera.scale) - this._draw_height * 0.5;
					},
					
					tick: function() {
						
					},
					
					render: function(viewport) {
						var ctx = viewport.ctx;
						ctx.fillStyle = this.colour;
						ctx.strokeStyle = "black";
						ctx.lineWidth = 2;
						ctx.beginPath();
						ctx.rect(this._draw_x,this._draw_y,this._draw_width,this._draw_height);
						ctx.fill();
						ctx.stroke();
					}
				}
			);
			
			// A more specialized type of game object that
			// can move to a specific location
			var MoveAgent = _class.extends(GameObject,
				function(x,y,width,height,colour) {
					this.currentState = this.STATE_IDLE;
					this.targetX = 0.0;
					this.targetY = 0.0;
				},{
					STATE_IDLE: 1000,
					STATE_MOVING_TO_TARGET: 1001,
					
					MOVE_SPEED: 1.0,
					GOAL_TOLERANCE: 5.0, // How close is 'good enough' to the target
					
					moveTo: function(x,y) {
						this.targetX = x || 0.0;
						this.targetY = y || 0.0;
						this.currentState = this.STATE_MOVING_TO_TARGET;
					},
					
					tick: function() {
						switch(this.currentState) {
							case this.STATE_IDLE:
								
							break;
							
							case this.STATE_MOVING_TO_TARGET:
								var x = this.targetX - this.x;
								var y = this.targetY - this.y;
								var l = x * x + y * y;
								
								if (l < this.GOAL_TOLERANCE * this.GOAL_TOLERANCE) {
									this.currentState = this.STATE_IDLE;
								} else {
									l = 1.0 / Math.sqrt(l);
									this.dx = x * l * this.MOVE_SPEED;
									this.dy = y * l * this.MOVE_SPEED;
									this.x += this.dx;
									this.y += this.dy;
								}
							break;
						}
					}
				}
			);
			
			var ControlledMoveAgent = _class.extends(MoveAgent,
				function(x,y,width,height,colour,camera) {
					this.camera = camera || null;
					
					this.mouseDown = false;
					this.mouseX = 0.0;
					this.mouseY = 0.0;
				
					viewport.canvas.addEventListener("mousedown",this.onmousedown.bind(this));
					viewport.canvas.addEventListener("mouseup",this.onmouseup.bind(this));
					viewport.canvas.addEventListener("mousemove",this.onmousemove.bind(this));
				},{
					MOVE_TOLLERANCE: 5.0,
				
					onmousedown: function(e) {
						if (e.button === 0) {
							this.mouseDown = true;
							this.mouseX = e.clientX;
							this.mouseY = e.clientY;
						}
					},
					
					onmouseup: function(e) {
						if (e.button === 0 && this.mouseDown) {
							this.mouseDown = false;
							
							var x = e.clientX - this.camera.viewport.leftMargin;
							var y = e.clientY - this.camera.viewport.topMargin;
							
							[x,y] = this.camera.scaleCoordinates(x,y);
							
							this.moveTo(x,y);
						}
					},
					
					onmousemove: function(e) {
						if (this.mouseDown) {
							var x = this.mouseX - e.clientX;
							var y = this.mouseY - e.clientY;
							var l = Math.sqrt(x * x + y * y);
							
							if (l > this.MOVE_TOLLERANCE) {
								this.mouseDown = false;
							}
						}
					}
				}
			);
			
			// Vars
			var camera = null;
			var viewport = null;
			var scenery = [];
			var character = null;
			
			// Functions
			function loop() {
				// Tick
				for (var i = 0; i < scenery.length; ++i) {
					scenery[i].updateDrawParameters(camera);
				}
				
				character.tick();
				character.updateDrawParameters(camera);
				
				// Render
				viewport.clear();
				
				for (var i = 0; i < scenery.length; ++i) {
					scenery[i].render(viewport);
				}
				
				character.render(viewport);
				
				//
				requestAnimationFrame(loop);
			}
			
			// Entry Point
			onload = function() {
				viewport = new Viewport("canvas",180,160,"gray");
				camera = new Camera(viewport,0,0);
				camera.allowUserInput = true;
				camera.zoom(0.25);
				
				for (var i = 0; i < 10; ++i) {
					scenery[i] = new GameObject(
						180 * Math.random() - 90,
						160 * Math.random() - 80,
						10 + Math.random() * 10,
						10 + Math.random() * 10,
						"#" + ((Math.random() * 255) | 0).toString(16)
							+ ((Math.random() * 255) | 0).toString(16)
							+ ((Math.random() * 255) | 0).toString(16)
					);
				}
				
				character = new ControlledMoveAgent(0,0,10,10,"darkred",camera);
				
				loop();
			}
		}()
		
		</script>
	</body>
</html>
...