我在一个嵌入式系统上用C语言制作了一个月球登陆器游戏,我们有一个相当简单的运动矢量。它还没有完成,但是我遇到了一个问题,登陆器本身的运动看起来很不稳定,我相信这是因为我使用的显示驱动程序只允许传入int,以便绘图。
我现在的逻辑是给盒子的位置加上一个速度值,每一个滴答声本质上就是给加速度加上一个加速度常数,加速度常数加到加到盒子的位置上,这使得重力可以不断地把盒子拉下来,同时也使得垂直和水平推力可以根据cos和sin值加上,cos和sin值是从着陆器的Angular 计算出来的。
这里有一个链接到我的系统(很抱歉质量很差,我从来没有发布到YouTube)https://youtube.com/shorts/NVvTxVoZjY4
所有的代码是非常大的,但我会张贴部分,我认为是相关的。
#include "game_control.h"
#include "buttons.h"
#include "display.h"
#include "stdio.h"
#include "lander.h"
#define THRUST_SCALER 0.3
int16_t x0 = -10;
int16_t y_point0 = 0;
int16_t x1 = 0;
int16_t y_point1 = 0;
int16_t x2 = 0;
int16_t y2 = 10;
int16_t x3 = -10;
int16_t y3 = 10;
int16_t x_origin = 0;
int16_t y_origin = 120;
#define gravity 0.05
double y_velocity = 0.9;
double x_velocity = 1;
bool tick_is_odd = true;
int8_t tick_fourth = 0;
int8_t rotate = 0;
double thrust_x = 0.;
double thrust_y = 0.;
struct lander_t the_lander;
void map1() {
display_drawLine(0, 240, 100, 200, DISPLAY_WHITE);
display_drawLine(100, 200, 160, 220, DISPLAY_WHITE);
display_drawLine(160, 220, 190, 220, DISPLAY_DARK_YELLOW);
display_drawLine(190, 220, 300, 160, DISPLAY_WHITE);
display_drawLine(300, 160, 320, 240, DISPLAY_WHITE);
}
// Tick the game control logic
//
// This function should tick the lander and check for wins on the game
void gameControl_tick() {
uint8_t button_value = buttons_read();
printf("vertical velocity: %f\n", y_velocity);
printf("horizontal velocity: %f\n\n", x_velocity);
if((button_value & BUTTONS_BTN0_MASK) == BUTTONS_BTN0_MASK){
lean_right(&the_lander);
} else if ((button_value & BUTTONS_BTN3_MASK) == BUTTONS_BTN3_MASK){
lean_left(&the_lander);
}
//testing rotations given preset rotation values
if (y_point0 <= 230) {
display_drawLine(x0, y_point0, x1, y_point1, DISPLAY_BLACK);
display_drawLine(x1, y_point1, x2, y2, DISPLAY_BLACK);
display_drawLine(x2, y2, x3, y3, DISPLAY_BLACK);
display_drawLine(x3, y3, x0, y_point0, DISPLAY_BLACK);
display_drawPixel(x0, y_point0, DISPLAY_BLACK);
y_point0 = y_point0 + (int)y_velocity;
y_point1 = y_point1 + (int)y_velocity;
y2 = y2 + (int)y_velocity;
y3 = y3 + (int)y_velocity;
x0 = x0 + x_velocity;
x1 = x1 + x_velocity;
x2 = x2 + x_velocity;
x3 = x3 + x_velocity;
if (tick_fourth == 1) {
tick_fourth = 0;
// if statements to turn left
if (((button_value & BUTTONS_BTN0_MASK) == BUTTONS_BTN0_MASK) &&
(rotate == 0)) {
x0 = x0 + 3;
y_point0 = y_point0 - 1;
x1 = x1 + 1;
y_point1 = y_point1 + 3;
x2 = x2 - 3;
y2 = y2 + 1;
x3 = x3 - 1;
y3 = y3 - 3;
rotate++;
} else if (((button_value & BUTTONS_BTN0_MASK) == BUTTONS_BTN0_MASK) &&
(rotate == 1)) {
x0 = x0 + 2;
y_point0 = y_point0 - 1;
x1 = x1 + 1;
y_point1 = y_point1 + 2;
x2 = x2 - 2;
y2 = y2 + 1;
x3 = x3 - 1;
y3 = y3 - 2;
rotate++;
} else if (((button_value & BUTTONS_BTN0_MASK) == BUTTONS_BTN0_MASK) &&
(rotate == 2)) {
x0 = x0 + 2;
y_point0 = y_point0 + 1;
x1 = x1 - 1;
y_point1 = y_point1 + 2;
x2 = x2 - 2;
y2 = y2 - 1;
x3 = x3 + 1;
y3 = y3 - 2;
rotate++;
} else if (((button_value & BUTTONS_BTN0_MASK) == BUTTONS_BTN0_MASK) &&
(rotate == 3)) {
x0 = x0 + 3;
y_point0 = y_point0 + 1;
x1 = x1 - 1;
y_point1 = y_point1 + 3;
x2 = x2 - 3;
y2 = y2 - 1;
x3 = x3 + 1;
y3 = y3 - 3;
rotate++;
} else if (((button_value & BUTTONS_BTN0_MASK) == BUTTONS_BTN0_MASK) &&
(rotate == -1)) {
x0 = x0 + 1;
y_point0 = y_point0 - 3;
x1 = x1 + 3;
y_point1 = y_point1 + 1;
x2 = x2 - 1;
y2 = y2 + 3;
x3 = x3 - 3;
y3 = y3 - 1;
rotate++;
} else if (((button_value & BUTTONS_BTN0_MASK) == BUTTONS_BTN0_MASK) &&
(rotate == -2)) {
x0 = x0 + 1;
y_point0 = y_point0 - 2;
x1 = x1 + 2;
y_point1 = y_point1 + 1;
x2 = x2 - 1;
y2 = y2 + 2;
x3 = x3 - 2;
y3 = y3 - 1;
rotate++;
} else if (((button_value & BUTTONS_BTN0_MASK) == BUTTONS_BTN0_MASK) &&
(rotate == -3)) {
x0 = x0 - 1;
y_point0 = y_point0 - 2;
x1 = x1 + 2;
y_point1 = y_point1 - 1;
x2 = x2 + 1;
y2 = y2 + 2;
x3 = x3 - 2;
y3 = y3 + 1;
rotate++;
} else if (((button_value & BUTTONS_BTN0_MASK) == BUTTONS_BTN0_MASK) &&
(rotate == -4)) {
x0 = x0 - 1;
y_point0 = y_point0 - 3;
x1 = x1 + 3;
y_point1 = y_point1 - 1;
x2 = x2 + 1;
y2 = y2 + 3;
x3 = x3 - 3;
y3 = y3 + 1;
rotate++;
}
// turn right calculations:
else if (((button_value & BUTTONS_BTN3_MASK) == BUTTONS_BTN3_MASK) &&
(rotate == 1)) {
x0 = x0 - 3;
y_point0 = y_point0 + 1;
x1 = x1 - 1;
y_point1 = y_point1 - 3;
x2 = x2 + 3;
y2 = y2 - 1;
x3 = x3 + 1;
y3 = y3 + 3;
rotate--;
} else if (((button_value & BUTTONS_BTN3_MASK) == BUTTONS_BTN3_MASK) &&
(rotate == 2)) {
x0 = x0 - 2;
y_point0 = y_point0 + 1;
x1 = x1 - 1;
y_point1 = y_point1 - 2;
x2 = x2 + 2;
y2 = y2 - 1;
x3 = x3 + 1;
y3 = y3 + 2;
rotate--;
} else if (((button_value & BUTTONS_BTN3_MASK) == BUTTONS_BTN3_MASK) &&
(rotate == 3)) {
x0 = x0 - 2;
y_point0 = y_point0 - 1;
x1 = x1 + 1;
y_point1 = y_point1 - 2;
x2 = x2 + 2;
y2 = y2 + 1;
x3 = x3 - 1;
y3 = y3 + 2;
rotate--;
} else if (((button_value & BUTTONS_BTN3_MASK) == BUTTONS_BTN3_MASK) &&
(rotate == 4)) {
x0 = x0 - 3;
y_point0 = y_point0 - 1;
x1 = x1 + 1;
y_point1 = y_point1 - 3;
x2 = x2 + 3;
y2 = y2 + 1;
x3 = x3 - 1;
y3 = y3 + 3;
rotate--;
} else if (((button_value & BUTTONS_BTN3_MASK) == BUTTONS_BTN3_MASK) &&
(rotate == 0)) {
x0 = x0 - 1;
y_point0 = y_point0 + 3;
x1 = x1 - 3;
y_point1 = y_point1 - 1;
x2 = x2 + 1;
y2 = y2 - 3;
x3 = x3 + 3;
y3 = y3 + 1;
rotate--;
} else if (((button_value & BUTTONS_BTN3_MASK) == BUTTONS_BTN3_MASK) &&
(rotate == -1)) {
x0 = x0 - 1;
y_point0 = y_point0 + 2;
x1 = x1 - 2;
y_point1 = y_point1 - 1;
x2 = x2 + 1;
y2 = y2 - 2;
x3 = x3 + 2;
y3 = y3 + 1;
rotate--;
} else if (((button_value & BUTTONS_BTN3_MASK) == BUTTONS_BTN3_MASK) &&
(rotate == -2)) {
x0 = x0 + 1;
y_point0 = y_point0 + 2;
x1 = x1 - 2;
y_point1 = y_point1 + 1;
x2 = x2 - 1;
y2 = y2 - 2;
x3 = x3 + 2;
y3 = y3 - 1;
rotate--;
} else if (((button_value & BUTTONS_BTN3_MASK) == BUTTONS_BTN3_MASK) &&
(rotate == -3)) {
x0 = x0 + 1;
y_point0 = y_point0 + 3;
x1 = x1 - 3;
y_point1 = y_point1 + 1;
x2 = x2 - 1;
y2 = y2 - 3;
x3 = x3 + 3;
y3 = y3 - 1;
rotate--;
}
}
display_drawLine(x0, y_point0, x1, y_point1, DISPLAY_CYAN);
display_drawLine(x1, y_point1, x2, y2, DISPLAY_CYAN);
display_drawLine(x2, y2, x3, y3, DISPLAY_CYAN);
display_drawLine(x3, y3, x0, y_point0, DISPLAY_CYAN);
display_drawPixel(x0, y_point0, DISPLAY_YELLOW);
//this is where the velocities are actually being incremented given the calculated thrust values.
y_velocity = y_velocity + gravity - (THRUST_SCALER *thrust_y);
x_velocity = x_velocity + (THRUST_SCALER * thrust_x);
}
//change thrust value if button 1 is being pressed
if((button_value & BUTTONS_BTN1_MASK) == BUTTONS_BTN1_MASK){
thrust_x = get_thrust_x(&the_lander);
thrust_y = get_thrust_y(&the_lander);
} else {
thrust_x = 0;
thrust_y = 0;
}
tick_is_odd = !tick_is_odd;
tick_fourth++;
}
请原谅糟糕的编码实践,我还在测试概念。
这是着陆器的结构是如何实现的。
void lander_init(struct lander_t *lander){
lander->angle = 90;
//there going to be more values here, location etc, but I haven't implemented them yet.
}
这是推力和Angular 的计算方法。
static double cos_degrees(double theta){
//convert radians to degrees
theta = theta * (3.14 / 180);
// printf("cos_degrees %f\n", cos(theta));
return cos(theta);
}
static double sin_degrees(double theta){
//convert radians to degrees
theta = theta * (3.14 / 180);
// printf("sin_degrees %f\n", sin(theta));
return sin(theta);
}
//calculates the x and y thrust values given the current angle
double get_thrust_y(struct lander_t *lander){
return sin_degrees(lander->angle);
}
double get_thrust_x(struct lander_t *lander){
return cos_degrees(lander->angle);
}
//increment the angle
void lean_left(struct lander_t *lander){
if(lander->angle < 180){
lander->angle += 10;
}
}
//decrement the angle
void lean_right(struct lander_t *lander){
if(lander->angle > 0){
lander->angle -= 10;
}
}
任何建议都将不胜感激!谢谢你的帮助!还有人遇到过类似的问题吗,他们在这样的屏幕上的加速度总是离散的?
下面是我正在使用的显示驱动程序的github链接。https://github.com/byu-cpe/ecen330_student/blob/main/include/display.h
我试过改变游戏的滴答速度,试图让它不那么明显,但我不满意。
我在想,我可以创建一些帮助绘图的函数,它可以接受当前的加速度或速度值,并以某种方式将它们绘制得更平滑,但我还没有能够想清楚它是如何工作的。
1条答案
按热度按时间6tdlim6h1#
我可以通过改变控制游戏的状态机的频率来减慢移动速度。所以对于0到1之间的速度,我可以通过每4次、每3次或每隔1次等等来创建3个速度。这让我可以让移动速度更慢,看起来更像模拟,而不是总是添加离散像素。因为你仍然添加了一个像素的位置,但你只添加了一半的频率,而不是试图增加每一次。
如果有什么不明白的地方或者其他人有其他问题,请告诉我。