导航

萌即是正义!时不时分享一些ACG活动记录与有趣代码的小站!

侧边栏
热门文章
1推文
让AI写了个将三星手机拍摄的JPG Gain Map格式的照片转成压缩率更高的AVIF Gain Map格式的NPM包。 地址为:https://www.npmjs.com/package/libavif-with-gainmap 这样一定程度上能更快捷的管理HDR照片。 不过问题也是有的,比如服务器贫瘠的性能处理大尺寸的AVIF照片还是有点吃力的。 大照片一张大概需要30秒的样子...不知道还有没有优化的空间。 如果设备支持的话,示例图点击就能看到HDR效果啦!
热度
833
2页面
程序员老黄历&求签
热度
377
3推文
《节奏天国 奇迹之星》发售了,于是果断入手。 作为手残玩家,虽然每作都有买,但是每作好像又都没有玩到最后😅,毕竟真的好难。 掏出Switch,发现已经一点电都没有了,可见我已经多久没打开过Switch了。
热度
187
4博文
3DS模拟器简体中文字库 | Citra3ds字库 | 符文工房4乱码解决字库 | shared_font.bin
热度
130
5博文
《上伊那牡丹,酒醉身姿似百合花般》圣地巡礼之杂司谷旧传教士馆
热度
117
6页面
友链
热度
91
7博文
《mono女孩》圣地巡礼之甲府
热度
78
8博文
探访《蜡笔小新》老家——春日部游记
热度
78
9博文
Live2d模型合集分享 | FaceRig | 海王星系列 | 初音未来 | 雷姆 | 凉风青叶 | 尼禄 | 薇尔莉特 | 小埋 | 樱花庄 | 玉藻前
热度
65
10推文
又到了一年一度的《请问您今天要来点OIOI吗?》的时候了。 今年的周边使用的是今年愚人节的「Magical Order Rabbit」的立绘。 这次的纱路酱真的太优雅啦! 以及这次的亚克力立牌竟然是带闪光的! 书签也好好看!不过可惜的是书签第一周就卖完了。
热度
52
最新评论
广树管理员
2026-07-11 12:19
@666:因为avif格式到24年才几乎被主流浏览器覆盖。webp的缺点是不支持hdr
666
2026-07-11 12:17
avif见的不多,webp倒是不少
广树管理员
2026-07-11 11:50
@Ringnee:就是所有关卡clear
广树管理员
2026-07-11 11:50
@Aki:据我所知三星的HDR方案应该是安卓机较为通用的方案,也不排除其他手机特立独行。
Ringnee
2026-07-09 09:57
我前两天想玩一下健身环发现switch打开也没电了。节奏天国的玩到最后是什么意思?还有攻略关卡吗
攻略中
节奏天国 奇迹之星
暂无评分
NS节奏天国 奇迹之星
2026年7月08日 20时 ~ 攻略中
已累计游玩3天
《节奏天国:奇迹之星》是一款轻松又充满创意的音乐节奏游戏,玩家只需跟随音乐节拍按下按键,就能完成跳跃、敲击空罐、制作料理等各种有趣的小挑战。游戏延续了《节奏天国》系列简单易上手、节奏感强、画风幽默的特点,让玩家在一个个短小精巧的关卡中感受音乐与反应力结合的乐趣,适合喜欢节奏游戏和轻松休闲玩法的玩家体验。
告别回忆 -无垢少女- 致最爱的你
暂无评分
Steam告别回忆 -无垢少女- 致最爱的你
2026年6月24日 20时 ~ 攻略中
已累计游玩2周3天
系列作发售至今经历了19年,做为其系列最终作的《告别回忆 ~无垢少女~》(以下略称为本篇)在2018年3月发售。本次的FanDisc和至今的系列作相同,带给玩家在各结局后的短篇故事。请充分享受和各个女主角们在欢乐结局后的幸福时光。
传颂之物:循白之证
暂无评分
PS5传颂之物:循白之证
2026年5月31日 19时 ~ 攻略中
已累计游玩1个月11天
《传颂之物:循白之证》是 AQUAPLUS 开发、Shiravune 发行的《传颂之物》系列动作 RPG。故事发生在大国“大和”恢复和平之后:奥修特尔、御雷、宗近、修娘等人击退敌国阿瓦什兰的侵略,本应迎来安宁,但各地却陆续出现看似毫无关联的怪异现象,并逐渐指向同一个源头;随着三条线索彼此重叠,众人再次踏上旅程,而旅途尽...
亚路塔:狐狸狐途的面包冒险
暂无评分
Steam亚路塔:狐狸狐途的面包冒险
2026年2月12日 19时 ~ 攻略中
已累计游玩4个月29天
一场席卷全世界的面包革命现在开始! 主人公查雅阴错阳差之下,开始了在荒废的岛屿上经营面包店的生活。 出外冒险搜集食材、研发崭新面包配方、遇见性格各异的伙伴们,建造更丰富的设施,用面包香气使无人问津的广场再次热闹起来!
ToHeart
暂无评分
SteamToHeart
2025年6月26日 19时 ~ 攻略中
已累计游玩1年
AQUAPLUS推出的“温暖人心的校园恋爱游戏”将以高清全3D形式焕新归来!
fault - StP - LIGHTKRAVTE
暂无评分
Steamfault - StP - LIGHTKRAVTE
2025年5月29日 20时 ~ 攻略中
已累计游玩1年1个月
全球累计销量超过50万份的“fault”系列最新作!故事的舞台是一个融合了奇幻与科幻的超前世界——卢森海德王国。本作讲述了生活在此地的一个平凡又平庸的究极普通市民——名为果子的少年的故事。
PSN奖杯卡

