improved blog media layout
All checks were successful
Jenkins
Web/pipeline/head This commit looks good
|
@ -6,4 +6,5 @@ git_source(:github) { |repo_name| "https://github.com/#{repo_name}" }
|
|||
|
||||
gem "jekyll"
|
||||
gem "webrick"
|
||||
gem 'jekyll-feed'
|
||||
gem "jekyll-feed"
|
||||
gem "jekyll-postfiles"
|
||||
|
|
|
@ -31,6 +31,8 @@ GEM
|
|||
terminal-table (~> 2.0)
|
||||
jekyll-feed (0.16.0)
|
||||
jekyll (>= 3.7, < 5.0)
|
||||
jekyll-postfiles (3.1.0)
|
||||
jekyll (>= 3.8.6, < 5)
|
||||
jekyll-sass-converter (2.2.0)
|
||||
sassc (> 2.0.1, < 3.0)
|
||||
jekyll-watch (2.2.1)
|
||||
|
@ -66,6 +68,7 @@ PLATFORMS
|
|||
DEPENDENCIES
|
||||
jekyll
|
||||
jekyll-feed
|
||||
jekyll-postfiles
|
||||
webrick
|
||||
|
||||
BUNDLED WITH
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
permalink: blog/:title
|
||||
permalink: blog/:title.html
|
||||
|
||||
plugins:
|
||||
- jekyll-feed
|
||||
- jekyll-postfiles
|
||||
|
||||
# markdown formatting
|
||||
kramdown:
|
||||
|
|
|
@ -1,56 +1,56 @@
|
|||
---
|
||||
layout: blog
|
||||
title: 🔮 The Future of Actually Additions
|
||||
description: Not wanting to accept the fate of Actually Additions, someone has come to its rescue. 1.16, here we come?
|
||||
tags: [Minecraft]
|
||||
discuss: https://twitter.com/Ellpeck/status/1330938597785169925
|
||||
---
|
||||
|
||||
*TLDR: Actually Additions for 1.16.4 in the future. No ETA. No Fabric port. No 1.13, 1.14 or 1.15. Beautiful art overhaul. Don't ask Ellpeck anything ever. Stay awesome.*
|
||||
|
||||
**November 2021 update: The port is still being actively worked on. You can stay up to date with the progress through [the `1.16` branch](https://github.com/Ellpeck/ActuallyAdditions/tree/1.16) on the GitHub repository.**
|
||||
|
||||
Before I start this post, I want to re-iterate that I haven't had a direct programming-related connection to Actually Additions in [over three years](https://github.com/Ellpeck/ActuallyAdditions/commits/main?after=896a082d747a3e19755ded1973544d59fa992787+244). I don't plan on changing this. This means that, if you have *anything* to say about the mod, be it issue reports or feature requests, **do not talk to me about that**. Go to [the issue tracker](https://github.com/Ellpeck/ActuallyAdditions/issues) or [my Discord](https://ellpeck.de/discord)'s `#minecraft` channel.
|
||||
|
||||
Okay, now that that's out of the way... let's talk about the future of Actually Additions. In [my last post](https://ellpeck.de/blog-actually_additions), I talked about the things I disliked about the mod and, in that same vein, the reasons that I don't want it to be updated beyond Minecraft 1.12. What I didn't necessarily make clear in that post is that this isn't really my decision, because I haven't touched Actually Additions in *a long time*. For the last few years, **Shadows-of-Fire** has been maintaining the mod (that is, fixing issues and publishing updates), which is also the reason that there haven't been any new features during that time. So what about now?
|
||||
|
||||
# Who?
|
||||
A few months ago, Direwolf sent me a message on Discord along the lines of
|
||||
|
||||
> Hey, do you want someone to port Actually Additions? Because I know this really great guy called [MiKeY](https://github.com/MichaelHillcox) who really loves porting mods for some reason.
|
||||
|
||||
So, as a result of that, **MiKeY** is basically the new, official maintainer of Actually Additions.
|
||||
|
||||
A little while later, another person approached me: [Ridanisaurus](https://github.com/Ridanisaurus), who apparently really likes making beautiful art for mods. He asked me if I want new art for Actually Additions, and since I have some *opinions* about the current state of Actually Additions' graphics and visual consistency, I naturally said yes immediately. So yea, **Ridanisaurus** is basically the new, official artist of Actually Additions.
|
||||
|
||||
# What?
|
||||
MiKeY and Rid are going to port Actually Additions to **Forge** for **Minecraft 1.16.4**. They are re-doing all of the art for the mod and they will also modify some of the features that I dislike, based on my personal feedback and the information outlined in [my diss track](https://ellpeck.de/blog-actually_additions).
|
||||
|
||||
The art overhaul has already started (and even been finished, I believe), and because it is *gorgeous*, I'm going to show you some of the preview pictures that Rid has sent me right now. Enjoy.
|
||||
|
||||
<img src="/blog/res/future_actually_additions/1.png" width="100%">
|
||||
|
||||
<img src="/blog/res/future_actually_additions/2.png" width="100%">
|
||||
|
||||
<img src="/blog/res/future_actually_additions/3.png" width="100%">
|
||||
|
||||
Don't they look *so good*?
|
||||
|
||||
# What Not?
|
||||
Since I know a lot of people will ask questions about this, here is a list of some of the things that you will **not** be getting, no matter how frequently you ask.
|
||||
- We will *not* be releasing a Fabric version of the mod.
|
||||
- We will *not* be releasing 1.13, 1.14 or 1.15 versions of the mod.
|
||||
- We will *not* be keeping all of the features in the mod the same, especially not the Storage Crate, which will be getting a major overhaul.
|
||||
- There will be *no* entirely new features, only changes to existing ones. Since this has been the case for the last few years as well, I don't think it's very surprising.
|
||||
|
||||
MiKeY has expressed great interest in helping me overhaul the features that I dislike and, as a result, making Actually Additions a better and more refined mod than it used to be.
|
||||
|
||||
# When?
|
||||
We don't know yet. *Please* don't ask.
|
||||
|
||||
**November 2021 update: We still don't know. It's a process.**
|
||||
|
||||
# Thank You
|
||||
So yea, that's about it for the news. I hope all of you are as excited about the port and the upcoming changes as I am. If you want to be kept up to date with the changes, you can check the [GitHub repository](https://github.com/Ellpeck/ActuallyAdditions) every once in a while (specifically [its `1.16` branch](https://github.com/Ellpeck/ActuallyAdditions/tree/1.16)) and join [my Discord server](https://ellpeck.de/discord), where we might post some updates from time to time.
|
||||
|
||||
As an additional note, I would like to thank all of you for the continued support of not only Actually Additions, but all of my mods and even my non-Minecraft-related projects. Of course, there have also been some rude people, but all in all, yall have been an amazing community and I am so grateful that you enjoy the things I create. I love yall. ❤️
|
||||
---
|
||||
layout: blog
|
||||
title: 🔮 The Future of Actually Additions
|
||||
description: Not wanting to accept the fate of Actually Additions, someone has come to its rescue. 1.16, here we come?
|
||||
tags: [Minecraft]
|
||||
discuss: https://twitter.com/Ellpeck/status/1330938597785169925
|
||||
---
|
||||
|
||||
*TLDR: Actually Additions for 1.16.4 in the future. No ETA. No Fabric port. No 1.13, 1.14 or 1.15. Beautiful art overhaul. Don't ask Ellpeck anything ever. Stay awesome.*
|
||||
|
||||
**November 2021 update: The port is still being actively worked on. You can stay up to date with the progress through [the `1.16` branch](https://github.com/Ellpeck/ActuallyAdditions/tree/1.16) on the GitHub repository.**
|
||||
|
||||
Before I start this post, I want to re-iterate that I haven't had a direct programming-related connection to Actually Additions in [over three years](https://github.com/Ellpeck/ActuallyAdditions/commits/main?after=896a082d747a3e19755ded1973544d59fa992787+244). I don't plan on changing this. This means that, if you have *anything* to say about the mod, be it issue reports or feature requests, **do not talk to me about that**. Go to [the issue tracker](https://github.com/Ellpeck/ActuallyAdditions/issues) or [my Discord](https://ellpeck.de/discord)'s `#minecraft` channel.
|
||||
|
||||
Okay, now that that's out of the way... let's talk about the future of Actually Additions. In [my last post](https://ellpeck.de/blog-actually_additions), I talked about the things I disliked about the mod and, in that same vein, the reasons that I don't want it to be updated beyond Minecraft 1.12. What I didn't necessarily make clear in that post is that this isn't really my decision, because I haven't touched Actually Additions in *a long time*. For the last few years, **Shadows-of-Fire** has been maintaining the mod (that is, fixing issues and publishing updates), which is also the reason that there haven't been any new features during that time. So what about now?
|
||||
|
||||
# Who?
|
||||
A few months ago, Direwolf sent me a message on Discord along the lines of
|
||||
|
||||
> Hey, do you want someone to port Actually Additions? Because I know this really great guy called [MiKeY](https://github.com/MichaelHillcox) who really loves porting mods for some reason.
|
||||
|
||||
So, as a result of that, **MiKeY** is basically the new, official maintainer of Actually Additions.
|
||||
|
||||
A little while later, another person approached me: [Ridanisaurus](https://github.com/Ridanisaurus), who apparently really likes making beautiful art for mods. He asked me if I want new art for Actually Additions, and since I have some *opinions* about the current state of Actually Additions' graphics and visual consistency, I naturally said yes immediately. So yea, **Ridanisaurus** is basically the new, official artist of Actually Additions.
|
||||
|
||||
# What?
|
||||
MiKeY and Rid are going to port Actually Additions to **Forge** for **Minecraft 1.16.4**. They are re-doing all of the art for the mod and they will also modify some of the features that I dislike, based on my personal feedback and the information outlined in [my diss track](https://ellpeck.de/blog-actually_additions).
|
||||
|
||||
The art overhaul has already started (and even been finished, I believe), and because it is *gorgeous*, I'm going to show you some of the preview pictures that Rid has sent me right now. Enjoy.
|
||||
|
||||
![](faa_1.png)
|
||||
|
||||
![](faa_2.png)
|
||||
|
||||
![](faa_3.png)
|
||||
|
||||
Don't they look *so good*?
|
||||
|
||||
# What Not?
|
||||
Since I know a lot of people will ask questions about this, here is a list of some of the things that you will **not** be getting, no matter how frequently you ask.
|
||||
- We will *not* be releasing a Fabric version of the mod.
|
||||
- We will *not* be releasing 1.13, 1.14 or 1.15 versions of the mod.
|
||||
- We will *not* be keeping all of the features in the mod the same, especially not the Storage Crate, which will be getting a major overhaul.
|
||||
- There will be *no* entirely new features, only changes to existing ones. Since this has been the case for the last few years as well, I don't think it's very surprising.
|
||||
|
||||
MiKeY has expressed great interest in helping me overhaul the features that I dislike and, as a result, making Actually Additions a better and more refined mod than it used to be.
|
||||
|
||||
# When?
|
||||
We don't know yet. *Please* don't ask.
|
||||
|
||||
**November 2021 update: We still don't know. It's a process.**
|
||||
|
||||
# Thank You
|
||||
So yea, that's about it for the news. I hope all of you are as excited about the port and the upcoming changes as I am. If you want to be kept up to date with the changes, you can check the [GitHub repository](https://github.com/Ellpeck/ActuallyAdditions) every once in a while (specifically [its `1.16` branch](https://github.com/Ellpeck/ActuallyAdditions/tree/1.16)) and join [my Discord server](https://ellpeck.de/discord), where we might post some updates from time to time.
|
||||
|
||||
As an additional note, I would like to thank all of you for the continued support of not only Actually Additions, but all of my mods and even my non-Minecraft-related projects. Of course, there have also been some rude people, but all in all, yall have been an amazing community and I am so grateful that you enjoy the things I create. I love yall. ❤️
|
Before Width: | Height: | Size: 632 KiB After Width: | Height: | Size: 632 KiB |
Before Width: | Height: | Size: 380 KiB After Width: | Height: | Size: 380 KiB |
Before Width: | Height: | Size: 630 KiB After Width: | Height: | Size: 630 KiB |
|
@ -1,185 +1,185 @@
|
|||
---
|
||||
layout: blog
|
||||
title: ⬇️ How to make a Rock Bottom mod
|
||||
description: My adventures back into a game I stopped working on about two years ago and how I start on a mod for it
|
||||
tags: [Programming]
|
||||
discuss: https://twitter.com/Ellpeck/status/1180092634410487808
|
||||
---
|
||||
|
||||
So it's been a hot minute since I stopped working on my first big game project, [Rock Bottom](https://rockbottomgame.com). Since then, I've changed a lot, but the game hasn't changed that much: For a long time, the project was vacant, until I decided to make it open source. From that point on, a couple of my friends started working on it, adding some new features and fixing some bugs, until it seemingly fell back into vacancy over the last couple of weeks.
|
||||
|
||||
So let's port my recent Minecraft mod, [Nature's Aura](https://www.curseforge.com/minecraft/mc-mods/natures-aura), to Rock Bottom!
|
||||
|
||||
***Note: This is not a tutorial.***
|
||||
|
||||
# Setting up the dev environment
|
||||
Now I *somewhat* remember that, back when I was working on the game, I set up a pretty in-depth modding API as well as an actual Github project to easily allow people to set up a mod themselves.
|
||||
|
||||
*Aha, here it is: [the modding repo](https://github.com/RockBottomGame/Modding).* It even has some nice documentation that I apparently made! Okay, here goes.
|
||||
|
||||
Okay, finding [a build of the game](https://github.com/RockBottomGame/RockBottom/releases) was pretty easy. It even has an in-depth changelog! Good on you, raphy.
|
||||
|
||||
Hm. Okay.
|
||||
So something's already broken.
|
||||
<img src="/blog/res/rock_bottom_mod/1.png" width="100%">
|
||||
|
||||
It looks like here
|
||||
```
|
||||
dependencies {
|
||||
compile group: 'de.ellpeck.rockbottom', name: 'RockBottomAPI', version: '+'
|
||||
}
|
||||
```
|
||||
where it says `+`, it should actally be saying a specific version. So let's replace that with `0.4.6-753` and refresh.
|
||||
|
||||
That didn't seem to fix it either. Huh. Taking a look at [the maven](https://maven.chaosfield.at/de/ellpeck/rockbottom/RockBottomAPI/0.4.6-753/), it seems to be currently down because of `502 bad gateway`. Fun.
|
||||
|
||||
Okay, it's now the next day and it looks like the maven has been fixed, which is nice. So all the compile issues are finally resolved, I put the build into the `/gamedata` folder like explained in the tutorial, I renamed the examplemod to `NaturesAura`, and I can now finally try running the game!
|
||||
|
||||
<img src="/blog/res/rock_bottom_mod/2.png" width="100%">
|
||||
Ah! That worked quite well in the end.
|
||||
|
||||
# Actually making something
|
||||
So I feel like the first thing I should add to the game is the golden leaves, because they're also the first thing that you have to create when getting started with the Minecraft version of Nature's Aura.
|
||||
|
||||
So I quickly made a new class that extends `TileBasic`, which I vaguely remember was like an extended, better version of the `Tile` class with some useful helper methods.
|
||||
```java
|
||||
package de.ellpeck.naturesaura.tiles;
|
||||
|
||||
import de.ellpeck.rockbottom.api.tile.TileBasic;
|
||||
import de.ellpeck.rockbottom.api.util.reg.ResourceName;
|
||||
|
||||
public class TileGoldenLeaves extends TileBasic {
|
||||
|
||||
public TileGoldenLeaves(ResourceName name) {
|
||||
super(name);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
My Java is pretty rusty, but I seem to remember all of the naming conventions and, coming from C#, do find myself having trouble with the lowerCamelCase methods (because C# uses UpperCamelCase for method names, conventionally). I quickly made a `Tiles` class that's going to house all the tiles I create and made an instance of the golden leaves tile.
|
||||
|
||||
```java
|
||||
package de.ellpeck.naturesaura.tiles;
|
||||
|
||||
import de.ellpeck.naturesaura.NaturesAura;
|
||||
import de.ellpeck.rockbottom.api.tile.Tile;
|
||||
|
||||
public final class Tiles {
|
||||
|
||||
public static final Tile GOLDEN_LEAVES = new TileGoldenLeaves(NaturesAura.createRes("golden_leaves"));
|
||||
|
||||
}
|
||||
```
|
||||
|
||||
I also created a dummy instance of the Tiles class so that the static variables in it are loaded. If you're not extremely familiar with Java, then this might appear a bit weird for you, but static variables of a class only get instantiated once the class is first used in some way (be it instance creation, method calling, stuff like that), and because I want the golden leaves to be initialized in the `preInit` phase of the game, I just do this:
|
||||
|
||||
```java
|
||||
@Override
|
||||
public void preInit(IGameInstance game, IApiHandler apiHandler, IEventHandler eventHandler) {
|
||||
this.modLogger.info("Starting Nature's Aura for RockBottom");
|
||||
new Tiles();
|
||||
}
|
||||
```
|
||||
|
||||
So far, so good. Let's figure out how to add a texture to the thing.
|
||||
I somewhat remember that I made a horrible json-based asset system (instead of just loading all of the assets in the mod's jar automatically), so I'm going to try to add my tile to the `assets.json` file the example mod provided me with and also add a texture into the actual file system.
|
||||
|
||||
<img src="/blog/res/rock_bottom_mod/3.png" width="100%">
|
||||
This is the folder structure I decided on. I also created a quick golden version of the game's leaves texture by going to the [asset repository](https://github.com/RockBottomGame/Assets), stealing the leaves texture and recoloring it to be golden-ish.
|
||||
|
||||
Also, I put this in the assets file, but I have no idea if that's actually the right path. We'll find out.
|
||||
```json
|
||||
{
|
||||
"loc.": {
|
||||
"us_english": "/loc/us_english.json"
|
||||
},
|
||||
"tex.": {
|
||||
"tiles.": {
|
||||
"golden_leaves": "/tex/tiles/golden_leaves.png"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Okay, let's launch and see what happens. So I started the game, opened a lan server, opened the chat, typed `/items` to get a cheat menu, and... it's not showing up. What did I do wrong?
|
||||
|
||||
After some thinking, it turns out that I forgot to actually *register* the tile. So I went back into my `Tiles` class and appended `.register()` to the end of the whole thing, like this:
|
||||
```
|
||||
public static final Tile GOLDEN_LEAVES = new TileGoldenLeaves(NaturesAura.createRes("golden_leaves")).register();
|
||||
```
|
||||
*Crisis averted*.
|
||||
|
||||
<img src="/blog/res/rock_bottom_mod/4.png" width="100%">
|
||||
Yaaay, it... worked? *Somewhat?*
|
||||
|
||||
You're probably yelling at your screen by now, but yes, I finally noticed it as well: My assets path says `examplemod` instead of `naturesaura`. Easy fix, though.
|
||||
|
||||
While I'm at it though, I can also add a localization entry for the golden leaves. When hovering over it, the console informed me that `Localization with name naturesaura/item.golden_leaves is missing from locale with name us_english!`, so I quickly added it:
|
||||
```json
|
||||
{
|
||||
"naturesaura": {
|
||||
"item.": {
|
||||
"golden_leaves": "Golden Leaves"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Let's try again.
|
||||
|
||||
<img src="/blog/res/rock_bottom_mod/5.png" width="100%">
|
||||
Ta-da! Success, at last.
|
||||
|
||||
After some investigation, I realized that Rock Bottom's normal leaves can be walked through, so let's see how to make that happen. Typing `@Override` while in the `TileGoldenLeaves` class causes my IDE to list all of the methods I can override. Among them are two that interest me:
|
||||
```java
|
||||
@Override
|
||||
public boolean isFullTile() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BoundBox getBoundBox(IWorld world, TileState state, int x, int y, TileLayer layer) {
|
||||
return null;
|
||||
}
|
||||
```
|
||||
It seems like this is what I have to do to make the tile walk-through...able. Let's try it out.
|
||||
|
||||
<img src="/blog/res/rock_bottom_mod/6.png" width="100%">
|
||||
Yay, that seems to have worked. Great.
|
||||
|
||||
# Making an item
|
||||
Now that I have somewhat of a grip of this whole Rock Bottom stuff again, I'm quickly going to make an item. I won't bore you with the details as it's pretty similar to making a tile, but the gist of it is this: I made an `ItemGoldPowder` class that extends `ItemBasic`, and I initialized and registered an instance of that in my newly created `Items` class, of which I created an instance in my mod class's `preInit` method so that it gets initialized at the right time. Also, I did all of the annoying asset mumbo jumbo.
|
||||
|
||||
<img src="/blog/res/rock_bottom_mod/7.png" width="100%">
|
||||
*Oh, C#, you've ruined me.*
|
||||
|
||||
# Making stuff happen
|
||||
Now, to actually make the gold powder turn normal leaves into golden leaves, I have to write some actual code that isn't just boring boilerplate. When right clicking the golden powder onto a leaves tile, I want that tile to turn into the golden leaves. Eventually, they should then *transition* somehow, but... I'll leave that for later.
|
||||
|
||||
Let's write some code!
|
||||
```java
|
||||
@Override
|
||||
public boolean onInteractWith(IWorld world, int x, int y, TileLayer layer, double mouseX, double mouseY, AbstractEntityPlayer player, ItemInstance instance) {
|
||||
var state = world.getState(layer, x, y);
|
||||
if (state.getTile() != GameContent.TILE_LEAVES)
|
||||
return false;
|
||||
world.setState(layer, x, y, Tiles.GOLDEN_LEAVES.getDefState());
|
||||
player.getInv().remove(player.getSelectedSlot(), 1);
|
||||
return true;
|
||||
}
|
||||
```
|
||||
While writing this code, I quickly remembered that Rock Bottom has a tile state system similar to Minecraft, so I had to work with that. Before I realized, I sat there wondering why `IWorld` doesn't have a `getTile` method anywhere. Anyway, this should check the interacted tile; see if it's leaves; replace the leaves with golden leaves and deduct one from the item being currently held (which is obviously the gold powder, as this is in the `ItemGoldPowder` class. No need for checks there.)
|
||||
|
||||
Let's try it out! ...yea, no. The Java version that gradle uses to compile a Rock Bottom mod isn't new enough yet: You can't use the `var` keyword. Oh, my poor, poor C# soul. So let's swap that `var` out for a `TileState`.
|
||||
|
||||
<img src="/blog/res/rock_bottom_mod/8.gif" width="100%">
|
||||
Yay, it works! *Except that, in the gif, the mouse position is weirdly offset for some reason. It's correct in person, I promise!*
|
||||
|
||||
# Conclusion
|
||||
So yea, that was the start of my adventure back into Java, back into my old game and back into... well, modding, I guess. I hope you enjoyed reading this post and seeing my process of working out how to do stuff.
|
||||
|
||||
I think it's important to remember that, as a developer (especially an indie developer), you don't have to code everything perfectly or work stuff out correctly the first try. I mean, heck, this is my own game, and I completely forgot how to make a mod for it. But it was fun to figure it out again, and to get back into something I made two years ago.
|
||||
|
||||
Oh, also, if you really want, [here's a build of the mod](https://ellpeck.de/blog/res/rock_bottom_mod/NaturesAuraRockBottom-0.1.jar) that you can try out yourself, as the game is now actually open source and available to everyone! I created this jar with the command `gradlew build`, and all you have to do to run it is [download the game](https://github.com/RockBottomGame/RockBottom/releases), run it once, and then stick the mod jar into its `mods` folder. It really doesn't do that much right now, though, so I don't know why you'd bother.
|
||||
|
||||
As always, thanks for reading!
|
||||
---
|
||||
layout: blog
|
||||
title: ⬇️ How to make a Rock Bottom mod
|
||||
description: My adventures back into a game I stopped working on about two years ago and how I start on a mod for it
|
||||
tags: [Programming]
|
||||
discuss: https://twitter.com/Ellpeck/status/1180092634410487808
|
||||
---
|
||||
|
||||
So it's been a hot minute since I stopped working on my first big game project, [Rock Bottom](https://rockbottomgame.com). Since then, I've changed a lot, but the game hasn't changed that much: For a long time, the project was vacant, until I decided to make it open source. From that point on, a couple of my friends started working on it, adding some new features and fixing some bugs, until it seemingly fell back into vacancy over the last couple of weeks.
|
||||
|
||||
So let's port my recent Minecraft mod, [Nature's Aura](https://www.curseforge.com/minecraft/mc-mods/natures-aura), to Rock Bottom!
|
||||
|
||||
***Note: This is not a tutorial.***
|
||||
|
||||
# Setting up the dev environment
|
||||
Now I *somewhat* remember that, back when I was working on the game, I set up a pretty in-depth modding API as well as an actual Github project to easily allow people to set up a mod themselves.
|
||||
|
||||
*Aha, here it is: [the modding repo](https://github.com/RockBottomGame/Modding).* It even has some nice documentation that I apparently made! Okay, here goes.
|
||||
|
||||
Okay, finding [a build of the game](https://github.com/RockBottomGame/RockBottom/releases) was pretty easy. It even has an in-depth changelog! Good on you, raphy.
|
||||
|
||||
Hm. Okay.
|
||||
So something's already broken.
|
||||
![](rbm_1.png)
|
||||
|
||||
It looks like here
|
||||
```
|
||||
dependencies {
|
||||
compile group: 'de.ellpeck.rockbottom', name: 'RockBottomAPI', version: '+'
|
||||
}
|
||||
```
|
||||
where it says `+`, it should actally be saying a specific version. So let's replace that with `0.4.6-753` and refresh.
|
||||
|
||||
That didn't seem to fix it either. Huh. Taking a look at [the maven](https://maven.chaosfield.at/de/ellpeck/rockbottom/RockBottomAPI/0.4.6-753/), it seems to be currently down because of `502 bad gateway`. Fun.
|
||||
|
||||
Okay, it's now the next day and it looks like the maven has been fixed, which is nice. So all the compile issues are finally resolved, I put the build into the `/gamedata` folder like explained in the tutorial, I renamed the examplemod to `NaturesAura`, and I can now finally try running the game!
|
||||
|
||||
![](rbm_2.png)
|
||||
Ah! That worked quite well in the end.
|
||||
|
||||
# Actually making something
|
||||
So I feel like the first thing I should add to the game is the golden leaves, because they're also the first thing that you have to create when getting started with the Minecraft version of Nature's Aura.
|
||||
|
||||
So I quickly made a new class that extends `TileBasic`, which I vaguely remember was like an extended, better version of the `Tile` class with some useful helper methods.
|
||||
```java
|
||||
package de.ellpeck.naturesaura.tiles;
|
||||
|
||||
import de.ellpeck.rockbottom.api.tile.TileBasic;
|
||||
import de.ellpeck.rockbottom.api.util.reg.ResourceName;
|
||||
|
||||
public class TileGoldenLeaves extends TileBasic {
|
||||
|
||||
public TileGoldenLeaves(ResourceName name) {
|
||||
super(name);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
My Java is pretty rusty, but I seem to remember all of the naming conventions and, coming from C#, do find myself having trouble with the lowerCamelCase methods (because C# uses UpperCamelCase for method names, conventionally). I quickly made a `Tiles` class that's going to house all the tiles I create and made an instance of the golden leaves tile.
|
||||
|
||||
```java
|
||||
package de.ellpeck.naturesaura.tiles;
|
||||
|
||||
import de.ellpeck.naturesaura.NaturesAura;
|
||||
import de.ellpeck.rockbottom.api.tile.Tile;
|
||||
|
||||
public final class Tiles {
|
||||
|
||||
public static final Tile GOLDEN_LEAVES = new TileGoldenLeaves(NaturesAura.createRes("golden_leaves"));
|
||||
|
||||
}
|
||||
```
|
||||
|
||||
I also created a dummy instance of the Tiles class so that the static variables in it are loaded. If you're not extremely familiar with Java, then this might appear a bit weird for you, but static variables of a class only get instantiated once the class is first used in some way (be it instance creation, method calling, stuff like that), and because I want the golden leaves to be initialized in the `preInit` phase of the game, I just do this:
|
||||
|
||||
```java
|
||||
@Override
|
||||
public void preInit(IGameInstance game, IApiHandler apiHandler, IEventHandler eventHandler) {
|
||||
this.modLogger.info("Starting Nature's Aura for RockBottom");
|
||||
new Tiles();
|
||||
}
|
||||
```
|
||||
|
||||
So far, so good. Let's figure out how to add a texture to the thing.
|
||||
I somewhat remember that I made a horrible json-based asset system (instead of just loading all of the assets in the mod's jar automatically), so I'm going to try to add my tile to the `assets.json` file the example mod provided me with and also add a texture into the actual file system.
|
||||
|
||||
![](rbm_3.png)
|
||||
This is the folder structure I decided on. I also created a quick golden version of the game's leaves texture by going to the [asset repository](https://github.com/RockBottomGame/Assets), stealing the leaves texture and recoloring it to be golden-ish.
|
||||
|
||||
Also, I put this in the assets file, but I have no idea if that's actually the right path. We'll find out.
|
||||
```json
|
||||
{
|
||||
"loc.": {
|
||||
"us_english": "/loc/us_english.json"
|
||||
},
|
||||
"tex.": {
|
||||
"tiles.": {
|
||||
"golden_leaves": "/tex/tiles/golden_leaves.png"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Okay, let's launch and see what happens. So I started the game, opened a lan server, opened the chat, typed `/items` to get a cheat menu, and... it's not showing up. What did I do wrong?
|
||||
|
||||
After some thinking, it turns out that I forgot to actually *register* the tile. So I went back into my `Tiles` class and appended `.register()` to the end of the whole thing, like this:
|
||||
```
|
||||
public static final Tile GOLDEN_LEAVES = new TileGoldenLeaves(NaturesAura.createRes("golden_leaves")).register();
|
||||
```
|
||||
*Crisis averted*.
|
||||
|
||||
![](rbm_4.png)
|
||||
Yaaay, it... worked? *Somewhat?*
|
||||
|
||||
You're probably yelling at your screen by now, but yes, I finally noticed it as well: My assets path says `examplemod` instead of `naturesaura`. Easy fix, though.
|
||||
|
||||
While I'm at it though, I can also add a localization entry for the golden leaves. When hovering over it, the console informed me that `Localization with name naturesaura/item.golden_leaves is missing from locale with name us_english!`, so I quickly added it:
|
||||
```json
|
||||
{
|
||||
"naturesaura": {
|
||||
"item.": {
|
||||
"golden_leaves": "Golden Leaves"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Let's try again.
|
||||
|
||||
![](rbm_5.png)
|
||||
Ta-da! Success, at last.
|
||||
|
||||
After some investigation, I realized that Rock Bottom's normal leaves can be walked through, so let's see how to make that happen. Typing `@Override` while in the `TileGoldenLeaves` class causes my IDE to list all of the methods I can override. Among them are two that interest me:
|
||||
```java
|
||||
@Override
|
||||
public boolean isFullTile() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BoundBox getBoundBox(IWorld world, TileState state, int x, int y, TileLayer layer) {
|
||||
return null;
|
||||
}
|
||||
```
|
||||
It seems like this is what I have to do to make the tile walk-through...able. Let's try it out.
|
||||
|
||||
![](rbm_6.png)
|
||||
Yay, that seems to have worked. Great.
|
||||
|
||||
# Making an item
|
||||
Now that I have somewhat of a grip of this whole Rock Bottom stuff again, I'm quickly going to make an item. I won't bore you with the details as it's pretty similar to making a tile, but the gist of it is this: I made an `ItemGoldPowder` class that extends `ItemBasic`, and I initialized and registered an instance of that in my newly created `Items` class, of which I created an instance in my mod class's `preInit` method so that it gets initialized at the right time. Also, I did all of the annoying asset mumbo jumbo.
|
||||
|
||||
![](rbm_7.png)
|
||||
*Oh, C#, you've ruined me.*
|
||||
|
||||
# Making stuff happen
|
||||
Now, to actually make the gold powder turn normal leaves into golden leaves, I have to write some actual code that isn't just boring boilerplate. When right clicking the golden powder onto a leaves tile, I want that tile to turn into the golden leaves. Eventually, they should then *transition* somehow, but... I'll leave that for later.
|
||||
|
||||
Let's write some code!
|
||||
```java
|
||||
@Override
|
||||
public boolean onInteractWith(IWorld world, int x, int y, TileLayer layer, double mouseX, double mouseY, AbstractEntityPlayer player, ItemInstance instance) {
|
||||
var state = world.getState(layer, x, y);
|
||||
if (state.getTile() != GameContent.TILE_LEAVES)
|
||||
return false;
|
||||
world.setState(layer, x, y, Tiles.GOLDEN_LEAVES.getDefState());
|
||||
player.getInv().remove(player.getSelectedSlot(), 1);
|
||||
return true;
|
||||
}
|
||||
```
|
||||
While writing this code, I quickly remembered that Rock Bottom has a tile state system similar to Minecraft, so I had to work with that. Before I realized, I sat there wondering why `IWorld` doesn't have a `getTile` method anywhere. Anyway, this should check the interacted tile; see if it's leaves; replace the leaves with golden leaves and deduct one from the item being currently held (which is obviously the gold powder, as this is in the `ItemGoldPowder` class. No need for checks there.)
|
||||
|
||||
Let's try it out! ...yea, no. The Java version that gradle uses to compile a Rock Bottom mod isn't new enough yet: You can't use the `var` keyword. Oh, my poor, poor C# soul. So let's swap that `var` out for a `TileState`.
|
||||
|
||||
![](rbm_8.gif)
|
||||
Yay, it works! *Except that, in the gif, the mouse position is weirdly offset for some reason. It's correct in person, I promise!*
|
||||
|
||||
# Conclusion
|
||||
So yea, that was the start of my adventure back into Java, back into my old game and back into... well, modding, I guess. I hope you enjoyed reading this post and seeing my process of working out how to do stuff.
|
||||
|
||||
I think it's important to remember that, as a developer (especially an indie developer), you don't have to code everything perfectly or work stuff out correctly the first try. I mean, heck, this is my own game, and I completely forgot how to make a mod for it. But it was fun to figure it out again, and to get back into something I made two years ago.
|
||||
|
||||
Oh, also, if you really want, [here's a build of the mod](NaturesAuraRockBottom-0.1.jar) that you can try out yourself, as the game is now actually open source and available to everyone! I created this jar with the command `gradlew build`, and all you have to do to run it is [download the game](https://github.com/RockBottomGame/RockBottom/releases), run it once, and then stick the mod jar into its `mods` folder. It really doesn't do that much right now, though, so I don't know why you'd bother.
|
||||
|
||||
As always, thanks for reading!
|
Before Width: | Height: | Size: 17 KiB After Width: | Height: | Size: 17 KiB |
Before Width: | Height: | Size: 118 KiB After Width: | Height: | Size: 118 KiB |
Before Width: | Height: | Size: 5 KiB After Width: | Height: | Size: 5 KiB |
Before Width: | Height: | Size: 145 KiB After Width: | Height: | Size: 145 KiB |
Before Width: | Height: | Size: 133 KiB After Width: | Height: | Size: 133 KiB |
Before Width: | Height: | Size: 156 KiB After Width: | Height: | Size: 156 KiB |
Before Width: | Height: | Size: 9.1 KiB After Width: | Height: | Size: 9.1 KiB |
Before Width: | Height: | Size: 1.1 MiB After Width: | Height: | Size: 1.1 MiB |
|
@ -1,70 +1,70 @@
|
|||
---
|
||||
layout: blog
|
||||
title: 🗡️ Small Projects
|
||||
description: Why creating a small, unplanned project is sometimes good for you
|
||||
tags: [Programming]
|
||||
discuss: https://twitter.com/Ellpeck/status/1123651624201871360
|
||||
---
|
||||
|
||||
As it turns out, I struggle a lot with maintaining interest and motivation for working on bigger projects like my [other game](https://rockbottom.ellpeck.de/) or my Minecraft mods. However, an easy fix for that would be to just start less big projects and focus more on smaller ones, like **Foe Frenzy**. Foe Frenzy is a game I've been working on for about a month now.
|
||||
|
||||
<img src="/blog/res/small_projects/contrib.png" width="100%">
|
||||
|
||||
The basic gameplay is finished, as is enough content for my friends to have been testing it for the last week or so and saying that they enjoy it quite a bit, both visually and gameplay-wise. I thought I'd make a blog post about my process of working on it, showing what it's about and what I did this time around to make sure that I don't get burnt out with it.
|
||||
|
||||
<img src="/blog/res/small_projects/overview.png" width="100%">
|
||||
|
||||
_Foe Frenzy is a fast-paced fighting game where you battle up to three of your friends with random, short-lasting items in an attempt to be the last survivor._
|
||||
|
||||
# The Artstyle
|
||||
Not every developer has this problem, but I know a lot do: The inability to make good-looking art. Well, I have this same problem too.
|
||||
A lot of times, I'll find myself getting stuck on making art for my game projects and getting burnt out through trying too hard to force myself to make good-looking art.
|
||||
|
||||
So, this time around, what I did instead of doing that all over again, I just decided to go with _simple art_ instead. For example, as you can see, all the tiles in the world only have 8x8 pixels, and all of them follow a really simple pattern: The top and left side are slightly darker, giving the world a really tiled feel and making the levels seem like they were made with actual building bricks. As well as that, the character movement animations are _really_ simple.
|
||||
|
||||
<img src="/blog/res/small_projects/wobble.gif" width="100%">
|
||||
|
||||
<img src="/blog/res/small_projects/water_wobble.gif" width="100%">
|
||||
|
||||
Both of those aren't even real animations per se, because what they really are is just the player's static texture rotating around a sin wave that is centered on the player's feet. It looks cute, though.
|
||||
|
||||
# The Inner Workings
|
||||
Whenever I write code, I tend to try to overoptimize it a lot. What I mean by that is that I think about systems that I want to implement too intricately sometimes. For instance, if I want to make a tile-based game, I obviously set up some data structures around tiles and how they're going to be ordered and stored on the map. But then, I'll also go and write a bunch of utility methods, conversion functions, figure out a really in-depth coordinate system for dynamic objects, and so on. And, honestly, for projects that aren't too big, all of that isn't really necessary.
|
||||
|
||||
What I did for this game instead is just kind of... let the code take me where it wants to. That may sound a bit ridiculous and performance-intensive, but it honestly works pretty well if you know what you're doing with the framework you're using. A lot of the code in this game is put together somewhat hackily. A lot of hard references to certain items and tile types (like how bombs can only turn grass into dirt and nothing else), a lot of messy utility functions all bunched together into a single class, very little documentation and abstract methods, hub interfaces for things that do similar things, and so on. But that's fine, because this isn't a huge project and I don't plan on adding complicated systems like a modding API or anything like that, so it'd be unnecessary to waste my time on doing something overly fancy.
|
||||
|
||||
For example, the map parsing system is really simple: It consists of an XML file, which stores all the important information about a map like its name and the positions that players spawn in, and a png file.
|
||||
|
||||
<img src="/blog/res/small_projects/map.png" width="100%">
|
||||
|
||||
Each pixel in the file determines which tile will be put at its location. In this instance, black is deep water, blue is shallow water, yellow is sand and green is grass. And the cool thing is that this is really easy to deal with (reading pixels is a simple thing that's present in almost every game framework), because changing something on the map just takes an image editing program, no custom map editor needed.
|
||||
|
||||
# The Gameplay
|
||||
For some of the other games I've worked on, I've always had huge plans to start with. I had this one plan to make a big Animal Crossing-style game with real time progression, tons of NPCs, a lot of complicated gameplay mechanics. I'd worked on a game for over two years that was an open world sandbox, and it was supposed to have a huge story with optional, skippable elements, and... honestly, it's hard to actually make all that happen, at least for me. At some point, I just start looking at it from a different perspective and thinking to myself "Why did I take on such a huge project? This is impossible." and that makes me lose motivation.
|
||||
|
||||
So for Foe Frenzy, I went with a really simple concept that consists of a small amount of clearly definable main points:
|
||||
- Up to four players on a local computer, controlled by keyboard and gamepads
|
||||
- Predefined maps that the players can choose
|
||||
- Item spawners that spawn random items to battle or protect yourself with, where each of the items only lasts for a short time, so you have to keep going back and getting new ones
|
||||
- Kill all the other players to win
|
||||
|
||||
Because I had this clear plan in mind before starting the game, and because it's really not that much to do (I've been working on the game for a month, and all that's left to do is add more maps and more items to battle with), it's been easy to stay on track and stay focused rather than burning out because of responsibility overload.
|
||||
|
||||
# So yea...
|
||||
that's what I've been doing for the last month, and that's why [my other projects](https://minecraft.curseforge.com/projects/natures-aura) have been suffering a little bit. But it's been really fun, and I might even have something to actually release as a real, finished game some time in the near-ish future. It's also been making me feel accomplished, because I've already been able to have my friends test the game out, and they say it's been fun which means that I already accomplished a big part of what I wanted to accomplish with this game.
|
||||
|
||||
Keep updated about the game on [my Discord](https://ellpeck.de/discord) as well as [my Twitter](https://twitter.com/Ellpeck), and I hope you enjoyed reading about the game and my development process so far.
|
||||
|
||||
To finish off, here are some more pictures of the game for your enjoyment.
|
||||
|
||||
<img src="/blog/res/small_projects/cave.png" width="100%">
|
||||
A cave being lit up by torches and lava. This is where a rubber hammer can spawn that you can use to knock the other players into the lava.
|
||||
|
||||
<img src="/blog/res/small_projects/map_select.png" width="100%">
|
||||
The map selection screen, where each player can choose the map that they'd like to play most.
|
||||
|
||||
<img src="/blog/res/small_projects/flame_thrower.gif" width="100%">
|
||||
The favorite item I've added so far: The flamethrower.
|
||||
|
||||
<img src="/blog/res/small_projects/win.gif" width="100%">
|
||||
Killing the last person alive and winning
|
||||
---
|
||||
layout: blog
|
||||
title: 🗡️ Small Projects
|
||||
description: Why creating a small, unplanned project is sometimes good for you
|
||||
tags: [Programming]
|
||||
discuss: https://twitter.com/Ellpeck/status/1123651624201871360
|
||||
---
|
||||
|
||||
As it turns out, I struggle a lot with maintaining interest and motivation for working on bigger projects like my [other game](https://rockbottom.ellpeck.de/) or my Minecraft mods. However, an easy fix for that would be to just start less big projects and focus more on smaller ones, like **Foe Frenzy**. Foe Frenzy is a game I've been working on for about a month now.
|
||||
|
||||
![](contrib.png)
|
||||
|
||||
The basic gameplay is finished, as is enough content for my friends to have been testing it for the last week or so and saying that they enjoy it quite a bit, both visually and gameplay-wise. I thought I'd make a blog post about my process of working on it, showing what it's about and what I did this time around to make sure that I don't get burnt out with it.
|
||||
|
||||
![](overview.png)
|
||||
|
||||
_Foe Frenzy is a fast-paced fighting game where you battle up to three of your friends with random, short-lasting items in an attempt to be the last survivor._
|
||||
|
||||
# The Artstyle
|
||||
Not every developer has this problem, but I know a lot do: The inability to make good-looking art. Well, I have this same problem too.
|
||||
A lot of times, I'll find myself getting stuck on making art for my game projects and getting burnt out through trying too hard to force myself to make good-looking art.
|
||||
|
||||
So, this time around, what I did instead of doing that all over again, I just decided to go with _simple art_ instead. For example, as you can see, all the tiles in the world only have 8x8 pixels, and all of them follow a really simple pattern: The top and left side are slightly darker, giving the world a really tiled feel and making the levels seem like they were made with actual building bricks. As well as that, the character movement animations are _really_ simple.
|
||||
|
||||
![](wobble.gif)
|
||||
|
||||
![](water_wobble.gif)
|
||||
|
||||
Both of those aren't even real animations per se, because what they really are is just the player's static texture rotating around a sin wave that is centered on the player's feet. It looks cute, though.
|
||||
|
||||
# The Inner Workings
|
||||
Whenever I write code, I tend to try to overoptimize it a lot. What I mean by that is that I think about systems that I want to implement too intricately sometimes. For instance, if I want to make a tile-based game, I obviously set up some data structures around tiles and how they're going to be ordered and stored on the map. But then, I'll also go and write a bunch of utility methods, conversion functions, figure out a really in-depth coordinate system for dynamic objects, and so on. And, honestly, for projects that aren't too big, all of that isn't really necessary.
|
||||
|
||||
What I did for this game instead is just kind of... let the code take me where it wants to. That may sound a bit ridiculous and performance-intensive, but it honestly works pretty well if you know what you're doing with the framework you're using. A lot of the code in this game is put together somewhat hackily. A lot of hard references to certain items and tile types (like how bombs can only turn grass into dirt and nothing else), a lot of messy utility functions all bunched together into a single class, very little documentation and abstract methods, hub interfaces for things that do similar things, and so on. But that's fine, because this isn't a huge project and I don't plan on adding complicated systems like a modding API or anything like that, so it'd be unnecessary to waste my time on doing something overly fancy.
|
||||
|
||||
For example, the map parsing system is really simple: It consists of an XML file, which stores all the important information about a map like its name and the positions that players spawn in, and a png file.
|
||||
|
||||
![](map.png)
|
||||
|
||||
Each pixel in the file determines which tile will be put at its location. In this instance, black is deep water, blue is shallow water, yellow is sand and green is grass. And the cool thing is that this is really easy to deal with (reading pixels is a simple thing that's present in almost every game framework), because changing something on the map just takes an image editing program, no custom map editor needed.
|
||||
|
||||
# The Gameplay
|
||||
For some of the other games I've worked on, I've always had huge plans to start with. I had this one plan to make a big Animal Crossing-style game with real time progression, tons of NPCs, a lot of complicated gameplay mechanics. I'd worked on a game for over two years that was an open world sandbox, and it was supposed to have a huge story with optional, skippable elements, and... honestly, it's hard to actually make all that happen, at least for me. At some point, I just start looking at it from a different perspective and thinking to myself "Why did I take on such a huge project? This is impossible." and that makes me lose motivation.
|
||||
|
||||
So for Foe Frenzy, I went with a really simple concept that consists of a small amount of clearly definable main points:
|
||||
- Up to four players on a local computer, controlled by keyboard and gamepads
|
||||
- Predefined maps that the players can choose
|
||||
- Item spawners that spawn random items to battle or protect yourself with, where each of the items only lasts for a short time, so you have to keep going back and getting new ones
|
||||
- Kill all the other players to win
|
||||
|
||||
Because I had this clear plan in mind before starting the game, and because it's really not that much to do (I've been working on the game for a month, and all that's left to do is add more maps and more items to battle with), it's been easy to stay on track and stay focused rather than burning out because of responsibility overload.
|
||||
|
||||
# So yea...
|
||||
that's what I've been doing for the last month, and that's why [my other projects](https://minecraft.curseforge.com/projects/natures-aura) have been suffering a little bit. But it's been really fun, and I might even have something to actually release as a real, finished game some time in the near-ish future. It's also been making me feel accomplished, because I've already been able to have my friends test the game out, and they say it's been fun which means that I already accomplished a big part of what I wanted to accomplish with this game.
|
||||
|
||||
Keep updated about the game on [my Discord](https://ellpeck.de/discord) as well as [my Twitter](https://twitter.com/Ellpeck), and I hope you enjoyed reading about the game and my development process so far.
|
||||
|
||||
To finish off, here are some more pictures of the game for your enjoyment.
|
||||
|
||||
![](cave.png)
|
||||
A cave being lit up by torches and lava. This is where a rubber hammer can spawn that you can use to knock the other players into the lava.
|
||||
|
||||
![](map_select.png)
|
||||
The map selection screen, where each player can choose the map that they'd like to play most.
|
||||
|
||||
![](flame_thrower.gif)
|
||||
The favorite item I've added so far: The flamethrower.
|
||||
|
||||
![](win.gif)
|
||||
Killing the last person alive and winning
|
Before Width: | Height: | Size: 112 KiB After Width: | Height: | Size: 112 KiB |
Before Width: | Height: | Size: 7.3 KiB After Width: | Height: | Size: 7.3 KiB |
Before Width: | Height: | Size: 158 KiB After Width: | Height: | Size: 158 KiB |
Before Width: | Height: | Size: 2.5 KiB After Width: | Height: | Size: 2.5 KiB |
Before Width: | Height: | Size: 126 KiB After Width: | Height: | Size: 126 KiB |
Before Width: | Height: | Size: 81 KiB After Width: | Height: | Size: 81 KiB |
Before Width: | Height: | Size: 121 KiB After Width: | Height: | Size: 121 KiB |
Before Width: | Height: | Size: 4.3 MiB After Width: | Height: | Size: 4.3 MiB |
Before Width: | Height: | Size: 96 KiB After Width: | Height: | Size: 96 KiB |
|
@ -1,190 +1,190 @@
|
|||
---
|
||||
layout: blog
|
||||
title: 🤡 One Year of Tiny Life, and Cursed Comment Time
|
||||
description: It's been exactly one year since I started working on my isometric Sims-style life simulation game Tiny Life, and since then, a lot has happened, especially in the realm of weird, funny and cursed comments in the code.
|
||||
tags: [Programming, Featured]
|
||||
discuss: https://ellpeck.itch.io/tiny-life/devlog/256839/one-year-of-tiny-life-and-cursed-comment-time
|
||||
---
|
||||
|
||||
On this day, exactly one year ago, I made my first commit to the Tiny Life repository. Since that first commit, which included some code for the isometric perspective that the game uses, Tiny Life has come *a long way*.
|
||||
|
||||
<img src="/blog/res/tiny_life_one_year/commit.png" width="100%">
|
||||
|
||||
If you don't recall just how long of a way it has come, or you don't even know about the game yet: Tiny Life is, as I wrote on its [itch page](https://ellpeck.itch.io/tiny-life):
|
||||
|
||||
> Tiny Life is a fun simulation game that tries to capture the essence of games like The Sims, but in an isometric pixelart style.
|
||||
>
|
||||
> In the game, you control a set of people that live together in a household. You take care of their daily needs, build their skills, forge new relationships... or just mess up their entire life in whatever way you can think of!
|
||||
|
||||
So, to celebrate, and because of a Twitter poll I did a while ago that made it clear that yall are interested in something like this, let's go through Tiny Life's current code and fish out some funny, cursed and weird code comments that just naturally come about when making a game that tries to simulate the personalities and behaviors of human people.
|
||||
|
||||
While this blog post *does* include a lot of programming-related humor, most of the comments are still funny and a bit ridiculous out of context, so you don't have to be a programmer to laugh along by any means.
|
||||
|
||||
<img src="/blog/res/tiny_life_one_year/search.png" width="100%">
|
||||
|
||||
That should do for now. *Oh, boy.* Note that I'll just be going through them using the order they appear in these search results, so the funniest ones won't be at the start or the end, but just... somewhere in between.
|
||||
|
||||
First up, this is one that most of you will probably find pretty relatable.
|
||||
```cs
|
||||
// we want people to clean dishes when they're hungry to make space for food
|
||||
Ai = {
|
||||
SolvedNeeds = new[] {NeedType.Hunger},
|
||||
}
|
||||
```
|
||||
|
||||
This one is for the introverts (to whom I most certainly belong) out there.
|
||||
```cs
|
||||
// we only want to visit someone when we're currently at home for long enough
|
||||
if (a)
|
||||
return i.Person.LotVisitCooldown <= TimeSpan.Zero && i.Person.LastVisitedLot == i.Person.HomeLot ? Valid : Hidden;
|
||||
|
||||
```
|
||||
|
||||
Teenagers should probably remember this one. Consent is (very unironically) important, yall!
|
||||
```cs
|
||||
// automatic romance interactions should only happen if we're already romantic towards each other
|
||||
return relationship?.RomanceLevel > 0 ? Valid : Hidden;
|
||||
```
|
||||
|
||||
Fair enough.
|
||||
```cs
|
||||
// eat food if we're hungry
|
||||
if (person.GetNeedPercentage(NeedType.Hunger) <= 0.5F && obj.ServingSize <= 1)
|
||||
return ActionType.Eat.Construct(person.GetHeldActionInfo());
|
||||
```
|
||||
|
||||
Especially in the city! Don't linger around too long, kids.
|
||||
```cs
|
||||
// move to the sidewalk once we're done driving
|
||||
var road = this.Map.GetClosestRoad(car.Position.ToPoint(), Map.RoadRadius + 1);
|
||||
```
|
||||
|
||||
You: Oh no, my car broke down!
|
||||
Me:
|
||||
```cs
|
||||
// if the driving fails, we always want to walk to the goal in the end
|
||||
return base.ShouldFail(completedAction, completion) && completedAction is not DriveAction;
|
||||
```
|
||||
|
||||
Do yall also do this thing where you're like "I cleaned *a single dish*, now I can take a break"?
|
||||
```cs
|
||||
// should we start to take a break between actions?
|
||||
if (this.OnBetweenActions(time, passedInGame, speed, current, completion)) {
|
||||
this.isBetweenActions = true;
|
||||
return true;
|
||||
}
|
||||
```
|
||||
|
||||
It might be sad to hear, but this is something *you* have to do as well.
|
||||
```cs
|
||||
// we want to prioritize going to work over sleeping automatically
|
||||
if (this.StartedAutomatically && this.Person.Job != null && this.Person.Job.Type.IsTimeToWork(GameImpl.Instance.CurrentTime + TimeSpan.FromHours(1)))
|
||||
return CompletionType.Canceled;
|
||||
```
|
||||
|
||||
A bit creepy, don't you think?
|
||||
```cs
|
||||
// follow our partner until we reach them
|
||||
if (this.IsMain) {
|
||||
this.followTimer -= time.ElapsedGameTime;
|
||||
```
|
||||
|
||||
Jesus Christ, mom, how many more times do you want to tell me that *same story*?
|
||||
```cs
|
||||
// we add the recent social to the relationship of the recipient
|
||||
// so it represents an "I've heard this story already" list
|
||||
relationship.AddRecentSocial(action.Type);
|
||||
```
|
||||
|
||||
Also... fair enough.
|
||||
```cs
|
||||
// make lots more interesting if we have friends on them
|
||||
lot = Random.GetRandomWeightedEntry(lots, l => l.Type.GetVisitPriority(l, this.Person));
|
||||
```
|
||||
|
||||
It really *is* based on our mood how efficiently we work.
|
||||
```cs
|
||||
// if we're currently working, we should increase job performance based on our mood
|
||||
var performance = this.Person.Needs.Values.Count(n => n.Percentage >= 0.75F) * 0.004F;
|
||||
```
|
||||
|
||||
Does this also apply to *sleepovers*?
|
||||
```cs
|
||||
// the bed that we last slept in should be the one we try to sleep in again
|
||||
if (this.HasCategory(person, ObjectCategory.Bed) && categories.HasFlag(ObjectCategory.Bed) && this.Id == person.LastBedSleptIn)
|
||||
return 10;
|
||||
```
|
||||
|
||||
Fair... enough.
|
||||
```cs
|
||||
// pee puddles should be more disgusting
|
||||
DecorativeRating = f => f.Colors[0] == 1 ? -30 : -10
|
||||
```
|
||||
|
||||
For this one, I especially like that I chose to name the variable `naked`.
|
||||
```cs
|
||||
// if someone isn't wearing pants and they aren't romantic with us, we should get (them) embarrassed
|
||||
var naked = room.GetObjects<Person>()
|
||||
.Where(p => p != this && p.GetRelationship(this, false)?.RomancePercentage < 0.25F && !p.WornLayers.HasFlag(ClothesLayer.Pants))
|
||||
.ToArray();
|
||||
```
|
||||
|
||||
This comment is, of course, in the `Person.Die` method.
|
||||
```cs
|
||||
// make friends sad
|
||||
foreach (var rel in this.Relationships) {
|
||||
```
|
||||
|
||||
You: I'm bored!
|
||||
Me:
|
||||
```cs
|
||||
// if we don't have anything else to do, also try random actions
|
||||
if (this.person.ActionQueue.Count <= 0 && this.person.CurrentActions.Count <= 0)
|
||||
avail.AddRange(RandomActions);
|
||||
```
|
||||
|
||||
Drunk people, anyone?
|
||||
```cs
|
||||
// don't do stuff that's inappropriate here
|
||||
if (type.Settings.IsInappropriateElsewhere) {
|
||||
```
|
||||
|
||||
Am I wrong? I say no.
|
||||
```cs
|
||||
// the front door is the closest door to the mailbox that connects outside and inside
|
||||
var mailbox = this.GetObjects<Furniture>().FirstOrDefault(f => f.Type == FurnitureType.Mailbox);
|
||||
```
|
||||
|
||||
Oh no, I *really* hope it isn't.
|
||||
```cs
|
||||
// is it just turning monday now?
|
||||
var game = GameImpl.Instance;
|
||||
if (game.Weekday == DayOfWeek.Sunday && (game.CurrentTime + passedInGame).Days != game.CurrentTime.Days) {
|
||||
```
|
||||
|
||||
Clearly.
|
||||
```cs
|
||||
// if we're not loading from disk, we want to replace the floor with concrete
|
||||
if (initializeRooms) {
|
||||
```
|
||||
|
||||
*Am I wrong?*
|
||||
```cs
|
||||
// drywall should be considered ugly
|
||||
if (wall.Wallpapers[side].BaseName == "Default")
|
||||
rating--;
|
||||
```
|
||||
|
||||
I said it once (multiple times, actually), and I'll say it again: *Am I wrong?*
|
||||
```cs
|
||||
// energetic people should be able to stay awake longer than others
|
||||
public static readonly NeedType Energy = Register(new NeedType("Energy", 0.5F, p => ActionType.PassOut, p => p.HasPersonality(PersonalityType.Energetic) ? TimeSpan.FromHours(1) : TimeSpan.Zero, 10));
|
||||
```
|
||||
|
||||
There we go, that's most of the funny human-related comments I could find with the very simple search I did. I definitely think some of these are *very funny* out of context, but what makes it even better is that some of them are also pretty funny *in* context. Humans really do act very weirdly sometimes, don't they?
|
||||
|
||||
All of that being said, thanks so much for reading this blog post. If you haven't already, you should definitely check out the game, as it is very much a passion project of mine, and I think it currently has enough content to be quite a bit of fun to play already.
|
||||
|
||||
You can download the game for free (or for a price of your choosing) on its [itch page](https://ellpeck.itch.io/tiny-life).
|
||||
|
||||
❤, everyone.
|
||||
---
|
||||
layout: blog
|
||||
title: 🤡 One Year of Tiny Life, and Cursed Comment Time
|
||||
description: It's been exactly one year since I started working on my isometric Sims-style life simulation game Tiny Life, and since then, a lot has happened, especially in the realm of weird, funny and cursed comments in the code.
|
||||
tags: [Programming, Featured]
|
||||
discuss: https://ellpeck.itch.io/tiny-life/devlog/256839/one-year-of-tiny-life-and-cursed-comment-time
|
||||
---
|
||||
|
||||
On this day, exactly one year ago, I made my first commit to the Tiny Life repository. Since that first commit, which included some code for the isometric perspective that the game uses, Tiny Life has come *a long way*.
|
||||
|
||||
![](commit.png)
|
||||
|
||||
If you don't recall just how long of a way it has come, or you don't even know about the game yet: Tiny Life is, as I wrote on its [itch page](https://ellpeck.itch.io/tiny-life):
|
||||
|
||||
> Tiny Life is a fun simulation game that tries to capture the essence of games like The Sims, but in an isometric pixelart style.
|
||||
>
|
||||
> In the game, you control a set of people that live together in a household. You take care of their daily needs, build their skills, forge new relationships... or just mess up their entire life in whatever way you can think of!
|
||||
|
||||
So, to celebrate, and because of a Twitter poll I did a while ago that made it clear that yall are interested in something like this, let's go through Tiny Life's current code and fish out some funny, cursed and weird code comments that just naturally come about when making a game that tries to simulate the personalities and behaviors of human people.
|
||||
|
||||
While this blog post *does* include a lot of programming-related humor, most of the comments are still funny and a bit ridiculous out of context, so you don't have to be a programmer to laugh along by any means.
|
||||
|
||||
![](search.png)
|
||||
|
||||
That should do for now. *Oh, boy.* Note that I'll just be going through them using the order they appear in these search results, so the funniest ones won't be at the start or the end, but just... somewhere in between.
|
||||
|
||||
First up, this is one that most of you will probably find pretty relatable.
|
||||
```cs
|
||||
// we want people to clean dishes when they're hungry to make space for food
|
||||
Ai = {
|
||||
SolvedNeeds = new[] {NeedType.Hunger},
|
||||
}
|
||||
```
|
||||
|
||||
This one is for the introverts (to whom I most certainly belong) out there.
|
||||
```cs
|
||||
// we only want to visit someone when we're currently at home for long enough
|
||||
if (a)
|
||||
return i.Person.LotVisitCooldown <= TimeSpan.Zero && i.Person.LastVisitedLot == i.Person.HomeLot ? Valid : Hidden;
|
||||
|
||||
```
|
||||
|
||||
Teenagers should probably remember this one. Consent is (very unironically) important, yall!
|
||||
```cs
|
||||
// automatic romance interactions should only happen if we're already romantic towards each other
|
||||
return relationship?.RomanceLevel > 0 ? Valid : Hidden;
|
||||
```
|
||||
|
||||
Fair enough.
|
||||
```cs
|
||||
// eat food if we're hungry
|
||||
if (person.GetNeedPercentage(NeedType.Hunger) <= 0.5F && obj.ServingSize <= 1)
|
||||
return ActionType.Eat.Construct(person.GetHeldActionInfo());
|
||||
```
|
||||
|
||||
Especially in the city! Don't linger around too long, kids.
|
||||
```cs
|
||||
// move to the sidewalk once we're done driving
|
||||
var road = this.Map.GetClosestRoad(car.Position.ToPoint(), Map.RoadRadius + 1);
|
||||
```
|
||||
|
||||
You: Oh no, my car broke down!
|
||||
Me:
|
||||
```cs
|
||||
// if the driving fails, we always want to walk to the goal in the end
|
||||
return base.ShouldFail(completedAction, completion) && completedAction is not DriveAction;
|
||||
```
|
||||
|
||||
Do yall also do this thing where you're like "I cleaned *a single dish*, now I can take a break"?
|
||||
```cs
|
||||
// should we start to take a break between actions?
|
||||
if (this.OnBetweenActions(time, passedInGame, speed, current, completion)) {
|
||||
this.isBetweenActions = true;
|
||||
return true;
|
||||
}
|
||||
```
|
||||
|
||||
It might be sad to hear, but this is something *you* have to do as well.
|
||||
```cs
|
||||
// we want to prioritize going to work over sleeping automatically
|
||||
if (this.StartedAutomatically && this.Person.Job != null && this.Person.Job.Type.IsTimeToWork(GameImpl.Instance.CurrentTime + TimeSpan.FromHours(1)))
|
||||
return CompletionType.Canceled;
|
||||
```
|
||||
|
||||
A bit creepy, don't you think?
|
||||
```cs
|
||||
// follow our partner until we reach them
|
||||
if (this.IsMain) {
|
||||
this.followTimer -= time.ElapsedGameTime;
|
||||
```
|
||||
|
||||
Jesus Christ, mom, how many more times do you want to tell me that *same story*?
|
||||
```cs
|
||||
// we add the recent social to the relationship of the recipient
|
||||
// so it represents an "I've heard this story already" list
|
||||
relationship.AddRecentSocial(action.Type);
|
||||
```
|
||||
|
||||
Also... fair enough.
|
||||
```cs
|
||||
// make lots more interesting if we have friends on them
|
||||
lot = Random.GetRandomWeightedEntry(lots, l => l.Type.GetVisitPriority(l, this.Person));
|
||||
```
|
||||
|
||||
It really *is* based on our mood how efficiently we work.
|
||||
```cs
|
||||
// if we're currently working, we should increase job performance based on our mood
|
||||
var performance = this.Person.Needs.Values.Count(n => n.Percentage >= 0.75F) * 0.004F;
|
||||
```
|
||||
|
||||
Does this also apply to *sleepovers*?
|
||||
```cs
|
||||
// the bed that we last slept in should be the one we try to sleep in again
|
||||
if (this.HasCategory(person, ObjectCategory.Bed) && categories.HasFlag(ObjectCategory.Bed) && this.Id == person.LastBedSleptIn)
|
||||
return 10;
|
||||
```
|
||||
|
||||
Fair... enough.
|
||||
```cs
|
||||
// pee puddles should be more disgusting
|
||||
DecorativeRating = f => f.Colors[0] == 1 ? -30 : -10
|
||||
```
|
||||
|
||||
For this one, I especially like that I chose to name the variable `naked`.
|
||||
```cs
|
||||
// if someone isn't wearing pants and they aren't romantic with us, we should get (them) embarrassed
|
||||
var naked = room.GetObjects<Person>()
|
||||
.Where(p => p != this && p.GetRelationship(this, false)?.RomancePercentage < 0.25F && !p.WornLayers.HasFlag(ClothesLayer.Pants))
|
||||
.ToArray();
|
||||
```
|
||||
|
||||
This comment is, of course, in the `Person.Die` method.
|
||||
```cs
|
||||
// make friends sad
|
||||
foreach (var rel in this.Relationships) {
|
||||
```
|
||||
|
||||
You: I'm bored!
|
||||
Me:
|
||||
```cs
|
||||
// if we don't have anything else to do, also try random actions
|
||||
if (this.person.ActionQueue.Count <= 0 && this.person.CurrentActions.Count <= 0)
|
||||
avail.AddRange(RandomActions);
|
||||
```
|
||||
|
||||
Drunk people, anyone?
|
||||
```cs
|
||||
// don't do stuff that's inappropriate here
|
||||
if (type.Settings.IsInappropriateElsewhere) {
|
||||
```
|
||||
|
||||
Am I wrong? I say no.
|
||||
```cs
|
||||
// the front door is the closest door to the mailbox that connects outside and inside
|
||||
var mailbox = this.GetObjects<Furniture>().FirstOrDefault(f => f.Type == FurnitureType.Mailbox);
|
||||
```
|
||||
|
||||
Oh no, I *really* hope it isn't.
|
||||
```cs
|
||||
// is it just turning monday now?
|
||||
var game = GameImpl.Instance;
|
||||
if (game.Weekday == DayOfWeek.Sunday && (game.CurrentTime + passedInGame).Days != game.CurrentTime.Days) {
|
||||
```
|
||||
|
||||
Clearly.
|
||||
```cs
|
||||
// if we're not loading from disk, we want to replace the floor with concrete
|
||||
if (initializeRooms) {
|
||||
```
|
||||
|
||||
*Am I wrong?*
|
||||
```cs
|
||||
// drywall should be considered ugly
|
||||
if (wall.Wallpapers[side].BaseName == "Default")
|
||||
rating--;
|
||||
```
|
||||
|
||||
I said it once (multiple times, actually), and I'll say it again: *Am I wrong?*
|
||||
```cs
|
||||
// energetic people should be able to stay awake longer than others
|
||||
public static readonly NeedType Energy = Register(new NeedType("Energy", 0.5F, p => ActionType.PassOut, p => p.HasPersonality(PersonalityType.Energetic) ? TimeSpan.FromHours(1) : TimeSpan.Zero, 10));
|
||||
```
|
||||
|
||||
There we go, that's most of the funny human-related comments I could find with the very simple search I did. I definitely think some of these are *very funny* out of context, but what makes it even better is that some of them are also pretty funny *in* context. Humans really do act very weirdly sometimes, don't they?
|
||||
|
||||
All of that being said, thanks so much for reading this blog post. If you haven't already, you should definitely check out the game, as it is very much a passion project of mine, and I think it currently has enough content to be quite a bit of fun to play already.
|
||||
|
||||
You can download the game for free (or for a price of your choosing) on its [itch page](https://ellpeck.itch.io/tiny-life).
|
||||
|
||||
❤, everyone.
|
Before Width: | Height: | Size: 22 KiB After Width: | Height: | Size: 22 KiB |
Before Width: | Height: | Size: 8.5 KiB After Width: | Height: | Size: 8.5 KiB |
|
@ -242,6 +242,11 @@ pre.highlight {
|
|||
margin-top: 20px;
|
||||
}
|
||||
|
||||
.post-content img {
|
||||
width: 100%;
|
||||
height: auto;
|
||||
}
|
||||
|
||||
@media(max-width: 1199px) {
|
||||
.blog-title {
|
||||
margin-top: 15px;
|
||||
|
|