ASSISTANT
Creating a 2D survival game in GameMaker involves several key systems, including resource collection, hunger management, and building mechanics. Below, I’ll guide you through implementing these features with detailed instructions and sample GML (GameMaker Language) code snippets. This guide assumes you have a basic understanding of GameMaker Studio's interface and fundamental concepts.
## Table of Contents
1. [Project Setup](#project-setup)
2. [Player Object](#player-object)
3. [Resource Collection](#resource-collection)
4. [Inventory System](#inventory-system)
5. [Hunger System](#hunger-system)
6. [Building Walls and Doors](#building-walls-and-doors)
7. [User Interface (UI)](#user-interface-ui)
8. [Additional Considerations](#additional-considerations)
---
## Project Setup
1. **Create a New Project:**
- Open GameMaker Studio and create a new project (GameMaker Language).
2. **Assets:**
- Prepare or import sprites for the player, resources (e.g., wood), walls, doors, and UI elements.
- Organize your assets in folders for better management (e.g., `Sprites`, `Objects`, `Scripts`, `Rooms`).
3. **Rooms:**
- Create a main game room where the gameplay will take place.
---
## Player Object
### Step 1: Create the Player Sprite and Object
1. **Sprite:**
- Create a sprite named `spr_player`.
2. **Object:**
- Create an object named `obj_player` and assign `spr_player` to it.
- Enable collision mask as needed (e.g., rectangle or precise).
### Step 2: Player Movement
Implement basic movement for the player.
**Create Event:**
```gml
// Player Variables
hsp = 0; // Horizontal speed
vsp = 0; // Vertical speed
speed = 4; // Movement speed
```
**Step Event:**
```gml
// Horizontal Movement
hsp = 0;
if (keyboard_check(vk_right) || keyboard_check(ord('D'))) {
hsp = speed;
}
if (keyboard_check(vk_left) || keyboard_check(ord('A'))) {
hsp = -speed;
}
// Vertical Movement
vsp = 0;
if (keyboard_check(vk_down) || keyboard_check(ord('S'))) {
vsp = speed;
}
if (keyboard_check(vk_up) || keyboard_check(ord('W'))) {
vsp = -speed;
}
// Collision Handling (Optional)
var collision_x = place_meeting(x + hsp, y, obj_wall);
if (!collision_x) {
x += hsp;
}
var collision_y = place_meeting(x, y + vsp, obj_wall);
if (!collision_y) {
y += vsp;
}
```
**Draw Event:**
```gml
draw_self();
// Additional drawing (e.g., inventory indicators) can be added here
```
---
## Resource Collection
### Step 1: Create Resource Objects
1. **Sprite:**
- Create a sprite named `spr_wood`.
2. **Object:**
- Create an object named `obj_wood` and assign `spr_wood` to it.
- Ensure `obj_wood` has a `Solid` or `Collectible` property as needed.
### Step 2: Spawning Resources
You can place `obj_wood` objects manually in the room or create a spawning system.
**Example: Manual Placement**
- Drag and drop instances of `obj_wood` into the room where you want them to appear.
### Step 3: Collecting Resources
Implement interaction when the player collides with a resource.
**Player Object (`obj_player`) - Step Event:**
```gml
// Existing movement code...
// Resource Collection
if (keyboard_check_pressed(vk_space)) { // Define a key for interaction
var resource = instance_nearest(x, y, obj_wood);
var collect_distance = 32; // Adjust as needed
if (distance_to_object(resource) < collect_distance) {
// Add wood to inventory
global.inventory.wood += 1;
// Destroy the resource
instance_destroy(resource);
}
}
```
**Note:** This example assumes a simple proximity-based collection. You might want to add animations or sounds for better feedback.
---
## Inventory System
Managing resources requires an inventory system.
### Step 1: Initialize Inventory
Use a global script or an initialization step to set up the inventory. Here, I'll use a `Game Start` event.
**Controller Object (`obj_controller`)**
1. **Create a Controller Object:**
- Create an object named `obj_controller` and place it in the first room.
2. **Create Event:**
```gml
// Initialize Global Inventory
global.inventory = {
wood: 0,
// Add other resources as needed
};
```
### Step 2: Display Inventory
Create a simple UI to display inventory counts.
**UI Object (`obj_ui`)**
1. **Create a UI Object:**
- Create an object named `obj_ui` and place it in the room.
2. **Draw Event:**
```gml
var wood_text = "Wood: " + string(global.inventory.wood);
draw_text(10, 10, wood_text);
// Add additional inventory items as needed
```
---
## Hunger System
Implementing a hunger mechanic requires tracking the player's hunger level over time and allowing them to consume food to replenish it.
### Step 1: Add Hunger Variables
**Player Object (`obj_player`) - Create Event:**
```gml
// Existing variables...
hunger = 100; // Max hunger
hunger_decrement = 0.1; // Hunger decrease per step
```
### Step 2: Decrease Hunger Over Time
**Player Object (`obj_player`) - Step Event:**
```gml
// Existing movement and collection code...
// Decrease Hunger
hunger -= hunger_decrement * delta_time / 1000000; // Adjust based on frame rate
hunger = clamp(hunger, 0, 100);
// Handle Player Starvation
if (hunger <= 0) {
// Implement consequences, e.g., damage over time, game over
// Example: Damage the player
hp -= 1; // Assuming you have a hp variable
if (hp <= 0) {
// Handle player death
instance_destroy();
// Optionally, change to a game over room
}
}
// Eating Food
if (keyboard_check_pressed(ord('E'))) { // Define a key for eating
if (global.inventory.food > 0) { // Assuming you have a food item
global.inventory.food -= 1;
hunger += 20; // Adjust the amount to replenish
hunger = clamp(hunger, 0, 100);
}
}
```
### Step 3: Add Food Resource
Repeat the resource collection steps to include food (e.g., berries, meat).
---
## Building Walls and Doors
Creating a building mechanic allows players to construct structures using collected resources.
### Step 1: Create Wall and Door Objects
1. **Sprites:**
- Create `spr_wall` and `spr_door`.
2. **Objects:**
- Create `obj_wall` and `obj_door`, assign respective sprites.
- Ensure these objects have collision properties if necessary.
### Step 2: Building Interface
Implement a system to place walls and doors in the game world.
**Player Object (`obj_player`) - Step Event:**
```gml
// Existing code...
// Building Mode Toggle
if (keyboard_check_pressed(ord('B'))) { // Define a key to toggle building mode
building_mode = !building_mode;
}
// Building Mode Behavior
if (building_mode) {
// Display placement preview
var grid_size = 32; // Adjust based on your game grid
var snap_x = grid_size * floor(x / grid_size);
var snap_y = grid_size * floor(y / grid_size);
draw_sprite_ext(spr_wall_preview, 0, snap_x, snap_y, 1, 1, 0, c_white, 0.5); // Semi-transparent preview
// Place wall or door
if (mouse_check_button_pressed(mb_left)) {
// Example: Place wall
if (global.inventory.wood >= 1) { // Check resource
instance_create_layer(snap_x, snap_y, "Instances", obj_wall);
global.inventory.wood -= 1;
}
}
if (mouse_check_button_pressed(mb_right)) {
// Example: Place door
if (global.inventory.wood >= 2) { // Doors might require more resources
instance_create_layer(snap_x, snap_y, "Instances", obj_door);
global.inventory.wood -= 2;
}
}
}
```
**Notes:**
- **Building Mode Toggle:** Players can enter and exit building mode using a specific key (e.g., 'B').
- **Placement Preview:** Provide visual feedback (e.g., semi-transparent sprite) to indicate where the structure will be placed.
- **Resource Check:** Ensure the player has enough resources before placing structures.
- **Grid System:** Snap placement to a grid for organized building.
### Step 3: Implement Grid Snapping
Ensure all placed objects align to the game grid.
**Helper Script (`scr_snap_to_grid`)**
Create a script to handle snapping:
```gml
/// scr_snap_to_grid(x_pos, y_pos, grid_size)
var x_pos = argument0;
var y_pos = argument1;
var grid_size = argument2;
var snapped_x = grid_size * floor(x_pos / grid_size);
var snapped_y = grid_size * floor(y_pos / grid_size);
return [snapped_x, snapped_y];
```
**Usage in Player Object:**
Replace the snapping code with the script:
```gml
var grid_size = 32;
var snap = scr_snap_to_grid(x, y, grid_size);
var snap_x = snap[0];
var snap_y = snap[1];
```
---
## User Interface (UI)
Creating a user-friendly interface enhances the gameplay experience.
### Step 1: Display Resources and Hunger
**UI Object (`obj_ui`) - Draw Event:**
```gml
// Display Wood
var wood_text = "Wood: " + string(global.inventory.wood);
draw_text(10, 10, wood_text);
// Display Hunger
var hunger_text = "Hunger: " + stringf(obj_player.hunger, 0, 1);
draw_text(10, 30, hunger_text);
// Add other UI elements as needed
```
### Step 2: Building Mode Indicators
Provide visual cues when in building mode.
**Player Object (`obj_player`) - Draw GUI Event:**
```gml
if (building_mode) {
draw_text(room_width - 150, 10, "Building Mode: ON");
} else {
draw_text(room_width - 150, 10, "Building Mode: OFF");
}
```
---
## Additional Considerations
1. **Collision Masks:**
- Ensure that walls and doors have appropriate collision masks to prevent players from moving through them unless it's a door.
2. **Doors Functionality:**
- Implement door open/close mechanics if needed. For example, doors could be toggleable via interaction.
3. **Resource Drops and Collection Range:**
- Fine-tune the collection range and resource distribution for balanced gameplay.
4. **Optimizations:**
- Use object pooling for resources if you're dealing with a large number of instances.
- Optimize rendering by managing object visibility and using layers effectively.
5. **Feedback and Sound:**
- Add sound effects for collecting resources, building structures, and player actions.
- Include animations for building and resource collection to enhance visual feedback.
6. **Save and Load System:**
- Implement a system to save the player's progress, inventory, and constructed structures.
---
## Complete Example: Player Object (`obj_player`)
For clarity, here’s a consolidated version of the `obj_player` with movement, resource collection, hunger, and building mode functionalities.
```gml
// obj_player - Create Event
hsp = 0;
vsp = 0;
speed = 4;
hunger = 100;
hunger_decrement = 0.1;
building_mode = false;
// Initialize HP if not already done
if (!variable_global_exists("hp")) {
global.hp = 100;
}
// obj_player - Step Event
// Movement
hsp = 0;
if (keyboard_check(vk_right) || keyboard_check(ord('D'))) {
hsp = speed;
}
if (keyboard_check(vk_left) || keyboard_check(ord('A'))) {
hsp = -speed;
}
vsp = 0;
if (keyboard_check(vk_down) || keyboard_check(ord('S'))) {
vsp = speed;
}
if (keyboard_check(vk_up) || keyboard_check(ord('W'))) {
vsp = -speed;
}
// Collision Handling
var collision_x = place_meeting(x + hsp, y, obj_wall);
if (!collision_x) {
x += hsp;
}
var collision_y = place_meeting(x, y + vsp, obj_wall);
if (!collision_y) {
y += vsp;
}
// Resource Collection
if (keyboard_check_pressed(vk_space)) {
var resource = instance_nearest(x, y, obj_wood);
var collect_distance = 32;
if (distance_to_object(resource) < collect_distance) {
global.inventory.wood += 1;
instance_destroy(resource);
}
}
// Hunger Management
hunger -= hunger_decrement * delta_time / 1000000;
hunger = clamp(hunger, 0, 100);
if (hunger <= 0) {
global.hp -= 1;
if (global.hp <= 0) {
show_message("You have died of starvation.");
game_end(); // Or transition to a game over room
}
}
// Eating Food
if (keyboard_check_pressed(ord('E'))) {
if (global.inventory.food > 0) {
global.inventory.food -= 1;
hunger += 20;
hunger = clamp(hunger, 0, 100);
}
}
// Building Mode Toggle
if (keyboard_check_pressed(ord('B'))) {
building_mode = !building_mode;
}
// Building Mode Actions
if (building_mode) {
var grid_size = 32;
var snap = scr_snap_to_grid(x, y, grid_size);
var snap_x = snap[0];
var snap_y = snap[1];
// Preview (Assuming spr_wall_preview exists)
// You might want to create separate previews for walls and doors
draw_sprite_ext(spr_wall_preview, 0, snap_x, snap_y, 1, 1, 0, c_white, 0.5);
if (mouse_check_button_pressed(mb_left)) {
if (global.inventory.wood >= 1) {
instance_create_layer(snap_x, snap_y, "Instances", obj_wall);
global.inventory.wood -= 1;
}
}
if (mouse_check_button_pressed(mb_right)) {
if (global.inventory.wood >= 2) {
instance_create_layer(snap_x, snap_y, "Instances", obj_door);
global.inventory.wood -= 2;
}
}
}
```
---
## Conclusion
Developing a 2D survival game in GameMaker involves integrating multiple systems to create an engaging experience. By following the steps outlined above, you can implement core mechanics such as resource collection, hunger management, and building structures. Remember to iterate on your design, test thoroughly, and refine the gameplay based on feedback. Additionally, consider expanding these systems with more features like crafting, day-night cycles, enemy AI, and more to enhance the depth and replayability of your game.
If you encounter specific issues or need further assistance with certain aspects of your game development, feel free to ask!