PSN奖杯卡

归档
赞助商广告

【H5小游戏】制作一个简单的丢鱼雷小游戏

2017-10-11 15:31:12
JavaScript

这是非常简单的一个小游戏,js脚本甚至就只用200多行。

首先,确定下游戏规则。

1、我方战舰通过按空格丢出一枚鱼雷,鱼雷会以一定速度移动。
2、我方战舰可以通过左右按键来移动,但是不能上下移动。
3、敌方战舰不定时刷新,并按照一定速度向左移动。
4、一艘敌方战舰移出了画面外,判断为敌舰逃脱,HP-1 。
5、当HP归零游戏结束。
6、打中一艘敌方战舰获得1分。
7、每打中一艘敌方战舰就立刻刷新出新的战舰并且战舰刷新速度加快。
8、每逃脱一艘则刷新速度减慢。

大致先制定这么一套游戏规则。

先把html部分写出来。

<canvas id="myCanvas" class="canvas" onClick="init()"></canvas>
<div>分数:<span id="score"></span></div>
<div>HP:<span id="HP"></span></div>

为了方便识别canvas 可以描个边。

.canvas{
	border:1px solid #333;
	cursor:pointer;
}

好了,接下来开始构思游戏。
因为是个简单的小游戏,可以用一些上个世纪的游戏布局。就是先将游戏画面拆分成一个一个小格子,这次制作的小游戏是12*6格子, 每格20*20像素。
图示:
sample.png

这样子只要通过比对鱼雷和敌方战舰的坐标就可以得出是否被炸到。

接下来脚本部分:

var canvas=document.getElementById('myCanvas');//获取画布
var scoreSpan = document.getElementById('score');//获取得分span
var HPSpan = document.getElementById('HP');//获取HP的span
var ctx=canvas.getContext('2d');//用于在画布上绘图的环境
var blockSize = 20;//每格像素
var ctxW = 12;//宽多少格
var ctxH = 6;//高多少格
canvas.width=ctxW*blockSize;//设定画布宽度,就是格子*每格像素
canvas.height=ctxH*blockSize;//设定画布高度,就是格子*每格像素
var emt = null;//用于存放定时器,用于更新敌舰坐标
var boomT =null;//用于存放定时器,用于更新鱼雷坐标和状态
var creatEm = null;//用于存放定时器,用于增加敌舰
var flush = null;//用于存放定时器,用于刷新画布

var myShipX=0;//我方初始位置
var emShip = [];//存放敌方数据
var boom = [];//存放鱼雷数据
var hard = 0;//难度(刷新速度,越小刷新越快单位毫秒)
var score = 0;//得分
var HP = 0;//HP
var boomReload = true;//装弹是否完毕

