Dxu1994
|
 |
«
Posted
2013-10-16 08:19:13 » |
|
  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). FACEBOOK: https://www.facebook.com/RenoriaOfficialINDIEDB: http://www.indiedb.com/games/renoriaTechnical details (client): - Renderer: Java2D / LWJGL / Android GLSurfaceView
- Audio: JavaSound
- Networking: Java NIO
- Engine: Ux2Engine
(Game engine is extremely optimised, runs 10K+ objects at 60fps.)  Technical details (server): - Architecture: distributed
- Networking: Java NIO
- Technology: Java Server
NOTE: WE ARE CURRENTLY ACCEPTING ALPHA TESTING REGISTRATIONS AT: http://ux-soft.com/renoria/
FEATURES:
- Create your own story! Do whatever you want!
- Fight monsters, level up!
- Mine rocks, forge your own weapons and armors!
- Shear sheep, spin thread, create your own clothes!
- Got a gold bar, hammer and jewel? Create your own jewelry!
SUPPORTED PLATFORMS:- Windows
- Mac OSX
- Linux, *Nix
- Android Tablets - Soon to come
- iPad - Soon to come
Screenshots:  
|
|
|
|
dime26
|
 |
«
Reply #1 - Posted
2013-10-16 08:34:45 » |
|
Looks great, I am thinking about adding network/multi play to my game, is it best to consider this form the outset?
Also what are you next features going to be?
|
|
|
|
Dxu1994
|
 |
«
Reply #2 - Posted
2013-10-16 08:46:11 » |
|
Looks great, I am thinking about adding network/multi play to my game, is it best to consider this form the outset?
Also what are you next features going to be?
Thank you! 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: 
|
|
|
|
Games published by our own members! Check 'em out!
|
|
Dxu1994
|
 |
«
Reply #3 - Posted
2013-10-17 09:30:37 » |
|
UPDATE: Rewrote main rendering part of graphics engine. Now handling 10K monsters on the map at a time at a nice 60-80 FPS (with debug data enabled):  Running on Java2D, JRE6 Also prettier character editing tool: 
|
|
|
|
Dxu1994
|
 |
«
Reply #4 - Posted
2013-10-18 20:35:16 » |
|
UPDATE: - Characters now have face, hair, and can wear equipments
- Ranged attacks (arrows & throwing stars) are now coded and work. They're also perfectly synchronized between clients.
Throwing stars: 
|
|
|
|
gouessej
|
 |
«
Reply #5 - Posted
2013-10-18 21:50:39 » |
|
Hi I'd like to give it a try as soon as possible. Keep up the good work 
|
|
|
|
Opiop
|
 |
«
Reply #6 - Posted
2013-10-19 03:04:46 » |
|
Your art looks really good, but I don't think that purple text fits just quite right! 
|
|
|
|
SHC
|
 |
«
Reply #7 - Posted
2013-10-19 13:28:39 » |
|
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.
|
|
|
|
Opiop
|
 |
«
Reply #8 - Posted
2013-10-19 13:36:00 » |
|
I would love to take part in the alpha!
|
|
|
|
Dxu1994
|
 |
