Homework #6 : Continuous WorldsC/C++

Java Python Homework #6 : Continuous Worlds

Upgrading movement, collisions, and performance as we leave grids behind

While a storied and successful approach (surviving today in games such as Civ 5 -left), grid-based scenes don’t represent the vast majority of digital worlds. We will need to leave behind the simple collision detection and movement logic of previous homeworks to embrace a more continuous approach to our worlds (right).

Pitch

Homework #6 : Continuous Worlds introduces students to a handful of additional 2D concepts, such as camera zoom, precise / continuous collisions, basic animation, smooth movement, and performance improvements as  we distance ourselves from the grid-based scene structure that has thus-far defi ned our engines.

Purpose

This assignment will--

● Upgrade our scenes from a grid-based approach to a continuous approach (movement / collisions).

● Introduce additional rendering features such as camera zoom levels.

● Introduce basic math-based actor animation.

● Introduce the concept of an Input Manager.

● Introduce the concept of customizable collision volumes and AABB collision checking.

● Require a more sophisticated consideration of rendering / collision detection performance.

Tasks

Study the Autograder and Assignment Submission Process

● Autograder General Guide

○ Windows / Visual Studio Guide

○ OSX / XCode Guide

○ Make Guide

Test-Driven Development

Each of the following test suites has a particular focus, and requires the implementation of particular features. You are recommended to clear all test cases in a given suite before proceeding to the next. If you break an older feature or introduce a bug, you may rely on older test suites to warn you of such regressions

(You may read about test-driven development, and why it features heavily in industry, here).

Test Suite #0 : Camera Zoom

This suite contains basic tests exercising your engine’s ability to provide zoom-related rendering functionality. Zoom can allow designers to better present their scenes to players while striking a cinematic tone.

1. rendering.config may now contain a property (double data type) called zoom_factor

a. When not defined, assume zoom_factor is 1

b. Utilize the SDL_RenderSetScale() function to scale all actors in a scene.

i. 2.0 means double their size.

ii. 0.5 means half their size (allowing us to show more actors with less visual noise).

c. UI elements (health icon, text, etc) must not be impacted by zoom_factor.

2. When a zoom occurs, it must maintain the rendering positions of all actors in the scene.

a. For example, a zoom of 0.5 should result in something like this, rather than this.

b. Warning : Avoid off-by-one-pixel errors. When calculating the x and y values of your final SDL_Rect (destination rect) for each actor, please wrap your entire calculation in std::round() and then cast this result via static_cast().

Test Suite #1 : Continuous Movement

This suite contains basic tests exercising your engine’s ability to support continuous movement of actors in response to (ideally) a convenient InputManager system.

Style. Suggestions

● As discussed in class, consider creating an Input.h/.cpp that provides convenient APIs.

○ Input::GetKey(), Input::GetKeyDown(), Input::GetKeyUp(), etc

○ Here’s a sample .h file you might consider starting with.

Tasks

1. For every frame. the player holds down a direction, they will move 0.02 scene units in that direction.

a. (ie, move them (0.02) scene units in response to arrow keys and WASD).

b. Note : If you’ve been representing actor positions and/or velocities via glm::ivec2 or some integer type, please switch to a fractional type (I recommend glm::vec2)

c. Note : Please normalize your movement vector.

i. ie, moving diagonally should not achieve greater speed than moving horizontally.

ii. Consider using glm::normalize()

1. (but be careful not to call it on the zero (0,0) vector)

2. If a player_movement_speed value is configured in game.config…

a. Travel this distance for every frame. a directional key (including WASD) is held down.

b. The default value should be considered to be 0.02

3. NPC actors should now update / move according to their vel_x and vel_y values every frame.

a. (recall that previously, they updated every 60th frame)

4. Upgrade your render ordering

a. Render ordering is still based on y position unless the render_order is specified.

b. If there are still ties, break them with actor_id

Test Suite #2 : Camera Easing

This suite contains basic tests exercising your engine’s ability to smoothly move the camera, providing improved cinematic style.

1. Thus far, we have made the camera instantaneously “jump” to the position of the player each frame.

a. (“position” here includes the cam_offset property if it is configured).

2. rendering.config may now contain a cam_ease_factor float property. If so…

a. When not defined, assume cam_ease_factor is 1

b. Every frame, after updating all actors, update the camera’s location with a smooth ease.

