Maze shooter thingy

Hi, I have been lurking the forum for something like 1.5 years. So I thought I’d reveal myself and what I have been working on.



It is my first game and I feel it’s starting to get done, sure there are many things that can improve and bugs to be fixed but it is fully playable and I’m feeling kinda good about coming this far. The next big hurdle is coming up with a name for it… :wink:



Anyhow, here is a clip of the game:

http://www.youtube.com/watch?v=PonV0-BQOHk&feature=g-upl&context=G26e7738AUAAAAAAAAAA



It is intended to be a network pvp game but it has a simple ai for trying it out. A word of caution, the ai is hastily written and will bring at least my computer to it's knees if I add to many NPCs.

Other features of the game is a randomly generated maze and a level up system.

It can be downloaded here http://ompldr.org/vY3hvcA/game1.jar

I wold love to hear what you think about it!
11 Likes

Amazing ^^.

1 Like
@pobtott said:
Other features of the game is a randomly generated maze and a level up system.


3d generated maze? would you like to make a video to show how it generate, I mean, the high level should be a bit harder than the previous, am I right, how can you make a maze harder??

As for the camera float up in the end of the game, good one... Your game compose things pretty nice!
1 Like
@atomix said:
3d generated maze? would you like to make a video to show how it generate, I mean, the high level should be a bit harder than the previous, am I right, how can you make a maze harder??

As for the camera float up in the end of the game, good one... Your game compose things pretty nice!


A new maze is not harder then the previous. A maze is generated when a new instance of the game is started. And an instance is basically a deathmatch between players, so it does not have to be a harder maze.

What I mean by a level up system is that when you kill an opponent you gain some xp, when the xp is high enough you level up and can improve things like damage, cooldown, health or get more bounces to your shot.

If you are still interested the maze is generated using the recursive division method, since the player never move up and down it works like a 2d maze. http://en.wikipedia.org/wiki/Maze_generation_algorithm#Recursive_division_method
2 Likes

how did you make bullets to bounce? it seems really cool.

1 Like

When a projectile hits a wall I get the normal of the wall and flip the projectile so it has the same angle to the normal but on the other side of it and then make the projectile go in the opposite direction. Not sure this is a good explanation but if you have read some physics, it is the same as how you calculate the angle when light reflects in a mirror.

2 Likes

Looks nice. How is the game only running at ~40fps? Did you set it that way or is there something which is taking a lot of space?

1 Like
@memonick said:
Looks nice. How is the game only running at ~40fps? Did you set it that way or is there something which is taking a lot of space?


Without the video capture on, the games runs at ~100 fps. What would be a good fps? I guess the hardware plays a big difference. The video is recorded on my laptop, playing it on my four year old desktop the fps is around 400 under the same conditions.

As stated in the original post, the ai is crudely done and can slow things down considerably. It performs a lot of unnecessary collision checks. It would not take that long to improve things but I don't see this game drawing much attention form others so I am more eager to work on other projects. Also I had not intended for this game to have an ai and to just be pvp. Ai was something I added so it could be tested without other players.

100 is very good. I would recommend stabilizing it to 60. Wouldn’t want a game that jumps from 100 to 200 in a few seconds, would you? Good luck in your projects man! If you ever need any help, don’t hesitate to ask.

1 Like

Hey, how many lights do u have in your scene? That looks pretty nice!

1 Like
@memonick said:
100 is very good. I would recommend stabilizing it to 60. Wouldn't want a game that jumps from 100 to 200 in a few seconds, would you? Good luck in your projects man! If you ever need any help, don't hesitate to ask.


Thanks for the advice!

@glaucomardano said:
Hey, how many lights do u have in your scene? That looks pretty nice!


There are four lights, one in each corner of the maze. This way you can orientate yourself to some degree based on which colors are around you.
1 Like

That is so cool! Great work. We all want to see your client/server code :slight_smile:

1 Like
@monkeyBrainz said:
That is so cool! Great work. We all want to see your client/server code :)


Sure but it was quite some time ago that i wrote it. If you have any questions I'll try my best to answer them.
There are probably a lot of things that could have been done better, this was the first time I wrote network code.

Server code:
[java]
package game;

import java.io.IOException;
import java.util.ArrayList;
import com.jme3.network.ConnectionListener;
import com.jme3.network.HostedConnection;
import com.jme3.network.Message;
import com.jme3.network.MessageListener;
import com.jme3.network.Network;
import com.jme3.network.Server;
import com.jme3.network.serializing.Serializer;


