HTML5+JS游戏开发模块----canvas图片拖放

本文介绍了如何在HTML5 canvas中实现图片的拖放功能,适用于塔防类游戏。难点包括记录鼠标坐标、判断鼠标是否在图片上、模拟拖动及图片放置。通过HTML5的draggable等标签结合canvas,解决了拖放问题。尽管在处理鼠标事件和类属性时遇到了挑战,但已成功实现基本功能。后续将面临子弹移动、寻路算法等更多挑战。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

边学边做笔记,现在游戏开发进入下一个阶段,canvas图片拖放模块,如果要做塔防类游戏,少不了拖放炮塔之类的。HTML5提供拖放标签,draggable,ondrop,ondragover,ondragup等标签实现元素拖放,但是,canvas内部图片是无法使用这种方式的。

canvas拖放难点:

1.鼠标移动到canvas上,记录鼠标坐标

2.怎样确定鼠标是否在图片上

3.怎样让图片跟随鼠标移动(模拟拖图片过程)

4.怎样让图片落到指定方块内


首先,鼠标移动到canvas上记录坐标,这个简单,只需要注意下兼容就好

if(e.offSetX||e.layerX){//兼容浏览器
		this.mx=e.offSetX==undefined?e.layerX:e.offSetX;
		this.my=e.offSetY==undefined?e.layerY:e.offSetY;
	}

鼠标是否在图片上,需要增加范围判断,然后在给个变量赋值this.isDown=true;,作为是否让图片跟随依据

//对比坐标位置,是否点击图片
	if(this.mx<X+W&&this.mx>X){
		if(this.my<Y+H&&this.my>Y){
			this.isDown=true;
		}
	}else{
		this.isDown=false;
	}

鼠标点击了图片,那么接下来就要图片跟随鼠标运动,原理就是鼠标的xy坐标作为绘画点,插入绘制图片的函数中去,然后不断的清理屏幕,重新画图

//如果isDown为真
	if(this.isDown){
		X=this.mx-W/2;//图片跟随鼠标移动
		Y=this.my-H/2;
	}
清理屏幕,画图函数就不说了

然后就是确定图片落在那个方块中

