世嘉MD游戏开发进阶篇【三】:向量归一化的实现及应用

向量归一化是非常有用的,游戏中经常能用到,就说大家都见过的,FC魂斗罗的敌人发射子弹就能用到了,敌人向玩家发射子弹首先要获取到向量,这个向量不能直接作为方向去用,必须要经过归一化处理才行,经过归一化处理后你才能精确的设置子弹的速度,不然子弹的速度是不可控的。

我做了个小demo来演示玩家向目标点移动的效果,跟魂斗罗的敌人向玩家发射子弹是一样的道理,效果图如下:

黑色的小方框是玩家,黑色的小点就是移动的目标点。

我先介绍一下向量归一化的计算方法吧:

//比如有一个向量v
Vector3 v = new Vector3(6.0, 10.0, 15.0);

//计算出向量所有元素的和,这里sum = 31,要是有元素是负数要用绝对值
float sum = v.x + v.y + v.z;

//每一个元素除以sum
v.x /= sum;
v.y /= sum;
v.z /= sum;

得到归一化的向量: [0.19, 0.32, 0.48]

在SGDK中的代码如下:

/*
    角色自动向点的方向移动,角色到点的距离小于等于1.5的时候,点的位置会随机改变
*/

#include <genesis.h>
#include <vdp.h>
#include "resources.h"

//目标点的坐标
Vect2D_f16 point;

//角色坐标
Vect2D_f16 charPos;

//精灵,目标点
Sprite *spr_point = NULL;

//精灵,角色
Sprite *spr_char = NULL;

//角色移动的速度
fix16 moveSpeed = FIX16(0.04);

//角色到点的最小距离
fix16 minDistance = FIX16(1.5);

//向量归一化
Vect2D_f16 vector_normalize(Vect2D_f32 _v);

//随机设置点的位置
void randomPoint();

int main()
{
    //绘制标题
    VDP_drawText("Vector Normalize", 12, 0);

    //设置PAL0的调色板
    VDP_setPalette(PAL0, res_point.palette->data);

    //初始化sprite
    SPR_init();

    //初始化点的位置
    charPos.x = FIX16(0);
    charPos.y = FIX16(0);

    //初始化角色的位置
    point.x = FIX16(60);
    point.y = FIX16(40);

    //设置点的精灵图片
    spr_point = SPR_addSprite(&res_point, fix16ToRoundedInt(point.x), fix16ToRoundedInt(point.y), TILE_ATTR(PAL0, 0, 0, 0));

    //设置角色的精灵图片
    spr_char = SPR_addSprite(&res_char, fix16ToRoundedInt(charPos.x), fix16ToRoundedInt(charPos.y), TILE_ATTR(PAL0, 0, 0, 0));

    //更新精灵
    SPR_update();

    while (TRUE)
    {
        //dir用来计算方向向量
        Vect2D_f32 dir;

        //你想去哪个位置,就用哪个位置减去自己的位置
        dir.x = point.x - charPos.x;
        dir.y = point.y - charPos.y;

        //获取归一化的方向
        Vect2D_f16 _nDir = vector_normalize(dir);

        //这一段是勾股定理的内容,目的是求出角色到点的距离,A² + B² = C²,不多做解释了,详细看我的世嘉MD游戏开发进阶教程之两点的距离
        fix32 powX = dir.x * dir.x;
        fix32 powY = dir.y * dir.y;
        fix32 powDist = minDistance * minDistance;
        fix32 sumXY = powX + powY;

        //距离大于最小距离,也就是没碰到目标点
        if (sumXY > powDist)
        {
            //向点的方向运动,方向_nDir和每帧移动速度moveSpeed
            charPos.x += _nDir.x * moveSpeed;
            charPos.y += _nDir.y * moveSpeed;
        }
        else
        {
            //碰到目标点后随机改变目标点的位置
            randomPoint();
        }

        //这俩都是很基础的内容了,设置精灵的坐标
        SPR_setPosition(spr_char, fix16ToRoundedInt(charPos.x), fix16ToRoundedInt(charPos.y));
        SPR_setPosition(spr_point, fix16ToRoundedInt(point.x), fix16ToRoundedInt(point.y));

        //更新精灵
        SPR_update();

        VDP_waitVSync();
    }
    return 0;
}

//向量归一化,计算方法是,先计算出向量所有数的和,二维向量就是x+y,三维向量就是x+y+z,然后再用每个元素除以这个和,得出归一化的元素
Vect2D_f16 vector_normalize(Vect2D_f32 _v)
{
    Vect2D_f16 _tmp;
    fix16 sum = fix32ToFix16(abs(_v.x) + abs(_v.y));
    _tmp.x = fix16Div(fix32ToFix16(_v.x), sum);
    _tmp.y = fix16Div(fix32ToFix16(_v.y), sum);
    return _tmp;
}

//随机设置点的位置
void randomPoint()
{
    point.x = FIX16(random() % 319);
    point.y = FIX16(random() % 223);
}

还是挺简单的^_^


版权声明:本文为qq272508839原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。