public class GameServer implements ConnectionListener, MessageListener<HostedConnection> {
private Server server;
private String[][] map;
private ArrayList<String> playerList;
private int syncId;
private int score;
private int nbrPlayers;
private ArrayList<MessagePlayerControll> ctrlList;


public GameServer(int port, String gameName, String[][] map, String playerName, int score, int nbrPlayers) {
super();
try {
server = Network.createServer(port);
server.start();
server.addConnectionListener(this);
server.addMessageListener(this, MessagePlayerState.class);
server.addMessageListener(this, MessageInitiziatePlayer.class);
server.addMessageListener(this, MessagePlayerControll.class);
server.addMessageListener(this, MessageDisconnectPlayer.class);

initzializeClasses();
System.out.println("Server connected: " + server.isRunning());

} catch (IOException e) {
System.out.println("Failed to create server.");
e.printStackTrace();
}
syncId = 0;
ctrlList = new ArrayList<MessagePlayerControll>();
playerList = new ArrayList<String>();
//this.playerName = playerName;
if (playerName != null) playerList.add(playerName);
this.map = map;
this.score = score;
this.nbrPlayers = nbrPlayers;
}

public static void initzializeClasses(){
Serializer.registerClass(PlayerState.class, new SerializerPlayerState());
Serializer.registerClass(BulletState.class, new SerializerBulletState());
Serializer.registerClass(MessagePlayerState.class);
Serializer.registerClass(MessageWorldState.class);
Serializer.registerClass(MessageWorldMap.class);
Serializer.registerClass(MessageInitiziatePlayer.class);
Serializer.registerClass(MessagePlayerControll.class);
Serializer.registerClass(MessageDisconnectPlayer.class);
}

@Override
public void connectionAdded(Server arg0, HostedConnection con) {
System.out.println("Client connected");


con.send(new MessageWorldMap(map, score));
//con.send(new TankyMessageInitiziatePlayer(playerName));
for (int i = 0; i < playerList.size(); i++) {
con.send(new MessageInitiziatePlayer(playerList.get(i)));
}

}

@Override
public void connectionRemoved(Server s, HostedConnection con) {
String player = (String) con.getAttribute("player");
int index = playerList.indexOf(player);
if (index >= 0) {
playerList.remove(index);
}

System.out.println("Conn remoevd, player: " + player);
}

@Override
public void messageReceived(HostedConnection arg0, Message arg1) {
if (arg1 instanceof MessagePlayerControll) {
MessagePlayerControll ctrl = ((MessagePlayerControll) arg1);
for (int i = 0; i < ctrlList.size(); i++) {
if (ctrlList.get(i).playerName.equals(ctrl.playerName) && (ctrlList.get(i).syncID < ctrl.syncID || (ctrlList.get(i).syncID - 50000) > ctrl.syncID)) {
ctrlList.get(i).update(ctrl);
}
}
}

if (arg1 instanceof MessageInitiziatePlayer) {
String name = ((MessageInitiziatePlayer)arg1).name;
if (!playerList.contains(name) && playerList.size() < nbrPlayers) {
System.out.println("Initziating player: " + name);
System.out.println(nbrPlayers + " " + playerList.size());
playerList.add(name);
MessagePlayerControll ctrl = new MessagePlayerControll(
name, 0, false, false, false, false, false, 0);
ctrlList.add(ctrl);
server.broadcast(new MessageInitiziatePlayer(name));
arg0.setAttribute("player", name);
} else if (playerList.size() >= nbrPlayers) {
System.out.println("The game is full");
arg0.close("The game is full");
} else {
System.out.println("Players name already in use");
arg0.close("Player name already in use");
}
}

if (arg1 instanceof MessageDisconnectPlayer) {
String name = ((MessageDisconnectPlayer)arg1).name;
for (int i = 0; i < playerList.size(); i++) {
if (playerList.get(i).equals(name)) {
playerList.remove(i);
i--;
}
}
for (int i = 0; i < ctrlList.size(); i++) {
if (ctrlList.get(i).equals(name)) {
ctrlList.remove(i);
i--;
}
}

}

}

public void brodcastState(ArrayList<PlayerState> plist, ArrayList<BulletState> blist){
try {
Message m = new MessageWorldState(plist, blist, syncId);
m.setReliable(false);
server.broadcast(m);
} catch (Exception e) {
System.out.println("State brodcast failed.");
e.printStackTrace();
}
syncId++;
if (syncId >= 100000) {
syncId = 0;
}
}

public void disconnect() {
server.close();
}

public void brodcastMap() {
server.broadcast(new MessageWorldMap(map, score));
}

public ArrayList<MessagePlayerControll> getControlList() {
return ctrlList;
}

public void setMap(String[][] map) {
this.map = map;
}

@SuppressWarnings("unchecked")
public ArrayList<String> getPlayerList(){
return (ArrayList<String>) playerList.clone();
}

}
[/java]