if(X<parseInt(X/50)*50+W&&X>parseInt(X/50)*50){
		if(Y<parseInt(Y/50)*50+H&&Y>parseInt(Y/50)*50){
			if(X<500&&Y<500&&X>0&&Y>0){
				X=parseInt(X/50)*50; //转换为方块坐标
				Y=parseInt(Y/50)*50;	
			}}

上面简单说一下,之前图片跟随时候,鼠标是保持在图片中间的部分,所以XY点就不是方块左上角的点,故我们要把XY重新赋值

到这里,上面几个难点基本解决,之后就是程序简单框架搭建,turret.js是炮塔类,但由于个人初学者,搞不明白鼠标事件为何接收不到内部this.x坐标,同样也无法改变,所以搞几个全局变量,但有违类搭建原则,而我无能为力,后期重新分配类的属性吧,暂时将就一下。

html页面

<!DOCTYPE html>
<html lang="en">
<head>
	<meta charset="UTF-8">
	<title>塔防拖放效果</title>
</head>
<body>
	<canvas id="can" width="625" height="505" ></canvas>
	
	<script type="text/javascript" src="js/turrets.js"></script>
	<script type="text/javascript">
		var can;
		var ctx;
		var img;
		var mx;//鼠标坐标
		var my;
		var turret;//炮塔对象
		window.requestAnimFrame=(function(){
			return window.requestAnimationFrame||window.webkitRequestAnimationFrame||window.mozRequestAnimationFrame||window.oRequestAnimationFrame||window.msRequestAnimationFrame||function( /* function FrameRequestCallback */ callback, /* DOMElement Element */ element) {
					return window.setTimeout(callback, 1000 / 60);
				};
		})();//自动执行函数
		document.body.onload=game();//游戏入口
		function game(){//入口函数
			init();
			gameLoop();//游戏循环
		}
		//初始化函数
		function init(){
			can=document.getElementById('can');
			ctx=can.getContext('2d');
			
			img=new Image();
			img.src='images/tafan.png';
			turret=new Turret();//new 实例
			turret.img=img;//图片地址
			turret.ctx=ctx;
			turret.init();
			//鼠标事件
			can.addEventListener("mousedown",turret.OnMouseDown,false);
            can.addEventListener("mousemove",turret.OnMouseMove,false);
            can.addEventListener("mouseup",turret.OnMouseUp,false);
		}
		//游戏循环函数
		function gameLoop(){
			ctx.clearRect(0,0,655,505);
			draw();
			requestAnimFrame(gameLoop);
		}
		//绘画游戏
		function draw(){
			ctx.save();
			for(var i=0;i<11;i++){
				ctx.beginPath();
				ctx.moveTo(i*50,0);
				ctx.lineTo(i*50,500);
				ctx.strokeStyle='#eee';
				ctx.stroke();
				ctx.closePath();
				ctx.beginPath();
				ctx.moveTo(0,i*50);
				ctx.lineTo(500,i*50);
				ctx.strokeStyle='#eee';
				ctx.stroke();
				ctx.closePath();
				ctx.beginPath();
				ctx.moveTo(515,i*50);
				ctx.lineTo(615,i*50);
				ctx.strokeStyle='#000';
				ctx.stroke();
				ctx.closePath();	
			}
			for(var j=0;j<3;j++){
				ctx.beginPath();
				ctx.moveTo(j*50+515,0);
				ctx.lineTo(j*50+515,500);
				ctx.strokeStyle='#000';
				ctx.stroke();
				ctx.closePath();
				
			}
			ctx.beginPath();
			turret.draw();//画出炮塔
			ctx.closePath();
			ctx.restore();
		}
	</script>
</body>
</html>


炮塔类,好失败的类,汗!!!

var X,Y,W,H,isRect;

//炮塔类
function Turret(img){//传入图片地址
	this.x=X;
	this.y=Y;
	this.w=W;//图片宽
	this.h=H;
	this.mx;//鼠标坐标
	this.my;
	this.img=img;
	this.isDown=false;//是否点中图片
	this.ctx;
	this.isRect=isRect;
}
//初始化炮塔
Turret.prototype.init=function(){
	X=515;
	Y=200;//图片坐标
	W=50;
	H=50;
	isDown=false;//默认鼠标没有点击图片
}
//重绘制炮塔
Turret.prototype.draw=function(){
	if(isRect&&X<500&&Y<500){
		this.ctx.arc(X+W/2,Y+H/2,150,0,2*Math.PI,false);
		this.ctx.fillStyle='rgba(232,225,225,0.2)';//火力范围
		this.ctx.fill();
		this.ctx.strokeStyle='red';
		this.ctx.stroke();
	}
	this.ctx.drawImage(this.img,X,Y,W,H);
}
//鼠标按下,确定是否点击到炮塔图片
Turret.prototype.OnMouseDown=function(e){
	isRect=true;
	if(e.offSetX||e.layerX){//兼容浏览器
		this.mx=e.offSetX==undefined?e.layerX:e.offSetX;
		this.my=e.offSetY==undefined?e.layerY:e.offSetY;
	}
	//对比坐标位置,是否点击图片
	if(this.mx<X+W&&this.mx>X){
		if(this.my<Y+H&&this.my>Y){
			this.isDown=true;
		}
	}else{
		this.isDown=false;
	}
	
}
//鼠标移动
Turret.prototype.OnMouseMove=function(e){
	if(e.offSetX||e.layerX){//兼容浏览器
		this.mx=e.offSetX==undefined?e.layerX:e.offSetX;
		this.my=e.offSetY==undefined?e.layerY:e.offSetY;
	}
	//如果isDown为真
	if(this.isDown){
		X=this.mx-W/2;//图片跟随鼠标移动
		Y=this.my-H/2;
	}
}
//鼠标按键松开
Turret.prototype.OnMouseUp=function(e){
	if(e.offSetX||e.layerX){//兼容浏览器
		this.mx=e.offSetX==undefined?e.layerX:e.offSetX;
		this.my=e.offSetY==undefined?e.layerY:e.offSetY;
	}
	//接收图片
	//如果图片当前坐标在某一个格子内,重画
	if(X<parseInt(X/50)*50+W&&X>parseInt(X/50)*50){
		if(Y<parseInt(Y/50)*50+H&&Y>parseInt(Y/50)*50){
			if(X<500&&Y<500&&X>0&&Y>0){
				X=parseInt(X/50)*50; //转换为方块坐标
				Y=parseInt(Y/50)*50;	
			}
			else{
				X=515;
				Y=200;
				this.isDown=false;
			}
			this.isDown=false;
			isRect=false;
		}
	}

}


实现鼠标拖放功能,接下来可能是要出塔防游戏,不过目前遇到问题,子弹跟随目标移动,目标寻路算法(压根看不懂算法),子弹碰撞,子弹飞行范围等一系列难题等待我慢慢解决。加油。

游戏截图



完整代码下载



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值