Renoria is a 2D-Sidescroller MMORPG written in Java based on LWJGL. It has been in development since 2008 but I put development on hold from 2010-2013 and I’ve started on the development of it again.
This has been my first project in Java and I started writing it when I was 14 (I’m 19 now).
Yep. You need to consider this from the start, because there are many features or additions that you might add that won’t work well in a synchronized network environment (think latency, network delays, synchronization etc.)
My next features will be addition of skills, buffs, monster powerups, character emotes, and other nice little effects in the game (think underwater lens, heat haze, etc). Also the programming of boss monsters that have special attacks and special features, such as spawning minions, special attacks and special rewards from killing bosses, oh and lastly I’m going to build a quest scripting system and cinematic scripting system (for cutscenes).
I’m also rewriting the main part of the engine for easy portability to other languages, for example Objective-C and C++ so the game can easily be moved onto iPads and other devices.
And I already kinda have a heat haze effect going:
Since you are doing it in Java2D, you can give the text a 3D look very easily. Just draw the text twice, once in black and then in white with some small offset, and it looks so cool. Also nice game. I want to see the code of engine, Can I? I also would like to test the game.
Haha, yeah it’s just there as a debug console
I’m using it to debug messages from the server, you can see messages like Vertical Difference (which is a method I use to test for hackers that do things like Fly hacking or jumping through platforms that they shouldn’t be able to.)
Yep, I’ll probably end up doing that eventually. I can post parts of the engine source upon request, but I won’t be posting the entire source to the client or server(s) (for obvious reasons)
Thank you! I’ll sign you up for Alpha when its ready!
Will definitely sign you up to Alpha too!
UPDATE:
Close range melee attacks are now handled by remote clients instead of being frame-by-frame transmitted by the server. Has the advantage of the illusion of decreased latency, and better timing & accuracy
Ranged attacks are now handled via a timer on the client instead of being run on the server. Same advantage applies above. MirrorRNG is used to display instantaneous damage instead of waiting for a damage number from the server. Basically the client and server carry a RNG with the same seed (sent from the server upon login) and this is used to randomise damage, and it also ensures both numbers generated by the server and client are in sync.
Rewote the MirrorRNG to use MersenneTwister instead of java.util.Random - would ease porting to other platforms later on.
Rewrote the packet encryption scheme to use BouncyCastle instead of JCE.
Clients will now only use the last 10 movement reference frames for object extrapolation, discarding the rest.
Source code for rendering characters if interested:
// providers
private CharacterPartsProvider skinProvider = null;
private EnumMap<EquipSlot, CharacterPartsProvider> equipsProvider = new EnumMap(EquipSlot.class);
private CharacterPartsProvider hairProvider = null;
private CharacterPartsProvider faceProvider = null;
// rendering stuff
private Set<CharacterPart> currentParts = new TreeSet<CharacterPart>(CHAR_PART_Z_COMPARATOR);
private CharacterStance lastRenderedStance = null;
private int lastFrame = -1;
private boolean partsDirty = false;
///////////////////////////////////////////////////////////////////////////
static final Comparator<CharacterPart> CHAR_PART_Z_COMPARATOR = new Comparator<CharacterPart>() {
public int compare(CharacterPart o1, CharacterPart o2) {
return o1.z - o2.z;
}
};
@Override
public void doRender(RenderSpace g) {
if (morph != null) {
morph.doRender(this, g);
return;
}
if (lastRenderedStance != stance || lastFrame != frame || partsDirty) {
currentParts.clear();
// provide skin
skinProvider.provide(currentParts, stance, frame);
// provide hair
if (hairProvider != null) {
hairProvider.provide(currentParts, stance, frame);
}
if (faceProvider != null) {
faceProvider.provide(currentParts, stance, frame);
}
// provide equips
for (final CharacterPartsProvider provider : equipsProvider.values()) {
provider.provide(currentParts, stance, frame);
}
// set state
lastRenderedStance = stance;
lastFrame = frame;
partsDirty = false;
}
this.update();
this.constrainFrame();
if (renoria.Core.systemTime() - getLastTalk() > 3500) {
chatBubble = null;
}
Rectangle r = getArea();
boolean flip = direction == ObjectDirection.RIGHT && !noFlip();
for (Iterator<CharacterPart> i = currentParts.iterator(); i.hasNext();) {
CharacterPart part = i.next();
int charX = x + r.width/2 - Core.view.x;
int charY = y + r.height - Core.view.y;
part.draw(charX, charY, g, flip);
}
// [EFFECTS]
for (int i = 0; i < effects.size(); i++) {
effects.get(i).doRender(g);
}
// [END EFFECTS]
//drawDebugBoundaries(g);
}
Basically characters are composed up from parts, for example arm, body, head, weapon, etc and this code does the Z-layering and providing for me. Providers are shared between characters, so if char1 and char2 are wearing the same weapon, they will be attached to the same provider. (Saves memory)
RenderSpace is a class I devised as an abstraction between Java2D and JOGL, but it can be extended to any Java API that can do rendering, for example LWJGL.
I just didn’t do the [icode]toCompatibleImage()[/icode] part. Without that, I’ve got 302 fps on my old laptop without a graphics card.
Now I had got a pc with an NVIDIA card and it boosted upto 750 fps. I didn’t had the same example now but I’ll try by including that fix. Would have to try. Thanks.
EDIT:
I thought I’ve lost the code, but it’s present in my backups. I’ll test it tomorrow morning.
I don’t quite understand why you’d want more than 60 FPS to be honest, most monitors only refresh at 60Hz anyway so any subsequent updates you write to the frame buffer won’t even be seen by the user?
Am not saying that I want more fps. This fps is for a game where there is only one screen with a very few objects. And if I keep on increasing the number of objects, it gets too less. You are asking why more than 60, right? Try to answer why not more? Nowadays, we’re having more processing powers, more graphics power, so the best bet is to do required amount of logic updates and always try to use the remaining time to get very high fps. I’ll calculate the collisions every frame and so I can have much smoother game play and a very fast collision response.
You need to check whether your bottleneck is in Java2D or your other logic code
When Java2D is used correctly it can yield super fast framerates as you can see, I think converting the buffered images to the device native format will give you a considerable speed boost.
Either way, I don’t try to render higher than 80 FPS. My code has a Thread.sleep( ) that will limit the framerate to 80 FPS. Without the sleep it can yield higher framerates, but I just don’t see the need for a super high framerate.
It’s a bit like saying we have 32 bit color but why not 64 bit color? Because the human eye can only distinguish about 4 billion different colours, therefore more would be pointless.
Same thing applies to FPS. I say 60 FPS is the sweet spot.
King Frost Dragon now has special attacks like the following:
Let me know what you think of our animations!
Attack1: Tail whip, stuns everyone standing on the ground, attack+5000, shakes the map.
Attack2: Fire breath, shoots dragonfire that will burn anyone it hits, damage over time for 30 seconds.
All this is perfectly synchronized between clients (ie Player1 and Player2 will see the same attack animation at the exact same time, assuming no latency)