• 用HTML+CSS+JS写的切水果小游戏它来了


    前言

    切水果游戏曾经是一款风靡手机的休闲游戏,今天要分享的就是一款网页版的切水果游戏, 由HTML+CSS+JS实现,虽然功能和原版的相差太大,但基本的功能具备,效果逼真。感兴趣的小伙伴可收藏学习(完整源码在文末)

    推荐学习专栏:



    效果展示

    在这里插入图片描述
    在这里插入图片描述

    游戏介绍

    智能手机刚刚普及时,切水果这款小游戏可谓风靡一时。几年过去了,现在,让我们用纯JavaScript来实现这个水果忍者游戏,就算是为了锤炼我们的JavaScript开发技能吧。

    《切水果》这款游戏的创意来源也非常简单,就是一位员工在家里看到电视播放销售水果刀的广告,为了体现出刀的锋利,广告里推销员把香蕉抛向空中,然后用水果刀在空中把香蕉切开。

    经典模式(图标为西瓜):在经典模式中无时间限制,水果和炸弹会不断浮动出现在屏幕上。玩家共有三次因没有切到水果而失误的机会,而只要一切到炸弹游戏就会马上结束。每积累到100分就会自动补充一次以前失去的机会。此模式中会随机出现石榴(连切来加分,分数高低,取决于玩家切的速度)、火龙果(切掉可以+50分)和杨桃

    开始游戏:用鼠标在网页上划一条横线切正中的“New Game”的西瓜开始新的游戏:

    图片展示

    在这里插入图片描述

    源码

    此处展示部分源码,完整源码点击下载切水果

    HTML源码

    DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
    <html xmlns="http://www.w3.org/1999/xhtml">
    <head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    <meta name="author" content="dron" />
    <meta name="viewport" content="width=device-width, height=device-height, user-scalable=no, initial-scale=1.0, maximum-scale=1.0" />
    <meta name="apple-mobile-web-app-capable" content="yes" />
    <meta name="apple-mobile-web-app-status-bar-style" content="black" />
    <title>水果忍者网页版--程序园title>
    
    <link rel="stylesheet" href="images/index.css" />
    head>
    <body>
    
        <div id="extra">div>
        <canvas id="view" width="640" height="480">canvas>
        <div id="desc">
            <div id="browser">div>
        div>
    
        <script src="scripts/all.js" type="text/javascript">script>
    	
    body>
    html>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    CSS样式

    • html, body
    html, body{
    	width: 100%;
    	height: 100%;
    	background: #484848;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • #extra, #view
    #extra, #view{
    	position: absolute;
    	left: 50%;
    	top: 50%;
    	width: 640px;
    	height: 480px;
    	margin: -280px auto auto -320px;
    	text-align: left;
    	background: #fff;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • #view
    #view{
    	display: block;
    	background: transparent url(blank.gif) repeat 0 0;
    	cursor: default;
    	z-index: 20;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • #fork
    #fork{
    	display: block;
    	position: absolute;
    	right: 0;
    	top: 0;
    	width: 356px;
    	height: 92px;
    	cursor: pointer;
    	background-image: url(fork.gif);
    	z-index: 0;
    }
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    部分JS源码

    image-20221104145954363

    main.js

    var log = function(){
        var time = 1e3, add = 300, fn;
        fn = function( text ){
            setTimeout( function(){ csl.log( text ); }, time );
            time += add;
        };
        fn.clear = function(){
            setTimeout( csl.clear.bind( csl ), time );
            time += add;
        };
        return fn;
    }();
    
    exports.start = function(){
    
        [ timeline, sence, control ].invoke( "init" );
    
        log( "正在加载鼠标控制脚本" );
        log( "正在加载图像资源" );
    	log( "正在加载游戏脚本" );
        log( "正在加载剧情" );
        log( "正在初始化" );
    	log( "正在启动游戏..." );
        log.clear();
    
        setTimeout( sence.switchSence.saturate( sence, "home-menu" ), 3000 );
    };
    
    message.addEventListener("slice", function( knife ){
        var fruits = collide.check( knife ), angle;
        if( fruits.length )
            angle = tools.getAngleByRadian( tools.pointToRadian( knife.slice(0, 2), knife.slice(2, 4) ) ),
            fruits.forEach(function( fruit ){
               message.postMessage( fruit, angle, "slice.at" );
            });
    });
    
    message.addEventListener("slice.at", function( fruit, angle ){
    
        if( state( "sence-state" ).isnot( "ready" ) )
            return ;
    
        if( state( "sence-name" ).is( "game-body" ) ){
            game.sliceAt( fruit, angle );
            return ;
        }
    
        if( state( "sence-name" ).is( "home-menu" ) ){
            fruit.broken( angle );
            if( fruit.isHomeMenu )
                switch( 1 ){
                    case fruit.isDojoIcon:
                        sence.switchSence( "dojo-body" ); break;
                    case fruit.isNewGameIcon:
                        sence.switchSence( "game-body" ); break;
                    case fruit.isQuitIcon:
                        sence.switchSence( "quit-body" ); break;
                }
            return ;
        }
    });
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63

    tools.js

    exports.unsetObject = function( object ){
    	for(var i in object)
    	    if(object.hasOwnProperty(i) && typeof object[i] == "function")
    	    	object[i] = function(){};
    };
    
    exports.getAngleByRadian = function( radian ){
    	return radian * 180 / Math.PI;
    }
    
    exports.pointToRadian =	function( origin, point ){
    	var PI = Math.PI;
    	
    	if( point[0] === origin[0] ){
    		if ( point[1] > origin[1] )
    			return PI * 0.5;
    		return PI * 1.5
    	}else if( point[1] === origin[1] ){
    		if ( point[0] > origin[0] )
    			return 0;
    		return PI;
    	}
    
    	var t = Math.atan( ( origin[1] - point[1] ) / ( origin[0] - point[0] ) );
    
    	if( point[0] > origin[0] && point[1] < origin[1] )
    		return t + 2 * PI;
    
    	if( point[0] > origin[0] && point[1] > origin[1] )
    		return t;
    
    	return t + PI;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33

    fruit.js

    • 分开
    ClassFruit.prototype.apart = function( angle ){
    	this.anims.clear();
    	this.image.hide();
    	this.shadow.hide();
    	this.aparted = true;
    
    	var inf = infos[ this.type ], preSrc = inf[0].replace( ".png", "" ), radius = this.radius;
    	var create = layer.createImage.saturate( layer, this.startX - radius, this.startY - radius, inf[1], inf[2] );
    
    	angle = ( ( angle % 180 ) + 360 + inf[4] ) % 360;
    
    	this.bImage1 = create( "fruit", preSrc + "-1.png" );
    	this.bImage2 = create( "fruit", preSrc + "-2.png" );
    
    	[ this.bImage1, this.bImage2 ].invoke( "rotate", angle );
    
    	this.apartAngle = angle;
    	timeline2.createTask({ 
    		start: 0, duration: dropTime, object: this, 
    		onTimeUpdate: this.onBrokenDropUpdate, onTimeStart: this.onBrokenDropStart, onTimeEnd: this.onBrokenDropEnd,
    		recycle: this.anims
    	});
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 抛出
    ClassFruit.prototype.shotOut = function(){
    	var sign = [ -1, 1 ];
        return function( start, endX ){
    
    		this.shotOutStartX = this.originX;
    		this.shotOutStartY = this.originY;
    		this.shotOutEndX = average( this.originX, endX );
    		this.shotOutEndY = min( this.startY - random( this.startY - 100 ), 200 );
    		this.fallOffToX = endX;
    
    		timeline.createTask({
    			start: start, duration: dropTime, object: this,
    			onTimeUpdate: this.onShotOuting, onTimeStart: this.onShotOutStart, onTimeEnd: this.onShotOutEnd,
    			recycle: this.anims
    		});
    
    		if( this.type != "boom" )
    		 	this.rotate( 0, ( random( 180 ) + 90 ) * sign[ random( 2 ) ] );
    
    		return this;
    	};
    }();
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 掉落
    ClassFruit.prototype.fallOff = function(){
    	var sign = [ -1, 1 ];
    	var signIndex = 0;
        return function( start, x ){
    
    		if( this.aparted || this.brokend )
    			return ;
    
    		var y = 600;
    
    		if( typeof x !== "number" )
    		    x = this.originX + random( dropXScope ) * sign[ ( signIndex ++ ) % 2 ];
    
    		this.fallTargetX = x;
    		this.fallTargetY = y;
    
    		timeline.createTask({
    			start: start, duration: dropTime, object: this,
    			onTimeUpdate: this.onFalling, onTimeStart: this.onFallStart, onTimeEnd: this.onFallEnd,
    			recycle: this.anims
    		});
    	}
    }();
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    资源下载

    彩蛋

    • 改变水果:找到文件夹images/fruit,直接替换图片,不要修改名称。如sandia,此处sandia.png代表完整的西瓜,sandia-1.pngsandia-2.png代表被切开的西瓜,注意替换的图片对应,否则影响观赏效果
      在这里插入图片描述
    • 修改音效:可在sound文件夹替换音频(什么都可以)
    • 手动开挂:找到all.js文件,修改number==3,可改成任意整数数字,具体位置如图所示
      在这里插入图片描述- 防切炸弹:只需要修改sliceAt函数,如下图if ( fruit.type != "boom")的红色框就是切到水果的分支,执行加分和显示水果被切成两半的效果。else的蓝色框是切到炸弹的分支,我们只需要将蓝色框内的代码注释掉,游戏就永远不能结束了
      在这里插入图片描述

    总结

    游戏介绍就到这里,学习的过程就是认识自己的过程,在开发中不断补充自己的知识,增加自己的理解,弥补不足,有一定的JavaSript水平的朋友,可以看看源代码,相信你的JavaSript水平会有很大的提升。欢迎订阅下边博主专栏,跟博主一起学习!后期将更新更多精彩文章!感觉还不错的话点个赞吧!

  • 相关阅读:
    DBCO 点击化学试剂:DBCO-PEG24-O-NH2,DBCO-PEG24-O-amine
    深入理解MySQL存储引擎、InnoDB与MyISAM的比较以及事务处理机制
    【深度学习】特征图的上采样(nn.Upsample)和转置卷积(nn.ConvTranspose2d) | pytorch
    【室友用一局王者荣耀的时间学会了用BI报表数据处理】
    NISP中渗透测试面试方式
    美创科技三重数据安全韧性,杜绝删库跑路
    鸿蒙textarea怎么设置可拖动大小
    【Java 基础篇】Java Date 类详解:日期和时间操作的利器
    Web3中文|NFT无法保障数字所有权?
    vite基础学习笔记:13.Dialog 对话框 (用户注册与登录)
  • 原文地址:https://blog.csdn.net/CSDN_anhl/article/details/128008770