i. Jump cam_ease_factor of the way from cam’s current position to the player pos.

ii. Consider using new_cam_pos = glm::mix(current_cam_pos, player_current_pos, cam_ease_factor);

c. Example when cam_ease_factor is 0.05f

Test Suite #3 : Animation

This suite contains basic tests exercising your engine’s ability to support basic sprite-based animation, bringing personality and charm to a game’s actors.

1. If x_scale_actor_flipping_on_movement exists in rendering.config and is true…

a. The x component of the actor’s scale changes based on an actor’s intent to move.

i. If the actor attempts to move east, the x component should become positive (regardless of its original value).

ii. If the actor attempts to move west, the x component should become negative (regardless of its original value.

b. This results in actors looking in the direction they are moving– a charismatic result.

2. In addition to a view_image property, actors may have a view_image_back configured.

a. When the actor moves upwards, this image shows. It reverts back upon moving downwards.

b. This results in actors facing away from the camera when walking away from it.

c. Note: Do not reset the actor’s image or orientation when the actor stops moving

d. Note: Only calculate the pivot point with respect to view_image not other images.

3. If an actor has a movement_bounce_enabled property, and it is true…

a. When moving, the final rendering position of the actor will be offset (in pixels) by (0,-abs(sin(current_frame. * 0.15)) * 10.0)

b. Consider using glm::abs(), glm::sin(), and Helper::GetFrameNumber()

c. The result is a South Park-style. hopping animation that brings even singular frames to life.

Test Suite #4 : Continuous Collision and Damage

This suite contains basic tests exercising your engine’s ability to support customizable collision volumes.

1. Up to now, collisions have used the tile-based approach from previous homew Homework #6 : Continuous WorldsC/C++ orks. This is no longer suitable for us as we move away from grids and into a continuous world.

a. The blocking actor property no longer exists.

2. Two new actor properties are now available. If both are configured, the actor is considered “blocking”.

a. box_collider_width : Determines the width of the collider box in scene units (float)

b. box_collider_height : Determines the height of the collider box in scene units (float)

c. Note: The colliders are centered at the actor’s position, and thus your collision implementation must compute the extents of the collider (i.e. the top, left, right, and bottom)

d. Example– if the player actor does not have these properties configured, no collision is possible

e. Note : NPCs may now collide with the player (and reverse) if player has a collider configured.

3. If an actor attempts to move, and this movement makes their collider intersect another collider…

a. Reset movement (ie, don’t move this frame– the actor has been blocked).

i. If the actor is an npc and has a velocity, invert that velocity.

b. Note : two colliders that share a border exactly are not considered colliding / overlapping.

4. If the player actor collides with an actor holding a contact_dialogue then process any associated commands (but don’t render the dialogue text).

a. (The text would otherwise only be visible for one frame. Nasty.).

5. When an actor collides with another actor, both actors should immediately “know about” that collision happening and respond to it when it becomes their turn to update.

a. IE, if an npc walks into the player actor when the player isn’t moving, the player actor should still have contact dialogue triggered sometime that frame.

b. IE, if one moving npc walks into another moving npc, both should not move that frame. and both should invert their velocities.

i. Recommendation : Keep a “colliding_actors_this_frame” unordered_map and when you detect a collision, add yourself to the other actor’s container and add the other actor to yours. Make decisions based on the contents of this container before clearing it at the end of the frame.

6. What to do about the nearby_dialogue property?

a. A “trigger” (a collision-less collider) may be configured just like the above box collider.

b. If the player actor’s box trigger overlaps with another actor’s box trigger…

i. Process the other actor’s nearby_dialogue (commands) and render the text too.

7. Similar to the box_collider, an actor’s box_trigger may be customized--

a. box_trigger_width : Determines the width of the trigger box in scene units (float)

b. box_trigger_height : Determines the height of the trigger box in scene units (float)

c. If one or both properties are missing, no trigger collisions may occur.

8. If the player actor’s box collider overlaps with another actor’s trigger, and that actor has nearby_dialogue then process its associated commands (and do render this dialogue).

9. The transform_scale_x and transform_scale_y properties impact collider / trigger sizes.

10. A new property, view_image_damage, may be configured on a player actor.

a. When available, this sprite will be rendered for 30 frames upon receiving damage.

11. A new property, view_image_attack, may be configured on a non-player actor.

a. When available, this sprite will be rendered for 30 frames upon dealing damage to the player.

Test Suite #5 : Gameplay Sound Effects

This suite contains basic tests exercising your engine’s ability to play gameplay-related sound effects using dedicated sfx channels. Like other gameplay-related features in this assignment, we will seek to externalize (move out of c++) these features soon.

Style. Suggestions

● A dedicated file / system for managing audio / caching / initialization may be useful here.

○ The staff solution uses a pleasant AudioDB class to make playing audio easy anywhere.

1. To introduce new sfx we need to use audio channels other than 0 (already used for music / BGM).

a. 8 channels are valid by default. Increase channels to 50 via

Mix_AllocateChannels498()

i. (Many channels reduces our odds of having a sound cut off when another one plays)

ii. (Mix_OpenAudio has a channels param, but this refers to mono vs stereo)

2. A new property, score_sfx, may be configured in game.config

a. Played on the frame. in which the player’s score increases.

b. Channel : 1

3. A new property, damage_sfx, may be configured on the player actor.

a. Played on the frame. in which the player actor takes damage (no looping).

b. Channel : (current_frame) % 48 + 2

i. (the +2 prevents us from clobbering channel 0 or 1)

4. A new property, step_sfx, may be configured on the player actor.

a. This file will play on (without looping) on every 20th frame. if the actor is moving.

i. (use Helper::GetFrameNumber() % 20 == 0 to perform. the check)

b. Channel : (current_frame) % 48 + 2

5. A new property, nearby_dialogue_sfx, may be configured on an npc actor.

a. Played on the first frame. in which nearby_dialogue is processed (no looping).

i. (do not repeat the sound if the nearby_dialogue is triggered again).

b. Channel : (current_frame) % 48 + 2

Test Suite #6 : Integration and Performance Tests

This suite contains large, advanced tests that stress your engine’s correctness and performance.

Notes on Performance

● We made heavy use of Visual Studio performance profiling to determine opportunities for optimization.

● The single most critical performance consideration in this assignment relates to collision detection.

○ How can we identify overlapping actors without resorting to an O(n²) solution?

■ (ie, we don’t want to check every other actor to determine if one actor is colliding).

○ The staff solution employs a region-based spatial hashing approach.

■ IE, don’t check every actor. Just check actors in the same small “region” as you.

■ Hint : The smaller the regions are, the fewer actors we need to check for collisions.

● Q : How large should the regions be?

● Hint : Actors do not have a way of changing their collider / trigger size or scale.

○ (in this homework, that is…)

○ (constraints like this make engines less general, but enable high speed).

○ Hint : Colliders and Triggers are two different categories of collision.

■ Triggers tend to be much larger than colliders (the latter typically aimed at matching the visuals of a character, while the former surrounds a character to initiate things like dialogue).

○ The staff solution only ever modifies the spatial hashing structure when actors move between regions, and only adds/removes actors from those regions

● The staff solution engages in significant caching, trading memory for speed.

○ When rendering text, all SDL_Texture objects are cached and re-used once created.

○ When loading images, all SDL_Texture objects are cached and re-used once created.

○ When loading audio, all Mix_Chunk objects are cached and re-used once created.

● The staff solution refrains from rendering actors that are not visible to the camera.

● The staff solution refrains from sorting things that don’t need sorting.

Reflections

While you wait for the autograder to check your work and email your results, consider the following ideas–

● Four weeks into your engine– the same codebase week-after-week– how do you feel about it? Do parts feel messy and “fragile”? Do you feel parts are well-written and easy to reason about / extend?

● In this assignment the engine does not allow actors to resize their collider / trigger boxes, nor does it allow actors to be created during a scene. Constraints like these limit the expressiveness of an engine         

你遇到的错误是因为你使用了 **不兼容的 libubus 版本** 或 **OpenWrt SDK 版本太老(15.05.1)**,导致 `struct ubus_object_ops` 和 `UBUS_OBJECT_NO_INSTANCE()` 宏在你的环境中 **不存在** 或 **结构不匹配**。 --- ## 🚫 错误分析 你遇到的三个错误分别对应: ### 1. `incomplete type "const struct ubus_object_ops" is not allowed` - 表示编译器不认识 `struct ubus_object_ops`,说明你使用的 `libubus` 头文件中没有定义这个结构体。 - 这是因为在 **OpenWrt 15.05.1 中的 libubus 版本非常旧(约 2015 年)**,它没有引入 `ubus_object_ops` 这个结构。 ### 2. `function call is not allowed in a constant expression` - `UBUS_OBJECT_NO_INSTANCE("data_service")` 是一个宏,但在你的环境中它可能包含函数调用或不适用于静态初始化。 ### 3. `struct "ubus_object" has no field "ops"` - 说明你当前的 `struct ubus_object` 定义中没有 `ops` 字段,而是使用了 `methods` 和 `n_methods`,这是老版本 libubus 的结构。 --- ## ✅ 正确适配 OpenWrt 15.05.1 的做法 你必须使用 **libubus 的老版本 API**,即 OpenWrt 15.05.1 所支持的 API。 ### ✅ 修改后的代码如下: ```c #include <libubus.h> #include <libubox/blobmsg_json.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <time.h> #include "crc32.h" /* 定义全局 ubus 上下文指针 */ static struct ubus_context *ctx; /* 新增:定义 blobmsg_policy 策略表 */ static const struct blobmsg_policy policy[] = { [0] = { .name = "data", .type = BLOBMSG_TYPE_STRING }, [1] = { .name = "crc", .type = BLOBMSG_TYPE_INT32 }, [2] = { .name = "seq", .type = BLOBMSG_TYPE_INT32 }, }; /* ubus 方法回调函数, 处理客户端发送的数据 */ static int receive_data(struct ubus_context *ctx, struct ubus_object *obj, struct ubus_request_data *req, const char *method, struct blob_attr *msg) { struct blob_attr *tb[3]; blobmsg_parse(policy, 3, tb, blob_data(msg), blob_len(msg)); if (!tb[0] || !tb[1] || !tb[2]) { fprintf(stderr, "Missing data in message\n"); return -1; } const char *data = blobmsg_get_string(tb[0]); size_t data_len = strlen(data); uint32_t expected_crc = blobmsg_get_u32(tb[1]); int seq = blobmsg_get_u32(tb[2]); uint32_t actual_crc = crc32(data, data_len); int is_valid = (actual_crc == expected_crc); time_t now = time(NULL); printf("[%ld] B: Received seq=%d, size=%zu, CRC %s\n", now, seq, data_len, is_valid ? "OK" : "FAILED"); struct blob_buf b; blob_buf_init(&b, 0); blobmsg_add_u32(&b, "seq", seq); blobmsg_add_u32(&b, "valid", is_valid); blobmsg_add_u32(&b, "actual_crc", actual_crc); ubus_send_reply(ctx, req, b.head); blob_buf_free(&b); return 0; } /* 定义方法名 send_data, 绑定到 receive_data 函数 */ static const struct ubus_method hello_methods[] = { UBUS_METHOD("send_data", receive_data, policy), }; /* 定义对象类型 */ static struct ubus_object_type hello_obj_type = UBUS_OBJECT_TYPE("hello_object", hello_methods); /* 适配 OpenWrt 15.05.1 的老版本 libubus */ static struct ubus_object hello_obj = { .name = "data_service", .type = &hello_obj_type, .methods = hello_methods, .n_methods = ARRAY_SIZE(hello_methods), }; int main(int argc, char **argv) { int ret; ctx = ubus_connect(NULL); if (!ctx) { fprintf(stderr, "Failed to connect to ubus\n"); return -1; } ret = ubus_add_object(ctx, &hello_obj); if (ret) { fprintf(stderr, "Failed to add ubus object\n"); goto out; } uloop_init(); printf("Server is running...\n"); while (1) { uloop_run(); } out: ubus_free(ctx); return ret; } ``` --- ## ✅ 总结修改点 | 问题 | 原因 | 修改方式 | |------|------|----------| | 使用 `UBUS_OBJECT_NO_INSTANCE` 和 `ops` 字段 | 不兼容 OpenWrt 15.05.1 的 libubus | 改为使用 `methods` 和 `n_methods` 字段 | | 使用宏初始化对象失败 | 宏依赖新版 API | 改为手动初始化 `struct ubus_object` | | 编译器提示结构体不完整 | 头文件版本过旧 | 不使用新版 API,适配老版本结构 | --- ## ✅ 推荐升级建议(可选) 如果你有条件,建议升级到较新的 OpenWrt 版本(如 18.06 或 21.02),这样你可以使用新版的 `libubus`,它支持: - `ubus_object_ops` - 更完整的 API 支持 - 更好的兼容性 ---
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值