- 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/
我找到了 this excellent question and answer它以 x/y(加上 center x/y 和 degrees/radians)开始并计算旋转- 到 x'/y'。这个计算很
全部: 我已经创建了一个 Windows 窗体和一个按钮。在另一个线程中,我试图更改按钮的文本,但它崩溃了;但是如果我尝试更改按钮的颜色,它肯定会成功。我认为如果您更改任何 Windows 窗体控件属
本网站的另一个问题已证实,C 中没有缩写的字面后缀,并且可以执行以下操作: short Number = (short)1; 但是转换它和不这样做有什么区别: short Number = 1; 您使
我有下表: ID (int) EMAIL (varchar(50)) CAMPAIGNID (int) isSubscribe (bit) isActionByUser (bit) 此表存储了用户对事
也就是说,无需触发Javascript事件即可改变的属性,如何保留我手动选中或取消选中的复选框的状态,然后复制到另一个地方? 运行下面的代码片段并选中或取消选中其中的一些,然后点击“复制”: $('#
我在网上找到的所有关于递增指针导致段错误的示例都涉及指针的取消引用 - 如果我只想递增它(例如在 for 循环的末尾)并且我不在乎它是否最终进入无效内存,因为我不会再使用它。例如,在这个程序中,每次迭
我有一个 Spring MVC REST 服务,它使用 XStream 将消息与 XML 相互转换。 有什么方法可以将请求和响应中的 xml(即正文)打印到普通的 log4j 记录器? 在 Contr
做我的任务有一个很大的挑战,那就是做相互依赖的任务我在这张照片中说的。假设我们有两个任务 A 和 B,执行子任务 A1、A2 和 B1、B2,假设任务 B 依赖于 A。 要理想地执行任务 B,您应该执
通过阅读该网站上的几个答案,我了解到 CoInitialize(Ex) should be called by the creator of a thread 。然后,在该线程中运行的任何代码都可以使
这个问题已经困扰我一段时间了。我以前从未真正使用过 ListViews,也没有使用过 FirebaseListAdapters。我想做的就是通过显示 id 和用户位置来启动列表的基础,但由于某种原因,
我很难解释这两个(看似简单)句子的含义: “受检异常由编译器在编译时检查” 这是什么意思?编译器检查是否捕获了所有已检查的异常(在代码中抛出)? “未经检查的异常在运行时检查,而不是编译时” 这句话中
我有一个包含排除子字符串的文本文件,我想迭代该文件以检查并返回不带排除子字符串的输入项。 这里我使用 python 2.4,因此下面的代码可以实现此目的,因为 with open 和 any 不起作用
Spring 的缓存框架能否了解请求上下文的身份验证状态,或者更容易推出自己的缓存解决方案? 最佳答案 尽管我发现这个用例 super 奇怪,但您可以为几乎任何与 SpEL 配合使用的内容设置缓存条件
我有以下函数模板: template HeldAs* duplicate(MostDerived *original, HeldAs *held) { // error checking omi
如果我的应用程序具有设备管理员/设备所有者权限(未获得 root 权限),我如何才能从我的应用程序中终止(或阻止启动)另一个应用程序? 最佳答案 设备所有者可以阻止应用程序: DevicePolicy
非常简单的问题,但我似乎无法让它正常工作。 我有一个组件,其中有一些 XSLT(用于导航)。它通过 XSLT TBB 使用 XSLT Mediator 发布。 发布后
我正在将一个对象拖动到一个可拖放的对象内,该对象也是可拖动的。放置对象后,它会嵌套在可放置对象内。同样,如果我将对象拖到可放置的外部,它就不再嵌套。 但是,如果我经常拖入和拖出可放置对象,则可拖动对象
我正在尝试为按钮和弹出窗口等多个指令实现“取消选择”功能。也就是说,我希望当用户单击不属于指令模板一部分的元素时触发我的函数。目前,我正在使用以下 JQuery 代码: $('body').click
我从 this question 得到了下面的代码,该脚本用于在 Google tasks 上更改 iframe[src="about:blank"] 内的 CSS使用 Chrome 扩展 Tempe
我有一些 @Mock 对象,但没有指定在该对象上调用方法的返回值。该方法返回 int (不是 Integer)。我很惊讶地发现 Mockito 没有抛出 NPE 并返回 0。这是预期的行为吗? 例如:
我是一名优秀的程序员,十分优秀!