«
Reply #9 - Posted
2013-10-19 13:57:21 » |
|
Hi I'd like to give it a try as soon as possible. Keep up the good work  Thank you, I'll definitely sign you up for Alpha! Your art looks really good, but I don't think that purple text fits just quite right!  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.) 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.
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! I would love to take part in the alpha!
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.
Screenshot of update:  Source code for rendering characters if interested: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75
| private CharacterPartsProvider skinProvider = null; private EnumMap<EquipSlot, CharacterPartsProvider> equipsProvider = new EnumMap(EquipSlot.class); private CharacterPartsProvider hairProvider = null; private CharacterPartsProvider faceProvider = null; 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(); skinProvider.provide(currentParts, stance, frame); if (hairProvider != null) { hairProvider.provide(currentParts, stance, frame); } if (faceProvider != null) { faceProvider.provide(currentParts, stance, frame); } for (final CharacterPartsProvider provider : equipsProvider.values()) { provider.provide(currentParts, stance, frame); } 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); } for (int i = 0; i < effects.size(); i++) { effects.get(i).doRender(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.
|
|
|
|
Games published by our own members! Check 'em out!
|
|
SHC
|
 |
«
Reply #10 - Posted
2013-10-19 16:02:34 » |
|
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)  Just wanted to see how you optimised to get 10k+ objects at 60 fps with Java2D. Can you please post the relevant parts where you did optimisations?
|
|
|
|
Dxu1994
|
 |
«
Reply #11 - Posted
2013-10-19 16:15:03 » |
|
Alright so here are the relevant parts: To convert BufferedImages to device-compatible images: (Extreme speed booster) 1 2 3 4 5 6 7 8 9 10 11 12 13 14
| public static BufferedImage toCompatibleImage(BufferedImage image, boolean override, boolean disposeOld) { if (image.getColorModel().equals(gfxConfig.getColorModel()) && !override) { return image; } BufferedImage newImage = gfxConfig.createCompatibleImage(image.getWidth(), image.getHeight(), image.getTransparency()); Graphics2D g2d = newImage.createGraphics(); g2d.drawImage(image, 0, 0, null); g2d.dispose(); if (disposeOld) { image.flush(); }
return newImage; } |
The Active-Rendering Canvas - uses BufferStrategy: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| drawCanvas = new RenoriaCanvas(); drawCanvas.setSize(RenoriaSize); drawCanvas.setPreferredSize(RenoriaSize); panel.add(drawCanvas); drawCanvas.setFocusTraversalKeysEnabled(false); drawCanvas.requestFocus(); drawCanvas.setIgnoreRepaint(true); if (Core.useDrawBuffers.getValue()) { drawCanvas.createBufferStrategy(RenoriaOptions.BufferCount.getValue()); this.buffer = drawCanvas.getBufferStrategy(); } else { drawBuffer = ImageFactory.gfxConfig.createCompatibleImage(RenoriaSize.width, RenoriaSize.height, BufferedImage.OPAQUE); drawBuffer = ImageFactory.gfxConfig.createCompatibleImage(RenoriaSize.width, RenoriaSize.height, BufferedImage.OPAQUE); } this.renderSpace = new RenderSpace(); |
Rendering to the Canvas: (Use another thread to call render() repeatedly) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| public void render() { if (!render) { return; } if (drawBuffer != null) { renderInternal(drawBuffer.createGraphics()); drawCanvas.update(drawCanvas.getGraphics()); return; } Graphics2D g = (Graphics2D) buffer.getDrawGraphics(); renderInternal(g); buffer.show(); if (RenoriaOptions.UseVsync.getValue()) { Toolkit.getDefaultToolkit().sync(); }
} |
Use a QuadTree to draw only whats required: 1 2 3 4 5 6 7 8
| public void doRender(RenderSpace g) { TreeSet<MapObject> objList = new TreeSet<MapObject>(MAP_OBJECT_Z_COMPARATOR); currentMap.getObjectsInRegionQuadTree(Core.viewX, Core.viewY, Core.viewWidth, Core.viewHeight, objList); for (Iterator<MapObject> i = objList.iterator(); i.hasNext();) { i.next().doRender(g); } } |
Hope this helps 
|
|
|
|
SHC
|
 |
«
Reply #12 - Posted
2013-10-19 16:25:12 » |
|
I just didn't do the 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.
|
|
|
|
Dxu1994
|
 |
«
Reply #13 - Posted
2013-10-19 16:42:24 » |
|
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?
|
|
|
|
SHC
|
 |
«
Reply #14 - Posted
2013-10-19 16:50:52 » |
|
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.
|
|
|
|
Dxu1994
|
 |
«
Reply #15 - Posted
2013-10-19 17:02:31 » |
|
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.
|
|
|
|
Dxu1994
|
 |
«
Reply #16 - Posted
2013-10-19 20:48:41 » |
|
Here is a tech demo video of the MMO and engine consisting of: - Monster attacking (melee and ranged)
- Item equipping and dropping
- Character movement and synchronisation
- A demo of me spawning 1000 monsters and killing them all with ranged throwing stars. (Shows just how well the engine performs.)
- Player chatting
- Some effects that the engine can support
 http://www.youtube.com/v/YtkQmY0sgF8?version=3&hl=en_US&start=
|
|
|
|
RobinB
|
 |
«
Reply #17 - Posted
2013-10-21 11:20:25 » |
|
Very nice, i would like to play the alpha. This game looks very much like maplestory, i hope you can make it better then that.
|
|
|
|
Dxu1994
|
 |
«
Reply #18 - Posted
2013-10-21 11:21:58 » |
|
UPDATE: Our first boss is in game!   He's using powerups Boost Attack and Boost Defence. Also, monster projectiles (such as dragonfire) are now coded and work. 
|
|
|
|
Dxu1994
|
 |
«
Reply #19 - Posted
2013-10-22 14:41:18 » |
|
UPDATE: 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) Also, better monster editor: 
|
|
|
|
Troubleshoots
|
 |
«
Reply #20 - Posted
2013-10-22 14:59:58 » |
|
Wow. I must ask; how did you learn to create such good art? It's amazing! I can't even draw 32x32 sprites. 
|
Why are all OpenGL tutorials written in Brainf**k?
|
|
|
Dxu1994
|
 |
«
Reply #21 - Posted
2013-10-22 15:02:33 » |
|
Wow. I must ask; how did you learn to create such good art? It's amazing! I can't even draw 32x32 sprites.  I don't haha. I'm just the programmer. I have hired a team of artists. 1 programmer, 10 artists = THIS!
|
|
|
|
|
Troubleshoots
|
 |
