Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: godot dungeon crawler resource #360

Merged
merged 38 commits into from
Oct 11, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
a329e3c
Scene creation, asset importing, and player idle animation
lillianhidet Sep 8, 2024
872a405
Merge branch 'Tuhura-Tech:main' into 304-godot-dungeon-crawler
lillianhidet Sep 8, 2024
445b207
Player movement
lillianhidet Sep 9, 2024
54dc043
Tilemap setup. and level creation
lillianhidet Sep 9, 2024
46e228a
Collision for tileset
lillianhidet Sep 15, 2024
487fe97
Sprite animation based on movement
lillianhidet Sep 15, 2024
4b1b174
Sprite facing
lillianhidet Sep 15, 2024
dc1d4f8
Weapon scene creation
lillianhidet Sep 20, 2024
cf4a9bf
Finished weapon, first half of health system
lillianhidet Oct 2, 2024
ef4ee7e
Merge branch 'main' into 304-godot-dungeon-crawler
Darkflame72 Oct 2, 2024
1aafdc3
First Iteration of health system
lillianhidet Oct 3, 2024
0f436c6
Update 2d Dungeon Crawler.mdx
lillianhidet Oct 3, 2024
fd051aa
Merge branch '304-godot-dungeon-crawler' of https://github.com/lillia…
lillianhidet Oct 3, 2024
6df1c54
Fixed failed commit
lillianhidet Oct 3, 2024
ef1c7ff
Merge branch '304-godot-dungeon-crawler' of https://github.com/lillia…
lillianhidet Oct 3, 2024
4759586
Finished Health System
lillianhidet Oct 3, 2024
fe9212d
Coins/Potions
lillianhidet Oct 3, 2024
ef96d56
Enemy Scene
lillianhidet Oct 3, 2024
7380273
Finished Enemy
lillianhidet Oct 3, 2024
73fdeff
Formated files for pages, added image s
lillianhidet Oct 3, 2024
6e0c434
Godot docs links
lillianhidet Oct 4, 2024
7e69e85
Added checkboxes to the end of each page
lillianhidet Oct 4, 2024
4b73dbe
Changed how player death is handled
lillianhidet Oct 4, 2024
d4455dd
Godot 4.3 Tilemaplayer level creation update
lillianhidet Oct 4, 2024
57215b4
Updated level loading to 4.3
lillianhidet Oct 4, 2024
d94e782
Changed order of Godot pages
lillianhidet Oct 4, 2024
70efc89
Merge branch 'main' into 304-godot-dungeon-crawler
lillianhidet Oct 4, 2024
1bf05eb
Spelling pass
lillianhidet Oct 4, 2024
c9c43d4
fix: tutorial nav directories
arimulligan Oct 5, 2024
120aa59
Added steps to pages requiring them
lillianhidet Oct 5, 2024
ae06d90
Merge branch 'main' into 304-godot-dungeon-crawler
lillianhidet Oct 5, 2024
c0c3743
fix: use correct file extension
Darkflame72 Oct 7, 2024
ae28942
Resolves all changes except intro/screenshots
lillianhidet Oct 8, 2024
3495b67
Merge branch '304-godot-dungeon-crawler' of https://github.com/lillia…
lillianhidet Oct 8, 2024
0b7e82f
Added preview + Refactored headings for clarity in tutorial tracker
lillianhidet Oct 8, 2024
4847730
fixed file extension
lillianhidet Oct 10, 2024
d979b04
Merge branch 'main' into 304-godot-dungeon-crawler
lillianhidet Oct 10, 2024
bc3c5a4
Merge branch 'main' into 304-godot-dungeon-crawler
lillianhidet Oct 11, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 22 additions & 4 deletions astro.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -71,10 +71,28 @@ export default defineConfig({
label: "About",
link: 'game-design/index'
}, {
label: "Godot",
autogenerate: {
directory: 'game-design/godot'
},
label: "Godot", items: [{
label: "Godot Basics",
link: "game-design/godot/basics"
},{
label: "Universal Features",
link: "game-design/godot/universal"
},{
label: "Survivors-Like",
link: "game-design/godot/survivors"
},{
label: "Top-down Dungeon Crawler",
link: "game-design/godot/dungeoncrawler/0-scenesetup/"
},{
label: "3D Intro",
link: "game-design/godot/3d"
},{
label: "3D Game",
link: "game-design/godot/3dgame"
},{
label: "Setting up C# For Godot",
link: "game-design/godot/projectsetup"
}],
collapsed: true
}],
},
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added src/assets/godot/dungeonCrawler/addanim.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added src/assets/godot/dungeonCrawler/animlength.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added src/assets/godot/dungeonCrawler/assets.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added src/assets/godot/dungeonCrawler/autoloop.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added src/assets/godot/dungeonCrawler/coinScene.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added src/assets/godot/dungeonCrawler/enemyscene.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added src/assets/godot/dungeonCrawler/eraseTool.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added src/assets/godot/dungeonCrawler/folders.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added src/assets/godot/dungeonCrawler/groups.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added src/assets/godot/dungeonCrawler/idleanim.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added src/assets/godot/dungeonCrawler/layersimg.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added src/assets/godot/dungeonCrawler/screenshot.png
Binary file added src/assets/godot/dungeonCrawler/walkanim.png
Binary file added src/assets/godot/dungeonCrawler/worldScene.png
6 changes: 4 additions & 2 deletions src/components/starlight/Pagination.astro
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
---
import Default from '@astrojs/starlight/components/Pagination.astro';
import type { Props } from '@astrojs/starlight/props';
import { isTutorialEntry } from '../../content/config';
import { getTutorialPages } from '../../util/getTutorialPages';
import { pages } from '../tutorial/TutorialNav.astro';
import { allPages } from '../tutorial/TutorialNav.astro';

