背景卷轴这个名字现在比较少听到了,现在的游戏引擎都不用这项技术了,或者可以轻松实现这个功能不值一提了,又或者不用这个技术照样也可以等等原因,大家基本听不到了。
玩过世嘉MD模拟器的可能对图层分层显示这个功能有印象,特别是对于提取游戏素材来说很有用。模拟器可以分别打开/关闭卷轴层和精灵层的显示,不过有的模拟器没有这个功能。
世嘉MD有双层卷轴,也就是有两层背景,背景可以滚动,做出很好的Parallax Scroll(视差滚动)效果。
这一节我们来做的案例效果如下图所示:
用到的素材是两张320x256的背景和一张40x32的精灵,我是从MD游戏《Mega Swiv》这个游戏截取的:
代码里设置的卷轴尺寸是32x64,单位是tile,64x8=512像素,其实大家直接用一张512高的背景图就可以了,不必用两张(懒得拼图- -)。本案例中的卷轴虽然只有32x64个tile,但是它是无限重复的。
素材大家自备就可以了,不一定非要跟我一样.
打飞机游戏我玩的不多,小时候玩的这个Mega Swiv确实震撼到我了,画面真的超级好,音乐也很动听,我也是在电视机上通关了,不过我是用的吉普车。
世嘉MD其实是没有摄像机这个概念的,我们之所以看到好像镜头移动似的,那都是用卷轴虚拟出来的,不是真的窗口移动,窗口其实从来就没动过,现在的游戏引擎都有摄像机对象可以控制,世嘉MD上是没有这个概念的,明白了这一点就找到正确的方向了,要不然可能会很茫然。
卷轴滚动看起来功能很简陋,其实可以设计出很精妙的效果的。
都讲到十一节了,相信大家对基础操作也不陌生了,前面没看过的可以翻看一下我的博客专栏。
直接上代码。
resources.res文件里的代码如下:
IMAGE res_bg1 "background1.png" 0
IMAGE res_bg2 "background2.png" 0
SPRITE res_spr "sprite.png" 5 4 0
main.c里的代码如下:
#include <genesis.h>
#include <vdp.h>
#include <sprite_eng.h>
#include "resources.h"
int main()
{
//设置Plan的尺寸,单位是tile,只能设置32,64,128这三个数,写别的没用
VDP_setPlanSize(32, 64);
//设置PAL0调色板,讲过不多说
VDP_setPalette(PAL0, res_bg1.palette->data);
//讲过不多说
u16 index = TILE_USERINDEX;
//绘制背景,讲过不多说
VDP_drawImageEx(PLAN_B, &res_bg1, TILE_ATTR_FULL(PAL0, 0, 0, 0, index), 0, 0, FALSE, CPU);
//讲过不多说
index += res_bg1.tileset->numTile;
//讲过不多说
VDP_drawImageEx(PLAN_B, &res_bg2, TILE_ATTR_FULL(PAL0, 0, 0, 0, index), 0, 32, FALSE, CPU);
//... ...
index += res_bg2.tileset->numTile;
//卷轴横向位置
s16 hScrollPosition = 0;
//卷轴纵向位置
s16 vScrollPosition = 0;
//卷轴横向滚动速度
s16 hScrollSpeed = 1;
//卷轴纵向滚动速度
s16 vScrollSpeed = 1;
//设置卷轴滚动模式,
//横向有三种模式:
//HSCROLL_PLANE:这个最常用,也就是以像素为单位滚动
//HSCROLL_TILE:这个是以tile为单位滚动,一下就是8个像素
//HSCROLL_LINE:这个是以一行像素为单位,我没用过,大家可以自己试试
//纵向模式有两种:跟横向的差不多
VDP_setScrollingMode(HSCROLL_PLANE, VSCROLL_PLANE);
//初始化精灵
SPR_init();
//精灵位置
s16 spr_pos_x = 140;
s16 spr_pos_y = 190;
//精灵移动速度
s16 spr_moveSpeed = 2;
//设置PAL1调色板
VDP_setPalette(PAL1, res_spr.palette->data);
//创建精灵,也就是我们控制的角色
Sprite *spr = SPR_addSprite(&res_spr, spr_pos_x, spr_pos_y, TILE_ATTR(PAL1, 0, 0, 0));
//设置精灵动画为第一个,从0开始数,详细见精灵动画这一篇
SPR_setAnim(spr, 0);
while (1)
{
//获取键值
u16 input = JOY_readJoypad(JOY_1);
if (input & BUTTON_UP)
{
//按上键,卷轴向下滚动
vScrollPosition -= vScrollSpeed;
//同时精灵往上移动
spr_pos_y -= spr_moveSpeed;
}
if (input & BUTTON_DOWN)
{
//按下键,卷轴往上滚动
vScrollPosition += vScrollSpeed;
//精灵往下移动
spr_pos_y += spr_moveSpeed;
}
if (input & BUTTON_LEFT)
{
hScrollPosition += hScrollSpeed;
spr_pos_x -= spr_moveSpeed;
}
if (input & BUTTON_RIGHT)
{
hScrollPosition -= hScrollSpeed;
spr_pos_x += spr_moveSpeed;
}
//这一块是做精灵坐标限制的,不让精灵走出屏幕之外
//40是精灵的宽,32是精灵的高,这个根据自己的图片素材分辨率不同而不同
if (spr_pos_x + 40 > VDP_getScreenWidth())
spr_pos_x = VDP_getScreenWidth() - 40;
if (spr_pos_x < 0)
spr_pos_x = 0;
if (spr_pos_y + 32 > VDP_getScreenHeight())
spr_pos_y = VDP_getScreenHeight() - 32;
if (spr_pos_y < 0)
spr_pos_y = 0;
//位置计算好了直接代入设置水平滚动的函数中
VDP_setHorizontalScroll(PLAN_B, hScrollPosition);
//同上,把计算好的速度代入纵向滚动函数中
VDP_setVerticalScroll(PLAN_B, vScrollPosition);
//设置精灵坐标
SPR_setPosition(spr, spr_pos_x, spr_pos_y);
//更新精灵
SPR_update();
//这个函数前面一直没讲过,这其实是垂直同步,
//要是不开的话,画面刷新速度就是处理器处理速度,处理器能计算多快就刷新多快,
//写的话就是画面固定刷新60帧,如果不写,有时候会出现花屏现象,建议写
VDP_waitVSync();
}
return 0;
}
编译,得到rom.bin,用模拟器打开,好了,可以开着小飞机到处走了。