精华内容
下载资源
问答
  • 弹幕射击小游戏

    热门讨论 2012-12-16 22:45:29
    模仿东方永夜抄,开发的C++弹幕游戏,包括素材、源码
  • 首先感谢我们组的两位大佬,认真负责又很有耐心地指导我们,跟着他们学到了不少东西。 先设计好初稿,然后再分析实现步骤,比如列出数学物理公式,最后就是编码实现阶段了。下面是我的代码: BulletCenterDance: ...
    首先感谢我们组的两位大佬,认真负责又很有耐心地指导我们,跟着他们学到了不少东西。

    先设计好初稿,然后再分析实现步骤,比如列出数学物理公式,最后就是编码实现阶段了。下面是我的代码:

    BulletCenterDance:

    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    
    public class BulletCenterDance : BulletTypeB {
    
        public Vector2 Valocity;
        
        // Update is called once per frame
        void Update () {
            transform.Translate(Valocity * Time.deltaTime);
        }
    }
    

    RevolveCircle:

    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    
    public class RevolveCircle : SpellCard {
    
        public RevolveCircle() : base(new Circle(), new Vector2(-1.5f, 2.4f), 78f, 15000, "想起「旋转圆舞」 ")
        {
        }
    }
    
    class Circle : State<Boss>{
        float time = 2f;
        float timeC = 4f;
        float t = -4f;
        GameObject Revolve;
        public override void Enter(Boss owner)
        {
            Revolve  = ((Satori)owner).RevolveCircleResources.GetComponent<RevolveCircleResource>().RevolveCircle;
            owner.transform.position = new Vector3(-1.53f, 0, 0);
        }
        public override void Execute(Boss owner)
        {
            timeC -= Time.deltaTime;
            time -= Time.deltaTime;
            t += Time.deltaTime;
            if (time < 0) {
                time += 0.1f;
                Vector2 StartLo;
                if (GameManager.player != null) {
                    StartLo = GameManager.player.transform.position - owner.transform.position;
                } else {
                    StartLo = new Vector2 (0, 1);
                }
                StartLo.Normalize ();
                for (int i = -1; i <= 1; i++) {
                    float routeAngle = 30 * Mathf.Deg2Rad * i;
                    Vector2 valocity = new Vector2(StartLo.x*Mathf.Cos(routeAngle)-StartLo.y*Mathf.Sin(routeAngle),StartLo.x*Mathf.Sin(routeAngle)+StartLo.y*Mathf.Cos(routeAngle));
                    valocity *= 3.0f;
                    BulletCenterDance c = GameObject.Instantiate (((Satori)owner).RevolveCircleResources.GetComponent<RevolveCircleResource> ().RevolveCircle, owner.transform.position, Quaternion.identity).GetComponent<BulletCenterDance> ();
                    c.Valocity = valocity;
                    GameObject.Destroy (c.gameObject, 5f);
                }
    
    
    
            }
            if (timeC<0) {
                timeC += 0.3f;
                for (int i = 0; i < 4; i++) {
                    Vector2 StartLocation = new Vector2 (Mathf.Cos (t), Mathf.Sin (t));
                    Vector2 valocity = new Vector2 (2f * Mathf.Cos (2f * t + i * Mathf.PI / 2), 2f * Mathf.Sin (2f * t + i * Mathf.PI / 2));
                    BulletCenterDance r = GameObject.Instantiate (((Satori)owner).RevolveCircleResources.GetComponent<RevolveCircleResource> ().BulletTriangle, owner.transform.position + (Vector3)StartLocation, Quaternion.identity).GetComponent<BulletCenterDance> ();
                    r.Valocity = valocity;
                    GameObject.Destroy (r.gameObject, 10f);
                }
                for (int i = 0; i < 4; i++) {
                    Vector2 StartLocation = new Vector2 (-Mathf.Cos (t), Mathf.Sin (t));
                    Vector2 valocity = new Vector2 (-2f * Mathf.Cos (2f * t + i * Mathf.PI / 2), 2f * Mathf.Sin (2f * t + i * Mathf.PI / 2));
                    BulletCenterDance r = GameObject.Instantiate (((Satori)owner).RevolveCircleResources.GetComponent<RevolveCircleResource> ().BulletTriangle, owner.transform.position + (Vector3)StartLocation, Quaternion.identity).GetComponent<BulletCenterDance> ();
                    r.Valocity = valocity;
                    GameObject.Destroy (r.gameObject, 10f);
                }
            }
        }
                
    
    
    }
    
    
    

    RevolveCircleResources:

    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    
    public class RevolveCircleResource : MonoBehaviour {
    
        public GameObject RevolveCircle; //
        public GameObject BulletTriangle; //
        // Use this for initialization
        void Start () {
            
        }
        
        // Update is called once per frame
        void Update () {
            
        }
    }
    
    

    转载于:https://www.cnblogs.com/1997Ff/p/7498400.html

    展开全文
  • 东方弹幕物理引擎

    2013-04-23 21:59:37
    完全模拟东方弹幕游戏的物理引擎,使用lua脚本语言进行编辑。 且内含现成的外挂脚本供学习观摩。
  • 了解微信小游戏 官方文档有详细的介绍 小游戏的文件结构 我们以新建一个官方示例说明 如图 最外层除了readme外 有3个文件 game.js 程序入口 game.json小游戏配置文件 project.config.json 项目设置文件 具体...

    了解微信小游戏

    官方文档有详细的介绍

    小游戏的文件结构

    我们以新建一个官方示例说明

    clipboard.png

    如图 最外层除了readme外 有3个文件

    • game.js 程序入口
    • game.json小游戏配置文件
    • project.config.json 项目设置文件

    具体配置可以查看官方文档,只有这几个文件需要按照文件名格式来写,其他文件的内容和

    clipboard.png

    这个文件是官方示例中用于模拟浏览器环境的适配器,如有需要可以自己写,我们这里沿用这个。

    入口文件 game.js

    import './js/libs/weapp-adapter'
    import './js/libs/symbol'
    
    import Main from './js/main'
    
    new Main()
    

    整个微信小游戏实际上是运行在微信框架中一个原生canvas中,没有浏览器页面环境如document(这就是为什么有一个模拟浏览器环境的适配器),启动时小游戏框架运行game.js,然后在main.js中基本上都是对微信小游戏api的调用及原生canvas的操作了。如果之前使用过原生canvas或者其他canvas库的同学 马上就可以上手开发0成本,官方开发工具也有es6=》es5的转换所以如果项目比较小都不用其他东西,直接文本编辑器修改 保存 查看 即可。

    图片描述

    开工

    1. 音频使用原来的代码
    2. 帧定时也使用wx的回调函数

      window.requestAnimationFrame(
            this.TimerHandel.bind(this),
            canvas
          )
    3. 引入一个canvas2d库createjs中的ease 和一个自己写的工具库

      import './js/libs/weapp-adapter'
      import './js/libs/ease'
      import './js/plugin/Math'
      
      import Main from './js/main'
      window.main = new Main();
      
    4. 保留原来的触摸移动飞机并且新增重力感应移动飞机

      this.initEvent();
      wx.startAccelerometer({ success:()=>{console.log('开始监听加速计')}});
      wx.onAccelerometerChange((res)=>{
        this.player.speedx = Math.floor(res.x*100)/10;
        this.player.speedy = Math.floor(-res.y * 100)/10;
      })
    5. 其他全部删除 基于create.js库重写;所有子弹继承一个父类

      export default class Bullet_Super {
      
          constructor(cantiner, SHOOT_FRAME = 10,sprite_sheet) {
              this.cantiner = cantiner;
              this.shoot_frame = SHOOT_FRAME;
              this.list = [];
              this.deletelist = [];
              this.y = 0;
              this.x = 0;
      
              this.spriteSheet = new createjs.SpriteSheet(sprite_sheet);
          }
          outOfScreen(s, test) {
              if (test) {
                  if (s.y > window.innerHeight + 100 || s.x > window.innerWidth + 100 || s.x < -100) {
                      this.deletelist.push(s);
                      s.visible = false;
                      return false;
                  }
              }
              return true;
          }
          createSprite(anime, option, die_option) {
              let isnew = true;
              let sprite = this.deletelist.length > 0
                  ? (isnew = false, this.deletelist.shift())
                  : new createjs.Sprite(this.spriteSheet, anime);
              sprite.isdie = false;
              sprite.dieing_frame=0;
              sprite.diecount = 0;
              Object.assign(sprite, option);
              sprite.die = sprite.die || (() => {
                  sprite.isdie = true;
                  Object.assign(sprite, die_option);
              });
              !isnew
                  ? (sprite.visible = true, sprite.gotoAndPlay(anime))
                  : this.cantiner.addChild(sprite);
              this.list.push(sprite);
          }
          update(timeFunc, dieFunc, diedFunc, test) {
              this.list = this.list.filter((s) => {
                  if (s.isdie) {
                      s.diecount++;
                      dieFunc(s);
                      if (s.diecount > (s.dieing_frame)) {
                          diedFunc(s);
                          this.deletelist.push(s);
                          s.visible = false;
                          return false;
                      }
                      return true;
                  }
                  timeFunc(s);
                  return this.outOfScreen(s, test);
              });
          }
      }
    6. 之后就是实现各种弹幕,计分显示等

    具体移步github https://github.com/lichddd/we...
    b站演示https://www.bilibili.com/vide...

    展开全文
  • 直接用xcode打开项目文件即可运行。当前项目使用xcode版本4.2.1
  • 简介DooMissO是本人使用JS、jQuery开发的一款弹幕射击游戏,现已推出1.8版 Js和jQuery代码混搭得比较厉害,后续几个版本会陆续修正统一github仓库地址:https://github.com/Kagashino/doomisso-demo 试玩地址:...

    简介

    DooMissO是本人使用JS、jQuery开发的一款弹幕射击游戏,现已推出1.8版
    HTML DOM操作和jQuery代码混搭得比较厉害,后续几个版本会陆续修正统一

    github仓库地址:https://github.com/Kagashino/doomisso-demo
    试玩地址:https://kagashino.github.io/doomisso-demo/

    实现步骤:

    一、游戏画布(伪)

    这个不是CANVAS开发的游戏,所以游戏画布是一个600*600的DIV,包括各种按钮和界面,画布右侧显示各种游戏即时数据。附上HTML代码:

    <!--    游戏设置画面   -->
        <div class="layout layout2">
            <center>
                <h2>游戏设置</h2>
                <h3>点击下方选项设置按键</h3><br>
                <h3 class="keySet">  向上    按键:<span id="UPKeySet"></span></h3>
                <h3 class="keySet">  向下    按键:<span id="DNKeySet"></span></h3>
                <h3 class="keySet">  向左    按键:<span id="LTKeySet"></span></h3>
                <h3 class="keySet">  向右    按键:<span id="RTKeySet"></span></h3>
                <h3 class="keySet">  低速    按键:<span id="LSKeySet"></span></h3>
                <h3 class="keySet">  还原默认按键</h3>
                <h3>难易度调节</h3>
                <span class="selectDiff" title="浅尝辄止的难度">简单</span><span class="selectDiff" title="代表大多数玩家的水平">正常</span><span class="selectDiff" title="难度越大,回报越高">疯狂</span>
                <input type="hidden" id="difficult" value="正常">
    
            </center>
    
            <h1 class="returnMain btn-style">返回</h1>
        </div>
    
        <!--    游戏说明        -->
        <div class="layout layout3">
            <center><h2>游戏说明</h2></center>
            <p class="howToPlay">
            1、默认<strong>Enter</strong>键开始,<strong>上下左右</strong>移动,<strong>shift</strong>低速移动,同时显示擦弹范围和判定点(见3、),您在下一个版本可以在“游戏设置”中修改游戏操作按键;<br />
            2、为了将来该游戏系统的布局计划,现在已开启<strong>自动开火</strong>模式;<br />
            3、擦弹范围是一个围绕着机体的<span class="gray">灰色的圈</span>,当圈内有子弹时分数会加得很快,判定点只有机体中间一个小<span class="wdot">白点</span>的范围,击中一次<span class="orange">生命值-10</span>(注意:碰到飞行物不会触发碰撞);<br />
            4、今后还会推出更丰富的游戏系统,敬请期待;<br />
            5、If it ran into any bug, REFRESH can solve 99% problems.(有任何问题,请使用刷新大法);<br>   
            6、good luck, have fun!
            </p>
            <img id="control" src="img/operate.png" />
            <h1 class="returnMain btn-style">返回</h1>
        </div>
    
        <!--                    游戏主面板                   -->
        <section id="gameScreen">
            <!-- 自机 -->
            <div id="p_ship" class="player1">
                <div id="laser"></div>
                <div id="p_spot"></div>
            </div>
    
        </section>
    
    
        <!--            数据面板            -->
        <aside>
            <button id="startBtn" >开始游戏</button><br>
    
            <button id="endTest"  onclick="endGame()">结束游戏</button><br><br>
    
            <p>生命值:<span id="hitCount">50</span></p><br>
            <p>擦弹:<span id="zijiPos">0</span></p><br>
            <p>分数:<span id="score">0</span></p><br><br>
            <p>屏幕弹幕数 <span id="dmkcount">0</span></p>
            <h4>HTML5弹幕射击游戏 ver1.8 作者:Kagashino</h4>
            <p>图片素材均来自恶魔之星</p><br>
            <p>历史版本 <br>
                <!--逻辑初成-->
                ver1.6.12.28 <br>
                <!--优化代码结构-->
                ver1.7.1.18 <br>
                <!--优化界面布局,增加自定义按键,优化代码结构-->
                ver1.7.2.28 <br>
                <!--重做了弹幕生成算法-->
                <!--新增自机狙、五角星和螺旋弹的算法-->
                <!--1.8更新:把弹幕添加到了Boss中,整个游戏流程基本成型-->
            </p><br><br>
    
        </aside>

    CSS设置

    body{
        margin: 0;
        padding: 0;
        z-index: -1000;
    }
    section,p,aside{
        margin: 0;padding: 0;
        display: inline-block;
        vertical-align: top;
    }
    aside{
        width: 30%;
    }
    
    
    .gray{
        border: 2px dashed #666;
        color:#666;
    }
    .orange{
    
        color: #f51;
    }
    .wdot{
        border: dashed 1px gray;
        color: #eee;
    }
    #gameScreen{
        width: 600px;
        height: 600px;
        background: #336 url(../img/bg.png);
        position: relative;
        /*overflow: hidden;*/
        z-index: 1;
    }
    
    #laser{
        position: absolute;
        width: 15px;
        height: 600px;
        background: transparent;
        border: 2px #fff solid;
        border-bottom: none;
        left: 35px;
        top: -560px;
        display: none;
    }
    #hitCount{
    }
    .btn-style{
        padding: 5px;
        position: absolute;
        font-weight: normal;
        border:3px solid white;
        color:white;
        z-index: 1000;
    }
    .btn-style:hover{
        cursor: pointer;
        font-weight: bold;
        box-shadow: 0 0 15px 5px white;
    }
    .btn-style::selection {
        background: none;
    }
    .btn-style::-moz-selection {
        background: none;
    }
    
    .keySet{
        text-align:left;
        width: 70%;
        border:2px solid transparent;
    }
    .keySet:hover{
        cursor: default;
        border-color: #fff;
    }
    .keySet::selection {
        background: none;
    }
    .keySet::-moz-selection {
        background: none;
    }
    .layout{
        width: 600px;
        height: 600px;
        color: #ffffff;
        position: absolute;
        z-index: 100;
    }
    .layout1{
        display: block;
    }
    .layout2{
        display: none;
    }
    .selectDiff{
        padding: 5px;
        border:solid 2px transparent;
    }
    .selectDiff:hover{
        cursor: pointer;
        text-shadow: 0px 0px 3px #fff;
    }
    .layout3{
        display: none;
        width: 550px;
        top: 10px;
        left: 30px;
    
    }
    .howToPlay{
        margin-top: 20px;
    }
    .currDifficult {
        position: absolute;
        top: 150px;
        left: 220px;
    }
    #startBtn2{
        top: 180px;
        left: 220px;
    }
    #gameConfig{
        top: 250px;
        left: 220px;
    }
    #readme{top: 320px;
        left:220px;
    }
    .returnMain {
        top: 500px;
        left: 450px;
    }
    #control{
        position: absolute;
        left: 50px;
        top: 300px;
        z-index: 1000;
    }
    
    /***************游戏物体样式******************/
    #p_ship{
        width:90px;
        height: 90px;
        background: url(../img/fighterAll.png) 0px 0px no-repeat;
        position: absolute;
        top: 300px;
        left: 250px;
        z-index: 10;
    }
    #p_spot{
        margin: 37px 37px;
        width: 10px;
        height: 10px;
        background: #fff;
        border: dotted 1px gray;
        border-radius: 50%;
        z-index: 100;
        display:block;
    }
    #p_spot:after{
        content: " ";
        display: block;
        width: 60px;
        height: 60px;
        border: dashed gray;border-radius: 50%;
        position: relative;
        top: -30px;
        left: -28px;
    }
    
    .enemy1{
        width: 60px;
        height: 60px;
        background: pink;
        position: absolute;
    }
    
    .left{
        background: url(../img/enemy1.png) no-repeat;
    }
    
    .right{
        background: url(../img/enemy1.png) -60px 0px no-repeat;
    }
    
    .enemy2{
        width: 60px;
        height: 60px;
        background: url(../img/enemy2.png) no-repeat;
        position: absolute;
    }
    
    #theBoss{
        width: 185px;
        height: 208px;
        background: url(../img/boss1.png) no-repeat;
        position: absolute;
        top: 85px;
        z-index:5;
    
    }
    
    .damagedBoss{
        background: url(../img/boss1dmg.png) no-repeat !important;
    }
    #bossHealthBar{
        width: 200px;
        height: 10px;
        position: absolute;
        top: 0;
        left: -10px;
        background: rgb(0,255,0);
        display: block;
    }
    
    .bullet,.poolBlt{
        width: 10px;
        height: 10px;
        background:red;
        border-radius: 50%;
        position: absolute;
        z-index: 100;
    }
    
    

    最终呈现的画面

    脚本引用:

    <script src="js/jquery.min.js"></script><!--jQuery-->
    <script src="js/keymap.js"></script><!-- 键盘对应名称 -->
    <script src="js/animateEasing.js"></script><!-- JQ动画速度曲线扩展 -->
    <script src="js/bulletClass.js"></script><!-- 子弹行为 -->
    <script src="js/newscript.js"></script><!-- 主逻辑 -->
    <script src="js/objAction.js"></script><!-- 物体移动逻辑 -->
    <script src="js/eventListener.js"></script><!-- 事件监听器 -->
    

    二、游戏逻辑控制

    初始化需要用到的变量:

    //键盘编码和对应条件判断变量
    var keySt = {
                UP: 38,
                DN: 40,
                LT: 37,
                RT: 39,
                LS: 16,
    
                toUp: false, 
                toDown: false, 
                toLeft: false, 
                toRight: false, 
                toLSpeed: false, 
                toShow: false,
                toPause: false, 
            }
    
    
    
    //状态
    var gameSt = {
                playing: false, //游戏是否进行中 
                boss: false,//是否在打BOSS
                graze : 0,//擦弹
                hp : 50,//生命值
                score : 0,//本轮得分
                highScore: 0,//最高分,目前尚未用到
                diff : 1 //难易度 0简单 1正常 2疯狂
            }
    /*定时器对象*/
    var timer = {
                general: null,//主定时器
                enemyCreator: null,//敌机1生成器
                enemy2Creator: null,//敌机2生成器
                overflowOperator: null,//子弹溢出处理器
                releaseBoss:null,
    
    }
    
    var boss = {
        health:300,
        position:[],
        state:1
    }
    /*检查是否与服务器连接,如果是,则开启分数记录功能*/
    var ajax = false;
    
    //自机
    var ziji = document.getElementById('p_ship');
    var spot = document.getElementById('p_spot');//判定点
    
    //画布
    var $gameScreen = $('#gameScreen');
    var $startBtn = $('#startBtn,#startBtn2');//两处可以控制开始的按钮

      点击开始按钮执行初始化游戏

    //初始化
    function gameInit(){
        gameSt.stop = keySt.toShow = false;
        initDanmaku();
        gameContinue();
    }

      开始游戏后关闭判定点显示,隐藏所有选单,gameProcess为生成敌人、boss等相关操作,同时必须先清除一次定时器,否则游戏进行到第二轮或以上,定时器会叠加执行
    fireUp为开火行为,第一次延迟1毫秒,之后每200毫秒执行一次

    function gameContinue(){
    
        $('.layout').hide();
        gameSt.playing = true;
        gameProccess();
        clearInterval(timer.general);
        timer.general=null;
    
        timer.openFire = setTimeout(fireUp,1);
        timer.general = setInterval(zijiOperator,21);
    }

    弹幕在游戏一开始就生成,只是将其放在屏幕看不见的地方作为弹幕池以备用,需要时再发出请求,子弹击中或者飞出屏幕后再回收,弹幕池里共有512枚子弹,因为屏幕子弹数达到250左右就会出现明显的卡顿了,所以我在后面将活动的弹幕控制在150左右,理论上是用不完的。

    /*生成弹幕池*/
    function initDanmaku(){
        var dmFrag = document.createDocumentFragment();//以文档碎片的形式添加弹幕
        for(var i=0; i<511; i++){
            var elem = document.createElement("p");
            elem.id = "danmaku"+i;
            elem.className = "poolBlt";
            elem.title = "1";
            resetObject(elem,"620px","620px")
            dmFrag.appendChild(elem);
        }
        $gameScreen.append(dmFrag);
        return true;
    }
    /*请求弹幕池*/
    function requestDanmaku() {
        if(gameSt.playing){
            for(var i=0; i<511; i++){
    
                if(document.getElementById("danmaku"+i).title==="1"){
                    document.getElementById("danmaku"+i).title = "2";
                    return i;
                }
    
            }
        }
    }

    生成敌人和boss

    /*游戏流程控制*/
    function gameProccess(){
        clearInterval(timer.overflowOperator);//防止Interval叠加,下同
        clearInterval(timer.enemyCreator);
        timer.overflowOperator = timer.enemyCreator = null;
    
    
        if(gameSt.playing) {
            createEnemy();//生成敌人
            //回收子弹和横向敌人
            timer.overflowOperator = setInterval(function () {
                ammoOperating();
                enemy1Operating();
    
            }, 200)//每200毫秒回收一次飞出屏幕的敌机和弹幕
        }
    
        //游戏开始30秒后生成BOSS
        timer.releaseBoss = setTimeout(BossInSight,30000)
    }

    生成BOSS和BOSS死亡后的回调,BOSS具体如何运动的,请参考第三节:

    /*BOSS状态*/
    function BossInSight() {
    
        if(gameSt.playing && !gameSt.boss){
            clearTimeout(timer.releaseBoss);//防止定时器叠加
            console.log("Enemy Ultra Cruiser is Approaching!");
    
            /*BOSS出现后,小怪不再生成*/
            clearInterval(timer.enemy2Creator);
            clearInterval(timer.enemyCreator);
            timer.enemy2Creator = timer.enemyCreator = null;
            gameSt.boss = true;//BOSS状态为真
            drawBoss();//绘制BOSS
        }
    
    }
    /*BOSS死亡后*/
    function  BossDie() {
        $('#theBoss').removeClass('damagedBoss').stop().remove();
        gameSt.boss = false;
        boss.state = 1;
    
        createEnemy();
        setTimeout(BossInSight,30000);
    }

    游戏结束后执行:清除定时器,停止自机行为,删除屏幕上的所有弹幕和敌人,弹出主菜单:

    function endGame(){
        gameSt.playing = gameSt.boss = false;//游戏进行和打BOSS状态关闭
    
        clearTimeout(timer.openFire);//先停火
        alert("你的生命值被耗尽,游戏结束");
    
        alert("最终得分:"+gameSt.score);
    
        keySt.toUp = keySt.toDown = keySt.toLeft = keySt.toRight = keySt.toLSpeed = keySt.toFire =  false;//停止移动
        /*下次将这些对象属性进一步细分,以便能够遍历*/
        clearInterval(timer.enemyCreator);
        clearInterval(timer.overflowOperator);
        clearInterval(timer.general);
        clearTimeout(timer.enemy2Creator);
        clearTimeout(timer.releaseBoss);
        clearTimeout(bossAction);
    
        for(item in timer){
            timer[item]=null
        }
        /*删除所有子弹、敌机*/
        $('.enemy1,.enemy2,.bullet,#theBoss,.poolBlt').stop().remove();
        /*重置自机和数据*/
        resetObject(ziji,"250px","300px");
        resetData();
        /*显示主菜单*/
        $('.layout1').show();
    
    }
    
    
    //重置数据
    function resetData(hp,score,graze){
        gameSt.hp = hp || 50;
        gameSt.score = score || 0;
        gameSt.graze = graze || 0;
        $('#hitCount').html(gameSt.hp);
        $('#zijiPos').html(gameSt.graze);
        $('#score').html(gameSt.score);
    }
    //重置对象CSS,传px
    function resetObject(obj,x,y){
        obj.style.left = x ;
        obj.style.top = y;
    
    }

    游戏画面:
    这里写图片描述

    三、游戏物体行为

      开火时显示2根激光柱,并且执行歼灭逻辑(消灭正前方的敌人),为了节约性能,我把自机的武器做成了瞬发,即时用即时判断:

    /*/开火/*/
    function fireUp(){
        eliminate();//歼灭敌人
    
        $('#laser').show();
        $('#laser').fadeOut(100);
    
        if(gameSt.playing){
            setTimeout(fireUp,250);
        }
    
    }
    
    *       敌人被击中判定     */
        function eliminate(){
    
            var px = ziji.offsetLeft+43,py = ziji.offsetTop;//开火判定位置偏移到元素视觉中心
    
            $('.theEnemy').each(function(){
                var ex = this.offsetLeft+30,ey = this.offsetTop;
                if(ex+35>px && ex-35<px && ey<py){
                    gameSt.score+=(100+gameSt.diff*100);
                    explode(0,ex,ey);//在被歼灭的位置绘制爆炸效果
                    $(this).remove();
                }
            });
            /*打BOSS另算*/
            if(gameSt.boss){
                hitTheBoss(px,py)
            }
        }

      zijiOperator是自机实现连续移动和碰撞的核心,每21毫秒判断执行一次,需要注意的是我们希望子弹元素与自机元素判断碰撞的位置是自机元素视觉中心,而非元素锚点位置(元素左上角),所以必须向右和向下偏移一定的位置:

    function zijiOperator() {
        var mvrg = keySt.toLSpeed? 4:10;//低速/高速状态下的移动距离
        if(keySt.toLeft){
            ziji.style.left=ziji.offsetLeft-mvrg+"px";
            ziji.style.backgroundPositionX = "-90px";//自机左右移动会变换贴图样式
        }
        if(keySt.toRight){
            ziji.style.left=ziji.offsetLeft+mvrg+"px";
            ziji.style.backgroundPositionX = "-180px";
        }
        if(keySt.toUp){
            ziji.style.top=ziji.offsetTop-mvrg+"px";
            ziji.style.backgroundPositionX = "0px";
    
        }
        if(keySt.toDown){
            ziji.style.top=ziji.offsetTop+mvrg+"px";
           ziji.style.backgroundPositionX = "0px";
        }
        if(!keySt.toRight && !keySt.toLeft){
            ziji.style.backgroundPositionX = "0px";
        }
        if(keySt.toLSpeed){
            spot.style.visibility = "visible";//低速模式下显示判定点和擦弹圈
        }else{
            spot.style.visibility = "hidden";
        }
    
        if(gameSt.playing){
            gameSt.score ++;
            $('#score').text(gameSt.score);
        }
    
        limit(ziji);//防止自机飞出游戏屏幕
        collision(ziji.offsetLeft+37,ziji.offsetTop+37);//传入自己XY坐标判断与子弹的碰撞,但是需要偏移到元素视觉中心
    
    }

    接下来处理碰撞与防溢出逻辑

    /***********************防溢出**********************************/
    function limit(ziji){/*对象*/
            //上下溢出
            ziji.style.top = ziji.offsetTop<-35?"-35px":ziji.offsetTop>550?"550px":ziji.style.top;
            //左右溢出
            ziji.style.left = ziji.offsetLeft<-35?"-35px":ziji.offsetLeft>550?"550px":ziji.style.left;
        }
    
    
        /************************自机碰撞判定***************************/
        /*
            *通过遍历所有子弹相对自机的距离判断是否碰撞
            *判断区域是圆形
            *擦弹加分
            *中弹减生命,生命为0结束游戏
        */
    function collision(x,y){
    
        $('.bullet').each(function () {
            var bltX = this.style.left.slice(0,-2)
            var bltY = this.style.top.slice(0,-2)
            if( Math.pow((x-bltX),2)+Math.pow((y-bltY),2)<750 ){
            /*擦弹距离根号750*/
                    gameSt.graze++;
                    gameSt.score += parseInt(gameSt.graze/20);
                    $('#zijiPos').text(gameSt.graze);
            }
            if( Math.pow((x-bltX),2)+Math.pow((y-bltY),2)<150 ){
            /*中弹距离约14左右*/
                    gameSt.hp-=10;
                    explode(1,bltX,bltY);//在中弹位置生成视觉效果
                    recycleBullet(this);//删除击中的子弹
                    $('#hitCount').text(gameSt.hp);//更新显示生命值
            if(gameSt.hp<=0)
                    endGame();//gg
            }
        });
      }

    敌人和BOSS的生成,注意下面很多代码都出现了gameSt.diff变量,这个是难度系数对游戏数值的补正

    /*生成敌人*/
    function createEnemy(){
        //生成敌人1和敌人2
        timer.enemyCreator = setInterval(function(){
            if($('.left').length==0 && $('.right').length==0){
                var both = Math.random()>0.1?1:0;//是否两边出飞机
                if(both){
                    drawEnemy1(1,2+gameSt.diff,4500 - gameSt.diff*500);
                    drawEnemy1(0,2+gameSt.diff,4500 - gameSt.diff*500);
                } else {
                /*单边出飞机*/
                    var lr = Math.random()>0.5?1:0;
                    drawEnemy1(lr,3+gameSt.diff*2,4500 - gameSt.diff*500);
                }
    
            }
            timer.enemy2Creator = setTimeout(drawEnemy2,(Math.random()*1000+200))
        },1000)
    }

    敌人1是从屏幕左上或右上飞入的战机,飞到一定距离发射2枚子弹,其中一枚是自机狙,敌机2是从屏幕顶部垂直飞下来的战机,降到一定高度发射开花弹,我们首先构造这两种敌人,在绘制函数中实例化

    //构造横向飞行物
    function Xobject(sign,speed,hp){
        this.ox = sign?-60:620//初始位置(左还是右)
        this.x = sign?660:-90;//结束位置与初始位置相对
        this.oy = parseInt(Math.random()*100);//初始高度
        this.y = parseInt(Math.random()*100);//到达目的地的高度
        this.hp = hp || 10;//这个貌似没用
        this.speed = speed || 3000;
    }
    
    //构造纵向飞行物
    function Yobject(hp,speed){
    
        this.x = Math.random()*500+10 || 300;//随机出现在顶端
        this.oy = -30;
        this.y = -60;
        this.hp = hp || 10;
        this.speed = speed || 1000;
    
    }
    
    //绘制横向飞行物,0为左,1为右
    function drawEnemy1(lr,howmany,speed){
        var obj = new Xobject(lr,speed)//左边还是右边生成
    
        var frag = document.createDocumentFragment()
    
        for(var i = 0; i<howmany ; i++){
            var div = $('<div>');
            div.addClass("theEnemy");
            div.addClass(lr?'enemy1 left':'enemy1 right');
            div.css({
                left:obj.ox + "px",
                top:obj.oy + "px"
            });
            div.appendTo($(frag));
    
        }
        $(frag).appendTo($gameScreen);
    
    
        for(var i = 0; i<howmany; i++){
            /*判断左右。。。。这里还需要再完善*/
            if(lr){
                var eachObj = $('.left:eq('+i+')');
                eachObj.delay(speed/5*i).animate({left: obj.x+'px', top: obj.y+'px'},obj.speed,"linear");
            }
    
            else{
                var eachObj = $('.right:eq('+i+')')
                eachObj.delay(speed/5*i).animate({left: obj.x+'px', top: obj.y+'px'},obj.speed,"linear");
            }
    
        }
    
    }
    //敌人1开火与回收
    function enemy1Operating(){
    
        $('.enemy1').each(function(){
            var obj = $(this);
            var objX = obj.offset().left, objY = obj.offset().top;
    
            /*指定一个随机范围的位置,如果敌人1到达指定位置即开火*/
            var ranL = parseInt(50+Math.random()*10);
            var ranR = parseInt(550-Math.random()*10);
    
            if(objX>ranL && objX<ranR){
    
                if(obj.css('opacity')=="1"){
                    /*发射完毕后试图隐身撤离*/
                    doLaunch(objX,objY+20);//发射直线弹
                    doLaunch(objX,objY+20,1);
                    obj.css('opacity','0.7');
    
                }
            }
    
            if(objX>650 || objX<-80){
                $(this).remove();
            }
    
        })
    }
    
    //敌人2行为
    function drawEnemy2(howmany,speed){
        var obj2 = new Yobject(howmany,speed);
        /*从屏幕顶端随机X坐标下落*/
        var ranY = Math.random()*100+50;
        var div = $('<div>').addClass('enemy2').addClass('theEnemy');
        div.css({
            top: obj2.y + 'px',
            left: obj2.x + 'px'
        });
    
        div.appendTo($gameScreen);
        /*2层动画,先下落,再发射,再向上逃离,并删除*/
        div.animate({top: ranY+'px'},obj2.speed,"linear",function(){
            if(!$(div).is(':hidden')){
    
                blossomLaunch(div[0].offsetLeft+10,div[0].offsetTop+20,"linear",0,1);//发射开花弹
            }
        }).animate({top: '-100px'},obj2.speed,"linear",function(){
            div.remove();
        });
    }

    BOSS是一个血超厚的敌人,随机在屏幕上半部分乱飞,并且发射有规则的弹幕

    /*绘制BOSS*/
    function drawBoss(){
        $('#theBoss').remove();
        var div = $('<div>').attr('id','theBoss');//创建一个BOSS元素
    
        resetObject(div[0],"200px","-200px");//设置BOSS起始位置
        boss.health = 150+100*gameSt.diff;//定义BOSS血量
        div.appendTo($gameScreen);
        $('<div id="bossHealthBar">').appendTo($('#theBoss'));//给BOSS添加生命条
    /*首先让BOSS从初始位置下降到屏幕中*/
        div.animate({top:"50px",left:"200px"},1500,"linear",function () {
    
            blossomLaunch(290,130,"easeOutQuad",0,1,1);//初见杀
            bossAction();//BOSS开始乱跑
        })
    
    
    }
    /*Boss行动*/
    function bossAction() {
        var bossX = Math.floor(Math.random()*400) , bossY = Math.floor(Math.random()*100);//随机BOSS飞行位置
        /*BOSS移动到目的地后才发射弹幕*/
        $('#theBoss').animate({
            top: bossY+"px",
            left: bossX+"px"
        },1000,function () {
            if(gameSt.boss){
            /*根据BOSS形态,分别发射2组不同的弹幕*/
                switch (boss.state){
                    case 1:{
                        blossomLaunch(bossX+90,bossY+80,"linear",1,1+gameSt.diff,$('#theBoss'));//开花弹
                        OutLaunch(gameSt.diff*5);//召唤支援火力
                    };break;
                    case 2:{
                        pentagonStar(ziji.offsetLeft+37,ziji.offsetTop+37,80,5+2*gameSt.diff,1)
                        pentagonStar(ziji.offsetLeft+37,ziji.offsetTop-13,240,5+2*gameSt.diff,2)//用五角星围住玩家
                    };break;
                    default:{
                        blossomLaunch(bossX+90,bossY+80,"linear",1,1+gameSt.diff,$('#theBoss'))//默认是螺旋弹
                    };
                }
            }
        })
        if(gameSt.boss){
            setTimeout(bossAction,3500+gameSt.diff*500);//重复这个函数
        }
    }

    正常状态下的BOSS
    这里写图片描述
    半血线以下的BOSS
    这里写图片描述

    四、弹幕算法

    本游戏中暂时没有拐弯飞行的子弹,所有的子弹都是直线飞行
    核心实现:请求弹幕池,定义初始坐标,用animate发射到目的地坐标去,
    先定义最简单的,单个子弹直线发射函数,自机狙指的是朝玩家当前方向射去的子弹:

    //直线发射,snipe为自机狙
    function doLaunch(x,y,snipe,direct){
    
        var toXY = [];
        var blt1 = $('#danmaku' + requestDanmaku());//请求弹幕池中不在动画序列中的子弹的,返回ID值
    
        /*如果不是自机狙,则子弹落点随机*/
        if(!snipe){
            toXY = [direct?direct:parseInt(Math.random()*800),650];
    
        } else {
            toXY = snipeCoord(x,y);//这里返回的是子弹-玩家连线的延长线终点坐标,终点确保能飞出屏幕外以被子弹回收器回收
    
        }
    
        shootIt(blt1,x,y,toXY[0],toXY[1],2500-gameSt.diff*250,"linear",0);//只要朝着给定的坐标射去就好了
    
    }

    开花弹逻辑(包括螺旋弹)

      落点位置是CircleMatrix使用函数调用后返回的一圈圆形离散坐标,setTimeout不能用for循环实现,我这里根据变量作用域链原理去执行有限次数的setTimeout

    /*
    *开花弹
    *参数:起始X,起始Y坐标,速度曲线,是否螺旋发射,几层圆圈(多为定义螺旋弹的圈数),发射本体是否还存在
    */
    function blossomLaunch(x,y,ease,spiral,lay,byWho){
        var ammo2Speed = 8000-400*gameSt.diff;//飞行速度
        var ammo2Number = parseInt(Math.random()*20+5)*gameSt.diff;//多少颗子弹组成的圆圈
        var mtx = new Array;//声明发射坐标数组
        for(var i=0;i<lay;i++){
            mtx=mtx.concat(CircleMatrix(ammo2Number));//有几层就请求多少圈圆形坐标
        }
        var mtxRest = mtx.length-1;//螺旋发射弹幕调用timeout次数
        /*内部定义螺旋发射弹幕*/
        function spiralLaunch() {
            var bltSpiral = $('#danmaku' + requestDanmaku());
            shootIt(bltSpiral,x,y,mtx[mtxRest][1],mtx[mtxRest][0],ammo2Speed,ease);//发射
            mtxRest--;
            if(mtxRest>=0 && byWho){
            /*如果发射本体不存在了或者子弹发射完毕,螺旋弹幕将不再继续发射*/
                setTimeout(spiralLaunch,10)
            }
        }
        if(spiral){
            spiralLaunch();//螺旋发射
        } else {
            for(var i = mtx.length-1; i>=0; i--){
    
                var blt2 = $('#danmaku' + requestDanmaku());
                shootIt(blt2,x,y,mtx[i][1],mtx[i][0],ammo2Speed,ease)
    
            }//正常发射
        }
    
    }

    CircleMatrix函数:

    function CircleMatrix(num) {/*传入多少颗*/
        var len = num || 20;/*默认20颗*/
        var arr = [];
        for(var i=0; i<len; i++){
            arr.push([1291*Math.sin(2*Math.PI*i/len),1291*Math.cos(2*Math.PI*i/len)]);
        }
        return arr;
    }



    从屏幕外360度随机飞入的自机狙:

    /*外部自机狙*/
    function OutLaunch(num) {
        var delay = Math.floor(Math.random()*500+100);//不同时发射
        var rest = num;
        delayLaunch();
        //内部定义执行的timeout
        function delayLaunch() {
            /*随机一个屏幕外的坐标*/
            var ranX,ranY;
            do{
                ranX = Math.floor(Math.random()*630-15);
                ranY = Math.floor(Math.random()*630-15);
            } while(ranX>-10 && ranX<610 && ranY>-10 && ranY<610)
    
            doLaunch(ranX,ranY,1);//直线发射
            rest--;
            if(rest>0){
                setTimeout(delayLaunch,delay)
            }
        }




    五角星弹幕

    逻辑比之前的复杂,游戏中我选用了反向扩张的五角星:实际上还有另外3种发射方式:

    *五角星*/
    /*
    *起始X,起始Y,宽度,每条边子弹数量,运动模式:
    *1. 正向扩张
    * 2. 反向扩张
    * 3. 自机狙
    * 其他 竖直砸下
    * */
    function pentagonStar(x,y,size,num,mode) {
        var coord = fillPentagon(size,x,y,num);//获取五角星初始坐标
        var coolen = coord.length;
    
        for(var i=0;i<coolen ;i++){
    
            if( Math.pow((ziji.offsetLeft+37-coord[i][0]),2)+Math.pow((ziji.offsetTop+37-coord[i][1]),2)>1000 ){
    
                var blt3 = $('#danmaku' + requestDanmaku());
                var toXY = [];
                switch(mode){
                    case 1:{
                        if(i>=0 && i<coolen/5){
                            toXY[0] = 0;
                            toXY[1] = -650;
                        }else if(i>=coolen/5 && i<coolen*2/5){
                            toXY[0] =  650*Math.tan(Math.PI/5)/// + coord[i][0];
                            toXY[1] = 650;
                        } else if(i>=coolen*2/5 && i<coolen*3/5){
                            toXY[0] = -650;
                            toXY[1] = -650*Math.tan(Math.PI/5)// - coord[i][0];
    
                        } else if(i>=coolen*3/5 && i<coolen*4/5){
                            toXY[0] = 650;
                            toXY[1] = -650*Math.tan(Math.PI/5)// - coord[i][0];
    
                        } else {
                            toXY[0] = -650;
                            toXY[1] = 650*Math.tan(Math.PI/5);
                        }
                        toXY[0] = "+=" + toXY[0];
                        toXY[1] = "+=" + toXY[1];
                    };break;
                    case 2:{
                        if(i>=0 && i<coolen/5){
                            toXY[0] = 0;
                            toXY[1] = 650;
                        }else if(i>=coolen/5 && i<coolen*2/5){
                            toXY[0] =  -650*Math.tan(Math.PI/5) // + coord[i][0];
                            toXY[1] = -650;
                        } else if(i>=coolen*2/5 && i<coolen*3/5){
                            toXY[0] = 650;
                            toXY[1] = 650*Math.tan(Math.PI/5) //+ coord[i][0];
    
                        } else if(i>=coolen*3/5 && i<coolen*4/5){
                            toXY[0] = -650;
                            toXY[1] = 650*Math.tan(Math.PI/5) //+ coord[i][0];
    
                        } else {
                            toXY[0] = 650;
                            toXY[1] = -650*Math.tan(Math.PI/5) //- coord[i][0];
                        }
                        toXY[0] = "+=" + toXY[0];
                        toXY[1] = "+=" + toXY[1];
                    };break;
                    case 3:{
                        toXY = snipeCoord();
                    };break;
                    default:{
                        toXY[0] = "+=0";
                        toXY[1] = "+=650";
                    };
                }
                blt3.hide();//一开始不显示
    
    
                shootIt(blt3,coord[i][0],coord[i][1],toXY[0],toXY[1],5000-400*gameSt.diff,"linear",2500-gameSt.diff*200);//先绑定发射动画
                blt3.delay(i*20).fadeIn(1,function () {});//加入延迟使每颗五角星一个个按轨迹出现
    
            }
    
        }
    
    }

    如何返回一个离散的正五角星坐标?

    需要传入五角星横边中点坐标、五角星的边长和每条边要生成多少枚子弹。先定下五角星五个角的坐标ABCDE,再分别给五条边AD\AC\CE\EB\BD填充一定数量的子弹的坐标:
    五角星坐标公式
    实现原理:

     /* 构造五角星的五个端点坐标    */
     /*传入边长,O点相对于画布X,Y的位置*/
    function Pentagon(a,x,y) {
        var pt = [
            [-a-a*Math.sin(Math.PI/10)+x,y],//-a-a*sin18°,0
            [a+a*Math.sin(Math.PI/10)+x,y],//a+a*sin18°,0
            [-a*Math.cos(Math.PI/5)+x,
                a*Math.cos(Math.PI/5)*(1/Math.tan(Math.PI/10))-a*Math.cos(Math.PI/10)+y],//-a*cos36°,-a*cos36°*cot18°+a*cos18°
            [x,-a*Math.cos(Math.PI/10)+y],//0,a*cos18°
            [a*Math.cos(Math.PI/5)+x,
                a*Math.cos(Math.PI/5)*(1/Math.tan(Math.PI/10))-a*Math.cos(Math.PI/10)+y]//a*cos36°,-a*cos36°*cot18°+a*cos18°
        ];//这里是个[[x1,y1],[x2,y2],[x3,y3],[x4,y4],[x5,y5]]结构的二位数组
    
    
        return pt;//返回这五个点的坐标
    }
    
    /*连线五角星*/
    function  fillPentagon(a,x,y,num) {
        a = a || 120;
        num = num || 7+2*gameSt.diff;
        var pt = Pentagon(a,x,y);//获取五角星端点
        var arr = new Array();
    
        for(var i=0; i<5; i++){
            var j = 0;
    
    
                var len = pt[(i+1)%5][0]-pt[i][0];
                while(Math.abs(j)<Math.abs(len)){
                    arr.push(
                        [pt[i][0]+j,pt[i][1]+j*(pt[(i+1)%5][1]-pt[i][1])/len]
                    )
                        j += len/num;
                }
    
        }
        return arr;//这下返回的就是一个离散五角星点了
    }

    shootIt是将执行的动画序列封装起来,以便不同类型的弹幕调用

    /*参数依次是:要发射的子弹对象,起始横坐标,起始纵坐标,目的地横坐标,目的地纵坐标,飞行速度,速度曲线,延迟发射时间*/
    function shootIt($obj,x,y,toX,toY,speed,ease,delay) {
    
        speed = speed || 2500-gameSt.diff*250;
        ease = ease || "linear"
        $obj.addClass('bullet');
        $obj.css({
            left: x+"px",
            top: y+"px"
        });
    
        function delayShoot() {
            if($obj.attr("title")==2){
                $obj.animate({top: toY + "px", left: toX + "px"},speed,ease);
            }
        }
    
        if(!delay){
            $obj.animate({top: toY + "px", left: toX + "px"},speed,ease);
        } else {
            setTimeout(delayShoot,delay)//不会出现for循环setTimeout问题了
        }
    
    }

    五、事件监听器

    给自机绑定键盘事件

    //Bind KeyBoardEvent
    window.onkeydown = function(event){
    
        var event=event||window.event;//兼容
        var code = event.keyCode || event.which;
        //console.log(event.key)//获取按键名称
        /*开控制台*/
    
        if(code==38 || code == 40){
            event.preventDefault();
        }//防止滚屏
    
        switch(code){
            case 13:{                   /*ENTER*/
                if(!gameSt.playing){
                    gameInit();
                }
            };break;
            case keySt.LS : {keySt.toLSpeed=true; }                 ;break;//You can check Keycode at Keymap.js at this path
            case keySt.LT : {keySt.toLeft=true; }                   ;break;
            case keySt.UP : {keySt.toUp=true; }                     ;break;
            case keySt.RT : {keySt.toRight=true; }                  ;break;
            case keySt.DN : {keySt.toDown=true; }                   ;break;
            // case keySt.FR : {keySt.tofire=true; fireUp() }       ;break;
            case 80       : pauseTheGame()                          ;break;
    
        }
    
    }
    
    
    
    window.onkeyup = function(event){
    
        var event=event||window.event;
        var code = event.keyCode || event.which;
        switch(code){
            case keySt.LS : keySt.toLSpeed=false        ;break;//Release Key to break the loop
            case keySt.LT : keySt.toLeft=false          ;break;
            case keySt.UP : keySt.toUp=false            ;break;
            case keySt.RT : keySt.toRight=false         ;break;
            case keySt.DN : keySt.toDown=false          ;break;
            // case keySt.FR : keySt.toFire = false     ;break;
    
        }
    
    }

    给按钮绑定鼠标点击事件

    /*This is for Mouse-click Test for Creating barrage*/
    /*鼠标点击游戏画面可以测试弹幕*/
    $gameScreen.click(function (e) {
        var X = e.clientX,Y=e.clientY;
        // pentagonStar(X,Y,80,7+2*gameSt.diff,1)
        // pentagonStar(X,Y-50,240,7+2*gameSt.diff,2)
        //OutLaunch(9);
        //blossomLaunch(X,Y,"linear",1,3,1)
        //doLaunch(X,Y,1,0)
    
    })
    
    $('#readme').click(function () {
        $('.layout1').hide();
        $('.layout3').show();
    })
    $('#gameConfig').click(function () {
        $('.layout1').hide();
        $('.layout2').show();
    })
    $('.returnMain').click(function () {
        $('.layout').hide();
        $('.layout1').show();
    })
    
    
    /*      难易度选择   */
    $('.selectDiff').click(function () {
        switch(this.innerText){
            case "简单":gameSt.diff = 0;break;
            case "正常":gameSt.diff = 1;break;
            case "疯狂":gameSt.diff = 2;break;
            default: console.log(this.innerText);break;
        }
        $('#difficult').val(this.innerText);
        $('.currDiff').text($('#difficult').val());
        $('.selectDiff').css({ borderColor:"transparent" });
        $(this).css({ borderColor:"#fff" });
    
    })
    
    /*这个日后开发*/
    $('.keySet').click(function(){
        alert('developing');
    })
    展开全文
  • 东方弹幕游戏!!!

    2018-02-22 20:18:00
    package com.totoo.TouhouMassLight...import android.app.Activity;import android.graphics.Bitmap;import android.graphics.Canvas;import android.graphics.Color;import android.graphics.Paint;import android...

    package com.totoo.TouhouMassLight;


    import android.app.Activity;
    import android.graphics.Bitmap;
    import android.graphics.Canvas;
    import android.graphics.Color;
    import android.graphics.Paint;
    import android.os.Build;
    import android.os.Bundle;
    import android.os.Handler;
    import android.os.Message;
    import android.util.DisplayMetrics;
    import android.view.KeyEvent;
    import android.view.MotionEvent;
    import android.view.View;
    import android.view.Window;
    import android.view.WindowManager;
    import android.view.animation.Animation;
    import android.view.animation.RotateAnimation;
    import android.widget.HorizontalScrollView;
    import android.widget.TextView;

    import com.totoo.TouhouMassLight.creature.NewHero;
    import com.totoo.TouhouMassLight.creature.NewMagic;
    import com.totoo.TouhouMassLight.creature.NewSuperShow;
    import com.totoo.TouhouMassLight.util.ContorlView;

    public class FullscreenActivity extends Activity {
    static Canvas GameCan = null;
    static Paint drawSome = null;
    public static final Double UITpersent = 0.25;
    public static final Double UIpersent2 = 0.2;
    public int SW = 480;
    public int SH = 768;
    public int EarthLine = (int) (SH * 0.62);
    int TouchArceH = (int) (SH * UITpersent);
    int TouchArceW = (int) (SW * UITpersent);
    int LeftDivede = (int) (SW * UITpersent);
    int RightDivede = (int) (SW * UITpersent * 3);
    int HighDivede = (int) (SH * UIpersent2);
    int MiddleDivede = (int) (SH * UIpersent2 * 2);
    int Center = (int) (SH * 0.8);
    int LowDivede = (int) (SH * UIpersent2 * 3);
    static NewHero molisha;
    static NewHero reimei;
    static int MapBodderX;
    static int MapBodderY;
    int[][] WorldMap;
    int[][] mapCache;
    int x;
    int y;
    int[] tagetXY;

    // Bitmap bgPic;
    Canvas CMain = null;
    Bitmap bMap = null;
    Bitmap bSCmap = null;
    // NotificationManager nm;
    // Notification n;
    DisplayMetrics dm;
    public static GameViewNew gv;
    String AlretString = "look there";
    NewSuperShow RSS;
    NewSuperShow MSS;
    View view;
    public static ContorlView contorlView;
    protected Handler mHandler;

    // OrientationEventListener mOrientationListener;
    private HorizontalScrollView horizontalScrollView1;
    protected TextView HeathTextView;

    private int NewMagicListSize = 72;
    protected int _pixiv;
    private boolean ExitGame = false;
    Runnable thread;
    Thread game;


    @Override
    protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    requestWindowFeature(Window.FEATURE_NO_TITLE);
    getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
    // ȫ���ö�
    prepare(0);
    game = new Thread(thread);
    thread = new GameThread();
    game.start();
    }


    @Override
    protected void onRestart() {
    super.onRestart();
    ExitGame = false;
    }


    protected void prepare(int degare) {
    initGameSource();
    HeathTextView = initUI(_pixiv = 8);
    mHandler = new GameUIHandler(HeathTextView, FullscreenActivity.this, gv);

    gv.getBoder(SW, SH, _pixiv);
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
    gv.setRotationX(25);
    }
    // gv.flashThem();
    }
    //void registListener(){
    // if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
    // gv.setRotationX(45);
    // }
    // mOrientationListener = new OrientationEventListener(this, SensorManager.SENSOR_DELAY_NORMAL) {
    // @Override
    // public void onOrientationChanged(int orientation) {
    // // Log.v(DEBUG_TAG, "Orientation changed to " + orientation);
    // if (orientation > 350 || orientation < 10) { // 0��
    // if (0 == orientation) {
    prepare(0);
    // } else
    // orientation = 0;
    // } else if (orientation > 80 && orientation < 100) { // 90��
    // if (90 == orientation) {
    prepare(90);
    // } else
    // orientation = 90;
    // } else if (orientation > 170 && orientation < 190) { // 180��
    // if (180 == orientation) {
    prepare(180);
    // } else
    // orientation = 180;
    // } else if (orientation > 260 && orientation < 280) { // 270��
    // if (270 == orientation) {
    prepare(270);
    // } else
    // orientation = 270;
    // } else {
    // return;
    // } // http://blog.csdn.net/goldenfish1919/article/details/47423131
    //
    // }
    // };
    // if (mOrientationListener.canDetectOrientation()) {
    // // Log.v(DEBUG_TAG, "Can detect orientation");
    // mOrientationListener.enable();
    // } else {
    // // Log.v(DEBUG_TAG, "Cannot detect orientation");
    // mOrientationListener.disable();
    // }}
    // protected TextView initUI(int pixiv) {
    // if (0 != pixiv)
    // _pixiv = pixiv;
    // return initUI(0);
    // }


    protected TextView initUI(int pixiv) {// ����ϵ�y
    view = getLayoutInflater().inflate(R.layout.activity_fullscreen, null);
    setContentView(view);
    gv = (GameViewNew) view.findViewById(R.id.imageView1)
    // new GameView(this)
    ;
    contorlView = (ContorlView) findViewById(R.id.cl);
    TextView HeathTV = (TextView) view.findViewById(R.id.HeathTextView);
    return HeathTV;
    }

    // RotateAnimation animation2 = new RotateAnimation(0, degare + 45, SW / 2, SH / 4*3);
    // animation2.setRepeatMode(RotateAnimation.RESTART);
    // animation2.setFillAfter(true);
    // contorlView.setAnimation(animation);
    // animation2.start();
    // horizontalScrollView1 = (HorizontalScrollView) findViewById(R.id.horizontalScrollView1);
    // horizontalScrollView1.setMinimumHeight((int) gv.startY);


    protected void initGameSource() {// ��ʼ���[���YԴ
    dm = new DisplayMetrics();
    getWindowManager().getDefaultDisplay().getMetrics(dm);
    SH = dm.heightPixels;
    SW = dm.widthPixels;
    EarthLine = (int) (SH * 0.62);
    Center = (int) (SH * 0.7);
    TouchArceH = (int) (SH * UITpersent);
    TouchArceW = (int) (SW * UITpersent);
    LeftDivede = (int) (SW * UITpersent);
    RightDivede = (int) (SW * UITpersent * 3);
    HighDivede = (int) (SH * UIpersent2);
    MiddleDivede = (int) (SH * UIpersent2 * 2);
    Center = (int) (SH * 0.8);
    LowDivede = (int) (SH * UIpersent2 * 3);
    drawSome = new Paint();
    drawSome.setColor(Color.RED);

    }

    @Override
    protected void onResume() {
    super.onResume();
    }

    @Override
    protected void onPause() {
    // thread.stop();
    super.onPause();
    }

    @Override
    protected void onDestroy() {
    super.onDestroy();
    // mOrientationListener.disable();

    }


    protected RotateAnimation startAnimate(int degare, View viewObj) {

    RotateAnimation animation = new RotateAnimation(0, degare + 45, SW / 2, SH / 2);
    animation.setAnimationListener(new Animation.AnimationListener() {

    @Override
    public void onAnimationStart(Animation arg0) {

    }

    @Override
    public void onAnimationRepeat(Animation arg0) {

    }

    @Override
    public void onAnimationEnd(Animation arg0) {

    }
    });
    viewObj.setAnimation(animation);
    // animation.setRepeatMode(RotateAnimation.RESTART);
    animation.setFillAfter(true);
    return animation;
    }
    // void comfrimMap() {// ���µ؈D���
    // if (null != mapCache) {
    // WorldMap = mapCache;
    // }
    // }

    @Override
    public boolean onTouchEvent(MotionEvent event) {// ���²�׽
    int ia = event.getAction();
    int x = (int) event.getX();
    int y = (int) event.getY();
    gv.TouchX = x;
    gv.TouchY = y;
    if (MotionEvent.ACTION_DOWN == event.getAction())
    pressACircle();
    else
    PressKey(x, y);
    return super.onTouchEvent(event);
    }

    private void pressACircle() {
    // TODO Auto-generated method stub

    }

    boolean PressKey(int x, int y) {// ���I푑�
    TouchArce();
    if (gv.NewMagicList.size() < NewMagicListSize)
    gv.NewMagicList.add(new NewMagic(AlretString, gv.molisha.getXinMap() > x ? -1 : 1, //
    gv.molisha.getYinMap() > y ? -1 : 1, //
    gv.molisha, gv.TouchX, gv.TouchY));
    else
    for (int i = 0; i < NewMagicListSize; i++) {
    gv.NewMagicList.get(i).DeractionInX = gv.molisha.getXinMap() > x ? -1 : 1;
    gv.NewMagicList.get(i).DeractionInY = gv.molisha.getYinMap() > y ? -1 : 1;

    }
    return false;
    }

    boolean TouchArce() {// �օ^��׽ϵ�y
    if (gv.TouchX < LeftDivede) {// �ұ�
    if (gv.TouchY < HighDivede) {// �����
    // tz("�����");
    SSA();
    } else if (gv.TouchY < MiddleDivede) {// �����
    // tz("�����");
    WSA();
    } else if (gv.TouchY < LowDivede) {// �w���I
    // tz("�w���I");
    PF();
    } else {// ����
    // tz("����");
    PL();
    }
    } else if (gv.TouchX < RightDivede) {// �м�
    if (gv.TouchY > Center) {// ����
    // tz("����");
    PD();
    } else {// ����
    // tz("����");
    PU();
    }
    } else {// ���

    if (gv.TouchY < HighDivede) {// ����1
    // tz("����1");
    SC1();
    } else if (gv.TouchY < MiddleDivede) {// ����2
    // tz("����2");
    SC2();
    } else if (gv.TouchY < LowDivede) {// ����
    // tz("����");
    A();
    } else {// ����
    // tz("����");
    PR();
    }
    }

    return false;
    }


    class GameThread implements Runnable {
    Message msg;
    boolean exitflag = false;

    @Override
    public void run() {// �[�?�
    while (!exitflag && !Thread.currentThread().isInterrupted()) {
    try {
    Thread.sleep(100);
    } catch (InterruptedException e) {
    }
    if (ExitGame) {
    exitflag = true;
    game.interrupt();
    // Message msg = new Message();
    // msg.obj = true;
    // mHandler.sendMessage(msg);
    } else {
    contorlView.postInvalidate();
    if (!gv.molisha.isGameExit()) {//是否绘制
    gv.postInvalidate();
    mHandler.sendEmptyMessage(0);//交给
    }
    }
    }
    }
    }


    private void A() {

    }

    private void SC2() {

    }

    private void SC1() {

    }

    private void PU() {
    // molisha.setDescription(3);// ����
    // mapCache = molisha.moveUp(WorldMap, MapBodderX, MapBodderY);
    // comfrimMap();
    }

    private void PD() {
    // molisha.setDescription(1);// ����
    // mapCache = molisha.moveDown(WorldMap, MapBodderX, MapBodderY);
    // comfrimMap();
    }

    private void PL() {
    // molisha.setDescription(2);// ����

    // mapCache = molisha.moveLeft(WorldMap, MapBodderX, MapBodderY);
    // comfrimMap();
    }

    private void PR() {
    // molisha.setDescription(0);// ����
    // mapCache = molisha.moveRight(WorldMap, MapBodderX, MapBodderY);
    // comfrimMap();
    }

    private void PF() {

    }

    private void WSA() {

    }

    private void SSA() {

    }

    @Override
    public boolean onKeyDown(int keyCode, KeyEvent event) {
    if (keyCode == KeyEvent.KEYCODE_BACK && event.getRepeatCount() == 0) { //按下的如果是BACK,同时没有重复
    // Toast.makeText("lyj_test","now_is_back_event",1).show();
    ExitGame = true;
    try {
    Thread.sleep(500);
    } catch (InterruptedException e) {
    e.printStackTrace();
    }
    game = null;
    // game.destroy();
    // game.stop();
    // game.exit = true; // 终止线程thread
    // game.join();
    finish();
    return true;

    }
    return super.onKeyDown(keyCode, event);
    }
    // 2、重写onBackPressed方法
    //
    // Android 2.0开始又多出了一种新的方法,对于Activity 可以单独获取Back键的按下事件,直接重写onBackPressed方法即可,代码如下

    @Override
    public void onBackPressed() {
    // 这里处理逻辑代码,大家注意:该方法仅适用于2.0或更新版的sdk
    return;
    }
    }

     

    动漫迎春贺图:祝大家狗年大吉 狗年告别单身狗

    2018-02-16 11:59:03 来源:pixiv 作者:未知 编辑:祈求 浏览:55744

    游民星空
    67288091

    游民星空
    66567522

    游民星空
    67242435

    游民星空
    65881016

    上一页 1 2 3 4 5 6 7 8 下一页
    友情提示:支持键盘左右键“← →”翻页

    用手机访问
    下载APP
    appicon 下载
    扫一扫,手机浏览
    code
    http://acg.gamersky.com/pic/201802/1015669_7.shtml

    转载于:https://www.cnblogs.com/totoo/p/youbang.html

    展开全文
  • 开发环境 Win10, Cocos2d-x v3.16, Visual Studio 2017, Visual Studio Code 项目阐述 ...游戏的设计主要借鉴了东方系列的弹幕游戏,借鉴内容包括pop子发射的各种弹,以及部分的关卡设计。 ...
  • 本文作为开发过程记录用。 目前游戏画面: ...弹幕类 from pygame.sprite import Sprite from pygame import transform import math class Barrage(Sprite): def __init__(self,raiden_setting...
  • 我最近开坑了一个类似东方project的弹幕游戏制作,由于之前没有经验(也就是说我是个小白),遇到弹幕碰撞时产生如下问题: 我有敌人的ArrayList<Enemy> 也有玩家的弹幕...
  • 四圣龙神录 官网地址 ...开源仿东方STG-四圣龙神录,带弹幕制作教程60讲,使用C语言+DXLib 非常不错的仿东方的STG,网站上面带制作教程,可以用来参考。 附带60讲教程详细介绍怎样修改他的弹幕STG工
  • 最近东方弹幕神乐开了第一个限时活动,一群肝帝真的太强了,奈何本人平时还要上班,根本没多少时间肝活动,于是利用软件解放双手,24小时自动AUTO音游打歌。 模拟器配置指南: 1.使用最新的安卓9.0测试版夜神模拟器 ...
  • package com.totoo.TouhouMassLight...import android.app.Activity;import android.graphics.Bitmap;import android.graphics.Canvas;import android.graphics.Color;import android.graphics.Paint;import android...
  • 东方project的弹幕美学

    2019-10-05 13:19:19
    弹幕射击游戏,也就是子弹像...东方Project的弹幕又跟很多的弹幕游戏不一样,这里我会配合下截图说下东方的特别之处 1.弹幕组成各种几何图形,给人一种美感 东方的弹幕除了一部分无规则的子弹之外,还会组成各...
  •  bilibili是中国大陆一个动画、游戏相关的弹幕视频分享网站,也被称为哔哩哔哩、B站,其前身为视频分享网站Mikufans。该网站由原AcFun网友“⑨bishi”于2009年6月26日创建。由于AcFun网站在运行时往往不稳定,所以...
  • 提到弹幕游戏,想到的最多的应该是《东方Project》系列了吧 酷炫的弹幕~~酷炫的弹幕~~我只记得酷炫。。。。   今天我们也来实现一个仿制版,阉割版~   关于弹幕游戏,有篇文章写的不错。我也就不重复写了...
  • 慢着,显示子弹之前,我们需要小小的抽象一下,把游戏中所有能显示的物体抽象成GameObject,好处是什么?好处是看起来很帅。。 当然不是,好处简单来说,整合公共部分、利于管理~~好吧我也不知道好处。。。。 //...
  • Doodle Flight一款非常有趣的涂鸦射击游戏,玩家可以自己手绘属于自己的个性战机,看看本9秒画的幽灵战机是不是略屌,哈哈! 直接运行源码中的Xcode工程即可,有可能需要改下Deployment Target和选择合适的模拟器,...
  • 还记得被东方project弹幕支配的恐惧吗——————————————————————如何用construct2做一个简易的弹幕游戏游戏链接http://1.projectboli.applinzi.com/当然,开始的开始,还是需要大家下载安装free...
  • 基本的子弹幕游戏 跨平台 支持Windows命令提示符 60帧 颜色 游戏时调整控制台大小 动机 所以我想这可能是不错的实现一个我自己的挑战,完成本场比赛中6小时,我完成了约4小时结合游戏中我找不到基于东方danmaku(弾...
  • 弹幕源自日本视频分享网站(niconico),国内首先引进为AcFun以及后来的bilibili,当大量评论一起在屏幕上飘过时看上去就像是飞行射击游戏里的弹幕一样,所以这些评论就被N站网民称作弹幕弹幕的特点就在于它的实时...
  • 因为之前已经做好了固定...【洩矢大人】这个弹幕东方风神录EX面的最后一个弹幕。 不太清楚的人看下面的视频来确认一下吧。(对不起,原文给nico的地址我打不开,只好发b站的了) http://www.bilibili.tv/search?keyw
  • 东方永夜抄的无敌源码 适用于1 00d版本 原理是跳过死亡
  • 测试STG4 Test STG4是一个用于iOS和macOS的实验性地狱引擎,... 弹幕府的设计原则(3) 为什么这个 除非没有更好的选择,否则没有理由应该使用此选项。 执照 代码是麻省理工学院 快照表和播放器精灵均为CC BY NC 4.0
  • Teki() Teki是系列的开源同人游戏,使用和OpenGL用Rust编写。 建筑 由于teki依赖于SDL2,因此您首先需要。...Z导致短时发射弹幕; 它可能会被按住以进行急速射击 Esc暂停游戏,并带您进入游戏内菜单
  • 东方决斗 对弹幕地狱游戏。 描述 这(完成后)是一个两人对战的游戏,玩家互相发射弹幕并试图降低对方的 HP。 ——还在建设中——
  • 系列中主要形式是飞机弹幕游戏,也有格斗游戏,本次我进行了新的尝试,设计了一款简单的Rpg探索解谜类游戏。用户在一个屋子里醒来,通过不断探索获得道具达成条件,避开死亡点,了解到整个故事并从...
  • 游戏中,你需要躲避他人的弹幕,并发射出自己的弹幕来攻击对方。本题中,为简单起见,只考虑对方发射的弹幕。 假设主角始终处于画面低端,将每秒与主角出现在一排的弹幕进行叠加,总共游戏进行了T秒,可

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 462
精华内容 184
关键字:

弹幕游戏东方