【问题标题】:Game logic and game loops in ActionScript 3ActionScript 3 中的游戏逻辑和游戏循环
【发布时间】:2011-12-13 08:09:50
【问题描述】:

我正在使用 flash actionscript 3 制作射击游戏,并且对逻辑流程以及如何巧妙地使用 OOP 概念有一些疑问。

主要有3个类:

  1. 主类:初始化屏幕上的对象。
  2. Enemy Class:用于在屏幕上移动敌人。
  3. 子弹类:用于射击。

我想要做的是找出敌人是否被子弹击中并做一些必须做的事情......

我现在正在做的是我有一个 ENTER_FRAME 事件,在该事件中我检查每个敌方单位(保存在数组中)与创建的子弹实例的碰撞检测,如果它发生碰撞,则执行所有必要的操作主类..在进程中阻塞主类..

这是正确的技术吗?还是有更好的解决方案?

【问题讨论】:

    标签: actionscript-3


    【解决方案1】:

    尝试更多地考虑 OOP,每个对象负责的目的是什么?

    我们有可以击中的敌人:

    class Enemy : extends NPC implements IHittable {
        . . .
    
        function update(delta) {
            // move, shoot, etc.
        }
    
        function handleHit(bullet) {
            // die
        }
    }
    

    一个可命中的对象:

    interface IHittable {
        function handleHit(bullet);
    }
    

    假设子弹会移动并击中物体:

    class Bullet : {
        function update(delta) {
            // update position
        }
    
        function checkHits(world:World) {
            for each(var hittable:IHittable in world.objects) { // might want to cluster objects by location if you're handling lots of objects / bullets)
                if (isColidingWith(hittable))
                    o.handleHit(bullet);
            }
        }
    }
    

    然后我们就拥有了里面的一切:

    class World {
        var npcs: Array ...
        var bullets: Array ...
        var hittables: Array ...
    
        function update(delta) {
            foreach(var c:NPC in npcs)
                c.update(delta);
    
            foreach(var b:Bullet in bullets) {
                b.update(delta);
                b.checkCollisions(world);
            }
        }
    }
    

    你的主循环就是这么简单:

    var lastTime:int;
    
    function onEnterFrame(...) {
        var now:int = getTimer(); // FlashPlayer utility function to get the time since start (in ms)
    
        world.update(now - lastTime);
        lastTime = now;
    }
    

    其他几点说明:

    • 尽量根据delta的时间进行所有计算,否则游戏的速度会随着帧速率而变化。

    • 当角色死亡时会发生什么?子弹消失?好吧,您可以通过多种方式做到这一点:

      • 触发一个事件,例如EnemyDied 并将其从世界上移除
      • 实现一个具有(get dead():Boolean 属性)的接口CanDie,并在每次更新时使用它来清理世界。
      • 但不要在Enemy 类中编写删除敌人的代码,因为那样您将使用应该由World 处理的代码污染类,并且以后很难维护。

    对不起,回答太长了,但我忍不住 :)

    【讨论】:

    • 嘿,感谢这个精彩的回复.. :D 真的很有帮助你能解释我更多的事情......什么是接口实现?其次,我在这里有点困惑..假设当我的子弹实例创建时,世界中有 9 个敌人实例,而当子弹移动时,又创建了一个敌人实例..那么我的子弹实例将如何检查它与所有的碰撞敌人实例?
    • 你应该只有一个敌人列表,每次你创建一个新敌人时,把它添加到那个地方,每次你检查 colisions 时,循环进入那个列表。在我的示例中,这将是 World.npcs 列表。 (npc = 非玩家角色:p)。
    • 接口是一种通过一些通用功能来处理不同类型对象的方式。想想你的电视和吸尘器,它们都可以实现一个叫做 CanTurnOn 的接口。尝试对此进行更多阅读,这是非常基本且重要的内容。
    【解决方案2】:

    是阻塞主类的问题,还是找出是什么子弹击中了哪个敌人的问题?如果是子弹,你需要描述子弹的行为——它可以击中多个敌人,它移动的速度有多快(是否有可能在使用“enterFrame”进行测试时,子弹首先出现在敌人面前,并且,在第二帧,会出现在敌人身后?)。可以将敌人简化为一些基本的几何形状,例如圆形或矩形,还是您需要像素级的精确度?最后,您打算在任何时候拥有多少子弹和多少敌人?如果每个子弹有数百个显示对象,则每个子弹都有一个显示对象可能太昂贵了,然后将它们绘制成单个形状/位图数据可能更有意义。

    如果问题是Main类太长,这里有几种可能。

    1. 对此问题的简单回答 - 使用继承将部分代码简单地放在单独的文件中。不是最好的方法,但很多人都会这样做。
    2. 如果您做了第一个,那么您会意识到您将某些函数组放入超类和子类中 - 这将帮助您将“阻塞”的类拆分为几个更小的独立部分,这些部分具有更特殊的专业化。
    3. 做完第二个之后,你可能会发现大类拆分成小类之间存在一定的依赖关系,所以你可以尝试按照一定的模式生成这些小类。
    4. 然后您编写阻塞代码来概括您刚刚设法拆分的那些部分。

    以上基本上是从更具体的代码到更通用的代码的循环。在完善最后一步的过程中,你会再次编写一些具体的代码。这将使您进入第 1 步。起泡、冲洗、重复 :) 事实上,您不想编写 OO 代码、过程代码或当今时尚告诉您要做的任何事情。你想写出好的代码 :) 你通过从更通用到更具体再回到更通用来做到这一点,直到它完美:P

    可能不是最好的答案,但你必须承认,你没有提供太多信息来给你更准确的答案。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-03-09
      • 1970-01-01
      • 1970-01-01
      • 2014-01-21
      • 2011-02-10
      • 2020-07-14
      • 1970-01-01
      • 2011-12-15
      相关资源
      最近更新 更多