«
Reply #23 - Posted
2013-10-23 12:56:12 » |
|
Nice, however the damage needs to show up for longer; maybe twice as long. You can't read it otherwise.
|
Why are all OpenGL tutorials written in Brainf**k?
|
|
|
nsigma
|
 |
«
Reply #24 - Posted
2013-10-23 13:19:33 » |
|
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.
Interesting. That shouldn't have any effect, unless you're doing something else to the images that is making them unmanaged.
|
Praxis LIVE - hybrid visual IDE for (live) creative coding
|
|
|
Dxu1994
|
 |
«
Reply #25 - Posted
2013-10-23 16:14:05 » |
|
@Troubleshoots
Thanks for your feedback. I've changed numbers so they show up for twice as long.
@nsigma:
ImageIO.read can load images in formats that aren't optimized for the current GraphicsDevice. That code will optimize them to use the same colormodel as the current GraphicsDevice so no conversions are necessary when rendering.
|
|
|
|
tyeeeee1
|
 |
«
Reply #26 - Posted
2013-10-24 02:34:06 » |
|
@nsigma:
ImageIO.read can load images in formats that aren't optimized for the current GraphicsDevice. That code will optimize them to use the same colormodel as the current GraphicsDevice so no conversions are necessary when rendering.
So would running every image loaded for the game through the toCompatibleImage method improve the performance? Could you explain the method step-by-step if you have a chance?
|
|
|
|
Dxu1994
|
 |
«
Reply #27 - Posted
2013-10-24 04:33:22 » |
|
@nsigma:
ImageIO.read can load images in formats that aren't optimized for the current GraphicsDevice. That code will optimize them to use the same colormodel as the current GraphicsDevice so no conversions are necessary when rendering.
So would running every image loaded for the game through the toCompatibleImage method improve the performance? Could you explain the method step-by-step if you have a chance? Alright so, the method does this: 1. Test if the ColorModel of the image is compatible with the current display. If so, just return it. 2. If the ColorModel is not compatible with the current display, a conversion will need to be done every time the image is rendered to screen (slow). So instead, we do the conversion ourselves: 3. Create a Buffered Image compatible with the current display. 4. Create a graphics context and render the incompatible image onto the compatible image. 5. Dispose the old image and return the new compatible image.
|
|
|
|
Dxu1994
|
 |
«
Reply #28 - Posted
2013-10-24 04:44:44 » |
|
UPDATE: New monster! Hill giants!  A bunch of new items added into the game, including: Etc King Frost Dragon Claw – Claw obtained from killing King Frost Dragon Copper Ore – Ore obtained from a copper rock Tin Ore – Ore obtained from a tin rock Log – Log obtained from chopping trees Wool - Obtained from killing sheep Golem Rubble - Obtained from killing golems Cloth - Obtained from killing wraiths Giant Rat Tail - Obtained from killing giant rats Green dragon scale - Obtained from killing Green dragons Green dragon wing - Obtained from killing green dragons Dragon Horn - Obtained from killing any dragon Fox fur - Obtained from killing foxes Zorb Eye - Obtained from killing zorbs Bat wing - Obtained from killing bats Cowhide - Obtained from killing cows Feather - Obtained from killing chickens Rags - Obtained from killing zombies Apple – Food Banana – Food Pear – Food Watermelon Slice – Food Ice Cream Cone – Food Vanilla Cone – Food Chocolate Cone – Food Strawberry Cone – Food Lime Cone – Food Cookies and Cream Cone – Food Bread – Food Red Potion – Health Potion Light Blue Potion – Health Potion Orange Potion – Health Potion tier 2 Dark Blue Potion – Mana potion tier 2 Red Elixr – Health Potion tier 3 Blue Elixir – Mana Potion tier 3
|
|
|
|
nsigma
|
 |
«
Reply #29 - Posted
2013-10-24 09:43:38 » |
|
ImageIO.read can load images in formats that aren't optimized for the current GraphicsDevice. That code will optimize them to use the same colormodel as the current GraphicsDevice so no conversions are necessary when rendering.
Yes, I understand what that does. I'm not sure you're understanding managed images though? Any BufferedImage (including those read through ImageIO) can be managed, meaning it's cached in VRAM, and no conversion would therefore be necessary when rendering. Theoretically seeing such a "considerable speed boost" between BufferedImage formats would suggest that something else is going on in how you draw or use the images that is stopping rendering from them being hardware accelerated (or alternatively it's the OS you're on, or just Java2D being Java2D!  ) Anyway, I wasn't seeking to hijack your thread on that discussion - maybe start a new one if you want to discuss further? Game looks great btw 
|
Praxis LIVE - hybrid visual IDE for (live) creative coding
|
|
|
|