Client code:
[java]
package game;

import java.io.IOException;
import java.util.ArrayList;
import com.jme3.network.Client;
import com.jme3.network.ClientStateListener;
import com.jme3.network.Message;
import com.jme3.network.MessageListener;
import com.jme3.network.Network;

public class GameClient implements MessageListener<Client>, ClientStateListener{
private Client client;
private ArrayList<PlayerState> stateList;
private ArrayList<BulletState> bulletStateList;
private String[][] map;
private String playerName;
private ArrayList<String> playerList;
public boolean worldLoaded = false;
private int syncId;
private int worldSync;
public String score = "Score:";
public String playersScore = "Player:";
private boolean connected;
public int scoreGoal;
public String lastError = "";

public GameClient(int port, String ip, String playerName) throws IOException {
stateList = new ArrayList<PlayerState>();
playerList = new ArrayList<String>();
this.playerName = playerName;
this.syncId = 0;
this.worldSync = 0;
stateList.add(new PlayerState(playerName));
playerList.add(playerName);

try {
client = Network.connectToServer(ip, port);
GameServer.initzializeClasses();
client.addMessageListener(this, MessageWorldMap.class);
client.addMessageListener(this, MessageWorldState.class);
client.addMessageListener(this, MessageInitiziatePlayer.class);
client.addClientStateListener(this);
client.start();
connected = true;
} catch (IOException e) {
System.out.println("Failed to initiate client.");
throw e;
}
}

@Override
public void messageReceived(Client arg0, Message arg1) {

if (arg1 instanceof MessageWorldMap) {
System.out.println("Recived map");
map = ((MessageWorldMap)arg1).map;
scoreGoal = ((MessageWorldMap)arg1).score;
}

if (arg1 instanceof MessageWorldState) {
ArrayList<PlayerState> state = ((MessageWorldState)arg1).playerStates;

if (((MessageWorldState)arg1).syncId > this.worldSync) {
this.bulletStateList = ((MessageWorldState)arg1).bulletStates;
this.worldSync = ((MessageWorldState)arg1).syncId;

for (int i = 0; i < state.size(); i++) {

if (stateList.contains(state.get(i))) {
int index = stateList.indexOf(state.get(i));
stateList.set(index, interpolate(stateList.get(index), state.get(i)));
}
}
}
}
if (arg1 instanceof MessageInitiziatePlayer) {
if (!playerList.contains(((MessageInitiziatePlayer) arg1).name)) {
System.out.println("Initziating player: " + ((MessageInitiziatePlayer) arg1).name);
playerList.add(((MessageInitiziatePlayer) arg1).name);
stateList.add(new PlayerState(((MessageInitiziatePlayer) arg1).name));
}
}
}

public PlayerState interpolate(PlayerState s1, PlayerState s2) {
PlayerState ps = s2.cloneState();
ps.pos = s1.pos.interpolate(s2.pos, 0.25f);
if (s2.rot != null && s1.rot != null) ps.rot = s1.rot.add(s2.rot).mult(0.5f);
return ps;
}

public void sendControls(MessagePlayerControll ctrlMsg) {
if (client == null) return;
ctrlMsg.setSyncId(syncId);
syncId++;
if (syncId >= 100000) {
syncId = 1;
}
ctrlMsg.setReliable(false);
client.send(ctrlMsg);
}

public String[][] getMap() {
return map;
}

public int getScoreGoal() {
return scoreGoal;
}

public ArrayList<PlayerState> readState(){
return stateList;
}

public ArrayList<String> getPlayerList(){
return playerList;
}

public ArrayList<BulletState> getBulletStates() {
return this.bulletStateList;
}

@Override
public void clientConnected(Client arg0) {
client.send(new MessageInitiziatePlayer(playerName));
}

public void clientDisconnect() {
client.send(new MessageDisconnectPlayer(playerName));
connected = false;
}

@Override
public void clientDisconnected(Client arg0, DisconnectInfo info) {
lastError = info.reason;
connected = false;
client.close();
}

public boolean isConnected() {
return connected;
}


}

[/java]

Thank you. I have never written network code but I was always interested in the possibility.



I am currently working on a voxel map engine and editor that I will release freely to the forum. Perhaps you could use it for one of your future games!

1 Like