- android - 多次调用 OnPrimaryClipChangedListener
- android - 无法更新 RecyclerView 中的 TextView 字段
- android.database.CursorIndexOutOfBoundsException : Index 0 requested, 光标大小为 0
- android - 使用 AppCompat 时,我们是否需要明确指定其 UI 组件(Spinner、EditText)颜色
这可能需要一段时间才能解释-在阅读本文时,请先品尝小吃。
我正在为C ++中的Gameboy Advance开发2D益智平台游戏(我是一个相当新的程序员)。直到昨晚,我一直在制作物理引擎(只是一些与轴对齐的边界框东西),我正在使用GBA屏幕大小的水平进行测试。但是,最终游戏将要求其级别大于屏幕大小,因此我尝试实现一种系统,该系统允许GBA的屏幕跟随玩家,因此,我必须绘制所有内容在屏幕上相对于屏幕的偏移量。
但是,当我显示可以在关卡中拾取和操纵的多维数据集时遇到麻烦。每当玩家移动时,屏幕上的多维数据集的位置似乎就会偏离其在关卡中的实际位置。这就像绘制多维数据集的帧是一个不同步的帧-当我在玩家移动时暂停游戏时,这些框会显示在正确的位置,但是当我取消暂停时,它们会错位直到玩家停止再次移动。
我的类的简要说明-有一个称为Object的基类,它定义(x,y)位置和宽度和高度,还有一个Entity类,它从Object继承并添加速度分量,而Character类则从Entity继承并增加了运动功能。我的播放器是一个Character对象,而我要拾取的多维数据集是Entity对象的数组。 player和cubes数组都是Level类的成员,该类也从Object继承。
我怀疑问题出在最后一个代码示例中,但是,为了完全理解我要执行的操作,我以更加合逻辑的顺序排列了这些示例。
以下是Level的截断头:
class Level : public Object
{
private:
//Data
int backgroundoffsetx;
int backgroundoffsety;
//Methods
void ApplyEntityOffsets();
void DetermineBackgroundOffsets();
public:
//Data
enum {MAXCUBES = 20};
Entity cube[MAXCUBES];
Character player;
int numofcubes;
//Methods
Level();
void Draw();
void DrawBackground(dimension);
void UpdateLevelObjects();
};
class Entity : public Object
{
private:
//Methods
int GetScreenAxis(int &, int &, const int, int &, const int);
public:
//Data
int drawx; //Where the Entity's x position is relative to the screen
int drawy; //Where the Entity's y position is relative to the screen
//Methods
void SetScreenPosition(int &, int &);
};
//Main loop
while (true)
{
...
level.MoveObjects(buttons);
level.Draw();
level.UpdateLevelObjects();
...
}
MoveObjects()
上,这确定了玩家和该立方体相对于该立方体的位置。这样就剩下
Draw()
和
UpdateLevelObjects()
。
Draw()
。如果不是正确显示不是我的多维数据集,而是由于它们位于的水平和平台(我认为这不是问题,但有可能),我将提供此信息。
Draw()
仅调用一个相关函数
DrawBackground()
:
/**
Draws the background of the level;
*/
void Level::DrawBackground(dimension curdimension)
{
...
//Platforms
for (int i = 0; i < numofplatforms; i++)
{
for (int y = platform[i].Gety() / 8 ; y < platform[i].GetBottom() / 8; y++)
{
for (int x = platform[i].Getx() / 8; x < platform[i].GetRight() / 8; x++)
{
if (x < 32)
{
if (y < 32)
{
SetTile(25, x, y, 103);
}
else
{
SetTile(27, x, y - 32, 103);
}
}
else
{
if (y < 32)
{
SetTile(26, x - 32, y, 103);
}
else
{
SetTile(28, x - 32, y - 32, 103);
}
}
}
}
}
}
SetTile()
首先需要一个屏幕阻止编号。我用来显示平台的背景层是64x64瓦片,因此需要2x2屏幕块(每个块32x32瓦片)才能全部显示。屏幕块编号为25-28。 103是我的地图中的地图编号。
UpdateLevelObjects()
:
/**
Updates all gba objects in Level
*/
void Level::UpdateLevelObjects()
{
DetermineBackgroundOffsets();
ApplyEntityOffsets();
REG_BG2HOFS = backgroundoffsetx;
REG_BG3HOFS = backgroundoffsetx / 2;
REG_BG2VOFS = backgroundoffsety;
REG_BG3VOFS = backgroundoffsety / 2;
...
//Code which sets player position (drawx, drawy);
//Draw cubes
for (int i = 0; i < numofcubes; i++)
{
//Code which sets cube[i] position to (drawx, drawy);
}
}
REG_BG
位是GBA的寄存器,它允许背景层在垂直和水平方向上偏移多个像素。这些偏移量首先在
DetermineBackgroundOffsets()
中计算:
/**
Calculate the offsets of screen based on where the player is in the level
*/
void Level::DetermineBackgroundOffsets()
{
if (player.Getx() < SCREEN_WIDTH / 2) //If player is less than half the width of the screen away from the left wall of the level
{
backgroundoffsetx = 0;
}
else if (player.Getx() > width - (SCREEN_WIDTH / 2)) //If player is less than half the width of the screen away from the right wall of the level
{
backgroundoffsetx = width - SCREEN_WIDTH;
}
else //If the player is in the middle of the level
{
backgroundoffsetx = -((SCREEN_WIDTH / 2) - player.Getx());
}
if (player.Gety() < SCREEN_HEIGHT / 2)
{
backgroundoffsety = 0;
}
else if (player.Gety() > height - (SCREEN_HEIGHT / 2))
{
backgroundoffsety = height - SCREEN_HEIGHT;
}
else
{
backgroundoffsety = -((SCREEN_HEIGHT / 2) - player.Gety());
}
}
width
指的是像素水平的宽度,而
SCREEN_WIDTH
指的是GBA屏幕宽度的常数。另外,对这个懒惰的重复也感到抱歉。
ApplyEntityOffsets
:
/**
Determines the offsets that keep the player in the middle of the screen
*/
void Level::ApplyEntityOffsets()
{
//Player offsets
player.drawx = player.Getx() - backgroundoffsetx;
player.drawy = player.Gety() - backgroundoffsety;
//Cube offsets
for (int i = 0; i < numofcubes; i++)
{
cube[i].SetScreenPosition(backgroundoffsetx, backgroundoffsety);
}
}
/**
Determines the x and y positions of an entity relative to the screen
*/
void Entity::SetScreenPosition(int &backgroundoffsetx, int &backgroundoffsety)
{
drawx = GetScreenAxis(x, width, 512, backgroundoffsetx, SCREEN_WIDTH);
drawy = GetScreenAxis(y, height, 256, backgroundoffsety, SCREEN_HEIGHT);
}
GetScreenAxis()
:
/**
Sets the position along an axis of an entity relative to the screen's position
*/
int Entity::GetScreenAxis(int &axis, int &dimensioninaxis, const int OBJECT_OFFSET,
int &backgroundoffsetaxis, const int SCREEN_DIMENSION)
{
int newposition;
bool onawkwardedgeofscreen = false;
//If position of entity is partially off screen in -ve direction
if (axis - backgroundoffsetaxis < dimensioninaxis)
{
newposition = axis - backgroundoffsetaxis + OBJECT_OFFSET;
onawkwardedgeofscreen = true;
}
else
{
newposition = axis - backgroundoffsetaxis;
}
if ((newposition > SCREEN_DIMENSION) && !onawkwardedgeofscreen)
{
newposition = SCREEN_DIMENSION; //Gets rid of glitchy squares appearing on screen
}
return newposition;
}
OBJECT_OFFSET
(512和256)是GBA特有的东西-将对象的x或y位置设置为负数将无法正常执行您的预期-弄乱了用于显示它的精灵。但是有个窍门:如果您想将X位置设置为负数,则可以在负数上加上512,然后精灵将显示在正确的位置(例如,如果您要将其设置为-1,则将其设置为512 + -1 = 511)。同样,为负Y位置添加256也可以(这都是相对于屏幕,而不是水平)。如果通常将多维数据集显示在更远的地方,则最后一个if语句会使多维数据集在屏幕上显示的比例保持较小,因为尝试将它们显示得太远会导致出现小方块,这也是GBA特定的东西。
for (int i = 0; i < numofcubes; i++)
{
SetObject(cube[i].GetObjNum(),
ATTR0_SHAPE(0) | ATTR0_8BPP | ATTR0_REG | ATTR0_Y(cube[i].drawy),
ATTR1_SIZE(0) | ATTR1_X(cube[i].drawx),
ATTR2_ID8(0) | ATTR2_PRIO(2));
}
最佳答案
我将解释这个答案,按位运算符是如何工作的,一个数字如何表示一个可能值为0到255(256个组合)的字节,它包含所有GBA Control印刷机。这类似于您的X / Y位置问题。
控件Up - Down - Left - Right - A - B - Select - Start
这些是GameBoy Color控件,我认为GameBoy Advanced具有更多控件。
因此共有8个控件。
每个控件都可以被按下(按住)或不被按下。
这意味着每个控件应仅使用数字1
或0
。
由于1
或0
仅占用1位信息。在一个字节中,您最多可以存储8个不同的位,适合所有控件。
现在您可能正在考虑如何通过添加或其他方式将它们组合在一起?是的,您可以这样做,但是这会使您的理解变得非常复杂,并且会给您带来这个问题。
假设您有半杯空的水,并且向其中添加了更多的水,并且想要将新添加的水与旧水分离。.您就是不能这样做,因为水都变成了一种水,无法取消此操作(除非我们标记每个水分子,而且我们还不是外星人。..哈哈)。
但是对于按位运算,它使用数学运算来找出整个位流(列表)中的哪个位确切是1
或0
。
因此,您要做的第一件事就是将每一点都交给控件。
每个位都是二进制的2的倍数,因此您只需将值加倍即可。Up - Down - Left - Right - A - B - Select - Start
1 - 2 - 4 - 8 - 16 - 32 - 64 - 128
同样,按位运算不仅用于确定哪个位是1
或0
,还可以使用它们将某些内容组合在一起。控件可以很好地完成此操作,因为您可以一次按住多个按钮。
这是我用来找出被按下或未被按下的代码。
我不使用C / C ++,所以这是javascript
我在我的Gameboy模拟器网站上使用了它,字符串部分可能是错误的,但实际的按位代码在几乎所有编程语言上都是通用的,我所看到的唯一区别是Visual Basic cc>在此处称为&
。
function WhatControlsPressed(controlsByte) {
var controlsPressed = " ";
if (controlsByte & 1) {
controlsPressed = controlsPressed + "up "
}
if (controlsByte & 2) {
controlsPressed = controlsPressed + "down "
}
if (controlsByte & 4) {
controlsPressed = controlsPressed + "left "
}
if (controlsByte & 8) {
controlsPressed = controlsPressed + "right "
}
if (controlsByte & 16) {
controlsPressed = controlsPressed + "a "
}
if (controlsByte & 32) {
controlsPressed = controlsPressed + "b "
}
if (controlsByte & 64) {
controlsPressed = controlsPressed + "select "
}
if (controlsByte & 128) {
controlsPressed = controlsPressed + "start "
}
return controlsPressed;
}
#DEFINE UP 1
#DEFINE DOWN 2
#DFFINE LEFT 4
#DEFINE RIGHT 8
AND
和
Up
所以您按下了
A
和
1
unsigned char ControlsPressed = 0;
ControlsPressed |= 1; //Pressed Up
ControlsPressed |= 16; //Pressed A
16
现在将保留数字
ControlsPressed
,您可能只是在想
17
这就是它的工作原理,但是是的,您无法将其恢复到基本值的原因首先使用基本数学。
1+16
更改为
17
,然后放开向上箭头并按住
16
按钮,就可以了。
A
=
1+4+16+128
149
现在如何取回密钥?好吧,这是很容易的,是的,就是开始减去最高的数字,您可以找到控件使用的最高数字,该数字低于
149
;如果您减去它的数值较大,那么它不会被按下。
ControlsPressed = ControlsPressed AND NOT (NEGATE) Number
ControlsPressed &= ~1; //Let go of Up key.
ControlsPressed &= ~16; //Let go of A key.
149
或
<<
,我真的不知道如何在基本层面上对此进行解释。
int SomeInteger = 123;
print SomeInteger >> 3;
SomeInteger = 123 / 8;
>>
与将值除以2的幂是一回事。
>>
在逻辑上意味着您将值乘以2的幂。
X: (0 to 63)
Y: (0 to 63)
<<
和
X
各自占用6位,而两者总共占用12位。
X | Y
int X = 33;
int Y = 11;
int packedValue1 = X << 6; //2112
int packedValue2 = Y << 6; //704
int finalPackedValue = packedValue1 + packedValue2; //2816
Y
2816
返回值,并在相反的方向进行相同的移位。
2816 >> 6 //Gives you back 44. lol.
2816
和
6
。
int packedValue1 = X << 6; //2112
int packedValue2 = Y << 12; //45056
int finalPackedValue = packedValue1 + packedValue2; //47168
47168 >> 12; //11
11 << 12; //45056
//47168 - 45056 = 2112
2112 >> 6; //33
int finalPackedValue = (X << 6) | (Y << 12);
关于c++ - 玩家移动时,GameBoy Advance对象未显示在正确的位置,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23718832/
我的一位教授给了我们一些考试练习题,其中一个问题类似于下面(伪代码): a.setColor(blue); b.setColor(red); a = b; b.setColor(purple); b
我似乎经常使用这个测试 if( object && object !== "null" && object !== "undefined" ){ doSomething(); } 在对象上,我
C# Object/object 是值类型还是引用类型? 我检查过它们可以保留引用,但是这个引用不能用于更改对象。 using System; class MyClass { public s
我在通过 AJAX 发送 json 时遇到问题。 var data = [{"name": "Will", "surname": "Smith", "age": "40"},{"name": "Wil
当我尝试访问我的 View 中的对象 {{result}} 时(我从 Express js 服务器发送该对象),它只显示 [object][object]有谁知道如何获取 JSON 格式的值吗? 这是
我有不同类型的数据(可能是字符串、整数......)。这是一个简单的例子: public static void main(String[] args) { before("one"); }
嗨,我是 json 和 javascript 的新手。 我在这个网站找到了使用json数据作为表格的方法。 我很好奇为什么当我尝试使用 json 数据作为表时,我得到 [Object,Object]
已关闭。此问题需要 debugging details 。目前不接受答案。 编辑问题以包含 desired behavior, a specific problem or error, and the
我听别人说 null == object 比 object == null check 例如: void m1(Object obj ) { if(null == obj) // Is thi
Match 对象 提供了对正则表达式匹配的只读属性的访问。 说明 Match 对象只能通过 RegExp 对象的 Execute 方法来创建,该方法实际上返回了 Match 对象的集合。所有的
Class 对象 使用 Class 语句创建的对象。提供了对类的各种事件的访问。 说明 不允许显式地将一个变量声明为 Class 类型。在 VBScript 的上下文中,“类对象”一词指的是用
Folder 对象 提供对文件夹所有属性的访问。 说明 以下代码举例说明如何获得 Folder 对象并查看它的属性: Function ShowDateCreated(f
File 对象 提供对文件的所有属性的访问。 说明 以下代码举例说明如何获得一个 File 对象并查看它的属性: Function ShowDateCreated(fil
Drive 对象 提供对磁盘驱动器或网络共享的属性的访问。 说明 以下代码举例说明如何使用 Drive 对象访问驱动器的属性: Function ShowFreeSpac
FileSystemObject 对象 提供对计算机文件系统的访问。 说明 以下代码举例说明如何使用 FileSystemObject 对象返回一个 TextStream 对象,此对象可以被读
我是 javascript OOP 的新手,我认为这是一个相对基本的问题,但我无法通过搜索网络找到任何帮助。我是否遗漏了什么,或者我只是以错误的方式解决了这个问题? 这是我的示例代码: functio
我可以很容易地创造出很多不同的对象。例如像这样: var myObject = { myFunction: function () { return ""; } };
function Person(fname, lname) { this.fname = fname, this.lname = lname, this.getName = function()
任何人都可以向我解释为什么下面的代码给出 (object, Object) 吗? (console.log(dope) 给出了它应该的内容,但在 JSON.stringify 和 JSON.parse
我正在尝试完成散点图 exercise来自免费代码营。然而,我现在只自己学习了 d3 几个小时,在遵循 lynda.com 的教程后,我一直在尝试确定如何在工具提示中显示特定数据。 This code
我是一名优秀的程序员,十分优秀!