vrekt / lunar Goto Github PK
View Code? Open in Web Editor NEWMaking games in Java is now easier than ever before!
License: MIT License
Making games in Java is now easier than ever before!
License: MIT License
Adding and removing entities during the game loop causes a ConcurrentModificationException
. This varies from implementation to implementation, but basically if an entity is being updated and should be removed, the intuition is to call world.removeEntity(this)
. However, if the entity is being updated from the world loop, say
@Override
public void onTick() {
worldEntities.forEach(Entity::updateEntity);
}
the exception is thrown, because you can't remove the entity from a list that is being traversed.
This is fairly common mistake, and it could be useful to provide the user a solution. I'll make a branch and link it here real quick with a potential solution.
I've been working a lot on multiplayer over the last couple of days and have some things to discuss here. I am attempting to keep it as general as possible at this point. The idea here is that the users can look at what's in place and add on top of it.
There are a lot of different methods to implement Server-Client communication, but I just went with the simple, typical Java based method which is over sockets. The server starts and listens on a socket, and for every connection it receives it starts a new thread to handle all the communication with that client.
To send data back and forth, I created a packet exchange system. This was the first thing that came to mind, and I just went for it to test it out. Each packet has a specific use case that it is responsible for serializing/deserializing to/from a byte
stream. This byte
stream is written/read over the socket.
An example: A client moves their player, a packet is then sent to the server with the client's player entity's id and the new location. This is encoded as a byte
stream of (id, x, y) and sent over the socket to the server. The server reads the packet by reading from the stream three int
s in the same order as they were written by the client.
Obviously this has some fairly significant flaws and doesn't really do much of any validation between client/server, but that's a hurdle for another time.
Moving on, whenever the server receives a packet from a client, it forwards that packet to all other clients if it's something that all clients need to be aware of.
Entity
information over the sockets. To do so, there must be some way to serialize them to a byte
stream. Currently I see three ways of doing this.
Entity
class and override them where need be. This would look like:// in Entity.java
public byte[] serialize(DataOutputStream dos) throws IOException {
dos.writeInt(getEntityID());
dos.writeInt(getY());
dos.writeInt(getX());
return // bytes
}
// in LivingEntity.java
@Override
public byte[] serialize(DataOutputStream dos) throws IOException {
super(dos);
dos.writeFloat(getHealth());
dos.writeDouble(getSpeed());
return //the bytes
}
// etc...
public void deserialize(DataInputStream dis) ...
NetworkSerializable
with serialize
and deserialize
methods to anything that should be able to be sent over the network. My gripe with this method is that it would just be hierarchy hell. And could end up to requiring different types of entities for single player vs multiplayer (annoying).@Serialize
& @Deserialize
. This is my personal favorite solution. The benefit of this is that any method could be marked and be used as long as the correct return type and parameters are used. The user would be free to have any hierarchy they desire and could just slap this down anywhere. It does require them to manage more state, though. The major drawback is annotation based stuff is all going to be reflection which can get slow. This could be offset somewhat by doing class path scanning or build registries to avoid scanning during general runtime for the methods.There's still a lot to be learned in this process, but I wanted to share what i have so far. I've been doing this in my fork so as to not create noise in the main repo. You can check it out here. Only 1300 lines of code! Phew.
Thoughts?
While making an example game I discovered currently drawing to 0, 0 will draw behind the title bars because we take the whole window into account. I wanted to fix this since its a bit annoying. I'm not sure which approach to take though.
I was thinking of a JPanel or using a Canvas. Using a JPanel will get rid of the buffer strategy code I believe since those components are double-buffered. Thoughts?
Also, I think it would be great for location stuff to use doubles instead of integers. I've made a new branch to work on this since I'm still working on changing everything. The only problem is translating doubles to tiles on the map.
I'm currently working on ray casting within the context of the world and tiles. Right now just making an attempt at implementing the basics of it and then we can discuss changes needed to get it to work with what is already in place.
General idea would be this:
RayCastResult result = world.raycast(x, y, targetX, targetY); // or raycast(x, y, dirX, dirY, distance)
Tile tile = result.getCollidedTile(); //null if no collision
boolean didCollide = result.didCollide(); // T/F whether there was a collision with a tile.
Location location = result.getCollidedLocation(); // x,y of the collision
Collision is based of the isSolid()
property of tiles.
So far what I'm seeing is we would need some way to translate between world space and screen space, if we wanted to do pixel perfect ray casting (might as well). This would mean the world would need to be aware of the dimensions of the tiles. I'll have a PR for this probably by tomorrow and we can review it.
For reference, I'm adapting ray casting from this post (without the solidity matrices for tiles).
Getting the following exception when using getEntityAt if there is no entity at the given location:
Exception in thread "AWT-EventQueue-0" java.util.NoSuchElementException: No value present
at java.util.Optional.get(Optional.java:135)
at me.vrekt.lunar.world.World.getEntityAt(World.java:144)
Offending code:
public final Entity getEntityAt(int x, int y) {
return worldEntities.stream().filter(entity -> entity.getX() == x && entity.getY() == y).findAny().get();
}
Changing the get()
to .orElse(null);
fixes it.
Entity#getLineOfSight
should be updated to use the new RayCasting class/functions.
Per this conversation
BTW: I'm going to assign more people to this once they accept.
I'm wanting to add basic physics to the game. Something easy and simple to use. If you have an ideas please share them with me below.
Something like gravity would be simple enough. I'm thinking:
BasicPhysics.handleGravity(myEntity, direction, speed);
or something where the entity implements a physics class and it handles it automatically. I'm not sure still thinking about how to implement it.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.