const { entry, pagination } = Astro.props;
const { entry, pagination, id } = Astro.props;
const { type } = Astro.props.entry.data;
let { prev, next } = pagination;

const pages = allPages.filter((page) => isTutorialEntry(page, id));
const tutorialPages = getTutorialPages(pages);

if (type === 'tutorial') {
Expand Down
4 changes: 1 addition & 3 deletions src/components/tutorial/ProgressStore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -207,8 +207,6 @@ export class ProgressStore {
}

private static slugFromPathname(pathname: string) {
// Remove the language segment from the path,
// and strip a trailing slash, if present.
return pathname.split('/').slice(2).join('/').replace(/\/$/, '');
return pathname.replace(/\/$/, '');
}
}
9 changes: 4 additions & 5 deletions src/components/tutorial/TutorialNav.astro
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
---
import type { Props } from '@astrojs/starlight/props';
import { getCollection } from "astro:content";
import { isTutorialEntry } from '../../content/config';
import { getTutorialPages, getTutorialUnits } from '../../util/getTutorialPages';
Expand All @@ -8,13 +9,11 @@ import TabPanel from '../tabs/TabPanel.astro';
import Progress from './Progress.astro';
import UnitProgressIcon from './UnitProgressIcon.astro';

export interface Props {
id: string;
}

const currentUrl = Astro.url.pathname.replace(/\/$/, '');
const { id } = Astro.props;

export const allPages = await getCollection('docs');
export const pages = allPages.filter(isTutorialEntry);
const pages = allPages.filter((page) => isTutorialEntry(page, id));

const tutorialPages = getTutorialPages(pages);
const units = getTutorialUnits(tutorialPages);
Expand Down
16 changes: 14 additions & 2 deletions src/content/config.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { docsSchema, i18nSchema } from "@astrojs/starlight/schema";
import { type CollectionEntry, defineCollection, z } from "astro:content";
import path from 'node:path';