function init(){//初始化

	myShipX=3;//设定我方的初始位置
	emShip = [];//清空敌舰数据
	boom = [];//清空鱼雷数据
	hard = 3000;//初始化难度
	score = 0;//初始化分数
	HP = 50;//初始化HP
	boomReload = true;//装载鱼雷初始化
	
	ctx.clearRect(0,0,canvas.width,canvas.height);//清空画布
	
	creatEmShip();//创建敌舰
	paintMyShip();//绘制我方
	paintEmship();//绘制敌舰
	scoreSpan.innerHTML = String(score);//初始化计分板
	HPSpan.innerHTML = String(HP);//初始化HP剩余量
	
	clearInterval(emt);//清除更新敌舰坐标定时器
	clearInterval(boomT);//清除更新鱼雷坐标定时器
	clearInterval(creatEm);//清除创建敌舰定时器
	clearInterval(flush);//清除刷新画布定时器
	
	emt = setInterval(function(){//每400毫秒敌舰向左移动一次
		emShipMove();
	},400);
	
	boomT = setInterval(function(){//每200毫秒鱼雷向下移动一次
		boomMove();
	},200);
	
	creatEm = setInterval(function(){//根据难度创建敌舰
		creatEmShip();
	},hard);
	
	flush = setInterval(function(){//100毫秒刷新画布
		ctx.clearRect(0,0,canvas.width,canvas.height);//清空画布
		paintBoom();//绘制鱼雷
		paintEmship();//绘制敌舰
		paintMyShip();//绘制我方
		boomEmship();//判断是否炸中敌舰
	},100);
	
}
function paintMyShip(){//绘制我方
	var shipX = (myShipX-1)*blockSize;//设定我方船只的X坐标,因为左边是从(0,0)开始,格子定为1开始所以-1
	ctx.fillStyle="#0075a9";//设定我方颜色
	ctx.fillRect(shipX+2,blockSize-10,blockSize-4,blockSize-10);//填充方块,因为不想团一起并没有画正方形。
}
function creatEmShip(){//随机出现敌舰
	var Y = Math.floor(Math.random()*(ctxH-2) + 1);//高度一共有6个格子,出去丢雷的格子和我方的格子就是6-2,然后就随机从1-4中生成随机数
	emShip.push([blockSize*ctxW,Y]);//给敌舰数据添加敌舰坐标
}
function paintEmship(){//绘制敌舰
	for(var i=0;i<emShip.length;i++){//循环敌舰数据
		var emShipX = emShip[i][0];//保存敌舰X坐标
		var emShipY = (emShip[i][1]+1)*blockSize;//保存敌舰Y坐标,因为Y是1-4的所在格子,所以要*每格像素来计算出像素坐标
		ctx.fillStyle="#e60012";//设定敌舰颜色
		ctx.fillRect(emShipX+2,emShipY,blockSize-4,blockSize-10);//填充敌舰方块
	}
}
function emShipMove(){//移动敌舰
	for(let i=0;i<emShip.length;i++){//循环敌舰数据
		var X = emShip[i][0]-blockSize;//敌舰X坐标向左移动一个格子
		emShip[i][0] = X;//重新写入X坐标
		
	}
	removeEmShip();//清除多余的敌舰(画布外)
}
function addBoom(){//增加鱼雷
	if(boomReload){//判断是否还在装弹
		var boomX = (myShipX-1)*blockSize;//计算出鱼雷的初始位置,根据我方所在的X坐标
		boom.push([boomX,blockSize,true]);//设定鱼雷的X坐标,Y坐标因为是第二格直接就是格子的高度,true为正在投雷
		boomReload = false;//开始装弹
		var boomT = setTimeout(function(){
			boomReload = true;//800毫秒后装弹完毕
		},800);
	}
}
function paintBoom(){//绘制鱼雷
	for(let i=0;i<boom.length;i++){//循环鱼雷数据
		var boomX = boom[i][0];//保存鱼雷X坐标
		var boomY = boom[i][1];//保存鱼雷Y坐标
		ctx.fillStyle="#6b6b6b";//设定鱼雷颜色
		ctx.fillRect(boomX+7,boomY,blockSize-14,blockSize-10);//填充鱼雷方块
	}
}
function boomMove(){//鱼雷移动
	for(let i=0;i<boom.length;i++){//循环鱼雷数据
		if(boom[i][2]){
			boom[i][2] = false;//判断是否正在投雷,如果正在投弹则将其改变为投雷完毕状态
		}else{
			var Y = boom[i][1]+blockSize;//如果不是正在透雷,则Y坐标增加1格
			boom[i][1] = Y//重新写入Y坐标
		}
	}
	removeBoom();//清除多余的鱼雷(画布外)
}
function removeBoom(){//移除鱼雷
	for(let i=0;i<boom.length;i++){//循环鱼雷数据
		var Y = boom[i][1];//保存鱼雷Y坐标
		if(Y>ctxH*blockSize){
			boom.splice(i,1);//如果已经超过画布就删除
		}	
	}
}
function removeEmShip(){//超出范围删除敌舰并且HP-1
	for(let i=0;i<emShip.length;i++){//循环敌舰数据
		var X = emShip[i][0];//储存敌舰X坐标
		if(X<0){//如果已经在画布外
			minusHP();//减HP
			emShip.splice(i,1);//删除敌舰
			hard = hard+50;//难度降低50
			if(hard>=3000){
				hard=3000;//如果难度已经是3000了则保持3000
			}
		}
	}
}
function boomEmship(){//判定炸了
	for(let i=0;i<boom.length;i++){//循环鱼雷数据
		var boom_X = boom[i][0];//保存鱼雷X坐标
		var boom_Y = boom[i][1];//保存鱼雷Y坐标
		for(let j=0;j<emShip.length;j++){//循环敌舰数据
			var emShip_X = emShip[j][0];//保存敌舰X坐标
			var emShip_Y = emShip[j][1];//保存敌舰Y坐标
			if(boom_X===emShip_X){//判断是否X坐标相同
				if(boom_Y===(emShip_Y+1)*blockSize){//如果Y坐标也相同
					boom.splice(i,1);//删除这个鱼雷
					emShip.splice(j,1);//删除这个敌舰
					hard = hard-50;//难度增加50
					addScore();//加分
					if(hard<=1200){
						hard=1200;//如果难度已经是1200则保持1200
					}
					clearInterval(creatEm);//清除创建敌舰定时器
					creatEmShip();//立刻创建一个敌舰
					creatEm = setInterval(function(){
						creatEmShip();//用新的难度(速度)创建敌舰
					},hard);
				}
			}
		}
	}
}
function gameOver(){//游戏结束
	ctx.clearRect(0,0,canvas.width,canvas.height);//清空画布
	clearInterval(emt);
	clearInterval(boomT);
	clearInterval(creatEm);
	clearInterval(flush);//清空所有定时器
	ctx.font = "14px Courier New";//设定字体
	ctx.fillStyle = "#333";//设定字颜色
	ctx.textAlign="center";//设定字居中
	ctx.fillText("游戏结束,你得了"+score+"分", Math.round(ctxW*blockSize/2), 50);
	//显示游戏结束,你得了x分在画布中间
}
function addScore(){//加分
	score ++;//加分
	scoreSpan.innerHTML = String(score);//更新计分板
}
function minusHP(){//减HP
	HP --;//减HP
	if(HP<=0){
		HPSpan.innerHTML = String(HP);//更新HP剩余量
		setTimeout("gameOver()",0);//如果HP为0则游戏结束
	}else{
		HPSpan.innerHTML = String(HP);//更新HP剩余量
	}
}

document.onkeydown=function(event){//绑定键盘事件
	var e = event || window.event || arguments.callee.caller.arguments[0];
	if(e && e.keyCode==37){//左
		if(myShipX===1){//防止我方移动到画布外面
			return
		}
		myShipX= myShipX-1;
	}
	if(e && e.keyCode==39){//右
		if(myShipX===ctxW){//防止我方移动到画布外面
			return
		}
		myShipX= myShipX+1;
	}
	if(e && e.keyCode==32){//空格
		addBoom();//创建鱼雷
	}
	
}
预览DEMO

---------------------

PS.怎么感觉这游戏像是个拉屎丢人的游戏……


收款.png


file_000000008460720687635c008459256b.png