// find all tutorial pages
const baseSchema = z.object({
Expand All @@ -24,11 +25,22 @@ export type DocsEntry<T extends DocsEntryType> = CollectionEntry<'docs'> & {
type DocsEntryType = DocsEntryData['type'];

function createIsDocsEntry<T extends DocsEntryType>(type: T) {
return (entry: CollectionEntry<'docs'>): entry is DocsEntry<T> => entry.data.type === type;
return (entry: CollectionEntry<'docs'>, id: string): entry is DocsEntry<T> => {
if (entry.data.type !== type) {
return false;
}
const currentPath = path.parse(id);
const currentDir = path.dirname(currentPath.dir);

const pagePath = path.parse(entry.id);
const pageDir = path.dirname(pagePath.dir);

return pageDir === currentDir;
};
}

export type TutorialEntry = DocsEntry<'tutorial'>;
export const isTutorialEntry = createIsDocsEntry('tutorial');
export const isTutorialEntry = createIsDocsEntry<'tutorial'>('tutorial');

export const collections = {
docs: defineCollection({ schema: docsSchema({ extend: docsCollectionSchema }) }),
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
---
type: tutorial
lillianhidet marked this conversation as resolved.
Show resolved Hide resolved
unitTitle: Making a 2D top-down dungeon crawler
title: Setting up our scene
description: This page works through 2D top-down dungeon crawler step-by-step
sidebar:
order: 2
---

import Checklist from '/src/components/tutorial/Checklist.astro';
import Box from '/src/components/tutorial/Box.astro';
import { Steps } from '@astrojs/starlight/components';

This is a guide to making a 2-dimensional dungeon crawling game in [Godot](https://godotengine.org/). If you are unfamiliar with Godot, check out the [Godot basics](/game-design/godot/basics) doc as this tutorial assumes basic knowledge of navigating and using the Godot Engine.

:::note[Version]
This guide is up-to-date with Godot 4.3 stable official release, and will likely work with any version of Godot newer than 4.3. Due to the use of **TileMapLayers** which were introduced in 4.3, this tutorial isn't compatible with any version pre 4.3
:::

## What you'll be making

![Screenshot preview of the game](/src/assets/godot/dungeonCrawler/screenshot.png)

In this tutorial, you'll work step by step through creating your very own Dungeon Crawler! In this game, the player will navigate through a multi-level dungeon of your design, full of enemies to fight, and treasure to collect!

You'll learn to:
- Create an animated player character
- Create enemies that chase and attack the player
- Create a User Interface that tracks health and points
- Switch levels
- Design 2D Combat

Let's jump right in!

## Making the project

:::note[Godot Documentation]
Godot Documentation for nodes discussed in this section:

[Importing](https://docs.godotengine.org/en/stable/tutorials/assets_pipeline/import_process.html)
:::


We won't be creating our own assets as part of this project, we'll instead be using a free asset pack by Ox72 on Itch.IO which [can be found here](https://0x72.itch.io/dungeontileset-ii) Just click *Download now* followed by *No thanks, just take me to the download* and download the file called *0x72_DungeonTilesetII_v1.7.zip*

Create a new 2D project, using the Forward+ Renderer.

Let's start by importing our assets!

<Steps>

1. First let's create a new folder, and call it 'Assets'
Then, let's extract the assets from the folder we downloaded, and at them into our Assets folder. Mine looks like this, but it's fine if yours looks slightly different.

![Assets](/src/assets/godot/dungeonCrawler/assets.png)

2. Let's also create two new top level folders called 'Scripts' and 'Scenes'

![Folders](/src/assets/godot/dungeonCrawler/folders.png)

3. To ensure our pixel art assets look crisp and not blurred we'll want to make one quick change.
Using the buttons in the top left of the screen, select **Project -> Project settings** In this menu, select the **General** tab, and scroll until you see the **Rendering** header. Under this, select **Textures**
Change **Default Texture Filter** from **Linear** to **Nearest**

![Folders](/src/assets/godot/dungeonCrawler/TextureFilter.png)
</Steps>

<Box>
## Checklist
<Checklist>
- [ ] I have imported the assets
- [ ] I have setup my folders and changed the settings
- [ ] I'm ready to make a game!
</Checklist>
</Box>
149 changes: 149 additions & 0 deletions src/content/docs/game-design/godot/dungeoncrawler/1-player/index.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
---
type: tutorial
unitTitle: Creating our player
title: Setting up our player.
description: Creating our player scene and scripts
---

import Checklist from '/src/components/tutorial/Checklist.astro';
import Box from '/src/components/tutorial/Box.astro';
import { Steps } from '@astrojs/starlight/components';

## Creating the Player

:::note[Godot Documentation]
Godot Documentation for nodes discussed in this section:

[Collision Shapes](https://docs.godotengine.org/en/stable/tutorials/physics/collision_shapes_2d.html) [CharacterBody2D](https://docs.godotengine.org/en/stable/classes/class_characterbody2d.html) [AnimatedSprite2D](https://docs.godotengine.org/en/stable/classes/class_animatedsprite2d.html) [Area2D](https://docs.godotengine.org/en/stable/classes/class_area2d.html)
:::


Great! Let's start by making a basic version of our player character that will let us move around. We'll worry about more complicated things like attacking later.


<Steps>

1. Start by creating a new 2D Scene, with a **CharacterBody2D** as the root node. Call it 'Player'

2. Give it two children:
A **CollisionShape2D** and an **AnimatedSprite2D**

</Steps>

Here's how my scene looks with no other modifications:

![Basic player scene](/src/assets/godot/dungeonCrawler/playerscenebasic.png)

Let's hit **Ctrl + S** and save this scene in our **Scenes** folder, call it **Player.tscn**

## Animations

Let's give ourselves something to look at!
<Steps>
1. Click on the **AnimatedSprite2D** and in the inspector, under **Animation** you'll see **\<Empty>** in the **Spriteframes** field.

2. Click on **\<Empty>** and create a new **Spriteframes** Click on the **Spriteframes** you created. This will open a new window at the bottom of the screen.
This is where we'll create our player's animations. Rename the *General* animation to *Idle* and click the *Add frames from File* Button (The folder icon)

3. Navigate to your *assets/frames* folder, and decide which character you want to be your player. I'll be using the Plague Doctor. Using Shift + Click select all the frames for your character labeled *Idle* (This should be four frames) then open them.

![Idle Animation Frames](/src/assets/godot/dungeonCrawler/idleanim.png)

You'll see them added to the animation timeline.

4. We'll want to select two things in the timeline. The **Loop** Button (To ensure the animation loops) and the **Play on start button** (To ensure the animation plays automatically)
Let's also increase the FPS to 8 so that the animation plays a little faster.

![Idle Animation Frames](/src/assets/godot/dungeonCrawler/autoloop.png)

Hit play to test! You'll see the player now has an idle animation that loops!

5. Let's add our character's walking animation. Add a new animation using the **Add animation** Button and call it "Walk"

![Idle Animation Frames](/src/assets/godot/dungeonCrawler/addanim.png)

Do the same thing we did to grab the frames for the idle animation, but this time, grab all the frames labeled "Run" it should again be 4 frames. We want this animation to loop, but we **don't** want it to autoplay. Let's also give this a framerate of 8 FPS.

![Walk Animation Frames](/src/assets/godot/dungeonCrawler/walkanim.png)

Finally, just select your idle animation again, to make sure this is what our player will start on.

Great! That's our animations all done!
</Steps>

## Collision

Now that we have something to look at, let's give our player a hitbox.
<Steps>
1. Open the inspector for the **CollisionShape2D** we added, and add a new shape in the **empty** shape field.
It's a good idea to use a **CapsuleShape** as it will make us less likely to get stuck on corners. Position and adjust the capsule so that it's *slightly* smaller than the sprite for our player.
Mine looks like this:

![CollissionShape](/src/assets/godot/dungeonCrawler/collshapeimg.png)

2. Great! Our player now has collision. We'll do one more thing while we're here, which is give our player a script to handle movement. Right click on the **CharacterBody2D** and Attach a script. Call it something like "player.gd" and make sure we're saving it in our Scripts folder.
We also need to make sure we **untick** the **template** box as we will not be using the template! This is because the template is designed for gravity based platformers.
</Steps>

With our script created and attached, let's get to programming our movement!

## Movement

<Steps>

1. First, let's set up a variable to control our speed.

```gdscript
extends CharacterBody2D

@export var speed = 200
lillianhidet marked this conversation as resolved.
Show resolved Hide resolved
```

The **\@export** tag will allow us to easily edit our speed variable, without needing to open the script!

2. Then, we'll want to use Godots built-in **_physics_process(delta):** function for our movement logic. Inside that we'll want to get the combined vector of all the inputs the player is pressing.

```gdscript
func _physics_process(delta):
var direction = Input.get_vector("ui_left", "ui_right", "ui_up", "ui_down")
```

3. We'll then add some lines to multiply this vector by our speed, and then invoke Godots built-in **move_and_slide()** function, which actually does the moving!

```gdscript
func _physics_process(delta):
var direction = Input.get_vector("ui_left", "ui_right", "ui_up", "ui_down")

velocity = direction * speed

move_and_slide()
```

4. giving us a final script that looks like this:

```gdscript
extends CharacterBody2D

@export var speed = 200

func _physics_process(delta):
var direction = Input.get_vector("ui_left", "ui_right", "ui_up", "ui_down")
velocity = direction * speed

move_and_slide()
```
</Steps>
For now our movement is controlled using the arrow keys, but we'll go over how to map it to whatever we want later in the guide.

Switch back to 2D view at the top of the screen.

And that's our player ready to go for now!

<Box>
## Checklist
<Checklist>
- [ ] I've created the player scene
- [ ] I've setup the animations
- [ ] I've attached the script
</Checklist>
</Box>
Loading